Subject: cardbus and pcibios not working, Panasonic Toughbook CF-25 MKII
To: None <port-i386@netbsd.org>
From: Miles Nordin <carton@Ivy.NET>
List: port-i386
Date: 01/24/2004 00:17:57
I'm trying to make PC Cards work in a Panasonic Toughbook CF-25 MKII.
The two cardbus controllers aren't assigned interrupts by the BIOS:

cbb0 at pci0 dev 16 function 0: Ricoh 5C466 PCI-CardBus bridge (rev. 0x01)
cbb0: NOT USED because of unconfigured interrupt
cbb1 at pci0 dev 16 function 1: Ricoh 5C466 PCI-CardBus bridge (rev. 0x01)
cbb1: NOT USED because of unconfigured interrupt
cbb2 at pci0 dev 19 function 0: Ricoh 5C466 PCI-CardBus bridge (rev. 0x01)
cbb2: NOT USED because of unconfigured interrupt
cbb3 at pci0 dev 19 function 1: Ricoh 5C466 PCI-CardBus bridge (rev. 0x01)
cbb3: NOT USED because of unconfigured interrupt

pcibios does not work because the $PIR table has only zeroes in the
``link'' column:

-----8<-----
PCI BIOS rev. 2.1 found at 0xfd92c
pcibios: config mechanism [1][x], special cycles [1][x], last bus 0
PCI BIOS has 7 Interrupt Routing table entries
PCI Exclusive IRQs: 0
PIR Entry 0:
	Bus: 0  Device: 0
		INTA: link 0x00 bitmap 0x8eb8
		INTB: link 0x00 bitmap 0x8eb8
		INTC: link 0x00 bitmap 0x0000
		INTD: link 0x00 bitmap 0x0000
PIR Entry 1:
	Bus: 0  Device: 1
		INTA: link 0x00 bitmap 0x8eb8
		INTB: link 0x00 bitmap 0x8eb8
		INTC: link 0x00 bitmap 0x0000
		INTD: link 0x00 bitmap 0x0000
PIR Entry 2:
	Bus: 0  Device: 16
		INTA: link 0x00 bitmap 0x8eb8
		INTB: link 0x00 bitmap 0x8eb8
		INTC: link 0x00 bitmap 0x0000
		INTD: link 0x00 bitmap 0x0000
PIR Entry 3:
	Bus: 0  Device: 19
		INTA: link 0x00 bitmap 0x8eb8
		INTB: link 0x00 bitmap 0x8eb8
		INTC: link 0x00 bitmap 0x0000
		INTD: link 0x00 bitmap 0x0000
PIR Entry 4:
	Bus: 0  Device: 20
		INTA: link 0x00 bitmap 0x8eb8
		INTB: link 0x00 bitmap 0x8eb8
		INTC: link 0x00 bitmap 0x0000
		INTD: link 0x00 bitmap 0x0000
PIR Entry 5:
	Bus: 0  Device: 0
		INTA: link 0x00 bitmap 0x0000
		INTB: link 0x00 bitmap 0x0000
		INTC: link 0x00 bitmap 0x0000
		INTD: link 0x00 bitmap 0x0000
PIR Entry 6:
	Bus: 0  Device: 0
		INTA: link 0x00 bitmap 0x0000
		INTB: link 0x00 bitmap 0x0000
		INTC: link 0x00 bitmap 0x0000
		INTD: link 0x00 bitmap 0x0000
PCI Interrupt Router at 000:01:0 (Intel 82371MX Mobile PCI I/O IDE Xcelerator (MPIIX))
----------------------------------------------------------
  device vendor product pin link PIRQ BIOSirq ICRirq stage
----------------------------------------------------------
000:00:0 0x8086 0x1235   @     -    -       -      0  -    WARNING: no useable row in $PIR table
000:01:0 0x8086 0x1234   @     -    -       -      0  -    WARNING: no useable row in $PIR table
000:16:0 0x1180 0x0466   A     -    -       -      0  -    WARNING: no useable row in $PIR table
000:16:1 0x1180 0x0466   B     -    -       -      0  -    WARNING: no useable row in $PIR table
000:19:0 0x1180 0x0466   A     -    -       -      0  -    WARNING: no useable row in $PIR table
000:19:1 0x1180 0x0466   B     -    -       -      0  -    WARNING: no useable row in $PIR table
000:20:0 0x102c 0x00e0   @     -    -       -      0  -    WARNING: no useable row in $PIR table
----------------------------------------------------------
-----8<-----

I'm using current-20031212.  I made some changes.  At first, the
kernel paniced in the pcibios boot stuff whenever PCIBIOS_INTR_FIXUP
was enabled.  I fixed this by importing the __asm calls into the
pcibios from OpenBSD.

With the OpenBSD patch, pcibios does get a $PIR table.  Looking for a
signature fails, but it gets one from the __asm call.  However the
table has no information in the ``link'' column, just zeroes---that is
the problem now, AFAICT.

Is there any hope to work around this?  To fix it?  Or maybe some way
I can through trial and error determine what belongs in that column,
and hard-code it into a kernel?

It's difficult for me because I don't understand PCI.  Like, AFAICT
``wire'' can refer to wires on the pc board that don't move, or to
``wiring'' one kind of interrupt to another by writing config
registers.  And ``interrupt'' can refer to a PCI pin A, B, C, D, a
``link'' number 0x??, or a PeeCee ISA interrupt 3, 4, 5, 7, 9, 10, 11.

i dunno.  I have all notPeeCee hardware, and buy just this one PeeCee,
and it turns into a multi-week disaster.

Below I also added columns to the diagnostic table, and made it print
the type of ICU it found even if it's found by iterating over bus 0.
Befor eit only prints this status if the ICU is found from the $PIR
table header.  the important change is the OpenBSD __asm though.

-----8<-----
Index: pci_intr_fixup.c
===================================================================
RCS file: /scratch/cvsroot/netbsd/src/sys/arch/i386/pci/pci_intr_fixup.c,v
retrieving revision 1.1.1.5
diff -u -r1.1.1.5 pci_intr_fixup.c
--- pci_intr_fixup.c	12 Dec 2003 11:33:05 -0000	1.1.1.5
+++ pci_intr_fixup.c	24 Jan 2004 04:38:46 -0000
@@ -588,11 +588,11 @@
 pciintr_header_fixup(pc)
 	pci_chipset_tag_t pc;
 {
-	PCIBIOS_PRINTV(("------------------------------------------\n"));
-	PCIBIOS_PRINTV(("  device vendor product pin PIRQ IRQ stage\n"));
-	PCIBIOS_PRINTV(("------------------------------------------\n"));
+	PCIBIOS_PRINTV(("----------------------------------------------------------\n"));
+	PCIBIOS_PRINTV(("  device vendor product pin link PIRQ BIOSirq ICRirq stage\n"));
+	PCIBIOS_PRINTV(("----------------------------------------------------------\n"));
 	pci_device_foreach(pc, pcibios_max_bus, pciintr_do_header_fixup, NULL);
-	PCIBIOS_PRINTV(("------------------------------------------\n"));
+	PCIBIOS_PRINTV(("----------------------------------------------------------\n"));
 
 	return (0);
 }
@@ -631,36 +631,43 @@
 		 * Interrupt not connected; no
 		 * need to change.
 		 */
-		return;
-	}
+	        l = NULL;
+	} else
+	        l = pciintr_link_lookup(link);
 
-	l = pciintr_link_lookup(link);
+#ifdef PCIBIOSVERBOSE
+	if (pcibiosverbose) {
+		printf("%03d:%02d:%d 0x%04x 0x%04x   %c",
+		    bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id),
+		    '@' + pin);
+	        if (l == NULL) {
+	                printf("     -    -       -");
+                } else {
+	                printf("    0x%02x   0x%02x",
+		            l->link, l->clink);
+		        if (l->irq == X86_PCI_INTERRUPT_LINE_NO_CONNECTION)
+			    printf("       -");
+		        else
+			        printf("     %3d", l->irq);
+	        }
+		if (irq == X86_PCI_INTERRUPT_LINE_NO_CONNECTION)
+			printf("      -");
+		else
+			printf("    %3d", irq);
+		if (l == NULL)
+		        printf("  -    WARNING: no useable row in $PIR table\n");
+		else
+		        printf("  %d   ", l->fixup_stage);
+	}
+#endif
 	if (l == NULL) {
-#ifdef PCIINTR_DEBUG
 		/*
 		 * No link map entry.
 		 * Probably pciintr_icu_getclink() or pciintr_icu_get_intr()
 		 * was failed.
 		 */
-		printf("pciintr_header_fixup: no entry for link 0x%02x "
-		       "(%d:%d:%d:%c)\n", link, bus, device, function,
-		       '@' + pin);
-#endif
 		return;
 	}
-
-#ifdef PCIBIOSVERBOSE
-	if (pcibiosverbose) {
-		printf("%03d:%02d:%d 0x%04x 0x%04x   %c  0x%02x",
-		    bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id),
-		    '@' + pin, l->clink);
-		if (l->irq == X86_PCI_INTERRUPT_LINE_NO_CONNECTION)
-			printf("   -");
-		else
-			printf(" %3d", l->irq);
-		printf("  %d   ", l->fixup_stage);
-	}
-#endif
 	
 	/*
 	 * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck
@@ -718,6 +725,8 @@
 	bus_space_tag_t iot;
 	u_int16_t *pciirq;
 {
+	char devinfo[256];
+	int bus, device, function;
 	const struct pciintr_icu_table *piit = NULL;
 	pcitag_t icutag;
 	pcireg_t icuid;
@@ -758,7 +767,7 @@
 		if (piit == NULL)
 			piit = pciintr_icu_lookup(icuid);
 	} else {
-		int device, maxdevs = pci_bus_maxdevs(pc, 0);
+		int maxdevs = pci_bus_maxdevs(pc, 0);
 
 		/*
 		 * Search configuration space for a known interrupt
@@ -766,7 +775,7 @@
 		 */
 		for (device = 0; device < maxdevs; device++) {
 			const struct pci_quirkdata *qd;
-			int function, nfuncs;
+			int nfuncs;
 			pcireg_t bhlcr;
 
 			icutag = pci_make_tag(pc, 0, device, 0);
@@ -836,6 +845,18 @@
 		return (-1);		/* non-fatal */
 #endif
 	}
+
+	/*
+	 * disclose results of the searching and probing
+	 */
+	pci_decompose_tag(pc, icutag, &bus, &device, &function);
+	printf("PCI Interrupt Router at %03d:%02d:%01d",
+	       bus, device, function);
+	if (icuid != 0) {
+		pci_devinfo(icuid, 0, 0, devinfo);
+		printf(" (%s)", devinfo);
+	}
+	printf("\n");
 
 	/*
 	 * Initialize the PCI ICU.
Index: pcibios.c
===================================================================
RCS file: /scratch/cvsroot/netbsd/src/sys/arch/i386/pci/pcibios.c,v
retrieving revision 1.1.1.5
diff -u -r1.1.1.5 pcibios.c
--- pcibios.c	12 Dec 2003 11:33:05 -0000	1.1.1.5
+++ pcibios.c	24 Jan 2004 02:02:34 -0000
@@ -230,7 +230,6 @@
 void
 pcibios_pir_init()
 {
-	char devinfo[256];
 	paddr_t pa;
 	caddr_t p;
 	unsigned char cksum;
@@ -290,16 +289,6 @@
 		memcpy(pcibios_pir_table, p + 32, tablesize - 32);
 		pcibios_pir_table_nentries = (tablesize - 32) / 16;
 
-		printf("PCI Interrupt Router at %03d:%02d:%01d",
-		    pcibios_pir_header.router_bus,
-		    PIR_DEVFUNC_DEVICE(pcibios_pir_header.router_devfunc),
-		    PIR_DEVFUNC_FUNCTION(pcibios_pir_header.router_devfunc));
-		if (pcibios_pir_header.compat_router != 0) {
-			pci_devinfo(pcibios_pir_header.compat_router, 0, 0,
-			    devinfo);
-			printf(" (%s)", devinfo);
-		}
-		printf("\n");
 		pcibios_print_exclirq();
 #ifdef PCIINTR_DEBUG
 		pcibios_print_pir_table();
@@ -347,12 +336,28 @@
 	u_int32_t edx;
 	int rv;
 
+#if 0
 	__asm __volatile("lcall *(%%edi)				; \
 			jc 1f						; \
 			xor %%ah, %%ah					; \
 		1:"
 		: "=a" (ax), "=b" (bx), "=c" (cx), "=d" (edx)
 		: "0" (0xb101), "D" (&pcibios_entry));
+#else
+	__asm __volatile("pushl	%%es\n\t"
+			 "pushl	%%ds\n\t"
+			 "movw	4(%%edi), %%cx\n\t"
+			 "movl	%%ecx, %%ds\n\t"
+			 "lcall	%%cs:*(%%edi)\n\t"
+			 "pop	%%ds\n\t"
+			 "pop	%%es\n\t"
+			 "jc	1f\n\t"
+			 "xor	%%ah, %%ah\n"
+		    "1:"
+		: "=a" (ax), "=b" (bx), "=c" (cx), "=d" (edx)
+		: "0" (0xb101), "D" (&pcibios_entry)
+		: "cc", "memory");
+#endif
 
 	rv = pcibios_return_code(ax, "pcibios_get_status");
 	if (rv != PCIBIOS_SUCCESS)
@@ -395,6 +400,7 @@
 
 	memset(table, 0, args.size);
 
+#if 0
 	__asm __volatile("lcall *(%%esi)				; \
 			jc 1f						; \
 			xor %%ah, %%ah					; \
@@ -403,6 +409,21 @@
 		: "=a" (ax), "=b" (bx)
 		: "r" GSEL(GDATA_SEL, SEL_KPL), "0" (0xb10e), "1" (0),
 		  "D" (&args), "S" (&pcibios_entry));
+#else
+	__asm __volatile("pushl	%%es\n\t"
+			 "pushl	%%ds\n\t"
+			 "movw	4(%%esi), %%cx\n\t"
+			 "movl	%%ecx, %%ds\n\t"
+			 "lcall	%%cs:*(%%esi)\n\t"
+			 "popl	%%ds\n\t"
+			 "popl	%%es\n\t"
+			 "jc	1f\n\t"
+			 "xor	%%ah, %%ah\n"
+		    "1:\n"
+		: "=a" (ax), "=b" (bx)
+		: "0" (0xb10e), "1" (0), "D" (&args), "S" (&pcibios_entry)
+		: "%ecx", "%edx", "cc", "memory");
+#endif
 
 	rv = pcibios_return_code(ax, "pcibios_get_intr_routing");
 	if (rv != PCIBIOS_SUCCESS)
-----8<-----

-- 
Le fascisme est la dictature ouverte de la bourgeoisie.
		-- Georg Dimitrov