From: Dominik Brodowski As a follow-up, we can make yenta_socket try harder to limit itself to the parent bridge windows. This is done by lowering the PCIBIOS_MIN_CARDBUS_IO and by updating yenta_allocate_res(). It now tries at first to get resources within the bridge windows, and if they are large enough (>=BRIDGE_{IO,MEM}_ACC), these are used. If no or only too small resources were found, it falls back to the resources behind the parent PCI bridge if this is "transparent". Using this patch may result in such "funny" /proc/ioports as: 2800-28ff : PCI CardBus #07 3000-3fff : PCI Bus #02 3000-303f : 0000:02:08.0 3000-303f : e100 3400-34ff : PCI CardBus #03 3800-38ff : PCI CardBus #03 3c00-3cff : PCI CardBus #07 There weren't enough properly aligned ports available inside PCI Bus #02 to stuff all four (2x2) IO windows into it, so one was taken outside the transparent PCI bridge ioport window. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton --- 25-akpm/drivers/pcmcia/yenta_socket.c | 41 +++++++++++++++++++++++----------- 25-akpm/include/asm-i386/pci.h | 2 - 2 files changed, 29 insertions(+), 14 deletions(-) diff -puN drivers/pcmcia/yenta_socket.c~pci-pci-transparent-bridge-handling-improvements-yenta_socket drivers/pcmcia/yenta_socket.c --- 25/drivers/pcmcia/yenta_socket.c~pci-pci-transparent-bridge-handling-improvements-yenta_socket Wed Mar 30 13:22:58 2005 +++ 25-akpm/drivers/pcmcia/yenta_socket.c Wed Mar 30 13:22:58 2005 @@ -516,19 +516,23 @@ static int yenta_sock_suspend(struct pcm * Use an adaptive allocation for the memory resource, * sometimes the memory behind pci bridges is limited: * 1/8 of the size of the io window of the parent. - * max 4 MB, min 16 kB. + * max 4 MB, min 16 kB. We try very hard to not get + * below the "ACC" values, though. */ #define BRIDGE_MEM_MAX 4*1024*1024 +#define BRIDGE_MEM_ACC 128*1024 #define BRIDGE_MEM_MIN 16*1024 #define BRIDGE_IO_MAX 256 +#define BRIDGE_IO_ACC 256 #define BRIDGE_IO_MIN 32 #ifndef PCIBIOS_MIN_CARDBUS_IO #define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO #endif -static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type) +static int yenta_try_allocate_res(struct yenta_socket *socket, int nr, + unsigned int type, unsigned int run) { struct pci_bus *bus; struct resource *root, *res; @@ -548,11 +552,11 @@ static void yenta_allocate_res(struct ye res->name = bus->name; res->flags = type; res->start = 0; - res->end = 0; + res->end = run; root = pci_find_parent_resource(socket->dev, res); if (!root) - return; + return -ENODEV; start = config_readl(socket, offset) & mask; end = config_readl(socket, offset+4) | ~mask; @@ -560,7 +564,8 @@ static void yenta_allocate_res(struct ye res->start = start; res->end = end; if (request_resource(root, res) == 0) - return; + return 0; + printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n", pci_name(socket->dev), nr); res->start = res->end = 0; @@ -569,12 +574,12 @@ static void yenta_allocate_res(struct ye if (type & IORESOURCE_IO) { align = 1024; size = BRIDGE_IO_MAX; - min = BRIDGE_IO_MIN; + min = run ? BRIDGE_IO_ACC : BRIDGE_IO_MIN; start = PCIBIOS_MIN_CARDBUS_IO; end = ~0U; } else { unsigned long avail = root->end - root->start; - int i; + u32 i; size = BRIDGE_MEM_MAX; if (size > avail/8) { size=(avail+1)/8; @@ -584,26 +589,36 @@ static void yenta_allocate_res(struct ye i++; size = 1 << i; } - if (size < BRIDGE_MEM_MIN) - size = BRIDGE_MEM_MIN; + i = run ? BRIDGE_MEM_ACC : BRIDGE_MEM_MIN; + if (size < i) + size = i; min = BRIDGE_MEM_MIN; align = size; start = PCIBIOS_MIN_MEM; end = ~0U; } - + do { if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) { config_writel(socket, offset, res->start); config_writel(socket, offset+4, res->end); - return; + return 0; } size = size/2; align = size; } while (size >= min); + + return -ENODEV; +} + +static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type) +{ + if (!(yenta_try_allocate_res(socket, nr, type, 1)) || + !(yenta_try_allocate_res(socket, nr, type, 0))) + return; + printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", pci_name(socket->dev), type); - res->start = res->end = 0; } /* @@ -614,7 +629,7 @@ static void yenta_allocate_resources(str yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); yenta_allocate_res(socket, 1, IORESOURCE_MEM); yenta_allocate_res(socket, 2, IORESOURCE_IO); - yenta_allocate_res(socket, 3, IORESOURCE_IO); /* PCI isn't clever enough to use this one yet */ + yenta_allocate_res(socket, 3, IORESOURCE_IO); } diff -puN include/asm-i386/pci.h~pci-pci-transparent-bridge-handling-improvements-yenta_socket include/asm-i386/pci.h --- 25/include/asm-i386/pci.h~pci-pci-transparent-bridge-handling-improvements-yenta_socket Wed Mar 30 13:22:58 2005 +++ 25-akpm/include/asm-i386/pci.h Wed Mar 30 13:22:58 2005 @@ -21,7 +21,7 @@ extern unsigned long pci_mem_start; #define PCIBIOS_MIN_IO 0x1000 #define PCIBIOS_MIN_MEM (pci_mem_start) -#define PCIBIOS_MIN_CARDBUS_IO 0x4000 +#define PCIBIOS_MIN_CARDBUS_IO 0x2000 void pcibios_config_init(void); struct pci_bus * pcibios_scan_root(int bus); _