aboutsummaryrefslogtreecommitdiff
path: root/sys/i386/isa/cy.c
diff options
context:
space:
mode:
authorJason Evans <jasone@FreeBSD.org>2000-09-07 01:33:02 +0000
committerJason Evans <jasone@FreeBSD.org>2000-09-07 01:33:02 +0000
commit0384fff8c5b098545c3db311b0e0aa1ec4c9ae7e (patch)
treebc6e36e781569f3efe04995c0b0befebb9154ef5 /sys/i386/isa/cy.c
parent62ae6c89ad2b03770097d05590093f93b9d94e08 (diff)
downloadsrc-0384fff8c5b098545c3db311b0e0aa1ec4c9ae7e.tar.gz
src-0384fff8c5b098545c3db311b0e0aa1ec4c9ae7e.zip
Major update to the way synchronization is done in the kernel. Highlights
include: * Mutual exclusion is used instead of spl*(). See mutex(9). (Note: The alpha port is still in transition and currently uses both.) * Per-CPU idle processes. * Interrupts are run in their own separate kernel threads and can be preempted (i386 only). Partially contributed by: BSDi (BSD/OS) Submissions by (at least): cp, dfr, dillon, grog, jake, jhb, sheldonh
Notes
Notes: svn path=/head/; revision=65557
Diffstat (limited to 'sys/i386/isa/cy.c')
-rw-r--r--sys/i386/isa/cy.c197
1 files changed, 144 insertions, 53 deletions
diff --git a/sys/i386/isa/cy.c b/sys/i386/isa/cy.c
index 52a8cf36892f..5487d8fe6299 100644
--- a/sys/i386/isa/cy.c
+++ b/sys/i386/isa/cy.c
@@ -94,11 +94,6 @@
#error "The cy device requires the old isa compatibility shims"
#endif
-#ifdef SMP
-#define disable_intr() COM_DISABLE_INTR()
-#define enable_intr() COM_ENABLE_INTR()
-#endif /* SMP */
-
/*
* Dictionary so that I can name everything *sio* or *com* to compare with
* sio.c. There is also lots of ugly formatting and unnecessary ifdefs to
@@ -366,7 +361,7 @@ static struct com_s *p_com_addr[NSIO];
#define com_addr(unit) (p_com_addr[unit])
struct isa_driver siodriver = {
- INTR_TYPE_TTY | INTR_TYPE_FAST,
+ INTR_TYPE_TTY | INTR_FAST,
sioprobe,
sioattach,
driver_name
@@ -604,11 +599,9 @@ cyattach_common(cy_iobase, cy_align)
com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
}
if (siosetwater(com, com->it_in.c_ispeed) != 0) {
- enable_intr();
free(com, M_DEVBUF);
return (0);
}
- enable_intr();
termioschars(&com->it_in);
com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
com->it_out = com->it_in;
@@ -662,6 +655,7 @@ sioopen(dev, flag, mode, p)
int s;
struct tty *tp;
int unit;
+ int intrsave;
mynor = minor(dev);
unit = MINOR_TO_UNIT(mynor);
@@ -768,14 +762,17 @@ open_top:
}
}
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
(void) inb(com->line_status_port);
(void) inb(com->data_port);
com->prev_modem_status = com->last_modem_status
= inb(com->modem_status_port);
outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
| IER_EMSC);
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
#else /* !0 */
/*
* Flush fifos. This requires a full channel reset which
@@ -786,13 +783,16 @@ open_top:
CD1400_CCR_CMDRESET | CD1400_CCR_CHANRESET);
cd1400_channel_cmd(com, com->channel_control);
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
com->prev_modem_status = com->last_modem_status
= cd_getreg(com, CD1400_MSVR2);
cd_setreg(com, CD1400_SRER,
com->intr_enable
= CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
#endif /* 0 */
/*
* Handle initial DCD. Callout devices get a fake initial
@@ -875,6 +875,7 @@ comhardclose(com)
int s;
struct tty *tp;
int unit;
+ int intrsave;
unit = com->unit;
iobase = com->iobase;
@@ -888,10 +889,13 @@ comhardclose(com)
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
#else
/* XXX */
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
com->etc = ETC_NONE;
cd_setreg(com, CD1400_COR2, com->cor[1] &= ~CD1400_COR2_ETC);
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF);
#endif
@@ -899,9 +903,12 @@ comhardclose(com)
#if 0
outb(iobase + com_ier, 0);
#else
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
cd_setreg(com, CD1400_SRER, com->intr_enable = 0);
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
#endif
tp = com->tp;
if ((tp->t_cflag & HUPCL)
@@ -991,6 +998,11 @@ siodtrwakeup(chan)
wakeup(&com->dtr_wait);
}
+/*
+ * This function:
+ * a) needs to be called with COM_LOCK() held, and
+ * b) needs to return with COM_LOCK() held.
+ */
static void
sioinput(com)
struct com_s *com;
@@ -1000,6 +1012,7 @@ sioinput(com)
u_char line_status;
int recv_data;
struct tty *tp;
+ int intrsave;
buf = com->ibuf;
tp = com->tp;
@@ -1016,7 +1029,15 @@ sioinput(com)
* slinput is reasonably fast (usually 40 instructions plus
* call overhead).
*/
+
do {
+ /*
+ * This may look odd, but it is using save-and-enable
+ * semantics instead of the save-and-disable semantics
+ * that are used everywhere else.
+ */
+ intrsave = save_intr();
+ COM_UNLOCK();
enable_intr();
incc = com->iptr - buf;
if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
@@ -1038,10 +1059,18 @@ sioinput(com)
tp->t_lflag &= ~FLUSHO;
comstart(tp);
}
- disable_intr();
+ restore_intr(intrsave);
+ COM_LOCK();
} while (buf < com->iptr);
} else {
do {
+ /*
+ * This may look odd, but it is using save-and-enable
+ * semantics instead of the save-and-disable semantics
+ * that are used everywhere else.
+ */
+ intrsave = save_intr();
+ COM_UNLOCK();
enable_intr();
line_status = buf[com->ierroff];
recv_data = *buf++;
@@ -1057,7 +1086,8 @@ sioinput(com)
recv_data |= TTY_PE;
}
(*linesw[tp->t_line].l_rint)(recv_data, tp);
- disable_intr();
+ restore_intr(intrsave);
+ COM_LOCK();
} while (buf < com->iptr);
}
com_events -= (com->iptr - com->ibuf);
@@ -1729,6 +1759,7 @@ static void
siopoll()
{
int unit;
+ int intrsave;
#ifdef CyDebug
++cy_timeouts;
@@ -1751,7 +1782,9 @@ repeat:
* (actually never opened devices) so that we don't
* loop.
*/
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
incc = com->iptr - com->ibuf;
com->iptr = com->ibuf;
if (com->state & CS_CHECKMSR) {
@@ -1759,7 +1792,8 @@ repeat:
com->state &= ~CS_CHECKMSR;
}
com_events -= incc;
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
if (incc != 0)
log(LOG_DEBUG,
"sio%d: %d events for device with no tp\n",
@@ -1767,29 +1801,39 @@ repeat:
continue;
}
if (com->iptr != com->ibuf) {
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
sioinput(com);
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
}
if (com->state & CS_CHECKMSR) {
u_char delta_modem_status;
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
+ sioinput(com);
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;
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
if (delta_modem_status & MSR_DCD)
(*linesw[tp->t_line].l_modem)
(tp, com->prev_modem_status & MSR_DCD);
}
if (com->extra_state & CSE_ODONE) {
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
com_events -= LOTS_OF_EVENTS;
com->extra_state &= ~CSE_ODONE;
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
if (!(com->state & CS_BUSY)) {
tp->t_state &= ~TS_BUSY;
ttwwakeup(com->tp);
@@ -1801,10 +1845,13 @@ repeat:
}
}
if (com->state & CS_ODONE) {
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
com_events -= LOTS_OF_EVENTS;
com->state &= ~CS_ODONE;
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
(*linesw[tp->t_line].l_start)(tp);
}
if (com_events == 0)
@@ -1833,6 +1880,7 @@ comparam(tp, t)
u_char opt;
int s;
int unit;
+ int intrsave;
/* do historical conversions */
if (t->c_ispeed == 0)
@@ -1857,14 +1905,9 @@ comparam(tp, t)
else
(void)commctl(com, TIOCM_DTR, DMBIS);
- /*
- * This returns with interrupts disabled so that we can complete
- * the speed change atomically.
- */
(void) siosetwater(com, t->c_ispeed);
/* XXX we don't actually change the speed atomically. */
- enable_intr();
if (idivisor != 0) {
cd_setreg(com, CD1400_RBPR, idivisor);
@@ -1985,12 +2028,15 @@ comparam(tp, t)
if (cflag & CCTS_OFLOW)
opt |= CD1400_COR2_CCTS_OFLOW;
#endif
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
if (opt != com->cor[1]) {
cor_change |= CD1400_CCR_COR2;
cd_setreg(com, CD1400_COR2, com->cor[1] = opt);
}
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
/*
* set channel option register 3 -
@@ -2111,7 +2157,9 @@ comparam(tp, t)
* XXX should have done this long ago, but there is too much state
* to change all atomically.
*/
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
com->state &= ~CS_TTGO;
if (!(tp->t_state & TS_TTSTOP))
@@ -2177,7 +2225,8 @@ comparam(tp, t)
| CD1400_SRER_TXMPTY);
}
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
splx(s);
comstart(tp);
if (com->ibufold != NULL) {
@@ -2196,6 +2245,7 @@ siosetwater(com, speed)
u_char *ibuf;
int ibufsize;
struct tty *tp;
+ int intrsave;
/*
* Make the buffer size large enough to handle a softtty interrupt
@@ -2207,7 +2257,6 @@ siosetwater(com, speed)
for (ibufsize = 128; ibufsize < cp4ticks;)
ibufsize <<= 1;
if (ibufsize == com->ibufsize) {
- disable_intr();
return (0);
}
@@ -2217,7 +2266,6 @@ siosetwater(com, speed)
*/
ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT);
if (ibuf == NULL) {
- disable_intr();
return (ENOMEM);
}
@@ -2235,7 +2283,9 @@ siosetwater(com, speed)
* Read current input buffer, if any. Continue with interrupts
* disabled.
*/
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
if (com->iptr != com->ibuf)
sioinput(com);
@@ -2254,6 +2304,9 @@ siosetwater(com, speed)
com->ibufend = ibuf + ibufsize;
com->ierroff = ibufsize;
com->ihighwater = ibuf + 3 * ibufsize / 4;
+
+ COM_UNLOCK();
+ restore_intr(intrsave);
return (0);
}
@@ -2267,6 +2320,7 @@ comstart(tp)
bool_t started;
#endif
int unit;
+ int intrsave;
unit = DEV_TO_UNIT(tp->t_dev);
com = com_addr(unit);
@@ -2277,7 +2331,9 @@ comstart(tp)
started = FALSE;
#endif
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
if (tp->t_state & TS_TTSTOP) {
com->state &= ~CS_TTGO;
if (com->intr_enable & CD1400_SRER_TXRDY)
@@ -2313,7 +2369,8 @@ comstart(tp)
com->mcr_image |= com->mcr_rts);
#endif
}
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
ttwwakeup(tp);
splx(s);
@@ -2332,7 +2389,9 @@ comstart(tp)
sizeof com->obuf1);
com->obufs[0].l_next = NULL;
com->obufs[0].l_queued = TRUE;
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
if (com->state & CS_BUSY) {
qp = com->obufq.l_next;
while ((next = qp->l_next) != NULL)
@@ -2351,7 +2410,8 @@ comstart(tp)
& ~CD1400_SRER_TXMPTY)
| CD1400_SRER_TXRDY);
}
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
}
if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
#ifdef CyDebug
@@ -2362,7 +2422,9 @@ comstart(tp)
sizeof com->obuf2);
com->obufs[1].l_next = NULL;
com->obufs[1].l_queued = TRUE;
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
if (com->state & CS_BUSY) {
qp = com->obufq.l_next;
while ((next = qp->l_next) != NULL)
@@ -2381,7 +2443,8 @@ comstart(tp)
& ~CD1400_SRER_TXMPTY)
| CD1400_SRER_TXRDY);
}
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
}
tp->t_state |= TS_BUSY;
}
@@ -2390,10 +2453,13 @@ comstart(tp)
++com->start_real;
#endif
#if 0
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
if (com->state >= (CS_BUSY | CS_TTGO))
siointr1(com); /* fake interrupt to start output */
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
#endif
ttwwakeup(tp);
splx(s);
@@ -2406,10 +2472,13 @@ comstop(tp, rw)
{
struct com_s *com;
bool_t wakeup_etc;
+ int intrsave;
com = com_addr(DEV_TO_UNIT(tp->t_dev));
wakeup_etc = FALSE;
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
if (rw & FWRITE) {
com->obufs[0].l_queued = FALSE;
com->obufs[1].l_queued = FALSE;
@@ -2432,7 +2501,8 @@ comstop(tp, rw)
com_events -= (com->iptr - com->ibuf);
com->iptr = com->ibuf;
}
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
if (wakeup_etc)
wakeup(&com->etc);
if (rw & FWRITE && com->etc == ETC_NONE)
@@ -2448,6 +2518,7 @@ commctl(com, bits, how)
{
int mcr;
int msr;
+ int intrsave;
if (how == DMGET) {
if (com->channel_control & CD1400_CCR_RCVEN)
@@ -2485,7 +2556,9 @@ commctl(com, bits, how)
mcr |= com->mcr_dtr;
if (bits & TIOCM_RTS)
mcr |= com->mcr_rts;
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
switch (how) {
case DMSET:
com->mcr_image = mcr;
@@ -2503,7 +2576,8 @@ commctl(com, bits, how)
cd_setreg(com, CD1400_MSVR2, mcr);
break;
}
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
return (0);
}
@@ -2565,9 +2639,14 @@ comwakeup(chan)
com = com_addr(unit);
if (com != NULL
&& (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
+ int intrsave;
+
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
siointr1(com);
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
}
}
#endif
@@ -2587,11 +2666,15 @@ comwakeup(chan)
for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
u_int delta;
u_long total;
+ int intrsave;
+ intrsave = save_intr();
disable_intr();
+ COM_LOCK();
delta = com->delta_error_counts[errnum];
com->delta_error_counts[errnum] = 0;
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
if (delta == 0)
continue;
total = com->error_counts[errnum] += delta;
@@ -2743,6 +2826,8 @@ cd_etc(com, etc)
struct com_s *com;
int etc;
{
+ int intrsave;
+
/*
* We can't change the hardware's ETC state while there are any
* characters in the tx fifo, since those characters would be
@@ -2754,26 +2839,28 @@ cd_etc(com, etc)
* for the tx to become empty so that the command is sure to be
* executed soon after we issue it.
*/
+ intrsave = save_intr();
disable_intr();
- if (com->etc == etc) {
- enable_intr();
+ COM_LOCK();
+ if (com->etc == etc)
goto wait;
- }
if ((etc == CD1400_ETC_SENDBREAK
&& (com->etc == ETC_BREAK_STARTING
|| com->etc == ETC_BREAK_STARTED))
|| (etc == CD1400_ETC_STOPBREAK
&& (com->etc == ETC_BREAK_ENDING || com->etc == ETC_BREAK_ENDED
|| com->etc == ETC_NONE))) {
- enable_intr();
+ COM_UNLOCK();
+ restore_intr(intrsave);
return;
}
com->etc = etc;
cd_setreg(com, CD1400_SRER,
com->intr_enable
= (com->intr_enable & ~CD1400_SRER_TXRDY) | CD1400_SRER_TXMPTY);
- enable_intr();
wait:
+ COM_UNLOCK();
+ restore_intr(intrsave);
while (com->etc == etc
&& tsleep(&com->etc, TTIPRI | PCATCH, "cyetc", 0) == 0)
continue;
@@ -2787,7 +2874,7 @@ cd_getreg(com, reg)
struct com_s *basecom;
u_char car;
int cy_align;
- u_long ef;
+ int intrsave;
cy_addr iobase;
int val;
@@ -2795,14 +2882,16 @@ cd_getreg(com, reg)
car = com->unit & CD1400_CAR_CHAN;
cy_align = com->cy_align;
iobase = com->iobase;
- ef = read_eflags();
- if (ef & PSL_I)
- disable_intr();
+ intrsave = save_intr();
+ disable_intr();
+ if (intrsave & PSL_I)
+ COM_LOCK();
if (basecom->car != car)
cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
val = cd_inb(iobase, reg, cy_align);
- if (ef & PSL_I)
- enable_intr();
+ if (intrsave & PSL_I)
+ COM_UNLOCK();
+ restore_intr(intrsave);
return (val);
}
@@ -2815,21 +2904,23 @@ cd_setreg(com, reg, val)
struct com_s *basecom;
u_char car;
int cy_align;
- u_long ef;
+ int intrsave;
cy_addr iobase;
basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
car = com->unit & CD1400_CAR_CHAN;
cy_align = com->cy_align;
iobase = com->iobase;
- ef = read_eflags();
- if (ef & PSL_I)
- disable_intr();
+ intrsave = save_intr();
+ disable_intr();
+ if (intrsave & PSL_I)
+ COM_LOCK();
if (basecom->car != car)
cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
cd_outb(iobase, reg, cy_align, val);
- if (ef & PSL_I)
- enable_intr();
+ if (intrsave & PSL_I)
+ COM_UNLOCK();
+ restore_intr(intrsave);
}
#ifdef CyDebug