From d09ee9687e027fc7d2c6b95daf05a8ef3ff06340 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 23 Apr 2009 20:49:25 -0700 Subject: PCI: improve resource allocation under transparent bridges We could run out of space under under 4g, but devices under transparent bridges can use 64bit resources, so keep trying on the parent bus until we hit a non-transparent bridge. Impact: better support for assigning unassigned resources Reviewed-by: Ivan Kokshaysky Signed-off-by: Yinghai Lu Signed-off-by: Jesse Barnes --- drivers/pci/setup-res.c | 49 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) (limited to 'drivers/pci/setup-res.c') diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 3039fcb86af..0b6908b4893 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -135,23 +135,16 @@ void pci_disable_bridge_window(struct pci_dev *dev) } #endif /* CONFIG_PCI_QUIRKS */ -int pci_assign_resource(struct pci_dev *dev, int resno) +static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, + int resno) { - struct pci_bus *bus = dev->bus; struct resource *res = dev->resource + resno; resource_size_t size, min, align; int ret; size = resource_size(res); min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; - align = resource_alignment(res); - if (!align) { - dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " - "alignment) %pR flags %#lx\n", - resno, res, res->flags); - return -EINVAL; - } /* First, try exact prefetching match.. */ ret = pci_bus_alloc_resource(bus, res, size, align, min, @@ -169,10 +162,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno) pcibios_align_resource, dev); } - if (ret) { - dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n", - resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res); - } else { + if (!ret) { res->flags &= ~IORESOURCE_STARTALIGN; if (resno < PCI_BRIDGE_RESOURCES) pci_update_resource(dev, resno); @@ -181,6 +171,39 @@ int pci_assign_resource(struct pci_dev *dev, int resno) return ret; } +int pci_assign_resource(struct pci_dev *dev, int resno) +{ + struct resource *res = dev->resource + resno; + resource_size_t align; + struct pci_bus *bus; + int ret; + + align = resource_alignment(res); + if (!align) { + dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " + "alignment) %pR flags %#lx\n", + resno, res, res->flags); + return -EINVAL; + } + + 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; + } + + if (ret) + dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n", + resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res); + + return ret; +} + #if 0 int pci_assign_resource_fixed(struct pci_dev *dev, int resno) { -- cgit v1.2.3-70-g09d2 From cebd78a8c5624b5cf04c39c3335a5fc8670a7b69 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 17 Jun 2009 16:33:33 -0400 Subject: Fix pci_claim_resource Instead of starting from the iomem or ioport roots, start from the parent bus' resources. This fixes a bug where child resources would appear above their parents resources if they had the same size. Signed-off-by: Matthew Wilcox Tested-by: Andrew Patterson Signed-off-by: Linus Torvalds --- drivers/pci/setup-res.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/setup-res.c') diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 3039fcb86af..12403516776 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -99,11 +99,11 @@ void pci_update_resource(struct pci_dev *dev, int resno) int pci_claim_resource(struct pci_dev *dev, int resource) { struct resource *res = &dev->resource[resource]; - struct resource *root = NULL; + struct resource *root; char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge"; int err; - root = pcibios_select_root(dev, res); + root = pci_find_parent_resource(dev, res); err = -EINVAL; if (root != NULL) -- cgit v1.2.3-70-g09d2