Hey all,
Enclosed is a patch to convert the sio driver from using a simplelock and the
*_intr() functions to using a single driver-wide spin mutex. The patch can
also be found at http://www.FreeBSD.org/~jhb/patches/sio.patch. Please test
this out and let me know if it breaks anyone's system.
Index: sio.c
===================================================================
RCS file: /usr/cvs/src/sys/isa/sio.c,v
retrieving revision 1.319
diff -u -r1.319 sio.c
--- sio.c 2000/10/25 05:19:37 1.319
+++ sio.c 2000/10/25 18:50:59
@@ -96,12 +96,6 @@
#endif
#include <isa/ic/ns16550.h>
-/* XXX - this is ok because we only do sio fast interrupts on i386 */
-#ifndef __i386__
-#define disable_intr()
-#define enable_intr()
-#endif
-
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from
input */
#define CALLOUT_MASK 0x80
@@ -323,7 +317,9 @@
static int sio_pci_probe __P((device_t dev));
#endif /* NPCI > 0 */
-static char driver_name[] = "sio";
+static char driver_name[] = "sio";
+static struct mtx sio_lock;
+static int sio_inited;
/* table and macro for fast conversion from a unit number to its com struct */
static devclass_t sio_devclass;
@@ -761,7 +757,6 @@
u_int flags = device_get_flags(dev);
int rid;
struct resource *port;
- int intrsave;
rid = xrid;
port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
@@ -773,6 +768,9 @@
com->bst = rman_get_bustag(port);
com->bsh = rman_get_bushandle(port);
+ if (atomic_cmpset_int(&sio_inited, 0, 1))
+ mtx_init(&sio_lock, "sio", MTX_SPIN);
+
#if 0
/*
* XXX this is broken - when we are first called, there are no
@@ -858,9 +856,7 @@
* but mask them in the processor as well in case there are some
* (misconfigured) shared interrupts.
*/
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
/* EXTRA DELAY? */
/*
@@ -957,8 +953,7 @@
CLR_FLAG(dev, COM_C_IIR_TXRDYBUG);
}
sio_setreg(com, com_cfcr, CFCR_8BITS);
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
return (iobase == siocniobase ? 0 : result);
}
@@ -998,8 +993,7 @@
irqmap[3] = isa_irq_pending();
failures[9] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_NOPEND;
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
irqs = irqmap[1] & ~irqmap[0];
if (bus_get_resource(idev, SYS_RES_IRQ, 0, &xirq, NULL) == 0 &&
@@ -1118,7 +1112,6 @@
int rid;
struct resource *port;
int ret;
- int intrstate;
rid = xrid;
port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
@@ -1187,10 +1180,8 @@
com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
} else
com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
- intrstate = save_intr();
if (siosetwater(com, com->it_in.c_ispeed) != 0) {
- COM_UNLOCK();
- restore_intr(intrstate);
+ mtx_exit(&sio_lock, MTX_SPIN);
/*
* Leave i/o resources allocated if this is a `cn'-level
* console, so that other devices can't snarf them.
@@ -1199,8 +1190,7 @@
bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
return (ENOMEM);
}
- COM_UNLOCK();
- restore_intr(intrstate);
+ mtx_exit(&sio_lock, MTX_SPIN);
termioschars(&com->it_in);
com->it_out = com->it_in;
@@ -1436,8 +1426,6 @@
goto out;
}
} else {
- int intrsave;
-
/*
* The device isn't open, so there are no conflicts.
* Initialize it. Initialization is done twice in many
@@ -1497,9 +1485,7 @@
}
}
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
(void) inb(com->line_status_port);
(void) inb(com->data_port);
com->prev_modem_status = com->last_modem_status
@@ -1511,8 +1497,7 @@
outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY
| IER_ERLS | IER_EMSC);
}
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
/*
* Handle initial DCD. Callout devices get a fake initial
* DCD (trapdoor DCD). If we are callout, then any sleeping
@@ -1734,7 +1719,8 @@
}
/*
- * Call this function with COM_LOCK. It will return with the lock still held.
+ * Call this function with the sio_lock mutex held. It will return with the
+ * lock still held.
*/
static void
sioinput(com)
@@ -1745,7 +1731,6 @@
u_char line_status;
int recv_data;
struct tty *tp;
- int intrsave;
buf = com->ibuf;
tp = com->tp;
@@ -1768,9 +1753,7 @@
* semantics instead of the save-and-disable semantics
* that are used everywhere else.
*/
- intrsave = save_intr();
- COM_UNLOCK();
- enable_intr();
+ mtx_exit(&sio_lock, MTX_SPIN);
incc = com->iptr - buf;
if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
&& (com->state & CS_RTS_IFLOW
@@ -1791,8 +1774,7 @@
tp->t_lflag &= ~FLUSHO;
comstart(tp);
}
- restore_intr(intrsave);
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
} while (buf < com->iptr);
} else {
do {
@@ -1801,9 +1783,7 @@
* semantics instead of the save-and-disable semantics
* that are used everywhere else.
*/
- intrsave = save_intr();
- COM_UNLOCK();
- enable_intr();
+ mtx_exit(&sio_lock, MTX_SPIN);
line_status = buf[com->ierroff];
recv_data = *buf++;
if (line_status
@@ -1818,8 +1798,7 @@
recv_data |= TTY_PE;
}
(*linesw[tp->t_line].l_rint)(recv_data, tp);
- restore_intr(intrsave);
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
} while (buf < com->iptr);
}
com_events -= (com->iptr - com->ibuf);
@@ -1839,14 +1818,17 @@
siointr(arg)
void *arg;
{
+ struct com_s *com;
+
#ifndef COM_MULTIPORT
- COM_LOCK();
- siointr1((struct com_s *) arg);
- COM_UNLOCK();
+ com = (struct com_s *)arg;
+
+ mtx_enter(&sio_lock, MTX_SPIN);
+ siointr1(com);
+ mtx_exit(&sio_lock, MTX_SPIN);
#else /* COM_MULTIPORT */
bool_t possibly_more_intrs;
int unit;
- struct com_s *com;
/*
* Loop until there is no activity on any port. This is necessary
@@ -1855,7 +1837,7 @@
* devices, then the edge from one may be lost because another is
* on.
*/
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
do {
possibly_more_intrs = FALSE;
for (unit = 0; unit < sio_numunits; ++unit) {
@@ -1874,7 +1856,7 @@
/* XXX COM_UNLOCK(); */
}
} while (possibly_more_intrs);
- COM_UNLOCK();
+ mtx_exit(&sio_lock, MTX_SPIN);
#endif /* COM_MULTIPORT */
}
@@ -2264,7 +2246,6 @@
siopoll(void *dummy)
{
int unit;
- int intrsave;
if (com_events == 0)
return;
@@ -2283,9 +2264,7 @@
* Discard any events related to never-opened or
* going-away devices.
*/
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
incc = com->iptr - com->ibuf;
com->iptr = com->ibuf;
if (com->state & CS_CHECKMSR) {
@@ -2293,43 +2272,33 @@
com->state &= ~CS_CHECKMSR;
}
com_events -= incc;
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
continue;
}
if (com->iptr != com->ibuf) {
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
sioinput(com);
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
}
if (com->state & CS_CHECKMSR) {
u_char delta_modem_status;
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
delta_modem_status = com->last_modem_status
^ com->prev_modem_status;
com->prev_modem_status = com->last_modem_status;
com_events -= LOTS_OF_EVENTS;
com->state &= ~CS_CHECKMSR;
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
if (delta_modem_status & MSR_DCD)
(*linesw[tp->t_line].l_modem)
(tp, com->prev_modem_status & MSR_DCD);
}
if (com->state & CS_ODONE) {
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
com_events -= LOTS_OF_EVENTS;
com->state &= ~CS_ODONE;
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
if (!(com->state & CS_BUSY)
&& !(com->extra_state & CSE_BUSYCHECK)) {
timeout(siobusycheck, com, hz / 100);
@@ -2357,7 +2326,6 @@
u_char dlbl;
int s;
int unit;
- int intrsave;
/* do historical conversions */
if (t->c_ispeed == 0)
@@ -2429,7 +2397,6 @@
* the speed change atomically. Keeping interrupts disabled is
* especially important while com_data is hidden.
*/
- intrsave = save_intr();
(void) siosetwater(com, t->c_ispeed);
if (divisor != 0) {
@@ -2517,8 +2484,7 @@
if (com->state >= (CS_BUSY | CS_TTGO))
siointr1(com);
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
splx(s);
comstart(tp);
if (com->ibufold != NULL) {
@@ -2529,8 +2495,8 @@
}
/*
- * This function must be called with interrupts enabled and the com_lock
- * unlocked. It will return with interrupts disabled and the com_lock locked.
+ * This function must be called with the sio_lock mutex released and will
+ * return with it obtained.
*/
static int
siosetwater(com, speed)
@@ -2552,8 +2518,7 @@
for (ibufsize = 128; ibufsize < cp4ticks;)
ibufsize <<= 1;
if (ibufsize == com->ibufsize) {
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
return (0);
}
@@ -2563,8 +2528,7 @@
*/
ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT);
if (ibuf == NULL) {
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
return (ENOMEM);
}
@@ -2582,8 +2546,7 @@
* Read current input buffer, if any. Continue with interrupts
* disabled.
*/
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
if (com->iptr != com->ibuf)
sioinput(com);
@@ -2612,16 +2575,13 @@
struct com_s *com;
int s;
int unit;
- int intrsave;
unit = DEV_TO_UNIT(tp->t_dev);
com = com_addr(unit);
if (com == NULL)
return;
s = spltty();
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
if (tp->t_state & TS_TTSTOP)
com->state &= ~CS_TTGO;
else
@@ -2634,8 +2594,7 @@
&& com->state & CS_RTS_IFLOW)
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
}
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
ttwwakeup(tp);
splx(s);
@@ -2651,9 +2610,7 @@
sizeof com->obuf1);
com->obufs[0].l_next = NULL;
com->obufs[0].l_queued = TRUE;
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
if (com->state & CS_BUSY) {
qp = com->obufq.l_next;
while ((next = qp->l_next) != NULL)
@@ -2665,8 +2622,7 @@
com->obufq.l_next = &com->obufs[0];
com->state |= CS_BUSY;
}
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
}
if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
com->obufs[1].l_tail
@@ -2674,9 +2630,7 @@
sizeof com->obuf2);
com->obufs[1].l_next = NULL;
com->obufs[1].l_queued = TRUE;
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
if (com->state & CS_BUSY) {
qp = com->obufq.l_next;
while ((next = qp->l_next) != NULL)
@@ -2688,18 +2642,14 @@
com->obufq.l_next = &com->obufs[1];
com->state |= CS_BUSY;
}
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
}
tp->t_state |= TS_BUSY;
}
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
if (com->state >= (CS_BUSY | CS_TTGO))
siointr1(com); /* fake interrupt to start output */
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
ttwwakeup(tp);
splx(s);
}
@@ -2710,14 +2660,11 @@
int rw;
{
struct com_s *com;
- int intrsave;
com = com_addr(DEV_TO_UNIT(tp->t_dev));
if (com == NULL || com->gone)
return;
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
if (rw & FWRITE) {
if (com->hasfifo)
#ifdef COM_ESP
@@ -2744,8 +2691,7 @@
com_events -= (com->iptr - com->ibuf);
com->iptr = com->ibuf;
}
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
comstart(tp);
}
@@ -2757,7 +2703,6 @@
{
int mcr;
int msr;
- int intrsave;
if (how == DMGET) {
bits = TIOCM_LE; /* XXX - always enabled while open */
@@ -2789,9 +2734,7 @@
mcr |= MCR_RTS;
if (com->gone)
return(0);
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
switch (how) {
case DMSET:
outb(com->modem_ctl_port,
@@ -2804,8 +2747,7 @@
outb(com->modem_ctl_port, com->mcr_image &= ~mcr);
break;
}
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
return (0);
}
@@ -2853,7 +2795,6 @@
{
struct com_s *com;
int unit;
- int intrsave;
sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout);
@@ -2865,12 +2806,9 @@
com = com_addr(unit);
if (com != NULL && !com->gone
&& (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
siointr1(com);
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
}
}
@@ -2892,13 +2830,10 @@
u_int delta;
u_long total;
- intrsave = save_intr();
- disable_intr();
- COM_LOCK();
+ mtx_enter(&sio_lock, MTX_SPIN);
delta = com->delta_error_counts[errnum];
com->delta_error_counts[errnum] = 0;
- COM_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&sio_lock, MTX_SPIN);
if (delta == 0)
continue;
total = com->error_counts[errnum] += delta;
--
John Baldwin <[EMAIL PROTECTED]> -- http://www.FreeBSD.org/~jhb/
PGP Key: http://www.baldwin.cx/~john/pgpkey.asc
"Power Users Use the Power to Serve!" - http://www.FreeBSD.org/
To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message