summaryrefslogtreecommitdiffstats
path: root/sys/dev/scc
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2006-07-24 22:25:16 +0000
committermarcel <marcel@FreeBSD.org>2006-07-24 22:25:16 +0000
commit047391001188e58ab368864adb44a723e0767d8d (patch)
treec73efe57e4cfccb1fb4041a213b416b102159de8 /sys/dev/scc
parent0bad58d974eac93f7cf843a0338a5967d1287413 (diff)
downloadFreeBSD-src-047391001188e58ab368864adb44a723e0767d8d.zip
FreeBSD-src-047391001188e58ab368864adb44a723e0767d8d.tar.gz
If we have multiple interrupt resources, like for Z8530 clones on the
mac-io bus, we cannot setup FAST interrupt handlers. This because we use spinlocks to protect the hardware and all interrupt resources are assigned the same interrupt handler. When the interrupt handler is invoked for interrupt X, it could be preempted for interrupt Y while it was holding the lock (where X and Y are the interrupt resources corresponding a single instance of this driver). This is a deadlock. By only using a MPSAFE handler in that case we prevent preemption.
Diffstat (limited to 'sys/dev/scc')
-rw-r--r--sys/dev/scc/scc_core.c24
1 files changed, 13 insertions, 11 deletions
diff --git a/sys/dev/scc/scc_core.c b/sys/dev/scc/scc_core.c
index c9cda51..1101f8a 100644
--- a/sys/dev/scc/scc_core.c
+++ b/sys/dev/scc/scc_core.c
@@ -102,7 +102,7 @@ scc_bfe_attach(device_t dev)
const char *sep;
bus_space_handle_t bh;
u_long base, size, start;
- int c, error, mode, sysdev;
+ int c, error, mode, nintr, sysdev;
/*
* The sc_class field defines the type of SCC we're going to work
@@ -140,11 +140,14 @@ scc_bfe_attach(device_t dev)
*/
sc->sc_chan = malloc(sizeof(struct scc_chan) * cl->cl_channels,
M_SCC, M_WAITOK | M_ZERO);
+ nintr = 0;
for (c = 0; c < cl->cl_channels; c++) {
ch = &sc->sc_chan[c];
ch->ch_irid = c;
ch->ch_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
&ch->ch_irid, RF_ACTIVE | RF_SHAREABLE);
+ if (ch->ch_ires != NULL)
+ nintr++;
}
/*
@@ -210,16 +213,18 @@ scc_bfe_attach(device_t dev)
* that our children's are fast as well. We make it MPSAFE as soon
* as a child sets up a MPSAFE interrupt handler.
* Of course, if we can't setup a fast handler, we make it MPSAFE
- * right away.
+ * right away. If we have multiple interrupt resources, we don't
+ * use fast handlers, because we need to serialize the interrupts.
*/
for (c = 0; c < cl->cl_channels; c++) {
ch = &sc->sc_chan[c];
if (ch->ch_ires == NULL)
continue;
- error = bus_setup_intr(dev, ch->ch_ires,
- INTR_TYPE_TTY | INTR_FAST, scc_bfe_intr, sc,
- &ch->ch_icookie);
- if (error) {
+ if (nintr == 1)
+ error = bus_setup_intr(dev, ch->ch_ires,
+ INTR_TYPE_TTY | INTR_FAST, scc_bfe_intr, sc,
+ &ch->ch_icookie);
+ if (nintr > 1 || error) {
error = bus_setup_intr(dev, ch->ch_ires,
INTR_TYPE_TTY | INTR_MPSAFE, scc_bfe_intr, sc,
&ch->ch_icookie);
@@ -231,13 +236,10 @@ scc_bfe_attach(device_t dev)
bus_release_resource(dev, SYS_RES_IRQ, ch->ch_irid,
ch->ch_ires);
ch->ch_ires = NULL;
+ nintr--;
}
}
- sc->sc_polled = 1;
- for (c = 0; c < cl->cl_channels; c++) {
- if (sc->sc_chan[0].ch_ires != NULL)
- sc->sc_polled = 0;
- }
+ sc->sc_polled = (nintr == 0) ? 1 : 0;
/*
* Attach all child devices that were probed successfully.
OpenPOWER on IntegriCloud