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*63635Smckusick * @(#)if_le.c 7.12 (Berkeley) 06/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 25260599Sralph lesetladrf(le) 25360599Sralph register struct le_softc *le; 25459836Sralph { 25560599Sralph register volatile struct lereg2 *ler2 = le->sc_r2; 25660599Sralph 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 27260599Sralph LER2_ladrf0(ler2, 0); 27360599Sralph LER2_ladrf1(ler2, 0); 27459836Sralph ifp->if_flags &= ~IFF_ALLMULTI; 27560599Sralph 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. */ 31860599Sralph switch (crc >> 5) { 31960599Sralph case 0: 32060599Sralph LER2_ladrf0(ler2, 1 << (crc & 0x1f)); 32160599Sralph break; 32260599Sralph case 1: 32360599Sralph LER2_ladrf1(ler2, 1 << (crc & 0x1f)); 32460599Sralph break; 32560599Sralph case 2: 32660599Sralph LER2_ladrf2(ler2, 1 << (crc & 0x1f)); 32760599Sralph break; 32860599Sralph case 3: 32960599Sralph LER2_ladrf3(ler2, 1 << (crc & 0x1f)); 33060599Sralph } 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; 47852130Smckusick #if NBPFILTER > 0 47952130Smckusick /* 48052130Smckusick * If bpf is listening on this interface, let it 48152130Smckusick * see the packet before we commit it to the wire. 48252130Smckusick */ 48359836Sralph if (ifp->if_bpf) 484*63635Smckusick bpf_mtap(ifp->if_bpf, m); 48552130Smckusick #endif 486*63635Smckusick len = leput(le, LER2_TBUFADDR(le->sc_r2, bix), m); 48756819Sralph LER2_tmd3(tmd, 0); 48856819Sralph LER2_tmd2(tmd, -len); 48956819Sralph LER2_tmd1(tmd, LE_OWN | LE_STP | LE_ENP); 49052130Smckusick LENEXTTMP; 49152130Smckusick } 49252130Smckusick if (len != 0) { 49352130Smckusick le->sc_if.if_flags |= IFF_OACTIVE; 49452130Smckusick LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp); 49552130Smckusick } 49652130Smckusick le->sc_tmdnext = bix; 49752130Smckusick return (0); 49852130Smckusick } 49952130Smckusick 50052130Smckusick /* 50152130Smckusick * Process interrupts from the 7990 chip. 50252130Smckusick */ 50352695Sralph void 50452695Sralph leintr(unit) 50552695Sralph int unit; 50652130Smckusick { 50752130Smckusick register struct le_softc *le; 50852130Smckusick register volatile struct lereg1 *ler1; 50952695Sralph register int stat; 51052130Smckusick 51152130Smckusick le = &le_softc[unit]; 51252130Smckusick ler1 = le->sc_r1; 51352130Smckusick stat = ler1->ler1_rdp; 51452130Smckusick if (!(stat & LE_INTR)) { 51553081Sralph printf("le%d: spurrious interrupt\n", unit); 51652130Smckusick return; 51752130Smckusick } 51852130Smckusick if (stat & LE_SERR) { 51952130Smckusick leerror(unit, stat); 52052130Smckusick if (stat & LE_MERR) { 52152130Smckusick le->sc_merr++; 52252130Smckusick lereset(unit); 52352130Smckusick return; 52452130Smckusick } 52552130Smckusick if (stat & LE_BABL) 52652130Smckusick le->sc_babl++; 52752130Smckusick if (stat & LE_CERR) 52852130Smckusick le->sc_cerr++; 52952130Smckusick if (stat & LE_MISS) 53052130Smckusick le->sc_miss++; 53152130Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); 53252130Smckusick } 53352130Smckusick if ((stat & LE_RXON) == 0) { 53452130Smckusick le->sc_rxoff++; 53552130Smckusick lereset(unit); 53652130Smckusick return; 53752130Smckusick } 53852130Smckusick if ((stat & LE_TXON) == 0) { 53952130Smckusick le->sc_txoff++; 54052130Smckusick lereset(unit); 54152130Smckusick return; 54252130Smckusick } 54352130Smckusick if (stat & LE_RINT) { 54452130Smckusick /* interrupt is cleared in lerint */ 54552130Smckusick lerint(unit); 54652130Smckusick } 54752130Smckusick if (stat & LE_TINT) { 54852130Smckusick LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp); 54952130Smckusick lexint(unit); 55052130Smckusick } 55152130Smckusick } 55252130Smckusick 55352130Smckusick /* 55452130Smckusick * Ethernet interface transmitter interrupt. 55552130Smckusick * Start another output if more data to send. 55652130Smckusick */ 55752130Smckusick lexint(unit) 55852130Smckusick register int unit; 55952130Smckusick { 56052130Smckusick register struct le_softc *le = &le_softc[unit]; 56152130Smckusick register int bix = le->sc_tmd; 56256819Sralph register volatile void *tmd; 56352130Smckusick 56452130Smckusick if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { 56552130Smckusick le->sc_xint++; 56652130Smckusick return; 56752130Smckusick } 56852130Smckusick LENEXTTMP; 56956819Sralph while (bix != le->sc_tmdnext && (LER2V_tmd1(tmd) & LE_OWN) == 0) { 57052130Smckusick le->sc_tmd = bix; 57156819Sralph if ((LER2V_tmd1(tmd) & LE_ERR) || (LER2V_tmd3(tmd) & LE_TBUFF)) { 57252130Smckusick lexerror(unit); 57352130Smckusick le->sc_if.if_oerrors++; 57456819Sralph if (LER2V_tmd3(tmd) & (LE_TBUFF|LE_UFLO)) { 57552130Smckusick le->sc_uflo++; 57652130Smckusick lereset(unit); 57752130Smckusick break; 57852130Smckusick } 57956819Sralph else if (LER2V_tmd3(tmd) & LE_LCOL) 58052130Smckusick le->sc_if.if_collisions++; 58156819Sralph else if (LER2V_tmd3(tmd) & LE_RTRY) 58252130Smckusick le->sc_if.if_collisions += 16; 58352130Smckusick } 58456819Sralph else if (LER2V_tmd1(tmd) & LE_ONE) 58552130Smckusick le->sc_if.if_collisions++; 58656819Sralph else if (LER2V_tmd1(tmd) & LE_MORE) 58752130Smckusick /* what is the real number? */ 58852130Smckusick le->sc_if.if_collisions += 2; 58952130Smckusick else 59052130Smckusick le->sc_if.if_opackets++; 59152130Smckusick LENEXTTMP; 59252130Smckusick } 59352130Smckusick if (bix == le->sc_tmdnext) 59452130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 59552130Smckusick (void) lestart(&le->sc_if); 59652130Smckusick } 59752130Smckusick 59852130Smckusick #define LENEXTRMP \ 59956819Sralph if (++bix == LERBUF) \ 60056819Sralph bix = 0; \ 60156819Sralph rmd = LER2_RMDADDR(le->sc_r2, bix) 60252130Smckusick 60352130Smckusick /* 60452130Smckusick * Ethernet interface receiver interrupt. 60552130Smckusick * If input error just drop packet. 60652130Smckusick * Decapsulate packet based on type and pass to type specific 60752130Smckusick * higher-level input routine. 60852130Smckusick */ 60952130Smckusick lerint(unit) 61052130Smckusick int unit; 61152130Smckusick { 61252130Smckusick register struct le_softc *le = &le_softc[unit]; 61352130Smckusick register int bix = le->sc_rmd; 61456819Sralph register volatile void *rmd = LER2_RMDADDR(le->sc_r2, bix); 61552130Smckusick 61652130Smckusick /* 61752130Smckusick * Out of sync with hardware, should never happen? 61852130Smckusick */ 61956819Sralph if (LER2V_rmd1(rmd) & LE_OWN) { 62059836Sralph le->sc_rown++; 62152130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 62252130Smckusick return; 62352130Smckusick } 62452130Smckusick 62552130Smckusick /* 62652130Smckusick * Process all buffers with valid data 62752130Smckusick */ 62856819Sralph while ((LER2V_rmd1(rmd) & LE_OWN) == 0) { 62956819Sralph int len = LER2V_rmd3(rmd); 63052130Smckusick 63152130Smckusick /* Clear interrupt to avoid race condition */ 63252130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 63352130Smckusick 63456819Sralph if (LER2V_rmd1(rmd) & LE_ERR) { 63552130Smckusick le->sc_rmd = bix; 63652130Smckusick lererror(unit, "bad packet"); 63752130Smckusick le->sc_if.if_ierrors++; 63856819Sralph } else if ((LER2V_rmd1(rmd) & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 63952130Smckusick /* 64052130Smckusick * Find the end of the packet so we can see how long 64152130Smckusick * it was. We still throw it away. 64252130Smckusick */ 64352130Smckusick do { 64452130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, 64552130Smckusick le->sc_r1->ler1_rdp); 64656819Sralph LER2_rmd3(rmd, 0); 64756819Sralph LER2_rmd1(rmd, LE_OWN); 64852130Smckusick LENEXTRMP; 64956819Sralph } while (!(LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 65052130Smckusick le->sc_rmd = bix; 65152130Smckusick lererror(unit, "chained buffer"); 65252130Smckusick le->sc_rxlen++; 65352130Smckusick /* 65452130Smckusick * If search terminated without successful completion 65552130Smckusick * we reset the hardware (conservative). 65652130Smckusick */ 65756819Sralph if ((LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 65852130Smckusick LE_ENP) { 65952130Smckusick lereset(unit); 66052130Smckusick return; 66152130Smckusick } 66252130Smckusick } else 66356819Sralph leread(unit, LER2_RBUFADDR(le->sc_r2, bix), len); 66456819Sralph LER2_rmd3(rmd, 0); 66556819Sralph LER2_rmd1(rmd, LE_OWN); 66652130Smckusick LENEXTRMP; 66752130Smckusick } 66852130Smckusick MachEmptyWriteBuffer(); /* Paranoia */ 66952130Smckusick le->sc_rmd = bix; 67052130Smckusick } 67152130Smckusick 67252130Smckusick /* 67352130Smckusick * Look at the packet in network buffer memory so we can be smart about how 67452130Smckusick * we copy the data into mbufs. 67552130Smckusick * This needs work since we can't just read network buffer memory like 67652130Smckusick * regular memory. 67752130Smckusick */ 67852130Smckusick leread(unit, buf, len) 67952130Smckusick int unit; 68056819Sralph volatile void *buf; 68152130Smckusick int len; 68252130Smckusick { 68352130Smckusick register struct le_softc *le = &le_softc[unit]; 68452130Smckusick struct ether_header et; 685*63635Smckusick struct mbuf *m; 68659836Sralph int off, resid, flags; 68756819Sralph u_short sbuf[2], eth_type; 68852695Sralph extern struct mbuf *leget(); 68952130Smckusick 69052130Smckusick le->sc_if.if_ipackets++; 69156819Sralph (*le->sc_copyfrombuf)(buf, 0, (char *)&et, sizeof (et)); 69256819Sralph eth_type = ntohs(et.ether_type); 69352130Smckusick /* adjust input length to account for header and CRC */ 69452130Smckusick len = len - sizeof(struct ether_header) - 4; 69552130Smckusick 69656819Sralph if (eth_type >= ETHERTYPE_TRAIL && 69756819Sralph eth_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 69856819Sralph off = (eth_type - ETHERTYPE_TRAIL) * 512; 69952130Smckusick if (off >= ETHERMTU) 70052130Smckusick return; /* sanity */ 70156819Sralph (*le->sc_copyfrombuf)(buf, sizeof (et) + off, (char *)sbuf, 70256819Sralph sizeof (sbuf)); 70356819Sralph eth_type = ntohs(sbuf[0]); 70452130Smckusick resid = ntohs(sbuf[1]); 70552130Smckusick if (off + resid > len) 70652130Smckusick return; /* sanity */ 70752130Smckusick len = off + resid; 70852130Smckusick } else 70952130Smckusick off = 0; 71052130Smckusick 71152130Smckusick if (len <= 0) { 71252130Smckusick if (ledebug) 71352130Smckusick log(LOG_WARNING, 71452130Smckusick "le%d: ierror(runt packet): from %s: len=%d\n", 71552130Smckusick unit, ether_sprintf(et.ether_shost), len); 71652130Smckusick le->sc_runt++; 71752130Smckusick le->sc_if.if_ierrors++; 71852130Smckusick return; 71952130Smckusick } 72059836Sralph flags = 0; 72159836Sralph if (bcmp((caddr_t)etherbroadcastaddr, 72259836Sralph (caddr_t)et.ether_dhost, sizeof(etherbroadcastaddr)) == 0) 72359836Sralph flags |= M_BCAST; 72459836Sralph if (et.ether_dhost[0] & 1) 72559836Sralph flags |= M_MCAST; 72652130Smckusick 727*63635Smckusick /* 728*63635Smckusick * Pull packet off interface. Off is nonzero if packet 729*63635Smckusick * has trailing header; leget will then force this header 730*63635Smckusick * information to be at the front, but we still have to drop 731*63635Smckusick * the type and length which are at the front of any trailer data. 732*63635Smckusick */ 733*63635Smckusick m = leget(le, buf, len, off, &le->sc_if); 734*63635Smckusick if (m == 0) 735*63635Smckusick return; 73659836Sralph #if NBPFILTER > 0 73752130Smckusick /* 73859836Sralph * Check if there's a bpf filter listening on this interface. 73959836Sralph * If so, hand off the raw packet to enet. 74059836Sralph */ 74159836Sralph if (le->sc_if.if_bpf) { 742*63635Smckusick bpf_mtap(le->sc_if.if_bpf, m); 74359836Sralph 74459836Sralph /* 74559836Sralph * Keep the packet if it's a broadcast or has our 74659836Sralph * physical ethernet address (or if we support 74759836Sralph * multicast and it's one). 74859836Sralph */ 74959836Sralph if ( 75059836Sralph #ifdef MULTICAST 75159836Sralph (flags & (M_BCAST | M_MCAST)) == 0 && 75259836Sralph #else 75359836Sralph (flags & M_BCAST) == 0 && 75459836Sralph #endif 75559836Sralph bcmp(et.ether_dhost, le->sc_addr, 756*63635Smckusick sizeof(et.ether_dhost)) != 0) { 757*63635Smckusick m_freem(m); 75859836Sralph return; 759*63635Smckusick } 76059836Sralph } 76159836Sralph #endif 76259836Sralph m->m_flags |= flags; 76356819Sralph et.ether_type = eth_type; 76452130Smckusick ether_input(&le->sc_if, &et, m); 76552130Smckusick } 76652130Smckusick 76752130Smckusick /* 76852130Smckusick * Routine to copy from mbuf chain to transmit buffer in 76952130Smckusick * network buffer memory. 77052130Smckusick */ 77156819Sralph leput(le, lebuf, m) 77256819Sralph struct le_softc *le; 77356819Sralph register volatile void *lebuf; 77452130Smckusick register struct mbuf *m; 77552130Smckusick { 77652130Smckusick register struct mbuf *mp; 77752695Sralph register int len, tlen = 0; 77856819Sralph register int boff = 0; 77952130Smckusick 78052130Smckusick for (mp = m; mp; mp = mp->m_next) { 78152130Smckusick len = mp->m_len; 78252130Smckusick if (len == 0) 78352130Smckusick continue; 78456819Sralph (*le->sc_copytobuf)(mtod(mp, char *), lebuf, boff, len); 78552130Smckusick tlen += len; 78656819Sralph boff += len; 78752130Smckusick } 78852130Smckusick m_freem(m); 78952695Sralph if (tlen < LEMINSIZE) { 79056819Sralph (*le->sc_zerobuf)(lebuf, boff, LEMINSIZE - tlen); 79152130Smckusick tlen = LEMINSIZE; 79252695Sralph } 79352130Smckusick return(tlen); 79452130Smckusick } 79552130Smckusick 79652130Smckusick /* 79752130Smckusick * Routine to copy from network buffer memory into mbufs. 79852130Smckusick */ 79952130Smckusick struct mbuf * 800*63635Smckusick leget(le, lebuf, totlen, off, ifp) 80156819Sralph struct le_softc *le; 80256819Sralph volatile void *lebuf; 80352130Smckusick int totlen, off; 80452130Smckusick struct ifnet *ifp; 80552130Smckusick { 80652130Smckusick register struct mbuf *m; 80752130Smckusick struct mbuf *top = 0, **mp = ⊤ 80856819Sralph register int len, resid, boff; 80952130Smckusick 81052130Smckusick /* NOTE: sizeof(struct ether_header) should be even */ 81156819Sralph boff = sizeof(struct ether_header); 81252130Smckusick if (off) { 81352130Smckusick /* NOTE: off should be even */ 81456819Sralph boff += off + 2 * sizeof(u_short); 81552130Smckusick totlen -= 2 * sizeof(u_short); 81652130Smckusick resid = totlen - off; 81752130Smckusick } else 81852130Smckusick resid = totlen; 81952130Smckusick 82052130Smckusick MGETHDR(m, M_DONTWAIT, MT_DATA); 82152130Smckusick if (m == 0) 82252130Smckusick return (0); 82352130Smckusick m->m_pkthdr.rcvif = ifp; 82452130Smckusick m->m_pkthdr.len = totlen; 82552130Smckusick m->m_len = MHLEN; 82652130Smckusick 82752130Smckusick while (totlen > 0) { 82852130Smckusick if (top) { 82952130Smckusick MGET(m, M_DONTWAIT, MT_DATA); 83052130Smckusick if (m == 0) { 83152130Smckusick m_freem(top); 83252130Smckusick return (0); 83352130Smckusick } 83452130Smckusick m->m_len = MLEN; 83552130Smckusick } 83652130Smckusick 83752130Smckusick if (resid >= MINCLSIZE) 83852130Smckusick MCLGET(m, M_DONTWAIT); 83952130Smckusick if (m->m_flags & M_EXT) 84055745Sralph m->m_len = min(resid, MCLBYTES); 84152130Smckusick else if (resid < m->m_len) { 84252130Smckusick /* 84352130Smckusick * Place initial small packet/header at end of mbuf. 84452130Smckusick */ 84552130Smckusick if (top == 0 && resid + max_linkhdr <= m->m_len) 84652130Smckusick m->m_data += max_linkhdr; 84752130Smckusick m->m_len = resid; 84852130Smckusick } 84952130Smckusick len = m->m_len; 85056819Sralph (*le->sc_copyfrombuf)(lebuf, boff, mtod(m, char *), len); 85156819Sralph boff += len; 85252130Smckusick *mp = m; 85352130Smckusick mp = &m->m_next; 85452130Smckusick totlen -= len; 85552130Smckusick resid -= len; 85652130Smckusick if (resid == 0) { 85756819Sralph boff = sizeof (struct ether_header); 85852130Smckusick resid = totlen; 85952130Smckusick } 86052130Smckusick } 86152130Smckusick return (top); 86252130Smckusick } 86352130Smckusick 86452130Smckusick /* 86552130Smckusick * Process an ioctl request. 86652130Smckusick */ 86752130Smckusick leioctl(ifp, cmd, data) 86852130Smckusick register struct ifnet *ifp; 86952130Smckusick int cmd; 87052130Smckusick caddr_t data; 87152130Smckusick { 87252130Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 87352130Smckusick struct le_softc *le = &le_softc[ifp->if_unit]; 87452130Smckusick volatile struct lereg1 *ler1 = le->sc_r1; 87552130Smckusick int s, error = 0; 87652130Smckusick 87752130Smckusick s = splnet(); 87852130Smckusick switch (cmd) { 87952130Smckusick 88052130Smckusick case SIOCSIFADDR: 88152130Smckusick ifp->if_flags |= IFF_UP; 88252130Smckusick switch (ifa->ifa_addr->sa_family) { 88352130Smckusick #ifdef INET 88452130Smckusick case AF_INET: 88552130Smckusick leinit(ifp->if_unit); /* before arpwhohas */ 88652130Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 88752130Smckusick IA_SIN(ifa)->sin_addr; 88852130Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 88952130Smckusick break; 89052130Smckusick #endif 89152130Smckusick #ifdef NS 89252130Smckusick case AF_NS: 89352130Smckusick { 89452130Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 89552130Smckusick 89652130Smckusick if (ns_nullhost(*ina)) 89752130Smckusick ina->x_host = *(union ns_host *)(le->sc_addr); 89852130Smckusick else { 89952130Smckusick /* 90052130Smckusick * The manual says we can't change the address 90152130Smckusick * while the receiver is armed, 90252130Smckusick * so reset everything 90352130Smckusick */ 90452130Smckusick ifp->if_flags &= ~IFF_RUNNING; 90559836Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 90652130Smckusick bcopy((caddr_t)ina->x_host.c_host, 90752130Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 90852130Smckusick } 90952130Smckusick leinit(ifp->if_unit); /* does le_setaddr() */ 91052130Smckusick break; 91152130Smckusick } 91252130Smckusick #endif 91352130Smckusick default: 91452130Smckusick leinit(ifp->if_unit); 91552130Smckusick break; 91652130Smckusick } 91752130Smckusick break; 91852130Smckusick 91959836Sralph #if defined (CCITT) && defined (LLC) 92059836Sralph case SIOCSIFCONF_X25: 92159836Sralph ifp->if_flags |= IFF_UP; 92259836Sralph ifa->ifa_rtrequest = cons_rtrequest; 92359836Sralph error = x25_llcglue(PRC_IFUP, ifa->ifa_addr); 92459836Sralph if (error == 0) 92559836Sralph leinit(ifp->if_unit); 92659836Sralph break; 92759836Sralph #endif /* CCITT && LLC */ 92859836Sralph 92952130Smckusick case SIOCSIFFLAGS: 93052130Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 93152130Smckusick ifp->if_flags & IFF_RUNNING) { 93256819Sralph LEWREG(LE_STOP, ler1->ler1_rdp); 93352130Smckusick ifp->if_flags &= ~IFF_RUNNING; 93452130Smckusick } else if (ifp->if_flags & IFF_UP && 93552130Smckusick (ifp->if_flags & IFF_RUNNING) == 0) 93652130Smckusick leinit(ifp->if_unit); 93752130Smckusick /* 93852130Smckusick * If the state of the promiscuous bit changes, the interface 93952130Smckusick * must be reset to effect the change. 94052130Smckusick */ 94152130Smckusick if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && 94252130Smckusick (ifp->if_flags & IFF_RUNNING)) { 94352130Smckusick le->sc_iflags = ifp->if_flags; 94452130Smckusick lereset(ifp->if_unit); 94552130Smckusick lestart(ifp); 94652130Smckusick } 94752130Smckusick break; 94852130Smckusick 94959836Sralph #ifdef MULTICAST 95059836Sralph case SIOCADDMULTI: 95159836Sralph case SIOCDELMULTI: 95259836Sralph /* Update our multicast list */ 95359836Sralph error = (cmd == SIOCADDMULTI) ? 95459836Sralph ether_addmulti((struct ifreq *)data, &le->sc_ac) : 95559836Sralph ether_delmulti((struct ifreq *)data, &le->sc_ac); 95659836Sralph 95759836Sralph if (error == ENETRESET) { 95859836Sralph /* 95959836Sralph * Multicast list has changed; set the hardware 96059836Sralph * filter accordingly. 96159836Sralph */ 96259836Sralph lereset(ifp->if_unit); 96359836Sralph error = 0; 96459836Sralph } 96559836Sralph break; 96659836Sralph #endif 96759836Sralph 96852130Smckusick default: 96952130Smckusick error = EINVAL; 97052130Smckusick } 97152130Smckusick splx(s); 97252130Smckusick return (error); 97352130Smckusick } 97452130Smckusick 97552130Smckusick leerror(unit, stat) 97652130Smckusick int unit; 97752130Smckusick int stat; 97852130Smckusick { 97952130Smckusick if (!ledebug) 98052130Smckusick return; 98152130Smckusick 98252130Smckusick /* 98352130Smckusick * Not all transceivers implement heartbeat 98452130Smckusick * so we only log CERR once. 98552130Smckusick */ 98652130Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 98752130Smckusick return; 98852130Smckusick log(LOG_WARNING, 98952130Smckusick "le%d: error: stat=%b\n", unit, 99052130Smckusick stat, 99152130Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 99252130Smckusick } 99352130Smckusick 99452130Smckusick lererror(unit, msg) 99552130Smckusick int unit; 99652130Smckusick char *msg; 99752130Smckusick { 99852130Smckusick register struct le_softc *le = &le_softc[unit]; 99956819Sralph register volatile void *rmd; 100054144Sralph u_char eaddr[6]; 100152130Smckusick int len; 100252130Smckusick 100352130Smckusick if (!ledebug) 100452130Smckusick return; 100552130Smckusick 100656819Sralph rmd = LER2_RMDADDR(le->sc_r2, le->sc_rmd); 100756819Sralph len = LER2V_rmd3(rmd); 100856819Sralph if (len > 11) 100956819Sralph (*le->sc_copyfrombuf)(LER2_RBUFADDR(le->sc_r2, le->sc_rmd), 101056819Sralph 6, eaddr, 6); 101152130Smckusick log(LOG_WARNING, 101252130Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 101356819Sralph unit, msg, 101456819Sralph len > 11 ? ether_sprintf(eaddr) : "unknown", 101556819Sralph le->sc_rmd, len, 101656819Sralph LER2V_rmd1(rmd), 101752130Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 101852130Smckusick } 101952130Smckusick 102052130Smckusick lexerror(unit) 102152130Smckusick int unit; 102252130Smckusick { 102352130Smckusick register struct le_softc *le = &le_softc[unit]; 102456819Sralph register volatile void *tmd; 102554144Sralph u_char eaddr[6]; 102652130Smckusick int len; 102752130Smckusick 102852130Smckusick if (!ledebug) 102952130Smckusick return; 103052130Smckusick 103156819Sralph tmd = LER2_TMDADDR(le->sc_r2, 0); 103256819Sralph len = -LER2V_tmd2(tmd); 103356819Sralph if (len > 5) 103456819Sralph (*le->sc_copyfrombuf)(LER2_TBUFADDR(le->sc_r2, 0), 0, eaddr, 6); 103552130Smckusick log(LOG_WARNING, 103652130Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 103756819Sralph unit, 103856819Sralph len > 5 ? ether_sprintf(eaddr) : "unknown", 103956819Sralph 0, len, 104056819Sralph LER2V_tmd1(tmd), 104152130Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 104256819Sralph LER2V_tmd3(tmd), 104352130Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 104452130Smckusick } 104556819Sralph 104656819Sralph /* 104756819Sralph * Write a lance register port, reading it back to ensure success. This seems 104856819Sralph * to be necessary during initialization, since the chip appears to be a bit 104956819Sralph * pokey sometimes. 105056819Sralph */ 105156819Sralph static void 105256819Sralph lewritereg(regptr, val) 105356819Sralph register volatile u_short *regptr; 105456819Sralph register u_short val; 105556819Sralph { 105656819Sralph register int i = 0; 105756819Sralph 105856819Sralph while (*regptr != val) { 105956819Sralph *regptr = val; 106056819Sralph MachEmptyWriteBuffer(); 106156819Sralph if (++i > 10000) { 106256819Sralph printf("le: Reg did not settle (to x%x): x%x\n", 106356819Sralph val, *regptr); 106456819Sralph return; 106556819Sralph } 106656819Sralph DELAY(100); 106756819Sralph } 106856819Sralph } 106956819Sralph 107056819Sralph /* 107156819Sralph * Routines for accessing the transmit and receive buffers. Unfortunately, 107256819Sralph * CPU addressing of these buffers is done in one of 3 ways: 107356819Sralph * - contiguous (for the 3max and turbochannel option card) 107456819Sralph * - gap2, which means shorts (2 bytes) interspersed with short (2 byte) 107556819Sralph * spaces (for the pmax) 107656819Sralph * - gap16, which means 16bytes interspersed with 16byte spaces 107756819Sralph * for buffers which must begin on a 32byte boundary (for 3min and maxine) 107856819Sralph * The buffer offset is the logical byte offset, assuming contiguous storage. 107956819Sralph */ 108056819Sralph void 108156819Sralph copytobuf_contig(from, lebuf, boff, len) 108256819Sralph char *from; 108356819Sralph volatile void *lebuf; 108456819Sralph int boff; 108556819Sralph int len; 108656819Sralph { 108756819Sralph 108856819Sralph /* 108956819Sralph * Just call bcopy() to do the work. 109056819Sralph */ 109156819Sralph bcopy(from, ((char *)lebuf) + boff, len); 109256819Sralph } 109356819Sralph 109456819Sralph void 109556819Sralph copyfrombuf_contig(lebuf, boff, to, len) 109656819Sralph volatile void *lebuf; 109756819Sralph int boff; 109856819Sralph char *to; 109956819Sralph int len; 110056819Sralph { 110156819Sralph 110256819Sralph /* 110356819Sralph * Just call bcopy() to do the work. 110456819Sralph */ 110556819Sralph bcopy(((char *)lebuf) + boff, to, len); 110656819Sralph } 110756819Sralph 110856819Sralph void 110956819Sralph bzerobuf_contig(lebuf, boff, len) 111056819Sralph volatile void *lebuf; 111156819Sralph int boff; 111256819Sralph int len; 111356819Sralph { 111456819Sralph 111556819Sralph /* 111656819Sralph * Just let bzero() do the work 111756819Sralph */ 111856819Sralph bzero(((char *)lebuf) + boff, len); 111956819Sralph } 112056819Sralph 112156819Sralph /* 112256819Sralph * For the pmax the buffer consists of shorts (2 bytes) interspersed with 112356819Sralph * short (2 byte) spaces and must be accessed with halfword load/stores. 112456819Sralph * (don't worry about doing an extra byte) 112556819Sralph */ 112656819Sralph void 112756819Sralph copytobuf_gap2(from, lebuf, boff, len) 112856819Sralph register char *from; 112956819Sralph volatile void *lebuf; 113056819Sralph int boff; 113156819Sralph register int len; 113256819Sralph { 113356819Sralph register volatile u_short *bptr; 113456819Sralph register int xfer; 113556819Sralph 113656819Sralph if (boff & 0x1) { 113756819Sralph /* handle unaligned first byte */ 113856819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 113956819Sralph *bptr = (*from++ << 8) | (*bptr & 0xff); 114056819Sralph bptr += 2; 114156819Sralph len--; 114256819Sralph } else 114356819Sralph bptr = ((volatile u_short *)lebuf) + boff; 114456819Sralph if ((unsigned)from & 0x1) { 114556819Sralph while (len > 1) { 114656819Sralph *bptr = (from[1] << 8) | from[0]; 114756819Sralph bptr += 2; 114856819Sralph from += 2; 114956819Sralph len -= 2; 115056819Sralph } 115156819Sralph } else { 115256819Sralph /* optimize for aligned transfers */ 115356819Sralph xfer = (int)((unsigned)len & ~0x1); 115456819Sralph CopyToBuffer((u_short *)from, bptr, xfer); 115556819Sralph bptr += xfer; 115656819Sralph from += xfer; 115756819Sralph len -= xfer; 115856819Sralph } 115956819Sralph if (len == 1) 116056819Sralph *bptr = (u_short)*from; 116156819Sralph } 116256819Sralph 116356819Sralph void 116456819Sralph copyfrombuf_gap2(lebuf, boff, to, len) 116556819Sralph volatile void *lebuf; 116656819Sralph int boff; 116756819Sralph register char *to; 116856819Sralph register int len; 116956819Sralph { 117056819Sralph register volatile u_short *bptr; 117156819Sralph register u_short tmp; 117256819Sralph register int xfer; 117356819Sralph 117456819Sralph if (boff & 0x1) { 117556819Sralph /* handle unaligned first byte */ 117656819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 117756819Sralph *to++ = (*bptr >> 8) & 0xff; 117856819Sralph bptr += 2; 117956819Sralph len--; 118056819Sralph } else 118156819Sralph bptr = ((volatile u_short *)lebuf) + boff; 118256819Sralph if ((unsigned)to & 0x1) { 118356819Sralph while (len > 1) { 118456819Sralph tmp = *bptr; 118556819Sralph *to++ = tmp & 0xff; 118656819Sralph *to++ = (tmp >> 8) & 0xff; 118756819Sralph bptr += 2; 118856819Sralph len -= 2; 118956819Sralph } 119056819Sralph } else { 119156819Sralph /* optimize for aligned transfers */ 119256819Sralph xfer = (int)((unsigned)len & ~0x1); 119356819Sralph CopyFromBuffer(bptr, to, xfer); 119456819Sralph bptr += xfer; 119556819Sralph to += xfer; 119656819Sralph len -= xfer; 119756819Sralph } 119856819Sralph if (len == 1) 119956819Sralph *to = *bptr & 0xff; 120056819Sralph } 120156819Sralph 120256819Sralph void 120356819Sralph bzerobuf_gap2(lebuf, boff, len) 120456819Sralph volatile void *lebuf; 120556819Sralph int boff; 120656819Sralph int len; 120756819Sralph { 120856819Sralph register volatile u_short *bptr; 120956819Sralph 121056819Sralph if ((unsigned)boff & 0x1) { 121156819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1); 121256819Sralph *bptr &= 0xff; 121356819Sralph bptr += 2; 121456819Sralph len--; 121556819Sralph } else 121656819Sralph bptr = ((volatile u_short *)lebuf) + boff; 121756819Sralph while (len > 0) { 121856819Sralph *bptr = 0; 121956819Sralph bptr += 2; 122056819Sralph len -= 2; 122156819Sralph } 122256819Sralph } 122356819Sralph 122456819Sralph /* 122556819Sralph * For the 3min and maxine, the buffers are in main memory filled in with 122656819Sralph * 16byte blocks interspersed with 16byte spaces. 122756819Sralph */ 122856819Sralph void 122956819Sralph copytobuf_gap16(from, lebuf, boff, len) 123056819Sralph register char *from; 123156819Sralph volatile void *lebuf; 123256819Sralph int boff; 123356819Sralph register int len; 123456819Sralph { 123556819Sralph register char *bptr; 123656819Sralph register int xfer; 123756819Sralph 123856819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 123956819Sralph boff &= 0xf; 124056819Sralph xfer = min(len, 16 - boff); 124156819Sralph while (len > 0) { 124256819Sralph bcopy(from, ((char *)bptr) + boff, xfer); 124356819Sralph from += xfer; 124456819Sralph bptr += 32; 124556819Sralph boff = 0; 124656819Sralph len -= xfer; 124756819Sralph xfer = min(len, 16); 124856819Sralph } 124956819Sralph } 125056819Sralph 125156819Sralph void 125256819Sralph copyfrombuf_gap16(lebuf, boff, to, len) 125356819Sralph volatile void *lebuf; 125456819Sralph int boff; 125556819Sralph register char *to; 125656819Sralph register int len; 125756819Sralph { 125856819Sralph register char *bptr; 125956819Sralph register int xfer; 126056819Sralph 126156819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 126256819Sralph boff &= 0xf; 126356819Sralph xfer = min(len, 16 - boff); 126456819Sralph while (len > 0) { 126556819Sralph bcopy(((char *)bptr) + boff, to, xfer); 126656819Sralph to += xfer; 126756819Sralph bptr += 32; 126856819Sralph boff = 0; 126956819Sralph len -= xfer; 127056819Sralph xfer = min(len, 16); 127156819Sralph } 127256819Sralph } 127356819Sralph 127456819Sralph void 127556819Sralph bzerobuf_gap16(lebuf, boff, len) 127656819Sralph volatile void *lebuf; 127756819Sralph int boff; 127856819Sralph register int len; 127956819Sralph { 128056819Sralph register char *bptr; 128156819Sralph register int xfer; 128256819Sralph 128356819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f); 128456819Sralph boff &= 0xf; 128556819Sralph xfer = min(len, 16 - boff); 128656819Sralph while (len > 0) { 128756819Sralph bzero(((char *)bptr) + boff, xfer); 128856819Sralph bptr += 32; 128956819Sralph boff = 0; 129056819Sralph len -= xfer; 129156819Sralph xfer = min(len, 16); 129256819Sralph } 129356819Sralph } 129456819Sralph #endif /* NLE */ 1295