diff options
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r-- | drivers/pci/setup-bus.c | 37 |
1 files changed, 25 insertions, 12 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 7853ac6999e2..77a566aeae60 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -28,6 +28,10 @@ #include <linux/acpi.h> #include "pci.h" +#define PCI_RES_TYPE_MASK \ + (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH |\ + IORESOURCE_MEM_64) + unsigned int pci_flags; EXPORT_SYMBOL_GPL(pci_flags); @@ -384,13 +388,19 @@ static bool pci_need_to_release(unsigned long mask, struct resource *res) } /* Return: @true if assignment of a required resource failed. */ -static bool pci_required_resource_failed(struct list_head *fail_head) +static bool pci_required_resource_failed(struct list_head *fail_head, + unsigned long type) { struct pci_dev_resource *fail_res; + type &= PCI_RES_TYPE_MASK; + list_for_each_entry(fail_res, fail_head, list) { int idx = pci_resource_num(fail_res->dev, fail_res->res); + if (type && (fail_res->flags & PCI_RES_TYPE_MASK) != type) + continue; + if (!pci_resource_is_optional(fail_res->dev, idx)) return true; } @@ -504,7 +514,7 @@ assign: } /* Without realloc_head and only optional fails, nothing more to do. */ - if (!pci_required_resource_failed(&local_fail_head) && + if (!pci_required_resource_failed(&local_fail_head, 0) && list_empty(realloc_head)) { list_for_each_entry(save_res, &save_head, list) { struct resource *res = save_res->res; @@ -1169,6 +1179,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, resource_size_t children_add_size = 0; resource_size_t children_add_align = 0; resource_size_t add_align = 0; + resource_size_t relaxed_align; if (!b_res) return -ENOSPC; @@ -1246,8 +1257,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, if (bus->self && size0 && !pbus_upstream_space_available(bus, mask | IORESOURCE_PREFETCH, type, size0, min_align)) { - min_align = 1ULL << (max_order + __ffs(SZ_1M)); - min_align = max(min_align, win_align); + relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); + relaxed_align = max(relaxed_align, win_align); + min_align = min(min_align, relaxed_align); size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), win_align); pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n", b_res, &bus->busn_res); @@ -1261,8 +1273,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, if (bus->self && size1 && !pbus_upstream_space_available(bus, mask | IORESOURCE_PREFETCH, type, size1, add_align)) { - min_align = 1ULL << (max_order + __ffs(SZ_1M)); - min_align = max(min_align, win_align); + relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); + relaxed_align = max(relaxed_align, win_align); + min_align = min(min_align, relaxed_align); size1 = calculate_memsize(size, min_size, add_size, children_add_size, resource_size(b_res), win_align); pci_info(bus->self, @@ -1704,10 +1717,6 @@ static void __pci_bridge_assign_resources(const struct pci_dev *bridge, } } -#define PCI_RES_TYPE_MASK \ - (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH |\ - IORESOURCE_MEM_64) - static void pci_bridge_release_resources(struct pci_bus *bus, unsigned long type) { @@ -2446,8 +2455,12 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) free_list(&added); if (!list_empty(&failed)) { - ret = -ENOSPC; - goto cleanup; + if (pci_required_resource_failed(&failed, type)) { + ret = -ENOSPC; + goto cleanup; + } + /* Only resources with unrelated types failed (again) */ + free_list(&failed); } list_for_each_entry(dev_res, &saved, list) { |