diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-09-17 22:25:35 -0700 |
---|---|---|
committer | Yinghai Lu <yinghai@kernel.org> | 2012-09-17 22:25:35 -0700 |
commit | ead29924bbddcf583ff6153eb0e6f3310b185583 (patch) | |
tree | 67f8891baf83f31d50d7de0fd2e2a53dacc5a279 | |
parent | 713695faf3aacad7e47620e3e9b8b2c8c1060644 (diff) | |
download | linux-yinghai-ead29924bbddcf583ff6153eb0e6f3310b185583.tar.gz |
PCI: Sort unassigned resources with correct alignment
For SIZEALIGN type resource, we need to add back add_size in optional
resource list during __dev_sort_resources(), otherwise those optional
resources will get skipped.
SRIOV BAR is specical one, it will always re-read size for BAR.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
-rw-r--r-- | drivers/pci/setup-bus.c | 33 |
1 files changed, 26 insertions, 7 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 28e40f43f3beea..d075e42cfc89d4 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -120,8 +120,25 @@ static resource_size_t get_res_add_size(struct list_head *head, return 0; } +static resource_size_t __pci_resource_alignment( + struct pci_dev *dev, + struct resource *r, + struct list_head *realloc_head) +{ + resource_size_t r_align, add_size = 0; + + if ((r->flags & IORESOURCE_SIZEALIGN) && realloc_head) + add_size = get_res_add_size(realloc_head, r); + r->end += add_size; + r_align = pci_resource_alignment(dev, r); + r->end -= add_size; + + return r_align; +} /* Sort resources by alignment */ -static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) +static void pdev_sort_resources(struct pci_dev *dev, + struct list_head *realloc_head, + struct list_head *head) { int i; struct resource *r; @@ -137,7 +154,7 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) if (!(r->flags) || r->parent) continue; - r_align = pci_resource_alignment(dev, r); + r_align = __pci_resource_alignment(dev, r, realloc_head); if (!r_align) { dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n", i, r); @@ -157,8 +174,9 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) list_for_each_entry(dev_res, head, list) { resource_size_t align; - align = pci_resource_alignment(dev_res->dev, - dev_res->res); + align = __pci_resource_alignment(dev_res->dev, + dev_res->res, + realloc_head); if (r_align > align || (r_align == align && @@ -173,6 +191,7 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) } static void __dev_sort_resources(struct pci_dev *dev, + struct list_head *realloc_head, struct list_head *head) { u16 class = dev->class >> 8; @@ -189,7 +208,7 @@ static void __dev_sort_resources(struct pci_dev *dev, return; } - pdev_sort_resources(dev, head); + pdev_sort_resources(dev, realloc_head, head); } static inline void reset_resource(struct resource *res) @@ -385,7 +404,7 @@ static void pdev_assign_resources_sorted(struct pci_dev *dev, { LIST_HEAD(head); - __dev_sort_resources(dev, &head); + __dev_sort_resources(dev, add_head, &head); __assign_resources_sorted(&head, add_head, fail_head); } @@ -398,7 +417,7 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus, LIST_HEAD(head); list_for_each_entry(dev, &bus->devices, bus_list) - __dev_sort_resources(dev, &head); + __dev_sort_resources(dev, realloc_head, &head); __assign_resources_sorted(&head, realloc_head, fail_head); } |