From: Greg Kroah-Hartman Date: Wed, 21 Nov 2012 20:40:23 +0000 (-0800) Subject: 3.0-stable patches X-Git-Tag: v3.0.53~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=15dd0666c91f1683848e81246dd0471051781e8a;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0-stable patches added patches: pci-ability-to-relocate-assigned-pci-resources.patch pci-calculate-right-add_size.patch --- diff --git a/queue-3.0/pci-ability-to-relocate-assigned-pci-resources.patch b/queue-3.0/pci-ability-to-relocate-assigned-pci-resources.patch new file mode 100644 index 00000000000..3bc3a831ff1 --- /dev/null +++ b/queue-3.0/pci-ability-to-relocate-assigned-pci-resources.patch @@ -0,0 +1,325 @@ +From 2bbc6942273b5b3097bd265d82227bdd84b351b2 Mon Sep 17 00:00:00 2001 +From: Ram Pai +Date: Mon, 25 Jul 2011 13:08:39 -0700 +Subject: PCI : ability to relocate assigned pci-resources + +From: Ram Pai + +commit 2bbc6942273b5b3097bd265d82227bdd84b351b2 upstream. + +Currently pci-bridges are allocated enough resources to satisfy their immediate +requirements. Any additional resource-requests fail if additional free space, +contiguous to the one already allocated, is not available. This behavior is not +reasonable since sufficient contiguous resources, that can satisfy the request, +are available at a different location. + +This patch provides the ability to expand and relocate a allocated resource. + + v2: Changelog: Fixed size calculation in pci_reassign_resource() + v3: Changelog : Split this patch. The resource.c changes are already + upstream. All the pci driver changes are in here. + +Signed-off-by: Ram Pai +Signed-off-by: Jesse Barnes +Cc: Andrew Worsley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/setup-bus.c | 27 +++++--- + drivers/pci/setup-res.c | 150 ++++++++++++++++++++++++++++++------------------ + include/linux/pci.h | 1 + 3 files changed, 112 insertions(+), 66 deletions(-) + +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -34,6 +34,7 @@ struct resource_list_x { + resource_size_t start; + resource_size_t end; + resource_size_t add_size; ++ resource_size_t min_align; + unsigned long flags; + }; + +@@ -65,7 +66,7 @@ void pci_realloc(void) + */ + static void add_to_list(struct resource_list_x *head, + struct pci_dev *dev, struct resource *res, +- resource_size_t add_size) ++ resource_size_t add_size, resource_size_t min_align) + { + struct resource_list_x *list = head; + struct resource_list_x *ln = list->next; +@@ -84,13 +85,16 @@ static void add_to_list(struct resource_ + tmp->end = res->end; + tmp->flags = res->flags; + tmp->add_size = add_size; ++ tmp->min_align = min_align; + list->next = tmp; + } + + static void add_to_failed_list(struct resource_list_x *head, + struct pci_dev *dev, struct resource *res) + { +- add_to_list(head, dev, res, 0); ++ add_to_list(head, dev, res, ++ 0 /* dont care */, ++ 0 /* dont care */); + } + + static void __dev_sort_resources(struct pci_dev *dev, +@@ -159,13 +163,16 @@ static void adjust_resources_sorted(stru + + idx = res - &list->dev->resource[0]; + add_size=list->add_size; +- if (!resource_size(res) && add_size) { +- res->end = res->start + add_size - 1; +- if(pci_assign_resource(list->dev, idx)) ++ if (!resource_size(res)) { ++ res->end = res->start + add_size - 1; ++ if(pci_assign_resource(list->dev, idx)) + reset_resource(res); +- } else if (add_size) { +- adjust_resource(res, res->start, +- resource_size(res) + add_size); ++ } else { ++ resource_size_t align = list->min_align; ++ res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); ++ if (pci_reassign_resource(list->dev, idx, add_size, align)) ++ dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n", ++ res); + } + out: + tmp = list; +@@ -622,7 +629,7 @@ static void pbus_size_io(struct pci_bus + b_res->end = b_res->start + size0 - 1; + b_res->flags |= IORESOURCE_STARTALIGN; + if (size1 > size0 && add_head) +- add_to_list(add_head, bus->self, b_res, size1-size0); ++ add_to_list(add_head, bus->self, b_res, size1-size0, 4096); + } + + /** +@@ -725,7 +732,7 @@ static int pbus_size_mem(struct pci_bus + b_res->end = size0 + min_align - 1; + b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask; + if (size1 > size0 && add_head) +- add_to_list(add_head, bus->self, b_res, size1-size0); ++ add_to_list(add_head, bus->self, b_res, size1-size0, min_align); + return 1; + } + +--- a/drivers/pci/setup-res.c ++++ b/drivers/pci/setup-res.c +@@ -129,16 +129,16 @@ void pci_disable_bridge_window(struct pc + } + #endif /* CONFIG_PCI_QUIRKS */ + ++ ++ + static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, +- int resno) ++ int resno, resource_size_t size, resource_size_t align) + { + struct resource *res = dev->resource + resno; +- resource_size_t size, min, align; ++ resource_size_t min; + int ret; + +- size = resource_size(res); + min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; +- align = pci_resource_alignment(dev, res); + + /* First, try exact prefetching match.. */ + ret = pci_bus_alloc_resource(bus, res, size, align, min, +@@ -155,56 +155,101 @@ static int __pci_assign_resource(struct + ret = pci_bus_alloc_resource(bus, res, size, align, min, 0, + pcibios_align_resource, dev); + } ++ return ret; ++} + +- if (ret < 0 && dev->fw_addr[resno]) { +- struct resource *root, *conflict; +- resource_size_t start, end; ++static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev, ++ int resno, resource_size_t size) ++{ ++ struct resource *root, *conflict; ++ resource_size_t start, end; ++ int ret = 0; ++ ++ if (res->flags & IORESOURCE_IO) ++ root = &ioport_resource; ++ else ++ root = &iomem_resource; ++ ++ start = res->start; ++ end = res->end; ++ res->start = dev->fw_addr[resno]; ++ res->end = res->start + size - 1; ++ dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n", ++ resno, res); ++ conflict = request_resource_conflict(root, res); ++ if (conflict) { ++ dev_info(&dev->dev, ++ "BAR %d: %pR conflicts with %s %pR\n", resno, ++ res, conflict->name, conflict); ++ res->start = start; ++ res->end = end; ++ ret = 1; ++ } ++ return ret; ++} + +- /* +- * If we failed to assign anything, let's try the address +- * where firmware left it. That at least has a chance of +- * working, which is better than just leaving it disabled. +- */ ++static int _pci_assign_resource(struct pci_dev *dev, int resno, int size, resource_size_t min_align) ++{ ++ struct resource *res = dev->resource + resno; ++ struct pci_bus *bus; ++ int ret; ++ char *type; + +- if (res->flags & IORESOURCE_IO) +- root = &ioport_resource; ++ bus = dev->bus; ++ while ((ret = __pci_assign_resource(bus, dev, resno, size, min_align))) { ++ if (!bus->parent || !bus->self->transparent) ++ break; ++ bus = bus->parent; ++ } ++ ++ if (ret) { ++ if (res->flags & IORESOURCE_MEM) ++ if (res->flags & IORESOURCE_PREFETCH) ++ type = "mem pref"; ++ else ++ type = "mem"; ++ else if (res->flags & IORESOURCE_IO) ++ type = "io"; + else +- root = &iomem_resource; ++ type = "unknown"; ++ dev_info(&dev->dev, ++ "BAR %d: can't assign %s (size %#llx)\n", ++ resno, type, (unsigned long long) resource_size(res)); ++ } + +- start = res->start; +- end = res->end; +- res->start = dev->fw_addr[resno]; +- res->end = res->start + size - 1; +- dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n", +- resno, res); +- conflict = request_resource_conflict(root, res); +- if (conflict) { +- dev_info(&dev->dev, +- "BAR %d: %pR conflicts with %s %pR\n", resno, +- res, conflict->name, conflict); +- res->start = start; +- res->end = end; +- } else +- ret = 0; ++ return ret; ++} ++ ++int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsize, ++ resource_size_t min_align) ++{ ++ struct resource *res = dev->resource + resno; ++ resource_size_t new_size; ++ int ret; ++ ++ if (!res->parent) { ++ dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resouce %pR " ++ "\n", resno, res); ++ return -EINVAL; + } + ++ new_size = resource_size(res) + addsize + min_align; ++ ret = _pci_assign_resource(dev, resno, new_size, min_align); + if (!ret) { + res->flags &= ~IORESOURCE_STARTALIGN; + dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res); + if (resno < PCI_BRIDGE_RESOURCES) + pci_update_resource(dev, resno); + } +- + return ret; + } + + int pci_assign_resource(struct pci_dev *dev, int resno) + { + struct resource *res = dev->resource + resno; +- resource_size_t align; ++ resource_size_t align, size; + struct pci_bus *bus; + int ret; +- char *type; + + align = pci_resource_alignment(dev, res); + if (!align) { +@@ -214,34 +259,27 @@ int pci_assign_resource(struct pci_dev * + } + + bus = dev->bus; +- while ((ret = __pci_assign_resource(bus, dev, resno))) { +- if (bus->parent && bus->self->transparent) +- bus = bus->parent; +- else +- bus = NULL; +- if (bus) +- continue; +- break; +- } ++ size = resource_size(res); ++ ret = _pci_assign_resource(dev, resno, size, align); + +- if (ret) { +- if (res->flags & IORESOURCE_MEM) +- if (res->flags & IORESOURCE_PREFETCH) +- type = "mem pref"; +- else +- type = "mem"; +- else if (res->flags & IORESOURCE_IO) +- type = "io"; +- else +- type = "unknown"; +- dev_info(&dev->dev, +- "BAR %d: can't assign %s (size %#llx)\n", +- resno, type, (unsigned long long) resource_size(res)); +- } ++ /* ++ * If we failed to assign anything, let's try the address ++ * where firmware left it. That at least has a chance of ++ * working, which is better than just leaving it disabled. ++ */ ++ if (ret < 0 && dev->fw_addr[resno]) ++ ret = pci_revert_fw_address(res, dev, resno, size); + ++ if (!ret) { ++ res->flags &= ~IORESOURCE_STARTALIGN; ++ dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res); ++ if (resno < PCI_BRIDGE_RESOURCES) ++ pci_update_resource(dev, resno); ++ } + return ret; + } + ++ + /* Sort resources by alignment */ + void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) + { +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -800,6 +800,7 @@ int __pci_reset_function(struct pci_dev + int pci_reset_function(struct pci_dev *dev); + void pci_update_resource(struct pci_dev *dev, int resno); + int __must_check pci_assign_resource(struct pci_dev *dev, int i); ++int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align); + int pci_select_bars(struct pci_dev *dev, unsigned long flags); + + /* ROM control related routines */ diff --git a/queue-3.0/pci-calculate-right-add_size.patch b/queue-3.0/pci-calculate-right-add_size.patch new file mode 100644 index 00000000000..287337df8d9 --- /dev/null +++ b/queue-3.0/pci-calculate-right-add_size.patch @@ -0,0 +1,105 @@ +From a4ac9fea016fc5c09227eb479bd35e34978323a4 Mon Sep 17 00:00:00 2001 +From: Yinghai Lu +Date: Sat, 21 Jan 2012 02:08:17 -0800 +Subject: PCI : Calculate right add_size + +From: Yinghai Lu + +commit a4ac9fea016fc5c09227eb479bd35e34978323a4 upstream. + +During debug of one SRIOV enabled hotplug device, we found found that +add_size is not passed properly. + +The device has devices under two level bridges: + + +-[0000:80]-+-00.0-[81-8f]-- + | +-01.0-[90-9f]-- + | +-02.0-[a0-af]----00.0-[a1-a3]--+-02.0-[a2]--+-00.0 Oracle Corporation Device + | | \-03.0-[a3]--+-00.0 Oracle Corporation Device + +Which means later the parent bridge will not try to add a big enough range: + +[ 557.455077] pci 0000:a0:00.0: BAR 14: assigned [mem 0xf9000000-0xf93fffff] +[ 557.461974] pci 0000:a0:00.0: BAR 15: assigned [mem 0xf6000000-0xf61fffff pref] +[ 557.469340] pci 0000:a1:02.0: BAR 14: assigned [mem 0xf9000000-0xf91fffff] +[ 557.476231] pci 0000:a1:02.0: BAR 15: assigned [mem 0xf6000000-0xf60fffff pref] +[ 557.483582] pci 0000:a1:03.0: BAR 14: assigned [mem 0xf9200000-0xf93fffff] +[ 557.490468] pci 0000:a1:03.0: BAR 15: assigned [mem 0xf6100000-0xf61fffff pref] +[ 557.497833] pci 0000:a1:03.0: BAR 14: can't assign mem (size 0x200000) +[ 557.504378] pci 0000:a1:03.0: failed to add optional resources res=[mem 0xf9200000-0xf93fffff] +[ 557.513026] pci 0000:a1:02.0: BAR 14: can't assign mem (size 0x200000) +[ 557.519578] pci 0000:a1:02.0: failed to add optional resources res=[mem 0xf9000000-0xf91fffff] + +It turns out we did not calculate size1 properly. + +static resource_size_t calculate_memsize(resource_size_t size, + resource_size_t min_size, + resource_size_t size1, + resource_size_t old_size, + resource_size_t align) +{ + if (size < min_size) + size = min_size; + if (old_size == 1 ) + old_size = 0; + if (size < old_size) + size = old_size; + size = ALIGN(size + size1, align); + return size; +} + +We should not pass add_size with min_size in calculate_memsize since +that will make add_size not contribute final add_size. + +So just pass add_size with size1 to calculate_memsize(). + +With this change, we should have chance to remove extra addon in +pci_reassign_resource. + +Signed-off-by: Yinghai Lu +Signed-off-by: Jesse Barnes +Cc: Andrew Worsley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/setup-bus.c | 4 ++-- + drivers/pci/setup-res.c | 5 +++-- + 2 files changed, 5 insertions(+), 4 deletions(-) + +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -614,7 +614,7 @@ static void pbus_size_io(struct pci_bus + if (children_add_size > add_size) + add_size = children_add_size; + size1 = (!add_head || (add_head && !add_size)) ? size0 : +- calculate_iosize(size, min_size+add_size, size1, ++ calculate_iosize(size, min_size, add_size + size1, + resource_size(b_res), 4096); + if (!size0 && !size1) { + if (b_res->start || b_res->end) +@@ -718,7 +718,7 @@ static int pbus_size_mem(struct pci_bus + if (children_add_size > add_size) + add_size = children_add_size; + size1 = (!add_head || (add_head && !add_size)) ? size0 : +- calculate_memsize(size, min_size+add_size, 0, ++ calculate_memsize(size, min_size, add_size, + resource_size(b_res), min_align); + if (!size0 && !size1) { + if (b_res->start || b_res->end) +--- a/drivers/pci/setup-res.c ++++ b/drivers/pci/setup-res.c +@@ -233,11 +233,12 @@ int pci_reassign_resource(struct pci_dev + return -EINVAL; + } + +- new_size = resource_size(res) + addsize + min_align; ++ /* already aligned with min_align */ ++ new_size = resource_size(res) + addsize; + ret = _pci_assign_resource(dev, resno, new_size, min_align); + if (!ret) { + res->flags &= ~IORESOURCE_STARTALIGN; +- dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res); ++ dev_info(&dev->dev, "BAR %d: reassigned %pR\n", resno, res); + if (resno < PCI_BRIDGE_RESOURCES) + pci_update_resource(dev, resno); + } diff --git a/queue-3.0/series b/queue-3.0/series index f23eb477ebc..eb122b4bd0e 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -34,3 +34,5 @@ reiserfs-protect-reiserfs_quota_on-with-write-lock.patch reiserfs-move-quota-calls-out-of-write-lock.patch reiserfs-protect-reiserfs_quota_write-with-write-lock.patch selinux-fix-sel_netnode_insert-suspicious-rcu-dereference.patch +pci-ability-to-relocate-assigned-pci-resources.patch +pci-calculate-right-add_size.patch