Subject: kern/8899: [rkb] CardBus CSC interrupts don't work on TI113X CardBus bridge
To: None <gnats-bugs@gnats.netbsd.org>
From: None <rafal@mediaone.net>
List: netbsd-bugs
Date: 11/27/1999 18:54:50
>Number:         8899
>Category:       kern
>Synopsis:       CB CSC interrupts not sent on TI113X (maybe others) CBB
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Nov 27 18:54:00 1999
>Last-Modified:
>Originator:     Rafal Boni
>Organization:
Insomniac Hackers Club
>Release:        -current as of today or yesterday
>Environment:
DEC VP765 laptop with TI PCI1131 CardBus bridge
		NetBSD 1.4P kernel with cardbus enabled
>Description:

	If PCI_SOCKBASE register holds addresses on the ISA bus (in my 
	case 0xcc000/0xcd000) at boot time, pccbbattach() will fail the 
	following test:

		if (PCI_MAPREG_MEM_ADDR(sock_base) >= 0x100000 &&
      		    PCI_MAPREG_MEM_ADDR(sock_base) != 0xfffffff0)

	and hence will not map the socket registers.  pccbb_chipinit(), 
	however, relies on having those registers mapped to do chip-specific
	initializations (eg, writing to the ExCA registers to set up the 
	TI113X and TI12XX CBBs).

	Note that since pccbb_chipinit() does not check if the handle for the
	socket registers (sc->sc_base_memt, sc->sc_base_memh) is valid before
	it uses it, it may write junk to some unrelated place in memory.

>How-To-Repeat:
	(1) Boot NetBSD-current on my laptop.  I don't know if this is 
	    specific to how my PCCBB is set up at boot or if this is a
	    general problem with all TI 113X, 12XX CBBs.

	(2) Note that inserted cards are not noticed until some other CBB 
	    interrupt occurrs (eg, a functional interrupt from an already 
	    present card).

	(3) Wonder why; turn on all the cardbus debug goo.  Wonder why the 
	    ExCA registers read in pccbb_chipinit() are all 0xff.

	(4) Look at the code, note that socket registers are not mapped
	    until later (in pccbb_pci_callback()).

>Fix:

	(1) Move the ExCA register setup to pccbb_pci_callback().  

	(2) Alternately, fix pccbb_attach() to do the same trick to 
	    map the socket registers as used by pccbb_pci_callback().

	Patch that does (1) follows; (2) seems either dangerous if implemented
	naiively, or much more work if implemented correctly -- that is, being
	careful to avoid stealing memory areas used by other PCI cards on 
	the PCCBB's bus.

Index: pccbb.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pci/pccbb.c,v
retrieving revision 1.8
diff -b -u -r1.8 pccbb.c
--- pccbb.c	1999/11/15 16:19:03	1.8
+++ pccbb.c	1999/11/28 02:24:26
@@ -410,6 +410,7 @@
    * config space), get it not polite way.
    */
   sock_base = pci_conf_read(pc, pa->pa_tag, PCI_SOCKBASE);
+  DPRINTF(("%s: sock_base = 0x%x",sc->sc_dev.dv_xname, sock_base));
 
   if (PCI_MAPREG_MEM_ADDR(sock_base) >= 0x100000 &&
       PCI_MAPREG_MEM_ADDR(sock_base) != 0xfffffff0) {
@@ -424,14 +425,14 @@
       if (pci_mapreg_map(pa, PCI_SOCKBASE, PCI_MAPREG_TYPE_IO, 0,
 			 &sc->sc_base_memt, &sc->sc_base_memh,
 			 &sockbase, NULL)) {
-	printf("%s: can't map socket base address 0x%lx: io mode\n",
-	       sc->sc_dev.dv_xname, sockbase);
+	printf("%s: can't map socket base address 0x%x: io mode\n",
+	       sc->sc_dev.dv_xname, sock_base);
 	/* give up... allocate register space via rbus. */
 	sc->sc_base_memh = 0;
 	pci_conf_write(pc, pa->pa_tag, PCI_SOCKBASE, 0);
       }
     } else {
-      DPRINTF(("%s: socket base address 0x%lx",sc->sc_dev.dv_xname, sockbase));
+      DPRINTF(("%s: mapped socket base address @ 0x%lx",sc->sc_dev.dv_xname, sockbase));
     }
   }
 
@@ -505,8 +506,10 @@
 {
   struct pccbb_softc *sc = (void *)self;
   pci_chipset_tag_t pc = sc->sc_pc;
+  pcitag_t tag = sc->sc_tag;
   bus_space_tag_t base_memt;
   bus_space_handle_t base_memh;
+  pcireg_t cbctrl;
   u_int32_t maskreg;
   pci_intr_handle_t ih;
   const char *intrstr = NULL;
@@ -555,7 +558,71 @@
   base_memt = sc->sc_base_memt;	/* socket regs memory tag */
   base_memh = sc->sc_base_memh;	/* socket regs memory handle */
 
+  /*
+   * Interrupt routing: use PCI interrupt
+   */
+  {
+    u_int32_t bcr = pci_conf_read(pc, tag, PCI_BCR_INTR);
+    bcr &= ~CB_BCR_INTR_IREQ_ENABLE; /* use PCI Intr */
+    bcr |= CB_BCR_WRITE_POST_ENABLE; /* enable write post */
+    pci_conf_write(pc, tag, PCI_BCR_INTR, bcr);
+  }
+
+  if (CB_TI113X == sc->sc_chipset) {
+    cbctrl = pci_conf_read(pc, tag, PCI_CBCTRL);
+    if (0 == sc->sc_function) {
+      cbctrl |= PCI113X_CBCTRL_PCI_IRQ_ENA;
+    }
+    cbctrl |= PCI113X_CBCTRL_PCI_IRQ_ENA;	/* XXX: bug in PCI113X */
+    cbctrl |= PCI113X_CBCTRL_PCI_CSC; /* CSC intr enable */
+    cbctrl &= ~PCI113X_CBCTRL_PCI_INTR; /* functional intr prohibit */
+    cbctrl &= ~PCI113X_CBCTRL_INT_MASK;	/* prohibit ISA routing */
+    pci_conf_write(pc, tag, PCI_CBCTRL, cbctrl);
 
+    /* set ExCA regs: PCI113X required to be set bit 4 at Interrupt
+       and General Register, which is IRQ Enable Register, and clear
+       bit 3:0 to zero in order to route CSC interrupt to PCI
+       interrupt pin. */
+    bus_space_write_1(base_memt, base_memh, 0x0803, 0x10);
+    /* set ExCA regs: prohibit all pcmcia-style CSC intr. */
+    bus_space_write_1(base_memt, base_memh, 0x0805, 0x00);
+#if 1
+    DPRINTF(("ExCA regs:"));
+    DPRINTF((" 0x803: %02x", bus_space_read_1(base_memt, base_memh, 0x803)));
+    DPRINTF((" 0x805: %02x", bus_space_read_1(base_memt, base_memh, 0x805)));
+    DPRINTF((" 0x81e: %02x\n", bus_space_read_1(base_memt,base_memh,0x81e)));
+#endif
+  } else if (sc->sc_chipset == CB_TI12XX) {
+    cbctrl = pci_conf_read(pc, tag, PCI_CBCTRL);
+    cbctrl &= ~PCI12XX_CBCTRL_INT_MASK;	/* intr routing reset */
+    pci_conf_write(pc, tag, PCI_CBCTRL, cbctrl);
+    /*
+     * set ExCA regs: PCI12XX required to be set bit 4 at Interrupt
+     * and General Register, which is IRQ Enable Register, and clear
+     * bit 3:0 to zero in order to route CSC interrupt to PCI
+     * interrupt pin.
+     */
+    bus_space_write_1(base_memt, base_memh, 0x0803, 0x10);
+    /* set ExCA regs: prohibit all pcmcia-style CSC intr. */
+    bus_space_write_1(base_memt, base_memh, 0x0805, 0x00);
+  } else if (sc->sc_chipset == CB_TOPIC95B) {
+    cardbusreg_t sock_ctrl, slot_ctrl;
+
+    sock_ctrl = pci_conf_read(pc, tag, TOPIC_SOCKET_CTRL);
+    pci_conf_write(pc, tag, TOPIC_SOCKET_CTRL,
+		   sock_ctrl | TOPIC_SOCKET_CTRL_SCR_IRQSEL);
+
+    slot_ctrl = pci_conf_read(pc, tag, TOPIC_SLOT_CTRL);
+    DPRINTF(("%s: topic slot ctrl reg 0x%x -> ", sc->sc_dev.dv_xname,
+	     slot_ctrl));
+    slot_ctrl |= (TOPIC_SLOT_CTRL_SLOTON | TOPIC_SLOT_CTRL_SLOTEN |
+		  TOPIC_SLOT_CTRL_ID_LOCK);
+    slot_ctrl |= TOPIC_SLOT_CTRL_CARDBUS;
+    slot_ctrl &= ~TOPIC_SLOT_CTRL_SWDETECT;
+    pci_conf_write(pc, tag, TOPIC_SLOT_CTRL, slot_ctrl);
+    DPRINTF(("0x%x\n", slot_ctrl));
+  }
+
   /* CSC Interrupt: Card detect interrupt on */
   maskreg = bus_space_read_4(base_memt, base_memh, CB_SOCKET_MASK);
   maskreg |= CB_SOCKET_MASK_CD;	/* Card detect intr is turned on. */
@@ -651,9 +718,6 @@
 {
   pci_chipset_tag_t pc = sc->sc_pc;
   pcitag_t tag = sc->sc_tag;
-  bus_space_tag_t base_memt = sc->sc_base_memt;	/* socket regs memory tag */
-  bus_space_handle_t base_memh = sc->sc_base_memh; /* socket regs memory handle */
-  pcireg_t cbctrl;
 
   /*
    * Set PCI command reg.
@@ -717,73 +781,6 @@
     /* XXX: I don't know proper way to kill Legacy IO properly. */
     pci_conf_write(pc, tag, PCI_LEGACY, 0x0);
     break;
-  }
-
-
-
-  /*
-   * Interrupt routing: use PCI interrupt
-   */
-  {
-    u_int32_t bcr = pci_conf_read(pc, tag, PCI_BCR_INTR);
-    bcr &= ~CB_BCR_INTR_IREQ_ENABLE; /* use PCI Intr */
-    bcr |= CB_BCR_WRITE_POST_ENABLE; /* enable write post */
-    pci_conf_write(pc, tag, PCI_BCR_INTR, bcr);
-  }
-
-  if (CB_TI113X == sc->sc_chipset) {
-    cbctrl = pci_conf_read(pc, tag, PCI_CBCTRL);
-    if (0 == sc->sc_function) {
-      cbctrl |= PCI113X_CBCTRL_PCI_IRQ_ENA;
-    }
-    cbctrl |= PCI113X_CBCTRL_PCI_IRQ_ENA;	/* XXX: bug in PCI113X */
-    cbctrl |= PCI113X_CBCTRL_PCI_CSC; /* CSC intr enable */
-    cbctrl &= ~PCI113X_CBCTRL_PCI_INTR; /* functional intr prohibit */
-    cbctrl &= ~PCI113X_CBCTRL_INT_MASK;	/* prohibit ISA routing */
-    pci_conf_write(pc, tag, PCI_CBCTRL, cbctrl);
-
-    /* set ExCA regs: PCI113X required to be set bit 4 at Interrupt
-       and General Register, which is IRQ Enable Register, and clear
-       bit 3:0 to zero in order to route CSC interrupt to PCI
-       interrupt pin. */
-    bus_space_write_1(base_memt, base_memh, 0x0803, 0x10);
-    /* set ExCA regs: prohibit all pcmcia-style CSC intr. */
-    bus_space_write_1(base_memt, base_memh, 0x0805, 0x00);
-#if 1
-    DPRINTF(("ExCA regs:"));
-    DPRINTF((" 0x803: %02x", bus_space_read_1(base_memt, base_memh, 0x803)));
-    DPRINTF((" 0x805: %02x", bus_space_read_1(base_memt, base_memh, 0x805)));
-    DPRINTF((" 0x81e: %02x\n", bus_space_read_1(base_memt,base_memh,0x81e)));
-#endif
-  } else if (sc->sc_chipset == CB_TI12XX) {
-    cbctrl = pci_conf_read(pc, tag, PCI_CBCTRL);
-    cbctrl &= ~PCI12XX_CBCTRL_INT_MASK;	/* intr routing reset */
-    pci_conf_write(pc, tag, PCI_CBCTRL, cbctrl);
-    /*
-     * set ExCA regs: PCI12XX required to be set bit 4 at Interrupt
-     * and General Register, which is IRQ Enable Register, and clear
-     * bit 3:0 to zero in order to route CSC interrupt to PCI
-     * interrupt pin.
-     */
-    bus_space_write_1(base_memt, base_memh, 0x0803, 0x10);
-    /* set ExCA regs: prohibit all pcmcia-style CSC intr. */
-    bus_space_write_1(base_memt, base_memh, 0x0805, 0x00);
-  } else if (sc->sc_chipset == CB_TOPIC95B) {
-    cardbusreg_t sock_ctrl, slot_ctrl;
-
-    sock_ctrl = pci_conf_read(pc, tag, TOPIC_SOCKET_CTRL);
-    pci_conf_write(pc, tag, TOPIC_SOCKET_CTRL,
-		   sock_ctrl | TOPIC_SOCKET_CTRL_SCR_IRQSEL);
-
-    slot_ctrl = pci_conf_read(pc, tag, TOPIC_SLOT_CTRL);
-    DPRINTF(("%s: topic slot ctrl reg 0x%x -> ", sc->sc_dev.dv_xname,
-	     slot_ctrl));
-    slot_ctrl |= (TOPIC_SLOT_CTRL_SLOTON | TOPIC_SLOT_CTRL_SLOTEN |
-		  TOPIC_SLOT_CTRL_ID_LOCK);
-    slot_ctrl |= TOPIC_SLOT_CTRL_CARDBUS;
-    slot_ctrl &= ~TOPIC_SLOT_CTRL_SWDETECT;
-    pci_conf_write(pc, tag, TOPIC_SLOT_CTRL, slot_ctrl);
-    DPRINTF(("0x%x\n", slot_ctrl));
   }
 
   /* close all memory and io windows */
>Audit-Trail:
>Unformatted: