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*60599Sralph * @(#)if_le.c 7.11 (Berkeley) 05/29/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> 2759836Sralph #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 5459836Sralph #if defined (CCITT) && defined (LLC) 5559836Sralph #include <sys/socketvar.h> 5659836Sralph #include <netccitt/x25.h> 5759836Sralph 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 */ 10359836Sralph /* stats */ 10452130Smckusick int sc_runt; 10552130Smckusick int sc_merr; 10652130Smckusick int sc_babl; 10752130Smckusick int sc_cerr; 10852130Smckusick int sc_miss; 10959836Sralph 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; 15459836Sralph 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; 22759836Sralph ifp->if_reset = lereset; 22852130Smckusick ifp->if_ioctl = leioctl; 22952130Smckusick ifp->if_output = ether_output; 23052130Smckusick ifp->if_start = lestart; 23159836Sralph #ifdef MULTICAST 23259836Sralph ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 23359836Sralph #else 23452130Smckusick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 23559836Sralph #endif 23652130Smckusick #if NBPFILTER > 0 23759836Sralph 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 24759836Sralph #ifdef MULTICAST 24859836Sralph /* 24959836Sralph * Setup the logical address filter 25059836Sralph */ 25159836Sralph void 252*60599Sralph lesetladrf(le) 253*60599Sralph register struct le_softc *le; 25459836Sralph { 255*60599Sralph register volatile struct lereg2 *ler2 = le->sc_r2; 256*60599Sralph register struct ifnet *ifp = &le->sc_if; 25759836Sralph register struct ether_multi *enm; 25859836Sralph register u_char *cp; 25959836Sralph register u_long crc; 26059836Sralph register u_long c; 26159836Sralph register int i, len; 26259836Sralph struct ether_multistep step; 26359836Sralph 26459836Sralph /* 26559836Sralph * Set up multicast address filter by passing all multicast 26659836Sralph * addresses through a crc generator, and then using the high 26759836Sralph * order 6 bits as a index into the 64 bit logical address 26859836Sralph * filter. The high order two bits select the word, while the 26959836Sralph * rest of the bits select the bit within the word. 27059836Sralph */ 27159836Sralph 272*60599Sralph LER2_ladrf0(ler2, 0); 273*60599Sralph LER2_ladrf1(ler2, 0); 27459836Sralph ifp->if_flags &= ~IFF_ALLMULTI; 275*60599Sralph ETHER_FIRST_MULTI(step, &le->sc_ac, enm); 27659836Sralph while (enm != NULL) { 27759836Sralph if (bcmp((caddr_t)&enm->enm_addrlo, 27859836Sralph (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) == 0) { 27959836Sralph /* 28059836Sralph * We must listen to a range of multicast 28159836Sralph * addresses. For now, just accept all 28259836Sralph * multicasts, rather than trying to set only 28359836Sralph * those filter bits needed to match the range. 28459836Sralph * (At this time, the only use of address 28559836Sralph * ranges is for IP multicast routing, for 28659836Sralph * which the range is big enough to require all 28759836Sralph * bits set.) 28859836Sralph */ 28959836Sralph LER2_ladrf0(ler2, 0xff); 29059836Sralph LER2_ladrf1(ler2, 0xff); 29159836Sralph LER2_ladrf2(ler2, 0xff); 29259836Sralph LER2_ladrf3(ler2, 0xff); 29359836Sralph ifp->if_flags |= IFF_ALLMULTI; 29459836Sralph return; 29559836Sralph } 29659836Sralph 29759836Sralph cp = (unsigned char *)&enm->enm_addrlo; 29859836Sralph c = *cp; 29959836Sralph crc = 0xffffffff; 30059836Sralph len = 6; 30159836Sralph while (len-- > 0) { 30259836Sralph c = *cp; 30359836Sralph for (i = 0; i < 8; i++) { 30459836Sralph if ((c & 0x01) ^ (crc & 0x01)) { 30559836Sralph crc >>= 1; 30659836Sralph crc = crc ^ 0xedb88320; 30759836Sralph } 30859836Sralph else 30959836Sralph crc >>= 1; 31059836Sralph c >>= 1; 31159836Sralph } 31259836Sralph cp++; 31359836Sralph } 31459836Sralph /* Just want the 6 most significant bits. */ 31559836Sralph crc = crc >> 26; 31659836Sralph 31759836Sralph /* Turn on the corresponding bit in the filter. */ 318*60599Sralph switch (crc >> 5) { 319*60599Sralph case 0: 320*60599Sralph LER2_ladrf0(ler2, 1 << (crc & 0x1f)); 321*60599Sralph break; 322*60599Sralph case 1: 323*60599Sralph LER2_ladrf1(ler2, 1 << (crc & 0x1f)); 324*60599Sralph break; 325*60599Sralph case 2: 326*60599Sralph LER2_ladrf2(ler2, 1 << (crc & 0x1f)); 327*60599Sralph break; 328*60599Sralph case 3: 329*60599Sralph LER2_ladrf3(ler2, 1 << (crc & 0x1f)); 330*60599Sralph } 33159836Sralph 33259836Sralph ETHER_NEXT_MULTI(step, enm); 33359836Sralph } 33459836Sralph } 33559836Sralph #endif 33659836Sralph 33756819Sralph ledrinit(le) 33856819Sralph struct le_softc *le; 33952130Smckusick { 34056819Sralph register volatile void *rp; 34152130Smckusick register int i; 34252130Smckusick 34352130Smckusick for (i = 0; i < LERBUF; i++) { 34456819Sralph rp = LER2_RMDADDR(le->sc_r2, i); 34556819Sralph LER2_rmd0(rp, CPU_TO_CHIP_ADDR(ler2_rbuf[i][0])); 34656819Sralph LER2_rmd1(rp, LE_OWN); 34756819Sralph LER2_rmd2(rp, -LEMTU); 34856819Sralph LER2_rmd3(rp, 0); 34952130Smckusick } 35052130Smckusick for (i = 0; i < LETBUF; i++) { 35156819Sralph rp = LER2_TMDADDR(le->sc_r2, i); 35256819Sralph LER2_tmd0(rp, CPU_TO_CHIP_ADDR(ler2_tbuf[i][0])); 35356819Sralph LER2_tmd1(rp, 0); 35456819Sralph LER2_tmd2(rp, 0); 35556819Sralph LER2_tmd3(rp, 0); 35652130Smckusick } 35752130Smckusick } 35852130Smckusick 35952130Smckusick lereset(unit) 36052130Smckusick register int unit; 36152130Smckusick { 36252130Smckusick register struct le_softc *le = &le_softc[unit]; 36352130Smckusick register volatile struct lereg1 *ler1 = le->sc_r1; 36456819Sralph register volatile void *ler2 = le->sc_r2; 36552130Smckusick register int timo = 100000; 36652130Smckusick register int stat; 36752130Smckusick 36852130Smckusick #ifdef lint 36952130Smckusick stat = unit; 37052130Smckusick #endif 37156819Sralph LEWREG(LE_CSR0, ler1->ler1_rap); 37256819Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 37356819Sralph 37456819Sralph /* 37556819Sralph * Setup for transmit/receive 37656819Sralph */ 37752130Smckusick #if NBPFILTER > 0 37852130Smckusick if (le->sc_if.if_flags & IFF_PROMISC) 37952130Smckusick /* set the promiscuous bit */ 38059836Sralph LER2_mode(ler2, LE_MODE | 0x8000); 38152130Smckusick else 38252130Smckusick #endif 38356819Sralph LER2_mode(ler2, LE_MODE); 38456819Sralph LER2_padr0(ler2, (le->sc_addr[1] << 8) | le->sc_addr[0]); 38556819Sralph LER2_padr1(ler2, (le->sc_addr[3] << 8) | le->sc_addr[2]); 38656819Sralph LER2_padr2(ler2, (le->sc_addr[5] << 8) | le->sc_addr[4]); 38759836Sralph /* Setup the logical address filter */ 38859836Sralph #ifdef MULTICAST 38959836Sralph lesetladrf(le); 39052130Smckusick #else 39156819Sralph LER2_ladrf0(ler2, 0); 39256819Sralph LER2_ladrf1(ler2, 0); 39356819Sralph LER2_ladrf2(ler2, 0); 39456819Sralph LER2_ladrf3(ler2, 0); 39552130Smckusick #endif 39656819Sralph LER2_rlen(ler2, LE_RLEN); 39756819Sralph LER2_rdra(ler2, CPU_TO_CHIP_ADDR(ler2_rmd[0])); 39856819Sralph LER2_tlen(ler2, LE_TLEN); 39956819Sralph LER2_tdra(ler2, CPU_TO_CHIP_ADDR(ler2_tmd[0])); 40056819Sralph ledrinit(le); 40152130Smckusick le->sc_rmd = 0; 40252130Smckusick le->sc_tmd = LETBUF - 1; 40352130Smckusick le->sc_tmdnext = 0; 40452130Smckusick 40556819Sralph LEWREG(LE_CSR1, ler1->ler1_rap); 40656819Sralph LEWREG(CPU_TO_CHIP_ADDR(ler2_mode), ler1->ler1_rdp); 40756819Sralph LEWREG(LE_CSR2, ler1->ler1_rap); 40856819Sralph LEWREG(0, ler1->ler1_rdp); 40956819Sralph LEWREG(LE_CSR3, ler1->ler1_rap); 41056819Sralph LEWREG(0, ler1->ler1_rdp); 41156819Sralph LEWREG(LE_CSR0, ler1->ler1_rap); 41252130Smckusick LERDWR(ler0, LE_INIT, ler1->ler1_rdp); 41352130Smckusick do { 41452130Smckusick if (--timo == 0) { 41552130Smckusick printf("le%d: init timeout, stat = 0x%x\n", 41652130Smckusick unit, stat); 41752130Smckusick break; 41852130Smckusick } 41956819Sralph stat = ler1->ler1_rdp; 42052130Smckusick } while ((stat & LE_IDON) == 0); 42152130Smckusick LERDWR(ler0, LE_IDON, ler1->ler1_rdp); 42252130Smckusick LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); 42352130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 42452130Smckusick } 42552130Smckusick 42652130Smckusick /* 42752130Smckusick * Initialization of interface 42852130Smckusick */ 42952130Smckusick leinit(unit) 43052130Smckusick int unit; 43152130Smckusick { 43259836Sralph register struct ifnet *ifp = &le_softc[unit].sc_if; 43359836Sralph register struct ifaddr *ifa; 43452130Smckusick int s; 43552130Smckusick 43652130Smckusick /* not yet, if address still unknown */ 43759836Sralph for (ifa = ifp->if_addrlist;; ifa = ifa->ifa_next) 43859836Sralph if (ifa == 0) 43959836Sralph return; 44059836Sralph else if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK) 44159836Sralph break; 44252130Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 44352130Smckusick s = splnet(); 44452130Smckusick ifp->if_flags |= IFF_RUNNING; 44552130Smckusick lereset(unit); 44652130Smckusick (void) lestart(ifp); 44752130Smckusick splx(s); 44852130Smckusick } 44952130Smckusick } 45052130Smckusick 45152130Smckusick #define LENEXTTMP \ 45256819Sralph if (++bix == LETBUF) \ 45356819Sralph bix = 0; \ 45456819Sralph tmd = LER2_TMDADDR(le->sc_r2, bix) 45552130Smckusick 45652130Smckusick /* 45752130Smckusick * Start output on interface. Get another datagram to send 45852130Smckusick * off of the interface queue, and copy it to the interface 45952130Smckusick * before starting the output. 46052130Smckusick */ 46152130Smckusick lestart(ifp) 46252130Smckusick struct ifnet *ifp; 46352130Smckusick { 46452130Smckusick register struct le_softc *le = &le_softc[ifp->if_unit]; 46552130Smckusick register int bix = le->sc_tmdnext; 46656819Sralph register volatile void *tmd = LER2_TMDADDR(le->sc_r2, bix); 46752130Smckusick register struct mbuf *m; 46852130Smckusick int len = 0; 46952130Smckusick 47052130Smckusick if ((le->sc_if.if_flags & IFF_RUNNING) == 0) 47152130Smckusick return (0); 47252130Smckusick while (bix != le->sc_tmd) { 47356819Sralph if (LER2V_tmd1(tmd) & LE_OWN) 47452130Smckusick panic("lestart"); 47552130Smckusick IF_DEQUEUE(&le->sc_if.if_snd, m); 47652130Smckusick if (m == 0) 47752130Smckusick break; 47859836Sralph len = leput(le, LER2_TBUFADDR(le->sc_r2, bix), m); 47952130Smckusick #if NBPFILTER > 0 48052130Smckusick /* 48152130Smckusick * If bpf is listening on this interface, let it 48252130Smckusick * see the packet before we commit it to the wire. 48352130Smckusick */ 48459836Sralph if (ifp->if_bpf) 48559836Sralph bpf_tap(ifp->if_bpf, 48659836Sralph LER2_TBUFADDR(le->sc_r2, le->sc_tmd), len); 48752130Smckusick #endif 48856819Sralph LER2_tmd3(tmd, 0); 48956819Sralph LER2_tmd2(tmd, -len); 49056819Sralph LER2_tmd1(tmd, LE_OWN | LE_STP | LE_ENP); 49152130Smckusick LENEXTTMP; 49252130Smckusick } 49352130Smckusick if (len != 0) { 49452130Smckusick le->sc_if.if_flags |= IFF_OACTIVE; 49552130Smckusick LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp); 49652130Smckusick } 49752130Smckusick le->sc_tmdnext = bix; 49852130Smckusick return (0); 49952130Smckusick } 50052130Smckusick 50152130Smckusick /* 50252130Smckusick * Process interrupts from the 7990 chip. 50352130Smckusick */ 50452695Sralph void 50552695Sralph leintr(unit) 50652695Sralph int unit; 50752130Smckusick { 50852130Smckusick register struct le_softc *le; 50952130Smckusick register volatile struct lereg1 *ler1; 51052695Sralph register int stat; 51152130Smckusick 51252130Smckusick le = &le_softc[unit]; 51352130Smckusick ler1 = le->sc_r1; 51452130Smckusick stat = ler1->ler1_rdp; 51552130Smckusick if (!(stat & LE_INTR)) { 51653081Sralph printf("le%d: spurrious interrupt\n", unit); 51752130Smckusick return; 51852130Smckusick } 51952130Smckusick if (stat & LE_SERR) { 52052130Smckusick leerror(unit, stat); 52152130Smckusick if (stat & LE_MERR) { 52252130Smckusick le->sc_merr++; 52352130Smckusick lereset(unit); 52452130Smckusick return; 52552130Smckusick } 52652130Smckusick if (stat & LE_BABL) 52752130Smckusick le->sc_babl++; 52852130Smckusick if (stat & LE_CERR) 52952130Smckusick le->sc_cerr++; 53052130Smckusick if (stat & LE_MISS) 53152130Smckusick le->sc_miss++; 53252130Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); 53352130Smckusick } 53452130Smckusick if ((stat & LE_RXON) == 0) { 53552130Smckusick le->sc_rxoff++; 53652130Smckusick lereset(unit); 53752130Smckusick return; 53852130Smckusick } 53952130Smckusick if ((stat & LE_TXON) == 0) { 54052130Smckusick le->sc_txoff++; 54152130Smckusick lereset(unit); 54252130Smckusick return; 54352130Smckusick } 54452130Smckusick if (stat & LE_RINT) { 54552130Smckusick /* interrupt is cleared in lerint */ 54652130Smckusick lerint(unit); 54752130Smckusick } 54852130Smckusick if (stat & LE_TINT) { 54952130Smckusick LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp); 55052130Smckusick lexint(unit); 55152130Smckusick } 55252130Smckusick } 55352130Smckusick 55452130Smckusick /* 55552130Smckusick * Ethernet interface transmitter interrupt. 55652130Smckusick * Start another output if more data to send. 55752130Smckusick */ 55852130Smckusick lexint(unit) 55952130Smckusick register int unit; 56052130Smckusick { 56152130Smckusick register struct le_softc *le = &le_softc[unit]; 56252130Smckusick register int bix = le->sc_tmd; 56356819Sralph register volatile void *tmd; 56452130Smckusick 56552130Smckusick if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { 56652130Smckusick le->sc_xint++; 56752130Smckusick return; 56852130Smckusick } 56952130Smckusick LENEXTTMP; 57056819Sralph while (bix != le->sc_tmdnext && (LER2V_tmd1(tmd) & LE_OWN) == 0) { 57152130Smckusick le->sc_tmd = bix; 57256819Sralph if ((LER2V_tmd1(tmd) & LE_ERR) || (LER2V_tmd3(tmd) & LE_TBUFF)) { 57352130Smckusick lexerror(unit); 57452130Smckusick le->sc_if.if_oerrors++; 57556819Sralph if (LER2V_tmd3(tmd) & (LE_TBUFF|LE_UFLO)) { 57652130Smckusick le->sc_uflo++; 57752130Smckusick lereset(unit); 57852130Smckusick break; 57952130Smckusick } 58056819Sralph else if (LER2V_tmd3(tmd) & LE_LCOL) 58152130Smckusick le->sc_if.if_collisions++; 58256819Sralph else if (LER2V_tmd3(tmd) & LE_RTRY) 58352130Smckusick le->sc_if.if_collisions += 16; 58452130Smckusick } 58556819Sralph else if (LER2V_tmd1(tmd) & LE_ONE) 58652130Smckusick le->sc_if.if_collisions++; 58756819Sralph else if (LER2V_tmd1(tmd) & LE_MORE) 58852130Smckusick /* what is the real number? */ 58952130Smckusick le->sc_if.if_collisions += 2; 59052130Smckusick else 59152130Smckusick le->sc_if.if_opackets++; 59252130Smckusick LENEXTTMP; 59352130Smckusick } 59452130Smckusick if (bix == le->sc_tmdnext) 59552130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 59652130Smckusick (void) lestart(&le->sc_if); 59752130Smckusick } 59852130Smckusick 59952130Smckusick #define LENEXTRMP \ 60056819Sralph if (++bix == LERBUF) \ 60156819Sralph bix = 0; \ 60256819Sralph rmd = LER2_RMDADDR(le->sc_r2, bix) 60352130Smckusick 60452130Smckusick /* 60552130Smckusick * Ethernet interface receiver interrupt. 60652130Smckusick * If input error just drop packet. 60752130Smckusick * Decapsulate packet based on type and pass to type specific 60852130Smckusick * higher-level input routine. 60952130Smckusick */ 61052130Smckusick lerint(unit) 61152130Smckusick int unit; 61252130Smckusick { 61352130Smckusick register struct le_softc *le = &le_softc[unit]; 61452130Smckusick register int bix = le->sc_rmd; 61556819Sralph register volatile void *rmd = LER2_RMDADDR(le->sc_r2, bix); 61652130Smckusick 61752130Smckusick /* 61852130Smckusick * Out of sync with hardware, should never happen? 61952130Smckusick */ 62056819Sralph if (LER2V_rmd1(rmd) & LE_OWN) { 62159836Sralph le->sc_rown++; 62252130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 62352130Smckusick return; 62452130Smckusick } 62552130Smckusick 62652130Smckusick /* 62752130Smckusick * Process all buffers with valid data 62852130Smckusick */ 62956819Sralph while ((LER2V_rmd1(rmd) & LE_OWN) == 0) { 63056819Sralph int len = LER2V_rmd3(rmd); 63152130Smckusick 63252130Smckusick /* Clear interrupt to avoid race condition */ 63352130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 63452130Smckusick 63556819Sralph if (LER2V_rmd1(rmd) & LE_ERR) { 63652130Smckusick le->sc_rmd = bix; 63752130Smckusick lererror(unit, "bad packet"); 63852130Smckusick le->sc_if.if_ierrors++; 63956819Sralph } else if ((LER2V_rmd1(rmd) & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 64052130Smckusick /* 64152130Smckusick * Find the end of the packet so we can see how long 64252130Smckusick * it was. We still throw it away. 64352130Smckusick */ 64452130Smckusick do { 64552130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, 64652130Smckusick le->sc_r1->ler1_rdp); 64756819Sralph LER2_rmd3(rmd, 0); 64856819Sralph LER2_rmd1(rmd, LE_OWN); 64952130Smckusick LENEXTRMP; 65056819Sralph } while (!(LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 65152130Smckusick le->sc_rmd = bix; 65252130Smckusick lererror(unit, "chained buffer"); 65352130Smckusick le->sc_rxlen++; 65452130Smckusick /* 65552130Smckusick * If search terminated without successful completion 65652130Smckusick * we reset the hardware (conservative). 65752130Smckusick */ 65856819Sralph if ((LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 65952130Smckusick LE_ENP) { 66052130Smckusick lereset(unit); 66152130Smckusick return; 66252130Smckusick } 66352130Smckusick } else 66456819Sralph leread(unit, LER2_RBUFADDR(le->sc_r2, bix), len); 66556819Sralph LER2_rmd3(rmd, 0); 66656819Sralph LER2_rmd1(rmd, LE_OWN); 66752130Smckusick LENEXTRMP; 66852130Smckusick } 66952130Smckusick MachEmptyWriteBuffer(); /* Paranoia */ 67052130Smckusick le->sc_rmd = bix; 67152130Smckusick } 67252130Smckusick 67352130Smckusick /* 67452130Smckusick * Look at the packet in network buffer memory so we can be smart about how 67552130Smckusick * we copy the data into mbufs. 67652130Smckusick * This needs work since we can't just read network buffer memory like 67752130Smckusick * regular memory. 67852130Smckusick */ 67952130Smckusick leread(unit, buf, len) 68052130Smckusick int unit; 68156819Sralph volatile void *buf; 68252130Smckusick int len; 68352130Smckusick { 68452130Smckusick register struct le_softc *le = &le_softc[unit]; 68552130Smckusick struct ether_header et; 68656819Sralph struct mbuf *m, **hdrmp, **tailmp; 68759836Sralph int off, resid, flags; 68856819Sralph u_short sbuf[2], eth_type; 68952695Sralph extern struct mbuf *leget(); 69052130Smckusick 69152130Smckusick le->sc_if.if_ipackets++; 69256819Sralph (*le->sc_copyfrombuf)(buf, 0, (char *)&et, sizeof (et)); 69356819Sralph eth_type = ntohs(et.ether_type); 69452130Smckusick /* adjust input length to account for header and CRC */ 69552130Smckusick len = len - sizeof(struct ether_header) - 4; 69652130Smckusick 69756819Sralph if (eth_type >= ETHERTYPE_TRAIL && 69856819Sralph eth_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 69956819Sralph off = (eth_type - ETHERTYPE_TRAIL) * 512; 70052130Smckusick if (off >= ETHERMTU) 70152130Smckusick return; /* sanity */ 70256819Sralph (*le->sc_copyfrombuf)(buf, sizeof (et) + off, (char *)sbuf, 70356819Sralph sizeof (sbuf)); 70456819Sralph eth_type = ntohs(sbuf[0]); 70552130Smckusick resid = ntohs(sbuf[1]); 70652130Smckusick if (off + resid > len) 70752130Smckusick return; /* sanity */ 70852130Smckusick len = off + resid; 70952130Smckusick } else 71052130Smckusick off = 0; 71152130Smckusick 71252130Smckusick if (len <= 0) { 71352130Smckusick if (ledebug) 71452130Smckusick log(LOG_WARNING, 71552130Smckusick "le%d: ierror(runt packet): from %s: len=%d\n", 71652130Smckusick unit, ether_sprintf(et.ether_shost), len); 71752130Smckusick le->sc_runt++; 71852130Smckusick le->sc_if.if_ierrors++; 71952130Smckusick return; 72052130Smckusick } 72159836Sralph flags = 0; 72259836Sralph if (bcmp((caddr_t)etherbroadcastaddr, 72359836Sralph (caddr_t)et.ether_dhost, sizeof(etherbroadcastaddr)) == 0) 72459836Sralph flags |= M_BCAST; 72559836Sralph if (et.ether_dhost[0] & 1) 72659836Sralph flags |= M_MCAST; 72752130Smckusick 72859836Sralph #if NBPFILTER > 0 72952130Smckusick /* 73059836Sralph * Check if there's a bpf filter listening on this interface. 73159836Sralph * If so, hand off the raw packet to enet. 73259836Sralph */ 73359836Sralph if (le->sc_if.if_bpf) { 73459836Sralph bpf_tap(le->sc_if.if_bpf, buf, len + sizeof(struct ether_header)); 73559836Sralph 73659836Sralph /* 73759836Sralph * Keep the packet if it's a broadcast or has our 73859836Sralph * physical ethernet address (or if we support 73959836Sralph * multicast and it's one). 74059836Sralph */ 74159836Sralph if ( 74259836Sralph #ifdef MULTICAST 74359836Sralph (flags & (M_BCAST | M_MCAST)) == 0 && 74459836Sralph #else 74559836Sralph (flags & M_BCAST) == 0 && 74659836Sralph #endif 74759836Sralph bcmp(et.ether_dhost, le->sc_addr, 74859836Sralph sizeof(et.ether_dhost)) != 0) 74959836Sralph return; 75059836Sralph } 75159836Sralph #endif 75259836Sralph 75359836Sralph /* 75452130Smckusick * Pull packet off interface. Off is nonzero if packet 75552130Smckusick * has trailing header; leget will then force this header 75652130Smckusick * information to be at the front, but we still have to drop 75752130Smckusick * the type and length which are at the front of any trailer data. 75856819Sralph * The hdrmp and tailmp pointers are used by lebpf_tap() to 75956819Sralph * temporarily reorder the mbuf list. See the comment at the beginning 76056819Sralph * of lebpf_tap() for all the ugly details. 76152130Smckusick */ 76256819Sralph m = leget(le, buf, len, off, &le->sc_if, &hdrmp, &tailmp); 76352130Smckusick if (m == 0) 76452130Smckusick return; 76559836Sralph m->m_flags |= flags; 76656819Sralph et.ether_type = eth_type; 76752130Smckusick ether_input(&le->sc_if, &et, m); 76852130Smckusick } 76952130Smckusick 77052130Smckusick /* 77152130Smckusick * Routine to copy from mbuf chain to transmit buffer in 77252130Smckusick * network buffer memory. 77352130Smckusick */ 77456819Sralph leput(le, lebuf, m) 77556819Sralph struct le_softc *le; 77656819Sralph register volatile void *lebuf; 77752130Smckusick register struct mbuf *m; 77852130Smckusick { 77952130Smckusick register struct mbuf *mp; 78052695Sralph register int len, tlen = 0; 78156819Sralph register int boff = 0; 78252130Smckusick 78352130Smckusick for (mp = m; mp; mp = mp->m_next) { 78452130Smckusick len = mp->m_len; 78552130Smckusick if (len == 0) 78652130Smckusick continue; 78756819Sralph (*le->sc_copytobuf)(mtod(mp, char *), lebuf, boff, len); 78852130Smckusick tlen += len; 78956819Sralph boff += len; 79052130Smckusick } 79152130Smckusick m_freem(m); 79252695Sralph if (tlen < LEMINSIZE) { 79356819Sralph (*le->sc_zerobuf)(lebuf, boff, LEMINSIZE - tlen); 79452130Smckusick tlen = LEMINSIZE; 79552695Sralph } 79652130Smckusick return(tlen); 79752130Smckusick } 79852130Smckusick 79952130Smckusick /* 80052130Smckusick * Routine to copy from network buffer memory into mbufs. 80152130Smckusick */ 80252130Smckusick struct mbuf * 80356819Sralph leget(le, lebuf, totlen, off, ifp, hdrmp, tailmp) 80456819Sralph struct le_softc *le; 80556819Sralph volatile void *lebuf; 80652130Smckusick int totlen, off; 80752130Smckusick struct ifnet *ifp; 80856819Sralph struct mbuf ***hdrmp, ***tailmp; 80952130Smckusick { 81052130Smckusick register struct mbuf *m; 81152130Smckusick struct mbuf *top = 0, **mp = ⊤ 81256819Sralph register int len, resid, boff; 81352130Smckusick 81452130Smckusick /* NOTE: sizeof(struct ether_header) should be even */ 81556819Sralph boff = sizeof(struct ether_header); 81652130Smckusick if (off) { 81752130Smckusick /* NOTE: off should be even */ 81856819Sralph boff += off + 2 * sizeof(u_short); 81952130Smckusick totlen -= 2 * sizeof(u_short); 82052130Smckusick resid = totlen - off; 82152130Smckusick } else 82252130Smckusick resid = totlen; 82352130Smckusick 82452130Smckusick MGETHDR(m, M_DONTWAIT, MT_DATA); 82552130Smckusick if (m == 0) 82652130Smckusick return (0); 82752130Smckusick m->m_pkthdr.rcvif = ifp; 82852130Smckusick m->m_pkthdr.len = totlen; 82952130Smckusick m->m_len = MHLEN; 83052130Smckusick 83152130Smckusick while (totlen > 0) { 83252130Smckusick if (top) { 83352130Smckusick MGET(m, M_DONTWAIT, MT_DATA); 83452130Smckusick if (m == 0) { 83552130Smckusick m_freem(top); 83652130Smckusick return (0); 83752130Smckusick } 83852130Smckusick m->m_len = MLEN; 83952130Smckusick } 84052130Smckusick 84152130Smckusick if (resid >= MINCLSIZE) 84252130Smckusick MCLGET(m, M_DONTWAIT); 84352130Smckusick if (m->m_flags & M_EXT) 84455745Sralph m->m_len = min(resid, MCLBYTES); 84552130Smckusick else if (resid < m->m_len) { 84652130Smckusick /* 84752130Smckusick * Place initial small packet/header at end of mbuf. 84852130Smckusick */ 84952130Smckusick if (top == 0 && resid + max_linkhdr <= m->m_len) 85052130Smckusick m->m_data += max_linkhdr; 85152130Smckusick m->m_len = resid; 85252130Smckusick } 85352130Smckusick len = m->m_len; 85456819Sralph (*le->sc_copyfrombuf)(lebuf, boff, mtod(m, char *), len); 85556819Sralph boff += len; 85652130Smckusick *mp = m; 85752130Smckusick mp = &m->m_next; 85852130Smckusick totlen -= len; 85952130Smckusick resid -= len; 86052130Smckusick if (resid == 0) { 86156819Sralph boff = sizeof (struct ether_header); 86252130Smckusick resid = totlen; 86356819Sralph *hdrmp = mp; 86452130Smckusick } 86552130Smckusick } 86656819Sralph *tailmp = mp; 86752130Smckusick return (top); 86852130Smckusick } 86952130Smckusick 87052130Smckusick /* 87152130Smckusick * Process an ioctl request. 87252130Smckusick */ 87352130Smckusick leioctl(ifp, cmd, data) 87452130Smckusick register struct ifnet *ifp; 87552130Smckusick int cmd; 87652130Smckusick caddr_t data; 87752130Smckusick { 87852130Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 87952130Smckusick struct le_softc *le = &le_softc[ifp->if_unit]; 88052130Smckusick volatile struct lereg1 *ler1 = le->sc_r1; 88152130Smckusick int s, error = 0; 88252130Smckusick 88352130Smckusick s = splnet(); 88452130Smckusick switch (cmd) { 88552130Smckusick 88652130Smckusick case SIOCSIFADDR: 88752130Smckusick ifp->if_flags |= IFF_UP; 88852130Smckusick switch (ifa->ifa_addr->sa_family) { 88952130Smckusick #ifdef INET 89052130Smckusick case AF_INET: 89152130Smckusick leinit(ifp->if_unit); /* before arpwhohas */ 89252130Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 89352130Smckusick IA_SIN(ifa)->sin_addr; 89452130Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 89552130Smckusick break; 89652130Smckusick #endif 89752130Smckusick #ifdef NS 89852130Smckusick case AF_NS: 89952130Smckusick { 90052130Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 90152130Smckusick 90252130Smckusick if (ns_nullhost(*ina)) 90352130Smckusick ina->x_host = *(union ns_host *)(le->sc_addr); 90452130Smckusick else { 90552130Smckusick /* 90652130Smckusick * The manual says we can't change the address 90752130Smckusick * while the receiver is armed, 90852130Smckusick * so reset everything 90952130Smckusick */ 91052130Smckusick ifp->if_flags &= ~IFF_RUNNING; 91159836Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 91252130Smckusick bcopy((caddr_t)ina->x_host.c_host, 91352130Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 91452130Smckusick } 91552130Smckusick leinit(ifp->if_unit); /* does le_setaddr() */ 91652130Smckusick break; 91752130Smckusick } 91852130Smckusick #endif 91952130Smckusick default: 92052130Smckusick leinit(ifp->if_unit); 92152130Smckusick break; 92252130Smckusick } 92352130Smckusick break; 92452130Smckusick 92559836Sralph #if defined (CCITT) && defined (LLC) 92659836Sralph case SIOCSIFCONF_X25: 92759836Sralph ifp->if_flags |= IFF_UP; 92859836Sralph ifa->ifa_rtrequest = cons_rtrequest; 92959836Sralph error = x25_llcglue(PRC_IFUP, ifa->ifa_addr); 93059836Sralph if (error == 0) 93159836Sralph leinit(ifp->if_unit); 93259836Sralph break; 93359836Sralph #endif /* CCITT && LLC */ 93459836Sralph 93552130Smckusick case SIOCSIFFLAGS: 93652130Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 93752130Smckusick ifp->if_flags & IFF_RUNNING) { 93856819Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 93952130Smckusick ifp->if_flags &= ~IFF_RUNNING; 94052130Smckusick } else if (ifp->if_flags & IFF_UP && 94152130Smckusick (ifp->if_flags & IFF_RUNNING) == 0) 94252130Smckusick leinit(ifp->if_unit); 94352130Smckusick /* 94452130Smckusick * If the state of the promiscuous bit changes, the interface 94552130Smckusick * must be reset to effect the change. 94652130Smckusick */ 94752130Smckusick if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && 94852130Smckusick (ifp->if_flags & IFF_RUNNING)) { 94952130Smckusick le->sc_iflags = ifp->if_flags; 95052130Smckusick lereset(ifp->if_unit); 95152130Smckusick lestart(ifp); 95252130Smckusick } 95352130Smckusick break; 95452130Smckusick 95559836Sralph #ifdef MULTICAST 95659836Sralph case SIOCADDMULTI: 95759836Sralph case SIOCDELMULTI: 95859836Sralph /* Update our multicast list */ 95959836Sralph error = (cmd == SIOCADDMULTI) ? 96059836Sralph ether_addmulti((struct ifreq *)data, &le->sc_ac) : 96159836Sralph ether_delmulti((struct ifreq *)data, &le->sc_ac); 96259836Sralph 96359836Sralph if (error == ENETRESET) { 96459836Sralph /* 96559836Sralph * Multicast list has changed; set the hardware 96659836Sralph * filter accordingly. 96759836Sralph */ 96859836Sralph lereset(ifp->if_unit); 96959836Sralph error = 0; 97059836Sralph } 97159836Sralph break; 97259836Sralph #endif 97359836Sralph 97452130Smckusick default: 97552130Smckusick error = EINVAL; 97652130Smckusick } 97752130Smckusick splx(s); 97852130Smckusick return (error); 97952130Smckusick } 98052130Smckusick 98152130Smckusick leerror(unit, stat) 98252130Smckusick int unit; 98352130Smckusick int stat; 98452130Smckusick { 98552130Smckusick if (!ledebug) 98652130Smckusick return; 98752130Smckusick 98852130Smckusick /* 98952130Smckusick * Not all transceivers implement heartbeat 99052130Smckusick * so we only log CERR once. 99152130Smckusick */ 99252130Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 99352130Smckusick return; 99452130Smckusick log(LOG_WARNING, 99552130Smckusick "le%d: error: stat=%b\n", unit, 99652130Smckusick stat, 99752130Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 99852130Smckusick } 99952130Smckusick 100052130Smckusick lererror(unit, msg) 100152130Smckusick int unit; 100252130Smckusick char *msg; 100352130Smckusick { 100452130Smckusick register struct le_softc *le = &le_softc[unit]; 100556819Sralph register volatile void *rmd; 100654144Sralph u_char eaddr[6]; 100752130Smckusick int len; 100852130Smckusick 100952130Smckusick if (!ledebug) 101052130Smckusick return; 101152130Smckusick 101256819Sralph rmd = LER2_RMDADDR(le->sc_r2, le->sc_rmd); 101356819Sralph len = LER2V_rmd3(rmd); 101456819Sralph if (len > 11) 101556819Sralph (*le->sc_copyfrombuf)(LER2_RBUFADDR(le->sc_r2, le->sc_rmd), 101656819Sralph 6, eaddr, 6); 101752130Smckusick log(LOG_WARNING, 101852130Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 101956819Sralph unit, msg, 102056819Sralph len > 11 ? ether_sprintf(eaddr) : "unknown", 102156819Sralph le->sc_rmd, len, 102256819Sralph LER2V_rmd1(rmd), 102352130Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 102452130Smckusick } 102552130Smckusick 102652130Smckusick lexerror(unit) 102752130Smckusick int unit; 102852130Smckusick { 102952130Smckusick register struct le_softc *le = &le_softc[unit]; 103056819Sralph register volatile void *tmd; 103154144Sralph u_char eaddr[6]; 103252130Smckusick int len; 103352130Smckusick 103452130Smckusick if (!ledebug) 103552130Smckusick return; 103652130Smckusick 103756819Sralph tmd = LER2_TMDADDR(le->sc_r2, 0); 103856819Sralph len = -LER2V_tmd2(tmd); 103956819Sralph if (len > 5) 104056819Sralph (*le->sc_copyfrombuf)(LER2_TBUFADDR(le->sc_r2, 0), 0, eaddr, 6); 104152130Smckusick log(LOG_WARNING, 104252130Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 104356819Sralph unit, 104456819Sralph len > 5 ? ether_sprintf(eaddr) : "unknown", 104556819Sralph 0, len, 104656819Sralph LER2V_tmd1(tmd), 104752130Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 104856819Sralph LER2V_tmd3(tmd), 104952130Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 105052130Smckusick } 105156819Sralph 105256819Sralph /* 105356819Sralph * Write a lance register port, reading it back to ensure success. This seems 105456819Sralph * to be necessary during initialization, since the chip appears to be a bit 105556819Sralph * pokey sometimes. 105656819Sralph */ 105756819Sralph static void 105856819Sralph lewritereg(regptr, val) 105956819Sralph register volatile u_short *regptr; 106056819Sralph register u_short val; 106156819Sralph { 106256819Sralph register int i = 0; 106356819Sralph 106456819Sralph while (*regptr != val) { 106556819Sralph *regptr = val; 106656819Sralph MachEmptyWriteBuffer(); 106756819Sralph if (++i > 10000) { 106856819Sralph printf("le: Reg did not settle (to x%x): x%x\n", 106956819Sralph val, *regptr); 107056819Sralph return; 107156819Sralph } 107256819Sralph DELAY(100); 107356819Sralph } 107456819Sralph } 107556819Sralph 107656819Sralph /* 107756819Sralph * Routines for accessing the transmit and receive buffers. Unfortunately, 107856819Sralph * CPU addressing of these buffers is done in one of 3 ways: 107956819Sralph * - contiguous (for the 3max and turbochannel option card) 108056819Sralph * - gap2, which means shorts (2 bytes) interspersed with short (2 byte) 108156819Sralph * spaces (for the pmax) 108256819Sralph * - gap16, which means 16bytes interspersed with 16byte spaces 108356819Sralph * for buffers which must begin on a 32byte boundary (for 3min and maxine) 108456819Sralph * The buffer offset is the logical byte offset, assuming contiguous storage. 108556819Sralph */ 108656819Sralph void 108756819Sralph copytobuf_contig(from, lebuf, boff, len) 108856819Sralph char *from; 108956819Sralph volatile void *lebuf; 109056819Sralph int boff; 109156819Sralph int len; 109256819Sralph { 109356819Sralph 109456819Sralph /* 109556819Sralph * Just call bcopy() to do the work. 109656819Sralph */ 109756819Sralph bcopy(from, ((char *)lebuf) + boff, len); 109856819Sralph } 109956819Sralph 110056819Sralph void 110156819Sralph copyfrombuf_contig(lebuf, boff, to, len) 110256819Sralph volatile void *lebuf; 110356819Sralph int boff; 110456819Sralph char *to; 110556819Sralph int len; 110656819Sralph { 110756819Sralph 110856819Sralph /* 110956819Sralph * Just call bcopy() to do the work. 111056819Sralph */ 111156819Sralph bcopy(((char *)lebuf) + boff, to, len); 111256819Sralph } 111356819Sralph 111456819Sralph void 111556819Sralph bzerobuf_contig(lebuf, boff, len) 111656819Sralph volatile void *lebuf; 111756819Sralph int boff; 111856819Sralph int len; 111956819Sralph { 112056819Sralph 112156819Sralph /* 112256819Sralph * Just let bzero() do the work 112356819Sralph */ 112456819Sralph bzero(((char *)lebuf) + boff, len); 112556819Sralph } 112656819Sralph 112756819Sralph /* 112856819Sralph * For the pmax the buffer consists of shorts (2 bytes) interspersed with 112956819Sralph * short (2 byte) spaces and must be accessed with halfword load/stores. 113056819Sralph * (don't worry about doing an extra byte) 113156819Sralph */ 113256819Sralph void 113356819Sralph copytobuf_gap2(from, lebuf, boff, len) 113456819Sralph register char *from; 113556819Sralph volatile void *lebuf; 113656819Sralph int boff; 113756819Sralph register int len; 113856819Sralph { 113956819Sralph register volatile u_short *bptr; 114056819Sralph register int xfer; 114156819Sralph 114256819Sralph if (boff & 0x1) { 114356819Sralph /* handle unaligned first byte */ 114456819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 114556819Sralph *bptr = (*from++ << 8) | (*bptr & 0xff); 114656819Sralph bptr += 2; 114756819Sralph len--; 114856819Sralph } else 114956819Sralph bptr = ((volatile u_short *)lebuf) + boff; 115056819Sralph if ((unsigned)from & 0x1) { 115156819Sralph while (len > 1) { 115256819Sralph *bptr = (from[1] << 8) | from[0]; 115356819Sralph bptr += 2; 115456819Sralph from += 2; 115556819Sralph len -= 2; 115656819Sralph } 115756819Sralph } else { 115856819Sralph /* optimize for aligned transfers */ 115956819Sralph xfer = (int)((unsigned)len & ~0x1); 116056819Sralph CopyToBuffer((u_short *)from, bptr, xfer); 116156819Sralph bptr += xfer; 116256819Sralph from += xfer; 116356819Sralph len -= xfer; 116456819Sralph } 116556819Sralph if (len == 1) 116656819Sralph *bptr = (u_short)*from; 116756819Sralph } 116856819Sralph 116956819Sralph void 117056819Sralph copyfrombuf_gap2(lebuf, boff, to, len) 117156819Sralph volatile void *lebuf; 117256819Sralph int boff; 117356819Sralph register char *to; 117456819Sralph register int len; 117556819Sralph { 117656819Sralph register volatile u_short *bptr; 117756819Sralph register u_short tmp; 117856819Sralph register int xfer; 117956819Sralph 118056819Sralph if (boff & 0x1) { 118156819Sralph /* handle unaligned first byte */ 118256819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 118356819Sralph *to++ = (*bptr >> 8) & 0xff; 118456819Sralph bptr += 2; 118556819Sralph len--; 118656819Sralph } else 118756819Sralph bptr = ((volatile u_short *)lebuf) + boff; 118856819Sralph if ((unsigned)to & 0x1) { 118956819Sralph while (len > 1) { 119056819Sralph tmp = *bptr; 119156819Sralph *to++ = tmp & 0xff; 119256819Sralph *to++ = (tmp >> 8) & 0xff; 119356819Sralph bptr += 2; 119456819Sralph len -= 2; 119556819Sralph } 119656819Sralph } else { 119756819Sralph /* optimize for aligned transfers */ 119856819Sralph xfer = (int)((unsigned)len & ~0x1); 119956819Sralph CopyFromBuffer(bptr, to, xfer); 120056819Sralph bptr += xfer; 120156819Sralph to += xfer; 120256819Sralph len -= xfer; 120356819Sralph } 120456819Sralph if (len == 1) 120556819Sralph *to = *bptr & 0xff; 120656819Sralph } 120756819Sralph 120856819Sralph void 120956819Sralph bzerobuf_gap2(lebuf, boff, len) 121056819Sralph volatile void *lebuf; 121156819Sralph int boff; 121256819Sralph int len; 121356819Sralph { 121456819Sralph register volatile u_short *bptr; 121556819Sralph 121656819Sralph if ((unsigned)boff & 0x1) { 121756819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 121856819Sralph *bptr &= 0xff; 121956819Sralph bptr += 2; 122056819Sralph len--; 122156819Sralph } else 122256819Sralph bptr = ((volatile u_short *)lebuf) + boff; 122356819Sralph while (len > 0) { 122456819Sralph *bptr = 0; 122556819Sralph bptr += 2; 122656819Sralph len -= 2; 122756819Sralph } 122856819Sralph } 122956819Sralph 123056819Sralph /* 123156819Sralph * For the 3min and maxine, the buffers are in main memory filled in with 123256819Sralph * 16byte blocks interspersed with 16byte spaces. 123356819Sralph */ 123456819Sralph void 123556819Sralph copytobuf_gap16(from, lebuf, boff, len) 123656819Sralph register char *from; 123756819Sralph volatile void *lebuf; 123856819Sralph int boff; 123956819Sralph register int len; 124056819Sralph { 124156819Sralph register char *bptr; 124256819Sralph register int xfer; 124356819Sralph 124456819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 124556819Sralph boff &= 0xf; 124656819Sralph xfer = min(len, 16 - boff); 124756819Sralph while (len > 0) { 124856819Sralph bcopy(from, ((char *)bptr) + boff, xfer); 124956819Sralph from += xfer; 125056819Sralph bptr += 32; 125156819Sralph boff = 0; 125256819Sralph len -= xfer; 125356819Sralph xfer = min(len, 16); 125456819Sralph } 125556819Sralph } 125656819Sralph 125756819Sralph void 125856819Sralph copyfrombuf_gap16(lebuf, boff, to, len) 125956819Sralph volatile void *lebuf; 126056819Sralph int boff; 126156819Sralph register char *to; 126256819Sralph register int len; 126356819Sralph { 126456819Sralph register char *bptr; 126556819Sralph register int xfer; 126656819Sralph 126756819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 126856819Sralph boff &= 0xf; 126956819Sralph xfer = min(len, 16 - boff); 127056819Sralph while (len > 0) { 127156819Sralph bcopy(((char *)bptr) + boff, to, xfer); 127256819Sralph to += xfer; 127356819Sralph bptr += 32; 127456819Sralph boff = 0; 127556819Sralph len -= xfer; 127656819Sralph xfer = min(len, 16); 127756819Sralph } 127856819Sralph } 127956819Sralph 128056819Sralph void 128156819Sralph bzerobuf_gap16(lebuf, boff, len) 128256819Sralph volatile void *lebuf; 128356819Sralph int boff; 128456819Sralph register int len; 128556819Sralph { 128656819Sralph register char *bptr; 128756819Sralph register int xfer; 128856819Sralph 128956819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 129056819Sralph boff &= 0xf; 129156819Sralph xfer = min(len, 16 - boff); 129256819Sralph while (len > 0) { 129356819Sralph bzero(((char *)bptr) + boff, xfer); 129456819Sralph bptr += 32; 129556819Sralph boff = 0; 129656819Sralph len -= xfer; 129756819Sralph xfer = min(len, 16); 129856819Sralph } 129956819Sralph } 130056819Sralph #endif /* NLE */ 1301