summaryrefslogtreecommitdiffstats
path: root/sys/dev/pccbb
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2003-06-12 03:37:28 +0000
committerimp <imp@FreeBSD.org>2003-06-12 03:37:28 +0000
commit2c0da83361413653fcb6462f83005ae3f97e9a64 (patch)
treef63de3e9804db173ad6de64a14c36a45a4238605 /sys/dev/pccbb
parent78dbcf9c67e2333962eccae3afe7532398f373ae (diff)
downloadFreeBSD-src-2c0da83361413653fcb6462f83005ae3f97e9a64.zip
FreeBSD-src-2c0da83361413653fcb6462f83005ae3f97e9a64.tar.gz
Make cbb interrupts MPSAFE:
o Register ISR INTR_MPSAFE. o Loop on KTHREAD_DONE == 0 in the thread. o Safe the INTR_MPSAFE flag for client drivers (don't know if there are any CardBus/PCI drivers that are INTR_MPSAFE) o Read status after acquiring mtx_lock(Giant) rather than before so that we catch state changes that happen while Giant is being acquired. o Turn off the CD bit when we see a CD interrupt, and turn it back on after we've attached/detached the card. o On suspend, actually set the CBB_SOCKET_MASK to zero rather than oring in '0' to turn it off on suspend. o If the ISR that's registerd is MPSAFE, don't acquire Giant around call to client ISR. o Fix comments to reflect these changes.
Diffstat (limited to 'sys/dev/pccbb')
-rw-r--r--sys/dev/pccbb/pccbb.c51
-rw-r--r--sys/dev/pccbb/pccbbvar.h5
2 files changed, 34 insertions, 22 deletions
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c
index 68a7924..93bd251 100644
--- a/sys/dev/pccbb/pccbb.c
+++ b/sys/dev/pccbb/pccbb.c
@@ -730,8 +730,8 @@ cbb_attach(device_t brdev)
goto err;
}
- if (bus_setup_intr(brdev, sc->irq_res, INTR_TYPE_AV, cbb_intr, sc,
- &sc->intrhand)) {
+ if (bus_setup_intr(brdev, sc->irq_res, INTR_TYPE_AV | INTR_MPSAFE,
+ cbb_intr, sc, &sc->intrhand)) {
device_printf(brdev, "couldn't establish interrupt");
goto err;
}
@@ -866,6 +866,7 @@ cbb_setup_intr(device_t dev, device_t child, struct resource *irq,
*cookiep = ih;
ih->intr = intr;
ih->arg = arg;
+ ih->flags = flags & INTR_MPSAFE;
STAILQ_INSERT_TAIL(&sc->intr_handlers, ih, entries);
/*
* XXX need to turn on ISA interrupts, if we ever support them, but
@@ -937,24 +938,17 @@ cbb_event_thread(void *arg)
uint32_t status;
int err;
- /*
- * We take out Giant here because we need it deep, down in
- * the bowels of the vm system for mapping the memory we need
- * to read the CIS. We also need it for kthread_exit, which
- * drops it.
- */
sc->flags |= CBB_KTHREAD_RUNNING;
- while (1) {
+ while ((sc->flags & CBB_KTHREAD_DONE) == 0) {
/*
- * Check to see if we have anything first so that
- * if there's a card already inserted, we do the
- * right thing.
+ * We take out Giant here because we need it deep,
+ * down in the bowels of the vm system for mapping the
+ * memory we need to read the CIS. In addition, since
+ * we are adding/deleting devices from the dev tree,
+ * and that code isn't MP safe, we have to hold Giant.
*/
- if (sc->flags & CBB_KTHREAD_DONE)
- break;
-
- status = cbb_get(sc, CBB_SOCKET_STATE);
mtx_lock(&Giant);
+ status = cbb_get(sc, CBB_SOCKET_STATE);
if ((status & CBB_SOCKET_STAT_CD) == 0)
cbb_insert(sc);
else
@@ -962,20 +956,32 @@ cbb_event_thread(void *arg)
mtx_unlock(&Giant);
/*
+ * In our ISR, we turn off the card changed interrupt. Turn
+ * them back on here before we wait for them to happen. We
+ * turn them on/off so that we can tolerate a large latency
+ * between the time we signal cbb_event_thread and it gets
+ * a chance to run.
+ */
+ cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
+
+ /*
* Wait until it has been 1s since the last time we
* get an interrupt. We handle the rest of the interrupt
- * at the top of the loop.
+ * at the top of the loop. Although we clear the bit in the
+ * ISR, we signal sc->cv from the detach path after we've
+ * set the CBB_KTHREAD_DONE bit, so we can't do a simple
+ * 1s sleep here.
*/
mtx_lock(&sc->mtx);
cv_wait(&sc->cv, &sc->mtx);
err = 0;
- while (err != EWOULDBLOCK &&
+ while (err != EWOULDBLOCK &&
(sc->flags & CBB_KTHREAD_DONE) == 0)
err = cv_timedwait(&sc->cv, &sc->mtx, 1 * hz);
mtx_unlock(&sc->mtx);
}
sc->flags &= ~CBB_KTHREAD_RUNNING;
- mtx_lock(&Giant);
+ mtx_lock(&Giant); /* kthread_exit drops */
kthread_exit(0);
}
@@ -1063,6 +1069,7 @@ cbb_intr(void *arg)
* excellent results.
*/
if (sockevent & CBB_SOCKET_EVENT_CD) {
+ cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
mtx_lock(&sc->mtx);
sc->flags &= ~CBB_CARD_OK;
cv_signal(&sc->cv);
@@ -1080,7 +1087,11 @@ cbb_intr(void *arg)
}
if (sc->flags & CBB_CARD_OK) {
STAILQ_FOREACH(ih, &sc->intr_handlers, entries) {
+ if ((ih->flags & INTR_MPSAFE) != 0)
+ mtx_lock(&Giant);
(*ih->intr)(ih->arg);
+ if ((ih->flags & INTR_MPSAFE) != 0)
+ mtx_lock(&Giant);
}
}
}
@@ -1877,7 +1888,7 @@ cbb_suspend(device_t self)
int error = 0;
struct cbb_softc *sc = device_get_softc(self);
- cbb_setb(sc, CBB_SOCKET_MASK, 0); /* Quiet hardware */
+ cbb_set(sc, CBB_SOCKET_MASK, 0); /* Quiet hardware */
bus_teardown_intr(self, sc->irq_res, sc->intrhand);
sc->flags &= ~CBB_CARD_OK; /* Card is bogus now */
error = bus_generic_suspend(self);
diff --git a/sys/dev/pccbb/pccbbvar.h b/sys/dev/pccbb/pccbbvar.h
index d77d33b..c050c11 100644
--- a/sys/dev/pccbb/pccbbvar.h
+++ b/sys/dev/pccbb/pccbbvar.h
@@ -33,8 +33,9 @@
*/
struct cbb_intrhand {
- driver_intr_t *intr;
- void *arg;
+ driver_intr_t *intr;
+ void *arg;
+ uint32_t flags;
STAILQ_ENTRY(cbb_intrhand) entries;
};
OpenPOWER on IntegriCloud