From: Dominik Brodowski The current CardBus window allocation code in yenta_socket is unable to handle the transparent PCI-bridge handling update in 2.6.13. We need to check _all_ resources of a given type to find the best one suitable for CardBus windows, not just the first one. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton --- drivers/pcmcia/yenta_socket.c | 126 +++++++++++++++++++++++++++++------------- 1 files changed, 88 insertions(+), 38 deletions(-) diff -puN drivers/pcmcia/yenta_socket.c~yenta-allocate-resource-fixes drivers/pcmcia/yenta_socket.c --- 25/drivers/pcmcia/yenta_socket.c~yenta-allocate-resource-fixes Mon Jul 11 17:25:47 2005 +++ 25-akpm/drivers/pcmcia/yenta_socket.c Mon Jul 11 17:25:47 2005 @@ -591,24 +591,87 @@ 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_MAX 512 +#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 int yenta_search_one_res(struct resource *root, struct resource *res, + u32 min) +{ + u32 align, size, start, end; + + if (res->flags & IORESOURCE_IO) { + align = 1024; + size = BRIDGE_IO_MAX; + start = PCIBIOS_MIN_CARDBUS_IO; + end = ~0U; + } else { + unsigned long avail = root->end - root->start; + int i; + size = BRIDGE_MEM_MAX; + if (size > avail/8) { + size=(avail+1)/8; + /* round size down to next power of 2 */ + i = 0; + while ((size /= 2) != 0) + i++; + size = 1 << i; + } + if (size < min) + size = min; + align = size; + start = PCIBIOS_MIN_MEM; + end = ~0U; + } + + do { + if (allocate_resource(root, res, size, start, end, align, + NULL, NULL)==0) { + return 1; + } + size = size/2; + align = size; + } while (size >= min); + + return 0; +} + + +static int yenta_search_res(struct yenta_socket *socket, struct resource *res, + u32 min) +{ + int i; + for (i=0; idev->bus->resource[i]; + if (!root) + continue; + + if ((res->flags ^ root->flags) & + (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH)) + continue; /* Wrong type */ + + if (yenta_search_one_res(root, res, min)) + return 1; + } + return 0; +} + static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) { struct pci_bus *bus; struct resource *root, *res; u32 start, end; - u32 align, size, min; unsigned mask; res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; @@ -637,48 +700,35 @@ static void yenta_allocate_res(struct ye pci_name(socket->dev), nr); } - res->start = 0; - res->end = 0; - root = pci_find_parent_resource(socket->dev, res); - if (type & IORESOURCE_IO) { - align = 1024; - size = BRIDGE_IO_MAX; - min = BRIDGE_IO_MIN; - start = PCIBIOS_MIN_CARDBUS_IO; - end = ~0U; + if ((yenta_search_res(socket, res, BRIDGE_IO_MAX)) || + (yenta_search_res(socket, res, BRIDGE_IO_ACC)) || + (yenta_search_res(socket, res, BRIDGE_IO_MIN))) { + config_writel(socket, addr_start, res->start); + config_writel(socket, addr_end, res->end); + } } else { - unsigned long avail = root->end - root->start; - int i; - size = BRIDGE_MEM_MAX; - if (size > avail/8) { - size=(avail+1)/8; - /* round size down to next power of 2 */ - i = 0; - while ((size /= 2) != 0) - i++; - size = 1 << i; + if (type & IORESOURCE_PREFETCH) { + if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || + (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || + (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { + config_writel(socket, addr_start, res->start); + config_writel(socket, addr_end, res->end); + } + /* Approximating prefetchable by non-prefetchable */ + res->flags = IORESOURCE_MEM; } - if (size < BRIDGE_MEM_MIN) - size = BRIDGE_MEM_MIN; - 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) { + if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || + (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || + (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { config_writel(socket, addr_start, res->start); config_writel(socket, addr_end, res->end); - return; } - size = size/2; - align = size; - } while (size >= min); + } + 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; + pci_name(socket->dev), type); + res->start = res->end = res->flags = 0; } /* _