📄 if_ex.c
字号:
/* * Copyright (c) 1989 The 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.5 (Berkeley) 12/16/90 */#include "ex.h"#if NEX > 0 /* * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers */#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/vmparam.h"#include "sys/syslog.h"#include "sys/uio.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/pte.h"#include "../include/mtpr.h"#include "../vba/vbavar.h"#include "if_exreg.h"#include "if_vba.h"#define NH2X 32 /* Host to eXcelan request buffers */#define NX2H 16 /* eXcelan to Host reply buffers */#define NREC 16 /* Number of RECeive buffers */#define NTRB 4 /* Number of TRansmit Buffers */#define NVBI (NREC + NTRB)#define EXWATCHINTVL 10 /* call exwatch every x secs */int exprobe(), exslave(), exattach(), exintr(), exstart();struct vba_device *exinfo[NEX];long exstd[] = { 0 };struct vba_driver exdriver = { exprobe, 0, exattach, exstart, exstd, "ex", exinfo };int exinit(),ether_output(),exioctl(),exreset(),exwatch();struct ex_msg *exgetcbuf();int ex_ncall = 0; /* counts calls to exprobe */u_long busoff;/* * 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, ... NOTE: To configure multiple * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr). */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 */ 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 */ int xs_cvec; /* probe stores cvec here */ short xs_enetunit; /* unit number for enet filtering */ short xs_enetinit; /* enet inetrface is initialized */ struct ex_msg *xs_h2xnext; /* host pointer to request queue */ struct ex_msg *xs_x2hnext; /* host pointer to reply queue */ u_long xs_qbaddr; /* map info for structs below */ struct ex_shm { /* the following structures are always mapped in */ u_short sm_h2xhdr; /* EXOS's request queue header */ u_short sm_x2hhdr; /* EXOS's reply queue header */ struct ex_msg sm_h2xent[NH2X];/* request msg buffers */ struct ex_msg sm_x2hent[NX2H];/* reply msg buffers */ struct ex_conf sm_cm; /* configuration message */ struct ex_stat sm_xsa; /* EXOS writes stats here */ /* end mapped area */ } *xs_shm; /* host pointer to shared area */#define xs_h2xhdr xs_shm->sm_h2xhdr#define xs_x2hhdr xs_shm->sm_x2hhdr#define xs_h2xent xs_shm->sm_h2xent#define xs_x2hent xs_shm->sm_x2hent#define xs_cm xs_shm->sm_cm#define xs_xsa xs_shm->sm_xsa#define BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFFF))#define P_BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFF0))#define INCORE_BASE(p) (((u_long)(p)->xs_shm) & 0xFFFFFFF0)/* we will arrange that the shared memory begins on a 16 byte boundary */#define RVAL_OFF(n) (((char *)&(((struct ex_shm *)0)->n))-(char *)0)#define LVAL_OFF(n) (((char *)(((struct ex_shm *)0)->n))-(char *)0)#define H2XHDR_OFFSET RVAL_OFF(sm_h2xhdr)#define X2HHDR_OFFSET RVAL_OFF(sm_x2hhdr)#define H2XENT_OFFSET LVAL_OFF(sm_h2xent)#define X2HENT_OFFSET LVAL_OFF(sm_x2hent)#define CM_OFFSET RVAL_OFF(sm_cm)#define SA_OFFSET RVAL_OFF(sm_xsa) struct ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */ struct ifvba *xs_pkblist; /* free list of above */#define GetPkBuf(b, v) ((v = (b)->mb_pkb = xs->xs_pkblist),\ (xs->xs_pkblist = (struct ifvba *)(v)->iff_mbuf))#define FreePkBuf(v) (((v)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\ (xs->xs_pkblist = v)) char xs_nrec; /* number of pending receive buffers */ char xs_ntrb; /* number of pending transmit buffers */} ex_softc[NEX];int ex_padcheck = sizeof (struct ex_softc);exprobe(reg, vi) caddr_t reg; struct vba_device *vi;{ register br, cvec; /* r12, r11 value-result */ register struct exdevice *exaddr = (struct exdevice *)reg; int i; if (badaddr((caddr_t)exaddr, 2)) return 0; /* * Reset EXOS and run self-test (should complete within 2 seconds). */ movow(&exaddr->ex_porta, EX_RESET); for (i = 1000000; i; i--) { uncache(&(exaddr->ex_portb)); if (exaddr->ex_portb & EX_TESTOK) break; } if ((exaddr->ex_portb & EX_TESTOK) == 0) return 0; br = 0x15; cvec = --vi->ui_hd->vh_lastiv; ex_softc[vi->ui_unit].xs_cvec = cvec; 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. * A NET_ADDRS command is done to get the ethernet address. */exattach(ui) register struct vba_device *ui;{ register struct ex_softc *xs = &ex_softc[ui->ui_unit]; register struct ifnet *ifp = &xs->xs_if; register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; register struct ex_msg *bp; ifp->if_unit = ui->ui_unit; ifp->if_name = "ex"; ifp->if_mtu = ETHERMTU; ifp->if_init = exinit; ifp->if_ioctl = exioctl; ifp->if_output = ether_output; ifp->if_reset = exreset; ifp->if_start = exstart; ifp->if_flags = IFF_BROADCAST; /* * Note: extra memory gets returned by if_vbareserve() * first, so, being page alligned, it is also 16-byte alligned. */ if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF, (caddr_t *)&xs->xs_shm, sizeof(*xs->xs_shm)) == 0) return; /* * Temporarily map queues in order to configure EXOS */ xs->xs_qbaddr = INCORE_BASE(xs); exconfig(ui, 0); /* without interrupts */ if (xs->xs_cm.cm_cc) return; /* bad conf */ /* * Get Ethernet address. */ if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0) panic("exattach"); bp->mb_na.na_mask = READ_OBJ; bp->mb_na.na_slot = PHYSSLOT; bp->mb_status |= MH_EXOS; movow(&exaddr->ex_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)); if_attach(ifp);}/* * Reset of interface after BUS reset. * If interface is on specified vba, reset its state. */exreset(unit)int unit;{ register struct vba_device *ui; if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0) 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 BUS usage. Called at boot time, and at ifconfig time via * exioctl, with interrupts disabled. */exinit(unit)int unit;{ register struct ex_softc *xs = &ex_softc[unit]; register struct vba_device *ui = exinfo[unit]; register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; register struct ifnet *ifp = &xs->xs_if; register struct sockaddr_in *sin; 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; xs->xs_qbaddr = INCORE_BASE(xs); exconfig(ui, 4); /* with vectored interrupts*/ /* * Put EXOS on the Ethernet, using NET_MODE command */ if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0) panic("exinit"); 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; movow(&exaddr->ex_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 */ movow(&exaddr->ex_portb, EX_NTRUPT); xs->xs_x2hnext = xs->xs_x2hnext->mb_next; ifp->if_watchdog = exwatch; ifp->if_timer = EXWATCHINTVL; s = splimp(); /* are interrupts disabled here, anyway? */ exhangrcv(unit); 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 exstart(&ex_softc[unit].xs_if); /* start transmits */ splx(s); /* are interrupts disabled here, anyway? */}/* * Reset, test, and configure EXOS. It is called by exinit, and exattach. * Returns 0 if successful, 1 if self-test failed. */exconfig(ui, itype)struct vba_device *ui;int itype;{ register int unit = ui->ui_unit; register struct ex_softc *xs = &ex_softc[unit]; register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr; register struct ex_conf *cm = &xs->xs_cm; register struct ex_msg *bp; register struct ifvba *pkb; int i; u_long shiftreg; static u_char cmaddr[8] = {0xFF, 0xFF, 0, 0}; xs->xs_flags = 0; /* * Reset EXOS, wait for self-test to complete */ movow(&exaddr->ex_porta, EX_RESET); do { uncache(&exaddr->ex_portb); } while ((exaddr->ex_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_BUSADDR(xs->xs_qbaddr); cm->cm_h2xhdr = H2XHDR_OFFSET; cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */ cm->cm_x2hba = cm->cm_h2xba; cm->cm_x2hhdr = X2HHDR_OFFSET; cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */ cm->cm_x2haddr = xs->xs_cvec; /* ivec allocated in exprobe */ /* * Set up message queues and headers. * First the request queue */ for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) { bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); bp->mb_rsrv = 0; bp->mb_length = MBDATALEN; bp->mb_status = MH_HOST; bp->mb_next = bp+1; } xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET; xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent; /* Now the reply queue. */ for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) { bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); bp->mb_rsrv = 0; bp->mb_length = MBDATALEN; bp->mb_status = MH_EXOS; bp->mb_next = bp+1; } xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET; xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent; xs->xs_nrec = 0; xs->xs_ntrb = 0; xs->xs_pkblist = xs->xs_vbinfo + NVBI - 1; for (pkb = xs->xs_pkblist; pkb > xs->xs_vbinfo; pkb--) pkb->iff_mbuf = (struct mbuf *)(pkb - 1); xs->xs_vbinfo[0].iff_mbuf = 0; /* * Write config msg address to EXOS and wait for configuration to * complete (guaranteed response within 2 seconds). */ shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET; for (i = 4; i < 8; i++) { cmaddr[i] = (u_char)(shiftreg & 0xFF); shiftreg >>= 8; } for (i = 0; i < 8; i++) { do { uncache(&exaddr->ex_portb); } while (exaddr->ex_portb & EX_UNREADY) ; DELAY(500); movow(&exaddr->ex_portb, cmaddr[i]); } for (i = 500000; i; --i) { DELAY(10); uncache(&cm->cm_cc); if (cm->cm_cc != 0xFF) break; } if (cm->cm_cc) printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc);}/* * Start or re-start output on interface. Get another datagram to send off of * the interface queue, and map it to the interface before starting the output. * This routine is called by exinit(), exoutput(), and excdint(). In all cases,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -