With rtsx(4), I can trigger a panic in sdmmc_needs_discover()
by inserting an SD card (actually, a microSD in an SD-card sized
adapter) during boot (while the boot loader is loading the kernel).

I haven't copied the backtrace (no serial console) but what happens
is that rtsx_intr() fires during rtsx_init() called from rtsx_attach().

The rtsx_init() function enables interrupts very early, and then goes
on to init various things. The last thing it does is check the ISR
to see if a card is already inserted, and if so it sets the
RTSX_F_CARD_PRESENT flag in the softc.

If rtsx_intr() runs concurrently, and before the RTSX_F_CARD_PRESENT
flag has been set, it will check the ISR as well, see that a card
is present, and run sdmmc_needs_discover(). However, we haven't yet
attached the sdmmc subsystem at this point, so the kernel panics.

Enabling interrupts after checking whether a card is inserted
seems to fix this problem and doesn't seem to cause a regression.
I've tested various things, booting with and without a card and
inserting a card at various times during the boot process, and it
now seems solid.

I'm not really sure why I didn't catch this before. For some reason
the problem does not happen if the card is inserted while powering
on the machine, so perhaps the hardware doesn't fire an interrupt
in that case and I've never tested inserting a card during boot before.

Index: rtsx.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/rtsx.c,v
retrieving revision 1.2
diff -u -p -r1.2 rtsx.c
--- rtsx.c      7 Dec 2012 22:18:56 -0000       1.2
+++ rtsx.c      28 Mar 2013 13:46:07 -0000
@@ -215,10 +215,6 @@ rtsx_init(struct rtsx_softc *sc, int att
 {
        u_int32_t status;
 
-       /* Enable interrupts. */
-       WRITE4(sc, RTSX_BIER,
-           RTSX_TRANS_OK_INT_EN | RTSX_TRANS_FAIL_INT_EN | RTSX_SD_INT_EN);
-
        /* Enable interrupt write-clear (default is read-clear). */
        RTSX_CLR(sc, RTSX_NFTS_TX_CTRL, RTSX_INT_READ_CLR);
 
@@ -226,6 +222,14 @@ rtsx_init(struct rtsx_softc *sc, int att
        status = READ4(sc, RTSX_BIPR);
        WRITE4(sc, RTSX_BIPR, status);
 
+       /* Check for cards already inserted at attach time. */
+       if (attaching && (status & RTSX_SD_EXIST))
+               sc->flags |= RTSX_F_CARD_PRESENT;
+
+       /* Enable interrupts. */
+       WRITE4(sc, RTSX_BIER,
+           RTSX_TRANS_OK_INT_EN | RTSX_TRANS_FAIL_INT_EN | RTSX_SD_INT_EN);
+
        /* Power on SSC clock. */
        RTSX_CLR(sc, RTSX_FPDCTL, RTSX_SSC_POWER_DOWN);
        delay(200);
@@ -267,10 +271,6 @@ rtsx_init(struct rtsx_softc *sc, int att
        /* Set up LED GPIO. */
        RTSX_WRITE(sc, RTSX_CARD_GPIO, 0x03);
        RTSX_WRITE(sc, RTSX_CARD_GPIO_DIR, 0x03);
-
-       /* Check for cards already inserted at attach time. */
-       if (attaching && (status & RTSX_SD_EXIST))
-               sc->flags |= RTSX_F_CARD_PRESENT;
 
        return (0);
 }

Reply via email to