Skip to contentSkip to conversation

PATCH: Fix CardBus bridge behind a PCI bridge

PATCH H. J. Lu 3 participants 10 messages Aug 12, 2002 – Aug 18, 2002 11 messages not in the archive

Subsystems (2)
lore
Share & tools
lore

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

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

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

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

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

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

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

H. J. Lu

author
#7 lore raw
Quoted 24 lines · H. J. Lu
Quoted 11 lines · dhinds
Quoted 7 lines · H. J. Lu
Quoted 3 lines · dhinds

There's a current thread on linux-kernel about "PCI hotplug resource reservation" that is relevant, and there's a patch that claims to provide a workable solution to the problem for cPCI.

Thanks. Do you think if the "PCI<->PCI bridges, transparent resource fix" thread is related to it?

I glanced at that and didn't think so, but I didn't read much.

I think they are relevant. Your pcmcia-cs 3.20 works fine on Sony. Here is the output of "lspci -v". PCI bride has

	I/O behind bridge: 00004000-00004fff
	Memory behind bridge: e8200000-e82fffff

The kernel cardbus code tries to allocate memory and I/O from them. It doesn't work. BTW, I checked another notebook. That code is not reached at all since slot has been initialized by BIOS. Your pcmcia-cs doesn't follow the PCI brigde:

Quoted 5 lines
	I/O ports at 0200
	Memory at 60040000 (32-bit, non-prefetchable)

and works. Any ides why?

Here is a patch against 2.4.18 to fix CardBus bridge behind a PCI bridge with positive decode. I checked Windows XP. It is how it allocates resources for the CardBus slots, that is outside of the memory and I/O windows on the PCI bridge.

Let me know if it works for you.

H.J.

drivers/pcmcia/yenta.c renamed from drivers/pcmcia/yenta.c.bridge +27 -4
@@ -712,6 +712,7 @@ static void yenta_allocate_res(pci_socke
 	u32 align, size, min, max;
 	unsigned offset;
 	unsigned mask;
+	int failed;
 
 	/* The granularity of the memory limit is 4kB, on IO it's 4 bytes */
 	mask = ~0xfff;
@@ -739,17 +740,39 @@ 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)
-		return;
+
+	do {
+		failed = allocate_resource(root, res, size, min, max,
+					   align, NULL, NULL);
+		if (failed) {
+			/* If we failed to allocate the resources here, we
+			   try its parent if we are on a bridge with
+			   positive decode.  */
+			struct pci_dev *bridge;
+			bus = bus->parent;
+			if (bus == NULL)
+				return;
+			bridge = bus->self;
+			if (bridge == NULL
+			    || (bridge->class >> 16) != PCI_BASE_CLASS_BRIDGE
+			    || (bridge->class & 0xff) != 0)
+				return;
+			res->name = bridge->subordinate->name;
+			root = pci_find_parent_resource(bridge, res);
+		}
+	} while (failed);
 
 	config_writel(socket, offset, res->start);
 	config_writel(socket, offset+4, res->end);

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

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

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

author
#11 lore raw
Quoted 15 lines · dhinds
Quoted 10 lines · H. J. Lu
Quoted 4 lines

what does "positive decode" mean in this context? Does the bridge somehow figure out that if no other device claims a transaction, that it should do so?

I am not a PCI expert. As I understand, if a PCI bridge does negative decode, you don't need to do it for the CardBus bride behind it. I guess it is only needed for positive decode. For some reason, a PCI bridge with positive decode may pass address to the CardBus bridge behind it or the CardBus bridge has some back door to the PCI bus.

I pulled up the datasheet for this chip and now I think maybe I understand what's going on.

Quoted 8 lines

It says that the PCI-to-PCI bridge function in this chip forwards all transactions to the external PCI bus. The bridge windows determine ranges of addresses which it may claim back as a target, in this case I guess just for the LAN function, which is the only integrated device on bus 2.

So this actually seems to be effectively a transparent bridge.

How about this pacth? It works for me.

H.J.

drivers/pcmcia/yenta.c renamed from drivers/pcmcia/yenta.c.bridge +31 -4
@@ -706,7 +706,8 @@ static int yenta_suspend(pci_socket_t *s
 
 static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
 {
-	struct pci_bus *bus;
+	struct pci_bus *bus, *parent;
+	struct pci_dev *bridge;
 	struct resource *root, *res;
 	u32 start, end;
 	u32 align, size, min, max;
@@ -739,17 +740,43 @@ 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)
+
+	/* We check if we are behind an Intel 82801BAM/CAM PCI bridge
+	   which is a transparent bridge for us. We just allocate
+	   resources from its parent.  */
+	parent = bus->parent;
+	if (parent != NULL) {
+		bridge = parent->self;
+		if (bridge != NULL
+		    && (bridge->class >> 8) == PCI_CLASS_BRIDGE_PCI
+		    && bridge->vendor == PCI_VENDOR_ID_INTEL
+		    && bridge->device >= PCI_DEVICE_ID_INTEL_82801BA_0
+		    && bridge->device <= PCI_DEVICE_ID_INTEL_82801BA_11) {
+			res->name = bridge->subordinate->name;
+			root = pci_find_parent_resource(bridge, res);
+		}
+	}
+
+	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);

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

author
#13 lore raw

PATCH: New fix for CardBus bridge behind a PCI bridge

Quoted 4 lines · dhinds

I guess the advantage of your original patch is that I think it should never hurt, and will help in any situation where a PCI bridge actually is transparent.

I was told all PCI_CLASS_BRIDGE_PCI bridges were transparent. The non- transparent ones have class code PCI_CLASS_BRIDGE_OTHER. This new patch only checks PCI_CLASS_BRIDGE_PCI and works for me.

H.J.

drivers/pcmcia/yenta.c renamed from drivers/pcmcia/yenta.c.bridge +26 -4
@@ -706,7 +706,8 @@ static int yenta_suspend(pci_socket_t *s
 
 static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
 {
-	struct pci_bus *bus;
+	struct pci_bus *bus, *parent;
+	struct pci_dev *bridge;
 	struct resource *root, *res;
 	u32 start, end;
 	u32 align, size, min, max;
@@ -739,17 +740,38 @@ 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)
+
+	/* We check if we are behind a transparent PCI bridge. If yes,
+	   we just allocate resources from its parent.  */
+	for (parent = bus->parent; parent != NULL; parent = parent->parent) {
+		bridge = parent->self;
+		if (bridge != NULL
+		    && (bridge->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+			res->name = bridge->subordinate->name;
+			root = pci_find_parent_resource(bridge, res);
+		}
+	}
+
+	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);
#14 lore raw

Re: PATCH: New fix for CardBus bridge behind a PCI bridge

Quoted 3 lines · H. J. Lu

I was told all PCI_CLASS_BRIDGE_PCI bridges were transparent. The non- transparent ones have class code PCI_CLASS_BRIDGE_OTHER. This new patch only checks PCI_CLASS_BRIDGE_PCI and works for me.

I guess that info came from Intel ;-) Interesting, but completely wrong. The devices they call "non-transparent PCI-to-PCI bridges" aren't classic PCI-to-PCI bridges at all, that's why they are PCI_CLASS_BRIDGE_OTHER. It's more to do with CPU-to-CPU bridges.
In our terms, "transparent" PCI-to-PCI bridge means subtractive decoding one. Your previous patch makes much more sense, although a) it should belong to generic pci code b) is way incomplete.

Please try this one instead.

Ivan.

drivers/pci/quirks.c +11 -0
@@ -471,6 +471,11 @@ static void __init quirk_dunord ( struct
 	r -> end = 0xffffff;
 }
 
+static void __init quirk_transparent_bridge(struct pci_dev *dev)
+{
+	dev->class |= 1;
+}
+
 /*
  *  The main table of quirks.
  */
@@ -525,6 +530,12 @@ static struct pci_fixup pci_fixups[] __i
 
 	{ PCI_FIXUP_FINAL, 	PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7410,	quirk_amd_ioapic },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering },
+	/*
+	 * i82380FB mobile docking controller: its PCI-to-PCI bridge
+	 * is subtractive decoding (transparent), and does indicate this
+	 * in the ProgIf. Unfortunately, in the wrong bit - 7 instead of 0.
+	 */
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82380FB,	quirk_transparent_bridge },
 
 	{ 0 }
 };
drivers/pci/pci.c +7 -15
@@ -1073,6 +1073,13 @@ void __devinit pci_read_bridge_bases(str
 	if (!dev)		/* It's a host bus, nothing to read */
 		return;
 
+	if (dev->class & 1) {
+		printk("Transparent bridge - %s\n", dev->name);
+		for(i=0; i < 3; i++)
+			child->resource[i] = child->parent->resource[i];
+		return;
+	}
+
 	for(i=0; i<3; i++)
 		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
 
@@ -1095,13 +1102,6 @@ void __devinit pci_read_bridge_bases(str
 		res->start = base;
 		res->end = limit + 0xfff;
 		res->name = child->name;
-	} else {
-		/*
-		 * Ugh. We don't know enough about this bridge. Just assume
-		 * that it's entirely transparent.
-		 */
-		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0);
-		child->resource[0] = child->parent->resource[0];
 	}
 
 	res = child->resource[1];
@@ -1114,10 +1114,6 @@ void __devinit pci_read_bridge_bases(str
 		res->start = base;
 		res->end = limit + 0xfffff;
 		res->name = child->name;
-	} else {
-		/* See comment above. Same thing */
-		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1);
-		child->resource[1] = child->parent->resource[1];
 	}
 
 	res = child->resource[2];
@@ -1145,10 +1141,6 @@ void __devinit pci_read_bridge_bases(str
 		res->start = base;
 		res->end = limit + 0xfffff;
 		res->name = child->name;
-	} else {
-		/* See comments above */
-		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2);
-		child->resource[2] = child->parent->resource[2];
 	}
 }
 
arch/i386/kernel/pci-pc.c +18 -0
@@ -1245,6 +1245,23 @@ static void __init pci_fixup_via_northbr
 	}
 }
 
+/*
+ * For some weird reasons Intel decided that certain parts of their
+ * 815, 845 and some other chipsets must look like PCI-to-PCI bridges
+ * while they are obviously not. The 82801xx (AA, AB, BAM/CAM, BA/CA/DB
+ * and E) PCI bridges are actually HUB-to-PCI ones, according to Intel
+ * terminology. These devices do forward all addresses from system to
+ * PCI bus no matter what are their window settings, so they are
+ * "transparent" (or subtractive decoding) from programmers point of view.
+ * Indicate this in ProgIf bit 0.
+ */
+static void __init pci_fixup_transparent_bridge(struct pci_dev *dev)
+{
+	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+	    (dev->device & 0xff00) == 0x2400);
+		dev->class |= 1;
+}
+
 struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454GX,	pci_fixup_i450gx },
@@ -1259,6 +1276,7 @@ struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,	        pci_fixup_via_northbridge_bug },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8367_0,	pci_fixup_via_northbridge_bug },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C810,	pci_fixup_ncr53c810 },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_ANY_ID,			pci_fixup_transparent_bridge },
 	{ 0 }
 };
 
author
#15 lore raw

Re: PATCH: New fix for CardBus bridge behind a PCI bridge

Quoted 13 lines · Ivan Kokshaysky
Quoted 3 lines · H. J. Lu

I was told all PCI_CLASS_BRIDGE_PCI bridges were transparent. The non- transparent ones have class code PCI_CLASS_BRIDGE_OTHER. This new patch only checks PCI_CLASS_BRIDGE_PCI and works for me.

I guess that info came from Intel ;-) Interesting, but completely wrong. The devices they call "non-transparent PCI-to-PCI bridges" aren't classic PCI-to-PCI bridges at all, that's why they are PCI_CLASS_BRIDGE_OTHER. It's more to do with CPU-to-CPU bridges.
In our terms, "transparent" PCI-to-PCI bridge means subtractive decoding one. Your previous patch makes much more sense, although a) it should belong to generic pci code b) is way incomplete.

Quoted 2 lines

Please try this one instead.

CardBus works now. But I can no longer load usb-uhci. My X server no longer works. Your patch is not right.

H.J.

#16 lore raw

Re: PATCH: New fix for CardBus bridge behind a PCI bridge

Quoted 15 lines · Ivan Kokshaysky
Quoted 15 lines · H. J. Lu
Quoted 4 lines

I was told all PCI_CLASS_BRIDGE_PCI bridges were transparent. The non- transparent ones have class code PCI_CLASS_BRIDGE_OTHER. This new patch only checks PCI_CLASS_BRIDGE_PCI and works for me.

I guess that info came from Intel ;-) Interesting, but completely wrong. The devices they call "non-transparent PCI-to-PCI bridges" aren't classic PCI-to-PCI bridges at all, that's why they are PCI_CLASS_BRIDGE_OTHER. It's more to do with CPU-to-CPU bridges.
In our terms, "transparent" PCI-to-PCI bridge means subtractive decoding one. Your previous patch makes much more sense, although a) it should belong to generic pci code b) is way incomplete.

Quoted 6 lines
Quoted 2 lines

Please try this one instead.

CardBus works now. But I can no longer load usb-uhci. My X server no longer works. Your patch is not right.

I would be willing to bet there is some silliness in the X server, at least. It's PCI code has always left a lot to be desired...

Jeff

author
#17 lore raw

Re: PATCH: New fix for CardBus bridge behind a PCI bridge

Quoted 21 lines · Jeff Garzik

H. J. Lu wrote:> On Fri, Aug 16, 2002 at 07:48:25PM +0400, Ivan

Quoted 19 lines · Kokshaysky
Quoted 17 lines · H. J. Lu
Quoted 4 lines

I was told all PCI_CLASS_BRIDGE_PCI bridges were transparent. The non- transparent ones have class code PCI_CLASS_BRIDGE_OTHER. This new patch only checks PCI_CLASS_BRIDGE_PCI and works for me.

I guess that info came from Intel ;-) Interesting, but completely wrong. The devices they call "non-transparent PCI-to-PCI bridges" aren't classic PCI-to-PCI bridges at all, that's why they are PCI_CLASS_BRIDGE_OTHER. It's more to do with CPU-to-CPU bridges.
In our terms, "transparent" PCI-to-PCI bridge means subtractive decoding one. Your previous patch makes much more sense, although a) it should belong to generic pci code b) is way incomplete.

Please try this one instead.

Quoted 7 lines
Quoted 2 lines

CardBus works now. But I can no longer load usb-uhci. My X server no longer works. Your patch is not right.

I would be willing to bet there is some silliness in the X server, at least. It's PCI code has always left a lot to be desired...

It could be. But I doubt it. At least, I don't think you can treat a AGP bridge like a 82801BAM/CAM bridge. I think 82801BAM/CAM is a special case. You really have to read the datasheet to know for sure.

H.J.

#18 lore raw

Re: PATCH: New fix for CardBus bridge behind a PCI bridge

Quoted 3 lines · H. J. Lu

It could be. But I doubt it. At least, I don't think you can treat a AGP bridge like a 82801BAM/CAM bridge. I think 82801BAM/CAM is a special case. You really have to read the datasheet to know for sure.

You're right by all means. AGP bridges are _always_ positive decoders. The problems you've seen were caused by the wrong semicolon somehow sneaked into the patch:

+static void __init pci_fixup_transparent_bridge(struct pci_dev *dev) +{
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&

+	    (dev->device & 0xff00) == 0x2400);
					     ^ Ugh..

+ dev->class |= 1;
+}

Which means that I'm setting bit 0 in the ProgIf for _all_ Intel devices... I'm really sorry about that.
Thanks for the pci dump - it's very useful anyway.

Ivan.

author
#19 lore raw

Re: PATCH: New fix for CardBus bridge behind a PCI bridge

Quoted 17 lines · Ivan Kokshaysky
Quoted 3 lines · H. J. Lu

It could be. But I doubt it. At least, I don't think you can treat a AGP bridge like a 82801BAM/CAM bridge. I think 82801BAM/CAM is a special case. You really have to read the datasheet to know for sure.

You're right by all means. AGP bridges are _always_ positive decoders. The problems you've seen were caused by the wrong semicolon somehow sneaked into the patch:

arch/i386/kernel/pci-pc.c +4 -0
+static void __init pci_fixup_transparent_bridge(struct pci_dev *dev)
+{
+	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+	    (dev->device & 0xff00) == 0x2400);
					     ^ Ugh..
(quoted diff) +2 -0
+		dev->class |= 1;
+}
Quoted 2 lines

Which means that I'm setting bit 0 in the ProgIf for _all_ Intel devices... I'm really sorry about that.

Yes. It works now. Thanks.

H.J.

#20 lore raw

Re: PATCH: New fix for CardBus bridge behind a PCI bridge

In reply to H. J. Lu
Quoted 2 lines · H. J. Lu

CardBus works now. But I can no longer load usb-uhci. My X server no longer works. Your patch is not right.

More info, please (probably off-list). Kernel and X error messages, and 'lspci -vvxxx' output from your machine.
Those "transparent" bridges cause too much problems, and I'm just trying to find a generic solution...

Ivan.