Signed-off-by: Yu Zhao <yu.zhao@xxxxxxxxx> --- drivers/char/agp/intel-agp.c | 2 +- drivers/pci/bus.c | 5 ++- drivers/pci/setup-res.c | 59 ++++++++++++++++++++++++++++++++++++-- drivers/pcmcia/rsrc_mgr.c | 2 +- drivers/pcmcia/rsrc_nonstatic.c | 4 +- include/linux/pci.h | 2 +- 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index c771418..a811fc4 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -886,7 +886,7 @@ static int intel_alloc_chipset_flush_resource(void) { int ret; ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE, - PAGE_SIZE, PCIBIOS_MIN_MEM, 0, + PAGE_SIZE, PCIBIOS_MIN_MEM, -1, 0, pcibios_align_resource, agp_bridge->dev); return ret; diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 52b54f0..b9038ed 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -35,7 +35,8 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t size, resource_size_t align, - resource_size_t min, unsigned int type_mask, + resource_size_t min, resource_size_t max, + unsigned int type_mask, void (*alignf)(void *, struct resource *, resource_size_t, resource_size_t), void *alignf_data) @@ -62,7 +63,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, /* Ok, try it out.. */ ret = allocate_resource(r, res, size, r->start ? : min, - -1, align, + max, align, alignf, alignf_data); if (ret == 0) break; diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 32e8d88..2703889 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -120,11 +120,60 @@ int pci_claim_resource(struct pci_dev *dev, int resource) return err; } +static resource_size_t pci_resource_limit(struct pci_dev *dev, int resno) +{ + u8 io; + u16 mem; + struct resource *res = dev->resource + resno; + + if (resno < PCI_BRIDGE_RESOURCES) { + /* Memory BAR could be 64-bit */ + if ((res->flags & PCI_BASE_ADDRESS_SPACE) == + PCI_BASE_ADDRESS_SPACE_MEMORY && + (res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + return (u64)-1; + + /* I/O and ROM BAR are always 32-bit */ + return (u32)-1; + } + + resno -= PCI_BRIDGE_RESOURCES; + + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + if (resno == PCI_BRIDGE_IO) { + /* I/O window could be 16 or 32-bit */ + pci_read_config_byte(dev, PCI_IO_BASE, &io); + return (io & 0xf) ? (u32)-1 : (u16)-1; + } + if (resno == PCI_BRIDGE_MEM) + /* Memory window is always 32-bit */ + return (u32)-1; + + if (resno == PCI_BRIDGE_PREF_MEM) { + /* Prefetch memory window could be 32 or 64-bit */ + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem); + return (mem & 0xf) ? (u64)-1 : (u32)-1; + } + } + + if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { + /* Cardbus resource windows are always 32-bit??? */ + if (resno < PCI_CARDBUS_MAX_RESOURCE) + return (u32)-1; + } + + dev_err(&dev->dev, "BAR %d: unknown resource %pR flags %#lx\n", + resno, res, res->flags); + + return -1; +} + int pci_assign_resource(struct pci_dev *dev, int resno) { struct pci_bus *bus = dev->bus; struct resource *res = dev->resource + resno; - resource_size_t size, min, align; + resource_size_t size, min, max, align; int ret; size = resource_size(res); @@ -138,8 +187,10 @@ int pci_assign_resource(struct pci_dev *dev, int resno) return -EINVAL; } + max = pci_resource_limit(dev, resno); + /* First, try exact prefetching match.. */ - ret = pci_bus_alloc_resource(bus, res, size, align, min, + ret = pci_bus_alloc_resource(bus, res, size, align, min, max, IORESOURCE_PREFETCH, pcibios_align_resource, dev); @@ -150,8 +201,8 @@ int pci_assign_resource(struct pci_dev *dev, int resno) * But a prefetching area can handle a non-prefetching * window (it will just not perform as well). */ - ret = pci_bus_alloc_resource(bus, res, size, align, min, 0, - pcibios_align_resource, dev); + ret = pci_bus_alloc_resource(bus, res, size, align, min, max, + 0, pcibios_align_resource, dev); } if (ret) { diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index c0e2afc..35bd25e 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -167,7 +167,7 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num, #ifdef CONFIG_PCI if (s->cb_dev) { ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, - min, 0, pcmcia_align, &data); + min, -1, 0, pcmcia_align, &data); } else #endif ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 9ca22c7..46cb9b7 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -641,7 +641,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num, #ifdef CONFIG_PCI if (s->cb_dev) { ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, - min, 0, pcmcia_align, &data); + min, -1, 0, pcmcia_align, &data); } else #endif ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, @@ -683,7 +683,7 @@ static struct resource * nonstatic_find_mem_region(u_long base, u_long num, #ifdef CONFIG_PCI if (s->cb_dev) { ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, - 1, min, 0, + 1, min, -1, 0, pcmcia_align, &data); } else #endif diff --git a/include/linux/pci.h b/include/linux/pci.h index 8841c8a..e208b24 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -760,7 +760,7 @@ void pci_release_selected_regions(struct pci_dev *, int); int __must_check pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t size, resource_size_t align, resource_size_t min, - unsigned int type_mask, + resource_size_t max, unsigned int type_mask, void (*alignf)(void *, struct resource *, resource_size_t, resource_size_t), void *alignf_data); -- 1.5.6.4 -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html