Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb0a90b4 authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds
Browse files

[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: default avatarDominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 27879835
Loading
Loading
Loading
Loading
+88 −38
Original line number Original line Diff line number Diff line
@@ -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;
			config_writel(socket, addr_start, res->start);
		end = ~0U;
			config_writel(socket, addr_end, res->end);
		}
	} else {
	} else {
		unsigned long avail = root->end - root->start;
		if (type & IORESOURCE_PREFETCH) {
		int i;
			if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) ||
		size = BRIDGE_MEM_MAX;
			    (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) ||
		if (size > avail/8) {
			    (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) {
			size=(avail+1)/8;
				config_writel(socket, addr_start, res->start);
			/* round size down to next power of 2 */
				config_writel(socket, addr_end, res->end);
			i = 0;
			while ((size /= 2) != 0)
				i++;
			size = 1 << i;
			}
			}
		if (size < BRIDGE_MEM_MIN)
			/* Approximating prefetchable by non-prefetchable */
			size = BRIDGE_MEM_MIN;
			res->flags = IORESOURCE_MEM;
		min = BRIDGE_MEM_MIN;
		align = size;
		start = PCIBIOS_MIN_MEM;
		end = ~0U;
		}
		}
	
		if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) ||
	do {
		    (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) ||
		if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) {
		    (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) {
			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;
	}
		align = size;

	} while (size >= min);
	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;
}
}


/*
/*