📄 if_dmv.c
字号:
/* * Copyright (c) 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_dmv.c 7.12 (Berkeley) 12/16/90 *//* * DMV-11 Driver * * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode * * Written by Bob Kridle of Mt Xinu * starting from if_dmc.c version 6.12 dated 4/23/86 */#include "dmv.h"#if NDMV > 0#include "sys/param.h"#include "sys/systm.h"#include "sys/mbuf.h"#include "sys/buf.h"#include "sys/ioctl.h" /* must precede tty.h */#include "sys/tty.h"#include "sys/protosw.h"#include "sys/socket.h"#include "sys/syslog.h"#include "sys/vmmac.h"#include "sys/errno.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"#endif#include "../include/cpu.h"#include "../include/mtpr.h"#include "../include/pte.h"#include "../uba/ubareg.h"#include "../uba/ubavar.h"#include "if_uba.h"#include "if_dmv.h"int dmv_timeout = 8; /* timeout value *//* * Driver information for auto-configuration stuff. */int dmvprobe(), dmvattach(), dmvinit(), dmvioctl();int dmvoutput(), dmvreset(), dmvtimeout();struct uba_device *dmvinfo[NDMV];u_short dmvstd[] = { 0 };struct uba_driver dmvdriver = { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo };/* * Don't really know how many buffers/commands can be queued to a DMV-11. * Manual doesn't say... Perhaps we can look at a DEC driver some day. * These numbers ame from DMC/DMR driver. */#define NRCV 5#define NXMT 3 #define NCMDS (NRCV+NXMT+4) /* size of command queue */#ifdef DEBUG#define printd(f) if (sc->sc_if.if_flags & IFF_DEBUG) \ printf("DMVDEBUG: dmv%d: ", unit), printf(f)#else#define printd(f) /* nil */#endif/* error reporting intervals */#define DMV_RPRTE 1#define DMV_RPTTE 1#define DMV_RPSTE 1#define DMV_RPNXM 1#define DMV_RPMODD 1#define DMV_RPQOVF 1#define DMV_RPCXRL 1/* number of errors to accept before trying a reset */#define DMV_RPUNKNOWN 10struct dmv_command { u_char qp_mask; /* Which registers to set up */#define QP_TRIB 0x01#define QP_SEL4 0x02#define QP_SEL6 0x04#define QP_SEL10 0x08 u_char qp_cmd; u_char qp_tributary; u_short qp_sel4; u_short qp_sel6; u_short qp_sel10; struct dmv_command *qp_next; /* next command on queue */};#define qp_lowbufaddr qp_struct dmvbufs { int ubinfo; /* from uballoc */ short cc; /* buffer size */ short flags; /* access control */};#define DBUF_OURS 0 /* buffer is available */#define DBUF_DMVS 1 /* buffer claimed by somebody */#define DBUF_XMIT 4 /* transmit buffer */#define DBUF_RCV 8 /* receive buffer *//* * DMV software status per interface. * * Each interface is referenced by a network interface structure, * sc_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 set of 7 UBA interface structures * for each, which * contain 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 dmv_softc { struct ifnet sc_if; /* network-visible interface */ short sc_oused; /* output buffers currently in use */ short sc_iused; /* input buffers given to DMV */ short sc_flag; /* flags */ short sc_ipl; /* interrupt priority */ int sc_ubinfo; /* UBA mapping info for base table */ int sc_errors[8]; /* error counters */#define sc_rte sc_errors[0] /* receive threshhold error */#define sc_xte sc_errors[1] /* xmit threshhold error */#define sc_ste sc_errors[2] /* select threshhold error */#define sc_nxm sc_errors[3] /* non-existant memory */#define sc_modd sc_errors[4] /* modem disconnect */#define sc_qovf sc_errors[5] /* command/response queue overflow */#define sc_cxrl sc_errors[6] /* carrier loss */#define sc_unknown sc_errors[7] /* other errors - look in DMV manual */ struct dmvbufs sc_rbufs[NRCV]; /* receive buffer info */ struct dmvbufs sc_xbufs[NXMT]; /* transmit buffer info */ struct ifubinfo sc_ifuba; /* UNIBUS resources */ struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ /* command queue stuff */ struct dmv_command sc_cmdbuf[NCMDS]; struct dmv_command *sc_qhead; /* head of command queue */ struct dmv_command *sc_qtail; /* tail of command queue */ struct dmv_command *sc_qactive; /* command in progress */ struct dmv_command *sc_qfreeh; /* head of list of free cmd buffers */ struct dmv_command *sc_qfreet; /* tail of list of free cmd buffers */ /* end command queue stuff */} dmv_softc[NDMV];/* flags */#define DMV_RESTART 0x01 /* software restart in progress */#define DMV_ONLINE 0x02 /* device managed to transmit */#define DMV_RUNNING 0x04 /* device initialized *//* queue manipulation macros */#define QUEUE_AT_HEAD(qp, head, tail) \ (qp)->qp_next = (head); \ (head) = (qp); \ if ((tail) == (struct dmv_command *) 0) \ (tail) = (head) #define QUEUE_AT_TAIL(qp, head, tail) \ if ((tail)) \ (tail)->qp_next = (qp); \ else \ (head) = (qp); \ (qp)->qp_next = (struct dmv_command *) 0; \ (tail) = (qp)#define DEQUEUE(head, tail) \ (head) = (head)->qp_next;\ if ((head) == (struct dmv_command *) 0)\ (tail) = (head)dmvprobe(reg, ui) caddr_t reg; struct uba_device *ui;{ register int br, cvec; register struct dmvdevice *addr = (struct dmvdevice *)reg; register int i;#ifdef lint br = 0; cvec = br; br = cvec; dmvrint(0); dmvxint(0);#endif addr->bsel1 = DMV_MCLR; for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) ; if ((addr->bsel1 & DMV_RUN) == 0) { printf("dmvprobe: can't start device\n" ); return (0); } if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) { printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n", addr->bsel4, addr->bsel6); return (0); } (void) spl6(); addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO; DELAY(1000000); dmv_softc[ui->ui_unit].sc_ipl = br = qbgetpri(); addr->bsel1 = DMV_MCLR; for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) ; return (sizeof(struct dmvdevice));}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */dmvattach(ui) register struct uba_device *ui;{ register struct dmv_softc *sc = &dmv_softc[ui->ui_unit]; sc->sc_if.if_unit = ui->ui_unit; sc->sc_if.if_name = "dmv"; sc->sc_if.if_mtu = DMVMTU; sc->sc_if.if_init = dmvinit; sc->sc_if.if_output = dmvoutput; sc->sc_if.if_ioctl = dmvioctl; sc->sc_if.if_reset = dmvreset; sc->sc_if.if_watchdog = dmvtimeout; sc->sc_if.if_flags = IFF_POINTOPOINT; sc->sc_ifuba.iff_flags = UBA_CANTWAIT; if_attach(&sc->sc_if);}/* * Reset of interface after UNIBUS reset. * If interface is on specified UBA, reset its state. */dmvreset(unit, uban) int unit, uban;{ register struct uba_device *ui; register struct dmv_softc *sc = &dmv_softc[unit]; if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) return; printf(" dmv%d", unit); sc->sc_flag = 0; sc->sc_if.if_flags &= ~IFF_RUNNING; dmvinit(unit);}/* * Initialization of interface; reinitialize UNIBUS usage. */dmvinit(unit) int unit;{ register struct dmv_softc *sc = &dmv_softc[unit]; register struct uba_device *ui = dmvinfo[unit]; register struct dmvdevice *addr; register struct ifnet *ifp = &sc->sc_if; register struct ifrw *ifrw; register struct ifxmt *ifxp; register struct dmvbufs *rp; register struct dmv_command *qp; struct ifaddr *ifa; int base; int s; addr = (struct dmvdevice *)ui->ui_addr; /* * Check to see that an address has been set * (both local and destination for an address family). */ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) if (ifa->ifa_addr->sa_family && ifa->ifa_addr->sa_family != AF_LINK && ifa->ifa_dstaddr && ifa->ifa_dstaddr->sa_family) break; if (ifa == (struct ifaddr *) 0) return; if ((addr->bsel1&DMV_RUN) == 0) { log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit); ifp->if_flags &= ~IFF_UP; return; } printd(("dmvinit\n")); /* initialize UNIBUS resources */ sc->sc_iused = sc->sc_oused = 0; if ((ifp->if_flags & IFF_RUNNING) == 0) { if (if_ubaminit( &sc->sc_ifuba, ui->ui_ubanum, sizeof(struct dmv_header), (int)btoc(DMVMTU), sc->sc_ifr, NRCV, sc->sc_ifw, NXMT ) == 0) { log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit); ifp->if_flags &= ~IFF_UP; return; } ifp->if_flags |= IFF_RUNNING; } /* * Limit packets enqueued until we see if we're on the air. */ ifp->if_snd.ifq_maxlen = 3; /* initialize buffer pool */ /* receives */ ifrw = &sc->sc_ifr[0]; for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); rp->cc = DMVMTU + sizeof (struct dmv_header); rp->flags = DBUF_OURS|DBUF_RCV; ifrw++; } /* transmits */ ifxp = &sc->sc_ifw[0]; for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { rp->ubinfo = UBAI_ADDR(ifxp->ifw_info); rp->cc = 0; rp->flags = DBUF_OURS|DBUF_XMIT; ifxp++; } /* set up command queues */ sc->sc_qfreeh = sc->sc_qfreet = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = (struct dmv_command *)0; /* set up free command buffer list */ for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); } if(sc->sc_flag & DMV_RUNNING) dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0); else dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0); dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0); sc->sc_flag |= (DMV_RESTART|DMV_RUNNING); sc->sc_flag &= ~DMV_ONLINE; addr->bsel0 |= DMV_IEO;}/* * Start output on interface. Get another datagram * to send from the interface queue and map it to * the interface before starting output. * * Must be called at spl 5 */dmvstart(dev) dev_t dev;{ int unit = minor(dev); register struct dmv_softc *sc = &dmv_softc[unit]; struct mbuf *m; register struct dmvbufs *rp; register int n; /* * Dequeue up to NXMT requests and map them to the UNIBUS. * If no more requests, or no dmv buffers available, just return. */ printd(("dmvstart\n")); n = 0; for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { /* find an available buffer */ if ((rp->flags & DBUF_DMVS) == 0) { IF_DEQUEUE(&sc->sc_if.if_snd, m); if (m == 0) return; /* mark it dmvs */ rp->flags |= (DBUF_DMVS); /* * Have request mapped to UNIBUS for transmission * and start the output. */ rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); if (++sc->sc_oused == 1) sc->sc_if.if_timer = dmv_timeout; dmvload( sc, DMV_BACCX, QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 1, rp->ubinfo, (rp->ubinfo>>16)&0x3f, rp->cc ); } n++; }}/* * Utility routine to load the DMV device registers. */dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10) register struct dmv_softc *sc; u_char cmd, tributary, mask; u_short sel4, sel6, sel10;{ register struct dmvdevice *addr; register int unit, sps; register struct dmv_command *qp; unit = sc - dmv_softc; printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n", (unsigned) cmd, (unsigned) mask, (unsigned) tributary, (unsigned) sel4, (unsigned) sel6, (unsigned) sel10 )); addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; sps = spl5(); /* grab a command buffer from the free list */ if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0) panic("dmv command queue overflow"); DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); /* fill in requested info */ qp->qp_cmd = cmd; qp->qp_mask = mask; qp->qp_tributary = tributary; qp->qp_sel4 = sel4; qp->qp_sel6 = sel6; qp->qp_sel10 = sel10; if (sc->sc_qactive) { /* command in progress */ if (cmd == DMV_BACCR) { /* supply read buffers first */ QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); } else { QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); } } else { /* command port free */ sc->sc_qactive = qp; addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); } splx(sps);}/* * DMV interface input interrupt. * Ready to accept another command, * pull one off the command queue. */dmvrint(unit) int unit;{ register struct dmv_softc *sc; register struct dmvdevice *addr; register struct dmv_command *qp; register int n; addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; sc = &dmv_softc[unit]; splx(sc->sc_ipl); printd(("dmvrint\n")); if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) { log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit); return; } while (addr->bsel2&DMV_RDI) { if(qp->qp_mask&QP_SEL4) addr->wsel4 = qp->qp_sel4; if(qp->qp_mask&QP_SEL6) addr->wsel6 = qp->qp_sel6; if(qp->qp_mask&QP_SEL10) { addr->wsel10 = qp->qp_sel10; qp->qp_cmd |= DMV_22BIT; } if(qp->qp_mask&QP_TRIB) addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8); else addr->bsel2 = qp->qp_cmd; QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0) break; qp = sc->sc_qactive; DEQUEUE(sc->sc_qhead, sc->sc_qtail); if (addr->bsel2&DMV_RDO) break; } if (!sc->sc_qactive) { if(addr->bsel2&DMV_RDI) { /* clear RQI prior to last command per DMV manual */ addr->bsel0 &= ~DMV_RQI; addr->wsel6 = DMV_NOP; addr->bsel2 = DMV_CNTRLI;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -