[PATCH 03/36] PCI: Use correct align for optional only resources during sorting for resource allocation

Yinghai Lu
2015-07-06T23:41:06Z

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 <linux@iam.tj>
Signed-off-by: Yinghai Lu <yinghai@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