156819Sralph /*- 256819Sralph * Copyright (c) 1992 The Regents of the University of California. 352130Smckusick * All rights reserved. 452130Smckusick * 552130Smckusick * This code is derived from software contributed to Berkeley by 656819Sralph * Ralph Campbell and Rick Macklem. 752130Smckusick * 852130Smckusick * %sccs.include.redist.c% 952130Smckusick * 10*57234Sralph * @(#)if_le.c 7.9 (Berkeley) 12/20/92 1152130Smckusick */ 1252130Smckusick 1356819Sralph #include <le.h> 1452130Smckusick #if NLE > 0 1552130Smckusick 1656819Sralph #include <bpfilter.h> 1752130Smckusick 1852130Smckusick /* 1952130Smckusick * AMD 7990 LANCE 2052130Smckusick * 2152130Smckusick * This driver will generate and accept trailer encapsulated packets even 2252130Smckusick * though it buys us nothing. The motivation was to avoid incompatibilities 2352130Smckusick * with VAXen, SUNs, and others that handle and benefit from them. 2452130Smckusick * This reasoning is dubious. 2552130Smckusick */ 2656522Sbostic #include <sys/param.h> 2756522Sbostic #include <sys/systm.h> 2856522Sbostic #include <sys/mbuf.h> 2956522Sbostic #include <sys/buf.h> 3056522Sbostic #include <sys/protosw.h> 3156522Sbostic #include <sys/socket.h> 3256522Sbostic #include <sys/syslog.h> 3356522Sbostic #include <sys/ioctl.h> 3456522Sbostic #include <sys/errno.h> 3552130Smckusick 3656522Sbostic #include <net/if.h> 3756522Sbostic #include <net/netisr.h> 3856522Sbostic #include <net/route.h> 3952130Smckusick 4052130Smckusick #ifdef INET 4156522Sbostic #include <netinet/in.h> 4256522Sbostic #include <netinet/in_systm.h> 4356522Sbostic #include <netinet/in_var.h> 4456522Sbostic #include <netinet/ip.h> 4556522Sbostic #include <netinet/if_ether.h> 4652130Smckusick #endif 4752130Smckusick 4852130Smckusick #ifdef NS 4956522Sbostic #include <netns/ns.h> 5056522Sbostic #include <netns/ns_if.h> 5152130Smckusick #endif 5252130Smckusick 5352130Smckusick #ifdef RMP 5456522Sbostic #include <netrmp/rmp.h> 5556522Sbostic #include <netrmp/rmp_var.h> 5652130Smckusick #endif 5752130Smckusick 5856522Sbostic #include <machine/machConst.h> 5956819Sralph 6056819Sralph #include <pmax/pmax/pmaxtype.h> 6156819Sralph #include <pmax/pmax/kn01.h> 6256819Sralph #include <pmax/pmax/kmin.h> 6356819Sralph #include <pmax/pmax/asic.h> 6456819Sralph 6556525Sbostic #include <pmax/dev/device.h> 6656525Sbostic #include <pmax/dev/if_lereg.h> 6752130Smckusick 6852130Smckusick #if NBPFILTER > 0 6956522Sbostic #include <net/bpf.h> 7056522Sbostic #include <net/bpfdesc.h> 7152130Smckusick #endif 7252130Smckusick 7352130Smckusick int leprobe(); 7452695Sralph void leintr(); 7552130Smckusick struct driver ledriver = { 7652695Sralph "le", leprobe, 0, 0, leintr, 7752130Smckusick }; 7852130Smckusick 7952130Smckusick int ledebug = 1; /* console error messages */ 8052130Smckusick 8152130Smckusick /* 8252130Smckusick * Ethernet software status per interface. 8352130Smckusick * 8452130Smckusick * Each interface is referenced by a network interface structure, 8552130Smckusick * le_if, which the routing code uses to locate the interface. 8652130Smckusick * This structure contains the output queue for the interface, its address, ... 8752130Smckusick */ 8852130Smckusick struct le_softc { 8952130Smckusick struct arpcom sc_ac; /* common Ethernet structures */ 9052130Smckusick #define sc_if sc_ac.ac_if /* network-visible interface */ 9152130Smckusick #define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ 9252130Smckusick volatile struct lereg1 *sc_r1; /* LANCE registers */ 9356819Sralph volatile void *sc_r2; /* dual-port RAM */ 9456819Sralph int sc_ler2pad; /* Do ring descriptors require short pads? */ 9556819Sralph void (*sc_copytobuf)(); /* Copy to buffer */ 9656819Sralph void (*sc_copyfrombuf)(); /* Copy from buffer */ 9756819Sralph void (*sc_zerobuf)(); /* and Zero bytes in buffer */ 9852130Smckusick int sc_rmd; /* predicted next rmd to process */ 9952130Smckusick int sc_tmd; /* last tmd processed */ 10052130Smckusick int sc_tmdnext; /* next tmd to transmit with */ 10152130Smckusick int sc_runt; 10252130Smckusick int sc_jab; 10352130Smckusick int sc_merr; 10452130Smckusick int sc_babl; 10552130Smckusick int sc_cerr; 10652130Smckusick int sc_miss; 10752130Smckusick int sc_xint; 10852130Smckusick int sc_xown; 10952130Smckusick int sc_uflo; 11052130Smckusick int sc_rxlen; 11152130Smckusick int sc_rxoff; 11252130Smckusick int sc_txoff; 11352130Smckusick int sc_busy; 11452130Smckusick short sc_iflags; 11552130Smckusick #if NBPFILTER > 0 11652130Smckusick caddr_t sc_bpf; 11752130Smckusick #endif 11852130Smckusick } le_softc[NLE]; 11952130Smckusick 12052130Smckusick /* access LANCE registers */ 12156819Sralph static void lewritereg(); 12252130Smckusick #define LERDWR(cntl, src, dst) { (dst) = (src); DELAY(10); } 12356819Sralph #define LEWREG(src, dst) lewritereg(&(dst), (src)) 12452130Smckusick 12552130Smckusick #define CPU_TO_CHIP_ADDR(cpu) \ 12652695Sralph ((unsigned)(&(((struct lereg2 *)0)->cpu))) 12752695Sralph 12852695Sralph #define LE_OFFSET_RAM 0x0 12952695Sralph #define LE_OFFSET_LANCE 0x100000 13052695Sralph #define LE_OFFSET_ROM 0x1c0000 13152695Sralph 13256819Sralph void copytobuf_contig(), copyfrombuf_contig(), bzerobuf_contig(); 13356819Sralph void copytobuf_gap2(), copyfrombuf_gap2(), bzerobuf_gap2(); 13456819Sralph void copytobuf_gap16(), copyfrombuf_gap16(), bzerobuf_gap16(); 13556819Sralph 13656819Sralph extern int pmax_boardtype; 13756819Sralph extern u_long le_iomem; 138*57234Sralph extern u_long asic_base; 13956819Sralph 14052130Smckusick /* 14152130Smckusick * Test to see if device is present. 14252130Smckusick * Return true if found and initialized ok. 14352130Smckusick * If interface exists, make available by filling in network interface 14452130Smckusick * record. System will initialize the interface when it is ready 14552130Smckusick * to accept packets. 14652130Smckusick */ 14752130Smckusick leprobe(dp) 14852130Smckusick struct pmax_ctlr *dp; 14952130Smckusick { 15052130Smckusick volatile struct lereg1 *ler1; 15152130Smckusick struct le_softc *le = &le_softc[dp->pmax_unit]; 15252130Smckusick struct ifnet *ifp = &le->sc_if; 15352130Smckusick u_char *cp; 15452130Smckusick int i; 15552695Sralph extern int leinit(), leioctl(), lestart(), ether_output(); 15652130Smckusick 15756819Sralph switch (pmax_boardtype) { 15856819Sralph case DS_PMAX: 15956819Sralph le->sc_r1 = ler1 = (volatile struct lereg1 *)dp->pmax_addr; 16056819Sralph le->sc_r2 = (volatile void *)MACH_PHYS_TO_UNCACHED(0x19000000); 16156819Sralph cp = (u_char *)(MACH_PHYS_TO_UNCACHED(KN01_SYS_CLOCK) + 1); 16256819Sralph le->sc_ler2pad = 1; 16356819Sralph le->sc_copytobuf = copytobuf_gap2; 16456819Sralph le->sc_copyfrombuf = copyfrombuf_gap2; 16556819Sralph le->sc_zerobuf = bzerobuf_gap2; 16656819Sralph break; 16756819Sralph case DS_3MIN: 16856819Sralph case DS_MAXINE: 169*57234Sralph case DS_3MAXPLUS: 17056819Sralph if (dp->pmax_unit == 0) { 17156819Sralph volatile u_int *ssr, *ldp; 17252130Smckusick 17356819Sralph le->sc_r1 = ler1 = (volatile struct lereg1 *) 174*57234Sralph ASIC_SYS_LANCE(asic_base); 175*57234Sralph cp = (u_char *)ASIC_SYS_ETHER_ADDRESS(asic_base); 17656819Sralph le->sc_r2 = (volatile void *) 17756819Sralph MACH_PHYS_TO_UNCACHED(le_iomem); 17856819Sralph le->sc_ler2pad = 1; 17956819Sralph le->sc_copytobuf = copytobuf_gap16; 18056819Sralph le->sc_copyfrombuf = copyfrombuf_gap16; 18156819Sralph le->sc_zerobuf = bzerobuf_gap16; 18252130Smckusick 18356819Sralph /* 18456819Sralph * And enable Lance dma through the asic. 18556819Sralph */ 186*57234Sralph ssr = (volatile u_int *)ASIC_REG_CSR(asic_base); 18756819Sralph ldp = (volatile u_int *) 188*57234Sralph ASIC_REG_LANCE_DMAPTR(asic_base); 18956819Sralph *ldp = (le_iomem << 3); /* phys addr << 3 */ 19056819Sralph *ssr |= ASIC_CSR_DMAEN_LANCE; 19156819Sralph break; 19256819Sralph } 19356819Sralph /* 19456819Sralph * Units other than 0 are turbochannel option boards and fall 19556819Sralph * through to DS_3MAX. 19656819Sralph */ 19756819Sralph case DS_3MAX: 19856819Sralph le->sc_r1 = ler1 = (volatile struct lereg1 *) 19956819Sralph (dp->pmax_addr + LE_OFFSET_LANCE); 20056819Sralph le->sc_r2 = (volatile void *)(dp->pmax_addr + LE_OFFSET_RAM); 20156819Sralph cp = (u_char *)(dp->pmax_addr + LE_OFFSET_ROM + 2); 20256819Sralph le->sc_ler2pad = 0; 20356819Sralph le->sc_copytobuf = copytobuf_contig; 20456819Sralph le->sc_copyfrombuf = copyfrombuf_contig; 20556819Sralph le->sc_zerobuf = bzerobuf_contig; 20656819Sralph break; 20756819Sralph default: 20856819Sralph printf("Unknown CPU board type %d\n", pmax_boardtype); 20956819Sralph return (0); 21056819Sralph }; 21156819Sralph 21252695Sralph /* 21356819Sralph * Get the ethernet address out of rom 21452695Sralph */ 21552695Sralph for (i = 0; i < sizeof(le->sc_addr); i++) { 21652695Sralph le->sc_addr[i] = *cp; 21752695Sralph cp += 4; 21852695Sralph } 21952695Sralph 22052130Smckusick /* make sure the chip is stopped */ 22156819Sralph LEWREG(LE_CSR0, ler1->ler1_rap); 22256819Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 22352130Smckusick 22452130Smckusick ifp->if_unit = dp->pmax_unit; 22552130Smckusick ifp->if_name = "le"; 22652130Smckusick ifp->if_mtu = ETHERMTU; 22752130Smckusick ifp->if_init = leinit; 22852130Smckusick ifp->if_ioctl = leioctl; 22952130Smckusick ifp->if_output = ether_output; 23052130Smckusick ifp->if_start = lestart; 23152130Smckusick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 23252130Smckusick #if NBPFILTER > 0 23352130Smckusick bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 23452130Smckusick #endif 23552130Smckusick if_attach(ifp); 23652130Smckusick 23752695Sralph printf("le%d at nexus0 csr 0x%x priority %d ethernet address %s\n", 23852695Sralph dp->pmax_unit, dp->pmax_addr, dp->pmax_pri, 23952695Sralph ether_sprintf(le->sc_addr)); 24052130Smckusick return (1); 24152130Smckusick } 24252130Smckusick 24356819Sralph ledrinit(le) 24456819Sralph struct le_softc *le; 24552130Smckusick { 24656819Sralph register volatile void *rp; 24752130Smckusick register int i; 24852130Smckusick 24952130Smckusick for (i = 0; i < LERBUF; i++) { 25056819Sralph rp = LER2_RMDADDR(le->sc_r2, i); 25156819Sralph LER2_rmd0(rp, CPU_TO_CHIP_ADDR(ler2_rbuf[i][0])); 25256819Sralph LER2_rmd1(rp, LE_OWN); 25356819Sralph LER2_rmd2(rp, -LEMTU); 25456819Sralph LER2_rmd3(rp, 0); 25552130Smckusick } 25652130Smckusick for (i = 0; i < LETBUF; i++) { 25756819Sralph rp = LER2_TMDADDR(le->sc_r2, i); 25856819Sralph LER2_tmd0(rp, CPU_TO_CHIP_ADDR(ler2_tbuf[i][0])); 25956819Sralph LER2_tmd1(rp, 0); 26056819Sralph LER2_tmd2(rp, 0); 26156819Sralph LER2_tmd3(rp, 0); 26252130Smckusick } 26352130Smckusick } 26452130Smckusick 26552130Smckusick lereset(unit) 26652130Smckusick register int unit; 26752130Smckusick { 26852130Smckusick register struct le_softc *le = &le_softc[unit]; 26952130Smckusick register volatile struct lereg1 *ler1 = le->sc_r1; 27056819Sralph register volatile void *ler2 = le->sc_r2; 27152130Smckusick register int timo = 100000; 27252130Smckusick register int stat; 27352130Smckusick 27452130Smckusick #ifdef lint 27552130Smckusick stat = unit; 27652130Smckusick #endif 27756819Sralph LEWREG(LE_CSR0, ler1->ler1_rap); 27856819Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 27956819Sralph 28056819Sralph /* 28156819Sralph * Setup for transmit/receive 28256819Sralph */ 28352130Smckusick #if NBPFILTER > 0 28452130Smckusick if (le->sc_if.if_flags & IFF_PROMISC) 28552130Smckusick /* set the promiscuous bit */ 28656819Sralph LER2_mode(ler2, LE_MODE|0x8000); 28752130Smckusick else 28852130Smckusick #endif 28956819Sralph LER2_mode(ler2, LE_MODE); 29056819Sralph LER2_padr0(ler2, (le->sc_addr[1] << 8) | le->sc_addr[0]); 29156819Sralph LER2_padr1(ler2, (le->sc_addr[3] << 8) | le->sc_addr[2]); 29256819Sralph LER2_padr2(ler2, (le->sc_addr[5] << 8) | le->sc_addr[4]); 29352130Smckusick #ifdef RMP 29452130Smckusick /* 29552130Smckusick * Set up logical addr filter to accept multicast 9:0:9:0:0:4 29652130Smckusick * This should be an ioctl() to the driver. (XXX) 29752130Smckusick */ 29856819Sralph LER2_ladrf0(ler2, 0x0010); 29956819Sralph LER2_ladrf1(ler2, 0x0); 30056819Sralph LER2_ladrf2(ler2, 0x0); 30156819Sralph LER2_ladrf3(ler2, 0x0); 30252130Smckusick #else 30356819Sralph LER2_ladrf0(ler2, 0); 30456819Sralph LER2_ladrf1(ler2, 0); 30556819Sralph LER2_ladrf2(ler2, 0); 30656819Sralph LER2_ladrf3(ler2, 0); 30752130Smckusick #endif 30856819Sralph LER2_rlen(ler2, LE_RLEN); 30956819Sralph LER2_rdra(ler2, CPU_TO_CHIP_ADDR(ler2_rmd[0])); 31056819Sralph LER2_tlen(ler2, LE_TLEN); 31156819Sralph LER2_tdra(ler2, CPU_TO_CHIP_ADDR(ler2_tmd[0])); 31256819Sralph ledrinit(le); 31352130Smckusick le->sc_rmd = 0; 31452130Smckusick le->sc_tmd = LETBUF - 1; 31552130Smckusick le->sc_tmdnext = 0; 31652130Smckusick 31756819Sralph LEWREG(LE_CSR1, ler1->ler1_rap); 31856819Sralph LEWREG(CPU_TO_CHIP_ADDR(ler2_mode), ler1->ler1_rdp); 31956819Sralph LEWREG(LE_CSR2, ler1->ler1_rap); 32056819Sralph LEWREG(0, ler1->ler1_rdp); 32156819Sralph LEWREG(LE_CSR3, ler1->ler1_rap); 32256819Sralph LEWREG(0, ler1->ler1_rdp); 32356819Sralph LEWREG(LE_CSR0, ler1->ler1_rap); 32452130Smckusick LERDWR(ler0, LE_INIT, ler1->ler1_rdp); 32552130Smckusick do { 32652130Smckusick if (--timo == 0) { 32752130Smckusick printf("le%d: init timeout, stat = 0x%x\n", 32852130Smckusick unit, stat); 32952130Smckusick break; 33052130Smckusick } 33156819Sralph stat = ler1->ler1_rdp; 33252130Smckusick } while ((stat & LE_IDON) == 0); 33352130Smckusick LERDWR(ler0, LE_IDON, ler1->ler1_rdp); 33452130Smckusick LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); 33552130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 33652130Smckusick } 33752130Smckusick 33852130Smckusick /* 33952130Smckusick * Initialization of interface 34052130Smckusick */ 34152130Smckusick leinit(unit) 34252130Smckusick int unit; 34352130Smckusick { 34452130Smckusick struct le_softc *le = &le_softc[unit]; 34552130Smckusick register struct ifnet *ifp = &le->sc_if; 34652130Smckusick int s; 34752130Smckusick 34852130Smckusick /* not yet, if address still unknown */ 34952130Smckusick if (ifp->if_addrlist == (struct ifaddr *)0) 35052130Smckusick return; 35152130Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 35252130Smckusick s = splnet(); 35352130Smckusick ifp->if_flags |= IFF_RUNNING; 35452130Smckusick lereset(unit); 35552130Smckusick (void) lestart(ifp); 35652130Smckusick splx(s); 35752130Smckusick } 35852130Smckusick } 35952130Smckusick 36052130Smckusick #define LENEXTTMP \ 36156819Sralph if (++bix == LETBUF) \ 36256819Sralph bix = 0; \ 36356819Sralph tmd = LER2_TMDADDR(le->sc_r2, bix) 36452130Smckusick 36552130Smckusick /* 36652130Smckusick * Start output on interface. Get another datagram to send 36752130Smckusick * off of the interface queue, and copy it to the interface 36852130Smckusick * before starting the output. 36952130Smckusick */ 37052130Smckusick lestart(ifp) 37152130Smckusick struct ifnet *ifp; 37252130Smckusick { 37352130Smckusick register struct le_softc *le = &le_softc[ifp->if_unit]; 37452130Smckusick register int bix = le->sc_tmdnext; 37556819Sralph register volatile void *tmd = LER2_TMDADDR(le->sc_r2, bix); 37652130Smckusick register struct mbuf *m; 37752130Smckusick int len = 0; 37852130Smckusick 37952130Smckusick if ((le->sc_if.if_flags & IFF_RUNNING) == 0) 38052130Smckusick return (0); 38152130Smckusick while (bix != le->sc_tmd) { 38256819Sralph if (LER2V_tmd1(tmd) & LE_OWN) 38352130Smckusick panic("lestart"); 38452130Smckusick IF_DEQUEUE(&le->sc_if.if_snd, m); 38552130Smckusick if (m == 0) 38652130Smckusick break; 38752130Smckusick #if NBPFILTER > 0 38852130Smckusick /* 38952130Smckusick * If bpf is listening on this interface, let it 39052130Smckusick * see the packet before we commit it to the wire. 39152130Smckusick */ 39252130Smckusick if (le->sc_bpf) 39356819Sralph bpf_mtap(le->sc_bpf, m); 39452130Smckusick #endif 39556819Sralph len = leput(le, LER2_TBUFADDR(le->sc_r2, bix), m); 39656819Sralph LER2_tmd3(tmd, 0); 39756819Sralph LER2_tmd2(tmd, -len); 39856819Sralph LER2_tmd1(tmd, LE_OWN | LE_STP | LE_ENP); 39952130Smckusick LENEXTTMP; 40052130Smckusick } 40152130Smckusick if (len != 0) { 40252130Smckusick le->sc_if.if_flags |= IFF_OACTIVE; 40352130Smckusick LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp); 40452130Smckusick } 40552130Smckusick le->sc_tmdnext = bix; 40652130Smckusick return (0); 40752130Smckusick } 40852130Smckusick 40952130Smckusick /* 41052130Smckusick * Process interrupts from the 7990 chip. 41152130Smckusick */ 41252695Sralph void 41352695Sralph leintr(unit) 41452695Sralph int unit; 41552130Smckusick { 41652130Smckusick register struct le_softc *le; 41752130Smckusick register volatile struct lereg1 *ler1; 41852695Sralph register int stat; 41952130Smckusick 42052130Smckusick le = &le_softc[unit]; 42152130Smckusick ler1 = le->sc_r1; 42252130Smckusick stat = ler1->ler1_rdp; 42352130Smckusick if (!(stat & LE_INTR)) { 42453081Sralph printf("le%d: spurrious interrupt\n", unit); 42552130Smckusick return; 42652130Smckusick } 42752130Smckusick if (stat & LE_SERR) { 42852130Smckusick leerror(unit, stat); 42952130Smckusick if (stat & LE_MERR) { 43052130Smckusick le->sc_merr++; 43152130Smckusick lereset(unit); 43252130Smckusick return; 43352130Smckusick } 43452130Smckusick if (stat & LE_BABL) 43552130Smckusick le->sc_babl++; 43652130Smckusick if (stat & LE_CERR) 43752130Smckusick le->sc_cerr++; 43852130Smckusick if (stat & LE_MISS) 43952130Smckusick le->sc_miss++; 44052130Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); 44152130Smckusick } 44252130Smckusick if ((stat & LE_RXON) == 0) { 44352130Smckusick le->sc_rxoff++; 44452130Smckusick lereset(unit); 44552130Smckusick return; 44652130Smckusick } 44752130Smckusick if ((stat & LE_TXON) == 0) { 44852130Smckusick le->sc_txoff++; 44952130Smckusick lereset(unit); 45052130Smckusick return; 45152130Smckusick } 45252130Smckusick if (stat & LE_RINT) { 45352130Smckusick /* interrupt is cleared in lerint */ 45452130Smckusick lerint(unit); 45552130Smckusick } 45652130Smckusick if (stat & LE_TINT) { 45752130Smckusick LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp); 45852130Smckusick lexint(unit); 45952130Smckusick } 46052130Smckusick } 46152130Smckusick 46252130Smckusick /* 46352130Smckusick * Ethernet interface transmitter interrupt. 46452130Smckusick * Start another output if more data to send. 46552130Smckusick */ 46652130Smckusick lexint(unit) 46752130Smckusick register int unit; 46852130Smckusick { 46952130Smckusick register struct le_softc *le = &le_softc[unit]; 47052130Smckusick register int bix = le->sc_tmd; 47156819Sralph register volatile void *tmd; 47252130Smckusick 47352130Smckusick if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { 47452130Smckusick le->sc_xint++; 47552130Smckusick return; 47652130Smckusick } 47752130Smckusick LENEXTTMP; 47856819Sralph while (bix != le->sc_tmdnext && (LER2V_tmd1(tmd) & LE_OWN) == 0) { 47952130Smckusick le->sc_tmd = bix; 48056819Sralph if ((LER2V_tmd1(tmd) & LE_ERR) || (LER2V_tmd3(tmd) & LE_TBUFF)) { 48152130Smckusick lexerror(unit); 48252130Smckusick le->sc_if.if_oerrors++; 48356819Sralph if (LER2V_tmd3(tmd) & (LE_TBUFF|LE_UFLO)) { 48452130Smckusick le->sc_uflo++; 48552130Smckusick lereset(unit); 48652130Smckusick break; 48752130Smckusick } 48856819Sralph else if (LER2V_tmd3(tmd) & LE_LCOL) 48952130Smckusick le->sc_if.if_collisions++; 49056819Sralph else if (LER2V_tmd3(tmd) & LE_RTRY) 49152130Smckusick le->sc_if.if_collisions += 16; 49252130Smckusick } 49356819Sralph else if (LER2V_tmd1(tmd) & LE_ONE) 49452130Smckusick le->sc_if.if_collisions++; 49556819Sralph else if (LER2V_tmd1(tmd) & LE_MORE) 49652130Smckusick /* what is the real number? */ 49752130Smckusick le->sc_if.if_collisions += 2; 49852130Smckusick else 49952130Smckusick le->sc_if.if_opackets++; 50052130Smckusick LENEXTTMP; 50152130Smckusick } 50252130Smckusick if (bix == le->sc_tmdnext) 50352130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 50452130Smckusick (void) lestart(&le->sc_if); 50552130Smckusick } 50652130Smckusick 50752130Smckusick #define LENEXTRMP \ 50856819Sralph if (++bix == LERBUF) \ 50956819Sralph bix = 0; \ 51056819Sralph rmd = LER2_RMDADDR(le->sc_r2, bix) 51152130Smckusick 51252130Smckusick /* 51352130Smckusick * Ethernet interface receiver interrupt. 51452130Smckusick * If input error just drop packet. 51552130Smckusick * Decapsulate packet based on type and pass to type specific 51652130Smckusick * higher-level input routine. 51752130Smckusick */ 51852130Smckusick lerint(unit) 51952130Smckusick int unit; 52052130Smckusick { 52152130Smckusick register struct le_softc *le = &le_softc[unit]; 52252130Smckusick register int bix = le->sc_rmd; 52356819Sralph register volatile void *rmd = LER2_RMDADDR(le->sc_r2, bix); 52452130Smckusick 52552130Smckusick /* 52652130Smckusick * Out of sync with hardware, should never happen? 52752130Smckusick */ 52856819Sralph if (LER2V_rmd1(rmd) & LE_OWN) { 52952130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 53052130Smckusick return; 53152130Smckusick } 53252130Smckusick 53352130Smckusick /* 53452130Smckusick * Process all buffers with valid data 53552130Smckusick */ 53656819Sralph while ((LER2V_rmd1(rmd) & LE_OWN) == 0) { 53756819Sralph int len = LER2V_rmd3(rmd); 53852130Smckusick 53952130Smckusick /* Clear interrupt to avoid race condition */ 54052130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 54152130Smckusick 54256819Sralph if (LER2V_rmd1(rmd) & LE_ERR) { 54352130Smckusick le->sc_rmd = bix; 54452130Smckusick lererror(unit, "bad packet"); 54552130Smckusick le->sc_if.if_ierrors++; 54656819Sralph } else if ((LER2V_rmd1(rmd) & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 54752130Smckusick /* 54852130Smckusick * Find the end of the packet so we can see how long 54952130Smckusick * it was. We still throw it away. 55052130Smckusick */ 55152130Smckusick do { 55252130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, 55352130Smckusick le->sc_r1->ler1_rdp); 55456819Sralph LER2_rmd3(rmd, 0); 55556819Sralph LER2_rmd1(rmd, LE_OWN); 55652130Smckusick LENEXTRMP; 55756819Sralph } while (!(LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 55852130Smckusick le->sc_rmd = bix; 55952130Smckusick lererror(unit, "chained buffer"); 56052130Smckusick le->sc_rxlen++; 56152130Smckusick /* 56252130Smckusick * If search terminated without successful completion 56352130Smckusick * we reset the hardware (conservative). 56452130Smckusick */ 56556819Sralph if ((LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 56652130Smckusick LE_ENP) { 56752130Smckusick lereset(unit); 56852130Smckusick return; 56952130Smckusick } 57052130Smckusick } else 57156819Sralph leread(unit, LER2_RBUFADDR(le->sc_r2, bix), len); 57256819Sralph LER2_rmd3(rmd, 0); 57356819Sralph LER2_rmd1(rmd, LE_OWN); 57452130Smckusick LENEXTRMP; 57552130Smckusick } 57652130Smckusick MachEmptyWriteBuffer(); /* Paranoia */ 57752130Smckusick le->sc_rmd = bix; 57852130Smckusick } 57952130Smckusick 58052130Smckusick /* 58152130Smckusick * Look at the packet in network buffer memory so we can be smart about how 58252130Smckusick * we copy the data into mbufs. 58352130Smckusick * This needs work since we can't just read network buffer memory like 58452130Smckusick * regular memory. 58552130Smckusick */ 58652130Smckusick leread(unit, buf, len) 58752130Smckusick int unit; 58856819Sralph volatile void *buf; 58952130Smckusick int len; 59052130Smckusick { 59152130Smckusick register struct le_softc *le = &le_softc[unit]; 59252130Smckusick struct ether_header et; 59356819Sralph struct mbuf *m, **hdrmp, **tailmp; 59452130Smckusick int off, resid; 59556819Sralph u_short sbuf[2], eth_type; 59652695Sralph extern struct mbuf *leget(); 59752130Smckusick 59852130Smckusick le->sc_if.if_ipackets++; 59956819Sralph (*le->sc_copyfrombuf)(buf, 0, (char *)&et, sizeof (et)); 60056819Sralph eth_type = ntohs(et.ether_type); 60152130Smckusick /* adjust input length to account for header and CRC */ 60252130Smckusick len = len - sizeof(struct ether_header) - 4; 60352130Smckusick 60452130Smckusick #ifdef RMP 60552130Smckusick /* (XXX) 60652130Smckusick * 60752130Smckusick * If Ethernet Type field is < MaxPacketSize, we probably have 60852130Smckusick * a IEEE802 packet here. Make sure that the size is at least 60952130Smckusick * that of the HP LLC. Also do sanity checks on length of LLC 61052130Smckusick * (old Ethernet Type field) and packet length. 61152130Smckusick * 61252130Smckusick * Provided the above checks succeed, change `len' to reflect 61352130Smckusick * the length of the LLC (i.e. et.ether_type) and change the 61452130Smckusick * type field to ETHERTYPE_IEEE so we can switch() on it later. 61552130Smckusick * Yes, this is a hack and will eventually be done "right". 61652130Smckusick */ 61756819Sralph if (eth_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) && 61856819Sralph len >= eth_type && len >= IEEE802LEN_MIN) { 61956819Sralph len = eth_type; 62056819Sralph eth_type = ETHERTYPE_IEEE; /* hack! */ 62152130Smckusick } 62252130Smckusick #endif 62352130Smckusick 62456819Sralph if (eth_type >= ETHERTYPE_TRAIL && 62556819Sralph eth_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 62656819Sralph off = (eth_type - ETHERTYPE_TRAIL) * 512; 62752130Smckusick if (off >= ETHERMTU) 62852130Smckusick return; /* sanity */ 62956819Sralph (*le->sc_copyfrombuf)(buf, sizeof (et) + off, (char *)sbuf, 63056819Sralph sizeof (sbuf)); 63156819Sralph eth_type = ntohs(sbuf[0]); 63252130Smckusick resid = ntohs(sbuf[1]); 63352130Smckusick if (off + resid > len) 63452130Smckusick return; /* sanity */ 63552130Smckusick len = off + resid; 63652130Smckusick } else 63752130Smckusick off = 0; 63852130Smckusick 63952130Smckusick if (len <= 0) { 64052130Smckusick if (ledebug) 64152130Smckusick log(LOG_WARNING, 64252130Smckusick "le%d: ierror(runt packet): from %s: len=%d\n", 64352130Smckusick unit, ether_sprintf(et.ether_shost), len); 64452130Smckusick le->sc_runt++; 64552130Smckusick le->sc_if.if_ierrors++; 64652130Smckusick return; 64752130Smckusick } 64852130Smckusick 64952130Smckusick /* 65052130Smckusick * Pull packet off interface. Off is nonzero if packet 65152130Smckusick * has trailing header; leget will then force this header 65252130Smckusick * information to be at the front, but we still have to drop 65352130Smckusick * the type and length which are at the front of any trailer data. 65456819Sralph * The hdrmp and tailmp pointers are used by lebpf_tap() to 65556819Sralph * temporarily reorder the mbuf list. See the comment at the beginning 65656819Sralph * of lebpf_tap() for all the ugly details. 65752130Smckusick */ 65856819Sralph m = leget(le, buf, len, off, &le->sc_if, &hdrmp, &tailmp); 65952130Smckusick if (m == 0) 66052130Smckusick return; 66156819Sralph #if NBPFILTER > 0 66256819Sralph if (le->sc_bpf) 66356819Sralph if (lebpf_tap(le, m, hdrmp, tailmp, off, &et, sbuf)) 66456819Sralph return; 66556819Sralph #endif 66652130Smckusick #ifdef RMP 66752130Smckusick /* 66852130Smckusick * (XXX) 66952130Smckusick * This needs to be integrated with the ISO stuff in ether_input() 67052130Smckusick */ 67156819Sralph if (eth_type == ETHERTYPE_IEEE) { 67252130Smckusick /* 67352130Smckusick * Snag the Logical Link Control header (IEEE 802.2). 67452130Smckusick */ 67552130Smckusick struct hp_llc *llc = &(mtod(m, struct rmp_packet *)->hp_llc); 67652130Smckusick 67752130Smckusick /* 67852130Smckusick * If the DSAP (and HP's extended DXSAP) indicate this 67952130Smckusick * is an RMP packet, hand it to the raw input routine. 68052130Smckusick */ 68152130Smckusick if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) { 68252130Smckusick static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT}; 68352130Smckusick static struct sockaddr rmp_src = {AF_RMP}; 68452130Smckusick static struct sockaddr rmp_dst = {AF_RMP}; 68552130Smckusick 68652130Smckusick bcopy(et.ether_shost, rmp_src.sa_data, 68752130Smckusick sizeof(et.ether_shost)); 68852130Smckusick bcopy(et.ether_dhost, rmp_dst.sa_data, 68952130Smckusick sizeof(et.ether_dhost)); 69052130Smckusick 69152130Smckusick raw_input(m, &rmp_sp, &rmp_src, &rmp_dst); 69252130Smckusick return; 69352130Smckusick } 69452130Smckusick } 69552130Smckusick #endif 69656819Sralph et.ether_type = eth_type; 69752130Smckusick ether_input(&le->sc_if, &et, m); 69852130Smckusick } 69952130Smckusick 70052130Smckusick /* 70152130Smckusick * Routine to copy from mbuf chain to transmit buffer in 70252130Smckusick * network buffer memory. 70352130Smckusick */ 70456819Sralph leput(le, lebuf, m) 70556819Sralph struct le_softc *le; 70656819Sralph register volatile void *lebuf; 70752130Smckusick register struct mbuf *m; 70852130Smckusick { 70952130Smckusick register struct mbuf *mp; 71052695Sralph register int len, tlen = 0; 71156819Sralph register int boff = 0; 71252130Smckusick 71352130Smckusick for (mp = m; mp; mp = mp->m_next) { 71452130Smckusick len = mp->m_len; 71552130Smckusick if (len == 0) 71652130Smckusick continue; 71756819Sralph (*le->sc_copytobuf)(mtod(mp, char *), lebuf, boff, len); 71852130Smckusick tlen += len; 71956819Sralph boff += len; 72052130Smckusick } 72152130Smckusick m_freem(m); 72252695Sralph if (tlen < LEMINSIZE) { 72356819Sralph (*le->sc_zerobuf)(lebuf, boff, LEMINSIZE - tlen); 72452130Smckusick tlen = LEMINSIZE; 72552695Sralph } 72652130Smckusick return(tlen); 72752130Smckusick } 72852130Smckusick 72952130Smckusick /* 73052130Smckusick * Routine to copy from network buffer memory into mbufs. 73152130Smckusick */ 73252130Smckusick struct mbuf * 73356819Sralph leget(le, lebuf, totlen, off, ifp, hdrmp, tailmp) 73456819Sralph struct le_softc *le; 73556819Sralph volatile void *lebuf; 73652130Smckusick int totlen, off; 73752130Smckusick struct ifnet *ifp; 73856819Sralph struct mbuf ***hdrmp, ***tailmp; 73952130Smckusick { 74052130Smckusick register struct mbuf *m; 74152130Smckusick struct mbuf *top = 0, **mp = ⊤ 74256819Sralph register int len, resid, boff; 74352130Smckusick 74452130Smckusick /* NOTE: sizeof(struct ether_header) should be even */ 74556819Sralph boff = sizeof(struct ether_header); 74652130Smckusick if (off) { 74752130Smckusick /* NOTE: off should be even */ 74856819Sralph boff += off + 2 * sizeof(u_short); 74952130Smckusick totlen -= 2 * sizeof(u_short); 75052130Smckusick resid = totlen - off; 75152130Smckusick } else 75252130Smckusick resid = totlen; 75352130Smckusick 75452130Smckusick MGETHDR(m, M_DONTWAIT, MT_DATA); 75552130Smckusick if (m == 0) 75652130Smckusick return (0); 75752130Smckusick m->m_pkthdr.rcvif = ifp; 75852130Smckusick m->m_pkthdr.len = totlen; 75952130Smckusick m->m_len = MHLEN; 76052130Smckusick 76152130Smckusick while (totlen > 0) { 76252130Smckusick if (top) { 76352130Smckusick MGET(m, M_DONTWAIT, MT_DATA); 76452130Smckusick if (m == 0) { 76552130Smckusick m_freem(top); 76652130Smckusick return (0); 76752130Smckusick } 76852130Smckusick m->m_len = MLEN; 76952130Smckusick } 77052130Smckusick 77152130Smckusick if (resid >= MINCLSIZE) 77252130Smckusick MCLGET(m, M_DONTWAIT); 77352130Smckusick if (m->m_flags & M_EXT) 77455745Sralph m->m_len = min(resid, MCLBYTES); 77552130Smckusick else if (resid < m->m_len) { 77652130Smckusick /* 77752130Smckusick * Place initial small packet/header at end of mbuf. 77852130Smckusick */ 77952130Smckusick if (top == 0 && resid + max_linkhdr <= m->m_len) 78052130Smckusick m->m_data += max_linkhdr; 78152130Smckusick m->m_len = resid; 78252130Smckusick } 78352130Smckusick len = m->m_len; 78456819Sralph (*le->sc_copyfrombuf)(lebuf, boff, mtod(m, char *), len); 78556819Sralph boff += len; 78652130Smckusick *mp = m; 78752130Smckusick mp = &m->m_next; 78852130Smckusick totlen -= len; 78952130Smckusick resid -= len; 79052130Smckusick if (resid == 0) { 79156819Sralph boff = sizeof (struct ether_header); 79252130Smckusick resid = totlen; 79356819Sralph *hdrmp = mp; 79452130Smckusick } 79552130Smckusick } 79656819Sralph *tailmp = mp; 79752130Smckusick return (top); 79852130Smckusick } 79952130Smckusick 80052130Smckusick /* 80152130Smckusick * Process an ioctl request. 80252130Smckusick */ 80352130Smckusick leioctl(ifp, cmd, data) 80452130Smckusick register struct ifnet *ifp; 80552130Smckusick int cmd; 80652130Smckusick caddr_t data; 80752130Smckusick { 80852130Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 80952130Smckusick struct le_softc *le = &le_softc[ifp->if_unit]; 81052130Smckusick volatile struct lereg1 *ler1 = le->sc_r1; 81152130Smckusick int s, error = 0; 81252130Smckusick 81352130Smckusick s = splnet(); 81452130Smckusick switch (cmd) { 81552130Smckusick 81652130Smckusick case SIOCSIFADDR: 81752130Smckusick ifp->if_flags |= IFF_UP; 81852130Smckusick switch (ifa->ifa_addr->sa_family) { 81952130Smckusick #ifdef INET 82052130Smckusick case AF_INET: 82152130Smckusick leinit(ifp->if_unit); /* before arpwhohas */ 82252130Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 82352130Smckusick IA_SIN(ifa)->sin_addr; 82452130Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 82552130Smckusick break; 82652130Smckusick #endif 82752130Smckusick #ifdef NS 82852130Smckusick case AF_NS: 82952130Smckusick { 83052130Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 83152130Smckusick 83252130Smckusick if (ns_nullhost(*ina)) 83352130Smckusick ina->x_host = *(union ns_host *)(le->sc_addr); 83452130Smckusick else { 83552130Smckusick /* 83652130Smckusick * The manual says we can't change the address 83752130Smckusick * while the receiver is armed, 83852130Smckusick * so reset everything 83952130Smckusick */ 84052130Smckusick ifp->if_flags &= ~IFF_RUNNING; 84152130Smckusick bcopy((caddr_t)ina->x_host.c_host, 84252130Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 84352130Smckusick } 84452130Smckusick leinit(ifp->if_unit); /* does le_setaddr() */ 84552130Smckusick break; 84652130Smckusick } 84752130Smckusick #endif 84852130Smckusick default: 84952130Smckusick leinit(ifp->if_unit); 85052130Smckusick break; 85152130Smckusick } 85252130Smckusick break; 85352130Smckusick 85452130Smckusick case SIOCSIFFLAGS: 85552130Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 85652130Smckusick ifp->if_flags & IFF_RUNNING) { 85756819Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 85852130Smckusick ifp->if_flags &= ~IFF_RUNNING; 85952130Smckusick } else if (ifp->if_flags & IFF_UP && 86052130Smckusick (ifp->if_flags & IFF_RUNNING) == 0) 86152130Smckusick leinit(ifp->if_unit); 86252130Smckusick /* 86352130Smckusick * If the state of the promiscuous bit changes, the interface 86452130Smckusick * must be reset to effect the change. 86552130Smckusick */ 86652130Smckusick if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && 86752130Smckusick (ifp->if_flags & IFF_RUNNING)) { 86852130Smckusick le->sc_iflags = ifp->if_flags; 86952130Smckusick lereset(ifp->if_unit); 87052130Smckusick lestart(ifp); 87152130Smckusick } 87252130Smckusick break; 87352130Smckusick 87452130Smckusick default: 87552130Smckusick error = EINVAL; 87652130Smckusick } 87752130Smckusick splx(s); 87852130Smckusick return (error); 87952130Smckusick } 88052130Smckusick 88152130Smckusick leerror(unit, stat) 88252130Smckusick int unit; 88352130Smckusick int stat; 88452130Smckusick { 88552130Smckusick if (!ledebug) 88652130Smckusick return; 88752130Smckusick 88852130Smckusick /* 88952130Smckusick * Not all transceivers implement heartbeat 89052130Smckusick * so we only log CERR once. 89152130Smckusick */ 89252130Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 89352130Smckusick return; 89452130Smckusick log(LOG_WARNING, 89552130Smckusick "le%d: error: stat=%b\n", unit, 89652130Smckusick stat, 89752130Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 89852130Smckusick } 89952130Smckusick 90052130Smckusick lererror(unit, msg) 90152130Smckusick int unit; 90252130Smckusick char *msg; 90352130Smckusick { 90452130Smckusick register struct le_softc *le = &le_softc[unit]; 90556819Sralph register volatile void *rmd; 90654144Sralph u_char eaddr[6]; 90752130Smckusick int len; 90852130Smckusick 90952130Smckusick if (!ledebug) 91052130Smckusick return; 91152130Smckusick 91256819Sralph rmd = LER2_RMDADDR(le->sc_r2, le->sc_rmd); 91356819Sralph len = LER2V_rmd3(rmd); 91456819Sralph if (len > 11) 91556819Sralph (*le->sc_copyfrombuf)(LER2_RBUFADDR(le->sc_r2, le->sc_rmd), 91656819Sralph 6, eaddr, 6); 91752130Smckusick log(LOG_WARNING, 91852130Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 91956819Sralph unit, msg, 92056819Sralph len > 11 ? ether_sprintf(eaddr) : "unknown", 92156819Sralph le->sc_rmd, len, 92256819Sralph LER2V_rmd1(rmd), 92352130Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 92452130Smckusick } 92552130Smckusick 92652130Smckusick lexerror(unit) 92752130Smckusick int unit; 92852130Smckusick { 92952130Smckusick register struct le_softc *le = &le_softc[unit]; 93056819Sralph register volatile void *tmd; 93154144Sralph u_char eaddr[6]; 93252130Smckusick int len; 93352130Smckusick 93452130Smckusick if (!ledebug) 93552130Smckusick return; 93652130Smckusick 93756819Sralph tmd = LER2_TMDADDR(le->sc_r2, 0); 93856819Sralph len = -LER2V_tmd2(tmd); 93956819Sralph if (len > 5) 94056819Sralph (*le->sc_copyfrombuf)(LER2_TBUFADDR(le->sc_r2, 0), 0, eaddr, 6); 94152130Smckusick log(LOG_WARNING, 94252130Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 94356819Sralph unit, 94456819Sralph len > 5 ? ether_sprintf(eaddr) : "unknown", 94556819Sralph 0, len, 94656819Sralph LER2V_tmd1(tmd), 94752130Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 94856819Sralph LER2V_tmd3(tmd), 94952130Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 95052130Smckusick } 95156819Sralph 95256819Sralph /* 95356819Sralph * Write a lance register port, reading it back to ensure success. This seems 95456819Sralph * to be necessary during initialization, since the chip appears to be a bit 95556819Sralph * pokey sometimes. 95656819Sralph */ 95756819Sralph static void 95856819Sralph lewritereg(regptr, val) 95956819Sralph register volatile u_short *regptr; 96056819Sralph register u_short val; 96156819Sralph { 96256819Sralph register int i = 0; 96356819Sralph 96456819Sralph while (*regptr != val) { 96556819Sralph *regptr = val; 96656819Sralph MachEmptyWriteBuffer(); 96756819Sralph if (++i > 10000) { 96856819Sralph printf("le: Reg did not settle (to x%x): x%x\n", 96956819Sralph val, *regptr); 97056819Sralph return; 97156819Sralph } 97256819Sralph DELAY(100); 97356819Sralph } 97456819Sralph } 97556819Sralph 97656819Sralph /* 97756819Sralph * Routines for accessing the transmit and receive buffers. Unfortunately, 97856819Sralph * CPU addressing of these buffers is done in one of 3 ways: 97956819Sralph * - contiguous (for the 3max and turbochannel option card) 98056819Sralph * - gap2, which means shorts (2 bytes) interspersed with short (2 byte) 98156819Sralph * spaces (for the pmax) 98256819Sralph * - gap16, which means 16bytes interspersed with 16byte spaces 98356819Sralph * for buffers which must begin on a 32byte boundary (for 3min and maxine) 98456819Sralph * The buffer offset is the logical byte offset, assuming contiguous storage. 98556819Sralph */ 98656819Sralph void 98756819Sralph copytobuf_contig(from, lebuf, boff, len) 98856819Sralph char *from; 98956819Sralph volatile void *lebuf; 99056819Sralph int boff; 99156819Sralph int len; 99256819Sralph { 99356819Sralph 99456819Sralph /* 99556819Sralph * Just call bcopy() to do the work. 99656819Sralph */ 99756819Sralph bcopy(from, ((char *)lebuf) + boff, len); 99856819Sralph } 99956819Sralph 100056819Sralph void 100156819Sralph copyfrombuf_contig(lebuf, boff, to, len) 100256819Sralph volatile void *lebuf; 100356819Sralph int boff; 100456819Sralph char *to; 100556819Sralph int len; 100656819Sralph { 100756819Sralph 100856819Sralph /* 100956819Sralph * Just call bcopy() to do the work. 101056819Sralph */ 101156819Sralph bcopy(((char *)lebuf) + boff, to, len); 101256819Sralph } 101356819Sralph 101456819Sralph void 101556819Sralph bzerobuf_contig(lebuf, boff, len) 101656819Sralph volatile void *lebuf; 101756819Sralph int boff; 101856819Sralph int len; 101956819Sralph { 102056819Sralph 102156819Sralph /* 102256819Sralph * Just let bzero() do the work 102356819Sralph */ 102456819Sralph bzero(((char *)lebuf) + boff, len); 102556819Sralph } 102656819Sralph 102756819Sralph /* 102856819Sralph * For the pmax the buffer consists of shorts (2 bytes) interspersed with 102956819Sralph * short (2 byte) spaces and must be accessed with halfword load/stores. 103056819Sralph * (don't worry about doing an extra byte) 103156819Sralph */ 103256819Sralph void 103356819Sralph copytobuf_gap2(from, lebuf, boff, len) 103456819Sralph register char *from; 103556819Sralph volatile void *lebuf; 103656819Sralph int boff; 103756819Sralph register int len; 103856819Sralph { 103956819Sralph register volatile u_short *bptr; 104056819Sralph register int xfer; 104156819Sralph 104256819Sralph if (boff & 0x1) { 104356819Sralph /* handle unaligned first byte */ 104456819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 104556819Sralph *bptr = (*from++ << 8) | (*bptr & 0xff); 104656819Sralph bptr += 2; 104756819Sralph len--; 104856819Sralph } else 104956819Sralph bptr = ((volatile u_short *)lebuf) + boff; 105056819Sralph if ((unsigned)from & 0x1) { 105156819Sralph while (len > 1) { 105256819Sralph *bptr = (from[1] << 8) | from[0]; 105356819Sralph bptr += 2; 105456819Sralph from += 2; 105556819Sralph len -= 2; 105656819Sralph } 105756819Sralph } else { 105856819Sralph /* optimize for aligned transfers */ 105956819Sralph xfer = (int)((unsigned)len & ~0x1); 106056819Sralph CopyToBuffer((u_short *)from, bptr, xfer); 106156819Sralph bptr += xfer; 106256819Sralph from += xfer; 106356819Sralph len -= xfer; 106456819Sralph } 106556819Sralph if (len == 1) 106656819Sralph *bptr = (u_short)*from; 106756819Sralph } 106856819Sralph 106956819Sralph void 107056819Sralph copyfrombuf_gap2(lebuf, boff, to, len) 107156819Sralph volatile void *lebuf; 107256819Sralph int boff; 107356819Sralph register char *to; 107456819Sralph register int len; 107556819Sralph { 107656819Sralph register volatile u_short *bptr; 107756819Sralph register u_short tmp; 107856819Sralph register int xfer; 107956819Sralph 108056819Sralph if (boff & 0x1) { 108156819Sralph /* handle unaligned first byte */ 108256819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 108356819Sralph *to++ = (*bptr >> 8) & 0xff; 108456819Sralph bptr += 2; 108556819Sralph len--; 108656819Sralph } else 108756819Sralph bptr = ((volatile u_short *)lebuf) + boff; 108856819Sralph if ((unsigned)to & 0x1) { 108956819Sralph while (len > 1) { 109056819Sralph tmp = *bptr; 109156819Sralph *to++ = tmp & 0xff; 109256819Sralph *to++ = (tmp >> 8) & 0xff; 109356819Sralph bptr += 2; 109456819Sralph len -= 2; 109556819Sralph } 109656819Sralph } else { 109756819Sralph /* optimize for aligned transfers */ 109856819Sralph xfer = (int)((unsigned)len & ~0x1); 109956819Sralph CopyFromBuffer(bptr, to, xfer); 110056819Sralph bptr += xfer; 110156819Sralph to += xfer; 110256819Sralph len -= xfer; 110356819Sralph } 110456819Sralph if (len == 1) 110556819Sralph *to = *bptr & 0xff; 110656819Sralph } 110756819Sralph 110856819Sralph void 110956819Sralph bzerobuf_gap2(lebuf, boff, len) 111056819Sralph volatile void *lebuf; 111156819Sralph int boff; 111256819Sralph int len; 111356819Sralph { 111456819Sralph register volatile u_short *bptr; 111556819Sralph 111656819Sralph if ((unsigned)boff & 0x1) { 111756819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 111856819Sralph *bptr &= 0xff; 111956819Sralph bptr += 2; 112056819Sralph len--; 112156819Sralph } else 112256819Sralph bptr = ((volatile u_short *)lebuf) + boff; 112356819Sralph while (len > 0) { 112456819Sralph *bptr = 0; 112556819Sralph bptr += 2; 112656819Sralph len -= 2; 112756819Sralph } 112856819Sralph } 112956819Sralph 113056819Sralph /* 113156819Sralph * For the 3min and maxine, the buffers are in main memory filled in with 113256819Sralph * 16byte blocks interspersed with 16byte spaces. 113356819Sralph */ 113456819Sralph void 113556819Sralph copytobuf_gap16(from, lebuf, boff, len) 113656819Sralph register char *from; 113756819Sralph volatile void *lebuf; 113856819Sralph int boff; 113956819Sralph register int len; 114056819Sralph { 114156819Sralph register char *bptr; 114256819Sralph register int xfer; 114356819Sralph 114456819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 114556819Sralph boff &= 0xf; 114656819Sralph xfer = min(len, 16 - boff); 114756819Sralph while (len > 0) { 114856819Sralph bcopy(from, ((char *)bptr) + boff, xfer); 114956819Sralph from += xfer; 115056819Sralph bptr += 32; 115156819Sralph boff = 0; 115256819Sralph len -= xfer; 115356819Sralph xfer = min(len, 16); 115456819Sralph } 115556819Sralph } 115656819Sralph 115756819Sralph void 115856819Sralph copyfrombuf_gap16(lebuf, boff, to, len) 115956819Sralph volatile void *lebuf; 116056819Sralph int boff; 116156819Sralph register char *to; 116256819Sralph register int len; 116356819Sralph { 116456819Sralph register char *bptr; 116556819Sralph register int xfer; 116656819Sralph 116756819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 116856819Sralph boff &= 0xf; 116956819Sralph xfer = min(len, 16 - boff); 117056819Sralph while (len > 0) { 117156819Sralph bcopy(((char *)bptr) + boff, to, xfer); 117256819Sralph to += xfer; 117356819Sralph bptr += 32; 117456819Sralph boff = 0; 117556819Sralph len -= xfer; 117656819Sralph xfer = min(len, 16); 117756819Sralph } 117856819Sralph } 117956819Sralph 118056819Sralph void 118156819Sralph bzerobuf_gap16(lebuf, boff, len) 118256819Sralph volatile void *lebuf; 118356819Sralph int boff; 118456819Sralph register int len; 118556819Sralph { 118656819Sralph register char *bptr; 118756819Sralph register int xfer; 118856819Sralph 118956819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 119056819Sralph boff &= 0xf; 119156819Sralph xfer = min(len, 16 - boff); 119256819Sralph while (len > 0) { 119356819Sralph bzero(((char *)bptr) + boff, xfer); 119456819Sralph bptr += 32; 119556819Sralph boff = 0; 119656819Sralph len -= xfer; 119756819Sralph xfer = min(len, 16); 119856819Sralph } 119956819Sralph } 120056819Sralph 120156819Sralph #if NBPFILTER > 0 120256819Sralph /* 120356819Sralph * This is exceptionally ugly, but since the lance buffers are not always 120456819Sralph * contiguous in cpu address space, this was the best I could think of. 120556819Sralph * Essentially build an mbuf list with the entire raw packet in it and 120656819Sralph * then dismantle it again if it is a local packet. I can't believe I am 120756819Sralph * rebuilding the trailer encapsulation, but... 120856819Sralph * Return true if the packet has been thrown away. 120956819Sralph */ 121056819Sralph static int 121156819Sralph lebpf_tap(le, m, hdrmp, tailmp, off, ep, sbuf) 121256819Sralph struct le_softc *le; 121356819Sralph struct mbuf *m; 121456819Sralph struct mbuf **hdrmp; 121556819Sralph struct mbuf **tailmp; 121656819Sralph int off; 121756819Sralph struct ether_header *ep; 121856819Sralph u_short *sbuf; 121956819Sralph { 122056819Sralph register struct mbuf *em, *sm; 122156819Sralph u_short *sp; 122256819Sralph 122356819Sralph MGET(em, M_DONTWAIT, MT_DATA); 122456819Sralph if (off && em) { 122556819Sralph MGET(sm, M_DONTWAIT, MT_DATA); 122656819Sralph if (sm == (struct mbuf *)0) { 122756819Sralph m_freem(em); 122856819Sralph em = (struct mbuf *)0; 122956819Sralph } 123056819Sralph } 123156819Sralph if (em) { 123256819Sralph bcopy((caddr_t)ep, mtod(em, caddr_t), sizeof (*ep)); 123356819Sralph em->m_len = sizeof (*ep); 123456819Sralph if (off) { 123556819Sralph sp = mtod(sm, u_short *); 123656819Sralph *sp++ = *sbuf++; 123756819Sralph *sp = *sbuf; 123856819Sralph sm->m_len = 2 * sizeof (u_short); 123956819Sralph em->m_next = *hdrmp; 124056819Sralph *hdrmp = (struct mbuf *)0; 124156819Sralph *tailmp = sm; 124256819Sralph sm->m_next = m; 124356819Sralph } else 124456819Sralph em->m_next = m; 124556819Sralph bpf_tap(le->sc_bpf, em); 124656819Sralph } 124756819Sralph /* 124856819Sralph * Note that the interface cannot be in promiscuous mode if 124956819Sralph * there are no bpf listeners. And if we are in promiscuous 125056819Sralph * mode, we have to check if this packet is really ours. 125156819Sralph * 125256819Sralph * XXX This test does not support multicasts. 125356819Sralph */ 125456819Sralph if ((le->sc_if.if_flags & IFF_PROMISC) 125556819Sralph && bcmp(ep->ether_dhost, le->sc_addr, 125656819Sralph sizeof(ep->ether_dhost)) != 0 125756819Sralph && bcmp(ep->ether_dhost, etherbroadcastaddr, 125856819Sralph sizeof(ep->ether_dhost)) != 0) { 125956819Sralph if (em) 126056819Sralph m_freem(em); 126156819Sralph else 126256819Sralph m_freem(m); 126356819Sralph return (1); 126456819Sralph } 126556819Sralph if (em == (struct mbuf *)0) 126656819Sralph return (0); 126756819Sralph if (off) { 126856819Sralph MFREE(em, *hdrmp); 126956819Sralph *tailmp = (struct mbuf *)0; 127056819Sralph MFREE(sm, em); 127156819Sralph } else { 127256819Sralph MFREE(em, sm); 127356819Sralph } 127456819Sralph return (0); 127556819Sralph } 127656819Sralph #endif /* NBPFILTER */ 127756819Sralph #endif /* NLE */ 1278