Skip to contentSkip to conversation

reduce size of bridge regions for yenta.c]

PATCH H. J. Lu 2 participants 3 messages Aug 25, 2002 – Aug 27, 2002 1 message not in the archive Pcmcia

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

H. J. Lu

author
#1 lore raw

I don't like it at all. That change is not right. Usually the PCI bridge before the CardBus bridge is transparent. Please check out the Microsoft web site. Windows allocates 64MB region for each CardBus bridge by default and goes down from there. You should apply Ivan Kokshaysky's PCI bridge fix first. His first patch has a typo in it.

BTW, Guy, I bought an external USB-floppy drive. It is on sale at Fry's, $39.99. I can create a boot floopy on my Sony and boot from it.

H.J.

Quoted 134 lines · Andrew Morton

You guys may need this...

-------- Original Message --------
Subject: [PATCH] reduce size of bridge regions for yenta.c
Date: Sat, 24 Aug 2002 17:03:30 +0200
From: Manfred Spraul <[email protected]>
To: [email protected]
CC: [email protected], [email protected]

yenta.c tries to allocate 2 bridge regions, each 4 MB: one for prefetchable memory, one for non-prefetchable memory.

The size of the regions must be adaptive: in my laptop, the cardbus bridge sits behind a pci bridge with a 1 MB bridge region :-(

The attached patch:
- limits the memory window to 1/8 of the window of the parent bridge (max 4 MB, min 16 kB)
- frees the resources during module unload
- adds error checking+printk

Please test it - my laptop now works.
Patch vs. 2.4.19, applies to 2.5.30, too.

--
Manfred

drivers/pcmcia/yenta.c +55 -5
@@ -2,6 +2,11 @@
  * Regular lowlevel cardbus driver ("yenta")
  *
  * (C) Copyright 1999, 2000 Linus Torvalds
+ *
+ * Changelog:
+ * Aug 2002: Manfred Spraul <[email protected]>
+ * 	Dynamically adjust the size of the bridge resource
+ * 	
  */
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -704,6 +709,15 @@
 	return 0;
 }
 
+/*
+ * Use an adaptive allocation for the memory resource,
+ * sometimes the size behind pci bridges is limited:
+ * 1/8 of the size of the io window of the parent.
+ * max 4 MB, min 16 kB.
+ */
+#define BRIDGE_SIZE_MAX	4*1024*1024
+#define BRIDGE_SIZE_MIN	16*1024
+
 static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
 {
 	struct pci_bus *bus;
@@ -735,21 +749,42 @@
 	if (start && end > start) {
 		res->start = start;
 		res->end = end;
-		request_resource(root, res);
-		return;
+		if (request_resource(root, res) == 0)
+			return;
+		printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n",
+				socket->dev->slot_name, nr);
+		res->start = res->end = 0;
 	}
 
-	align = size = 4*1024*1024;
-	min = PCIBIOS_MIN_MEM; max = ~0U;
 	if (type & IORESOURCE_IO) {
 		align = 1024;
 		size = 256;
 		min = 0x4000;
 		max = 0xffff;
+	} else {
+		unsigned long avail = root->end - root->start;
+		int i;
+		align = size = BRIDGE_SIZE_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_SIZE_MIN)
+			size = BRIDGE_SIZE_MIN;
+		align = size;
+		min = PCIBIOS_MIN_MEM; max = ~0U;
 	}
 
-	if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0)
+	if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0) {
+		printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n",
+				socket->dev->slot_name, type);
+		res->start = res->end = 0;
 		return;
+	}
 
 	config_writel(socket, offset, res->start);
 	config_writel(socket, offset+4, res->end);
@@ -767,6 +802,20 @@
 }
 
 /*
+ * Free the bridge mappings for the device..
+ */
+static void yenta_free_resources(pci_socket_t *socket)
+{
+	int i;
+	for (i=0;i<4;i++) {
+		struct resource *res;
+		res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i;
+		if (res->start != 0 && res->end != 0)
+			release_resource(res);
+		res->start = res->end = 0;
+	}
+}
+/*
  * Close it down - release our resources and go home..
  */
 static void yenta_close(pci_socket_t *sock)
@@ -782,6 +831,7 @@
 
 	if (sock->base)
 		iounmap(sock->base);
+	yenta_free_resources(sock);
 }
 
 #include "ti113x.h"
#2 lore raw
Quoted 2 lines · H. J. Lu

I don't like it at all. That change is not right. Usually the PCI bridge before the CardBus bridge is transparent.

And what if the PCI bridge is not transparent? What if it's a server with a riser card, and a cardbus bridge to attach a WLAN card? That setup is quite common.

yenta.c doesn't contain error handling, and that should be fixed.

Quoted 5 lines

H.J.

Quoted 1 line · Andrew Morton

You guys may need this...

IMHO both patches are needed:

The current code that detects transparent bridges [bridges that implement subtractive decoding would be a better name] is bad, Ivan's patch fixes that.

My patch adds error handling to yenta.c. It's not strictly needed, because most PCI bridges in laptops forward all requests, and thus there is enough iomem space for the 8 MB allocation, but the lack of error handling [and lack of printks] just asks for trouble.

--
Manfred

author
#3 lore raw
Quoted 3 lines · Manfred Spraul

yenta.c doesn't contain error handling, and that should be fixed.

This is what I have been using.

H.J.

drivers/pcmcia/yenta.c renamed from drivers/pcmcia/yenta.c.resource +13 -3
@@ -739,17 +739,27 @@ static void yenta_allocate_res(pci_socke
 		return;
 	}
 
-	align = size = 4*1024*1024;
-	min = PCIBIOS_MIN_MEM; max = ~0U;
 	if (type & IORESOURCE_IO) {
 		align = 1024;
 		size = 256;
 		min = 0x4000;
 		max = 0xffff;
 	}
+	else {
+		align = size = 4*1024*1024;
+		min = PCIBIOS_MIN_MEM;
+		max = ~0U;
+	}
 		
-	if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0)
+
+	if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0) {
+		printk (KERN_NOTICE "PCI: CardBus bridge (%04x:%04x, %04x:%04x): Failed to allocate %s resource: %d bytes!\n",
+			socket->dev->vendor, socket->dev->device,
+			socket->dev->subsystem_vendor,
+			socket->dev->subsystem_device,
+			(type & IORESOURCE_IO) ? "I/O" : "memory", size);
 		return;
+	}
 
 	config_writel(socket, offset, res->start);
 	config_writel(socket, offset+4, res->end);