summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authormycroft <mycroft@NetBSD.org>1997-11-03 06:12:02 +0000
committermycroft <mycroft@NetBSD.org>1997-11-03 06:12:02 +0000
commit067898abb8da0f93398928fcd3d047c41fcf455e (patch)
tree1085c02851249678c63d8dd62d720d3058b939ee /sys/dev
parent80a52b9e7dcdcbf1875e556b34fd4f3c334f2ff2 (diff)
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.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/com.c242
1 files changed, 133 insertions, 109 deletions
diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c
index f6e6b79ef80..1c4bb6c3d70 100644
--- a/sys/dev/ic/com.c
+++ b/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;