aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2012-09-17 22:25:35 -0700
committerYinghai Lu <yinghai@kernel.org>2012-09-17 22:25:35 -0700
commitead29924bbddcf583ff6153eb0e6f3310b185583 (patch)
tree67f8891baf83f31d50d7de0fd2e2a53dacc5a279
parent713695faf3aacad7e47620e3e9b8b2c8c1060644 (diff)
downloadlinux-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.c33
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);
}