1*56819Sralph /*- 2*56819Sralph * 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 6*56819Sralph * Ralph Campbell and Rick Macklem. 752130Smckusick * 852130Smckusick * %sccs.include.redist.c% 952130Smckusick * 10*56819Sralph * @(#)if_le.c 7.8 (Berkeley) 11/15/92 1152130Smckusick */ 1252130Smckusick 13*56819Sralph #include <le.h> 1452130Smckusick #if NLE > 0 1552130Smckusick 16*56819Sralph #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> 59*56819Sralph 60*56819Sralph #include <pmax/pmax/pmaxtype.h> 61*56819Sralph #include <pmax/pmax/kn01.h> 62*56819Sralph #include <pmax/pmax/kmin.h> 63*56819Sralph #include <pmax/pmax/asic.h> 64*56819Sralph 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 */ 93*56819Sralph volatile void *sc_r2; /* dual-port RAM */ 94*56819Sralph int sc_ler2pad; /* Do ring descriptors require short pads? */ 95*56819Sralph void (*sc_copytobuf)(); /* Copy to buffer */ 96*56819Sralph void (*sc_copyfrombuf)(); /* Copy from buffer */ 97*56819Sralph 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 */ 121*56819Sralph static void lewritereg(); 12252130Smckusick #define LERDWR(cntl, src, dst) { (dst) = (src); DELAY(10); } 123*56819Sralph #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 132*56819Sralph void copytobuf_contig(), copyfrombuf_contig(), bzerobuf_contig(); 133*56819Sralph void copytobuf_gap2(), copyfrombuf_gap2(), bzerobuf_gap2(); 134*56819Sralph void copytobuf_gap16(), copyfrombuf_gap16(), bzerobuf_gap16(); 135*56819Sralph 136*56819Sralph extern int pmax_boardtype; 137*56819Sralph extern u_long le_iomem; 138*56819Sralph 13952130Smckusick /* 14052130Smckusick * Test to see if device is present. 14152130Smckusick * Return true if found and initialized ok. 14252130Smckusick * If interface exists, make available by filling in network interface 14352130Smckusick * record. System will initialize the interface when it is ready 14452130Smckusick * to accept packets. 14552130Smckusick */ 14652130Smckusick leprobe(dp) 14752130Smckusick struct pmax_ctlr *dp; 14852130Smckusick { 14952130Smckusick volatile struct lereg1 *ler1; 15052130Smckusick struct le_softc *le = &le_softc[dp->pmax_unit]; 15152130Smckusick struct ifnet *ifp = &le->sc_if; 15252130Smckusick u_char *cp; 15352130Smckusick int i; 15452695Sralph extern int leinit(), leioctl(), lestart(), ether_output(); 15552130Smckusick 156*56819Sralph switch (pmax_boardtype) { 157*56819Sralph case DS_PMAX: 158*56819Sralph le->sc_r1 = ler1 = (volatile struct lereg1 *)dp->pmax_addr; 159*56819Sralph le->sc_r2 = (volatile void *)MACH_PHYS_TO_UNCACHED(0x19000000); 160*56819Sralph cp = (u_char *)(MACH_PHYS_TO_UNCACHED(KN01_SYS_CLOCK) + 1); 161*56819Sralph le->sc_ler2pad = 1; 162*56819Sralph le->sc_copytobuf = copytobuf_gap2; 163*56819Sralph le->sc_copyfrombuf = copyfrombuf_gap2; 164*56819Sralph le->sc_zerobuf = bzerobuf_gap2; 165*56819Sralph break; 166*56819Sralph case DS_3MIN: 167*56819Sralph case DS_MAXINE: 168*56819Sralph if (dp->pmax_unit == 0) { 169*56819Sralph volatile u_int *ssr, *ldp; 17052130Smckusick 171*56819Sralph le->sc_r1 = ler1 = (volatile struct lereg1 *) 172*56819Sralph MACH_PHYS_TO_UNCACHED(KMIN_SYS_LANCE); 173*56819Sralph le->sc_r2 = (volatile void *) 174*56819Sralph MACH_PHYS_TO_UNCACHED(le_iomem); 175*56819Sralph cp = (u_char *)MACH_PHYS_TO_UNCACHED( 176*56819Sralph KMIN_SYS_ETHER_ADDRESS); 177*56819Sralph le->sc_ler2pad = 1; 178*56819Sralph le->sc_copytobuf = copytobuf_gap16; 179*56819Sralph le->sc_copyfrombuf = copyfrombuf_gap16; 180*56819Sralph le->sc_zerobuf = bzerobuf_gap16; 18152130Smckusick 182*56819Sralph /* 183*56819Sralph * And enable Lance dma through the asic. 184*56819Sralph */ 185*56819Sralph ssr = (volatile u_int *) 186*56819Sralph MACH_PHYS_TO_UNCACHED(KMIN_REG_CSR); 187*56819Sralph ldp = (volatile u_int *) 188*56819Sralph MACH_PHYS_TO_UNCACHED(KMIN_REG_LANCE_DMAPTR); 189*56819Sralph *ldp = (le_iomem << 3); /* phys addr << 3 */ 190*56819Sralph *ssr |= ASIC_CSR_DMAEN_LANCE; 191*56819Sralph break; 192*56819Sralph } 193*56819Sralph /* 194*56819Sralph * Units other than 0 are turbochannel option boards and fall 195*56819Sralph * through to DS_3MAX. 196*56819Sralph */ 197*56819Sralph case DS_3MAX: 198*56819Sralph le->sc_r1 = ler1 = (volatile struct lereg1 *) 199*56819Sralph (dp->pmax_addr + LE_OFFSET_LANCE); 200*56819Sralph le->sc_r2 = (volatile void *)(dp->pmax_addr + LE_OFFSET_RAM); 201*56819Sralph cp = (u_char *)(dp->pmax_addr + LE_OFFSET_ROM + 2); 202*56819Sralph le->sc_ler2pad = 0; 203*56819Sralph le->sc_copytobuf = copytobuf_contig; 204*56819Sralph le->sc_copyfrombuf = copyfrombuf_contig; 205*56819Sralph le->sc_zerobuf = bzerobuf_contig; 206*56819Sralph break; 207*56819Sralph default: 208*56819Sralph printf("Unknown CPU board type %d\n", pmax_boardtype); 209*56819Sralph return (0); 210*56819Sralph }; 211*56819Sralph 21252695Sralph /* 213*56819Sralph * 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 */ 221*56819Sralph LEWREG(LE_CSR0, ler1->ler1_rap); 222*56819Sralph 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 243*56819Sralph ledrinit(le) 244*56819Sralph struct le_softc *le; 24552130Smckusick { 246*56819Sralph register volatile void *rp; 24752130Smckusick register int i; 24852130Smckusick 24952130Smckusick for (i = 0; i < LERBUF; i++) { 250*56819Sralph rp = LER2_RMDADDR(le->sc_r2, i); 251*56819Sralph LER2_rmd0(rp, CPU_TO_CHIP_ADDR(ler2_rbuf[i][0])); 252*56819Sralph LER2_rmd1(rp, LE_OWN); 253*56819Sralph LER2_rmd2(rp, -LEMTU); 254*56819Sralph LER2_rmd3(rp, 0); 25552130Smckusick } 25652130Smckusick for (i = 0; i < LETBUF; i++) { 257*56819Sralph rp = LER2_TMDADDR(le->sc_r2, i); 258*56819Sralph LER2_tmd0(rp, CPU_TO_CHIP_ADDR(ler2_tbuf[i][0])); 259*56819Sralph LER2_tmd1(rp, 0); 260*56819Sralph LER2_tmd2(rp, 0); 261*56819Sralph 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; 270*56819Sralph 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 277*56819Sralph LEWREG(LE_CSR0, ler1->ler1_rap); 278*56819Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 279*56819Sralph 280*56819Sralph /* 281*56819Sralph * Setup for transmit/receive 282*56819Sralph */ 28352130Smckusick #if NBPFILTER > 0 28452130Smckusick if (le->sc_if.if_flags & IFF_PROMISC) 28552130Smckusick /* set the promiscuous bit */ 286*56819Sralph LER2_mode(ler2, LE_MODE|0x8000); 28752130Smckusick else 28852130Smckusick #endif 289*56819Sralph LER2_mode(ler2, LE_MODE); 290*56819Sralph LER2_padr0(ler2, (le->sc_addr[1] << 8) | le->sc_addr[0]); 291*56819Sralph LER2_padr1(ler2, (le->sc_addr[3] << 8) | le->sc_addr[2]); 292*56819Sralph 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 */ 298*56819Sralph LER2_ladrf0(ler2, 0x0010); 299*56819Sralph LER2_ladrf1(ler2, 0x0); 300*56819Sralph LER2_ladrf2(ler2, 0x0); 301*56819Sralph LER2_ladrf3(ler2, 0x0); 30252130Smckusick #else 303*56819Sralph LER2_ladrf0(ler2, 0); 304*56819Sralph LER2_ladrf1(ler2, 0); 305*56819Sralph LER2_ladrf2(ler2, 0); 306*56819Sralph LER2_ladrf3(ler2, 0); 30752130Smckusick #endif 308*56819Sralph LER2_rlen(ler2, LE_RLEN); 309*56819Sralph LER2_rdra(ler2, CPU_TO_CHIP_ADDR(ler2_rmd[0])); 310*56819Sralph LER2_tlen(ler2, LE_TLEN); 311*56819Sralph LER2_tdra(ler2, CPU_TO_CHIP_ADDR(ler2_tmd[0])); 312*56819Sralph ledrinit(le); 31352130Smckusick le->sc_rmd = 0; 31452130Smckusick le->sc_tmd = LETBUF - 1; 31552130Smckusick le->sc_tmdnext = 0; 31652130Smckusick 317*56819Sralph LEWREG(LE_CSR1, ler1->ler1_rap); 318*56819Sralph LEWREG(CPU_TO_CHIP_ADDR(ler2_mode), ler1->ler1_rdp); 319*56819Sralph LEWREG(LE_CSR2, ler1->ler1_rap); 320*56819Sralph LEWREG(0, ler1->ler1_rdp); 321*56819Sralph LEWREG(LE_CSR3, ler1->ler1_rap); 322*56819Sralph LEWREG(0, ler1->ler1_rdp); 323*56819Sralph 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 } 331*56819Sralph 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 \ 361*56819Sralph if (++bix == LETBUF) \ 362*56819Sralph bix = 0; \ 363*56819Sralph 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; 375*56819Sralph 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) { 382*56819Sralph 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) 393*56819Sralph bpf_mtap(le->sc_bpf, m); 39452130Smckusick #endif 395*56819Sralph len = leput(le, LER2_TBUFADDR(le->sc_r2, bix), m); 396*56819Sralph LER2_tmd3(tmd, 0); 397*56819Sralph LER2_tmd2(tmd, -len); 398*56819Sralph 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; 471*56819Sralph register volatile void *tmd; 47252130Smckusick 47352130Smckusick if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { 47452130Smckusick le->sc_xint++; 47552130Smckusick return; 47652130Smckusick } 47752130Smckusick LENEXTTMP; 478*56819Sralph while (bix != le->sc_tmdnext && (LER2V_tmd1(tmd) & LE_OWN) == 0) { 47952130Smckusick le->sc_tmd = bix; 480*56819Sralph if ((LER2V_tmd1(tmd) & LE_ERR) || (LER2V_tmd3(tmd) & LE_TBUFF)) { 48152130Smckusick lexerror(unit); 48252130Smckusick le->sc_if.if_oerrors++; 483*56819Sralph if (LER2V_tmd3(tmd) & (LE_TBUFF|LE_UFLO)) { 48452130Smckusick le->sc_uflo++; 48552130Smckusick lereset(unit); 48652130Smckusick break; 48752130Smckusick } 488*56819Sralph else if (LER2V_tmd3(tmd) & LE_LCOL) 48952130Smckusick le->sc_if.if_collisions++; 490*56819Sralph else if (LER2V_tmd3(tmd) & LE_RTRY) 49152130Smckusick le->sc_if.if_collisions += 16; 49252130Smckusick } 493*56819Sralph else if (LER2V_tmd1(tmd) & LE_ONE) 49452130Smckusick le->sc_if.if_collisions++; 495*56819Sralph 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 \ 508*56819Sralph if (++bix == LERBUF) \ 509*56819Sralph bix = 0; \ 510*56819Sralph 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; 523*56819Sralph register volatile void *rmd = LER2_RMDADDR(le->sc_r2, bix); 52452130Smckusick 52552130Smckusick /* 52652130Smckusick * Out of sync with hardware, should never happen? 52752130Smckusick */ 528*56819Sralph 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 */ 536*56819Sralph while ((LER2V_rmd1(rmd) & LE_OWN) == 0) { 537*56819Sralph 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 542*56819Sralph if (LER2V_rmd1(rmd) & LE_ERR) { 54352130Smckusick le->sc_rmd = bix; 54452130Smckusick lererror(unit, "bad packet"); 54552130Smckusick le->sc_if.if_ierrors++; 546*56819Sralph } 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); 554*56819Sralph LER2_rmd3(rmd, 0); 555*56819Sralph LER2_rmd1(rmd, LE_OWN); 55652130Smckusick LENEXTRMP; 557*56819Sralph } 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 */ 565*56819Sralph if ((LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 56652130Smckusick LE_ENP) { 56752130Smckusick lereset(unit); 56852130Smckusick return; 56952130Smckusick } 57052130Smckusick } else 571*56819Sralph leread(unit, LER2_RBUFADDR(le->sc_r2, bix), len); 572*56819Sralph LER2_rmd3(rmd, 0); 573*56819Sralph 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; 588*56819Sralph volatile void *buf; 58952130Smckusick int len; 59052130Smckusick { 59152130Smckusick register struct le_softc *le = &le_softc[unit]; 59252130Smckusick struct ether_header et; 593*56819Sralph struct mbuf *m, **hdrmp, **tailmp; 59452130Smckusick int off, resid; 595*56819Sralph u_short sbuf[2], eth_type; 59652695Sralph extern struct mbuf *leget(); 59752130Smckusick 59852130Smckusick le->sc_if.if_ipackets++; 599*56819Sralph (*le->sc_copyfrombuf)(buf, 0, (char *)&et, sizeof (et)); 600*56819Sralph 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 */ 617*56819Sralph if (eth_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) && 618*56819Sralph len >= eth_type && len >= IEEE802LEN_MIN) { 619*56819Sralph len = eth_type; 620*56819Sralph eth_type = ETHERTYPE_IEEE; /* hack! */ 62152130Smckusick } 62252130Smckusick #endif 62352130Smckusick 624*56819Sralph if (eth_type >= ETHERTYPE_TRAIL && 625*56819Sralph eth_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 626*56819Sralph off = (eth_type - ETHERTYPE_TRAIL) * 512; 62752130Smckusick if (off >= ETHERMTU) 62852130Smckusick return; /* sanity */ 629*56819Sralph (*le->sc_copyfrombuf)(buf, sizeof (et) + off, (char *)sbuf, 630*56819Sralph sizeof (sbuf)); 631*56819Sralph 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. 654*56819Sralph * The hdrmp and tailmp pointers are used by lebpf_tap() to 655*56819Sralph * temporarily reorder the mbuf list. See the comment at the beginning 656*56819Sralph * of lebpf_tap() for all the ugly details. 65752130Smckusick */ 658*56819Sralph m = leget(le, buf, len, off, &le->sc_if, &hdrmp, &tailmp); 65952130Smckusick if (m == 0) 66052130Smckusick return; 661*56819Sralph #if NBPFILTER > 0 662*56819Sralph if (le->sc_bpf) 663*56819Sralph if (lebpf_tap(le, m, hdrmp, tailmp, off, &et, sbuf)) 664*56819Sralph return; 665*56819Sralph #endif 66652130Smckusick #ifdef RMP 66752130Smckusick /* 66852130Smckusick * (XXX) 66952130Smckusick * This needs to be integrated with the ISO stuff in ether_input() 67052130Smckusick */ 671*56819Sralph 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 696*56819Sralph 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 */ 704*56819Sralph leput(le, lebuf, m) 705*56819Sralph struct le_softc *le; 706*56819Sralph register volatile void *lebuf; 70752130Smckusick register struct mbuf *m; 70852130Smckusick { 70952130Smckusick register struct mbuf *mp; 71052695Sralph register int len, tlen = 0; 711*56819Sralph 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; 717*56819Sralph (*le->sc_copytobuf)(mtod(mp, char *), lebuf, boff, len); 71852130Smckusick tlen += len; 719*56819Sralph boff += len; 72052130Smckusick } 72152130Smckusick m_freem(m); 72252695Sralph if (tlen < LEMINSIZE) { 723*56819Sralph (*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 * 733*56819Sralph leget(le, lebuf, totlen, off, ifp, hdrmp, tailmp) 734*56819Sralph struct le_softc *le; 735*56819Sralph volatile void *lebuf; 73652130Smckusick int totlen, off; 73752130Smckusick struct ifnet *ifp; 738*56819Sralph struct mbuf ***hdrmp, ***tailmp; 73952130Smckusick { 74052130Smckusick register struct mbuf *m; 74152130Smckusick struct mbuf *top = 0, **mp = ⊤ 742*56819Sralph register int len, resid, boff; 74352130Smckusick 74452130Smckusick /* NOTE: sizeof(struct ether_header) should be even */ 745*56819Sralph boff = sizeof(struct ether_header); 74652130Smckusick if (off) { 74752130Smckusick /* NOTE: off should be even */ 748*56819Sralph 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; 784*56819Sralph (*le->sc_copyfrombuf)(lebuf, boff, mtod(m, char *), len); 785*56819Sralph boff += len; 78652130Smckusick *mp = m; 78752130Smckusick mp = &m->m_next; 78852130Smckusick totlen -= len; 78952130Smckusick resid -= len; 79052130Smckusick if (resid == 0) { 791*56819Sralph boff = sizeof (struct ether_header); 79252130Smckusick resid = totlen; 793*56819Sralph *hdrmp = mp; 79452130Smckusick } 79552130Smckusick } 796*56819Sralph *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) { 857*56819Sralph 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]; 905*56819Sralph register volatile void *rmd; 90654144Sralph u_char eaddr[6]; 90752130Smckusick int len; 90852130Smckusick 90952130Smckusick if (!ledebug) 91052130Smckusick return; 91152130Smckusick 912*56819Sralph rmd = LER2_RMDADDR(le->sc_r2, le->sc_rmd); 913*56819Sralph len = LER2V_rmd3(rmd); 914*56819Sralph if (len > 11) 915*56819Sralph (*le->sc_copyfrombuf)(LER2_RBUFADDR(le->sc_r2, le->sc_rmd), 916*56819Sralph 6, eaddr, 6); 91752130Smckusick log(LOG_WARNING, 91852130Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 919*56819Sralph unit, msg, 920*56819Sralph len > 11 ? ether_sprintf(eaddr) : "unknown", 921*56819Sralph le->sc_rmd, len, 922*56819Sralph 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]; 930*56819Sralph register volatile void *tmd; 93154144Sralph u_char eaddr[6]; 93252130Smckusick int len; 93352130Smckusick 93452130Smckusick if (!ledebug) 93552130Smckusick return; 93652130Smckusick 937*56819Sralph tmd = LER2_TMDADDR(le->sc_r2, 0); 938*56819Sralph len = -LER2V_tmd2(tmd); 939*56819Sralph if (len > 5) 940*56819Sralph (*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", 943*56819Sralph unit, 944*56819Sralph len > 5 ? ether_sprintf(eaddr) : "unknown", 945*56819Sralph 0, len, 946*56819Sralph LER2V_tmd1(tmd), 94752130Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 948*56819Sralph LER2V_tmd3(tmd), 94952130Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 95052130Smckusick } 951*56819Sralph 952*56819Sralph /* 953*56819Sralph * Write a lance register port, reading it back to ensure success. This seems 954*56819Sralph * to be necessary during initialization, since the chip appears to be a bit 955*56819Sralph * pokey sometimes. 956*56819Sralph */ 957*56819Sralph static void 958*56819Sralph lewritereg(regptr, val) 959*56819Sralph register volatile u_short *regptr; 960*56819Sralph register u_short val; 961*56819Sralph { 962*56819Sralph register int i = 0; 963*56819Sralph 964*56819Sralph while (*regptr != val) { 965*56819Sralph *regptr = val; 966*56819Sralph MachEmptyWriteBuffer(); 967*56819Sralph if (++i > 10000) { 968*56819Sralph printf("le: Reg did not settle (to x%x): x%x\n", 969*56819Sralph val, *regptr); 970*56819Sralph return; 971*56819Sralph } 972*56819Sralph DELAY(100); 973*56819Sralph } 974*56819Sralph } 975*56819Sralph 976*56819Sralph /* 977*56819Sralph * Routines for accessing the transmit and receive buffers. Unfortunately, 978*56819Sralph * CPU addressing of these buffers is done in one of 3 ways: 979*56819Sralph * - contiguous (for the 3max and turbochannel option card) 980*56819Sralph * - gap2, which means shorts (2 bytes) interspersed with short (2 byte) 981*56819Sralph * spaces (for the pmax) 982*56819Sralph * - gap16, which means 16bytes interspersed with 16byte spaces 983*56819Sralph * for buffers which must begin on a 32byte boundary (for 3min and maxine) 984*56819Sralph * The buffer offset is the logical byte offset, assuming contiguous storage. 985*56819Sralph */ 986*56819Sralph void 987*56819Sralph copytobuf_contig(from, lebuf, boff, len) 988*56819Sralph char *from; 989*56819Sralph volatile void *lebuf; 990*56819Sralph int boff; 991*56819Sralph int len; 992*56819Sralph { 993*56819Sralph 994*56819Sralph /* 995*56819Sralph * Just call bcopy() to do the work. 996*56819Sralph */ 997*56819Sralph bcopy(from, ((char *)lebuf) + boff, len); 998*56819Sralph } 999*56819Sralph 1000*56819Sralph void 1001*56819Sralph copyfrombuf_contig(lebuf, boff, to, len) 1002*56819Sralph volatile void *lebuf; 1003*56819Sralph int boff; 1004*56819Sralph char *to; 1005*56819Sralph int len; 1006*56819Sralph { 1007*56819Sralph 1008*56819Sralph /* 1009*56819Sralph * Just call bcopy() to do the work. 1010*56819Sralph */ 1011*56819Sralph bcopy(((char *)lebuf) + boff, to, len); 1012*56819Sralph } 1013*56819Sralph 1014*56819Sralph void 1015*56819Sralph bzerobuf_contig(lebuf, boff, len) 1016*56819Sralph volatile void *lebuf; 1017*56819Sralph int boff; 1018*56819Sralph int len; 1019*56819Sralph { 1020*56819Sralph 1021*56819Sralph /* 1022*56819Sralph * Just let bzero() do the work 1023*56819Sralph */ 1024*56819Sralph bzero(((char *)lebuf) + boff, len); 1025*56819Sralph } 1026*56819Sralph 1027*56819Sralph /* 1028*56819Sralph * For the pmax the buffer consists of shorts (2 bytes) interspersed with 1029*56819Sralph * short (2 byte) spaces and must be accessed with halfword load/stores. 1030*56819Sralph * (don't worry about doing an extra byte) 1031*56819Sralph */ 1032*56819Sralph void 1033*56819Sralph copytobuf_gap2(from, lebuf, boff, len) 1034*56819Sralph register char *from; 1035*56819Sralph volatile void *lebuf; 1036*56819Sralph int boff; 1037*56819Sralph register int len; 1038*56819Sralph { 1039*56819Sralph register volatile u_short *bptr; 1040*56819Sralph register int xfer; 1041*56819Sralph 1042*56819Sralph if (boff & 0x1) { 1043*56819Sralph /* handle unaligned first byte */ 1044*56819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 1045*56819Sralph *bptr = (*from++ << 8) | (*bptr & 0xff); 1046*56819Sralph bptr += 2; 1047*56819Sralph len--; 1048*56819Sralph } else 1049*56819Sralph bptr = ((volatile u_short *)lebuf) + boff; 1050*56819Sralph if ((unsigned)from & 0x1) { 1051*56819Sralph while (len > 1) { 1052*56819Sralph *bptr = (from[1] << 8) | from[0]; 1053*56819Sralph bptr += 2; 1054*56819Sralph from += 2; 1055*56819Sralph len -= 2; 1056*56819Sralph } 1057*56819Sralph } else { 1058*56819Sralph /* optimize for aligned transfers */ 1059*56819Sralph xfer = (int)((unsigned)len & ~0x1); 1060*56819Sralph CopyToBuffer((u_short *)from, bptr, xfer); 1061*56819Sralph bptr += xfer; 1062*56819Sralph from += xfer; 1063*56819Sralph len -= xfer; 1064*56819Sralph } 1065*56819Sralph if (len == 1) 1066*56819Sralph *bptr = (u_short)*from; 1067*56819Sralph } 1068*56819Sralph 1069*56819Sralph void 1070*56819Sralph copyfrombuf_gap2(lebuf, boff, to, len) 1071*56819Sralph volatile void *lebuf; 1072*56819Sralph int boff; 1073*56819Sralph register char *to; 1074*56819Sralph register int len; 1075*56819Sralph { 1076*56819Sralph register volatile u_short *bptr; 1077*56819Sralph register u_short tmp; 1078*56819Sralph register int xfer; 1079*56819Sralph 1080*56819Sralph if (boff & 0x1) { 1081*56819Sralph /* handle unaligned first byte */ 1082*56819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 1083*56819Sralph *to++ = (*bptr >> 8) & 0xff; 1084*56819Sralph bptr += 2; 1085*56819Sralph len--; 1086*56819Sralph } else 1087*56819Sralph bptr = ((volatile u_short *)lebuf) + boff; 1088*56819Sralph if ((unsigned)to & 0x1) { 1089*56819Sralph while (len > 1) { 1090*56819Sralph tmp = *bptr; 1091*56819Sralph *to++ = tmp & 0xff; 1092*56819Sralph *to++ = (tmp >> 8) & 0xff; 1093*56819Sralph bptr += 2; 1094*56819Sralph len -= 2; 1095*56819Sralph } 1096*56819Sralph } else { 1097*56819Sralph /* optimize for aligned transfers */ 1098*56819Sralph xfer = (int)((unsigned)len & ~0x1); 1099*56819Sralph CopyFromBuffer(bptr, to, xfer); 1100*56819Sralph bptr += xfer; 1101*56819Sralph to += xfer; 1102*56819Sralph len -= xfer; 1103*56819Sralph } 1104*56819Sralph if (len == 1) 1105*56819Sralph *to = *bptr & 0xff; 1106*56819Sralph } 1107*56819Sralph 1108*56819Sralph void 1109*56819Sralph bzerobuf_gap2(lebuf, boff, len) 1110*56819Sralph volatile void *lebuf; 1111*56819Sralph int boff; 1112*56819Sralph int len; 1113*56819Sralph { 1114*56819Sralph register volatile u_short *bptr; 1115*56819Sralph 1116*56819Sralph if ((unsigned)boff & 0x1) { 1117*56819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 1118*56819Sralph *bptr &= 0xff; 1119*56819Sralph bptr += 2; 1120*56819Sralph len--; 1121*56819Sralph } else 1122*56819Sralph bptr = ((volatile u_short *)lebuf) + boff; 1123*56819Sralph while (len > 0) { 1124*56819Sralph *bptr = 0; 1125*56819Sralph bptr += 2; 1126*56819Sralph len -= 2; 1127*56819Sralph } 1128*56819Sralph } 1129*56819Sralph 1130*56819Sralph /* 1131*56819Sralph * For the 3min and maxine, the buffers are in main memory filled in with 1132*56819Sralph * 16byte blocks interspersed with 16byte spaces. 1133*56819Sralph */ 1134*56819Sralph void 1135*56819Sralph copytobuf_gap16(from, lebuf, boff, len) 1136*56819Sralph register char *from; 1137*56819Sralph volatile void *lebuf; 1138*56819Sralph int boff; 1139*56819Sralph register int len; 1140*56819Sralph { 1141*56819Sralph register char *bptr; 1142*56819Sralph register int xfer; 1143*56819Sralph 1144*56819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 1145*56819Sralph boff &= 0xf; 1146*56819Sralph xfer = min(len, 16 - boff); 1147*56819Sralph while (len > 0) { 1148*56819Sralph bcopy(from, ((char *)bptr) + boff, xfer); 1149*56819Sralph from += xfer; 1150*56819Sralph bptr += 32; 1151*56819Sralph boff = 0; 1152*56819Sralph len -= xfer; 1153*56819Sralph xfer = min(len, 16); 1154*56819Sralph } 1155*56819Sralph } 1156*56819Sralph 1157*56819Sralph void 1158*56819Sralph copyfrombuf_gap16(lebuf, boff, to, len) 1159*56819Sralph volatile void *lebuf; 1160*56819Sralph int boff; 1161*56819Sralph register char *to; 1162*56819Sralph register int len; 1163*56819Sralph { 1164*56819Sralph register char *bptr; 1165*56819Sralph register int xfer; 1166*56819Sralph 1167*56819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 1168*56819Sralph boff &= 0xf; 1169*56819Sralph xfer = min(len, 16 - boff); 1170*56819Sralph while (len > 0) { 1171*56819Sralph bcopy(((char *)bptr) + boff, to, xfer); 1172*56819Sralph to += xfer; 1173*56819Sralph bptr += 32; 1174*56819Sralph boff = 0; 1175*56819Sralph len -= xfer; 1176*56819Sralph xfer = min(len, 16); 1177*56819Sralph } 1178*56819Sralph } 1179*56819Sralph 1180*56819Sralph void 1181*56819Sralph bzerobuf_gap16(lebuf, boff, len) 1182*56819Sralph volatile void *lebuf; 1183*56819Sralph int boff; 1184*56819Sralph register int len; 1185*56819Sralph { 1186*56819Sralph register char *bptr; 1187*56819Sralph register int xfer; 1188*56819Sralph 1189*56819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 1190*56819Sralph boff &= 0xf; 1191*56819Sralph xfer = min(len, 16 - boff); 1192*56819Sralph while (len > 0) { 1193*56819Sralph bzero(((char *)bptr) + boff, xfer); 1194*56819Sralph bptr += 32; 1195*56819Sralph boff = 0; 1196*56819Sralph len -= xfer; 1197*56819Sralph xfer = min(len, 16); 1198*56819Sralph } 1199*56819Sralph } 1200*56819Sralph 1201*56819Sralph #if NBPFILTER > 0 1202*56819Sralph /* 1203*56819Sralph * This is exceptionally ugly, but since the lance buffers are not always 1204*56819Sralph * contiguous in cpu address space, this was the best I could think of. 1205*56819Sralph * Essentially build an mbuf list with the entire raw packet in it and 1206*56819Sralph * then dismantle it again if it is a local packet. I can't believe I am 1207*56819Sralph * rebuilding the trailer encapsulation, but... 1208*56819Sralph * Return true if the packet has been thrown away. 1209*56819Sralph */ 1210*56819Sralph static int 1211*56819Sralph lebpf_tap(le, m, hdrmp, tailmp, off, ep, sbuf) 1212*56819Sralph struct le_softc *le; 1213*56819Sralph struct mbuf *m; 1214*56819Sralph struct mbuf **hdrmp; 1215*56819Sralph struct mbuf **tailmp; 1216*56819Sralph int off; 1217*56819Sralph struct ether_header *ep; 1218*56819Sralph u_short *sbuf; 1219*56819Sralph { 1220*56819Sralph register struct mbuf *em, *sm; 1221*56819Sralph u_short *sp; 1222*56819Sralph 1223*56819Sralph MGET(em, M_DONTWAIT, MT_DATA); 1224*56819Sralph if (off && em) { 1225*56819Sralph MGET(sm, M_DONTWAIT, MT_DATA); 1226*56819Sralph if (sm == (struct mbuf *)0) { 1227*56819Sralph m_freem(em); 1228*56819Sralph em = (struct mbuf *)0; 1229*56819Sralph } 1230*56819Sralph } 1231*56819Sralph if (em) { 1232*56819Sralph bcopy((caddr_t)ep, mtod(em, caddr_t), sizeof (*ep)); 1233*56819Sralph em->m_len = sizeof (*ep); 1234*56819Sralph if (off) { 1235*56819Sralph sp = mtod(sm, u_short *); 1236*56819Sralph *sp++ = *sbuf++; 1237*56819Sralph *sp = *sbuf; 1238*56819Sralph sm->m_len = 2 * sizeof (u_short); 1239*56819Sralph em->m_next = *hdrmp; 1240*56819Sralph *hdrmp = (struct mbuf *)0; 1241*56819Sralph *tailmp = sm; 1242*56819Sralph sm->m_next = m; 1243*56819Sralph } else 1244*56819Sralph em->m_next = m; 1245*56819Sralph bpf_tap(le->sc_bpf, em); 1246*56819Sralph } 1247*56819Sralph /* 1248*56819Sralph * Note that the interface cannot be in promiscuous mode if 1249*56819Sralph * there are no bpf listeners. And if we are in promiscuous 1250*56819Sralph * mode, we have to check if this packet is really ours. 1251*56819Sralph * 1252*56819Sralph * XXX This test does not support multicasts. 1253*56819Sralph */ 1254*56819Sralph if ((le->sc_if.if_flags & IFF_PROMISC) 1255*56819Sralph && bcmp(ep->ether_dhost, le->sc_addr, 1256*56819Sralph sizeof(ep->ether_dhost)) != 0 1257*56819Sralph && bcmp(ep->ether_dhost, etherbroadcastaddr, 1258*56819Sralph sizeof(ep->ether_dhost)) != 0) { 1259*56819Sralph if (em) 1260*56819Sralph m_freem(em); 1261*56819Sralph else 1262*56819Sralph m_freem(m); 1263*56819Sralph return (1); 1264*56819Sralph } 1265*56819Sralph if (em == (struct mbuf *)0) 1266*56819Sralph return (0); 1267*56819Sralph if (off) { 1268*56819Sralph MFREE(em, *hdrmp); 1269*56819Sralph *tailmp = (struct mbuf *)0; 1270*56819Sralph MFREE(sm, em); 1271*56819Sralph } else { 1272*56819Sralph MFREE(em, sm); 1273*56819Sralph } 1274*56819Sralph return (0); 1275*56819Sralph } 1276*56819Sralph #endif /* NBPFILTER */ 1277*56819Sralph #endif /* NLE */ 1278