📄 if_xna.c
字号:
#ifndef lintstatic char *sccsid = "@(#)if_xna.c 4.3 (ULTRIX) 2/26/91";#endif lint/************************************************************************ * * * Copyright (c) 1988 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************/#include "xna.h"#if NXNA > 0 || defined(BINARY)/* * Revision History: * * 02/24/91 - jsd * Allow loopback packets if COPYALL mode is set * * 10/19/89 - Uttam Shikarpur * Added "if_version" support to return H/W type * Added counters for multicast packets and bytes sent. * * 07/11/89 - Fred L. Templin * Changed port register addressing to work with DEMNA. * * 07/11/89 - Ali Rafieymehr * Added XMI support for device interrupts and configuration. * Also, moved xnadriver initialization here from bi_data.c. * * 06/14/89 - Fred L. Templin * Packet filter support integrated. * * 06/12/89 - Fred L. Templin * Integrated error logging support for XNA port fatal * errors. * * 05/10/89 - Fred L. Templin * Re-architected "wait-for-command-completion" strategy. * Kick off timers instead of calls to sleep. * * 4/11/88 - Fred L. Templin * Added MIPS-to-VAX physical addressing mode for MIPS * * 04/07/89 - Fred L. Templin * Added locks to make the XNA driver SMP-Safe * * 12/12/88 - Fred L. Templin * Code cleanup for initial baselevel submit * * 08/29/88 - Fred L. Templin * Created the if_xna.c module */#include "packetfilter.h" /* NPACKETFILTER */#include "../data/if_xna_data.c"#include "../h/types.h"#include "../h/errlog.h"extern struct protosw *iftype_to_proto(), *iffamily_to_proto();extern int net_output();extern struct bidata bidata[];extern struct timeval time;extern struct xmidata *get_xmi();int xnaattach(), xnaintr(), xnaprobe();int xnainit(),xnastart(),xnaioctl(),xnareset(), xnawatch();struct mbuf *xnamkparam(), *xnamkuser();u_char xna_notset[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};#define XNAMCLGET(m) { \ register struct mbuf *p; \ MGET((m), M_DONTWAIT, MT_DATA); \ if ((m)) { \ MCLGET((m), p); \ m->m_len = CLBYTES; \ if (p == 0) { \ m_freem((m)); \ (m) = (struct mbuf *)NULL; \ } \ } \}#define XNATIMEOUT(xcmd, val) { \ register int s = splnet(); \ register long sec0 = time.tv_sec; \ while (((xcmd)->opcode == (val)) && ((time.tv_sec - sec0) < 3)); \ if ((xcmd)->opcode == (val)) \ (xcmd)->opcode = CMD_NOP; \ splx(s); \}/* * Probe the XNA; set up the register mappings with "nxv" giving the * base address. */xnaprobe(nxv,nxp,number,node,ui) caddr_t nxv; struct uba_device *ui;{ register struct xna_softc *sc = &xna_softc[ui->ui_unit]; register struct xnadevice *addr = &sc->xregs; register struct xnapdb *xpdb; register int delay; struct xnarecv_ring *rp; struct xnacmd_ring *tp; struct xmidata *xmidata; struct mbuf *m; int unit = ui->ui_unit; caddr_t dpa; int i; /* * Determine device type (DEBNI, DEXNA). Map register blocks * and check for power-up errors. */ addr->xnabase = (struct xnabase *)nxv; switch (addr->xna_dtype & XMIDTYPE_TYPE) { case XNADEXNA: addr->_xpd1 = (struct xnareg *)(nxv + XNAPD1_XMI); addr->_xpd2 = (struct xnareg *)(nxv + XNAPD2_XMI); addr->_xpst = (struct xnareg *)(nxv + XNAPST_XMI); addr->_xpud = (struct xnareg *)(nxv + XNAPUD_XMI); addr->_xpci = (struct xnareg *)(nxv + XNAPCI_XMI); addr->_xpcp = (struct xnareg *)(nxv + XNAPCP_XMI); addr->_xpcs = (struct xnareg *)(nxv + XNAPCS_XMI); /* * Wait up to 10 seconds for XPST_UNDEF state * to appear. */ for (delay = 1000; (delay && (addr->xnapst != XPST_UNDEF)); delay--) DELAY(10000); if ((addr->xber_xmi & XMI_STF) || (addr->xnapst != XPST_UNDEF)) { printf ("xna%d: port self test failed: xber = 0x%x, xpst = 0x%x, xpd1 = 0x%x, xpd2 = 0x%x, xpud = 0x%x\n", unit, addr->xber_xmi, addr->xnapst, addr->xnapd1, addr->xnapd2, addr->xnapud); return(0); } break; case XNADEBNI: addr->_xpst = (struct xnareg *)(nxv + XNAPST_BI); addr->_xpd1 = (struct xnareg *)(nxv + XNAPD1_BI); addr->_xpd2 = (struct xnareg *)(nxv + XNAPD2_BI); addr->_xpud = (struct xnareg *)(nxv + XNAPUD_BI); addr->_xpci = (struct xnareg *)(nxv + XNAPCI_BI); addr->_xpcp = (struct xnareg *)(nxv + XNAPCP_BI); addr->_xpcs = (struct xnareg *)(nxv + XNAPCS_BI); /* * Same as for DEXNA. Wait up to 10 seconds. If the * BROKE bit is set, or we're in the wrong state, * perform hard node restart. */ for (delay = 1000; (delay && (addr->xnapst != XPST_UNDEF)); delay--) DELAY(10000); if ((addr->xctrl_bi & BICTRL_BROKE) || (addr->xnapst != XPST_UNDEF)) { printf ("xna%d: port self test failed: bi_ctrl = 0x%x, bi_err = 0x%x, xpst = 0x%x, xpd1 = 0x%x, xpd2 = 0x%x, xpud = 0x%x\n", unit, addr->xctrl_bi, addr->xber_bi, addr->xnapst, addr->xnapd1, addr->xnapd2, addr->xnapud); return(0); } break; default: return (0); } /* * We are now guaranteed that the port has succesfully completed * self test and is in the "UNINITIALIZED" state. At this point, * we can grab the default physical address from the port data * registers. */ dpa = (caddr_t)&addr->xnapd1; for (i = 0; i < 4; i++) sc->is_dpaddr[i] = *dpa++; dpa = (caddr_t)&addr->xnapd2; for (; i < 6; i++) sc->is_dpaddr[i] = *dpa++; /* * Device actual physical address not set yet */ bcopy(xna_notset, sc->is_addr, 6); /* * allocate data structures, fill out port data block, and init device. */ KM_ALLOC(sc->rring,struct xnarecv_ring *,1024,KM_DEVBUF,KM_NOW_CL_CO_CA); if (sc->rring == 0) { printf ("xna%d: couldn't allocate receive ring\n", unit); return (0); } KM_ALLOC(sc->tring,struct xnacmd_ring *,1024,KM_DEVBUF,KM_NOW_CL_CO_CA); if (sc->tring == 0) { printf ("xna%d: couldn't allocate command ring\n", unit); KM_FREE(sc->rring, KM_DEVBUF); return (0); } KM_ALLOC(sc->xpdb,struct xnapdb *,512,KM_DEVBUF,KM_NOW_CL_CO_CA); if ((xpdb = sc->xpdb) == 0) { printf ("xna%d: couldn't allocate port data block\n", unit); KM_FREE(sc->rring, KM_DEVBUF); KM_FREE(sc->tring, KM_DEVBUF); return (0); } /* * Init first sc->nactv receive descriptors with buffer allocation * side-effects. (use nNXNAACTV as initial value). xnainitdesc() * will turn off ownership bit to give the descriptor to the port. * (XNAMCLGET() CAN fail in the case that there are no mbuf's * available, but the "while" loop in the receive interrupt handler * will initialize more as mbufs become available.) Set ownership of * left-over descriptors to the port driver. */ sc->nactv = nNXNAACTV; for (i = 0, rp = &sc->rring[0]; (i < sc->nactv); i++, rp++) { XNAMCLGET(m); if (m) xnainitdesc(rp, m); else break; } sc->nrecv = i; for (; i < nNXNARCV; i++, rp++) rp->status = ST_ROWN; for (i = 0, tp = &sc->tring[0]; i < nNXNACMD; i++, tp++) tp->status = ST_TOWN; /* * sc->tindex == index of next transmit/command desc. to activate * sc->tlast == index of last transmit/command processed * sc->nxmit == # of transmit/commands pending * sc->rindex == index of next recv. descriptor to activate * sc->rlast == index of last receive processed * sc->nrecv == # of receive descriptors currently active * sc->nproc == running count of receives and transmits processed */ sc->tindex = sc->nxmit = 0; sc->rindex = sc->nrecv; sc->rlast = sc->tlast = sc->nproc = -1;#ifdef vax xpdb->addr_mode = AM_VIRT30; /* 30-bit, non-interlocked virtual */ xpdb->cmd.xaddr_lo = (u_long)sc->tring; xpdb->recv.xaddr_lo = (u_long)sc->rring; xpdb->spt_len = (u_long)mfpr(SLR); xpdb->spt.xaddr_lo = (u_long)mfpr(SBR); xpdb->gpt = (u_long)(0x80000000 + mfpr(SBR)); /* Virt. address */ xpdb->ubua.xaddr_lo = (u_long)&sc->xna_ubuacnt;#endif vax#ifdef mips xpdb->addr_mode = AM_PHYS40; /* 40 bit, non-interlocked physical */ xpdb->cmd.xaddr_lo = svtophy(sc->tring); xpdb->recv.xaddr_lo = svtophy(sc->rring); xpdb->ubua.xaddr_lo = svtophy(&sc->xna_ubuacnt);#endif mips xpdb->cmd.xaddr_hi = 0; xpdb->cmd.xlen = sizeof(struct xnacmd_ring); /* cmd ring entry size */ xpdb->recv.xaddr_hi = xpdb->recv.xmbz = 0; xpdb->spt.xaddr_hi = xpdb->spt.xmbz = 0; xpdb->ubua.xaddr_hi = 0; xpdb->ubua.xlen = sizeof(struct xnactr_ent); /* * set up interrupt and error interrupt vectors */ switch (addr->xna_dtype & XMIDTYPE_TYPE) { case XNADEXNA: xmidata = get_xmi(number); xpdb->ivec.level = xpdb->evec.level = 1; xpdb->ivec.vector = xpdb->evec.vector = SCB_XMI_VEC_ADDR(xmidata, number,node,LEVEL15) - &scb.scb_stray; xpdb->ivec.nid_mask = xpdb->evec.nid_mask = xmidata->xmiintr_dst; break; case XNADEBNI: xpdb->ivec.level = xpdb->evec.level = 1; xpdb->ivec.vector = xpdb->evec.vector = SCB_BI_VEC_ADDR(number,node,LEVEL15) - &scb.scb_stray; xpdb->ivec.nid_mask = xpdb->evec.nid_mask = bidata[number].biintr_dst; break; } /* * Set up user buffer unavailable counter */ xpdb->ubua.xaddr_lo = (u_long)&sc->xna_ubuacnt; xpdb->ubua.xaddr_hi = 0; xpdb->ubua.xlen = sizeof(struct xnactr_ent); /* * Hit device init, and wait for XPST_INIT state to appear (up to * one second). */ addr->xnapd1 = svtophy(xpdb); addr->xnapd2 = 0; addr->xnapci = XPCI_INIT; for (delay = 100; (delay && (addr->xnapst != XPST_INIT)); delay--) DELAY(10000); if ((addr->xnapst & XPST_MASK) != XPST_INIT) { printf ("xna%d: port probe failed: xpst=0x%x, xpd1=0x%x, xpd2=0x%x, xpud=0x%x\n", unit, addr->xnapst, addr->xnapd1, addr->xnapd2, addr->xnapud); return (0); } /* * Get the initial value of the "potential system buffer unavailable" * counter. */ sc->xna_sbuacnt = xpdb->p_sbua; return (sizeof(struct xna_softc));}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */xnaattach(ui) struct uba_device *ui;{ register struct xna_softc *sc = &xna_softc[ui->ui_unit]; register struct xnadevice *addr = &sc->xregs; register struct ifnet *ifp = &sc->is_if; struct sockaddr_in *sin; register int i; ifp->if_unit = ui->ui_unit; ifp->if_name = "xna"; ifp->lk_softc = &sc->lk_xna_softc; ifp->if_mtu = ETHERMTU; ifp->if_type = IFT_ETHER; ifp->if_flags |= IFF_BROADCAST|IFF_DYNPROTO|IFF_NOTRAILERS; ((struct arpcom *)ifp)->ac_ipaddr.s_addr = 0; /* * Initialize multicast address table */ for (i = 0; i < NMULTI; i++) { bcopy(etherbroadcastaddr, sc->is_multi[i], 6); sc->is_muse[i] = 0; } /* * Set maxlen for the command queue; attach interface */ lockinit(&sc->lk_xna_softc, &lock_device15_d); sc->if_cmd.ifq_maxlen = IFQ_MAXLEN; sin = (struct sockaddr_in *)&ifp->if_addr; sin->sin_family = AF_INET; ifp->if_init = xnainit; ifp->if_output = net_output; ifp->if_start = xnastart; ifp->if_ioctl = xnaioctl; ifp->if_reset = xnareset; ifp->if_watchdog = xnawatch; ifp->if_timer = 1; ifp->d_affinity = ALLCPU; /* * Hook up the device interrupt vector to begin allowing interrupts. * We know that the device has been successfully initialized at this * point. Initialize if_version string. */ switch (addr->xna_dtype & XMIDTYPE_TYPE) { case XNADEXNA: xmidev_vec(ui->ui_adpt, ui->ui_nexus, LEVEL15, ui); bcopy("DEC DEMNA Ethernet Interface", ifp->if_version, 28); ifp->if_version[28] = '\0'; break; case XNADEBNI: bidev_vec(ui->ui_adpt, ui->ui_nexus, LEVEL15, ui); bcopy("DEC DEBNI Ethernet Interface", ifp->if_version, 28); ifp->if_version[28] = '\0'; break; } printf("xna%d: %s, hardware address %s\n", ifp->if_unit, ifp->if_version, ether_sprintf(sc->is_dpaddr));#if NPACKETFILTER > 0 attachpfilter(&(sc->is_ed));#endif NPACKETFILTER if_attach(ifp);}/* * Initialize interface. May be called by a user process or a software * interrupt scheduled by xnareset(). */xnainit(unit) int unit;{ register struct xna_softc *sc = &xna_softc[unit]; register struct xnadevice *addr = &sc->xregs; register struct xnacmd_buf *xcmd; register struct mbuf *m; register int delay; struct ifnet *ifp = &sc->is_if; int s, t; /* not yet, if address still unknown */ if (ifp->if_addrlist == (struct ifaddr *)0) return; if (ifp->if_flags & IFF_RUNNING) return; /* * Lock the softc to ensure coherency of softc data needed to fill * out the command buffers by "xnamkparam()" and "xnamkuser()", and * to lock access to the if_cmd queue by "xnacmd()". (xnaintr writes * command completion info. into the first longword of the command * buffer; XNATIMEOUT flags command timeouts. Need the splnet() if * we're called from softclock() by xnareset. */ s = splnet(); t = splimp(); smp_lock(&sc->lk_xna_softc, LK_RETRY); /* * Issue a "PARAM" command to fill in actual physical address (from * sc->is_addr) and other system parameters. Wait for completion, * which will be signaled by the interrupt handler. */ if (m = xnamkparam(sc, ifp)) { xnacmd(sc, m); smp_unlock(&sc->lk_xna_softc); splx(t); xcmd = mtod(m, struct xnacmd_buf *); XNATIMEOUT(xcmd, CMD_PARAM); /* Wait */ t = splimp(); smp_lock(&sc->lk_xna_softc, LK_RETRY); switch (xcmd->opcode) { case CMD_COMPLETE: /* * Set actual physical address */ bcopy(&xcmd->xnaparam.apa, sc->is_addr, 6); m_freem(m);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -