Mostly cosmetic and performance changes:
* Make the ring buffer size and water marks patchable, and allocate the buffer separately. * Do the ttymalloc() at attach time. * Reorganize the receive buffer so the status and data pair are next to each other. This is slightly faster. * Make sure we actually do turn off interrupts in comclose() if we have DDB configured and it's not the console. (D'oh!!!!) * When we exhaust the current transmit run, turn off transmit interrupts in comintr(), so we're fairly sure we don't get another one. * Nuke the silly lsrmap[] idea; it's slower in the normal case. * Cache the l_rint pointer in the soft interrupt routine.
This commit is contained in:
parent
80a52b9e7d
commit
067898abb8
242
sys/dev/ic/com.c
242
sys/dev/ic/com.c
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: com.c,v 1.126 1997/11/02 09:31:49 mycroft Exp $ */
|
||||
/* $NetBSD: com.c,v 1.127 1997/11/03 06:12:02 mycroft Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993, 1994, 1995, 1996, 1997
|
||||
@ -92,6 +92,7 @@
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <machine/intr.h>
|
||||
#include <machine/bus.h>
|
||||
@ -116,21 +117,11 @@ int comprobeHAYESP __P((bus_space_handle_t hayespioh, struct com_softc *sc));
|
||||
static void com_enable_debugport __P((struct com_softc *));
|
||||
#endif
|
||||
void com_attach_subr __P((struct com_softc *sc));
|
||||
void comdiag __P((void *));
|
||||
int comspeed __P((long, long));
|
||||
static u_char cflag2lcr __P((tcflag_t));
|
||||
int comparam __P((struct tty *, struct termios *));
|
||||
void comstart __P((struct tty *));
|
||||
void comstop __P((struct tty *, int));
|
||||
#ifdef __GENERIC_SOFT_INTERRUPTS
|
||||
void comsoft __P((void *));
|
||||
#else
|
||||
#ifndef alpha
|
||||
void comsoft __P((void));
|
||||
#else
|
||||
void comsoft __P((void *));
|
||||
#endif
|
||||
#endif
|
||||
int comhwiflow __P((struct tty *, int));
|
||||
|
||||
void com_loadchannelregs __P((struct com_softc *));
|
||||
@ -151,15 +142,36 @@ void comcnputc __P((dev_t, int));
|
||||
void comcnpollc __P((dev_t, int));
|
||||
|
||||
#define integrate static inline
|
||||
integrate void comrxint __P((struct com_softc *, struct tty *));
|
||||
integrate void comtxint __P((struct com_softc *, struct tty *));
|
||||
integrate void commsrint __P((struct com_softc *, struct tty *));
|
||||
#ifdef __GENERIC_SOFT_INTERRUPTS
|
||||
void comsoft __P((void *));
|
||||
#else
|
||||
#ifndef alpha
|
||||
void comsoft __P((void));
|
||||
#else
|
||||
void comsoft __P((void *));
|
||||
#endif
|
||||
#endif
|
||||
integrate void com_rxsoft __P((struct com_softc *, struct tty *));
|
||||
integrate void com_txsoft __P((struct com_softc *, struct tty *));
|
||||
integrate void com_stsoft __P((struct com_softc *, struct tty *));
|
||||
integrate void com_schedrx __P((struct com_softc *));
|
||||
void comdiag __P((void *));
|
||||
|
||||
|
||||
struct cfdriver com_cd = {
|
||||
NULL, "com", DV_TTY
|
||||
};
|
||||
|
||||
/*
|
||||
* Make this an option variable one can patch.
|
||||
* But be warned: this must be a power of 2!
|
||||
*/
|
||||
u_int com_rbuf_size = COM_RING_SIZE;
|
||||
|
||||
/* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
|
||||
u_int com_rbuf_hiwat = (COM_RING_SIZE * 1) / 4;
|
||||
u_int com_rbuf_lowat = (COM_RING_SIZE * 3) / 4;
|
||||
|
||||
static int comconsaddr;
|
||||
static bus_space_tag_t comconstag;
|
||||
static bus_space_handle_t comconsioh;
|
||||
@ -350,6 +362,7 @@ com_attach_subr(sc)
|
||||
int iobase = sc->sc_iobase;
|
||||
bus_space_tag_t iot = sc->sc_iot;
|
||||
bus_space_handle_t ioh = sc->sc_ioh;
|
||||
struct tty *tp;
|
||||
#ifdef COM16650
|
||||
u_int8_t lcr;
|
||||
#endif
|
||||
@ -470,6 +483,16 @@ com_attach_subr(sc)
|
||||
}
|
||||
#endif
|
||||
|
||||
tp = ttymalloc();
|
||||
tp->t_oproc = comstart;
|
||||
tp->t_param = comparam;
|
||||
tp->t_hwiflow = comhwiflow;
|
||||
tty_attach(tp);
|
||||
|
||||
sc->sc_tty = tp;
|
||||
sc->sc_rbuf = malloc(com_rbuf_size << 1, M_DEVBUF, M_WAITOK);
|
||||
sc->sc_ebuf = sc->sc_rbuf + (com_rbuf_size << 1);
|
||||
|
||||
if (!ISSET(sc->sc_hwflags, COM_HW_NOIEN))
|
||||
SET(sc->sc_mcr, MCR_IENABLE);
|
||||
|
||||
@ -539,14 +562,6 @@ comopen(dev, flag, mode, p)
|
||||
#endif
|
||||
|
||||
tp = sc->sc_tty;
|
||||
if (tp == 0) {
|
||||
sc->sc_tty = tp = ttymalloc();
|
||||
tp->t_dev = dev;
|
||||
tp->t_oproc = comstart;
|
||||
tp->t_param = comparam;
|
||||
tp->t_hwiflow = comhwiflow;
|
||||
tty_attach(tp);
|
||||
}
|
||||
|
||||
if (ISSET(tp->t_state, TS_ISOPEN) &&
|
||||
ISSET(tp->t_state, TS_XCLUDE) &&
|
||||
@ -564,6 +579,8 @@ comopen(dev, flag, mode, p)
|
||||
if (!ISSET(tp->t_state, TS_ISOPEN)) {
|
||||
struct termios t;
|
||||
|
||||
tp->t_dev = dev;
|
||||
|
||||
s2 = splserial();
|
||||
|
||||
/* Turn on interrupts. */
|
||||
@ -612,8 +629,8 @@ comopen(dev, flag, mode, p)
|
||||
s2 = splserial();
|
||||
|
||||
/* Clear the input ring, and unblock. */
|
||||
sc->sc_rbput = sc->sc_rbget = 0;
|
||||
sc->sc_rbavail = RXBUFSIZE;
|
||||
sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
|
||||
sc->sc_rbavail = com_rbuf_size;
|
||||
com_iflush(sc);
|
||||
CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
|
||||
com_hwiflow(sc);
|
||||
@ -661,8 +678,7 @@ comclose(dev, flag, mode, p)
|
||||
int flag, mode;
|
||||
struct proc *p;
|
||||
{
|
||||
int unit = COMUNIT(dev);
|
||||
struct com_softc *sc = com_cd.cd_devs[unit];
|
||||
struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
|
||||
struct tty *tp = sc->sc_tty;
|
||||
int s;
|
||||
|
||||
@ -700,9 +716,8 @@ comclose(dev, flag, mode, p)
|
||||
if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
|
||||
sc->sc_ier = IER_ERXRDY; /* interrupt on break */
|
||||
else
|
||||
#else
|
||||
sc->sc_ier = 0;
|
||||
#endif
|
||||
sc->sc_ier = 0;
|
||||
bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_ier, sc->sc_ier);
|
||||
|
||||
splx(s);
|
||||
@ -765,8 +780,7 @@ comioctl(dev, cmd, data, flag, p)
|
||||
int flag;
|
||||
struct proc *p;
|
||||
{
|
||||
int unit = COMUNIT(dev);
|
||||
struct com_softc *sc = com_cd.cd_devs[unit];
|
||||
struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
|
||||
struct tty *tp = sc->sc_tty;
|
||||
int error;
|
||||
|
||||
@ -932,16 +946,16 @@ cflag2lcr(cflag)
|
||||
u_char lcr = 0;
|
||||
|
||||
switch (ISSET(cflag, CSIZE)) {
|
||||
case CS5:
|
||||
case CS5:
|
||||
SET(lcr, LCR_5BITS);
|
||||
break;
|
||||
case CS6:
|
||||
case CS6:
|
||||
SET(lcr, LCR_6BITS);
|
||||
break;
|
||||
case CS7:
|
||||
case CS7:
|
||||
SET(lcr, LCR_7BITS);
|
||||
break;
|
||||
case CS8:
|
||||
case CS8:
|
||||
SET(lcr, LCR_8BITS);
|
||||
break;
|
||||
}
|
||||
@ -966,7 +980,7 @@ comparam(tp, t)
|
||||
u_char lcr;
|
||||
int s;
|
||||
|
||||
/* check requested parameters */
|
||||
/* Check requested parameters. */
|
||||
if (ospeed < 0)
|
||||
return (EINVAL);
|
||||
if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
|
||||
@ -1059,7 +1073,7 @@ comparam(tp, t)
|
||||
else
|
||||
sc->sc_fifo = 0;
|
||||
|
||||
/* and copy to tty */
|
||||
/* And copy to tty. */
|
||||
tp->t_ispeed = 0;
|
||||
tp->t_ospeed = t->c_ospeed;
|
||||
tp->t_cflag = t->c_cflag;
|
||||
@ -1086,8 +1100,8 @@ comparam(tp, t)
|
||||
com_hwiflow(sc);
|
||||
}
|
||||
} else {
|
||||
sc->sc_r_hiwat = RXHIWAT;
|
||||
sc->sc_r_lowat = RXLOWAT;
|
||||
sc->sc_r_hiwat = com_rbuf_hiwat;
|
||||
sc->sc_r_lowat = com_rbuf_lowat;
|
||||
}
|
||||
|
||||
splx(s);
|
||||
@ -1104,7 +1118,6 @@ comparam(tp, t)
|
||||
comstatus(sc, "comparam ");
|
||||
#endif
|
||||
|
||||
/* Block or unblock as needed. */
|
||||
if (!ISSET(t->c_cflag, CHWFLOW)) {
|
||||
if (sc->sc_tx_stopped) {
|
||||
sc->sc_tx_stopped = 0;
|
||||
@ -1218,13 +1231,10 @@ comstart(tp)
|
||||
int s;
|
||||
|
||||
s = spltty();
|
||||
if (ISSET(tp->t_state, TS_BUSY))
|
||||
if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
|
||||
goto out;
|
||||
if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
|
||||
goto stopped;
|
||||
|
||||
if (sc->sc_tx_stopped)
|
||||
goto stopped;
|
||||
goto out;
|
||||
|
||||
if (tp->t_outq.c_cc <= tp->t_lowat) {
|
||||
if (ISSET(tp->t_state, TS_ASLEEP)) {
|
||||
@ -1233,7 +1243,7 @@ comstart(tp)
|
||||
}
|
||||
selwakeup(&tp->t_wsel);
|
||||
if (tp->t_outq.c_cc == 0)
|
||||
goto stopped;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Grab the first contiguous region of buffer space. */
|
||||
@ -1263,22 +1273,13 @@ comstart(tp)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = sc->sc_fifolen;
|
||||
if (n > sc->sc_tbc)
|
||||
n = sc->sc_tbc;
|
||||
n = sc->sc_tbc;
|
||||
if (n > sc->sc_fifolen)
|
||||
n = sc->sc_fifolen;
|
||||
bus_space_write_multi_1(iot, ioh, com_data, sc->sc_tba, n);
|
||||
sc->sc_tbc -= n;
|
||||
sc->sc_tba += n;
|
||||
}
|
||||
splx(s);
|
||||
return;
|
||||
|
||||
stopped:
|
||||
/* Disable transmit completion interrupts if necessary. */
|
||||
if (ISSET(sc->sc_ier, IER_ETXRDY)) {
|
||||
CLR(sc->sc_ier, IER_ETXRDY);
|
||||
bus_space_write_1(iot, ioh, com_ier, sc->sc_ier);
|
||||
}
|
||||
out:
|
||||
splx(s);
|
||||
return;
|
||||
@ -1322,48 +1323,49 @@ comdiag(arg)
|
||||
sc->sc_errors = 0;
|
||||
splx(s);
|
||||
|
||||
log(LOG_WARNING,
|
||||
"%s: %d silo overflow%s, %d ibuf flood%s\n",
|
||||
log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
|
||||
sc->sc_dev.dv_xname,
|
||||
overflows, overflows == 1 ? "" : "s",
|
||||
floods, floods == 1 ? "" : "s");
|
||||
}
|
||||
|
||||
integrate void
|
||||
comrxint(sc, tp)
|
||||
struct com_softc *sc;
|
||||
struct tty *tp;
|
||||
com_rxsoft(sc, tp)
|
||||
struct com_softc *sc;
|
||||
struct tty *tp;
|
||||
{
|
||||
u_int get, cc, scc;
|
||||
int code;
|
||||
u_char lsr;
|
||||
int s;
|
||||
static int lsrmap[8] = {
|
||||
0, TTY_PE,
|
||||
TTY_FE, TTY_PE|TTY_FE,
|
||||
TTY_FE, TTY_PE|TTY_FE,
|
||||
TTY_FE, TTY_PE|TTY_FE
|
||||
};
|
||||
int (*rint) __P((int c, struct tty *tp)) = linesw[tp->t_line].l_rint;
|
||||
u_char *get, *end;
|
||||
u_int cc, scc;
|
||||
u_char lsr;
|
||||
int code;
|
||||
int s;
|
||||
|
||||
end = sc->sc_ebuf;
|
||||
get = sc->sc_rbget;
|
||||
scc = cc = RXBUFSIZE - sc->sc_rbavail;
|
||||
scc = cc = com_rbuf_size - sc->sc_rbavail;
|
||||
|
||||
if (cc == RXBUFSIZE) {
|
||||
if (cc == com_rbuf_size) {
|
||||
sc->sc_floods++;
|
||||
if (sc->sc_errors++ == 0)
|
||||
timeout(comdiag, sc, 60 * hz);
|
||||
}
|
||||
|
||||
while (cc) {
|
||||
lsr = sc->sc_lbuf[get];
|
||||
lsr = get[1];
|
||||
if (ISSET(lsr, LSR_OE)) {
|
||||
sc->sc_overflows++;
|
||||
if (sc->sc_errors++ == 0)
|
||||
timeout(comdiag, sc, 60 * hz);
|
||||
}
|
||||
code = sc->sc_rbuf[get] |
|
||||
lsrmap[(lsr & (LSR_BI|LSR_FE|LSR_PE)) >> 2];
|
||||
if ((*linesw[tp->t_line].l_rint)(code, tp) == -1) {
|
||||
code = get[0];
|
||||
if (ISSET(lsr, LSR_BI | LSR_FE | LSR_PE)) {
|
||||
if (ISSET(lsr, LSR_BI | LSR_FE))
|
||||
SET(code, TTY_FE);
|
||||
if (ISSET(lsr, LSR_PE))
|
||||
SET(code, TTY_PE);
|
||||
}
|
||||
if ((*rint)(code, tp) == -1) {
|
||||
/*
|
||||
* The line discipline's buffer is out of space.
|
||||
*/
|
||||
@ -1375,7 +1377,9 @@ comrxint(sc, tp)
|
||||
* know when there's more space available, so
|
||||
* just drop the rest of the data.
|
||||
*/
|
||||
get = (get + cc) & RXBUFMASK;
|
||||
get += cc << 1;
|
||||
if (get >= end)
|
||||
get -= com_rbuf_size << 1;
|
||||
cc = 0;
|
||||
} else {
|
||||
/*
|
||||
@ -1389,7 +1393,9 @@ comrxint(sc, tp)
|
||||
}
|
||||
break;
|
||||
}
|
||||
get = (get + 1) & RXBUFMASK;
|
||||
get += 2;
|
||||
if (get >= end)
|
||||
get = sc->sc_rbuf;
|
||||
cc--;
|
||||
}
|
||||
|
||||
@ -1414,9 +1420,9 @@ comrxint(sc, tp)
|
||||
}
|
||||
|
||||
integrate void
|
||||
comtxint(sc, tp)
|
||||
struct com_softc *sc;
|
||||
struct tty *tp;
|
||||
com_txsoft(sc, tp)
|
||||
struct com_softc *sc;
|
||||
struct tty *tp;
|
||||
{
|
||||
|
||||
CLR(tp->t_state, TS_BUSY);
|
||||
@ -1428,9 +1434,9 @@ comtxint(sc, tp)
|
||||
}
|
||||
|
||||
integrate void
|
||||
commsrint(sc, tp)
|
||||
struct com_softc *sc;
|
||||
struct tty *tp;
|
||||
com_stsoft(sc, tp)
|
||||
struct com_softc *sc;
|
||||
struct tty *tp;
|
||||
{
|
||||
u_char msr, delta;
|
||||
int s;
|
||||
@ -1460,7 +1466,7 @@ commsrint(sc, tp)
|
||||
|
||||
#ifdef COM_DEBUG
|
||||
if (com_debug)
|
||||
comstatus(sc, "commsrint");
|
||||
comstatus(sc, "com_stsoft");
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1505,17 +1511,17 @@ comsoft(arg)
|
||||
|
||||
if (sc->sc_rx_ready) {
|
||||
sc->sc_rx_ready = 0;
|
||||
comrxint(sc, tp);
|
||||
com_rxsoft(sc, tp);
|
||||
}
|
||||
|
||||
if (sc->sc_st_check) {
|
||||
sc->sc_st_check = 0;
|
||||
commsrint(sc, tp);
|
||||
com_stsoft(sc, tp);
|
||||
}
|
||||
|
||||
if (sc->sc_tx_done) {
|
||||
sc->sc_tx_done = 0;
|
||||
comtxint(sc, tp);
|
||||
com_txsoft(sc, tp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1528,18 +1534,20 @@ comsoft(arg)
|
||||
|
||||
int
|
||||
comintr(arg)
|
||||
void *arg;
|
||||
void *arg;
|
||||
{
|
||||
struct com_softc *sc = arg;
|
||||
bus_space_tag_t iot = sc->sc_iot;
|
||||
bus_space_handle_t ioh = sc->sc_ioh;
|
||||
u_char lsr, iir;
|
||||
u_int put, cc;
|
||||
u_char *put, *end;
|
||||
u_int cc;
|
||||
u_char lsr, iir;
|
||||
|
||||
iir = bus_space_read_1(iot, ioh, com_iir);
|
||||
if (ISSET(iir, IIR_NOPEND))
|
||||
return (0);
|
||||
|
||||
end = sc->sc_ebuf;
|
||||
put = sc->sc_rbput;
|
||||
cc = sc->sc_rbavail;
|
||||
|
||||
@ -1566,23 +1574,30 @@ comintr(arg)
|
||||
|
||||
if (ISSET(lsr, LSR_RCV_MASK) &&
|
||||
!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
|
||||
for (; ISSET(lsr, LSR_RCV_MASK) && cc > 0; cc--) {
|
||||
sc->sc_rbuf[put] =
|
||||
bus_space_read_1(iot, ioh, com_data);
|
||||
sc->sc_lbuf[put] = lsr;
|
||||
put = (put + 1) & RXBUFMASK;
|
||||
while (cc > 0) {
|
||||
put[0] = bus_space_read_1(iot, ioh, com_data);
|
||||
put[1] = lsr;
|
||||
put += 2;
|
||||
if (put >= end)
|
||||
put = sc->sc_rbuf;
|
||||
cc--;
|
||||
|
||||
lsr = bus_space_read_1(iot, ioh, com_lsr);
|
||||
if (!ISSET(lsr, LSR_RCV_MASK))
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Current string of incoming characters ended because
|
||||
* no more data was available. Schedule a receive event
|
||||
* if any data was received. Drop any characters that
|
||||
* we couldn't handle.
|
||||
* no more data was available or we ran out of space.
|
||||
* Schedule a receive event if any data was received.
|
||||
* If we're out of space, turn off receive interrupts.
|
||||
*/
|
||||
sc->sc_rbput = put;
|
||||
sc->sc_rbavail = cc;
|
||||
if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
|
||||
sc->sc_rx_ready = 1;
|
||||
|
||||
/*
|
||||
* See if we are in danger of overflowing a buffer. If
|
||||
* so, use hardware flow control to ease the pressure.
|
||||
@ -1592,6 +1607,7 @@ comintr(arg)
|
||||
SET(sc->sc_rx_flags, RX_IBUF_BLOCKED);
|
||||
com_hwiflow(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're out of space, disable receive interrupts
|
||||
* until the queue has drained a bit.
|
||||
@ -1615,7 +1631,7 @@ comintr(arg)
|
||||
delta = msr ^ sc->sc_msr;
|
||||
sc->sc_msr = msr;
|
||||
if (ISSET(delta, sc->sc_msr_mask)) {
|
||||
sc->sc_msr_delta |= delta;
|
||||
SET(sc->sc_msr_delta, delta);
|
||||
|
||||
/*
|
||||
* Stop output immediately if we lose the output
|
||||
@ -1650,19 +1666,27 @@ comintr(arg)
|
||||
sc->sc_tbc = sc->sc_heldtbc;
|
||||
sc->sc_heldtbc = 0;
|
||||
}
|
||||
|
||||
/* Output the next chunk of the contiguous buffer, if any. */
|
||||
if (sc->sc_tbc > 0) {
|
||||
int n;
|
||||
|
||||
n = sc->sc_fifolen;
|
||||
if (n > sc->sc_tbc)
|
||||
n = sc->sc_tbc;
|
||||
n = sc->sc_tbc;
|
||||
if (n > sc->sc_fifolen)
|
||||
n = sc->sc_fifolen;
|
||||
bus_space_write_multi_1(iot, ioh, com_data, sc->sc_tba, n);
|
||||
sc->sc_tbc -= n;
|
||||
sc->sc_tba += n;
|
||||
} else if (sc->sc_tx_busy) {
|
||||
sc->sc_tx_busy = 0;
|
||||
sc->sc_tx_done = 1;
|
||||
} else {
|
||||
/* Disable transmit completion interrupts if necessary. */
|
||||
if (ISSET(sc->sc_ier, IER_ETXRDY)) {
|
||||
CLR(sc->sc_ier, IER_ETXRDY);
|
||||
bus_space_write_1(iot, ioh, com_ier, sc->sc_ier);
|
||||
}
|
||||
if (sc->sc_tx_busy) {
|
||||
sc->sc_tx_busy = 0;
|
||||
sc->sc_tx_done = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1716,7 +1740,7 @@ com_common_putc(iot, ioh, c)
|
||||
{
|
||||
int s = splserial();
|
||||
u_char stat;
|
||||
register int timo;
|
||||
int timo;
|
||||
|
||||
/* wait for any pending transmission to finish */
|
||||
timo = 50000;
|
||||
|
Loading…
Reference in New Issue
Block a user