diff options
author | imp <imp@FreeBSD.org> | 2003-08-10 02:40:49 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2003-08-10 02:40:49 +0000 |
commit | af325fd3af882a05dc76b02119f41725de0dd5ec (patch) | |
tree | 00c12ab8da533ae0a5c13964ac445558fb327821 /sys/dev | |
parent | 38b3b484f3cb63d58a043bca4e4900b96a6f92ec (diff) | |
download | FreeBSD-src-af325fd3af882a05dc76b02119f41725de0dd5ec.zip FreeBSD-src-af325fd3af882a05dc76b02119f41725de0dd5ec.tar.gz |
Some bridges, like o2 micro and maybe ricoh, have some issues between
the time the card is inserted and the time that the card is
configured. This can lead to interrupt storms. The O2Micro suggested
workaround is to route the card function interrupt to IRQ1. It
appears from my testing that this is an acceptable workaround for most
chipsets (there's still some issue with the ricoh chipset).
Also, only look at the NOT_A_CARD bit when the bridge tells us there's
a card present. At least one test caused this to be true after the
card was removed, but the author couldn't recreate it with the
workaround in place. The change is more conservative than the
previous code, but still has the work around that wasn't present in
the older code.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pccbb/pccbb.c | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c index f0178e7..81f848a 100644 --- a/sys/dev/pccbb/pccbb.c +++ b/sys/dev/pccbb/pccbb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 M. Warner Losh. + * Copyright (c) 2002-2003 M. Warner Losh. * Copyright (c) 2000,2001 Jonathan Chen. * All rights reserved. * @@ -399,6 +399,39 @@ cbb_probe(device_t brdev) } +/* + * Disable function interrupts by telling the bridge to generate IRQ1 + * interrupts. These interrupts aren't really generated by the chip, since + * IRQ1 is reserved. Some chipsets assert INTA# inappropriately during + * initialization, so this helps to work around the problem. + */ +static void +cbb_disable_func_intr(struct cbb_softc *sc) +{ + uint8_t reg; + + reg = (exca_getb(&sc->exca, EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) | + EXCA_INTR_IRQ_RESERVED1; + exca_putb(&sc->exca, EXCA_INTR, reg); +} + +/* + * Enable function interrupts. We turn on function interrupts when the card + * requests an interrupt. The PCMCIA standard says that we should set + * the lower 4 bits to 0 to route via PCI. Note: we call this for both + * CardBus and R2 (PC Card) cases, but it should have no effect on CardBus + * cards. + */ +static void +cbb_enable_func_intr(struct cbb_softc *sc) +{ + uint8_t reg; + + reg = (exca_getb(&sc->exca, EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) | + EXCA_INTR_IRQ_NONE; + exca_putb(&sc->exca, EXCA_INTR, reg); +} + static void cbb_chipinit(struct cbb_softc *sc) { @@ -566,14 +599,16 @@ cbb_chipinit(struct cbb_softc *sc) } /* - * Need to tell ExCA registers to route via PCI interrupts. There - * are two ways to do this. Once is to set INTR_ENABLE and the - * other is to set CSC to 0. Since both methods are mutually - * compatible, we do both. + * Need to tell ExCA registers to CSC interrupts route via PCI + * interrupts. There are two ways to do this. Once is to set + * INTR_ENABLE and the other is to set CSC to 0. Since both + * methods are mutually compatible, we do both. */ exca_putb(&sc->exca, EXCA_INTR, EXCA_INTR_ENABLE); exca_putb(&sc->exca, EXCA_CSC_INTR, 0); + cbb_disable_func_intr(sc); + /* close all memory and io windows */ pci_write_config(sc->dev, CBBR_MEMBASE0, 0xffffffff, 4); pci_write_config(sc->dev, CBBR_MEMLIMIT0, 0, 4); @@ -869,6 +904,7 @@ cbb_setup_intr(device_t dev, device_t child, struct resource *irq, ih->arg = arg; ih->flags = flags & INTR_MPSAFE; STAILQ_INSERT_TAIL(&sc->intr_handlers, ih, entries); + cbb_enable_func_intr(sc); /* * XXX need to turn on ISA interrupts, if we ever support them, but * XXX for now that's all we need to do. @@ -952,7 +988,10 @@ cbb_event_thread(void *arg) mtx_lock(&Giant); status = cbb_get(sc, CBB_SOCKET_STATE); DPRINTF(("Status is 0x%x\n", status)); - if (status & CBB_STATE_NOT_A_CARD) { + if ((status & CBB_STATE_CD) != 0) { + not_a_card = 0; /* We know card type */ + cbb_removal(sc); + } else if (status & CBB_STATE_NOT_A_CARD) { /* * Up to 20 times, try to rescan the card when we * see NOT_A_CARD. @@ -967,10 +1006,7 @@ cbb_event_thread(void *arg) } } else { not_a_card = 0; /* We know card type */ - if ((status & CBB_STATE_CD) == 0) - cbb_insert(sc); - else - cbb_removal(sc); + cbb_insert(sc); } mtx_unlock(&Giant); @@ -1092,6 +1128,7 @@ cbb_intr(void *arg) cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD); mtx_lock(&sc->mtx); sc->flags &= ~CBB_CARD_OK; + cbb_disable_func_intr(sc); DPRINTF(("Waking up thread\n")); cv_signal(&sc->cv); mtx_unlock(&sc->mtx); |