summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2001-08-19 05:01:18 +0000
committerimp <imp@FreeBSD.org>2001-08-19 05:01:18 +0000
commit33c3c53a533a006733f0b78847fcf122188e0d74 (patch)
tree4e63915801d736650dadd97fa7343efa3c989826 /sys
parentc51d4d8eeeb05a290cd206983dba6d49fa070cf8 (diff)
downloadFreeBSD-src-33c3c53a533a006733f0b78847fcf122188e0d74.zip
FreeBSD-src-33c3c53a533a006733f0b78847fcf122188e0d74.tar.gz
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.
Diffstat (limited to 'sys')
-rw-r--r--sys/pccard/pcic_pci.c82
-rw-r--r--sys/pccard/pcic_pci.h2
-rw-r--r--sys/pccard/pcicvar.h4
3 files changed, 60 insertions, 28 deletions
diff --git a/sys/pccard/pcic_pci.c b/sys/pccard/pcic_pci.c
index 00460cd..e48e0f7 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 f5c7fd4..928f478 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 185e9a7..eef0e7f 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;
OpenPOWER on IntegriCloud