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: