Merge branch 'pci/resource'
- Clear only bridge windows (not BARs) while assigning bus resources (Logan Gunthorpe) - Improve resource assignment for deep hotplug hierarchies, e.g., Thunderbolt (Nicholas Johnson) * pci/resource: PCI: Allow adjust_bridge_window() to shrink resource if necessary PCI: Set resource size directly in adjust_bridge_window() PCI: Rename extend_bridge_window() to adjust_bridge_window() PCI: Rename extend_bridge_window() parameter PCI: Consider alignment of hot-added bridges when assigning resources PCI: Remove local variable usage in pci_bus_distribute_available_resources() PCI: Pass size + alignment to pci_bus_distribute_available_resources() PCI: Rename variables PCI: Remove unnecessary braces PCI: Don't disable bridge BARs when assigning bus resources
This commit is contained in:
commit
cee538f6a2
@ -1803,12 +1803,18 @@ again:
|
||||
/* Restore size and flags */
|
||||
list_for_each_entry(fail_res, &fail_head, list) {
|
||||
struct resource *res = fail_res->res;
|
||||
int idx;
|
||||
|
||||
res->start = fail_res->start;
|
||||
res->end = fail_res->end;
|
||||
res->flags = fail_res->flags;
|
||||
if (fail_res->dev->subordinate)
|
||||
res->flags = 0;
|
||||
|
||||
if (pci_is_bridge(fail_res->dev)) {
|
||||
idx = res - &fail_res->dev->resource[0];
|
||||
if (idx >= PCI_BRIDGE_RESOURCES &&
|
||||
idx <= PCI_BRIDGE_RESOURCE_END)
|
||||
res->flags = 0;
|
||||
}
|
||||
}
|
||||
free_list(&fail_head);
|
||||
|
||||
@ -1832,56 +1838,72 @@ void __init pci_assign_unassigned_resources(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void extend_bridge_window(struct pci_dev *bridge, struct resource *res,
|
||||
static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res,
|
||||
struct list_head *add_list,
|
||||
resource_size_t available)
|
||||
resource_size_t new_size)
|
||||
{
|
||||
struct pci_dev_resource *dev_res;
|
||||
resource_size_t add_size, size = resource_size(res);
|
||||
|
||||
if (res->parent)
|
||||
return;
|
||||
|
||||
if (resource_size(res) >= available)
|
||||
if (!new_size)
|
||||
return;
|
||||
|
||||
dev_res = res_to_dev_res(add_list, res);
|
||||
if (!dev_res)
|
||||
return;
|
||||
if (new_size > size) {
|
||||
add_size = new_size - size;
|
||||
pci_dbg(bridge, "bridge window %pR extended by %pa\n", res,
|
||||
&add_size);
|
||||
} else if (new_size < size) {
|
||||
add_size = size - new_size;
|
||||
pci_dbg(bridge, "bridge window %pR shrunken by %pa\n", res,
|
||||
&add_size);
|
||||
}
|
||||
|
||||
/* Is there room to extend the window? */
|
||||
if (available - resource_size(res) <= dev_res->add_size)
|
||||
return;
|
||||
|
||||
dev_res->add_size = available - resource_size(res);
|
||||
pci_dbg(bridge, "bridge window %pR extended by %pa\n", res,
|
||||
&dev_res->add_size);
|
||||
res->end = res->start + new_size - 1;
|
||||
remove_from_list(add_list, res);
|
||||
}
|
||||
|
||||
static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
||||
struct list_head *add_list,
|
||||
resource_size_t available_io,
|
||||
resource_size_t available_mmio,
|
||||
resource_size_t available_mmio_pref)
|
||||
struct resource io,
|
||||
struct resource mmio,
|
||||
struct resource mmio_pref)
|
||||
{
|
||||
resource_size_t remaining_io, remaining_mmio, remaining_mmio_pref;
|
||||
unsigned int normal_bridges = 0, hotplug_bridges = 0;
|
||||
struct resource *io_res, *mmio_res, *mmio_pref_res;
|
||||
struct pci_dev *dev, *bridge = bus->self;
|
||||
resource_size_t io_per_hp, mmio_per_hp, mmio_pref_per_hp, align;
|
||||
|
||||
io_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
|
||||
mmio_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
|
||||
mmio_pref_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
|
||||
|
||||
/*
|
||||
* Update additional resource list (add_list) to fill all the
|
||||
* extra resource space available for this port except the space
|
||||
* calculated in __pci_bus_size_bridges() which covers all the
|
||||
* devices currently connected to the port and below.
|
||||
* The alignment of this bridge is yet to be considered, hence it must
|
||||
* be done now before extending its bridge window.
|
||||
*/
|
||||
extend_bridge_window(bridge, io_res, add_list, available_io);
|
||||
extend_bridge_window(bridge, mmio_res, add_list, available_mmio);
|
||||
extend_bridge_window(bridge, mmio_pref_res, add_list,
|
||||
available_mmio_pref);
|
||||
align = pci_resource_alignment(bridge, io_res);
|
||||
if (!io_res->parent && align)
|
||||
io.start = min(ALIGN(io.start, align), io.end + 1);
|
||||
|
||||
align = pci_resource_alignment(bridge, mmio_res);
|
||||
if (!mmio_res->parent && align)
|
||||
mmio.start = min(ALIGN(mmio.start, align), mmio.end + 1);
|
||||
|
||||
align = pci_resource_alignment(bridge, mmio_pref_res);
|
||||
if (!mmio_pref_res->parent && align)
|
||||
mmio_pref.start = min(ALIGN(mmio_pref.start, align),
|
||||
mmio_pref.end + 1);
|
||||
|
||||
/*
|
||||
* Now that we have adjusted for alignment, update the bridge window
|
||||
* resources to fill as much remaining resource space as possible.
|
||||
*/
|
||||
adjust_bridge_window(bridge, io_res, add_list, resource_size(&io));
|
||||
adjust_bridge_window(bridge, mmio_res, add_list, resource_size(&mmio));
|
||||
adjust_bridge_window(bridge, mmio_pref_res, add_list,
|
||||
resource_size(&mmio_pref));
|
||||
|
||||
/*
|
||||
* Calculate how many hotplug bridges and normal bridges there
|
||||
@ -1902,11 +1924,9 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
||||
*/
|
||||
if (hotplug_bridges + normal_bridges == 1) {
|
||||
dev = list_first_entry(&bus->devices, struct pci_dev, bus_list);
|
||||
if (dev->subordinate) {
|
||||
if (dev->subordinate)
|
||||
pci_bus_distribute_available_resources(dev->subordinate,
|
||||
add_list, available_io, available_mmio,
|
||||
available_mmio_pref);
|
||||
}
|
||||
add_list, io, mmio, mmio_pref);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1919,12 +1939,9 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
||||
* extra space reduced by the minimal required space for the
|
||||
* non-hotplug bridges.
|
||||
*/
|
||||
remaining_io = available_io;
|
||||
remaining_mmio = available_mmio;
|
||||
remaining_mmio_pref = available_mmio_pref;
|
||||
|
||||
for_each_pci_bridge(dev, bus) {
|
||||
const struct resource *res;
|
||||
resource_size_t used_size;
|
||||
struct resource *res;
|
||||
|
||||
if (dev->is_hotplug_bridge)
|
||||
continue;
|
||||
@ -1934,24 +1951,39 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
||||
* bridge and devices below it occupy.
|
||||
*/
|
||||
res = &dev->resource[PCI_BRIDGE_RESOURCES + 0];
|
||||
if (!res->parent && available_io > resource_size(res))
|
||||
remaining_io -= resource_size(res);
|
||||
align = pci_resource_alignment(dev, res);
|
||||
align = align ? ALIGN(io.start, align) - io.start : 0;
|
||||
used_size = align + resource_size(res);
|
||||
if (!res->parent)
|
||||
io.start = min(io.start + used_size, io.end + 1);
|
||||
|
||||
res = &dev->resource[PCI_BRIDGE_RESOURCES + 1];
|
||||
if (!res->parent && available_mmio > resource_size(res))
|
||||
remaining_mmio -= resource_size(res);
|
||||
align = pci_resource_alignment(dev, res);
|
||||
align = align ? ALIGN(mmio.start, align) - mmio.start : 0;
|
||||
used_size = align + resource_size(res);
|
||||
if (!res->parent)
|
||||
mmio.start = min(mmio.start + used_size, mmio.end + 1);
|
||||
|
||||
res = &dev->resource[PCI_BRIDGE_RESOURCES + 2];
|
||||
if (!res->parent && available_mmio_pref > resource_size(res))
|
||||
remaining_mmio_pref -= resource_size(res);
|
||||
align = pci_resource_alignment(dev, res);
|
||||
align = align ? ALIGN(mmio_pref.start, align) -
|
||||
mmio_pref.start : 0;
|
||||
used_size = align + resource_size(res);
|
||||
if (!res->parent)
|
||||
mmio_pref.start = min(mmio_pref.start + used_size,
|
||||
mmio_pref.end + 1);
|
||||
}
|
||||
|
||||
io_per_hp = div64_ul(resource_size(&io), hotplug_bridges);
|
||||
mmio_per_hp = div64_ul(resource_size(&mmio), hotplug_bridges);
|
||||
mmio_pref_per_hp = div64_ul(resource_size(&mmio_pref),
|
||||
hotplug_bridges);
|
||||
|
||||
/*
|
||||
* Go over devices on this bus and distribute the remaining
|
||||
* resource space between hotplug bridges.
|
||||
*/
|
||||
for_each_pci_bridge(dev, bus) {
|
||||
resource_size_t align, io, mmio, mmio_pref;
|
||||
struct pci_bus *b;
|
||||
|
||||
b = dev->subordinate;
|
||||
@ -1963,42 +1995,31 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
||||
* hotplug-capable downstream ports taking alignment into
|
||||
* account.
|
||||
*/
|
||||
align = pci_resource_alignment(bridge, io_res);
|
||||
io = div64_ul(available_io, hotplug_bridges);
|
||||
io = min(ALIGN(io, align), remaining_io);
|
||||
remaining_io -= io;
|
||||
|
||||
align = pci_resource_alignment(bridge, mmio_res);
|
||||
mmio = div64_ul(available_mmio, hotplug_bridges);
|
||||
mmio = min(ALIGN(mmio, align), remaining_mmio);
|
||||
remaining_mmio -= mmio;
|
||||
|
||||
align = pci_resource_alignment(bridge, mmio_pref_res);
|
||||
mmio_pref = div64_ul(available_mmio_pref, hotplug_bridges);
|
||||
mmio_pref = min(ALIGN(mmio_pref, align), remaining_mmio_pref);
|
||||
remaining_mmio_pref -= mmio_pref;
|
||||
io.end = io.start + io_per_hp - 1;
|
||||
mmio.end = mmio.start + mmio_per_hp - 1;
|
||||
mmio_pref.end = mmio_pref.start + mmio_pref_per_hp - 1;
|
||||
|
||||
pci_bus_distribute_available_resources(b, add_list, io, mmio,
|
||||
mmio_pref);
|
||||
|
||||
io.start += io_per_hp;
|
||||
mmio.start += mmio_per_hp;
|
||||
mmio_pref.start += mmio_pref_per_hp;
|
||||
}
|
||||
}
|
||||
|
||||
static void pci_bridge_distribute_available_resources(struct pci_dev *bridge,
|
||||
struct list_head *add_list)
|
||||
{
|
||||
resource_size_t available_io, available_mmio, available_mmio_pref;
|
||||
const struct resource *res;
|
||||
struct resource available_io, available_mmio, available_mmio_pref;
|
||||
|
||||
if (!bridge->is_hotplug_bridge)
|
||||
return;
|
||||
|
||||
/* Take the initial extra resources from the hotplug port */
|
||||
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
|
||||
available_io = resource_size(res);
|
||||
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
|
||||
available_mmio = resource_size(res);
|
||||
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
|
||||
available_mmio_pref = resource_size(res);
|
||||
available_io = bridge->resource[PCI_BRIDGE_RESOURCES + 0];
|
||||
available_mmio = bridge->resource[PCI_BRIDGE_RESOURCES + 1];
|
||||
available_mmio_pref = bridge->resource[PCI_BRIDGE_RESOURCES + 2];
|
||||
|
||||
pci_bus_distribute_available_resources(bridge->subordinate,
|
||||
add_list, available_io,
|
||||
@ -2055,12 +2076,18 @@ again:
|
||||
/* Restore size and flags */
|
||||
list_for_each_entry(fail_res, &fail_head, list) {
|
||||
struct resource *res = fail_res->res;
|
||||
int idx;
|
||||
|
||||
res->start = fail_res->start;
|
||||
res->end = fail_res->end;
|
||||
res->flags = fail_res->flags;
|
||||
if (fail_res->dev->subordinate)
|
||||
res->flags = 0;
|
||||
|
||||
if (pci_is_bridge(fail_res->dev)) {
|
||||
idx = res - &fail_res->dev->resource[0];
|
||||
if (idx >= PCI_BRIDGE_RESOURCES &&
|
||||
idx <= PCI_BRIDGE_RESOURCE_END)
|
||||
res->flags = 0;
|
||||
}
|
||||
}
|
||||
free_list(&fail_head);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user