MFC rev 200397:
Fix interrupt handling. PR: kern/140947
This commit is contained in:
parent
d9adc7058d
commit
e88e64d392
@ -129,62 +129,78 @@ puc_intr(void *arg)
|
||||
{
|
||||
struct puc_port *port;
|
||||
struct puc_softc *sc = arg;
|
||||
u_long dev, devs;
|
||||
int i, idx, ipend, isrc;
|
||||
u_long ds, dev, devs;
|
||||
int i, idx, ipend, isrc, nints;
|
||||
uint8_t ilr;
|
||||
|
||||
devs = sc->sc_serdevs;
|
||||
if (sc->sc_ilr == PUC_ILR_DIGI) {
|
||||
idx = 0;
|
||||
while (devs & (0xfful << idx)) {
|
||||
ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
|
||||
devs &= ~0ul ^ ((u_long)ilr << idx);
|
||||
idx += 8;
|
||||
}
|
||||
} else if (sc->sc_ilr == PUC_ILR_QUATECH) {
|
||||
nints = 0;
|
||||
while (1) {
|
||||
/*
|
||||
* Don't trust the value if it's the same as the option
|
||||
* register. It may mean that the ILR is not active and
|
||||
* we're reading the option register instead. This may
|
||||
* lead to false positives on 8-port boards.
|
||||
* Obtain the set of devices with pending interrupts.
|
||||
*/
|
||||
ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
|
||||
if (ilr != (sc->sc_cfg_data & 0xff))
|
||||
devs &= (u_long)ilr;
|
||||
}
|
||||
|
||||
ipend = 0;
|
||||
idx = 0, dev = 1UL;
|
||||
while (devs != 0UL) {
|
||||
while ((devs & dev) == 0UL)
|
||||
idx++, dev <<= 1;
|
||||
devs &= ~dev;
|
||||
port = &sc->sc_port[idx];
|
||||
port->p_ipend = SERDEV_IPEND(port->p_dev);
|
||||
ipend |= port->p_ipend;
|
||||
}
|
||||
|
||||
i = 0, isrc = SER_INT_OVERRUN;
|
||||
while (ipend) {
|
||||
while (i < PUC_ISRCCNT && !(ipend & isrc))
|
||||
i++, isrc <<= 1;
|
||||
KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
|
||||
ipend &= ~isrc;
|
||||
idx = 0, dev = 1UL;
|
||||
devs = sc->sc_serdevs;
|
||||
while (devs != 0UL) {
|
||||
while ((devs & dev) == 0UL)
|
||||
idx++, dev <<= 1;
|
||||
devs &= ~dev;
|
||||
port = &sc->sc_port[idx];
|
||||
if (!(port->p_ipend & isrc))
|
||||
continue;
|
||||
if (port->p_ihsrc[i] != NULL)
|
||||
(*port->p_ihsrc[i])(port->p_iharg);
|
||||
if (sc->sc_ilr == PUC_ILR_DIGI) {
|
||||
idx = 0;
|
||||
while (devs & (0xfful << idx)) {
|
||||
ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
|
||||
devs &= ~0ul ^ ((u_long)ilr << idx);
|
||||
idx += 8;
|
||||
}
|
||||
} else if (sc->sc_ilr == PUC_ILR_QUATECH) {
|
||||
/*
|
||||
* Don't trust the value if it's the same as the option
|
||||
* register. It may mean that the ILR is not active and
|
||||
* we're reading the option register instead. This may
|
||||
* lead to false positives on 8-port boards.
|
||||
*/
|
||||
ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
|
||||
if (ilr != (sc->sc_cfg_data & 0xff))
|
||||
devs &= (u_long)ilr;
|
||||
}
|
||||
if (devs == 0UL)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Obtain the set of interrupt sources from those devices
|
||||
* that have pending interrupts.
|
||||
*/
|
||||
ipend = 0;
|
||||
idx = 0, dev = 1UL;
|
||||
ds = devs;
|
||||
while (ds != 0UL) {
|
||||
while ((ds & dev) == 0UL)
|
||||
idx++, dev <<= 1;
|
||||
ds &= ~dev;
|
||||
port = &sc->sc_port[idx];
|
||||
port->p_ipend = SERDEV_IPEND(port->p_dev);
|
||||
ipend |= port->p_ipend;
|
||||
}
|
||||
if (ipend == 0)
|
||||
break;
|
||||
|
||||
i = 0, isrc = SER_INT_OVERRUN;
|
||||
while (ipend) {
|
||||
while (i < PUC_ISRCCNT && !(ipend & isrc))
|
||||
i++, isrc <<= 1;
|
||||
KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
|
||||
ipend &= ~isrc;
|
||||
idx = 0, dev = 1UL;
|
||||
ds = devs;
|
||||
while (ds != 0UL) {
|
||||
while ((ds & dev) == 0UL)
|
||||
idx++, dev <<= 1;
|
||||
ds &= ~dev;
|
||||
port = &sc->sc_port[idx];
|
||||
if (!(port->p_ipend & isrc))
|
||||
continue;
|
||||
if (port->p_ihsrc[i] != NULL)
|
||||
(*port->p_ihsrc[i])(port->p_iharg);
|
||||
nints++;
|
||||
}
|
||||
}
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
return (FILTER_STRAY);
|
||||
|
||||
return ((nints > 0) ? FILTER_HANDLED : FILTER_STRAY);
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
x
Reference in New Issue
Block a user