summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1995-10-04 22:24:16 +0000
committerjkh <jkh@FreeBSD.org>1995-10-04 22:24:16 +0000
commit8a1fa70dc0da9908f692ff6de5fe8ca9cad9f310 (patch)
tree2fe87f819c9da98ccb878d0641f4b626f15c348d /sys/i386
parent1c1ef85e1307f05f0ae122e54088a9f8e7425ef7 (diff)
downloadFreeBSD-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')
-rw-r--r--sys/i386/include/cronyx.h22
-rw-r--r--sys/i386/isa/cronyx.c49
-rw-r--r--sys/i386/isa/cx.c127
-rw-r--r--sys/i386/isa/if_cx.c304
4 files changed, 372 insertions, 130 deletions
diff --git a/sys/i386/include/cronyx.h b/sys/i386/include/cronyx.h
index 9421cbc..0ea0e65 100644
--- a/sys/i386/include/cronyx.h
+++ b/sys/i386/include/cronyx.h
@@ -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.1, Wed Oct 26 16:09:46 MSK 1994
+ * Version 1.9, Wed Oct 4 18:58:15 MSK 1995
*/
/*
* Asynchronous channel mode -------------------------------------------------
@@ -382,6 +382,7 @@ typedef struct {
cx_opt_bisync_t bopt; /* bisync mode options */
cx_opt_x21_t xopt; /* x.21 mode options */
cx_soft_opt_t sopt; /* software options and state flags */
+ char master[16]; /* master interface name or \0 */
} cx_options_t; /* user settable options */
typedef struct _chan_t {
@@ -389,6 +390,7 @@ typedef struct _chan_t {
unsigned char num; /* channel number, 0..15 */
struct _board_t *board; /* board pointer */
struct _chip_t *chip; /* controller pointer */
+ struct _stat_t *stat; /* statistics */
unsigned long rxbaud; /* receiver speed */
unsigned long txbaud; /* transmitter speed */
cx_chan_mode_t mode; /* channel mode */
@@ -410,6 +412,8 @@ typedef struct _chan_t {
#ifdef KERNEL
struct tty *ttyp; /* tty structure pointer */
struct ifnet *ifp; /* network interface data */
+ struct ifnet *master; /* master interface, or ==ifp */
+ struct _chan_t *slaveq; /* slave queue pointer, or NULL */
caddr_t bpf; /* packet filter data */
cx_soft_opt_t sopt; /* software options and state flags */
cx_break_t brk; /* line break mode */
@@ -426,6 +430,20 @@ typedef struct _chip_t {
unsigned long oscfreq; /* oscillator frequency in Hz */
} cx_chip_t;
+typedef struct _stat_t {
+ unsigned char board; /* adapter number, 0..2 */
+ unsigned char channel; /* channel number, 0..15 */
+ unsigned long rintr; /* receive interrupts */
+ unsigned long tintr; /* transmit interrupts */
+ unsigned long mintr; /* modem interrupts */
+ unsigned long ibytes; /* input bytes */
+ unsigned long ipkts; /* input packets */
+ unsigned long ierrs; /* input errors */
+ unsigned long obytes; /* output bytes */
+ unsigned long opkts; /* output packets */
+ unsigned long oerrs; /* output errors */
+} cx_stat_t;
+
typedef struct _board_t {
unsigned short port; /* base board port, 0..3f0 */
unsigned short num; /* board number, 0..2 */
@@ -439,6 +457,7 @@ typedef struct _board_t {
unsigned short bcr1b; /* BCR1b image */
cx_chip_t chip[NCHIP]; /* controller structures */
cx_chan_t chan[NCHAN]; /* channel structures */
+ cx_stat_t stat[NCHAN]; /* channel statistics */
char name[16]; /* board version name */
unsigned char nuniv; /* number of universal channels */
unsigned char nsync; /* number of sync. channels */
@@ -473,3 +492,4 @@ void cx_clock (long hz, long ba, int *clk, int *div);
#define CXIOCGETMODE _IOWR('x', 1, cx_options_t) /* get channel options */
#define CXIOCSETMODE _IOW('x', 2, cx_options_t) /* set channel options */
+#define CXIOCGETSTAT _IOWR('x', 3, cx_stat_t) /* get channel stats */
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)
OpenPOWER on IntegriCloud