From 33c3c53a533a006733f0b78847fcf122188e0d74 Mon Sep 17 00:00:00 2001 From: imp Date: Sun, 19 Aug 2001 05:01:18 +0000 Subject: [PATCH] Improve interlocking for card removal. We now can remove the card in the ISR. We keep track of the card state and don't call the IRS when the card isn't inserted. This helps quite a bit with card ejection problems that Ian was seeing. Submitted by: Ian Dowse MFC upon: re approvel. --- sys/pccard/pcic_pci.c | 82 +++++++++++++++++++++++++++++-------------- sys/pccard/pcic_pci.h | 2 +- sys/pccard/pcicvar.h | 4 ++- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/sys/pccard/pcic_pci.c b/sys/pccard/pcic_pci.c index 00460cd12ed4..e48e0f79d25a 100644 --- a/sys/pccard/pcic_pci.c +++ b/sys/pccard/pcic_pci.c @@ -438,25 +438,36 @@ pcic_pci_cardtype(u_int32_t stat) return ("none (can't happen)"); } +/* + * Card insertion and removal code. The insertion events need to be + * debounced so that the noisy insertion/removal events don't result + * in the hardware being initialized many times, only to be torn down + * as well. This may also cause races with pccardd. Instead, we wait + * for the insertion signal to be stable for 0.5 seconds before we declare + * it to be a real insertion event. Removal is done right away. + * + * Note: We only handle the card detect change events. We don't handle + * power events and status change events. + */ static void -pcic_cd_event(void *arg) +pcic_cd_insert(void *arg) { struct pcic_softc *sc = (struct pcic_softc *) arg; struct pcic_slot *sp = &sc->slots[0]; u_int32_t stat; - + + sc->cd_pending = 0; stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); - device_printf(sc->dev, "debounced state is 0x%x\n", stat); - if ((stat & CB_SS_CD) == 0) { - if ((stat & CB_SS_16BIT) == 0) - device_printf(sp->sc->dev, "Unsupported card: %s\n", - pcic_pci_cardtype(stat)); - else - pccard_event(sp->slt, card_inserted); - } else { - pccard_event(sp->slt, card_removed); - } - sc->cd_pending = 0; + + /* Just return if the interrupt handler missed a remove transition. */ + if ((stat & CB_SS_CD) != 0) + return; + sc->cd_present = 1; + if ((stat & CB_SS_16BIT) == 0) + device_printf(sp->sc->dev, "Card type %s is unsupported\n", + pcic_pci_cardtype(stat)); + else + pccard_event(sp->slt, card_inserted); } static void @@ -466,20 +477,37 @@ pcic_pci_intr(void *arg) struct pcic_slot *sp = &sc->slots[0]; u_int32_t event; u_int32_t stat; + int present; event = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_EVENT); if (event != 0) { - device_printf(sc->dev, "Event mask 0x%x\n", event); - if ((event & CB_SE_CD) != 0 && !sc->cd_pending) { - sc->cd_pending = 1; - timeout(pcic_cd_event, arg, hz/2); + stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); + if (bootverbose) + device_printf(sc->dev, "Event mask 0x%x stat 0x%x\n", + event, stat); + + present = (stat & CB_SS_CD) == 0; + if (present != sc->cd_present) { + if (sc->cd_pending) { + untimeout(pcic_cd_insert, arg, sc->cd_ch); + sc->cd_pending = 0; + } + /* Delay insert events to debounce noisy signals. */ + if (present) { + sc->cd_ch = timeout(pcic_cd_insert, arg, hz/2); + sc->cd_pending = 1; + } else { + sc->cd_present = 0; + sp->intr = NULL; + pccard_event(sp->slt, card_removed); + } } - /* Ack the interrupt, all of them to be safe */ - bus_space_write_4(sp->bst, sp->bsh, 0, 0xffffffff); + /* Ack the interrupt */ + bus_space_write_4(sp->bst, sp->bsh, 0, event); } /* - * TI chips also require us to read the old ExCA register for + * Some TI chips also require us to read the old ExCA register for * card status change when we route CSC via PCI! So, we go ahead * and read it to clear the bits. Maybe we should check the status * ala the ISA interrupt handler, but those changes should be caught @@ -487,12 +515,14 @@ pcic_pci_intr(void *arg) */ sp->getb(sp, PCIC_STAT_CHG); - /* Now call children interrupts if any */ - stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); - if ((stat & CB_SS_CD) == 0) { - if (sp->intr != NULL) - sp->intr(sp->argp); - } + /* + * If we have a card in the slot with an interrupt handler, then + * call it. Note: This means that each card can have at most one + * interrupt handler for it. Since multifunction cards aren't + * supported, this shouldn't cause a problem in practice. + */ + if (sc->cd_present && sp->intr != NULL) + sp->intr(sp->argp); } /* diff --git a/sys/pccard/pcic_pci.h b/sys/pccard/pcic_pci.h index f5c7fd43419b..928f4786e690 100644 --- a/sys/pccard/pcic_pci.h +++ b/sys/pccard/pcic_pci.h @@ -144,8 +144,8 @@ #define CB_SOCKET_POWER 0x14 #define CB_EXCA_OFFSET 0x800 /* Offset for ExCA registers */ -#define CB_SM_CD 0x6 /* Socket MASK Card detect */ #define CB_SE_CD 0x6 /* Socket Event Card detect */ +#define CB_SM_CD 0x6 /* Socket MASK Card detect */ #define CB_SS_CARDSTS 0x00000001 /* Card Status Change */ #define CB_SS_CD1 0x00000002 /* Card Detect 1 */ diff --git a/sys/pccard/pcicvar.h b/sys/pccard/pcicvar.h index 185e9a7652c0..eef0e7f04b62 100644 --- a/sys/pccard/pcicvar.h +++ b/sys/pccard/pcicvar.h @@ -67,7 +67,9 @@ struct pcic_softc void (*slot_poll)(void *); struct callout_handle timeout_ch; struct pcic_slot slots[PCIC_MAX_SLOTS]; - int cd_pending; + int cd_pending; /* debounce timeout active */ + int cd_present; /* debounced card-present state */ + struct callout_handle cd_ch; /* handle for pcic_cd_insert */ }; extern devclass_t pcic_devclass;