[PATCH] yenta: allocate resource fixes

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 <linux@dominikbrodowski.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Dominik Brodowski 2005-07-12 13:58:17 -07:00 коммит произвёл Linus Torvalds
Родитель 278798357d
Коммит eb0a90b497
1 изменённых файлов: 90 добавлений и 40 удалений

Просмотреть файл

@ -527,24 +527,87 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock)
* Use an adaptive allocation for the memory resource, * Use an adaptive allocation for the memory resource,
* sometimes the memory behind pci bridges is limited: * sometimes the memory behind pci bridges is limited:
* 1/8 of the size of the io window of the parent. * 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_MAX 4*1024*1024
#define BRIDGE_MEM_ACC 128*1024
#define BRIDGE_MEM_MIN 16*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 #define BRIDGE_IO_MIN 32
#ifndef PCIBIOS_MIN_CARDBUS_IO #ifndef PCIBIOS_MIN_CARDBUS_IO
#define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO #define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO
#endif #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; i<PCI_BUS_NUM_RESOURCES; i++) {
struct resource * root = socket->dev->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) static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end)
{ {
struct pci_bus *bus; struct pci_bus *bus;
struct resource *root, *res; struct resource *root, *res;
u32 start, end; u32 start, end;
u32 align, size, min;
unsigned mask; unsigned mask;
res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
@ -573,48 +636,35 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ
pci_name(socket->dev), nr); pci_name(socket->dev), nr);
} }
res->start = 0;
res->end = 0;
root = pci_find_parent_resource(socket->dev, res);
if (type & IORESOURCE_IO) { if (type & IORESOURCE_IO) {
align = 1024; if ((yenta_search_res(socket, res, BRIDGE_IO_MAX)) ||
size = BRIDGE_IO_MAX; (yenta_search_res(socket, res, BRIDGE_IO_ACC)) ||
min = BRIDGE_IO_MIN; (yenta_search_res(socket, res, BRIDGE_IO_MIN))) {
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 < 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) {
config_writel(socket, addr_start, res->start); config_writel(socket, addr_start, res->start);
config_writel(socket, addr_end, res->end); config_writel(socket, addr_end, res->end);
return;
} }
size = size/2; } else {
align = size; if (type & IORESOURCE_PREFETCH) {
} while (size >= min); 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 ((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);
}
}
printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n",
pci_name(socket->dev), type); pci_name(socket->dev), type);
res->start = res->end = 0; res->start = res->end = res->flags = 0;
} }
/* /*