diff options
author | jkh <jkh@FreeBSD.org> | 1995-10-04 22:24:16 +0000 |
---|---|---|
committer | jkh <jkh@FreeBSD.org> | 1995-10-04 22:24:16 +0000 |
commit | 8a1fa70dc0da9908f692ff6de5fe8ca9cad9f310 (patch) | |
tree | 2fe87f819c9da98ccb878d0641f4b626f15c348d /sys/i386/isa | |
parent | 1c1ef85e1307f05f0ae122e54088a9f8e7425ef7 (diff) | |
download | FreeBSD-src-8a1fa70dc0da9908f692ff6de5fe8ca9cad9f310.zip FreeBSD-src-8a1fa70dc0da9908f692ff6de5fe8ca9cad9f310.tar.gz |
This upgrades the driver for Cronyx-Sigma multiplexor boards
from version 1.2 to version 1.9.
Submitted by: Serge Vakulenko, <vak@cronyx.ru>
Diffstat (limited to 'sys/i386/isa')
-rw-r--r-- | sys/i386/isa/cronyx.c | 49 | ||||
-rw-r--r-- | sys/i386/isa/cx.c | 127 | ||||
-rw-r--r-- | sys/i386/isa/if_cx.c | 304 |
3 files changed, 351 insertions, 129 deletions
diff --git a/sys/i386/isa/cronyx.c b/sys/i386/isa/cronyx.c index 31eeef3..c312100 100644 --- a/sys/i386/isa/cronyx.c +++ b/sys/i386/isa/cronyx.c @@ -1,8 +1,8 @@ /* * Low-level subroutines for Cronyx-Sigma adapter. * - * Copyright (C) 1994 Cronyx Ltd. - * Author: Serge Vakulenko, <vak@zebub.msk.su> + * Copyright (C) 1994-95 Cronyx Ltd. + * Author: Serge Vakulenko, <vak@cronyx.ru> * * This software is distributed with NO WARRANTIES, not even the implied * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. @@ -11,7 +11,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.2, Mon Nov 28 16:12:18 MSK 1994 + * Version 1.6, Wed May 31 16:03:20 MSD 1995 */ #if defined (MSDOS) || defined (__MSDOS__) # include <string.h> @@ -26,13 +26,15 @@ # include "cxreg.h" #else # include <sys/param.h> -# include <sys/systm.h> # include <sys/socket.h> # include <net/if.h> # include <vm/vm.h> # ifdef __FreeBSD__ # if __FreeBSD__ < 2 # include <machine/pio.h> +# else +# include <machine/cpufunc.h> +# include <sys/libkern.h> # endif # else # include <machine/inline.h> @@ -368,6 +370,7 @@ void cx_init_board (cx_board_t *b, int num, int port, int irq, int dma, c->num = i; c->board = b; c->chip = b->chip + i*NCHIP/NCHAN; + c->stat = b->stat + i; c->type = T_NONE; } @@ -772,20 +775,26 @@ void cx_chan_dtr (cx_chan_t *c, int on) /* Channels 4..7 and 12..15 in syncronous mode * have no DTR signal. */ break; - case 0: case 1: case 2: case 3: + + case 1: case 2: case 3: + if (c->type == T_UNIV_RS232) + break; + case 0: if (on) c->board->bcr1 |= 0x100 << c->num; else c->board->bcr1 &= ~(0x100 << c->num); - outb (CAR(c->chip->port), c->num); outw (BCR1(c->board->port), c->board->bcr1); break; - case 8: case 9: case 10: case 11: + + case 9: case 10: case 11: + if (c->type == T_UNIV_RS232) + break; + case 8: if (on) c->board->bcr1b |= 0x100 << (c->num & 3); else c->board->bcr1b &= ~(0x100 << (c->num & 3)); - outb (CAR(c->chip->port), c->num & 3); outw (BCR1(c->board->port+0x10), c->board->bcr1b); break; } @@ -820,10 +829,18 @@ int cx_chan_dsr (cx_chan_t *c) switch (c->num) { default: return (1); - case 0: case 1: case 2: case 3: + + case 1: case 2: case 3: + if (c->type == T_UNIV_RS232) + return (1); + case 0: sigval = inw (BSR(c->board->port)) >> 8; break; - case 8: case 9: case 10: case 11: + + case 9: case 10: case 11: + if (c->type == T_UNIV_RS232) + return (1); + case 8: sigval = inw (BSR(c->board->port+0x10)) >> 8; break; } @@ -848,10 +865,18 @@ int cx_chan_cd (cx_chan_t *c) switch (c->num) { default: return (1); - case 0: case 1: case 2: case 3: + + case 1: case 2: case 3: + if (c->type == T_UNIV_RS232) + return (1); + case 0: sigval = inw (BSR(c->board->port)) >> 8; break; - case 8: case 9: case 10: case 11: + + case 9: case 10: case 11: + if (c->type == T_UNIV_RS232) + return (1); + case 8: sigval = inw (BSR(c->board->port+0x10)) >> 8; break; } diff --git a/sys/i386/isa/cx.c b/sys/i386/isa/cx.c index 6c236f5..c01c157 100644 --- a/sys/i386/isa/cx.c +++ b/sys/i386/isa/cx.c @@ -13,7 +13,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.2, Tue Nov 22 18:57:27 MSK 1994 + * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 */ #undef DEBUG @@ -39,6 +39,7 @@ # include <machine/pio.h> # define RB_GETC(q) getc(q) # else /* BSD 4.4 Lite */ +# include <machine/cpufunc.h> # include <sys/devconf.h> # endif # define oproc_func_t void(*)(struct tty*) @@ -55,11 +56,9 @@ # define t_out t_outq # define RB_LEN(q) ((q).c_cc) # define RB_GETC(q) getc(&q) -#ifndef TSA_CARR_ON /* FreeBSD 2.x before not long after 2.0.5 */ # define TSA_CARR_ON(tp) tp # define TSA_OLOWAT(q) ((caddr_t)&(q)->t_out) #endif -#endif #include <machine/cronyx.h> #include <i386/isa/cxreg.h> @@ -67,7 +66,7 @@ #ifdef DEBUG # define print(s) printf s #else -# define print(s) /*void*/ +# define print(s) {/*void*/} #endif #define DMABUFSZ (6*256) /* buffer size */ @@ -107,9 +106,13 @@ int cxopen (dev_t dev, int flag, int mode, struct proc *p) if (c->mode != M_ASYNC) return (EBUSY); if (! c->ttyp) { +#ifdef __FreeBSD__ #if __FreeBSD__ >= 2 c->ttyp = &cx_tty[unit]; #else + c->ttyp = cx_tty[unit] = ttymalloc (cx_tty[unit]); +#endif +#else MALLOC (cx_tty[unit], struct tty*, sizeof (struct tty), M_DEVBUF, M_WAITOK); bzero (cx_tty[unit], sizeof (*cx_tty[unit])); c->ttyp = cx_tty[unit]; @@ -194,7 +197,7 @@ int cxopen (dev_t dev, int flag, int mode, struct proc *p) cx_chan_rts (c, 1); } if (cx_chan_cd (c)) - (*linesw[tp->t_line].l_modem)(tp, 1); + tp->t_state |= TS_CARR_ON; if (! (flag & O_NONBLOCK)) { /* Lock the channel against cxconfig while we are * waiting for carrier. */ @@ -283,10 +286,12 @@ int cxwrite (dev_t dev, struct uio *uio, int flag) int cxioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) { int unit = UNIT (dev); - cx_chan_t *c; + cx_chan_t *c, *m; + cx_stat_t *st; struct tty *tp; int error, s; unsigned char msv; + struct ifnet *master; if (unit == UNIT_CTL) { /* Process an ioctl request on /dev/cronyx */ @@ -324,6 +329,32 @@ int cxioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) /* Network interface is up? */ if (c->mode != M_ASYNC && (c->ifp->if_flags & IFF_UP)) return (EBUSY); + + /* Find the master interface. */ + master = *o->master ? ifunit (o->master) : c->ifp; + if (! master) + return (EINVAL); + m = cxchan[master->if_unit]; + + /* Leave the previous master queue. */ + if (c->master != c->ifp) { + cx_chan_t *p = cxchan[c->master->if_unit]; + + for (; p; p=p->slaveq) + if (p->slaveq == c) + p->slaveq = c->slaveq; + } + + /* Set up new master. */ + c->master = master; + c->slaveq = 0; + + /* Join the new master queue. */ + if (c->master != c->ifp) { + c->slaveq = m->slaveq; + m->slaveq = c; + } + c->mode = o->mode; c->rxbaud = o->rxbaud; c->txbaud = o->txbaud; @@ -336,13 +367,26 @@ int cxioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) case 0: c->board->if0type = o->iftype; break; case 8: c->board->if8type = o->iftype; break; } - cxswitch (c, o->sopt); s = spltty (); + cxswitch (c, o->sopt); cx_setup_chan (c); outb (IER(c->chip->port), 0); splx (s); break; + case CXIOCGETSTAT: + st = (cx_stat_t*) data; + st->rintr = c->stat->rintr; + st->tintr = c->stat->tintr; + st->mintr = c->stat->mintr; + st->ibytes = c->stat->ibytes; + st->ipkts = c->stat->ipkts; + st->ierrs = c->stat->ierrs; + st->obytes = c->stat->obytes; + st->opkts = c->stat->opkts; + st->oerrs = c->stat->oerrs; + break; + case CXIOCGETMODE: print (("cx%d.%d: CXIOCGETMODE\n", o->board, o->channel)); o->type = c->type; @@ -359,6 +403,11 @@ int cxioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) case 0: o->iftype = c->board->if0type; break; case 8: o->iftype = c->board->if8type; break; } + if (c->master != c->ifp) + sprintf (o->master, "%s%d", c->master->if_name, + c->master->if_unit); + else + *o->master = 0; break; } return (0); @@ -476,9 +525,9 @@ void cxout (cx_chan_t *c, char b) c->brk = BRK_IDLE; break; case BRK_IDLE: - len = RB_LEN (tp->t_out); + p = buf; if (tp->t_iflag & IXOFF) - for (i=0, p=buf; i<len && p<buf+DMABUFSZ-1; ++i) { + while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) { sym = RB_GETC (tp->t_out); /* Send XON/XOFF out of band. */ if (sym == tp->t_cc[VSTOP]) { @@ -495,7 +544,7 @@ void cxout (cx_chan_t *c, char b) *p++ = sym; } else - for (i=0, p=buf; i<len && p<buf+DMABUFSZ-1; ++i) { + while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) { sym = RB_GETC (tp->t_out); /* Duplicate NULLs in ETC mode. */ if (! sym) @@ -510,6 +559,7 @@ void cxout (cx_chan_t *c, char b) if (len) { outw (cnt_port, len); outb (sts_port, BSTS_INTR | BSTS_OWN24); + c->stat->obytes += len; tp->t_state |= TS_BUSY; print (("cx%d.%d: out %d bytes to %c\n", c->board->num, c->num, len, b)); @@ -544,9 +594,6 @@ void cxoproc (struct tty *tp) if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel) ttwwakeup (tp); #else /* FreeBSD 2.x and BSDI */ -#ifndef TS_ASLEEP /* FreeBSD some time after 2.0.5 */ - ttwwakeup(tp); -#else if (RB_LEN (tp->t_out) <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; @@ -555,16 +602,6 @@ void cxoproc (struct tty *tp) selwakeup(&tp->t_wsel); } #endif -#endif - /* - * Enable TXMPTY interrupt, - * to catch the case when the second buffer is empty. - */ - if ((inb (ATBSTS(port)) & BSTS_OWN24) && - (inb (BTBSTS(port)) & BSTS_OWN24)) { - outb (IER(port), IER_RXD|IER_RET|IER_TXD|IER_TXMPTY|IER_MDM); - } else - outb (IER(port), IER_RXD|IER_RET|IER_TXD|IER_MDM); splx (s); } @@ -682,12 +719,8 @@ struct tty *cxdevtotty (dev_t dev) { int unit = UNIT(dev); - if (unit == UNIT_CTL) - return (NULL); - - if (unit > NCX*NCHAN) - return (NULL); - + if (unit == UNIT_CTL || unit >= NCX*NCHAN) + return (0); return (cxchan[unit]->ttyp); } @@ -695,13 +728,13 @@ int cxselect (dev_t dev, int flag, struct proc *p) { int unit = UNIT (dev); - if (unit == UNIT_CTL) + if (unit == UNIT_CTL || unit >= NCX*NCHAN) return (0); - - if (unit > NCX*NCHAN) - return (ENXIO); - - return (ttyselect(cxchan[unit]->ttyp, flag, p)); +#if defined (__FreeBSD__) && __FreeBSD__ < 2 + return (ttselect (dev, flag, p)); +#else /* FreeBSD 2.x and BSDI */ + return (ttyselect (cxchan[unit]->ttyp, flag, p)); +#endif } /* @@ -765,6 +798,7 @@ int cxrinta (cx_chan_t *c) print (("cx%d.%d: async receive timeout (%d bytes), risr=%b, arbsts=%b, brbsts=%b\n", c->board->num, c->num, len, risr, RISA_BITS, inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS)); + c->stat->ibytes += len; if (tp && (tp->t_state & TS_ISOPEN)) { int i; void (*rint)() = (void(*)()) @@ -785,23 +819,29 @@ int cxrinta (cx_chan_t *c) c->board->num, c->num, risr, RISA_BITS, inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS)); - if (risr & RIS_BUSERR) + if (risr & RIS_BUSERR) { printf ("cx%d.%d: receive bus error\n", c->board->num, c->num); - + ++c->stat->ierrs; + } if (risr & (RIS_OVERRUN | RISA_PARERR | RISA_FRERR | RISA_BREAK)) { int err = 0; - if (risr & RIS_OVERRUN) - err |= TTY_OE; if (risr & RISA_PARERR) err |= TTY_PE; if (risr & RISA_FRERR) err |= TTY_FE; +#ifdef TTY_OE + if (risr & RIS_OVERRUN) + err |= TTY_OE; +#endif +#ifdef TTY_BI if (risr & RISA_BREAK) err |= TTY_BI; +#endif print (("cx%d.%d: receive error %x\n", c->board->num, c->num, err)); if (tp && (tp->t_state & TS_ISOPEN)) (*linesw[tp->t_line].l_rint) (err, tp); + ++c->stat->ierrs; } /* Discard exception characters. */ @@ -818,6 +858,7 @@ int cxrinta (cx_chan_t *c) print (("cx%d.%d: async: %d bytes received\n", c->board->num, c->num, len)); + c->stat->ibytes += len; buf = (risr & RIS_BB) ? c->brbuf : c->arbuf; for (i=0; i<len; ++i) @@ -849,13 +890,15 @@ void cxtinta (cx_chan_t *c) c->board->num, c->num, tisr, TIS_BITS, inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS)); - if (tisr & TIS_BUSERR) + if (tisr & TIS_BUSERR) { printf ("cx%d.%d: transmit bus error\n", c->board->num, c->num); - else if (tisr & TIS_UNDERRUN) + ++c->stat->oerrs; + } else if (tisr & TIS_UNDERRUN) { printf ("cx%d.%d: transmit underrun error\n", c->board->num, c->num); - + ++c->stat->oerrs; + } if (tp) { tp->t_state &= ~(TS_BUSY | TS_FLUSH); if (tp->t_line) diff --git a/sys/i386/isa/if_cx.c b/sys/i386/isa/if_cx.c index f4adf10..6292e74 100644 --- a/sys/i386/isa/if_cx.c +++ b/sys/i386/isa/if_cx.c @@ -14,13 +14,13 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.2, Tue Nov 22 18:57:27 MSK 1994 + * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 */ #undef DEBUG #include "cx.h" #if NCX > 0 -#include "bpfilter.h" +#include <bpfilter.h> #include <sys/param.h> #include <sys/systm.h> @@ -44,6 +44,7 @@ # if __FreeBSD__ < 2 # include <machine/pio.h> # else +# include <machine/cpufunc.h> # include <sys/devconf.h> # endif # define init_func_t void(*)(int) @@ -81,10 +82,10 @@ struct cxsoftc { #ifdef DEBUG # define print(s) printf s #else -# define print(s) /*void*/ +# define print(s) {/*void*/} #endif -#define TXTIMEOUT 2 /* transmit timeout in seconds */ +#define TXTIMEOUT 10 /* transmit timeout in seconds */ #define DMABUFSZ (6*256) /* buffer size */ #define PPP_HEADER_LEN 4 /* size of PPP header */ @@ -103,7 +104,6 @@ struct cxsoftc { #endif #define IFNETSZ (sizeof (struct ifnet)) -int cxoutput (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt); int cxsioctl (struct ifnet *ifp, int cmd, caddr_t data); void cxinit (int unit); void cxstart (struct ifnet *ifp); @@ -113,6 +113,8 @@ int cxrinta (cx_chan_t *c); void cxtinta (cx_chan_t *c); void cxmint (cx_chan_t *c); void cxtimeout (caddr_t a); +void cxdown (cx_chan_t *c); +void cxup (cx_chan_t *c); cx_board_t cxboard [NCX]; /* adapter state structures */ cx_chan_t *cxchan [NCX*NCHAN]; /* unit to channel struct pointer */ @@ -321,10 +323,12 @@ void cxattach (struct device *parent, struct device *self, void *aux) c->type = T_NONE; continue; } + bzero (c->ifp, IFSTRUCTSZ); + c->master = c->ifp; c->ifp->if_unit = u; c->ifp->if_name = "cx"; c->ifp->if_mtu = PP_MTU; - c->ifp->if_flags = IFF_POINTOPOINT|IFF_MULTICAST; + c->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; c->ifp->if_ioctl = cxsioctl; c->ifp->if_start = (start_func_t) cxstart; c->ifp->if_watchdog = (watchdog_func_t) cxwatchdog; @@ -380,62 +384,106 @@ struct cfdriver cxcd = { 0, "cx", cxprobe, cxattach, sizeof (struct cxsoftc) }; */ int cxsioctl (struct ifnet *ifp, int cmd, caddr_t data) { - cx_chan_t *c = cxchan[ifp->if_unit]; - int error, s; + cx_chan_t *q, *c = cxchan[ifp->if_unit]; + int error, s, was_up, should_be_up; + /* + * No socket ioctls while the channel is in async mode. + */ if (c->type==T_NONE || c->mode==M_ASYNC) return (EINVAL); + + /* + * Socket ioctls on slave subchannels are not allowed. + */ + if (c->master != c->ifp) + return (EBUSY); + + was_up = (ifp->if_flags & IFF_RUNNING) != 0; #ifdef __bsdi__ - if (c->sopt.ext) { - /* Save RUNNING flag. */ - int running = (ifp->if_flags & IFF_RUNNING); + if (c->sopt.ext) error = p2p_ioctl (ifp, cmd, data); - ifp->if_flags &= ~IFF_RUNNING; - ifp->if_flags |= running; - } else + else #endif error = sppp_ioctl (ifp, cmd, data); if (error) return (error); - if (cmd != SIOCSIFFLAGS) + + print (("cxioctl (%d.%d, ", c->board->num, c->num)); + switch (cmd) { + default: + print (("0x%x)\n", cmd)); + return (0); + case SIOCADDMULTI: + print (("SIOCADDMULTI)\n")); + return (0); + case SIOCDELMULTI: + print (("SIOCDELMULTI)\n")); return (0); + case SIOCSIFFLAGS: + print (("SIOCSIFFLAGS)\n")); + break; + case SIOCSIFADDR: + print (("SIOCSIFADDR)\n")); + break; + } + /* We get here only in case of SIFFLAGS or SIFADDR. */ s = splimp (); - if (! (ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING)) - /* Interface is down and running -- stop it. */ - cxinit (ifp->if_unit); - else if ((ifp->if_flags & IFF_UP) && ! (ifp->if_flags & IFF_RUNNING)) - /* Interface is up and not running -- start it. */ - cxinit (ifp->if_unit); + should_be_up = (ifp->if_flags & IFF_RUNNING) != 0; + if (!was_up && should_be_up) { + /* Interface goes up -- start it. */ + cxup (c); + + /* Start all slave subchannels. */ + for (q=c->slaveq; q; q=q->slaveq) + cxup (q); + + cxstart (c->ifp); + } else if (was_up && !should_be_up) { + /* Interface is going down -- stop it. */ + cxdown (c); + + /* Stop all slave subchannels. */ + for (q=c->slaveq; q; q=q->slaveq) + cxdown (q); + + /* Flush the interface output queue */ + if (! c->sopt.ext) + sppp_flush (c->ifp); + } splx (s); return (0); } /* - * Initialization of interface. + * Stop the interface. Called on splimp(). */ -void cxinit (int unit) +void cxdown (cx_chan_t *c) { - cx_chan_t *c = cxchan[unit]; unsigned short port = c->chip->port; - int s; - print (("cx%d.%d: cxinit\n", c->board->num, c->num)); + print (("cx%d.%d: cxdown\n", c->board->num, c->num)); - /* Disable interrupts */ - s = splimp(); + /* The interface is down, stop it */ + c->ifp->if_flags &= ~IFF_OACTIVE; /* Reset the channel (for sync modes only) */ - if (c->ifp->if_flags & IFF_OACTIVE) { outb (CAR(port), c->num & 3); outb (STCR(port), STC_ABORTTX | STC_SNDSPC); - } + cx_setup_chan (c); - c->ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); +} + +/* + * Start the interface. Called on splimp(). + */ +void cxup (cx_chan_t *c) +{ + unsigned short port = c->chip->port; - if (c->ifp->if_flags & IFF_UP) { /* The interface is up, start it */ - c->ifp->if_flags |= IFF_RUNNING; + print (("cx%d.%d: cxup\n", c->board->num, c->num)); #if __FreeBSD__ >= 2 /* Mark the board busy on the first startup. @@ -459,13 +507,31 @@ void cxinit (int unit) /* Enable interrupts */ outb (IER(port), IER_RXD | IER_TXD); +} - cxstart (c->ifp); +/* + * Initialization of interface. + */ +void cxinit (int unit) +{ + cx_chan_t *q, *c = cxchan[unit]; + int s = splimp(); - } else if (! c->sopt.ext) - /* Flush the interface output queue, if it is down */ - sppp_flush (c->ifp); + print (("cx%d.%d: cxinit\n", c->board->num, c->num)); + + cxdown (c); + + /* Stop all slave subchannels. */ + for (q=c->slaveq; q; q=q->slaveq) + cxdown (q); + if (c->ifp->if_flags & IFF_RUNNING) { + cxup (c); + + /* Start all slave subchannels. */ + for (q=c->slaveq; q; q=q->slaveq) + cxup (q); + } splx (s); } @@ -491,28 +557,37 @@ void cxput (cx_chan_t *c, char b) /* Is it busy? */ if (inb (sts_port) & BSTS_OWN24) { - c->ifp->if_flags |= IFF_OACTIVE; - return; + if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: tbuf %c already busy, bsts=%b\n", + c->board->num, c->num, b, + inb (sts_port), BSTS_BITS)); + goto ret; } /* Get the packet to send. */ #ifdef __bsdi__ if (c->sopt.ext) { - struct p2pcom *p = (struct p2pcom*) c->ifp; + struct p2pcom *p = (struct p2pcom*) c->master; int s = splimp (); IF_DEQUEUE (&p->p2p_isnd, m) if (! m) - IF_DEQUEUE (&c->ifp->if_snd, m) + IF_DEQUEUE (&c->master->if_snd, m) splx (s); } else #endif - m = sppp_dequeue (c->ifp); + m = sppp_dequeue (c->master); if (! m) return; len = m->m_pkthdr.len; + + /* Count the transmitted bytes to the subchannel, not the master. */ + c->master->if_obytes -= len + 3; + c->ifp->if_obytes += len + 3; + c->stat->obytes += len + 3; + if (len >= DMABUFSZ) { - printf ("cx%d.%d: too long packet: %d bytes\n", + printf ("cx%d.%d: too long packet: %d bytes: ", c->board->num, c->num, len); printmbuf (m); m_freem (m); @@ -528,26 +603,28 @@ void cxput (cx_chan_t *c, char b) /* Start transmitter. */ outw (cnt_port, len); outb (sts_port, BSTS_EOFR | BSTS_INTR | BSTS_OWN24); -#ifdef DEBUG + if (c->ifp->if_flags & IFF_DEBUG) - printf ("cx%d.%d: enqueue %d bytes to %c\n", - c->board->num, c->num, len, buf==c->atbuf ? 'A' : 'B'); -#endif + print (("cx%d.%d: enqueue %d bytes to %c\n", + c->board->num, c->num, len, buf==c->atbuf ? 'A' : 'B')); +ret: c->ifp->if_flags |= IFF_OACTIVE; } /* - * Start output on interface. Get another datagram to send + * Start output on the (slave) interface. Get another datagram to send * off of the interface queue, and copy it to the interface * before starting the output. */ -void cxstart (struct ifnet *ifp) +void cxsend (cx_chan_t *c) { - cx_chan_t *c = cxchan[ifp->if_unit]; unsigned short port = c->chip->port; + if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: cxsend\n", c->board->num, c->num)); + /* No output if the interface is down. */ - if (! (ifp->if_flags & IFF_RUNNING)) + if (! (c->ifp->if_flags & IFF_RUNNING)) return; /* Set the current channel number. */ @@ -563,8 +640,8 @@ void cxstart (struct ifnet *ifp) } /* Set up transmit timeout. */ - if (c->ifp->if_flags & IFF_OACTIVE) - c->ifp->if_timer = TXTIMEOUT; + if (c->master->if_flags & IFF_OACTIVE) + c->master->if_timer = TXTIMEOUT; /* * Enable TXMPTY interrupt, @@ -578,17 +655,50 @@ void cxstart (struct ifnet *ifp) } /* + * Start output on the (master) interface and all slave interfaces. + * Always called on splimp(). + */ +void cxstart (struct ifnet *ifp) +{ + cx_chan_t *q, *c = cxchan[ifp->if_unit]; + + if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: cxstart\n", c->board->num, c->num)); + + /* Start the master subchannel. */ + cxsend (c); + + /* Start all slave subchannels. */ + if (c->slaveq && ! sppp_isempty (c->master)) + for (q=c->slaveq; q; q=q->slaveq) + if ((q->ifp->if_flags & IFF_RUNNING) && + ! (q->ifp->if_flags & IFF_OACTIVE)) + cxsend (q); +} + +/* * Handle transmit timeouts. * Recover after lost transmit interrupts. + * Always called on splimp(). */ void cxwatchdog (int unit) { - cx_chan_t *c = cxchan[unit]; + cx_chan_t *q, *c = cxchan[unit]; + + if (! (c->ifp->if_flags & IFF_RUNNING)) + return; + if (c->ifp->if_flags & IFF_DEBUG) + printf ("cx%d.%d: device timeout\n", c->board->num, c->num); + + cxdown (c); + for (q=c->slaveq; q; q=q->slaveq) + cxdown (q); + + cxup (c); + for (q=c->slaveq; q; q=q->slaveq) + cxup (q); - if (c->ifp->if_flags & IFF_OACTIVE) { - c->ifp->if_flags &= ~IFF_OACTIVE; cxstart (c->ifp); - } } /* @@ -600,21 +710,26 @@ void cxrinth (cx_chan_t *c) unsigned short port = c->chip->port; unsigned short len, risr = inw (RISR(port)); - print (("cx%d.%d: hdlc receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n", - c->board->num, c->num, risr, RISH_BITS, - inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS)); - /* Receive errors. */ if (risr & (RIS_BUSERR | RIS_OVERRUN | RISH_CRCERR | RISH_RXABORT)) { if (c->ifp->if_flags & IFF_DEBUG) printf ("cx%d.%d: receive error, risr=%b\n", c->board->num, c->num, risr, RISH_BITS); ++c->ifp->if_ierrors; + ++c->stat->ierrs; if (risr & RIS_OVERRUN) ++c->ifp->if_collisions; } else if (risr & RIS_EOBUF) { + if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: hdlc receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n", + c->board->num, c->num, risr, RISH_BITS, + inb (ARBSTS(port)), BSTS_BITS, + inb (BRBSTS(port)), BSTS_BITS)); + ++c->stat->ipkts; + /* Handle received data. */ len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port)); + c->stat->ibytes += len; if (len > DMABUFSZ) { /* Fatal error: actual DMA transfer size * exceeds our buffer size. It could be caused @@ -633,11 +748,16 @@ void cxrinth (cx_chan_t *c) ++c->ifp->if_ierrors; } else { /* Valid frame received. */ - print (("cx%d.%d: HDLC: %d bytes received\n", + if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: hdlc received %d bytes\n", c->board->num, c->num, len)); cxinput (c, (risr & RIS_BB) ? c->brbuf : c->arbuf, len); ++c->ifp->if_ipackets; } + } else if (c->ifp->if_flags & IFF_DEBUG) { + print (("cx%d.%d: unknown hdlc receive interrupt, risr=%b\n", + c->board->num, c->num, risr, RISH_BITS)); + ++c->stat->ierrs; } /* Restart receiver. */ @@ -660,22 +780,35 @@ int cxtinth (cx_chan_t *c) unsigned char tisr = inb (TISR(port)); unsigned char teoir = 0; - print (("cx%d.%d: hdlc transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n", - c->board->num, c->num, tisr, TIS_BITS, - inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS)); + c->ifp->if_flags &= ~IFF_OACTIVE; + if (c->ifp == c->master) + c->ifp->if_timer = 0; if (tisr & (TIS_BUSERR | TIS_UNDERRUN)) { - if (c->ifp->if_flags & IFF_DEBUG) - printf ("cx%d.%d: transmit error, tisr=%b\n", - c->board->num, c->num, tisr, TIS_BITS); + /* if (c->ifp->if_flags & IFF_DEBUG) */ + print (("cx%d.%d: transmit error, tisr=%b, atbsts=%b, btbsts=%b\n", + c->board->num, c->num, tisr, TIS_BITS, + inb (ATBSTS(port)), BSTS_BITS, + inb (BTBSTS(port)), BSTS_BITS)); ++c->ifp->if_oerrors; + ++c->stat->oerrs; + /* Terminate the failed buffer. */ - teoir |= TEOI_TERMBUFF; - } else if (tisr & (TIS_EOFR)) + /* teoir = TEOI_TERMBUFF; */ + } else if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: hdlc transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n", + c->board->num, c->num, tisr, TIS_BITS, + inb (ATBSTS(port)), BSTS_BITS, + inb (BTBSTS(port)), BSTS_BITS)); + + if (tisr & TIS_EOFR) { ++c->ifp->if_opackets; + ++c->stat->opkts; + } + + /* Start output on the (sub-) channel. */ + cxsend (c); - c->ifp->if_flags &= ~IFF_OACTIVE; - cxstart (c->ifp); return (teoir); } @@ -715,6 +848,7 @@ void cxintr (cx_board_t *b) switch (livr & 3) { case LIV_EXCEP: /* receive exception */ case LIV_RXDATA: /* receive interrupt */ + ++c->stat->rintr; switch (c->mode) { case M_ASYNC: eoi = cxrinta (c); break; case M_HDLC: cxrinth (c); break; @@ -722,6 +856,7 @@ void cxintr (cx_board_t *b) } break; case LIV_TXDATA: /* transmit interrupt */ + ++c->stat->tintr; eoiport = TEOIR(port); switch (c->mode) { case M_ASYNC: cxtinta (c); break; @@ -730,6 +865,7 @@ void cxintr (cx_board_t *b) } break; case LIV_MODEM: /* modem/timer interrupt */ + ++c->stat->mintr; eoiport = MEOIR(port); cxmint (c); break; @@ -746,6 +882,18 @@ void cxintr (cx_board_t *b) /* Exit from interrupt context. */ outb (eoiport, eoi); + + /* Master channel - start output on all idle subchannels. */ + if (c->master == c->ifp && c->slaveq && + (livr & 3) == LIV_TXDATA && c->mode == M_HDLC && + ! sppp_isempty (c->ifp)) { + cx_chan_t *q; + + for (q=c->slaveq; q; q=q->slaveq) + if ((q->ifp->if_flags & IFF_RUNNING) && + ! (q->ifp->if_flags & IFF_OACTIVE)) + cxsend (q); + } } } @@ -763,8 +911,9 @@ void cxinput (cx_chan_t *c, void *buf, unsigned len) ++c->ifp->if_iqdrops; return; } - m->m_pkthdr.rcvif = c->ifp; + m->m_pkthdr.rcvif = c->master; #ifdef DEBUG + if (c->ifp->if_flags & IFF_DEBUG) printmbuf (m); #endif @@ -776,13 +925,18 @@ void cxinput (cx_chan_t *c, void *buf, unsigned len) if (c->bpf) bpf_tap (c->bpf, buf, len); #endif + + /* Count the received bytes to the subchannel, not the master. */ + c->master->if_ibytes -= len + 3; + c->ifp->if_ibytes += len + 3; + #ifdef __bsdi__ if (c->sopt.ext) { - struct p2pcom *p = (struct p2pcom*) c->ifp; + struct p2pcom *p = (struct p2pcom*) c->master; (*p->p2p_input) (p, m); } else #endif - sppp_input (c->ifp, m); + sppp_input (c->master, m); } void cxswitch (cx_chan_t *c, cx_soft_opt_t new) |