📄 if_ex.c
字号:
/* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Excelan Inc. * * 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_ex.c 7.9 (Berkeley) 12/16/90 */#include "ex.h"#if NEX > 0/* * Excelan EXOS 204 Interface * * George Powers * Excelan Inc. */#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/syslog.h"#include "sys/errno.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/pte.h"#include "../include/cpu.h"#include "../include/mtpr.h"#include "if_exreg.h"#include "if_uba.h"#include "../uba/ubareg.h"#include "../uba/ubavar.h"/* #define DEBUG /* check for "impossible" events */#define NH2X 4 /* a sufficient number is critical */#define NX2H 4 /* this is pretty arbitrary */#define EXWATCHINTVL 10 /* call exwatch() every 10 seconds */int exprobe(), exattach(), excdint();struct uba_device *exinfo[NEX];u_short exstd[] = { 0 };struct uba_driver exdriver = { exprobe, 0, exattach, 0, exstd, "ex", exinfo };int exinit(),exstart(),ether_output(),exioctl(),exreset(),exwatch();struct ex_msg *exgetcbuf();/* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * xs_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 ex_softc { struct arpcom xs_ac; /* Ethernet common part */#define xs_if xs_ac.ac_if /* network-visible interface */#define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */#ifdef DEBUG int xs_wait;#endif struct ifuba xs_ifuba; /* UNIBUS resources */ int xs_flags; /* private flags */#define EX_XPENDING 1 /* xmit rqst pending on EXOS */#define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */#define EX_RUNNING (1<<2) /* board is running */#define EX_SETADDR (1<<3) /* physaddr has been changed */ struct ex_msg *xs_h2xnext; /* host pointer to request queue */ struct ex_msg *xs_x2hnext; /* host pointer to reply queue */ int xs_ubaddr; /* map info for structs below */#define UNIADDR(x) ((u_long)(x)&0x3FFFF)#define P_UNIADDR(x) ((u_long)(x)&0x3FFF0) /* the following structures are always mapped in */ u_short xs_h2xhdr; /* EXOS's request queue header */ u_short xs_x2hhdr; /* EXOS's reply queue header */ struct ex_msg xs_h2xent[NH2X]; /* request msg buffers */ struct ex_msg xs_x2hent[NX2H]; /* reply msg buffers */ struct confmsg xs_cm; /* configuration message */ struct stat_array xs_xsa; /* EXOS writes stats here */ /* end mapped area */#define INCORE_BASE(p) ((caddr_t)((u_long)(&(p)->xs_h2xhdr) & 0xFFFFFFF0))#define RVAL_OFF(unit, n) \ ((caddr_t)(&(ex_softc[unit].n)) - INCORE_BASE(&ex_softc[unit]))#define LVAL_OFF(unit, n) \ ((caddr_t)(ex_softc[unit].n) - INCORE_BASE(&ex_softc[unit]))#define H2XHDR_OFFSET(unit) RVAL_OFF(unit, xs_h2xhdr)#define X2HHDR_OFFSET(unit) RVAL_OFF(unit, xs_x2hhdr)#define H2XENT_OFFSET(unit) LVAL_OFF(unit, xs_h2xent)#define X2HENT_OFFSET(unit) LVAL_OFF(unit, xs_x2hent)#define CM_OFFSET(unit) RVAL_OFF(unit, xs_cm)#define SA_OFFSET(unit) RVAL_OFF(unit, xs_xsa)#define INCORE_SIZE(unit) RVAL_OFF(unit, xs_end) int xs_end; /* place holder */} ex_softc[NEX];/* * The following structure is a kludge to store a cvec value * between the time exprobe is called, and exconfig. */struct ex_cvecs { struct exdevice *xc_csraddr; int xc_cvec;}ex_cvecs[NEX];int ex_ncall = 0; /* counts calls to exprobe */exprobe(reg) caddr_t reg;{ register int br, cvec; /* r11, r10 value-result */ register struct exdevice *addr = (struct exdevice *)reg; register i; /* * We program the EXOS interrupt vector, like dmf device. */ br = 0x15; cvec = (uba_hd[numuba].uh_lastiv -= 4); ex_cvecs[ex_ncall].xc_csraddr = addr; ex_cvecs[ex_ncall].xc_cvec = cvec; /* * Reset EXOS and run self-test (guaranteed to * complete within 2 seconds). */ addr->xd_porta = EX_RESET; i = 2000; while (((addr->xd_portb & EX_TESTOK) == 0) && --i) DELAY(1000); if ((addr->xd_portb & EX_TESTOK) == 0) { printf("ex: self-test failed\n"); return 0; }#ifdef lint br = br; excdint(0);#endif ex_ncall++; return (sizeof(struct exdevice));}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. Board is temporarily configured and issues * a NET_ADDRS command, only to get the Ethernet address. */exattach(ui) register struct uba_device *ui;{ register struct ex_softc *xs = &ex_softc[ui->ui_unit]; register struct ifnet *ifp = &xs->xs_if; register struct exdevice *addr = (struct exdevice *)ui->ui_addr; register struct ex_msg *bp; int unit = ui->ui_unit; ifp->if_unit = ui->ui_unit; ifp->if_name = "ex"; ifp->if_mtu = ETHERMTU; /* * Temporarily map queues in order to configure EXOS */ xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), INCORE_SIZE(unit), 0); exconfig(ui, 0); /* without interrupts */ if (xs->xs_cm.cm_cc) goto badconf; bp = exgetcbuf(xs); bp->mb_rqst = LLNET_ADDRS; bp->mb_na.na_mask = READ_OBJ; bp->mb_na.na_slot = PHYSSLOT; bp->mb_status |= MH_EXOS; addr->xd_portb = EX_NTRUPT; bp = xs->xs_x2hnext; while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ ; printf("ex%d: HW %c.%c, NX %c.%c, hardware address %s\n", ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3], xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1], ether_sprintf(bp->mb_na.na_addrs)); bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr, sizeof (xs->xs_addr)); ifp->if_init = exinit; ifp->if_output = ether_output; ifp->if_start = exstart; ifp->if_ioctl = exioctl; ifp->if_reset = exreset; ifp->if_flags = IFF_BROADCAST; xs->xs_ifuba.ifu_flags = UBA_CANTWAIT; if_attach(ifp);badconf: ubarelse(ui->ui_ubanum, &xs->xs_ubaddr);}/* * Reset of interface after UNIBUS reset. * If interface is on specified uba, reset its state. */exreset(unit, uban) int unit, uban;{ register struct uba_device *ui; if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) return; printf(" ex%d", unit); ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING; ex_softc[unit].xs_flags &= ~EX_RUNNING; exinit(unit);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. * Called at boot time (with interrupts disabled?), * and at ifconfig time via exioctl, with interrupts disabled. */exinit(unit) int unit;{ register struct ex_softc *xs = &ex_softc[unit]; register struct uba_device *ui = exinfo[unit]; register struct exdevice *addr = (struct exdevice *)ui->ui_addr; register struct ifnet *ifp = &xs->xs_if; register struct ex_msg *bp; int s; /* not yet, if address still unknown */ if (ifp->if_addrlist == (struct ifaddr *)0) return; if (xs->xs_flags & EX_RUNNING) return; if ((ifp->if_flags & IFF_RUNNING) == 0) { if (if_ubainit(&xs->xs_ifuba, ui->ui_ubanum, sizeof (struct ether_header), (int)btoc(EXMAXRBUF-sizeof(struct ether_header))) == 0) { printf("ex%d: can't initialize\n", unit); xs->xs_if.if_flags &= ~IFF_UP; return; } xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), INCORE_SIZE(unit), 0); } exconfig(ui, 4); /* with vectored interrupts*/ /* * Put EXOS on the Ethernet, using NET_MODE command */ bp = exgetcbuf(xs); bp->mb_rqst = LLNET_MODE; bp->mb_nm.nm_mask = WRITE_OBJ; bp->mb_nm.nm_optn = 0; bp->mb_nm.nm_mode = MODE_PERF; bp->mb_status |= MH_EXOS; addr->xd_portb = EX_NTRUPT; bp = xs->xs_x2hnext; while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ ; bp->mb_length = MBDATALEN; bp->mb_status |= MH_EXOS; /* free up buffer */ addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */ xs->xs_x2hnext = xs->xs_x2hnext->mb_next; ifp->if_watchdog = exwatch; ifp->if_timer = EXWATCHINTVL; s = splimp(); /* are interrupts always disabled here, anyway? */ exhangrcv(unit); /* hang receive request */ xs->xs_if.if_flags |= IFF_RUNNING; xs->xs_flags |= EX_RUNNING; if (xs->xs_flags & EX_SETADDR) ex_setaddr((u_char *)0, unit);#ifdef ISO ex_setmulti(all_es_snpa, unit, 1); ex_setmulti(all_is_snpa, unit, 2);#endif (void) exstart(&xs->xs_if); /* start transmits */ splx(s);}/* * Reset, test, and configure EXOS. This routine assumes * that message queues, etc. have already been mapped into * the UBA. It is called by exinit, and should also be * callable by exattach. */exconfig(ui, itype) struct uba_device *ui; int itype;{ register int unit = ui->ui_unit; register struct ex_softc *xs = &ex_softc[unit]; register struct exdevice *addr = (struct exdevice *) ui->ui_addr; register struct confmsg *cm = &xs->xs_cm; register struct ex_msg *bp; int i; u_long shiftreg; xs->xs_flags = 0; /* * Reset EXOS, wait for self-test to complete */ addr->xd_porta = EX_RESET; while ((addr->xd_portb & EX_TESTOK) == 0) ; /* * Set up configuration message. */ cm->cm_1rsrv = 1; cm->cm_cc = 0xFF; cm->cm_opmode = 0; /* link-level controller mode */ cm->cm_dfo = 0x0101; /* enable host data order conversion */ cm->cm_dcn1 = 1; cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0; cm->cm_ham = 3; /* absolute address mode */ cm->cm_3rsrv = 0; cm->cm_mapsiz = 0; cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */ cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */ cm->cm_byteptrn[2] = 0x07; cm->cm_byteptrn[3] = 0x0F; cm->cm_wordptrn[0] = 0x0103; cm->cm_wordptrn[1] = 0x070F; cm->cm_lwordptrn = 0x0103070F; for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0; cm->cm_mba = 0xFFFFFFFF; cm->cm_nproc = 0xFF; cm->cm_nmbox = 0xFF; cm->cm_nmcast = 0xFF; cm->cm_nhost = 1; cm->cm_h2xba = P_UNIADDR(xs->xs_ubaddr); cm->cm_h2xhdr = H2XHDR_OFFSET(unit); cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */ cm->cm_x2hba = cm->cm_h2xba; cm->cm_x2hhdr = X2HHDR_OFFSET(unit); cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */ for (i=0; (addr != ex_cvecs[i].xc_csraddr); i++)#ifdef DEBUG if (i >= NEX) panic("ex: matching csr address not found");#endif ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -