diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /sys/arch/vax/if |
initial import of NetBSD tree
Diffstat (limited to 'sys/arch/vax/if')
-rw-r--r-- | sys/arch/vax/if/if_de.c | 723 | ||||
-rw-r--r-- | sys/arch/vax/if/if_dereg.h | 220 | ||||
-rw-r--r-- | sys/arch/vax/if/if_qe.c | 975 | ||||
-rw-r--r-- | sys/arch/vax/if/if_qereg.h | 172 | ||||
-rw-r--r-- | sys/arch/vax/if/if_uba.c | 390 | ||||
-rw-r--r-- | sys/arch/vax/if/if_uba.h | 136 |
6 files changed, 2616 insertions, 0 deletions
diff --git a/sys/arch/vax/if/if_de.c b/sys/arch/vax/if/if_de.c new file mode 100644 index 00000000000..18f01217787 --- /dev/null +++ b/sys/arch/vax/if/if_de.c @@ -0,0 +1,723 @@ +/* $NetBSD: if_de.c,v 1.7.2.1 1995/10/15 13:56:24 ragge Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_de.c 7.12 (Berkeley) 12/16/90 + */ + +#include "de.h" +#if NDE > 0 + +/* + * DEC DEUNA interface + * + * Lou Salkind + * New York University + * + * TODO: + * timeout routine (get statistics) + */ + +#include "sys/param.h" +#include "sys/systm.h" +#include "sys/mbuf.h" +#include "sys/buf.h" +#include "sys/protosw.h" +#include "sys/socket.h" +/* #include "sys/vmmac.h" */ +#include "sys/ioctl.h" +#include "sys/errno.h" +#include "sys/syslog.h" +#include "sys/device.h" + +#include "vax/include/pte.h" +#include "vax/include/sid.h" + +#include "net/if.h" +#include "net/netisr.h" +#include "net/route.h" + +#ifdef INET +#include "netinet/in.h" +#include "netinet/in_systm.h" +#include "netinet/in_var.h" +#include "netinet/ip.h" +#include "netinet/if_ether.h" +#endif + +#ifdef NS +#include "netns/ns.h" +#include "netns/ns_if.h" +#endif + +#ifdef ISO +#include "netiso/iso.h" +#include "netiso/iso_var.h" +extern char all_es_snpa[], all_is_snpa[]; +#endif + +#include "../include/cpu.h" +#include "../include/mtpr.h" +#include "if_dereg.h" +#include "if_uba.h" +#include "../uba/ubareg.h" +#include "../uba/ubavar.h" + +#define NXMT 3 /* number of transmit buffers */ +#define NRCV 7 /* number of receive buffers (must be > 1) */ + +int dedebug = 0; + + +int deprobe(), deattach(), deintr(); +struct uba_device *deinfo[NDE]; +u_short destd[] = { 0 }; +struct uba_driver dedriver = + { deprobe, 0, deattach, 0, destd, "de", deinfo }; +int deinit(),deioctl(),dereset(); +void destart(); + + +/* + * Ethernet software status per interface. + * + * Each interface is referenced by a network interface structure, + * ds_if, which the routing code uses to locate the interface. + * This structure contains the output queue for the interface, its address, ... + * We also have, for each interface, a UBA interface structure, which + * contains information about the UNIBUS resources held by the interface: + * map registers, buffered data paths, etc. Information is cached in this + * structure for use by the if_uba.c routines in running the interface + * efficiently. + */ +struct de_softc { + struct arpcom ds_ac; /* Ethernet common part */ +#define ds_if ds_ac.ac_if /* network-visible interface */ +#define ds_addr ds_ac.ac_enaddr /* hardware Ethernet address */ + int ds_flags; +#define DSF_RUNNING 2 /* board is enabled */ +#define DSF_SETADDR 4 /* physical address is changed */ + int ds_ubaddr; /* map info for incore structs */ + struct ifubinfo ds_deuba; /* unibus resource structure */ + struct ifrw ds_ifr[NRCV]; /* unibus receive maps */ + struct ifxmt ds_ifw[NXMT]; /* unibus xmt maps */ + /* the following structures are always mapped in */ + struct de_pcbb ds_pcbb; /* port control block */ + struct de_ring ds_xrent[NXMT]; /* transmit ring entrys */ + struct de_ring ds_rrent[NRCV]; /* receive ring entrys */ + struct de_udbbuf ds_udbbuf; /* UNIBUS data buffer */ + /* end mapped area */ +#define INCORE_BASE(p) ((char *)&(p)->ds_pcbb) +#define RVAL_OFF(n) ((char *)&de_softc[0].n - INCORE_BASE(&de_softc[0])) +#define LVAL_OFF(n) ((char *)de_softc[0].n - INCORE_BASE(&de_softc[0])) +#define PCBB_OFFSET RVAL_OFF(ds_pcbb) +#define XRENT_OFFSET LVAL_OFF(ds_xrent) +#define RRENT_OFFSET LVAL_OFF(ds_rrent) +#define UDBBUF_OFFSET RVAL_OFF(ds_udbbuf) +#define INCORE_SIZE RVAL_OFF(ds_xindex) + int ds_xindex; /* UNA index into transmit chain */ + int ds_rindex; /* UNA index into receive chain */ + int ds_xfree; /* index for next transmit buffer */ + int ds_nxmit; /* # of transmits in progress */ +} de_softc[NDE]; + +deprobe(reg) + caddr_t reg; +{ + register int br, cvec; /* r11, r10 value-result */ + volatile struct dedevice *addr = (struct dedevice *)reg; + register i; + +#ifdef lint + br = 0; cvec = br; br = cvec; + i = 0; derint(i); deintr(i); +#endif + + /* + * Make sure self-test is finished before we screw with the board. + * Self-test on a DELUA can take 15 seconds (argh). + */ + for (i = 0; + i < 160 && + (addr->pcsr0 & PCSR0_FATI) == 0 && + (addr->pcsr1 & PCSR1_STMASK) == STAT_RESET; + ++i) + waitabit(10); + if ((addr->pcsr0 & PCSR0_FATI) != 0 || + (addr->pcsr1 & PCSR1_STMASK) != STAT_READY && + (addr->pcsr1 & PCSR1_STMASK) != STAT_RUN) + return(0); + + addr->pcsr0 = 0; + waitabit(1); + addr->pcsr0 = PCSR0_RSET; + while ((addr->pcsr0 & PCSR0_INTR) == 0) + ; + /* make board interrupt by executing a GETPCBB command */ + addr->pcsr0 = PCSR0_INTE; + addr->pcsr2 = 0; + addr->pcsr3 = 0; + addr->pcsr0 = PCSR0_INTE|CMD_GETPCBB; + waitabit(10); + return(1); +} + +/* + * Interface exists: make available by filling in network interface + * record. System will initialize the interface when it is ready + * to accept packets. We get the ethernet address here. + */ +deattach(ui) + struct uba_device *ui; +{ + register struct de_softc *ds = &de_softc[ui->ui_unit]; + register struct ifnet *ifp = &ds->ds_if; + volatile struct dedevice *addr = (struct dedevice *)ui->ui_addr; + int csr1; + + ifp->if_unit = ui->ui_unit; + ifp->if_name = "de"; + ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS; + + /* + * What kind of a board is this? + * The error bits 4-6 in pcsr1 are a device id as long as + * the high byte is zero. + */ + csr1 = addr->pcsr1; + if (csr1 & 0xff60) + printf("de%d: broken\n", ui->ui_unit); + else if (csr1 & 0x10) + printf("de%d: delua\n", ui->ui_unit); + else + printf("de%d: deuna\n", ui->ui_unit); + + /* + * Reset the board and temporarily map + * the pcbb buffer onto the Unibus. + */ + addr->pcsr0 = 0; /* reset INTE */ + waitabit(1); + addr->pcsr0 = PCSR0_RSET; + (void)dewait(ui, "reset"); + + ds->ds_ubaddr = uballoc(ui->ui_ubanum, (char *)&ds->ds_pcbb, + sizeof (struct de_pcbb), 0); + addr->pcsr2 = ds->ds_ubaddr & 0xffff; + addr->pcsr3 = (ds->ds_ubaddr >> 16) & 0x3; + addr->pclow = CMD_GETPCBB; + (void)dewait(ui, "pcbb"); + + ds->ds_pcbb.pcbb0 = FC_RDPHYAD; + addr->pclow = CMD_GETCMD; + (void)dewait(ui, "read addr "); + + ubarelse(ui->ui_ubanum, &ds->ds_ubaddr); + bcopy((caddr_t)&ds->ds_pcbb.pcbb2, (caddr_t)ds->ds_addr, + sizeof (ds->ds_addr)); + printf("de%d: hardware address %s\n", ui->ui_unit, + ether_sprintf(ds->ds_addr)); + ifp->if_ioctl = deioctl; + ifp->if_reset = dereset; + ifp->if_start = destart; + ds->ds_deuba.iff_flags = UBA_CANTWAIT; +#ifdef notdef + /* CAN WE USE BDP's ??? */ + ds->ds_deuba.iff_flags |= UBA_NEEDBDP; +#endif + if_attach(ifp); + ether_ifattach(ifp); +} + +/* + * Reset of interface after UNIBUS reset. + * If interface is on specified uba, reset its state. + */ +dereset(unit, uban) + int unit, uban; +{ + register struct uba_device *ui; + + if (unit >= NDE || (ui = deinfo[unit]) == 0 || ui->ui_alive == 0 || + ui->ui_ubanum != uban) + return; + printf(" de%d", unit); + de_softc[unit].ds_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + de_softc[unit].ds_flags &= ~DSF_RUNNING; + ((struct dedevice *)ui->ui_addr)->pcsr0 = PCSR0_RSET; + (void)dewait(ui, "reset"); + deinit(unit); +} + +/* + * Initialization of interface; clear recorded pending + * operations, and reinitialize UNIBUS usage. + */ +deinit(unit) + int unit; +{ + struct de_softc *ds; + struct uba_device *ui; + volatile struct dedevice *addr; + struct ifrw *ifrw; + struct ifxmt *ifxp; + struct ifnet *ifp; + struct de_ring *rp; + int s,incaddr; + + ds = &de_softc[unit]; + ui = deinfo[unit]; + ifp = &ds->ds_if; + + /* not yet, if address still unknown */ + if (ifp->if_addrlist.tqh_first == (struct ifaddr *)0) + return; + + if (ds->ds_flags & DSF_RUNNING) + return; + if ((ifp->if_flags & IFF_RUNNING) == 0) { + if (if_ubaminit(&ds->ds_deuba, ui->ui_ubanum, + sizeof (struct ether_header), (int)btoc(ETHERMTU), + ds->ds_ifr, NRCV, ds->ds_ifw, NXMT) == 0) { + printf("de%d: can't initialize\n", unit); + ds->ds_if.if_flags &= ~IFF_UP; + return; + } + ds->ds_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(ds), + INCORE_SIZE, 0); + } + addr = (struct dedevice *)ui->ui_addr; + + /* set the pcbb block address */ + incaddr = ds->ds_ubaddr + PCBB_OFFSET; + addr->pcsr2 = incaddr & 0xffff; + addr->pcsr3 = (incaddr >> 16) & 0x3; + addr->pclow = 0; /* reset INTE */ + waitabit(1); + addr->pclow = CMD_GETPCBB; + (void)dewait(ui, "pcbb"); + + /* set the transmit and receive ring header addresses */ + incaddr = ds->ds_ubaddr + UDBBUF_OFFSET; + ds->ds_pcbb.pcbb0 = FC_WTRING; + ds->ds_pcbb.pcbb2 = incaddr & 0xffff; + ds->ds_pcbb.pcbb4 = (incaddr >> 16) & 0x3; + + incaddr = ds->ds_ubaddr + XRENT_OFFSET; + ds->ds_udbbuf.b_tdrbl = incaddr & 0xffff; + ds->ds_udbbuf.b_tdrbh = (incaddr >> 16) & 0x3; + ds->ds_udbbuf.b_telen = sizeof (struct de_ring) / sizeof (short); + ds->ds_udbbuf.b_trlen = NXMT; + incaddr = ds->ds_ubaddr + RRENT_OFFSET; + ds->ds_udbbuf.b_rdrbl = incaddr & 0xffff; + ds->ds_udbbuf.b_rdrbh = (incaddr >> 16) & 0x3; + ds->ds_udbbuf.b_relen = sizeof (struct de_ring) / sizeof (short); + ds->ds_udbbuf.b_rrlen = NRCV; + + addr->pclow = CMD_GETCMD; + (void)dewait(ui, "wtring"); + + /* initialize the mode - enable hardware padding */ + ds->ds_pcbb.pcbb0 = FC_WTMODE; + /* let hardware do padding - set MTCH bit on broadcast */ + ds->ds_pcbb.pcbb2 = MOD_TPAD|MOD_HDX; + addr->pclow = CMD_GETCMD; + (void)dewait(ui, "wtmode"); + + /* set up the receive and transmit ring entries */ + ifxp = &ds->ds_ifw[0]; + for (rp = &ds->ds_xrent[0]; rp < &ds->ds_xrent[NXMT]; rp++) { + rp->r_segbl = ifxp->ifw_info & 0xffff; + rp->r_segbh = (ifxp->ifw_info >> 16) & 0x3; + rp->r_flags = 0; + ifxp++; + } + ifrw = &ds->ds_ifr[0]; + for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) { + rp->r_slen = sizeof (struct de_buf); + rp->r_segbl = ifrw->ifrw_info & 0xffff; + rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3; + rp->r_flags = RFLG_OWN; /* hang receive */ + ifrw++; + } + + /* start up the board (rah rah) */ + s = splimp(); + ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = ds->ds_nxmit = 0; + ds->ds_if.if_flags |= IFF_RUNNING; + addr->pclow = PCSR0_INTE; /* avoid interlock */ + destart(&ds->ds_if); /* queue output packets */ + ds->ds_flags |= DSF_RUNNING; /* need before de_setaddr */ + if (ds->ds_flags & DSF_SETADDR) + de_setaddr(ds->ds_addr, unit); + addr->pclow = CMD_START | PCSR0_INTE; + splx(s); +} + +/* + * Setup output on interface. + * Get another datagram to send off of the interface queue, + * and map it to the interface before starting the output. + * Must be called from ipl >= our interrupt level. + */ +void +destart(ifp) + struct ifnet *ifp; +{ + int len; + int unit = ifp->if_unit; + struct uba_device *ui = deinfo[unit]; + volatile struct dedevice *addr = (struct dedevice *)ui->ui_addr; + register struct de_softc *ds = &de_softc[unit]; + register struct de_ring *rp; + struct mbuf *m; + register int nxmit; + + /* + * the following test is necessary, since + * the code is not reentrant and we have + * multiple transmission buffers. + */ + if (ds->ds_if.if_flags & IFF_OACTIVE) + return; + for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) { + IF_DEQUEUE(&ds->ds_if.if_snd, m); + if (m == 0) + break; + rp = &ds->ds_xrent[ds->ds_xfree]; + if (rp->r_flags & XFLG_OWN) + panic("deuna xmit in progress"); + len = if_ubaput(&ds->ds_deuba, &ds->ds_ifw[ds->ds_xfree], m); + if (ds->ds_deuba.iff_flags & UBA_NEEDBDP) + UBAPURGE(ds->ds_deuba.iff_uba, + ds->ds_ifw[ds->ds_xfree].ifw_bdp); + rp->r_slen = len; + rp->r_tdrerr = 0; + rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN; + + ds->ds_xfree++; + if (ds->ds_xfree == NXMT) + ds->ds_xfree = 0; + } + if (ds->ds_nxmit != nxmit) { + ds->ds_nxmit = nxmit; + if (ds->ds_flags & DSF_RUNNING) + addr->pclow = PCSR0_INTE|CMD_PDMD; + } +} + +/* + * Command done interrupt. + */ +deintr(uba,vector,level,unit) +{ + struct uba_device *ui; + volatile struct dedevice *addr; + register struct de_softc *ds; + register struct de_ring *rp; + register struct ifxmt *ifxp; + short csr0; + + ui = deinfo[unit]; + addr = (struct dedevice *)ui->ui_addr; + ds = &de_softc[unit]; + + + /* save flags right away - clear out interrupt bits */ + csr0 = addr->pcsr0; + addr->pchigh = csr0 >> 8; + + + ds->ds_if.if_flags |= IFF_OACTIVE; /* prevent entering destart */ + /* + * if receive, put receive buffer on mbuf + * and hang the request again + */ + derecv(unit); + + /* + * Poll transmit ring and check status. + * Be careful about loopback requests. + * Then free buffer space and check for + * more transmit requests. + */ + for ( ; ds->ds_nxmit > 0; ds->ds_nxmit--) { + rp = &ds->ds_xrent[ds->ds_xindex]; + if (rp->r_flags & XFLG_OWN) + break; + ds->ds_if.if_opackets++; + ifxp = &ds->ds_ifw[ds->ds_xindex]; + /* check for unusual conditions */ + if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) { + if (rp->r_flags & XFLG_ERRS) { + /* output error */ + ds->ds_if.if_oerrors++; + if (dedebug) + printf("de%d: oerror, flags=%b tdrerr=%b (len=%d)\n", + unit, rp->r_flags, XFLG_BITS, + rp->r_tdrerr, XERR_BITS, rp->r_slen); + } else if (rp->r_flags & XFLG_ONE) { + /* one collision */ + ds->ds_if.if_collisions++; + } else if (rp->r_flags & XFLG_MORE) { + /* more than one collision */ + ds->ds_if.if_collisions += 2; /* guess */ + } else if (rp->r_flags & XFLG_MTCH) { + /* received our own packet */ + ds->ds_if.if_ipackets++; + deread(ds, &ifxp->ifrw, + rp->r_slen - sizeof (struct ether_header)); + } + } + if (ifxp->ifw_xtofree) { + m_freem(ifxp->ifw_xtofree); + ifxp->ifw_xtofree = 0; + } + /* check if next transmit buffer also finished */ + ds->ds_xindex++; + if (ds->ds_xindex == NXMT) + ds->ds_xindex = 0; + } + ds->ds_if.if_flags &= ~IFF_OACTIVE; + destart(&ds->ds_if); + + if (csr0 & PCSR0_RCBI) { + if (dedebug) + log(LOG_WARNING, "de%d: buffer unavailable\n", unit); + addr->pclow = PCSR0_INTE|CMD_PDMD; + } +} + +/* + * Ethernet interface receiver interface. + * If input error just drop packet. + * Otherwise purge input buffered data path and examine + * packet to determine type. If can't determine length + * from type, then have to drop packet. Othewise decapsulate + * packet based on type and pass to type specific higher-level + * input routine. + */ +derecv(unit) + int unit; +{ + register struct de_softc *ds = &de_softc[unit]; + register struct de_ring *rp; + int len; + + rp = &ds->ds_rrent[ds->ds_rindex]; + while ((rp->r_flags & RFLG_OWN) == 0) { + ds->ds_if.if_ipackets++; + if (ds->ds_deuba.iff_flags & UBA_NEEDBDP) + UBAPURGE(ds->ds_deuba.iff_uba, + ds->ds_ifr[ds->ds_rindex].ifrw_bdp); + len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header) + - 4; /* don't forget checksum! */ + /* check for errors */ + if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) || + (rp->r_flags&(RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP) || + (rp->r_lenerr & (RERR_BUFL|RERR_UBTO|RERR_NCHN)) || + len < ETHERMIN || len > ETHERMTU) { + ds->ds_if.if_ierrors++; + if (dedebug) + printf("de%d: ierror, flags=%b lenerr=%b (len=%d)\n", + unit, rp->r_flags, RFLG_BITS, rp->r_lenerr, + RERR_BITS, len); + } else + deread(ds, &ds->ds_ifr[ds->ds_rindex], len); + + /* hang the receive buffer again */ + rp->r_lenerr = 0; + rp->r_flags = RFLG_OWN; + + /* check next receive buffer */ + ds->ds_rindex++; + if (ds->ds_rindex == NRCV) + ds->ds_rindex = 0; + rp = &ds->ds_rrent[ds->ds_rindex]; + } +} + +/* + * Pass a packet to the higher levels. + * We deal with the trailer protocol here. + */ +deread(ds, ifrw, len) + register struct de_softc *ds; + struct ifrw *ifrw; + int len; +{ + struct ether_header *eh; + struct mbuf *m; + int s; + register struct ifqueue *inq; + + /* + * Deal with trailer protocol: if type is trailer type + * get true type from first 16-bit word past data. + * Remember that type was trailer by setting off. + */ + eh = (struct ether_header *)ifrw->ifrw_addr; +/* eh->ether_type = ntohs((u_short)eh->ether_type); */ + if (len == 0) + return; + + /* + * Pull packet off interface. Off is nonzero if packet + * has trailing header; if_ubaget will then force this header + * information to be at the front. + */ + m = if_ubaget(&ds->ds_deuba, ifrw, len, &ds->ds_if); + if (m) + ether_input(&ds->ds_if, eh, m); +} +/* + * Process an ioctl request. + */ +deioctl(ifp, cmd, data) + register struct ifnet *ifp; + int cmd; + caddr_t data; +{ + register struct ifaddr *ifa = (struct ifaddr *)data; + register struct de_softc *ds = &de_softc[ifp->if_unit]; + int s = splimp(), error = 0; + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + deinit(ifp->if_unit); + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + arp_ifinit(&ds->ds_ac, ifa); + break; +#endif +#ifdef NS + case AF_NS: + { + register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); + + if (ns_nullhost(*ina)) + ina->x_host = *(union ns_host *)(ds->ds_addr); + else + de_setaddr(ina->x_host.c_host,ifp->if_unit); + break; + } +#endif + } + break; + + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && + ds->ds_flags & DSF_RUNNING) { + ((struct dedevice *) + (deinfo[ifp->if_unit]->ui_addr))->pclow = 0; + waitabit(1); + ((struct dedevice *) + (deinfo[ifp->if_unit]->ui_addr))->pclow = PCSR0_RSET; + ds->ds_flags &= ~DSF_RUNNING; + ds->ds_if.if_flags &= ~IFF_OACTIVE; + } else if (ifp->if_flags & IFF_UP && + (ds->ds_flags & DSF_RUNNING) == 0) + deinit(ifp->if_unit); + break; + + default: + error = EINVAL; + } + splx(s); + return (error); +} + +/* + * set ethernet address for unit + */ +de_setaddr(physaddr, unit) + u_char *physaddr; + int unit; +{ + register struct de_softc *ds = &de_softc[unit]; + struct uba_device *ui = deinfo[unit]; + volatile struct dedevice *addr= (struct dedevice *)ui->ui_addr; + + if (! (ds->ds_flags & DSF_RUNNING)) + return; + + bcopy((caddr_t) physaddr, (caddr_t) &ds->ds_pcbb.pcbb2, 6); + ds->ds_pcbb.pcbb0 = FC_WTPHYAD; + addr->pclow = PCSR0_INTE|CMD_GETCMD; + if (dewait(ui, "address change") == 0) { + ds->ds_flags |= DSF_SETADDR; + bcopy((caddr_t) physaddr, (caddr_t) ds->ds_addr, 6); + } +} + +/* + * Await completion of the named function + * and check for errors. + */ +dewait(ui, fn) + register struct uba_device *ui; + char *fn; +{ + volatile struct dedevice *addr = (struct dedevice *)ui->ui_addr; + register csr0; + + while ((addr->pcsr0 & PCSR0_INTR) == 0) + ; + csr0 = addr->pcsr0; + addr->pchigh = csr0 >> 8; + if (csr0 & PCSR0_PCEI) + printf("de%d: %s failed, csr0=%b csr1=%b\n", + ui->ui_unit, fn, csr0, PCSR0_BITS, + addr->pcsr1, PCSR1_BITS); + return (csr0 & PCSR0_PCEI); +} + +de_match(){ + printf("de_match\n"); + return 0; +} + +void +de_attach(){ + printf("de_attach\n"); +} + +struct cfdriver decd = + { NULL,"de",de_match, de_attach, DV_IFNET, sizeof(struct uba_driver) }; + + +#endif diff --git a/sys/arch/vax/if/if_dereg.h b/sys/arch/vax/if/if_dereg.h new file mode 100644 index 00000000000..2f2b48c9796 --- /dev/null +++ b/sys/arch/vax/if/if_dereg.h @@ -0,0 +1,220 @@ +/* $NetBSD: if_dereg.h,v 1.2 1994/10/26 08:01:51 cgd Exp $ */ + +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_dereg.h 7.3 (Berkeley) 6/28/90 + */ + +/* + * DEC DEUNA interface + */ +struct dedevice { + union { + short p0_w; + char p0_b[2]; + } u_p0; +#define pcsr0 u_p0.p0_w +#define pclow u_p0.p0_b[0] +#define pchigh u_p0.p0_b[1] + short pcsr1; + short pcsr2; + short pcsr3; +}; + +/* + * PCSR 0 bit descriptions + */ +#define PCSR0_SERI 0x8000 /* Status error interrupt */ +#define PCSR0_PCEI 0x4000 /* Port command error interrupt */ +#define PCSR0_RXI 0x2000 /* Receive done interrupt */ +#define PCSR0_TXI 0x1000 /* Transmit done interrupt */ +#define PCSR0_DNI 0x0800 /* Done interrupt */ +#define PCSR0_RCBI 0x0400 /* Receive buffer unavail intrpt */ +#define PCSR0_FATI 0x0100 /* Fatal error interrupt */ +#define PCSR0_INTR 0x0080 /* Interrupt summary */ +#define PCSR0_INTE 0x0040 /* Interrupt enable */ +#define PCSR0_RSET 0x0020 /* DEUNA reset */ +#define PCSR0_CMASK 0x000f /* command mask */ + +#define PCSR0_BITS "\20\20SERI\17PCEI\16RXI\15TXI\14DNI\13RCBI\11FATI\10INTR\7INTE\6RSET" + +/* bits 0-3 are for the PORT_COMMAND */ +#define CMD_NOOP 0x0 +#define CMD_GETPCBB 0x1 /* Get PCB Block */ +#define CMD_GETCMD 0x2 /* Execute command in PCB */ +#define CMD_STEST 0x3 /* Self test mode */ +#define CMD_START 0x4 /* Reset xmit and receive ring ptrs */ +#define CMD_BOOT 0x5 /* Boot DEUNA */ +#define CMD_PDMD 0x8 /* Polling demand */ +#define CMD_TMRO 0x9 /* Sanity timer on */ +#define CMD_TMRF 0xa /* Sanity timer off */ +#define CMD_RSTT 0xb /* Reset sanity timer */ +#define CMD_STOP 0xf /* Suspend operation */ + +/* + * PCSR 1 bit descriptions + */ +#define PCSR1_XPWR 0x8000 /* Transceiver power BAD */ +#define PCSR1_ICAB 0x4000 /* Interconnect cabling BAD */ +#define PCSR1_STCODE 0x3f00 /* Self test error code */ +#define PCSR1_PCTO 0x0080 /* Port command timed out */ +#define PCSR1_ILLINT 0x0040 /* Illegal interrupt */ +#define PCSR1_TIMEOUT 0x0020 /* Timeout */ +#define PCSR1_POWER 0x0010 /* Power fail */ +#define PCSR1_RMTC 0x0008 /* Remote console reserved */ +#define PCSR1_STMASK 0x0007 /* State */ + +/* bit 0-3 are for STATE */ +#define STAT_RESET 0x0 +#define STAT_PRIMLD 0x1 /* Primary load */ +#define STAT_READY 0x2 +#define STAT_RUN 0x3 +#define STAT_UHALT 0x5 /* UNIBUS halted */ +#define STAT_NIHALT 0x6 /* NI halted */ +#define STAT_NIUHALT 0x7 /* NI and UNIBUS Halted */ + +#define PCSR1_BITS "\20\20XPWR\17ICAB\10PCTO\7ILLINT\6TIMEOUT\5POWER\4RMTC" + +/* + * Port Control Block Base + */ +struct de_pcbb { + short pcbb0; /* function */ + short pcbb2; /* command specific */ + short pcbb4; + short pcbb6; +}; + +/* PCBB function codes */ +#define FC_NOOP 0x00 /* NO-OP */ +#define FC_LSUADDR 0x01 /* Load and start microaddress */ +#define FC_RDDEFAULT 0x02 /* Read default physical address */ +#define FC_RDPHYAD 0x04 /* Read physical address */ +#define FC_WTPHYAD 0x05 /* Write physical address */ +#define FC_RDMULTI 0x06 /* Read multicast address list */ +#define FC_WTMULTI 0x07 /* Read multicast address list */ +#define FC_RDRING 0x08 /* Read ring format */ +#define FC_WTRING 0x09 /* Write ring format */ +#define FC_RDCNTS 0x0a /* Read counters */ +#define FC_RCCNTS 0x0b /* Read and clear counters */ +#define FC_RDMODE 0x0c /* Read mode */ +#define FC_WTMODE 0x0d /* Write mode */ +#define FC_RDSTATUS 0x0e /* Read port status */ +#define FC_RCSTATUS 0x0f /* Read and clear port status */ +#define FC_DUMPMEM 0x10 /* Dump internal memory */ +#define FC_LOADMEM 0x11 /* Load internal memory */ +#define FC_RDSYSID 0x12 /* Read system ID parameters */ +#define FC_WTSYSID 0x13 /* Write system ID parameters */ +#define FC_RDSERAD 0x14 /* Read load server address */ +#define FC_WTSERAD 0x15 /* Write load server address */ + +/* + * Unibus Data Block Base (UDBB) for ring buffers + */ +struct de_udbbuf { + short b_tdrbl; /* Transmit desc ring base low 16 bits */ + char b_tdrbh; /* Transmit desc ring base high 2 bits */ + char b_telen; /* Length of each transmit entry */ + short b_trlen; /* Number of entries in the XMIT desc ring */ + short b_rdrbl; /* Receive desc ring base low 16 bits */ + char b_rdrbh; /* Receive desc ring base high 2 bits */ + char b_relen; /* Length of each receive entry */ + short b_rrlen; /* Number of entries in the RECV desc ring */ +}; + +/* + * Transmit/Receive Ring Entry + */ +struct de_ring { + short r_slen; /* Segment length */ + short r_segbl; /* Segment address (low 16 bits) */ + char r_segbh; /* Segment address (hi 2 bits) */ + u_char r_flags; /* Status flags */ + u_short r_tdrerr; /* Errors */ +#define r_lenerr r_tdrerr + short r_rid; /* Request ID */ +}; + +#define XFLG_OWN 0x80 /* If 0 then owned by driver */ +#define XFLG_ERRS 0x40 /* Error summary */ +#define XFLG_MTCH 0x20 /* Address match on xmit request */ +#define XFLG_MORE 0x10 /* More than one entry required */ +#define XFLG_ONE 0x08 /* One collision encountered */ +#define XFLG_DEF 0x04 /* Transmit deferred */ +#define XFLG_STP 0x02 /* Start of packet */ +#define XFLG_ENP 0x01 /* End of packet */ + +#define XFLG_BITS "\10\10OWN\7ERRS\6MTCH\5MORE\4ONE\3DEF\2STP\1ENP" + +#define XERR_BUFL 0x8000 /* Buffer length error */ +#define XERR_UBTO 0x4000 /* UNIBUS tiemout +#define XERR_LCOL 0x1000 /* Late collision */ +#define XERR_LCAR 0x0800 /* Loss of carrier */ +#define XERR_RTRY 0x0400 /* Failed after 16 retries */ +#define XERR_TDR 0x03ff /* TDR value */ + +#define XERR_BITS "\20\20BUFL\17UBTO\15LCOL\14LCAR\13RTRY" + +#define RFLG_OWN 0x80 /* If 0 then owned by driver */ +#define RFLG_ERRS 0x40 /* Error summary */ +#define RFLG_FRAM 0x20 /* Framing error */ +#define RFLG_OFLO 0x10 /* Message overflow */ +#define RFLG_CRC 0x08 /* CRC error */ +#define RFLG_STP 0x02 /* Start of packet */ +#define RFLG_ENP 0x01 /* End of packet */ + +#define RFLG_BITS "\10\10OWN\7ERRS\6FRAM\5OFLO\4CRC\2STP\1ENP" + +#define RERR_BUFL 0x8000 /* Buffer length error */ +#define RERR_UBTO 0x4000 /* UNIBUS tiemout */ +#define RERR_NCHN 0x2000 /* No data chaining */ +#define RERR_MLEN 0x0fff /* Message length */ + +#define RERR_BITS "\20\20BUFL\17UBTO\16NCHN" + +/* mode description bits */ +#define MOD_HDX 0x0001 /* Half duplex mode */ +#define MOD_LOOP 0x0004 /* Enable internal loopback */ +#define MOD_DTCR 0x0008 /* Disables CRC generation */ +#define MOD_DMNT 0x0200 /* Disable maintenance features */ +#define MOD_ECT 0x0400 /* Enable collision test */ +#define MOD_TPAD 0x1000 /* Transmit message pad enable */ +#define MOD_DRDC 0x2000 /* Disable data chaining */ +#define MOD_ENAL 0x4000 /* Enable all multicast */ +#define MOD_PROM 0x8000 /* Enable promiscuous mode */ + +struct de_buf { + struct ether_header db_head; /* header */ + char db_data[ETHERMTU]; /* packet data */ + int db_crc; /* CRC - on receive only */ +}; diff --git a/sys/arch/vax/if/if_qe.c b/sys/arch/vax/if/if_qe.c new file mode 100644 index 00000000000..fbf584fd09e --- /dev/null +++ b/sys/arch/vax/if/if_qe.c @@ -0,0 +1,975 @@ +/* $NetBSD: if_qe.c,v 1.4.2.1 1995/10/15 13:56:26 ragge Exp $ */ +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Digital Equipment Corp. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_qe.c 7.20 (Berkeley) 3/28/91 + */ + +/* from @(#)if_qe.c 1.15 (ULTRIX) 4/16/86 */ + +/**************************************************************** + * * + * Licensed from Digital Equipment Corporation * + * Copyright (c) * + * Digital Equipment Corporation * + * Maynard, Massachusetts * + * 1985, 1986 * + * All rights reserved. * + * * + * The Information in this software is subject to change * + * without notice and should not be construed as a commitment * + * by Digital Equipment Corporation. Digital makes no * + * representations about the suitability of this software for * + * any purpose. It is supplied "As Is" without expressed or * + * implied warranty. * + * * + * If the Regents of the University of California or its * + * licensees modify the software in a manner creating * + * derivative copyright rights, appropriate copyright * + * legends may be placed on the derivative work in addition * + * to that set forth above. * + * * + ****************************************************************/ +/* --------------------------------------------------------------------- + * Modification History + * + * 15-Apr-86 -- afd + * Rename "unused_multi" to "qunused_multi" for extending Generic + * kernel to MicroVAXen. + * + * 18-mar-86 -- jaw br/cvec changed to NOT use registers. + * + * 12 March 86 -- Jeff Chase + * Modified to handle the new MCLGET macro + * Changed if_qe_data.c to use more receive buffers + * Added a flag to poke with adb to log qe_restarts on console + * + * 19 Oct 85 -- rjl + * Changed the watch dog timer from 30 seconds to 3. VMS is using + * less than 1 second in their's. Also turned the printf into an + * mprintf. + * + * 09/16/85 -- Larry Cohen + * Add 43bsd alpha tape changes for subnet routing + * + * 1 Aug 85 -- rjl + * Panic on a non-existent memory interrupt and the case where a packet + * was chained. The first should never happen because non-existant + * memory interrupts cause a bus reset. The second should never happen + * because we hang 2k input buffers on the device. + * + * 1 Aug 85 -- rich + * Fixed the broadcast loopback code to handle Clusters without + * wedging the system. + * + * 27 Feb. 85 -- ejf + * Return default hardware address on ioctl request. + * + * 12 Feb. 85 -- ejf + * Added internal extended loopback capability. + * + * 27 Dec. 84 -- rjl + * Fixed bug that caused every other transmit descriptor to be used + * instead of every descriptor. + * + * 21 Dec. 84 -- rjl + * Added watchdog timer to mask hardware bug that causes device lockup. + * + * 18 Dec. 84 -- rjl + * Reworked driver to use q-bus mapping routines. MicroVAX-I now does + * copying instead of m-buf shuffleing. + * A number of deficencies in the hardware/firmware were compensated + * for. See comments in qestart and qerint. + * + * 14 Nov. 84 -- jf + * Added usage counts for multicast addresses. + * Updated general protocol support to allow access to the Ethernet + * header. + * + * 04 Oct. 84 -- jf + * Added support for new ioctls to add and delete multicast addresses + * and set the physical address. + * Add support for general protocols. + * + * 14 Aug. 84 -- rjl + * Integrated Shannon changes. (allow arp above 1024 and ? ) + * + * 13 Feb. 84 -- rjl + * + * Initial version of driver. derived from IL driver. + * + * --------------------------------------------------------------------- + */ + +#include "qe.h" +#if NQE > 0 +/* + * Digital Q-BUS to NI Adapter + */ +#include "sys/param.h" +#include "sys/systm.h" +#include "sys/mbuf.h" +#include "sys/buf.h" +#include "sys/protosw.h" +#include "sys/socket.h" +#include "sys/ioctl.h" +#include "sys/errno.h" +#include "sys/syslog.h" +#include "sys/device.h" +#include "sys/time.h" +#include "sys/kernel.h" + +#include "net/if.h" +#include "net/netisr.h" +#include "net/route.h" + +#ifdef INET +#include "netinet/in.h" +#include "netinet/in_systm.h" +#include "netinet/in_var.h" +#include "netinet/ip.h" +#include "netinet/if_ether.h" +#endif + +#ifdef NS +#include "netns/ns.h" +#include "netns/ns_if.h" +#endif + +#ifdef ISO +#include "netiso/iso.h" +#include "netiso/iso_var.h" +extern char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[]; +#endif + +#include "vax/include/pte.h" +#include "vax/include/cpu.h" +#include "vax/include/mtpr.h" +#include "if_qereg.h" +#include "if_uba.h" +#include "vax/uba/ubareg.h" +#include "vax/uba/ubavar.h" + +#if NQE == 1 && !defined(QNIVERT) +#define NRCV 15 /* Receive descriptors */ +#else +#define NRCV 10 /* Receive descriptors */ +#endif +#define NXMT 5 /* Transmit descriptors */ +#define NTOT (NXMT + NRCV) + +#define QETIMEOUT 2 /* transmit timeout, must be > 1 */ +#define QESLOWTIMEOUT 40 /* timeout when no xmits in progress */ + +#define MINDATA 60 + +void qetimeout(int); + +/* + * Ethernet software status per interface. + * + * Each interface is referenced by a network interface structure, + * qe_if, which the routing code uses to locate the interface. + * This structure contains the output queue for the interface, its address, ... + */ +struct qe_softc { + struct arpcom qe_ac; /* Ethernet common part */ +#define qe_if qe_ac.ac_if /* network-visible interface */ +#define qe_addr qe_ac.ac_enaddr /* hardware Ethernet address */ + struct ifubinfo qe_uba; /* Q-bus resources */ + volatile struct ifrw qe_ifr[NRCV]; /* for receive buffers; */ + volatile struct ifxmt qe_ifw[NXMT]; /* for xmit buffers; */ + int qe_flags; /* software state */ +#define QEF_RUNNING 0x01 +#define QEF_SETADDR 0x02 +#define QEF_FASTTIMEO 0x04 + int setupaddr; /* mapping info for setup pkts */ + int ipl; /* interrupt priority */ + struct qe_ring *rringaddr; /* mapping info for rings */ + struct qe_ring *tringaddr; /* "" */ + volatile struct qe_ring rring[NRCV+1]; /* Receive ring descriptors */ + volatile struct qe_ring tring[NXMT+1]; /* Xmit ring descriptors */ + u_char setup_pkt[16][8]; /* Setup packet */ + int rindex; /* Receive index */ + int tindex; /* Transmit index */ + int otindex; /* Old transmit index */ + int qe_intvec; /* Interrupt vector */ + volatile struct qedevice *addr; /* device addr */ + int setupqueued; /* setup packet queued */ + int nxmit; /* Transmits in progress */ + int qe_restarts; /* timeouts */ +} qe_softc[NQE]; + +struct uba_device *qeinfo[NQE]; + +extern struct timeval time; + +int qeprobe(), qeattach(), qeintr(); +int qeinit(), qeioctl(), qereset(); +void qestart(); + +u_short qestd[] = { 0 }; +struct uba_driver qedriver = + { qeprobe, 0, qeattach, 0, qestd, "qe", qeinfo }; + +#define QEUNIT(x) minor(x) +/* + * The deqna shouldn't receive more than ETHERMTU + sizeof(struct ether_header) + * but will actually take in up to 2048 bytes. To guard against the receiver + * chaining buffers (which we aren't prepared to handle) we allocate 2kb + * size buffers. + */ +#define MAXPACKETSIZE 2048 /* Should really be ETHERMTU */ +/* + * Probe the QNA to see if it's there + */ +qeprobe(reg, ui) + caddr_t reg; + struct uba_device *ui; +{ + /* register int br, cvec; r11, r10 value-result */ + register volatile struct qedevice *addr = (struct qedevice *)reg; + register volatile struct qe_ring *rp; + register struct qe_ring *prp; /* physical rp */ + register int i; + register volatile struct qe_softc *sc = &qe_softc[ui->ui_unit]; + +#ifdef lint + br = 0; cvec = br; br = cvec; + qeintr(0); +#endif + + /* + * The QNA interrupts on i/o operations. To do an I/O operation + * we have to setup the interface by transmitting a setup packet. + */ + addr->qe_csr = QE_RESET; + addr->qe_csr &= ~QE_RESET; + addr->qe_vector = (uba_hd[numuba].uh_lastiv -= 4); + + /* + * Map the communications area and the setup packet. + */ + sc->setupaddr = + uballoc(0, (caddr_t)sc->setup_pkt, sizeof(sc->setup_pkt), 0); + sc->rringaddr = (struct qe_ring *) uballoc(0, (caddr_t)sc->rring, + sizeof(struct qe_ring) * (NTOT+2), 0); + prp = (struct qe_ring *)UBAI_ADDR((int)sc->rringaddr); + + /* + * The QNA will loop the setup packet back to the receive ring + * for verification, therefore we initialize the first + * receive & transmit ring descriptors and link the setup packet + * to them. + */ + qeinitdesc(sc->tring, (caddr_t)UBAI_ADDR(sc->setupaddr), + sizeof(sc->setup_pkt)); + qeinitdesc(sc->rring, (caddr_t)UBAI_ADDR(sc->setupaddr), + sizeof(sc->setup_pkt)); + + rp = (struct qe_ring *)sc->tring; + rp->qe_setup = 1; + rp->qe_eomsg = 1; + rp->qe_flag = rp->qe_status1 = QE_NOTYET; + rp->qe_valid = 1; + + rp = (struct qe_ring *)sc->rring; + rp->qe_flag = rp->qe_status1 = QE_NOTYET; + rp->qe_valid = 1; + + /* + * Get the addr off of the interface and place it into the setup + * packet. This code looks strange due to the fact that the address + * is placed in the setup packet in col. major order. + */ + for( i = 0 ; i < 6 ; i++ ) + sc->setup_pkt[i][1] = addr->qe_sta_addr[i]; + + qesetup( sc ); + /* + * Start the interface and wait for the packet. + */ + addr->qe_csr = QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT; + addr->qe_rcvlist_lo = (short)((int)prp); + addr->qe_rcvlist_hi = (short)((int)prp >> 16); + prp += NRCV+1; + addr->qe_xmtlist_lo = (short)((int)prp); + addr->qe_xmtlist_hi = (short)((int)prp >> 16); + DELAY(10000); + /* + * All done with the bus resources. + */ + ubarelse(0, &sc->setupaddr); + ubarelse(0, (int *)&sc->rringaddr); + sc->ipl = 0x15; + return( sizeof(struct qedevice) ); +} + +/* + * Interface exists: make available by filling in network interface + * record. System will initialize the interface when it is ready + * to accept packets. + */ +qeattach(ui) + struct uba_device *ui; +{ + struct qe_softc *sc = &qe_softc[ui->ui_unit]; + struct ifnet *ifp = (struct ifnet *)&sc->qe_if; + volatile struct qedevice *addr=(struct qedevice *)ui->ui_addr; + int i; + + ifp->if_unit = ui->ui_unit; + ifp->if_name = "qe"; + /* + * The Deqna is cable of transmitting broadcasts, but + * doesn't listen to its own. + */ + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; + + /* + * Read the address from the prom and save it. + */ + for( i=0 ; i<6 ; i++ ) + sc->setup_pkt[i][1] = sc->qe_addr[i] = addr->qe_sta_addr[i] & 0xff; + addr->qe_vector |= 1; + printf("qe%d: %s, hardware address %s\n", ui->ui_unit, + addr->qe_vector&01 ? "delqa":"deqna", + ether_sprintf(sc->qe_addr)); + addr->qe_vector &= ~1; + + /* + * Save the vector for initialization at reset time. + */ + sc->qe_intvec = addr->qe_vector; + + ifp->if_start = qestart; + ifp->if_ioctl = qeioctl; + ifp->if_reset = qereset; + ifp->if_watchdog = qetimeout; + sc->qe_uba.iff_flags = UBA_CANTWAIT; + if_attach(ifp); + ether_ifattach(ifp); +} + +/* + * Reset of interface after UNIBUS reset. + * If interface is on specified uba, reset its state. + */ +qereset(unit, uban) + int unit, uban; +{ + register struct uba_device *ui; + + if (unit >= NQE || (ui = qeinfo[unit]) == 0 || ui->ui_alive == 0 || + ui->ui_ubanum != uban) + return; + printf(" qe%d", unit); + qe_softc[unit].qe_if.if_flags &= ~IFF_RUNNING; + qeinit(unit); +} + +/* + * Initialization of interface. + */ +qeinit(unit) + int unit; +{ + volatile struct qe_softc *sc = &qe_softc[unit]; + struct uba_device *ui = qeinfo[unit]; + volatile struct qedevice *addr=(struct qedevice *)ui->ui_addr; + struct ifnet *ifp = (struct ifnet *)&sc->qe_if; + int i; + int s; + + /* address not known */ + if (ifp->if_addrlist.tqh_first == (struct ifaddr *)0) + return; + if (sc->qe_flags & QEF_RUNNING) + return; + + if ((ifp->if_flags & IFF_RUNNING) == 0) { + /* + * map the communications area onto the device + */ + i = uballoc(0, (caddr_t)sc->rring, + sizeof(struct qe_ring) * (NTOT+2), 0); + if (i == 0) + goto fail; + sc->rringaddr = (struct qe_ring *)UBAI_ADDR(i); + sc->tringaddr = sc->rringaddr + NRCV + 1; + i = uballoc(0, (caddr_t)sc->setup_pkt, + sizeof(sc->setup_pkt), 0); + if (i == 0) + goto fail; + sc->setupaddr = UBAI_ADDR(i); + /* + * init buffers and maps + */ + if (if_ubaminit(&sc->qe_uba, ui->ui_ubanum, + sizeof (struct ether_header), (int)btoc(MAXPACKETSIZE), + sc->qe_ifr, NRCV, sc->qe_ifw, NXMT) == 0) { + fail: + printf("qe%d: can't allocate uba resources\n", unit); + sc->qe_if.if_flags &= ~IFF_UP; + return; + } + } + /* + * Init the buffer descriptors and indexes for each of the lists and + * loop them back to form a ring. + */ + for (i = 0; i < NRCV; i++) { + qeinitdesc( &sc->rring[i], + (caddr_t)UBAI_ADDR(sc->qe_ifr[i].ifrw_info), MAXPACKETSIZE); + sc->rring[i].qe_flag = sc->rring[i].qe_status1 = QE_NOTYET; + sc->rring[i].qe_valid = 1; + } + qeinitdesc(&sc->rring[i], (caddr_t)NULL, 0); + + sc->rring[i].qe_addr_lo = (short)((int)sc->rringaddr); + sc->rring[i].qe_addr_hi = (short)((int)sc->rringaddr >> 16); + sc->rring[i].qe_chain = 1; + sc->rring[i].qe_flag = sc->rring[i].qe_status1 = QE_NOTYET; + sc->rring[i].qe_valid = 1; + + for( i = 0 ; i <= NXMT ; i++ ) + qeinitdesc(&sc->tring[i], (caddr_t)NULL, 0); + i--; + + sc->tring[i].qe_addr_lo = (short)((int)sc->tringaddr); + sc->tring[i].qe_addr_hi = (short)((int)sc->tringaddr >> 16); + sc->tring[i].qe_chain = 1; + sc->tring[i].qe_flag = sc->tring[i].qe_status1 = QE_NOTYET; + sc->tring[i].qe_valid = 1; + + sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0; + + /* + * Take the interface out of reset, program the vector, + * enable interrupts, and tell the world we are up. + */ + s = splimp(); + addr->qe_vector = sc->qe_intvec; + sc->addr = addr; + addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | + QE_RCV_INT | QE_ILOOP; + addr->qe_rcvlist_lo = (short)((int)sc->rringaddr); + addr->qe_rcvlist_hi = (short)((int)sc->rringaddr >> 16); + ifp->if_flags |= IFF_UP | IFF_RUNNING; + sc->qe_flags |= QEF_RUNNING; + qesetup( sc ); + qestart( ifp ); + sc->qe_if.if_timer = QESLOWTIMEOUT; /* Start watchdog */ + splx( s ); +} + +/* + * Start output on interface. + * + */ +void +qestart(ifp) + struct ifnet *ifp; +{ + int unit = ifp->if_unit; + struct uba_device *ui = qeinfo[unit]; + register volatile struct qe_softc *sc = &qe_softc[unit]; + register volatile struct qedevice *addr; + register volatile struct qe_ring *rp; + register index; + struct mbuf *m; + int buf_addr, len, s; + + + s = splimp(); + addr = (struct qedevice *)ui->ui_addr; + /* + * The deqna doesn't look at anything but the valid bit + * to determine if it should transmit this packet. If you have + * a ring and fill it the device will loop indefinately on the + * packet and continue to flood the net with packets until you + * break the ring. For this reason we never queue more than n-1 + * packets in the transmit ring. + * + * The microcoders should have obeyed their own defination of the + * flag and status words, but instead we have to compensate. + */ + for( index = sc->tindex; + sc->tring[index].qe_valid == 0 && sc->nxmit < (NXMT-1) ; + sc->tindex = index = ++index % NXMT){ + rp = &sc->tring[index]; + if( sc->setupqueued ) { + buf_addr = sc->setupaddr; + len = 128; + rp->qe_setup = 1; + sc->setupqueued = 0; + } else { + IF_DEQUEUE(&sc->qe_if.if_snd, m); + if( m == 0 ){ + splx(s); + return; + } + buf_addr = sc->qe_ifw[index].ifw_info; + len = if_ubaput(&sc->qe_uba, &sc->qe_ifw[index], m); + } + if( len < MINDATA ) + len = MINDATA; + /* + * Does buffer end on odd byte ? + */ + if( len & 1 ) { + len++; + rp->qe_odd_end = 1; + } + rp->qe_buf_len = -(len/2); + buf_addr = UBAI_ADDR(buf_addr); + rp->qe_flag = rp->qe_status1 = QE_NOTYET; + rp->qe_addr_lo = (short)buf_addr; + rp->qe_addr_hi = (short)(buf_addr >> 16); + rp->qe_eomsg = 1; + rp->qe_flag = rp->qe_status1 = QE_NOTYET; + rp->qe_valid = 1; + if (sc->nxmit++ == 0) { + sc->qe_flags |= QEF_FASTTIMEO; + sc->qe_if.if_timer = QETIMEOUT; + } + + /* + * See if the xmit list is invalid. + */ + if( addr->qe_csr & QE_XL_INVALID ) { + buf_addr = (int)(sc->tringaddr+index); + addr->qe_xmtlist_lo = (short)buf_addr; + addr->qe_xmtlist_hi = (short)(buf_addr >> 16); + } + } + splx(s); + return; +} + +/* + * Ethernet interface interrupt processor + */ +qeintr(uba, vector, level, unit) +{ + register volatile struct qe_softc *sc = &qe_softc[unit]; + volatile struct qedevice *addr = + (struct qedevice *)qeinfo[unit]->ui_addr; + int buf_addr, csr; + + splx(sc->ipl); + if (!(sc->qe_flags & QEF_FASTTIMEO)) + sc->qe_if.if_timer = QESLOWTIMEOUT; /* Restart timer clock */ + csr = addr->qe_csr; + addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP; + if( csr & QE_RCV_INT ) + qerint( unit ); + if( csr & QE_XMIT_INT ) + qetint( unit ); + if( csr & QE_NEX_MEM_INT ) + printf("qe%d: Nonexistent memory interrupt\n", unit); + + if( addr->qe_csr & QE_RL_INVALID && sc->rring[sc->rindex].qe_status1 == QE_NOTYET ) { + buf_addr = (int)&sc->rringaddr[sc->rindex]; + addr->qe_rcvlist_lo = (short)buf_addr; + addr->qe_rcvlist_hi = (short)(buf_addr >> 16); + } +} + +/* + * Ethernet interface transmit interrupt. + */ + +qetint(unit) + int unit; +{ + register volatile struct qe_softc *sc = &qe_softc[unit]; + register volatile struct qe_ring *rp; + register volatile struct ifxmt *ifxp; + int status1, setupflag; + short len; + + + while( sc->otindex != sc->tindex && sc->tring[sc->otindex].qe_status1 != QE_NOTYET && sc->nxmit > 0 ) { + /* + * Save the status words from the descriptor so that it can + * be released. + */ + rp = &sc->tring[sc->otindex]; + status1 = rp->qe_status1; + setupflag = rp->qe_setup; + len = (-rp->qe_buf_len) * 2; + if( rp->qe_odd_end ) + len++; + /* + * Init the buffer descriptor + */ + bzero((caddr_t)rp, sizeof(struct qe_ring)); + if( --sc->nxmit == 0 ) { + sc->qe_flags &= ~QEF_FASTTIMEO; + sc->qe_if.if_timer = QESLOWTIMEOUT; + } + if( !setupflag ) { + /* + * Do some statistics. + */ + sc->qe_if.if_opackets++; + sc->qe_if.if_collisions += ( status1 & QE_CCNT ) >> 4; + if (status1 & QE_ERROR) + sc->qe_if.if_oerrors++; + ifxp = &sc->qe_ifw[sc->otindex]; + if (ifxp->ifw_xtofree) { + m_freem(ifxp->ifw_xtofree); + ifxp->ifw_xtofree = 0; + } + } + sc->otindex = ++sc->otindex % NXMT; + } + qestart( &sc->qe_if ); +} + +/* + * Ethernet interface receiver interrupt. + * If can't determine length from type, then have to drop packet. + * Othewise decapsulate packet based on type and pass to type specific + * higher-level input routine. + */ +qerint(unit) + int unit; +{ + register volatile struct qe_softc *sc = &qe_softc[unit]; + register volatile struct qe_ring *rp; + register int nrcv = 0; + int len, status1, status2; + int bufaddr; + + /* + * Traverse the receive ring looking for packets to pass back. + * The search is complete when we find a descriptor not in use. + * + * As in the transmit case the deqna doesn't honor it's own protocols + * so there exists the possibility that the device can beat us around + * the ring. The proper way to guard against this is to insure that + * there is always at least one invalid descriptor. We chose instead + * to make the ring large enough to minimize the problem. With a ring + * size of 4 we haven't been able to see the problem. To be safe we + * doubled that to 8. + * + */ + while (sc->rring[sc->rindex].qe_status1 == QE_NOTYET && nrcv < NRCV) { + /* + * We got an interrupt but did not find an input packet + * where we expected one to be, probably because the ring + * was overrun. + * We search forward to find a valid packet and start + * processing from there. If no valid packet is found it + * means we processed all the packets during a previous + * interrupt and that the QE_RCV_INT bit was set while + * we were processing one of these earlier packets. In + * this case we can safely ignore the interrupt (by dropping + * through the code below). + */ + sc->rindex = (sc->rindex + 1) % NRCV; + nrcv++; + } + if (nrcv && nrcv < NRCV) + log(LOG_ERR, "qe%d: ring overrun, resync'd by skipping %d\n", + unit, nrcv); + + for( ; sc->rring[sc->rindex].qe_status1 != QE_NOTYET ; sc->rindex = ++sc->rindex % NRCV ){ + rp = &sc->rring[sc->rindex]; + status1 = rp->qe_status1; + status2 = rp->qe_status2; + bzero((caddr_t)rp, sizeof(struct qe_ring)); + if( (status1 & QE_MASK) == QE_MASK ) + panic("qe: chained packet"); + len = ((status1 & QE_RBL_HI) | (status2 & QE_RBL_LO)) + 60; + sc->qe_if.if_ipackets++; + + if (status1 & QE_ERROR) { + if ((status1 & QE_RUNT) == 0) + sc->qe_if.if_ierrors++; + } else { + /* + * We don't process setup packets. + */ + if( !(status1 & QE_ESETUP) ) + qeread(sc, &sc->qe_ifr[sc->rindex], + len - sizeof(struct ether_header)); + } + /* + * Return the buffer to the ring + */ + bufaddr = (int)UBAI_ADDR(sc->qe_ifr[sc->rindex].ifrw_info); + rp->qe_buf_len = -((MAXPACKETSIZE)/2); + rp->qe_addr_lo = (short)bufaddr; + rp->qe_addr_hi = (short)((int)bufaddr >> 16); + rp->qe_flag = rp->qe_status1 = QE_NOTYET; + rp->qe_valid = 1; + } +} + +/* + * Process an ioctl request. + */ +qeioctl(ifp, cmd, data) + register struct ifnet *ifp; + int cmd; + caddr_t data; +{ + struct qe_softc *sc = &qe_softc[ifp->if_unit]; + struct ifaddr *ifa = (struct ifaddr *)data; + int s = splimp(), error = 0; + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + qeinit(ifp->if_unit); + switch(ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + arp_ifinit(&sc->qe_ac, ifa); + break; +#endif +#ifdef NS + case AF_NS: + { + register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); + + if (ns_nullhost(*ina)) + ina->x_host = *(union ns_host *)(sc->qe_addr); + else + qe_setaddr(ina->x_host.c_host, ifp->if_unit); + break; + } +#endif + } + break; + + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && + sc->qe_flags & QEF_RUNNING) { + ((volatile struct qedevice *) + (qeinfo[ifp->if_unit]->ui_addr))->qe_csr = QE_RESET; + sc->qe_flags &= ~QEF_RUNNING; + } else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == + IFF_RUNNING && (sc->qe_flags & QEF_RUNNING) == 0) + qerestart(sc); + break; + + default: + error = EINVAL; + + } + splx(s); + return (error); +} + +/* + * set ethernet address for unit + */ +qe_setaddr(physaddr, unit) + u_char *physaddr; + int unit; +{ + register volatile struct qe_softc *sc = &qe_softc[unit]; + register int i; + + for (i = 0; i < 6; i++) + sc->setup_pkt[i][1] = sc->qe_addr[i] = physaddr[i]; + sc->qe_flags |= QEF_SETADDR; + if (sc->qe_if.if_flags & IFF_RUNNING) + qesetup(sc); + qeinit(unit); +} + + +/* + * Initialize a ring descriptor with mbuf allocation side effects + */ +qeinitdesc(rp, addr, len) + register volatile struct qe_ring *rp; + caddr_t addr; /* mapped address */ + int len; +{ + /* + * clear the entire descriptor + */ + bzero((caddr_t)rp, sizeof(struct qe_ring)); + + if( len ) { + rp->qe_buf_len = -(len/2); + rp->qe_addr_lo = (short)((int)addr); + rp->qe_addr_hi = (short)((int)addr >> 16); + } +} +/* + * Build a setup packet - the physical address will already be present + * in first column. + */ +qesetup( sc ) + volatile struct qe_softc *sc; +{ + register i, j; + + /* + * Copy the target address to the rest of the entries in this row. + */ + for ( j = 0; j < 6 ; j++ ) + for ( i = 2 ; i < 8 ; i++ ) + sc->setup_pkt[j][i] = sc->setup_pkt[j][1]; + /* + * Duplicate the first half. + */ + bcopy((caddr_t)sc->setup_pkt[0], (caddr_t)sc->setup_pkt[8], 64); + /* + * Fill in the broadcast (and ISO multicast) address(es). + */ + for ( i = 0; i < 6 ; i++ ) { + sc->setup_pkt[i][2] = 0xff; +#ifdef ISO + sc->setup_pkt[i][3] = all_es_snpa[i]; + sc->setup_pkt[i][4] = all_is_snpa[i]; + sc->setup_pkt[i][5] = all_l1is_snpa[i]; + sc->setup_pkt[i][6] = all_l2is_snpa[i]; +#endif + } + sc->setupqueued++; +} + +/* + * Pass a packet to the higher levels. + * We deal with the trailer protocol here. + */ +qeread(sc, ifrw, len) + register volatile struct qe_softc *sc; + volatile struct ifrw *ifrw; + int len; +{ + struct ether_header *eh; + struct mbuf *m; + int s; + struct ifqueue *inq; + + /* + * Deal with trailer protocol: if type is INET trailer + * get true type from first 16-bit word past data. + * Remember that type was trailer by setting off. + */ + + eh = (struct ether_header *)ifrw->ifrw_addr; + if (len == 0) + return; + + /* + * Pull packet off interface. Off is nonzero if packet + * has trailing header; qeget will then force this header + * information to be at the front, but we still have to drop + * the type and length which are at the front of any trailer data. + */ + m = if_ubaget(&sc->qe_uba, ifrw, len, &sc->qe_if); +#ifdef notdef +if (m) { +*(((u_long *)m->m_data)+0), +*(((u_long *)m->m_data)+1), +*(((u_long *)m->m_data)+2), +*(((u_long *)m->m_data)+3) +); } +#endif + + if (m) + ether_input((struct ifnet *)&sc->qe_if, eh, m); +} + +/* + * Watchdog timeout routine. There is a condition in the hardware that + * causes the board to lock up under heavy load. This routine detects + * the hang up and restarts the device. + */ +void +qetimeout(unit) + int unit; +{ + register volatile struct qe_softc *sc; + + sc = &qe_softc[unit]; +#ifdef notdef + log(LOG_ERR, "qe%d: transmit timeout, restarted %d\n", + unit, sc->qe_restarts++); +#endif + qerestart(sc); +} +/* + * Restart for board lockup problem. + */ +qerestart(sc) + register volatile struct qe_softc *sc; +{ + register struct ifnet *ifp = (struct ifnet *)&sc->qe_if; + register volatile struct qedevice *addr = sc->addr; + register volatile struct qe_ring *rp; + register i; + + addr->qe_csr = QE_RESET; + addr->qe_csr &= ~QE_RESET; + qesetup( sc ); + for (i = 0, rp = sc->tring; i < NXMT; rp++, i++) { + rp->qe_flag = rp->qe_status1 = QE_NOTYET; + rp->qe_valid = 0; + } + sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0; + addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | + QE_RCV_INT | QE_ILOOP; + addr->qe_rcvlist_lo = (short)((int)sc->rringaddr); + addr->qe_rcvlist_hi = (short)((int)sc->rringaddr >> 16); + sc->qe_flags |= QEF_RUNNING; + qestart(ifp); +} + +qe_match(){ + printf("qe_match\n"); + return 0; +} + +void +qe_attach(){ + printf("qe_attach\n"); +} + +struct cfdriver qecd = + { 0,"qe",qe_match, qe_attach, DV_IFNET, sizeof(struct uba_driver) }; + +#endif diff --git a/sys/arch/vax/if/if_qereg.h b/sys/arch/vax/if/if_qereg.h new file mode 100644 index 00000000000..fe608daa42a --- /dev/null +++ b/sys/arch/vax/if/if_qereg.h @@ -0,0 +1,172 @@ +/* $NetBSD: if_qereg.h,v 1.1 1995/03/30 20:26:41 ragge Exp $ */ +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Digital Equipment Corp. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_qereg.h 7.3 (Berkeley) 6/28/90 + */ + +/* @(#)if_qereg.h 1.2 (ULTRIX) 1/3/85 */ + +/**************************************************************** + * * + * Licensed from Digital Equipment Corporation * + * Copyright (c) * + * Digital Equipment Corporation * + * Maynard, Massachusetts * + * 1985, 1986 * + * All rights reserved. * + * * + * The Information in this software is subject to change * + * without notice and should not be construed as a commitment * + * by Digital Equipment Corporation. Digital makes no * + * representations about the suitability of this software for * + * any purpose. It is supplied "As Is" without expressed or * + * implied warranty. * + * * + * If the Regents of the University of California or its * + * licensees modify the software in a manner creating * + * diriviative copyright rights, appropriate copyright * + * legends may be placed on the drivative work in addition * + * to that set forth above. * + * * + ****************************************************************/ +/* --------------------------------------------------------------------- + * Modification History + * + * 13 Feb. 84 -- rjl + * + * Initial version of driver. derived from IL driver. + * + * --------------------------------------------------------------------- + */ + +/* + * Digital Q-BUS to NI Adapter + */ +struct qedevice { + u_short qe_sta_addr[2]; /* Station address (actually 6 */ + u_short qe_rcvlist_lo; /* Receive list lo address */ + u_short qe_rcvlist_hi; /* Receive list hi address */ + u_short qe_xmtlist_lo; /* Transmit list lo address */ + u_short qe_xmtlist_hi; /* Transmit list hi address */ + u_short qe_vector; /* Interrupt vector */ + u_short qe_csr; /* Command and Status Register */ +}; + +/* + * Command and status bits (csr) + */ +#define QE_RCV_ENABLE 0x0001 /* Receiver enable */ +#define QE_RESET 0x0002 /* Software reset */ +#define QE_NEX_MEM_INT 0x0004 /* Non existant mem interrupt */ +#define QE_LOAD_ROM 0x0008 /* Load boot/diag from rom */ +#define QE_XL_INVALID 0x0010 /* Transmit list invalid */ +#define QE_RL_INVALID 0x0020 /* Receive list invalid */ +#define QE_INT_ENABLE 0x0040 /* Interrupt enable */ +#define QE_XMIT_INT 0x0080 /* Transmit interrupt */ +#define QE_ILOOP 0x0100 /* Internal loopback */ +#define QE_ELOOP 0x0200 /* External loopback */ +#define QE_STIM_ENABLE 0x0400 /* Sanity timer enable */ +#define QE_POWERUP 0x1000 /* Tranceiver power on */ +#define QE_CARRIER 0x2000 /* Carrier detect */ +#define QE_RCV_INT 0x8000 /* Receiver interrupt */ + +/* + * Transmit and receive ring discriptor --------------------------- + * + * The QNA uses the flag, status1 and the valid bit as a handshake/semiphore + * mechinism. + * + * The flag word is written on ( bits 15,15 set to 1 ) when it reads the + * descriptor. If the valid bit is set it considers the address to be valid. + * When it uses the buffer pointed to by the valid address it sets status word + * one. + */ +struct qe_ring { + u_short qe_flag; /* Buffer utilization flags */ + u_short qe_addr_hi:6, /* Hi order bits of buffer addr */ + qe_odd_begin:1, /* Odd byte begin and end (xmit)*/ + qe_odd_end:1, + qe_fill1:4, + qe_setup:1, /* Setup packet */ + qe_eomsg:1, /* End of message flag */ + qe_chain:1, /* Chain address instead of buf */ + qe_valid:1; /* Address field is valid */ + u_short qe_addr_lo; /* Low order bits of address */ + short qe_buf_len; /* Negative buffer length */ + u_short qe_status1; /* Status word one */ + u_short qe_status2; /* Status word two */ +}; + +/* + * Status word definations (receive) + * word1 + */ +#define QE_OVF 0x0001 /* Receiver overflow */ +#define QE_CRCERR 0x0002 /* CRC error */ +#define QE_FRAME 0x0004 /* Framing alignment error */ +#define QE_SHORT 0x0008 /* Packet size < 10 bytes */ +#define QE_RBL_HI 0x0700 /* Hi bits of receive len */ +#define QE_RUNT 0x0800 /* Runt packet */ +#define QE_DISCARD 0x1000 /* Discard the packet */ +#define QE_ESETUP 0x2000 /* Looped back setup or eloop */ +#define QE_ERROR 0x4000 /* Receiver error */ +#define QE_LASTNOT 0x8000 /* Not the last in the packet */ +/* word2 */ +#define QE_RBL_LO 0x00ff /* Low bits of receive len */ + +/* + * Status word definations (transmit) + * word1 + */ +#define QE_CCNT 0x00f0 /* Collision count this packet */ +#define QE_FAIL 0x0100 /* Heart beat check failure */ +#define QE_ABORT 0x0200 /* Transmission abort */ +#define QE_STE16 0x0400 /* Sanity timer default on */ +#define QE_NOCAR 0x0800 /* No carrier */ +#define QE_LOSS 0x1000 /* Loss of carrier while xmit */ +/* word2 */ +#define QE_TDR 0x3fff /* Time domain reflectometry */ + +/* + * General constant definations + */ +#define QEALLOC 0 /* Allocate an mbuf */ +#define QENOALLOC 1 /* No mbuf allocation */ +#define QEDEALLOC 2 /* Release an mbuf chain */ + +#define QE_NOTYET 0x8000 /* Descriptor not in use yet */ +#define QE_INUSE 0x4000 /* Descriptor being used by QNA */ +#define QE_MASK 0xc000 /* Lastnot/error/used mask */ diff --git a/sys/arch/vax/if/if_uba.c b/sys/arch/vax/if/if_uba.c new file mode 100644 index 00000000000..1ef5b3f8179 --- /dev/null +++ b/sys/arch/vax/if/if_uba.c @@ -0,0 +1,390 @@ +/* $NetBSD: if_uba.c,v 1.6 1995/04/11 06:19:09 mycroft Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_uba.c 7.16 (Berkeley) 12/16/90 + */ + +#include "sys/param.h" +#include "sys/systm.h" +#include "sys/malloc.h" +#include "sys/mbuf.h" +#include "sys/map.h" +#include "sys/buf.h" +#include "sys/socket.h" +#include "sys/syslog.h" + +#include "net/if.h" + +#include "vax/include/pte.h" +#include "vax/include/mtpr.h" +#include "if_uba.h" +#include "vax/include/vmparam.h" +#include "vax/uba/ubareg.h" +#include "vax/uba/ubavar.h" +#include "machine/macros.h" + +static if_ubaalloc(struct ifubinfo *, struct ifrw *, int); +static rcv_xmtbuf(struct ifxmt *); +static restor_xmtbuf(struct ifxmt *); + +/* + * Routines supporting UNIBUS network interfaces. + * + * TODO: + * Support interfaces using only one BDP statically. + */ + +/* + * Init UNIBUS for interface on uban whose headers of size hlen are to + * end on a page boundary. We allocate a UNIBUS map register for the page + * with the header, and nmr more UNIBUS map registers for i/o on the adapter, + * doing this once for each read and once for each write buffer. We also + * allocate page frames in the mbuffer pool for these pages. + */ +if_ubaminit(ifu, uban, hlen, nmr, ifr, nr, ifw, nw) + register struct ifubinfo *ifu; + int uban, hlen, nmr, nr, nw; + register struct ifrw *ifr; + register struct ifxmt *ifw; +{ + register caddr_t p; + caddr_t cp; + int i, nclbytes, off; + + if (hlen) + off = MCLBYTES - hlen; + else + off = 0; + nclbytes = roundup(nmr * NBPG, MCLBYTES); + if (hlen) + nclbytes += MCLBYTES; + if (ifr[0].ifrw_addr) + cp = ifr[0].ifrw_addr - off; + else { + cp = (caddr_t)malloc((u_long)((nr + nw) * nclbytes), M_DEVBUF, + M_NOWAIT); + if (cp == 0) + return (0); + p = cp; + for (i = 0; i < nr; i++) { + ifr[i].ifrw_addr = p + off; + p += nclbytes; + } + for (i = 0; i < nw; i++) { + ifw[i].ifw_base = p; + ifw[i].ifw_addr = p + off; + p += nclbytes; + } + ifu->iff_hlen = hlen; + ifu->iff_uban = uban; + ifu->iff_uba = uba_hd[uban].uh_uba; + ifu->iff_ubamr = uba_hd[uban].uh_mr; + } + for (i = 0; i < nr; i++) + if (if_ubaalloc(ifu, &ifr[i], nmr) == 0) { + nr = i; + nw = 0; + goto bad; + } + for (i = 0; i < nw; i++) + if (if_ubaalloc(ifu, &ifw[i].ifrw, nmr) == 0) { + nw = i; + goto bad; + } + while (--nw >= 0) { + for (i = 0; i < nmr; i++) + ifw[nw].ifw_wmap[i] = ifw[nw].ifw_mr[i]; + ifw[nw].ifw_xswapd = 0; + ifw[nw].ifw_flags = IFRW_W; + ifw[nw].ifw_nmr = nmr; + } + return (1); +bad: + while (--nw >= 0) + ubarelse(ifu->iff_uban, &ifw[nw].ifw_info); + while (--nr >= 0) + ubarelse(ifu->iff_uban, &ifr[nr].ifrw_info); + free(cp, M_DEVBUF); + ifr[0].ifrw_addr = 0; + return (0); +} + +/* + * Setup an ifrw structure by allocating UNIBUS map registers, + * possibly a buffered data path, and initializing the fields of + * the ifrw structure to minimize run-time overhead. + */ +static +if_ubaalloc(ifu, ifrw, nmr) + struct ifubinfo *ifu; + register struct ifrw *ifrw; + int nmr; +{ + register int info; + + info = + uballoc(ifu->iff_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->iff_hlen, + ifu->iff_flags); + if (info == 0) + return (0); + ifrw->ifrw_info = info; + ifrw->ifrw_bdp = UBAI_BDP(info); + ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT); + ifrw->ifrw_mr = &ifu->iff_ubamr[UBAI_MR(info) + (ifu->iff_hlen? 1 : 0)]; + return (1); +} + +/* + * Pull read data off a interface. + * Totlen is length of data, with local net header stripped. + * When full cluster sized units are present + * on the interface on cluster boundaries we can get them more + * easily by remapping, and take advantage of this here. + * Save a pointer to the interface structure and the total length, + * so that protocols can determine where incoming packets arrived. + * Note: we may be called to receive from a transmit buffer by some + * devices. In that case, we must force normal mapping of the buffer, + * so that the correct data will appear (only unibus maps are + * changed when remapping the transmit buffers). + */ +struct mbuf * +if_ubaget(ifu, ifr, totlen, ifp) + struct ifubinfo *ifu; + register struct ifrw *ifr; + register int totlen; + struct ifnet *ifp; +{ + struct mbuf *top, **mp; + register struct mbuf *m; + register caddr_t cp = ifr->ifrw_addr + ifu->iff_hlen, pp; + register int len; + top = 0; + mp = ⊤ + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0){ + return ((struct mbuf *)NULL); + } + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = totlen; + m->m_len = MHLEN; + + if (ifr->ifrw_flags & IFRW_W){ + rcv_xmtbuf((struct ifxmt *)ifr); + } + while (totlen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m_freem(top); + top = 0; + goto out; + } + m->m_len = MLEN; + } + len = totlen; + if (len >= MINCLSIZE) { + struct pte *cpte, *ppte; + int x, *ip, i; + + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0){ + goto nopage; + } + len = min(len, MCLBYTES); + m->m_len = len; + if (!claligned(cp)){ + goto copy; + } + /* + * Switch pages mapped to UNIBUS with new page pp, + * as quick form of copy. Remap UNIBUS and invalidate. + */ + pp = mtod(m, char *); + cpte = (struct pte *)kvtopte(cp); + ppte = (struct pte *)kvtopte(pp); + x = vax_btop(cp - ifr->ifrw_addr); + ip = (int *)&ifr->ifrw_mr[x]; + for (i = 0; i < MCLBYTES/NBPG; i++) { + struct pte t; + t = *ppte; *ppte++ = *cpte; *cpte = t; + *ip++ = cpte++->pg_pfn|ifr->ifrw_proto; + mtpr(cp,PR_TBIS); + cp += NBPG; + mtpr((caddr_t)pp,PR_TBIS); + pp += NBPG; + } + goto nocopy; + } +nopage: + if (len < m->m_len) { + /* + * Place initial small packet/header at end of mbuf. + */ + if (top == 0 && len + max_linkhdr <= m->m_len) + m->m_data += max_linkhdr; + m->m_len = len; + } else + len = m->m_len; +copy: + bcopy(cp, mtod(m, caddr_t), (unsigned)len); + cp += len; +nocopy: + *mp = m; + mp = &m->m_next; + totlen -= len; + } +out: + if (ifr->ifrw_flags & IFRW_W){ + restor_xmtbuf((struct ifxmt *)ifr); + } + return (top); +} + +/* + * Change the mapping on a transmit buffer so that if_ubaget may + * receive from that buffer. Copy data from any pages mapped to Unibus + * into the pages mapped to normal kernel virtual memory, so that + * they can be accessed and swapped as usual. We take advantage + * of the fact that clusters are placed on the xtofree list + * in inverse order, finding the last one. + */ +static +rcv_xmtbuf(ifw) + register struct ifxmt *ifw; +{ + register struct mbuf *m; + struct mbuf **mprev; + register i; + char *cp; + + while (i = ffs((long)ifw->ifw_xswapd)) { + cp = ifw->ifw_base + i * MCLBYTES; + i--; + ifw->ifw_xswapd &= ~(1<<i); + mprev = &ifw->ifw_xtofree; + for (m = ifw->ifw_xtofree; m && m->m_next; m = m->m_next) + mprev = &m->m_next; + if (m == NULL) + break; + bcopy(mtod(m, caddr_t), cp, MCLBYTES); + (void) m_free(m); + *mprev = NULL; + } + ifw->ifw_xswapd = 0; + for (i = 0; i < ifw->ifw_nmr; i++) + ifw->ifw_mr[i] = ifw->ifw_wmap[i]; +} + +/* + * Put a transmit buffer back together after doing an if_ubaget on it, + * which may have swapped pages. + */ +static +restor_xmtbuf(ifw) + register struct ifxmt *ifw; +{ + register i; + + for (i = 0; i < ifw->ifw_nmr; i++) + ifw->ifw_wmap[i] = ifw->ifw_mr[i]; +} + +/* + * Map a chain of mbufs onto a network interface + * in preparation for an i/o operation. + * The argument chain of mbufs includes the local network + * header which is copied to be in the mapped, aligned + * i/o space. + */ +if_ubaput(ifu, ifw, m) + struct ifubinfo *ifu; + register struct ifxmt *ifw; + register struct mbuf *m; +{ + register struct mbuf *mp; + register caddr_t cp, dp; + register int i; + int xswapd = 0; + int x, cc, t; + + cp = ifw->ifw_addr; + while (m) { + dp = mtod(m, char *); + if (claligned(cp) && claligned(dp) && + (m->m_len == MCLBYTES || m->m_next == (struct mbuf *)0)) { + struct pte *pte; + int *ip; + + pte = (struct pte *)kvtopte(dp); + x = vax_btop(cp - ifw->ifw_addr); + ip = (int *)&ifw->ifw_mr[x]; + for (i = 0; i < MCLBYTES/NBPG; i++) + *ip++ = ifw->ifw_proto | pte++->pg_pfn; + xswapd |= 1 << (x>>(MCLSHIFT-PGSHIFT)); + mp = m->m_next; + m->m_next = ifw->ifw_xtofree; + ifw->ifw_xtofree = m; + cp += m->m_len; + } else { + bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len); + cp += m->m_len; + MFREE(m, mp); + } + m = mp; + } + + /* + * Xswapd is the set of clusters we just mapped out. Ifu->iff_xswapd + * is the set of clusters mapped out from before. We compute + * the number of clusters involved in this operation in x. + * Clusters mapped out before and involved in this operation + * should be unmapped so original pages will be accessed by the device. + */ + cc = cp - ifw->ifw_addr; + x = ((cc - ifu->iff_hlen) + MCLBYTES - 1) >> MCLSHIFT; + ifw->ifw_xswapd &= ~xswapd; + while (i = ffs((long)ifw->ifw_xswapd)) { + i--; + if (i >= x) + break; + ifw->ifw_xswapd &= ~(1<<i); + i *= MCLBYTES/NBPG; + for (t = 0; t < MCLBYTES/NBPG; t++) { + ifw->ifw_mr[i] = ifw->ifw_wmap[i]; + i++; + } + } + ifw->ifw_xswapd |= xswapd; + return (cc); +} diff --git a/sys/arch/vax/if/if_uba.h b/sys/arch/vax/if/if_uba.h new file mode 100644 index 00000000000..b1d6a2a203f --- /dev/null +++ b/sys/arch/vax/if/if_uba.h @@ -0,0 +1,136 @@ +/* $NetBSD: if_uba.h,v 1.3 1995/05/11 16:53:12 jtc Exp $ */ + +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_uba.h 7.4 (Berkeley) 6/28/90 + */ + +/* + * Structure and routine definitions + * for UNIBUS network interfaces. + */ + +#define IF_MAXNUBAMR 10 +/* + * Each interface has structures giving information + * about UNIBUS resources held by the interface + * for each send and receive buffer. + * + * We hold IF_NUBAMR map registers for datagram data, starting + * at ifr_mr. Map register ifr_mr[-1] maps the local network header + * ending on the page boundary. Bdp's are reserved for read and for + * write, given by ifr_bdp. The prototype of the map register for + * read and for write is saved in ifr_proto. + * + * When write transfers are not full pages on page boundaries we just + * copy the data into the pages mapped on the UNIBUS and start the + * transfer. If a write transfer is of a (1024 byte) page on a page + * boundary, we swap in UNIBUS pte's to reference the pages, and then + * remap the initial pages (from ifu_wmap) when the transfer completes. + * + * When read transfers give whole pages of data to be input, we + * allocate page frames from a network page list and trade them + * with the pages already containing the data, mapping the allocated + * pages to replace the input pages for the next UNIBUS data input. + */ + +/* + * Information per interface. + */ +struct ifubinfo { + short iff_uban; /* uba number */ + short iff_hlen; /* local net header length */ + struct uba_regs *iff_uba; /* uba adaptor regs, in vm */ + struct pte *iff_ubamr; /* uba map regs, in vm */ + short iff_flags; /* used during uballoc's */ +}; + +/* + * Information per buffer. + */ +struct ifrw { + caddr_t ifrw_addr; /* virt addr of header */ + short ifrw_bdp; /* unibus bdp */ + short ifrw_flags; /* type, etc. */ +#define IFRW_W 0x01 /* is a transmit buffer */ + int ifrw_info; /* value from ubaalloc */ + int ifrw_proto; /* map register prototype */ + struct pte *ifrw_mr; /* base of map registers */ +}; + +/* + * Information per transmit buffer, including the above. + */ +struct ifxmt { + struct ifrw ifrw; + caddr_t ifw_base; /* virt addr of buffer */ + struct pte ifw_wmap[IF_MAXNUBAMR]; /* base pages for output */ + struct mbuf *ifw_xtofree; /* pages being dma'd out */ + short ifw_xswapd; /* mask of clusters swapped */ + short ifw_nmr; /* number of entries in wmap */ +}; +#define ifw_addr ifrw.ifrw_addr +#define ifw_bdp ifrw.ifrw_bdp +#define ifw_flags ifrw.ifrw_flags +#define ifw_info ifrw.ifrw_info +#define ifw_proto ifrw.ifrw_proto +#define ifw_mr ifrw.ifrw_mr + +/* + * Most interfaces have a single receive and a single transmit buffer, + * and use struct ifuba to store all of the unibus information. + */ +struct ifuba { + struct ifubinfo ifu_info; + struct ifrw ifu_r; + struct ifxmt ifu_xmt; +}; + +#define ifu_uban ifu_info.iff_uban +#define ifu_hlen ifu_info.iff_hlen +#define ifu_uba ifu_info.iff_uba +#define ifu_ubamr ifu_info.iff_ubamr +#define ifu_flags ifu_info.iff_flags +#define ifu_w ifu_xmt.ifrw +#define ifu_xtofree ifu_xmt.ifw_xtofree + +#ifdef _KERNEL +#define if_ubainit(ifuba, uban, hlen, nmr) \ + if_ubaminit(&(ifuba)->ifu_info, uban, hlen, nmr, \ + &(ifuba)->ifu_r, 1, &(ifuba)->ifu_xmt, 1) +#define if_rubaget(ifu, totlen, off0, ifp) \ + if_ubaget(&(ifu)->ifu_info, &(ifu)->ifu_r, totlen, off0, ifp) +#define if_wubaput(ifu, m) \ + if_ubaput(&(ifu)->ifu_info, &(ifu)->ifu_xmt, m) +struct mbuf *if_ubaget(); +#endif |