📄 if_le.c
字号:
/*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * 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_le.c 8.2 (Berkeley) 11/16/93 */#include <le.h>#if NLE > 0#include <bpfilter.h>/* * AMD 7990 LANCE * * This driver will generate and accept trailer encapsulated packets even * though it buys us nothing. The motivation was to avoid incompatibilities * with VAXen, SUNs, and others that handle and benefit from them. * This reasoning is dubious. */#include <sys/param.h>#include <sys/proc.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/buf.h>#include <sys/protosw.h>#include <sys/socket.h>#include <sys/syslog.h>#include <sys/ioctl.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#if defined (CCITT) && defined (LLC)#include <sys/socketvar.h>#include <netccitt/x25.h>extern llc_ctlinput(), cons_rtrequest();#endif#include <machine/machConst.h>#include <pmax/pmax/pmaxtype.h>#include <pmax/pmax/kn01.h>#include <pmax/pmax/kmin.h>#include <pmax/pmax/asic.h>#include <pmax/dev/device.h>#include <pmax/dev/if_lereg.h>#if NBPFILTER > 0#include <net/bpf.h>#include <net/bpfdesc.h>#endifint leprobe();void leintr();struct driver ledriver = { "le", leprobe, 0, 0, leintr,};int ledebug = 1; /* console error messages *//* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * le_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... */struct le_softc { struct arpcom sc_ac; /* common Ethernet structures */#define sc_if sc_ac.ac_if /* network-visible interface */#define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ volatile struct lereg1 *sc_r1; /* LANCE registers */ volatile void *sc_r2; /* dual-port RAM */ int sc_ler2pad; /* Do ring descriptors require short pads? */ void (*sc_copytobuf)(); /* Copy to buffer */ void (*sc_copyfrombuf)(); /* Copy from buffer */ void (*sc_zerobuf)(); /* and Zero bytes in buffer */ int sc_rmd; /* predicted next rmd to process */ int sc_tmd; /* last tmd processed */ int sc_tmdnext; /* next tmd to transmit with */ /* stats */ int sc_runt; int sc_merr; int sc_babl; int sc_cerr; int sc_miss; int sc_rown; int sc_xint; int sc_uflo; int sc_rxlen; int sc_rxoff; int sc_txoff; int sc_busy; short sc_iflags;} le_softc[NLE];/* access LANCE registers */static void lewritereg();#define LERDWR(cntl, src, dst) { (dst) = (src); DELAY(10); }#define LEWREG(src, dst) lewritereg(&(dst), (src))#define CPU_TO_CHIP_ADDR(cpu) \ ((unsigned)(&(((struct lereg2 *)0)->cpu)))#define LE_OFFSET_RAM 0x0#define LE_OFFSET_LANCE 0x100000#define LE_OFFSET_ROM 0x1c0000void copytobuf_contig(), copyfrombuf_contig(), bzerobuf_contig();void copytobuf_gap2(), copyfrombuf_gap2(), bzerobuf_gap2();void copytobuf_gap16(), copyfrombuf_gap16(), bzerobuf_gap16();extern int pmax_boardtype;extern u_long le_iomem;extern u_long asic_base;/* * Test to see if device is present. * Return true if found and initialized ok. * If interface exists, make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */leprobe(dp) struct pmax_ctlr *dp;{ volatile struct lereg1 *ler1; struct le_softc *le = &le_softc[dp->pmax_unit]; struct ifnet *ifp = &le->sc_if; u_char *cp; int i; extern int leinit(), lereset(), leioctl(), lestart(), ether_output(); switch (pmax_boardtype) { case DS_PMAX: le->sc_r1 = ler1 = (volatile struct lereg1 *)dp->pmax_addr; le->sc_r2 = (volatile void *)MACH_PHYS_TO_UNCACHED(0x19000000); cp = (u_char *)(MACH_PHYS_TO_UNCACHED(KN01_SYS_CLOCK) + 1); le->sc_ler2pad = 1; le->sc_copytobuf = copytobuf_gap2; le->sc_copyfrombuf = copyfrombuf_gap2; le->sc_zerobuf = bzerobuf_gap2; break; case DS_3MIN: case DS_MAXINE: case DS_3MAXPLUS: if (dp->pmax_unit == 0) { volatile u_int *ssr, *ldp; le->sc_r1 = ler1 = (volatile struct lereg1 *) ASIC_SYS_LANCE(asic_base); cp = (u_char *)ASIC_SYS_ETHER_ADDRESS(asic_base); le->sc_r2 = (volatile void *) MACH_PHYS_TO_UNCACHED(le_iomem); le->sc_ler2pad = 1; le->sc_copytobuf = copytobuf_gap16; le->sc_copyfrombuf = copyfrombuf_gap16; le->sc_zerobuf = bzerobuf_gap16; /* * And enable Lance dma through the asic. */ ssr = (volatile u_int *)ASIC_REG_CSR(asic_base); ldp = (volatile u_int *) ASIC_REG_LANCE_DMAPTR(asic_base); *ldp = (le_iomem << 3); /* phys addr << 3 */ *ssr |= ASIC_CSR_DMAEN_LANCE; break; } /* * Units other than 0 are turbochannel option boards and fall * through to DS_3MAX. */ case DS_3MAX: le->sc_r1 = ler1 = (volatile struct lereg1 *) (dp->pmax_addr + LE_OFFSET_LANCE); le->sc_r2 = (volatile void *)(dp->pmax_addr + LE_OFFSET_RAM); cp = (u_char *)(dp->pmax_addr + LE_OFFSET_ROM + 2); le->sc_ler2pad = 0; le->sc_copytobuf = copytobuf_contig; le->sc_copyfrombuf = copyfrombuf_contig; le->sc_zerobuf = bzerobuf_contig; break; default: printf("Unknown CPU board type %d\n", pmax_boardtype); return (0); }; /* * Get the ethernet address out of rom */ for (i = 0; i < sizeof(le->sc_addr); i++) { le->sc_addr[i] = *cp; cp += 4; } /* make sure the chip is stopped */ LEWREG(LE_CSR0, ler1->ler1_rap); LEWREG(LE_STOP, ler1->ler1_rdp); ifp->if_unit = dp->pmax_unit; ifp->if_name = "le"; ifp->if_mtu = ETHERMTU; ifp->if_init = leinit; ifp->if_reset = lereset; ifp->if_ioctl = leioctl; ifp->if_output = ether_output; ifp->if_start = lestart;#ifdef MULTICAST ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;#else ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;#endif#if NBPFILTER > 0 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif if_attach(ifp); printf("le%d at nexus0 csr 0x%x priority %d ethernet address %s\n", dp->pmax_unit, dp->pmax_addr, dp->pmax_pri, ether_sprintf(le->sc_addr)); return (1);}#ifdef MULTICAST/* * Setup the logical address filter */voidlesetladrf(le) register struct le_softc *le;{ register volatile struct lereg2 *ler2 = le->sc_r2; register struct ifnet *ifp = &le->sc_if; register struct ether_multi *enm; register u_char *cp; register u_long crc; register u_long c; register int i, len; struct ether_multistep step; /* * Set up multicast address filter by passing all multicast * addresses through a crc generator, and then using the high * order 6 bits as a index into the 64 bit logical address * filter. The high order two bits select the word, while the * rest of the bits select the bit within the word. */ LER2_ladrf0(ler2, 0); LER2_ladrf1(ler2, 0); ifp->if_flags &= ~IFF_ALLMULTI; ETHER_FIRST_MULTI(step, &le->sc_ac, enm); while (enm != NULL) { if (bcmp((caddr_t)&enm->enm_addrlo, (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) == 0) { /* * We must listen to a range of multicast * addresses. For now, just accept all * multicasts, rather than trying to set only * those filter bits needed to match the range. * (At this time, the only use of address * ranges is for IP multicast routing, for * which the range is big enough to require all * bits set.) */ LER2_ladrf0(ler2, 0xff); LER2_ladrf1(ler2, 0xff); LER2_ladrf2(ler2, 0xff); LER2_ladrf3(ler2, 0xff); ifp->if_flags |= IFF_ALLMULTI; return; } cp = (unsigned char *)&enm->enm_addrlo; c = *cp; crc = 0xffffffff; len = 6; while (len-- > 0) { c = *cp; for (i = 0; i < 8; i++) { if ((c & 0x01) ^ (crc & 0x01)) { crc >>= 1; crc = crc ^ 0xedb88320; } else crc >>= 1; c >>= 1; } cp++; } /* Just want the 6 most significant bits. */ crc = crc >> 26; /* Turn on the corresponding bit in the filter. */ switch (crc >> 5) { case 0: LER2_ladrf0(ler2, 1 << (crc & 0x1f)); break; case 1: LER2_ladrf1(ler2, 1 << (crc & 0x1f)); break; case 2: LER2_ladrf2(ler2, 1 << (crc & 0x1f)); break; case 3: LER2_ladrf3(ler2, 1 << (crc & 0x1f)); } ETHER_NEXT_MULTI(step, enm); }}#endifledrinit(le) struct le_softc *le;{ register volatile void *rp; register int i; for (i = 0; i < LERBUF; i++) { rp = LER2_RMDADDR(le->sc_r2, i); LER2_rmd0(rp, CPU_TO_CHIP_ADDR(ler2_rbuf[i][0])); LER2_rmd1(rp, LE_OWN); LER2_rmd2(rp, -LEMTU); LER2_rmd3(rp, 0); } for (i = 0; i < LETBUF; i++) { rp = LER2_TMDADDR(le->sc_r2, i); LER2_tmd0(rp, CPU_TO_CHIP_ADDR(ler2_tbuf[i][0])); LER2_tmd1(rp, 0); LER2_tmd2(rp, 0); LER2_tmd3(rp, 0); }}lereset(unit) register int unit;{ register struct le_softc *le = &le_softc[unit]; register volatile struct lereg1 *ler1 = le->sc_r1; register volatile void *ler2 = le->sc_r2; register int timo = 100000; register int stat;#ifdef lint stat = unit;#endif LEWREG(LE_CSR0, ler1->ler1_rap); LEWREG(LE_STOP, ler1->ler1_rdp); /* * Setup for transmit/receive */#if NBPFILTER > 0 if (le->sc_if.if_flags & IFF_PROMISC) /* set the promiscuous bit */ LER2_mode(ler2, LE_MODE | 0x8000); else#endif LER2_mode(ler2, LE_MODE); LER2_padr0(ler2, (le->sc_addr[1] << 8) | le->sc_addr[0]); LER2_padr1(ler2, (le->sc_addr[3] << 8) | le->sc_addr[2]); LER2_padr2(ler2, (le->sc_addr[5] << 8) | le->sc_addr[4]); /* Setup the logical address filter */#ifdef MULTICAST lesetladrf(le);#else LER2_ladrf0(ler2, 0); LER2_ladrf1(ler2, 0); LER2_ladrf2(ler2, 0); LER2_ladrf3(ler2, 0);#endif LER2_rlen(ler2, LE_RLEN); LER2_rdra(ler2, CPU_TO_CHIP_ADDR(ler2_rmd[0])); LER2_tlen(ler2, LE_TLEN); LER2_tdra(ler2, CPU_TO_CHIP_ADDR(ler2_tmd[0])); ledrinit(le); le->sc_rmd = 0; le->sc_tmd = LETBUF - 1; le->sc_tmdnext = 0; LEWREG(LE_CSR1, ler1->ler1_rap); LEWREG(CPU_TO_CHIP_ADDR(ler2_mode), ler1->ler1_rdp); LEWREG(LE_CSR2, ler1->ler1_rap); LEWREG(0, ler1->ler1_rdp); LEWREG(LE_CSR3, ler1->ler1_rap); LEWREG(0, ler1->ler1_rdp); LEWREG(LE_CSR0, ler1->ler1_rap); LERDWR(ler0, LE_INIT, ler1->ler1_rdp); do { if (--timo == 0) { printf("le%d: init timeout, stat = 0x%x\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -