During sorting before assign, we only put resource with non-zero align
in the sorted list, so for optional resources that must part is 0 and only
have addon parts, we need to have correct align.

Use addon resource align instead in that case.

Sorted list will contain must res align/size to 0/0 to hold spot for
optional resources.

And later we will treat the ROM BAR as optional resource with this support.

The patch will pass realloc_head from sizing stage to sorting stage, and
get entry from realloc and calculate align from the entry.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=81431
Reported-by: TJ <li...@iam.tj>
Signed-off-by: Yinghai Lu <ying...@kernel.org>
---
 drivers/pci/setup-bus.c | 45 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 38 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 247d8fe..9f4c477 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -145,9 +145,38 @@ static resource_size_t get_res_add_align(struct list_head 
*head,
        return dev_res->min_align;
 }
 
+static resource_size_t __pci_resource_alignment(
+                               struct pci_dev *dev,
+                               struct resource *r,
+                               struct list_head *realloc_head)
+{
+       resource_size_t r_align = pci_resource_alignment(dev, r);
+       resource_size_t orig_start, orig_end;
+
+       if (r_align || !realloc_head)
+               return r_align;
+
+       orig_start = r->start;
+       orig_end = r->end;
+       r->end += get_res_add_size(realloc_head, r);
+       if ((r->flags & IORESOURCE_STARTALIGN)) {
+               resource_size_t r_size = resource_size(r);
+               resource_size_t add_align = get_res_add_align(realloc_head, r);
+
+               r->start = add_align;
+               r->end = add_align + r_size - 1;
+       }
+       r_align = pci_resource_alignment(dev, r);
+       r->start = orig_start;
+       r->end = orig_end;
+
+       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;
 
@@ -165,7 +194,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);
@@ -183,8 +212,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) {
                                n = &dev_res->list;
@@ -197,6 +227,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;
@@ -213,7 +244,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)
@@ -501,7 +532,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);
 
 }
@@ -514,7 +545,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);
 }
-- 
1.8.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to