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*59836Sralph * @(#)if_le.c 7.10 (Berkeley) 05/09/93 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> 27*59836Sralph #include <sys/proc.h> 2856522Sbostic #include <sys/systm.h> 2956522Sbostic #include <sys/mbuf.h> 3056522Sbostic #include <sys/buf.h> 3156522Sbostic #include <sys/protosw.h> 3256522Sbostic #include <sys/socket.h> 3356522Sbostic #include <sys/syslog.h> 3456522Sbostic #include <sys/ioctl.h> 3556522Sbostic #include <sys/errno.h> 3652130Smckusick 3756522Sbostic #include <net/if.h> 3856522Sbostic #include <net/netisr.h> 3956522Sbostic #include <net/route.h> 4052130Smckusick 4152130Smckusick #ifdef INET 4256522Sbostic #include <netinet/in.h> 4356522Sbostic #include <netinet/in_systm.h> 4456522Sbostic #include <netinet/in_var.h> 4556522Sbostic #include <netinet/ip.h> 4656522Sbostic #include <netinet/if_ether.h> 4752130Smckusick #endif 4852130Smckusick 4952130Smckusick #ifdef NS 5056522Sbostic #include <netns/ns.h> 5156522Sbostic #include <netns/ns_if.h> 5252130Smckusick #endif 5352130Smckusick 54*59836Sralph #if defined (CCITT) && defined (LLC) 55*59836Sralph #include <sys/socketvar.h> 56*59836Sralph #include <netccitt/x25.h> 57*59836Sralph extern llc_ctlinput(), cons_rtrequest(); 5852130Smckusick #endif 5952130Smckusick 6056522Sbostic #include <machine/machConst.h> 6156819Sralph 6256819Sralph #include <pmax/pmax/pmaxtype.h> 6356819Sralph #include <pmax/pmax/kn01.h> 6456819Sralph #include <pmax/pmax/kmin.h> 6556819Sralph #include <pmax/pmax/asic.h> 6656819Sralph 6756525Sbostic #include <pmax/dev/device.h> 6856525Sbostic #include <pmax/dev/if_lereg.h> 6952130Smckusick 7052130Smckusick #if NBPFILTER > 0 7156522Sbostic #include <net/bpf.h> 7256522Sbostic #include <net/bpfdesc.h> 7352130Smckusick #endif 7452130Smckusick 7552130Smckusick int leprobe(); 7652695Sralph void leintr(); 7752130Smckusick struct driver ledriver = { 7852695Sralph "le", leprobe, 0, 0, leintr, 7952130Smckusick }; 8052130Smckusick 8152130Smckusick int ledebug = 1; /* console error messages */ 8252130Smckusick 8352130Smckusick /* 8452130Smckusick * Ethernet software status per interface. 8552130Smckusick * 8652130Smckusick * Each interface is referenced by a network interface structure, 8752130Smckusick * le_if, which the routing code uses to locate the interface. 8852130Smckusick * This structure contains the output queue for the interface, its address, ... 8952130Smckusick */ 9052130Smckusick struct le_softc { 9152130Smckusick struct arpcom sc_ac; /* common Ethernet structures */ 9252130Smckusick #define sc_if sc_ac.ac_if /* network-visible interface */ 9352130Smckusick #define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ 9452130Smckusick volatile struct lereg1 *sc_r1; /* LANCE registers */ 9556819Sralph volatile void *sc_r2; /* dual-port RAM */ 9656819Sralph int sc_ler2pad; /* Do ring descriptors require short pads? */ 9756819Sralph void (*sc_copytobuf)(); /* Copy to buffer */ 9856819Sralph void (*sc_copyfrombuf)(); /* Copy from buffer */ 9956819Sralph void (*sc_zerobuf)(); /* and Zero bytes in buffer */ 10052130Smckusick int sc_rmd; /* predicted next rmd to process */ 10152130Smckusick int sc_tmd; /* last tmd processed */ 10252130Smckusick int sc_tmdnext; /* next tmd to transmit with */ 103*59836Sralph /* stats */ 10452130Smckusick int sc_runt; 10552130Smckusick int sc_merr; 10652130Smckusick int sc_babl; 10752130Smckusick int sc_cerr; 10852130Smckusick int sc_miss; 109*59836Sralph int sc_rown; 11052130Smckusick int sc_xint; 11152130Smckusick int sc_uflo; 11252130Smckusick int sc_rxlen; 11352130Smckusick int sc_rxoff; 11452130Smckusick int sc_txoff; 11552130Smckusick int sc_busy; 11652130Smckusick short sc_iflags; 11752130Smckusick } le_softc[NLE]; 11852130Smckusick 11952130Smckusick /* access LANCE registers */ 12056819Sralph static void lewritereg(); 12152130Smckusick #define LERDWR(cntl, src, dst) { (dst) = (src); DELAY(10); } 12256819Sralph #define LEWREG(src, dst) lewritereg(&(dst), (src)) 12352130Smckusick 12452130Smckusick #define CPU_TO_CHIP_ADDR(cpu) \ 12552695Sralph ((unsigned)(&(((struct lereg2 *)0)->cpu))) 12652695Sralph 12752695Sralph #define LE_OFFSET_RAM 0x0 12852695Sralph #define LE_OFFSET_LANCE 0x100000 12952695Sralph #define LE_OFFSET_ROM 0x1c0000 13052695Sralph 13156819Sralph void copytobuf_contig(), copyfrombuf_contig(), bzerobuf_contig(); 13256819Sralph void copytobuf_gap2(), copyfrombuf_gap2(), bzerobuf_gap2(); 13356819Sralph void copytobuf_gap16(), copyfrombuf_gap16(), bzerobuf_gap16(); 13456819Sralph 13556819Sralph extern int pmax_boardtype; 13656819Sralph extern u_long le_iomem; 13757234Sralph extern u_long asic_base; 13856819Sralph 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; 154*59836Sralph extern int leinit(), lereset(), leioctl(), lestart(), ether_output(); 15552130Smckusick 15656819Sralph switch (pmax_boardtype) { 15756819Sralph case DS_PMAX: 15856819Sralph le->sc_r1 = ler1 = (volatile struct lereg1 *)dp->pmax_addr; 15956819Sralph le->sc_r2 = (volatile void *)MACH_PHYS_TO_UNCACHED(0x19000000); 16056819Sralph cp = (u_char *)(MACH_PHYS_TO_UNCACHED(KN01_SYS_CLOCK) + 1); 16156819Sralph le->sc_ler2pad = 1; 16256819Sralph le->sc_copytobuf = copytobuf_gap2; 16356819Sralph le->sc_copyfrombuf = copyfrombuf_gap2; 16456819Sralph le->sc_zerobuf = bzerobuf_gap2; 16556819Sralph break; 16656819Sralph case DS_3MIN: 16756819Sralph case DS_MAXINE: 16857234Sralph case DS_3MAXPLUS: 16956819Sralph if (dp->pmax_unit == 0) { 17056819Sralph volatile u_int *ssr, *ldp; 17152130Smckusick 17256819Sralph le->sc_r1 = ler1 = (volatile struct lereg1 *) 17357234Sralph ASIC_SYS_LANCE(asic_base); 17457234Sralph cp = (u_char *)ASIC_SYS_ETHER_ADDRESS(asic_base); 17556819Sralph le->sc_r2 = (volatile void *) 17656819Sralph MACH_PHYS_TO_UNCACHED(le_iomem); 17756819Sralph le->sc_ler2pad = 1; 17856819Sralph le->sc_copytobuf = copytobuf_gap16; 17956819Sralph le->sc_copyfrombuf = copyfrombuf_gap16; 18056819Sralph le->sc_zerobuf = bzerobuf_gap16; 18152130Smckusick 18256819Sralph /* 18356819Sralph * And enable Lance dma through the asic. 18456819Sralph */ 18557234Sralph ssr = (volatile u_int *)ASIC_REG_CSR(asic_base); 18656819Sralph ldp = (volatile u_int *) 18757234Sralph ASIC_REG_LANCE_DMAPTR(asic_base); 18856819Sralph *ldp = (le_iomem << 3); /* phys addr << 3 */ 18956819Sralph *ssr |= ASIC_CSR_DMAEN_LANCE; 19056819Sralph break; 19156819Sralph } 19256819Sralph /* 19356819Sralph * Units other than 0 are turbochannel option boards and fall 19456819Sralph * through to DS_3MAX. 19556819Sralph */ 19656819Sralph case DS_3MAX: 19756819Sralph le->sc_r1 = ler1 = (volatile struct lereg1 *) 19856819Sralph (dp->pmax_addr + LE_OFFSET_LANCE); 19956819Sralph le->sc_r2 = (volatile void *)(dp->pmax_addr + LE_OFFSET_RAM); 20056819Sralph cp = (u_char *)(dp->pmax_addr + LE_OFFSET_ROM + 2); 20156819Sralph le->sc_ler2pad = 0; 20256819Sralph le->sc_copytobuf = copytobuf_contig; 20356819Sralph le->sc_copyfrombuf = copyfrombuf_contig; 20456819Sralph le->sc_zerobuf = bzerobuf_contig; 20556819Sralph break; 20656819Sralph default: 20756819Sralph printf("Unknown CPU board type %d\n", pmax_boardtype); 20856819Sralph return (0); 20956819Sralph }; 21056819Sralph 21152695Sralph /* 21256819Sralph * Get the ethernet address out of rom 21352695Sralph */ 21452695Sralph for (i = 0; i < sizeof(le->sc_addr); i++) { 21552695Sralph le->sc_addr[i] = *cp; 21652695Sralph cp += 4; 21752695Sralph } 21852695Sralph 21952130Smckusick /* make sure the chip is stopped */ 22056819Sralph LEWREG(LE_CSR0, ler1->ler1_rap); 22156819Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 22252130Smckusick 22352130Smckusick ifp->if_unit = dp->pmax_unit; 22452130Smckusick ifp->if_name = "le"; 22552130Smckusick ifp->if_mtu = ETHERMTU; 22652130Smckusick ifp->if_init = leinit; 227*59836Sralph ifp->if_reset = lereset; 22852130Smckusick ifp->if_ioctl = leioctl; 22952130Smckusick ifp->if_output = ether_output; 23052130Smckusick ifp->if_start = lestart; 231*59836Sralph #ifdef MULTICAST 232*59836Sralph ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 233*59836Sralph #else 23452130Smckusick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 235*59836Sralph #endif 23652130Smckusick #if NBPFILTER > 0 237*59836Sralph bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 23852130Smckusick #endif 23952130Smckusick if_attach(ifp); 24052130Smckusick 24152695Sralph printf("le%d at nexus0 csr 0x%x priority %d ethernet address %s\n", 24252695Sralph dp->pmax_unit, dp->pmax_addr, dp->pmax_pri, 24352695Sralph ether_sprintf(le->sc_addr)); 24452130Smckusick return (1); 24552130Smckusick } 24652130Smckusick 247*59836Sralph #ifdef MULTICAST 248*59836Sralph /* 249*59836Sralph * Setup the logical address filter 250*59836Sralph */ 251*59836Sralph void 252*59836Sralph lesetladrf(sc) 253*59836Sralph register struct le_softc *sc; 254*59836Sralph { 255*59836Sralph register volatile struct lereg2 *ler2 = sc->sc_r2; 256*59836Sralph register struct ifnet *ifp = &sc->sc_if; 257*59836Sralph register struct ether_multi *enm; 258*59836Sralph register u_char *cp; 259*59836Sralph register u_long crc; 260*59836Sralph register u_long c; 261*59836Sralph register int i, len; 262*59836Sralph struct ether_multistep step; 263*59836Sralph 264*59836Sralph /* 265*59836Sralph * Set up multicast address filter by passing all multicast 266*59836Sralph * addresses through a crc generator, and then using the high 267*59836Sralph * order 6 bits as a index into the 64 bit logical address 268*59836Sralph * filter. The high order two bits select the word, while the 269*59836Sralph * rest of the bits select the bit within the word. 270*59836Sralph */ 271*59836Sralph 272*59836Sralph ler2->ler2_ladrf[0] = 0; 273*59836Sralph ler2->ler2_ladrf[1] = 0; 274*59836Sralph ifp->if_flags &= ~IFF_ALLMULTI; 275*59836Sralph ETHER_FIRST_MULTI(step, &sc->sc_ac, enm); 276*59836Sralph while (enm != NULL) { 277*59836Sralph if (bcmp((caddr_t)&enm->enm_addrlo, 278*59836Sralph (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) == 0) { 279*59836Sralph /* 280*59836Sralph * We must listen to a range of multicast 281*59836Sralph * addresses. For now, just accept all 282*59836Sralph * multicasts, rather than trying to set only 283*59836Sralph * those filter bits needed to match the range. 284*59836Sralph * (At this time, the only use of address 285*59836Sralph * ranges is for IP multicast routing, for 286*59836Sralph * which the range is big enough to require all 287*59836Sralph * bits set.) 288*59836Sralph */ 289*59836Sralph LER2_ladrf0(ler2, 0xff); 290*59836Sralph LER2_ladrf1(ler2, 0xff); 291*59836Sralph LER2_ladrf2(ler2, 0xff); 292*59836Sralph LER2_ladrf3(ler2, 0xff); 293*59836Sralph ifp->if_flags |= IFF_ALLMULTI; 294*59836Sralph return; 295*59836Sralph } 296*59836Sralph 297*59836Sralph cp = (unsigned char *)&enm->enm_addrlo; 298*59836Sralph c = *cp; 299*59836Sralph crc = 0xffffffff; 300*59836Sralph len = 6; 301*59836Sralph while (len-- > 0) { 302*59836Sralph c = *cp; 303*59836Sralph for (i = 0; i < 8; i++) { 304*59836Sralph if ((c & 0x01) ^ (crc & 0x01)) { 305*59836Sralph crc >>= 1; 306*59836Sralph crc = crc ^ 0xedb88320; 307*59836Sralph } 308*59836Sralph else 309*59836Sralph crc >>= 1; 310*59836Sralph c >>= 1; 311*59836Sralph } 312*59836Sralph cp++; 313*59836Sralph } 314*59836Sralph /* Just want the 6 most significant bits. */ 315*59836Sralph crc = crc >> 26; 316*59836Sralph 317*59836Sralph /* Turn on the corresponding bit in the filter. */ 318*59836Sralph ler2->ler2_ladrf[crc >> 5] |= 1 << (crc & 0x1f); 319*59836Sralph 320*59836Sralph ETHER_NEXT_MULTI(step, enm); 321*59836Sralph } 322*59836Sralph } 323*59836Sralph #endif 324*59836Sralph 32556819Sralph ledrinit(le) 32656819Sralph struct le_softc *le; 32752130Smckusick { 32856819Sralph register volatile void *rp; 32952130Smckusick register int i; 33052130Smckusick 33152130Smckusick for (i = 0; i < LERBUF; i++) { 33256819Sralph rp = LER2_RMDADDR(le->sc_r2, i); 33356819Sralph LER2_rmd0(rp, CPU_TO_CHIP_ADDR(ler2_rbuf[i][0])); 33456819Sralph LER2_rmd1(rp, LE_OWN); 33556819Sralph LER2_rmd2(rp, -LEMTU); 33656819Sralph LER2_rmd3(rp, 0); 33752130Smckusick } 33852130Smckusick for (i = 0; i < LETBUF; i++) { 33956819Sralph rp = LER2_TMDADDR(le->sc_r2, i); 34056819Sralph LER2_tmd0(rp, CPU_TO_CHIP_ADDR(ler2_tbuf[i][0])); 34156819Sralph LER2_tmd1(rp, 0); 34256819Sralph LER2_tmd2(rp, 0); 34356819Sralph LER2_tmd3(rp, 0); 34452130Smckusick } 34552130Smckusick } 34652130Smckusick 34752130Smckusick lereset(unit) 34852130Smckusick register int unit; 34952130Smckusick { 35052130Smckusick register struct le_softc *le = &le_softc[unit]; 35152130Smckusick register volatile struct lereg1 *ler1 = le->sc_r1; 35256819Sralph register volatile void *ler2 = le->sc_r2; 35352130Smckusick register int timo = 100000; 35452130Smckusick register int stat; 35552130Smckusick 35652130Smckusick #ifdef lint 35752130Smckusick stat = unit; 35852130Smckusick #endif 35956819Sralph LEWREG(LE_CSR0, ler1->ler1_rap); 36056819Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 36156819Sralph 36256819Sralph /* 36356819Sralph * Setup for transmit/receive 36456819Sralph */ 36552130Smckusick #if NBPFILTER > 0 36652130Smckusick if (le->sc_if.if_flags & IFF_PROMISC) 36752130Smckusick /* set the promiscuous bit */ 368*59836Sralph LER2_mode(ler2, LE_MODE | 0x8000); 36952130Smckusick else 37052130Smckusick #endif 37156819Sralph LER2_mode(ler2, LE_MODE); 37256819Sralph LER2_padr0(ler2, (le->sc_addr[1] << 8) | le->sc_addr[0]); 37356819Sralph LER2_padr1(ler2, (le->sc_addr[3] << 8) | le->sc_addr[2]); 37456819Sralph LER2_padr2(ler2, (le->sc_addr[5] << 8) | le->sc_addr[4]); 375*59836Sralph /* Setup the logical address filter */ 376*59836Sralph #ifdef MULTICAST 377*59836Sralph lesetladrf(le); 37852130Smckusick #else 37956819Sralph LER2_ladrf0(ler2, 0); 38056819Sralph LER2_ladrf1(ler2, 0); 38156819Sralph LER2_ladrf2(ler2, 0); 38256819Sralph LER2_ladrf3(ler2, 0); 38352130Smckusick #endif 38456819Sralph LER2_rlen(ler2, LE_RLEN); 38556819Sralph LER2_rdra(ler2, CPU_TO_CHIP_ADDR(ler2_rmd[0])); 38656819Sralph LER2_tlen(ler2, LE_TLEN); 38756819Sralph LER2_tdra(ler2, CPU_TO_CHIP_ADDR(ler2_tmd[0])); 38856819Sralph ledrinit(le); 38952130Smckusick le->sc_rmd = 0; 39052130Smckusick le->sc_tmd = LETBUF - 1; 39152130Smckusick le->sc_tmdnext = 0; 39252130Smckusick 39356819Sralph LEWREG(LE_CSR1, ler1->ler1_rap); 39456819Sralph LEWREG(CPU_TO_CHIP_ADDR(ler2_mode), ler1->ler1_rdp); 39556819Sralph LEWREG(LE_CSR2, ler1->ler1_rap); 39656819Sralph LEWREG(0, ler1->ler1_rdp); 39756819Sralph LEWREG(LE_CSR3, ler1->ler1_rap); 39856819Sralph LEWREG(0, ler1->ler1_rdp); 39956819Sralph LEWREG(LE_CSR0, ler1->ler1_rap); 40052130Smckusick LERDWR(ler0, LE_INIT, ler1->ler1_rdp); 40152130Smckusick do { 40252130Smckusick if (--timo == 0) { 40352130Smckusick printf("le%d: init timeout, stat = 0x%x\n", 40452130Smckusick unit, stat); 40552130Smckusick break; 40652130Smckusick } 40756819Sralph stat = ler1->ler1_rdp; 40852130Smckusick } while ((stat & LE_IDON) == 0); 40952130Smckusick LERDWR(ler0, LE_IDON, ler1->ler1_rdp); 41052130Smckusick LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); 41152130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 41252130Smckusick } 41352130Smckusick 41452130Smckusick /* 41552130Smckusick * Initialization of interface 41652130Smckusick */ 41752130Smckusick leinit(unit) 41852130Smckusick int unit; 41952130Smckusick { 420*59836Sralph register struct ifnet *ifp = &le_softc[unit].sc_if; 421*59836Sralph register struct ifaddr *ifa; 42252130Smckusick int s; 42352130Smckusick 42452130Smckusick /* not yet, if address still unknown */ 425*59836Sralph for (ifa = ifp->if_addrlist;; ifa = ifa->ifa_next) 426*59836Sralph if (ifa == 0) 427*59836Sralph return; 428*59836Sralph else if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK) 429*59836Sralph break; 43052130Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 43152130Smckusick s = splnet(); 43252130Smckusick ifp->if_flags |= IFF_RUNNING; 43352130Smckusick lereset(unit); 43452130Smckusick (void) lestart(ifp); 43552130Smckusick splx(s); 43652130Smckusick } 43752130Smckusick } 43852130Smckusick 43952130Smckusick #define LENEXTTMP \ 44056819Sralph if (++bix == LETBUF) \ 44156819Sralph bix = 0; \ 44256819Sralph tmd = LER2_TMDADDR(le->sc_r2, bix) 44352130Smckusick 44452130Smckusick /* 44552130Smckusick * Start output on interface. Get another datagram to send 44652130Smckusick * off of the interface queue, and copy it to the interface 44752130Smckusick * before starting the output. 44852130Smckusick */ 44952130Smckusick lestart(ifp) 45052130Smckusick struct ifnet *ifp; 45152130Smckusick { 45252130Smckusick register struct le_softc *le = &le_softc[ifp->if_unit]; 45352130Smckusick register int bix = le->sc_tmdnext; 45456819Sralph register volatile void *tmd = LER2_TMDADDR(le->sc_r2, bix); 45552130Smckusick register struct mbuf *m; 45652130Smckusick int len = 0; 45752130Smckusick 45852130Smckusick if ((le->sc_if.if_flags & IFF_RUNNING) == 0) 45952130Smckusick return (0); 46052130Smckusick while (bix != le->sc_tmd) { 46156819Sralph if (LER2V_tmd1(tmd) & LE_OWN) 46252130Smckusick panic("lestart"); 46352130Smckusick IF_DEQUEUE(&le->sc_if.if_snd, m); 46452130Smckusick if (m == 0) 46552130Smckusick break; 466*59836Sralph len = leput(le, LER2_TBUFADDR(le->sc_r2, bix), m); 46752130Smckusick #if NBPFILTER > 0 46852130Smckusick /* 46952130Smckusick * If bpf is listening on this interface, let it 47052130Smckusick * see the packet before we commit it to the wire. 47152130Smckusick */ 472*59836Sralph if (ifp->if_bpf) 473*59836Sralph bpf_tap(ifp->if_bpf, 474*59836Sralph LER2_TBUFADDR(le->sc_r2, le->sc_tmd), len); 47552130Smckusick #endif 47656819Sralph LER2_tmd3(tmd, 0); 47756819Sralph LER2_tmd2(tmd, -len); 47856819Sralph LER2_tmd1(tmd, LE_OWN | LE_STP | LE_ENP); 47952130Smckusick LENEXTTMP; 48052130Smckusick } 48152130Smckusick if (len != 0) { 48252130Smckusick le->sc_if.if_flags |= IFF_OACTIVE; 48352130Smckusick LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp); 48452130Smckusick } 48552130Smckusick le->sc_tmdnext = bix; 48652130Smckusick return (0); 48752130Smckusick } 48852130Smckusick 48952130Smckusick /* 49052130Smckusick * Process interrupts from the 7990 chip. 49152130Smckusick */ 49252695Sralph void 49352695Sralph leintr(unit) 49452695Sralph int unit; 49552130Smckusick { 49652130Smckusick register struct le_softc *le; 49752130Smckusick register volatile struct lereg1 *ler1; 49852695Sralph register int stat; 49952130Smckusick 50052130Smckusick le = &le_softc[unit]; 50152130Smckusick ler1 = le->sc_r1; 50252130Smckusick stat = ler1->ler1_rdp; 50352130Smckusick if (!(stat & LE_INTR)) { 50453081Sralph printf("le%d: spurrious interrupt\n", unit); 50552130Smckusick return; 50652130Smckusick } 50752130Smckusick if (stat & LE_SERR) { 50852130Smckusick leerror(unit, stat); 50952130Smckusick if (stat & LE_MERR) { 51052130Smckusick le->sc_merr++; 51152130Smckusick lereset(unit); 51252130Smckusick return; 51352130Smckusick } 51452130Smckusick if (stat & LE_BABL) 51552130Smckusick le->sc_babl++; 51652130Smckusick if (stat & LE_CERR) 51752130Smckusick le->sc_cerr++; 51852130Smckusick if (stat & LE_MISS) 51952130Smckusick le->sc_miss++; 52052130Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); 52152130Smckusick } 52252130Smckusick if ((stat & LE_RXON) == 0) { 52352130Smckusick le->sc_rxoff++; 52452130Smckusick lereset(unit); 52552130Smckusick return; 52652130Smckusick } 52752130Smckusick if ((stat & LE_TXON) == 0) { 52852130Smckusick le->sc_txoff++; 52952130Smckusick lereset(unit); 53052130Smckusick return; 53152130Smckusick } 53252130Smckusick if (stat & LE_RINT) { 53352130Smckusick /* interrupt is cleared in lerint */ 53452130Smckusick lerint(unit); 53552130Smckusick } 53652130Smckusick if (stat & LE_TINT) { 53752130Smckusick LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp); 53852130Smckusick lexint(unit); 53952130Smckusick } 54052130Smckusick } 54152130Smckusick 54252130Smckusick /* 54352130Smckusick * Ethernet interface transmitter interrupt. 54452130Smckusick * Start another output if more data to send. 54552130Smckusick */ 54652130Smckusick lexint(unit) 54752130Smckusick register int unit; 54852130Smckusick { 54952130Smckusick register struct le_softc *le = &le_softc[unit]; 55052130Smckusick register int bix = le->sc_tmd; 55156819Sralph register volatile void *tmd; 55252130Smckusick 55352130Smckusick if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { 55452130Smckusick le->sc_xint++; 55552130Smckusick return; 55652130Smckusick } 55752130Smckusick LENEXTTMP; 55856819Sralph while (bix != le->sc_tmdnext && (LER2V_tmd1(tmd) & LE_OWN) == 0) { 55952130Smckusick le->sc_tmd = bix; 56056819Sralph if ((LER2V_tmd1(tmd) & LE_ERR) || (LER2V_tmd3(tmd) & LE_TBUFF)) { 56152130Smckusick lexerror(unit); 56252130Smckusick le->sc_if.if_oerrors++; 56356819Sralph if (LER2V_tmd3(tmd) & (LE_TBUFF|LE_UFLO)) { 56452130Smckusick le->sc_uflo++; 56552130Smckusick lereset(unit); 56652130Smckusick break; 56752130Smckusick } 56856819Sralph else if (LER2V_tmd3(tmd) & LE_LCOL) 56952130Smckusick le->sc_if.if_collisions++; 57056819Sralph else if (LER2V_tmd3(tmd) & LE_RTRY) 57152130Smckusick le->sc_if.if_collisions += 16; 57252130Smckusick } 57356819Sralph else if (LER2V_tmd1(tmd) & LE_ONE) 57452130Smckusick le->sc_if.if_collisions++; 57556819Sralph else if (LER2V_tmd1(tmd) & LE_MORE) 57652130Smckusick /* what is the real number? */ 57752130Smckusick le->sc_if.if_collisions += 2; 57852130Smckusick else 57952130Smckusick le->sc_if.if_opackets++; 58052130Smckusick LENEXTTMP; 58152130Smckusick } 58252130Smckusick if (bix == le->sc_tmdnext) 58352130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 58452130Smckusick (void) lestart(&le->sc_if); 58552130Smckusick } 58652130Smckusick 58752130Smckusick #define LENEXTRMP \ 58856819Sralph if (++bix == LERBUF) \ 58956819Sralph bix = 0; \ 59056819Sralph rmd = LER2_RMDADDR(le->sc_r2, bix) 59152130Smckusick 59252130Smckusick /* 59352130Smckusick * Ethernet interface receiver interrupt. 59452130Smckusick * If input error just drop packet. 59552130Smckusick * Decapsulate packet based on type and pass to type specific 59652130Smckusick * higher-level input routine. 59752130Smckusick */ 59852130Smckusick lerint(unit) 59952130Smckusick int unit; 60052130Smckusick { 60152130Smckusick register struct le_softc *le = &le_softc[unit]; 60252130Smckusick register int bix = le->sc_rmd; 60356819Sralph register volatile void *rmd = LER2_RMDADDR(le->sc_r2, bix); 60452130Smckusick 60552130Smckusick /* 60652130Smckusick * Out of sync with hardware, should never happen? 60752130Smckusick */ 60856819Sralph if (LER2V_rmd1(rmd) & LE_OWN) { 609*59836Sralph le->sc_rown++; 61052130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 61152130Smckusick return; 61252130Smckusick } 61352130Smckusick 61452130Smckusick /* 61552130Smckusick * Process all buffers with valid data 61652130Smckusick */ 61756819Sralph while ((LER2V_rmd1(rmd) & LE_OWN) == 0) { 61856819Sralph int len = LER2V_rmd3(rmd); 61952130Smckusick 62052130Smckusick /* Clear interrupt to avoid race condition */ 62152130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 62252130Smckusick 62356819Sralph if (LER2V_rmd1(rmd) & LE_ERR) { 62452130Smckusick le->sc_rmd = bix; 62552130Smckusick lererror(unit, "bad packet"); 62652130Smckusick le->sc_if.if_ierrors++; 62756819Sralph } else if ((LER2V_rmd1(rmd) & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 62852130Smckusick /* 62952130Smckusick * Find the end of the packet so we can see how long 63052130Smckusick * it was. We still throw it away. 63152130Smckusick */ 63252130Smckusick do { 63352130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, 63452130Smckusick le->sc_r1->ler1_rdp); 63556819Sralph LER2_rmd3(rmd, 0); 63656819Sralph LER2_rmd1(rmd, LE_OWN); 63752130Smckusick LENEXTRMP; 63856819Sralph } while (!(LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 63952130Smckusick le->sc_rmd = bix; 64052130Smckusick lererror(unit, "chained buffer"); 64152130Smckusick le->sc_rxlen++; 64252130Smckusick /* 64352130Smckusick * If search terminated without successful completion 64452130Smckusick * we reset the hardware (conservative). 64552130Smckusick */ 64656819Sralph if ((LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 64752130Smckusick LE_ENP) { 64852130Smckusick lereset(unit); 64952130Smckusick return; 65052130Smckusick } 65152130Smckusick } else 65256819Sralph leread(unit, LER2_RBUFADDR(le->sc_r2, bix), len); 65356819Sralph LER2_rmd3(rmd, 0); 65456819Sralph LER2_rmd1(rmd, LE_OWN); 65552130Smckusick LENEXTRMP; 65652130Smckusick } 65752130Smckusick MachEmptyWriteBuffer(); /* Paranoia */ 65852130Smckusick le->sc_rmd = bix; 65952130Smckusick } 66052130Smckusick 66152130Smckusick /* 66252130Smckusick * Look at the packet in network buffer memory so we can be smart about how 66352130Smckusick * we copy the data into mbufs. 66452130Smckusick * This needs work since we can't just read network buffer memory like 66552130Smckusick * regular memory. 66652130Smckusick */ 66752130Smckusick leread(unit, buf, len) 66852130Smckusick int unit; 66956819Sralph volatile void *buf; 67052130Smckusick int len; 67152130Smckusick { 67252130Smckusick register struct le_softc *le = &le_softc[unit]; 67352130Smckusick struct ether_header et; 67456819Sralph struct mbuf *m, **hdrmp, **tailmp; 675*59836Sralph int off, resid, flags; 67656819Sralph u_short sbuf[2], eth_type; 67752695Sralph extern struct mbuf *leget(); 67852130Smckusick 67952130Smckusick le->sc_if.if_ipackets++; 68056819Sralph (*le->sc_copyfrombuf)(buf, 0, (char *)&et, sizeof (et)); 68156819Sralph eth_type = ntohs(et.ether_type); 68252130Smckusick /* adjust input length to account for header and CRC */ 68352130Smckusick len = len - sizeof(struct ether_header) - 4; 68452130Smckusick 68556819Sralph if (eth_type >= ETHERTYPE_TRAIL && 68656819Sralph eth_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 68756819Sralph off = (eth_type - ETHERTYPE_TRAIL) * 512; 68852130Smckusick if (off >= ETHERMTU) 68952130Smckusick return; /* sanity */ 69056819Sralph (*le->sc_copyfrombuf)(buf, sizeof (et) + off, (char *)sbuf, 69156819Sralph sizeof (sbuf)); 69256819Sralph eth_type = ntohs(sbuf[0]); 69352130Smckusick resid = ntohs(sbuf[1]); 69452130Smckusick if (off + resid > len) 69552130Smckusick return; /* sanity */ 69652130Smckusick len = off + resid; 69752130Smckusick } else 69852130Smckusick off = 0; 69952130Smckusick 70052130Smckusick if (len <= 0) { 70152130Smckusick if (ledebug) 70252130Smckusick log(LOG_WARNING, 70352130Smckusick "le%d: ierror(runt packet): from %s: len=%d\n", 70452130Smckusick unit, ether_sprintf(et.ether_shost), len); 70552130Smckusick le->sc_runt++; 70652130Smckusick le->sc_if.if_ierrors++; 70752130Smckusick return; 70852130Smckusick } 709*59836Sralph flags = 0; 710*59836Sralph if (bcmp((caddr_t)etherbroadcastaddr, 711*59836Sralph (caddr_t)et.ether_dhost, sizeof(etherbroadcastaddr)) == 0) 712*59836Sralph flags |= M_BCAST; 713*59836Sralph if (et.ether_dhost[0] & 1) 714*59836Sralph flags |= M_MCAST; 71552130Smckusick 716*59836Sralph #if NBPFILTER > 0 71752130Smckusick /* 718*59836Sralph * Check if there's a bpf filter listening on this interface. 719*59836Sralph * If so, hand off the raw packet to enet. 720*59836Sralph */ 721*59836Sralph if (le->sc_if.if_bpf) { 722*59836Sralph bpf_tap(le->sc_if.if_bpf, buf, len + sizeof(struct ether_header)); 723*59836Sralph 724*59836Sralph /* 725*59836Sralph * Keep the packet if it's a broadcast or has our 726*59836Sralph * physical ethernet address (or if we support 727*59836Sralph * multicast and it's one). 728*59836Sralph */ 729*59836Sralph if ( 730*59836Sralph #ifdef MULTICAST 731*59836Sralph (flags & (M_BCAST | M_MCAST)) == 0 && 732*59836Sralph #else 733*59836Sralph (flags & M_BCAST) == 0 && 734*59836Sralph #endif 735*59836Sralph bcmp(et.ether_dhost, le->sc_addr, 736*59836Sralph sizeof(et.ether_dhost)) != 0) 737*59836Sralph return; 738*59836Sralph } 739*59836Sralph #endif 740*59836Sralph 741*59836Sralph /* 74252130Smckusick * Pull packet off interface. Off is nonzero if packet 74352130Smckusick * has trailing header; leget will then force this header 74452130Smckusick * information to be at the front, but we still have to drop 74552130Smckusick * the type and length which are at the front of any trailer data. 74656819Sralph * The hdrmp and tailmp pointers are used by lebpf_tap() to 74756819Sralph * temporarily reorder the mbuf list. See the comment at the beginning 74856819Sralph * of lebpf_tap() for all the ugly details. 74952130Smckusick */ 75056819Sralph m = leget(le, buf, len, off, &le->sc_if, &hdrmp, &tailmp); 75152130Smckusick if (m == 0) 75252130Smckusick return; 753*59836Sralph m->m_flags |= flags; 75456819Sralph et.ether_type = eth_type; 75552130Smckusick ether_input(&le->sc_if, &et, m); 75652130Smckusick } 75752130Smckusick 75852130Smckusick /* 75952130Smckusick * Routine to copy from mbuf chain to transmit buffer in 76052130Smckusick * network buffer memory. 76152130Smckusick */ 76256819Sralph leput(le, lebuf, m) 76356819Sralph struct le_softc *le; 76456819Sralph register volatile void *lebuf; 76552130Smckusick register struct mbuf *m; 76652130Smckusick { 76752130Smckusick register struct mbuf *mp; 76852695Sralph register int len, tlen = 0; 76956819Sralph register int boff = 0; 77052130Smckusick 77152130Smckusick for (mp = m; mp; mp = mp->m_next) { 77252130Smckusick len = mp->m_len; 77352130Smckusick if (len == 0) 77452130Smckusick continue; 77556819Sralph (*le->sc_copytobuf)(mtod(mp, char *), lebuf, boff, len); 77652130Smckusick tlen += len; 77756819Sralph boff += len; 77852130Smckusick } 77952130Smckusick m_freem(m); 78052695Sralph if (tlen < LEMINSIZE) { 78156819Sralph (*le->sc_zerobuf)(lebuf, boff, LEMINSIZE - tlen); 78252130Smckusick tlen = LEMINSIZE; 78352695Sralph } 78452130Smckusick return(tlen); 78552130Smckusick } 78652130Smckusick 78752130Smckusick /* 78852130Smckusick * Routine to copy from network buffer memory into mbufs. 78952130Smckusick */ 79052130Smckusick struct mbuf * 79156819Sralph leget(le, lebuf, totlen, off, ifp, hdrmp, tailmp) 79256819Sralph struct le_softc *le; 79356819Sralph volatile void *lebuf; 79452130Smckusick int totlen, off; 79552130Smckusick struct ifnet *ifp; 79656819Sralph struct mbuf ***hdrmp, ***tailmp; 79752130Smckusick { 79852130Smckusick register struct mbuf *m; 79952130Smckusick struct mbuf *top = 0, **mp = ⊤ 80056819Sralph register int len, resid, boff; 80152130Smckusick 80252130Smckusick /* NOTE: sizeof(struct ether_header) should be even */ 80356819Sralph boff = sizeof(struct ether_header); 80452130Smckusick if (off) { 80552130Smckusick /* NOTE: off should be even */ 80656819Sralph boff += off + 2 * sizeof(u_short); 80752130Smckusick totlen -= 2 * sizeof(u_short); 80852130Smckusick resid = totlen - off; 80952130Smckusick } else 81052130Smckusick resid = totlen; 81152130Smckusick 81252130Smckusick MGETHDR(m, M_DONTWAIT, MT_DATA); 81352130Smckusick if (m == 0) 81452130Smckusick return (0); 81552130Smckusick m->m_pkthdr.rcvif = ifp; 81652130Smckusick m->m_pkthdr.len = totlen; 81752130Smckusick m->m_len = MHLEN; 81852130Smckusick 81952130Smckusick while (totlen > 0) { 82052130Smckusick if (top) { 82152130Smckusick MGET(m, M_DONTWAIT, MT_DATA); 82252130Smckusick if (m == 0) { 82352130Smckusick m_freem(top); 82452130Smckusick return (0); 82552130Smckusick } 82652130Smckusick m->m_len = MLEN; 82752130Smckusick } 82852130Smckusick 82952130Smckusick if (resid >= MINCLSIZE) 83052130Smckusick MCLGET(m, M_DONTWAIT); 83152130Smckusick if (m->m_flags & M_EXT) 83255745Sralph m->m_len = min(resid, MCLBYTES); 83352130Smckusick else if (resid < m->m_len) { 83452130Smckusick /* 83552130Smckusick * Place initial small packet/header at end of mbuf. 83652130Smckusick */ 83752130Smckusick if (top == 0 && resid + max_linkhdr <= m->m_len) 83852130Smckusick m->m_data += max_linkhdr; 83952130Smckusick m->m_len = resid; 84052130Smckusick } 84152130Smckusick len = m->m_len; 84256819Sralph (*le->sc_copyfrombuf)(lebuf, boff, mtod(m, char *), len); 84356819Sralph boff += len; 84452130Smckusick *mp = m; 84552130Smckusick mp = &m->m_next; 84652130Smckusick totlen -= len; 84752130Smckusick resid -= len; 84852130Smckusick if (resid == 0) { 84956819Sralph boff = sizeof (struct ether_header); 85052130Smckusick resid = totlen; 85156819Sralph *hdrmp = mp; 85252130Smckusick } 85352130Smckusick } 85456819Sralph *tailmp = mp; 85552130Smckusick return (top); 85652130Smckusick } 85752130Smckusick 85852130Smckusick /* 85952130Smckusick * Process an ioctl request. 86052130Smckusick */ 86152130Smckusick leioctl(ifp, cmd, data) 86252130Smckusick register struct ifnet *ifp; 86352130Smckusick int cmd; 86452130Smckusick caddr_t data; 86552130Smckusick { 86652130Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 86752130Smckusick struct le_softc *le = &le_softc[ifp->if_unit]; 86852130Smckusick volatile struct lereg1 *ler1 = le->sc_r1; 86952130Smckusick int s, error = 0; 87052130Smckusick 87152130Smckusick s = splnet(); 87252130Smckusick switch (cmd) { 87352130Smckusick 87452130Smckusick case SIOCSIFADDR: 87552130Smckusick ifp->if_flags |= IFF_UP; 87652130Smckusick switch (ifa->ifa_addr->sa_family) { 87752130Smckusick #ifdef INET 87852130Smckusick case AF_INET: 87952130Smckusick leinit(ifp->if_unit); /* before arpwhohas */ 88052130Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 88152130Smckusick IA_SIN(ifa)->sin_addr; 88252130Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 88352130Smckusick break; 88452130Smckusick #endif 88552130Smckusick #ifdef NS 88652130Smckusick case AF_NS: 88752130Smckusick { 88852130Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 88952130Smckusick 89052130Smckusick if (ns_nullhost(*ina)) 89152130Smckusick ina->x_host = *(union ns_host *)(le->sc_addr); 89252130Smckusick else { 89352130Smckusick /* 89452130Smckusick * The manual says we can't change the address 89552130Smckusick * while the receiver is armed, 89652130Smckusick * so reset everything 89752130Smckusick */ 89852130Smckusick ifp->if_flags &= ~IFF_RUNNING; 899*59836Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 90052130Smckusick bcopy((caddr_t)ina->x_host.c_host, 90152130Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 90252130Smckusick } 90352130Smckusick leinit(ifp->if_unit); /* does le_setaddr() */ 90452130Smckusick break; 90552130Smckusick } 90652130Smckusick #endif 90752130Smckusick default: 90852130Smckusick leinit(ifp->if_unit); 90952130Smckusick break; 91052130Smckusick } 91152130Smckusick break; 91252130Smckusick 913*59836Sralph #if defined (CCITT) && defined (LLC) 914*59836Sralph case SIOCSIFCONF_X25: 915*59836Sralph ifp->if_flags |= IFF_UP; 916*59836Sralph ifa->ifa_rtrequest = cons_rtrequest; 917*59836Sralph error = x25_llcglue(PRC_IFUP, ifa->ifa_addr); 918*59836Sralph if (error == 0) 919*59836Sralph leinit(ifp->if_unit); 920*59836Sralph break; 921*59836Sralph #endif /* CCITT && LLC */ 922*59836Sralph 92352130Smckusick case SIOCSIFFLAGS: 92452130Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 92552130Smckusick ifp->if_flags & IFF_RUNNING) { 92656819Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 92752130Smckusick ifp->if_flags &= ~IFF_RUNNING; 92852130Smckusick } else if (ifp->if_flags & IFF_UP && 92952130Smckusick (ifp->if_flags & IFF_RUNNING) == 0) 93052130Smckusick leinit(ifp->if_unit); 93152130Smckusick /* 93252130Smckusick * If the state of the promiscuous bit changes, the interface 93352130Smckusick * must be reset to effect the change. 93452130Smckusick */ 93552130Smckusick if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && 93652130Smckusick (ifp->if_flags & IFF_RUNNING)) { 93752130Smckusick le->sc_iflags = ifp->if_flags; 93852130Smckusick lereset(ifp->if_unit); 93952130Smckusick lestart(ifp); 94052130Smckusick } 94152130Smckusick break; 94252130Smckusick 943*59836Sralph #ifdef MULTICAST 944*59836Sralph case SIOCADDMULTI: 945*59836Sralph case SIOCDELMULTI: 946*59836Sralph /* Update our multicast list */ 947*59836Sralph error = (cmd == SIOCADDMULTI) ? 948*59836Sralph ether_addmulti((struct ifreq *)data, &le->sc_ac) : 949*59836Sralph ether_delmulti((struct ifreq *)data, &le->sc_ac); 950*59836Sralph 951*59836Sralph if (error == ENETRESET) { 952*59836Sralph /* 953*59836Sralph * Multicast list has changed; set the hardware 954*59836Sralph * filter accordingly. 955*59836Sralph */ 956*59836Sralph lereset(ifp->if_unit); 957*59836Sralph error = 0; 958*59836Sralph } 959*59836Sralph break; 960*59836Sralph #endif 961*59836Sralph 96252130Smckusick default: 96352130Smckusick error = EINVAL; 96452130Smckusick } 96552130Smckusick splx(s); 96652130Smckusick return (error); 96752130Smckusick } 96852130Smckusick 96952130Smckusick leerror(unit, stat) 97052130Smckusick int unit; 97152130Smckusick int stat; 97252130Smckusick { 97352130Smckusick if (!ledebug) 97452130Smckusick return; 97552130Smckusick 97652130Smckusick /* 97752130Smckusick * Not all transceivers implement heartbeat 97852130Smckusick * so we only log CERR once. 97952130Smckusick */ 98052130Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 98152130Smckusick return; 98252130Smckusick log(LOG_WARNING, 98352130Smckusick "le%d: error: stat=%b\n", unit, 98452130Smckusick stat, 98552130Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 98652130Smckusick } 98752130Smckusick 98852130Smckusick lererror(unit, msg) 98952130Smckusick int unit; 99052130Smckusick char *msg; 99152130Smckusick { 99252130Smckusick register struct le_softc *le = &le_softc[unit]; 99356819Sralph register volatile void *rmd; 99454144Sralph u_char eaddr[6]; 99552130Smckusick int len; 99652130Smckusick 99752130Smckusick if (!ledebug) 99852130Smckusick return; 99952130Smckusick 100056819Sralph rmd = LER2_RMDADDR(le->sc_r2, le->sc_rmd); 100156819Sralph len = LER2V_rmd3(rmd); 100256819Sralph if (len > 11) 100356819Sralph (*le->sc_copyfrombuf)(LER2_RBUFADDR(le->sc_r2, le->sc_rmd), 100456819Sralph 6, eaddr, 6); 100552130Smckusick log(LOG_WARNING, 100652130Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 100756819Sralph unit, msg, 100856819Sralph len > 11 ? ether_sprintf(eaddr) : "unknown", 100956819Sralph le->sc_rmd, len, 101056819Sralph LER2V_rmd1(rmd), 101152130Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 101252130Smckusick } 101352130Smckusick 101452130Smckusick lexerror(unit) 101552130Smckusick int unit; 101652130Smckusick { 101752130Smckusick register struct le_softc *le = &le_softc[unit]; 101856819Sralph register volatile void *tmd; 101954144Sralph u_char eaddr[6]; 102052130Smckusick int len; 102152130Smckusick 102252130Smckusick if (!ledebug) 102352130Smckusick return; 102452130Smckusick 102556819Sralph tmd = LER2_TMDADDR(le->sc_r2, 0); 102656819Sralph len = -LER2V_tmd2(tmd); 102756819Sralph if (len > 5) 102856819Sralph (*le->sc_copyfrombuf)(LER2_TBUFADDR(le->sc_r2, 0), 0, eaddr, 6); 102952130Smckusick log(LOG_WARNING, 103052130Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 103156819Sralph unit, 103256819Sralph len > 5 ? ether_sprintf(eaddr) : "unknown", 103356819Sralph 0, len, 103456819Sralph LER2V_tmd1(tmd), 103552130Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 103656819Sralph LER2V_tmd3(tmd), 103752130Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 103852130Smckusick } 103956819Sralph 104056819Sralph /* 104156819Sralph * Write a lance register port, reading it back to ensure success. This seems 104256819Sralph * to be necessary during initialization, since the chip appears to be a bit 104356819Sralph * pokey sometimes. 104456819Sralph */ 104556819Sralph static void 104656819Sralph lewritereg(regptr, val) 104756819Sralph register volatile u_short *regptr; 104856819Sralph register u_short val; 104956819Sralph { 105056819Sralph register int i = 0; 105156819Sralph 105256819Sralph while (*regptr != val) { 105356819Sralph *regptr = val; 105456819Sralph MachEmptyWriteBuffer(); 105556819Sralph if (++i > 10000) { 105656819Sralph printf("le: Reg did not settle (to x%x): x%x\n", 105756819Sralph val, *regptr); 105856819Sralph return; 105956819Sralph } 106056819Sralph DELAY(100); 106156819Sralph } 106256819Sralph } 106356819Sralph 106456819Sralph /* 106556819Sralph * Routines for accessing the transmit and receive buffers. Unfortunately, 106656819Sralph * CPU addressing of these buffers is done in one of 3 ways: 106756819Sralph * - contiguous (for the 3max and turbochannel option card) 106856819Sralph * - gap2, which means shorts (2 bytes) interspersed with short (2 byte) 106956819Sralph * spaces (for the pmax) 107056819Sralph * - gap16, which means 16bytes interspersed with 16byte spaces 107156819Sralph * for buffers which must begin on a 32byte boundary (for 3min and maxine) 107256819Sralph * The buffer offset is the logical byte offset, assuming contiguous storage. 107356819Sralph */ 107456819Sralph void 107556819Sralph copytobuf_contig(from, lebuf, boff, len) 107656819Sralph char *from; 107756819Sralph volatile void *lebuf; 107856819Sralph int boff; 107956819Sralph int len; 108056819Sralph { 108156819Sralph 108256819Sralph /* 108356819Sralph * Just call bcopy() to do the work. 108456819Sralph */ 108556819Sralph bcopy(from, ((char *)lebuf) + boff, len); 108656819Sralph } 108756819Sralph 108856819Sralph void 108956819Sralph copyfrombuf_contig(lebuf, boff, to, len) 109056819Sralph volatile void *lebuf; 109156819Sralph int boff; 109256819Sralph char *to; 109356819Sralph int len; 109456819Sralph { 109556819Sralph 109656819Sralph /* 109756819Sralph * Just call bcopy() to do the work. 109856819Sralph */ 109956819Sralph bcopy(((char *)lebuf) + boff, to, len); 110056819Sralph } 110156819Sralph 110256819Sralph void 110356819Sralph bzerobuf_contig(lebuf, boff, len) 110456819Sralph volatile void *lebuf; 110556819Sralph int boff; 110656819Sralph int len; 110756819Sralph { 110856819Sralph 110956819Sralph /* 111056819Sralph * Just let bzero() do the work 111156819Sralph */ 111256819Sralph bzero(((char *)lebuf) + boff, len); 111356819Sralph } 111456819Sralph 111556819Sralph /* 111656819Sralph * For the pmax the buffer consists of shorts (2 bytes) interspersed with 111756819Sralph * short (2 byte) spaces and must be accessed with halfword load/stores. 111856819Sralph * (don't worry about doing an extra byte) 111956819Sralph */ 112056819Sralph void 112156819Sralph copytobuf_gap2(from, lebuf, boff, len) 112256819Sralph register char *from; 112356819Sralph volatile void *lebuf; 112456819Sralph int boff; 112556819Sralph register int len; 112656819Sralph { 112756819Sralph register volatile u_short *bptr; 112856819Sralph register int xfer; 112956819Sralph 113056819Sralph if (boff & 0x1) { 113156819Sralph /* handle unaligned first byte */ 113256819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 113356819Sralph *bptr = (*from++ << 8) | (*bptr & 0xff); 113456819Sralph bptr += 2; 113556819Sralph len--; 113656819Sralph } else 113756819Sralph bptr = ((volatile u_short *)lebuf) + boff; 113856819Sralph if ((unsigned)from & 0x1) { 113956819Sralph while (len > 1) { 114056819Sralph *bptr = (from[1] << 8) | from[0]; 114156819Sralph bptr += 2; 114256819Sralph from += 2; 114356819Sralph len -= 2; 114456819Sralph } 114556819Sralph } else { 114656819Sralph /* optimize for aligned transfers */ 114756819Sralph xfer = (int)((unsigned)len & ~0x1); 114856819Sralph CopyToBuffer((u_short *)from, bptr, xfer); 114956819Sralph bptr += xfer; 115056819Sralph from += xfer; 115156819Sralph len -= xfer; 115256819Sralph } 115356819Sralph if (len == 1) 115456819Sralph *bptr = (u_short)*from; 115556819Sralph } 115656819Sralph 115756819Sralph void 115856819Sralph copyfrombuf_gap2(lebuf, boff, to, len) 115956819Sralph volatile void *lebuf; 116056819Sralph int boff; 116156819Sralph register char *to; 116256819Sralph register int len; 116356819Sralph { 116456819Sralph register volatile u_short *bptr; 116556819Sralph register u_short tmp; 116656819Sralph register int xfer; 116756819Sralph 116856819Sralph if (boff & 0x1) { 116956819Sralph /* handle unaligned first byte */ 117056819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 117156819Sralph *to++ = (*bptr >> 8) & 0xff; 117256819Sralph bptr += 2; 117356819Sralph len--; 117456819Sralph } else 117556819Sralph bptr = ((volatile u_short *)lebuf) + boff; 117656819Sralph if ((unsigned)to & 0x1) { 117756819Sralph while (len > 1) { 117856819Sralph tmp = *bptr; 117956819Sralph *to++ = tmp & 0xff; 118056819Sralph *to++ = (tmp >> 8) & 0xff; 118156819Sralph bptr += 2; 118256819Sralph len -= 2; 118356819Sralph } 118456819Sralph } else { 118556819Sralph /* optimize for aligned transfers */ 118656819Sralph xfer = (int)((unsigned)len & ~0x1); 118756819Sralph CopyFromBuffer(bptr, to, xfer); 118856819Sralph bptr += xfer; 118956819Sralph to += xfer; 119056819Sralph len -= xfer; 119156819Sralph } 119256819Sralph if (len == 1) 119356819Sralph *to = *bptr & 0xff; 119456819Sralph } 119556819Sralph 119656819Sralph void 119756819Sralph bzerobuf_gap2(lebuf, boff, len) 119856819Sralph volatile void *lebuf; 119956819Sralph int boff; 120056819Sralph int len; 120156819Sralph { 120256819Sralph register volatile u_short *bptr; 120356819Sralph 120456819Sralph if ((unsigned)boff & 0x1) { 120556819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 120656819Sralph *bptr &= 0xff; 120756819Sralph bptr += 2; 120856819Sralph len--; 120956819Sralph } else 121056819Sralph bptr = ((volatile u_short *)lebuf) + boff; 121156819Sralph while (len > 0) { 121256819Sralph *bptr = 0; 121356819Sralph bptr += 2; 121456819Sralph len -= 2; 121556819Sralph } 121656819Sralph } 121756819Sralph 121856819Sralph /* 121956819Sralph * For the 3min and maxine, the buffers are in main memory filled in with 122056819Sralph * 16byte blocks interspersed with 16byte spaces. 122156819Sralph */ 122256819Sralph void 122356819Sralph copytobuf_gap16(from, lebuf, boff, len) 122456819Sralph register char *from; 122556819Sralph volatile void *lebuf; 122656819Sralph int boff; 122756819Sralph register int len; 122856819Sralph { 122956819Sralph register char *bptr; 123056819Sralph register int xfer; 123156819Sralph 123256819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 123356819Sralph boff &= 0xf; 123456819Sralph xfer = min(len, 16 - boff); 123556819Sralph while (len > 0) { 123656819Sralph bcopy(from, ((char *)bptr) + boff, xfer); 123756819Sralph from += xfer; 123856819Sralph bptr += 32; 123956819Sralph boff = 0; 124056819Sralph len -= xfer; 124156819Sralph xfer = min(len, 16); 124256819Sralph } 124356819Sralph } 124456819Sralph 124556819Sralph void 124656819Sralph copyfrombuf_gap16(lebuf, boff, to, len) 124756819Sralph volatile void *lebuf; 124856819Sralph int boff; 124956819Sralph register char *to; 125056819Sralph register int len; 125156819Sralph { 125256819Sralph register char *bptr; 125356819Sralph register int xfer; 125456819Sralph 125556819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 125656819Sralph boff &= 0xf; 125756819Sralph xfer = min(len, 16 - boff); 125856819Sralph while (len > 0) { 125956819Sralph bcopy(((char *)bptr) + boff, to, xfer); 126056819Sralph to += xfer; 126156819Sralph bptr += 32; 126256819Sralph boff = 0; 126356819Sralph len -= xfer; 126456819Sralph xfer = min(len, 16); 126556819Sralph } 126656819Sralph } 126756819Sralph 126856819Sralph void 126956819Sralph bzerobuf_gap16(lebuf, boff, len) 127056819Sralph volatile void *lebuf; 127156819Sralph int boff; 127256819Sralph register int len; 127356819Sralph { 127456819Sralph register char *bptr; 127556819Sralph register int xfer; 127656819Sralph 127756819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 127856819Sralph boff &= 0xf; 127956819Sralph xfer = min(len, 16 - boff); 128056819Sralph while (len > 0) { 128156819Sralph bzero(((char *)bptr) + boff, xfer); 128256819Sralph bptr += 32; 128356819Sralph boff = 0; 128456819Sralph len -= xfer; 128556819Sralph xfer = min(len, 16); 128656819Sralph } 128756819Sralph } 128856819Sralph #endif /* NLE */ 1289