📄 if_dmc.c
字号:
/* * 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_dmc.c 7.10 (Berkeley) 12/16/90 */#include "dmc.h"#if NDMC > 0/* * DMC11 device driver, internet version * * Bill Nesheim * Cornell University * * Lou Salkind * New York University *//* #define DEBUG /* for base table dump on fatal error */#include "../include/pte.h"#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 "if_uba.h"#include "if_dmc.h"#include "../uba/ubareg.h"#include "../uba/ubavar.h"/* * output timeout value, sec.; should depend on line speed. */int dmc_timeout = 20;/* * Driver information for auto-configuration stuff. */int dmcprobe(), dmcattach(), dmcinit(), dmcioctl();int dmcoutput(), dmcreset(), dmctimeout();struct uba_device *dmcinfo[NDMC];u_short dmcstd[] = { 0 };struct uba_driver dmcdriver = { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };#define NRCV 7#define NXMT 3 #define NCMDS (NRCV+NXMT+4) /* size of command queue */#define printd if(dmcdebug)printfint dmcdebug = 0;/* error reporting intervals */#define DMC_RPNBFS 50#define DMC_RPDSC 1#define DMC_RPTMO 10#define DMC_RPDCK 10struct dmc_command { char qp_cmd; /* command */ short qp_ubaddr; /* buffer address */ short qp_cc; /* character count || XMEM */ struct dmc_command *qp_next; /* next command on queue */};struct dmcbufs { int ubinfo; /* from uballoc */ short cc; /* buffer size */ short flags; /* access control */};#define DBUF_OURS 0 /* buffer is available */#define DBUF_DMCS 1 /* buffer claimed by somebody */#define DBUF_XMIT 4 /* transmit buffer */#define DBUF_RCV 8 /* receive buffer *//* * DMC 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 dmc_softc { struct ifnet sc_if; /* network-visible interface */ short sc_oused; /* output buffers currently in use */ short sc_iused; /* input buffers given to DMC */ short sc_flag; /* flags */ int sc_ubinfo; /* UBA mapping info for base table */ int sc_errors[4]; /* non-fatal error counters */#define sc_datck sc_errors[0]#define sc_timeo sc_errors[1]#define sc_nobuf sc_errors[2]#define sc_disc sc_errors[3] struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */ struct dmcbufs 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 dmc_command sc_cmdbuf[NCMDS]; struct dmc_command *sc_qhead; /* head of command queue */ struct dmc_command *sc_qtail; /* tail of command queue */ struct dmc_command *sc_qactive; /* command in progress */ struct dmc_command *sc_qfreeh; /* head of list of free cmd buffers */ struct dmc_command *sc_qfreet; /* tail of list of free cmd buffers */ /* end command queue stuff */} dmc_softc[NDMC];/* flags */#define DMC_RUNNING 0x01 /* device initialized */#define DMC_BMAPPED 0x02 /* base table mapped */#define DMC_RESTART 0x04 /* software restart in progress */#define DMC_ONLINE 0x08 /* device running (had a RDYO) */struct dmc_base { short d_base[128]; /* DMC base table */} dmc_base[NDMC];/* queue manipulation macros */#define QUEUE_AT_HEAD(qp, head, tail) \ (qp)->qp_next = (head); \ (head) = (qp); \ if ((tail) == (struct dmc_command *) 0) \ (tail) = (head) #define QUEUE_AT_TAIL(qp, head, tail) \ if ((tail)) \ (tail)->qp_next = (qp); \ else \ (head) = (qp); \ (qp)->qp_next = (struct dmc_command *) 0; \ (tail) = (qp)#define DEQUEUE(head, tail) \ (head) = (head)->qp_next;\ if ((head) == (struct dmc_command *) 0)\ (tail) = (head)dmcprobe(reg) caddr_t reg;{ register int br, cvec; register struct dmcdevice *addr = (struct dmcdevice *)reg; register int i;#ifdef lint br = 0; cvec = br; br = cvec; dmcrint(0); dmcxint(0);#endif addr->bsel1 = DMC_MCLR; for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ; if ((addr->bsel1 & DMC_RUN) == 0) { printf("dmcprobe: can't start device\n" ); return (0); } addr->bsel0 = DMC_RQI|DMC_IEI; /* let's be paranoid */ addr->bsel0 |= DMC_RQI|DMC_IEI; DELAY(1000000); addr->bsel1 = DMC_MCLR; for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ; return (1);}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */dmcattach(ui) register struct uba_device *ui;{ register struct dmc_softc *sc = &dmc_softc[ui->ui_unit]; sc->sc_if.if_unit = ui->ui_unit; sc->sc_if.if_name = "dmc"; sc->sc_if.if_mtu = DMCMTU; sc->sc_if.if_init = dmcinit; sc->sc_if.if_output = dmcoutput; sc->sc_if.if_ioctl = dmcioctl; sc->sc_if.if_reset = dmcreset; sc->sc_if.if_watchdog = dmctimeout; 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. */dmcreset(unit, uban) int unit, uban;{ register struct uba_device *ui; register struct dmc_softc *sc = &dmc_softc[unit]; if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) return; printf(" dmc%d", unit); sc->sc_flag = 0; sc->sc_if.if_flags &= ~IFF_RUNNING; dmcinit(unit);}/* * Initialization of interface; reinitialize UNIBUS usage. */dmcinit(unit) int unit;{ register struct dmc_softc *sc = &dmc_softc[unit]; register struct uba_device *ui = dmcinfo[unit]; register struct dmcdevice *addr; register struct ifnet *ifp = &sc->sc_if; register struct ifrw *ifrw; register struct ifxmt *ifxp; register struct dmcbufs *rp; register struct dmc_command *qp; struct ifaddr *ifa; int base; int s; addr = (struct dmcdevice *)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_dstaddr->sa_family) break; if (ifa == (struct ifaddr *) 0) return; if ((addr->bsel1&DMC_RUN) == 0) { printf("dmcinit: DMC not running\n"); ifp->if_flags &= ~IFF_UP; return; } /* map base table */ if ((sc->sc_flag & DMC_BMAPPED) == 0) { sc->sc_ubinfo = uballoc(ui->ui_ubanum, (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0); sc->sc_flag |= DMC_BMAPPED; } /* 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 dmc_header), (int)btoc(DMCMTU), sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) { printf("dmc%d: can't allocate uba resources\n", unit); ifp->if_flags &= ~IFF_UP; return; } ifp->if_flags |= IFF_RUNNING; } sc->sc_flag &= ~DMC_ONLINE; sc->sc_flag |= DMC_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 = DMCMTU + sizeof (struct dmc_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 dmc_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); } /* base in */ base = UBAI_ADDR(sc->sc_ubinfo); dmcload(sc, DMC_BASEI, (u_short)base, (base>>2) & DMC_XMEM); /* specify half duplex operation, flags tell if primary */ /* or secondary station */ if (ui->ui_flags == 0) /* use DDCMP mode in full duplex */ dmcload(sc, DMC_CNTLI, 0, 0); else if (ui->ui_flags == 1) /* use MAINTENENCE mode */ dmcload(sc, DMC_CNTLI, 0, DMC_MAINT ); else if (ui->ui_flags == 2) /* use DDCMP half duplex as primary station */ dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX); else if (ui->ui_flags == 3) /* use DDCMP half duplex as secondary station */ dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC); /* enable operation done interrupts */ while ((addr->bsel2 & DMC_IEO) == 0) addr->bsel2 |= DMC_IEO; s = spl5(); /* queue first NRCV buffers for DMC to fill */ for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { rp->flags |= DBUF_DMCS; dmcload(sc, DMC_READ, rp->ubinfo, (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc)); sc->sc_iused++; } splx(s);}/* * 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 */dmcstart(unit) int unit;{ register struct dmc_softc *sc = &dmc_softc[unit]; struct mbuf *m; register struct dmcbufs *rp; register int n; /* * Dequeue up to NXMT requests and map them to the UNIBUS. * If no more requests, or no dmc buffers available, just return. */ n = 0; for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { /* find an available buffer */ if ((rp->flags & DBUF_DMCS) == 0) { IF_DEQUEUE(&sc->sc_if.if_snd, m); if (m == 0) return; /* mark it dmcs */ rp->flags |= (DBUF_DMCS); /* * Have request mapped to UNIBUS for transmission * and start the output. */ rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); rp->cc &= DMC_CCOUNT; if (++sc->sc_oused == 1) sc->sc_if.if_timer = dmc_timeout; dmcload(sc, DMC_WRITE, rp->ubinfo, rp->cc | ((rp->ubinfo>>2)&DMC_XMEM)); } n++; }}/* * Utility routine to load the DMC device registers. */dmcload(sc, type, w0, w1) register struct dmc_softc *sc; int type; u_short w0, w1;{ register struct dmcdevice *addr; register int unit, sps; register struct dmc_command *qp; unit = sc - dmc_softc; addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; sps = spl5(); /* grab a command buffer from the free list */ if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0) panic("dmc command queue overflow"); DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); /* fill in requested info */ qp->qp_cmd = (type | DMC_RQI); qp->qp_ubaddr = w0; qp->qp_cc = w1; if (sc->sc_qactive) { /* command in progress */ if (type == DMC_READ) { 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 = qp->qp_cmd; dmcrint(unit); } splx(sps);}/* * DMC interface receiver interrupt. * Ready to accept another command, * pull one off the command queue. */dmcrint(unit) int unit;{ register struct dmc_softc *sc; register struct dmcdevice *addr; register struct dmc_command *qp; register int n; addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; sc = &dmc_softc[unit]; if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -