156819Sralph /*-
263636Sbostic * Copyright (c) 1992, 1993
363636Sbostic * The Regents of the University of California. 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*67798Smckusick * @(#)if_le.c 8.4 (Berkeley) 10/09/94
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
8167479Smckusick int ledebug = 0; /* 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
lesetladrf(le)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
26767479Smckusick * order 6 bits as an 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
lereset(unit)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 */
leinit(unit)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 */
437*67798Smckusick if (ifp->if_addrlist == NULL)
438*67798Smckusick return;
43952130Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) {
44052130Smckusick s = splnet();
44152130Smckusick ifp->if_flags |= IFF_RUNNING;
44252130Smckusick lereset(unit);
44352130Smckusick (void) lestart(ifp);
44452130Smckusick splx(s);
44552130Smckusick }
44652130Smckusick }
44752130Smckusick
44852130Smckusick #define LENEXTTMP \
44956819Sralph if (++bix == LETBUF) \
45056819Sralph bix = 0; \
45156819Sralph tmd = LER2_TMDADDR(le->sc_r2, bix)
45252130Smckusick
45352130Smckusick /*
45452130Smckusick * Start output on interface. Get another datagram to send
45552130Smckusick * off of the interface queue, and copy it to the interface
45652130Smckusick * before starting the output.
45752130Smckusick */
45852130Smckusick lestart(ifp)
45952130Smckusick struct ifnet *ifp;
46052130Smckusick {
46152130Smckusick register struct le_softc *le = &le_softc[ifp->if_unit];
46252130Smckusick register int bix = le->sc_tmdnext;
46356819Sralph register volatile void *tmd = LER2_TMDADDR(le->sc_r2, bix);
46452130Smckusick register struct mbuf *m;
46552130Smckusick int len = 0;
46652130Smckusick
46752130Smckusick if ((le->sc_if.if_flags & IFF_RUNNING) == 0)
46852130Smckusick return (0);
46952130Smckusick while (bix != le->sc_tmd) {
47056819Sralph if (LER2V_tmd1(tmd) & LE_OWN)
47152130Smckusick panic("lestart");
47252130Smckusick IF_DEQUEUE(&le->sc_if.if_snd, m);
47352130Smckusick if (m == 0)
47452130Smckusick break;
47552130Smckusick #if NBPFILTER > 0
47652130Smckusick /*
47752130Smckusick * If bpf is listening on this interface, let it
47852130Smckusick * see the packet before we commit it to the wire.
47952130Smckusick */
48059836Sralph if (ifp->if_bpf)
48163635Smckusick bpf_mtap(ifp->if_bpf, m);
48252130Smckusick #endif
48363635Smckusick len = leput(le, LER2_TBUFADDR(le->sc_r2, bix), m);
48456819Sralph LER2_tmd3(tmd, 0);
48556819Sralph LER2_tmd2(tmd, -len);
48656819Sralph LER2_tmd1(tmd, LE_OWN | LE_STP | LE_ENP);
48752130Smckusick LENEXTTMP;
48852130Smckusick }
48952130Smckusick if (len != 0) {
49052130Smckusick le->sc_if.if_flags |= IFF_OACTIVE;
49152130Smckusick LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp);
49252130Smckusick }
49352130Smckusick le->sc_tmdnext = bix;
49452130Smckusick return (0);
49552130Smckusick }
49652130Smckusick
49752130Smckusick /*
49852130Smckusick * Process interrupts from the 7990 chip.
49952130Smckusick */
50052695Sralph void
leintr(unit)50152695Sralph leintr(unit)
50252695Sralph int unit;
50352130Smckusick {
50452130Smckusick register struct le_softc *le;
50552130Smckusick register volatile struct lereg1 *ler1;
50652695Sralph register int stat;
50752130Smckusick
50852130Smckusick le = &le_softc[unit];
50952130Smckusick ler1 = le->sc_r1;
51052130Smckusick stat = ler1->ler1_rdp;
51152130Smckusick if (!(stat & LE_INTR)) {
51253081Sralph printf("le%d: spurrious interrupt\n", unit);
51352130Smckusick return;
51452130Smckusick }
51552130Smckusick if (stat & LE_SERR) {
51652130Smckusick leerror(unit, stat);
51752130Smckusick if (stat & LE_MERR) {
51852130Smckusick le->sc_merr++;
51952130Smckusick lereset(unit);
52052130Smckusick return;
52152130Smckusick }
52252130Smckusick if (stat & LE_BABL)
52352130Smckusick le->sc_babl++;
52452130Smckusick if (stat & LE_CERR)
52552130Smckusick le->sc_cerr++;
52652130Smckusick if (stat & LE_MISS)
52752130Smckusick le->sc_miss++;
52852130Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp);
52952130Smckusick }
53052130Smckusick if ((stat & LE_RXON) == 0) {
53152130Smckusick le->sc_rxoff++;
53252130Smckusick lereset(unit);
53352130Smckusick return;
53452130Smckusick }
53552130Smckusick if ((stat & LE_TXON) == 0) {
53652130Smckusick le->sc_txoff++;
53752130Smckusick lereset(unit);
53852130Smckusick return;
53952130Smckusick }
54052130Smckusick if (stat & LE_RINT) {
54152130Smckusick /* interrupt is cleared in lerint */
54252130Smckusick lerint(unit);
54352130Smckusick }
54452130Smckusick if (stat & LE_TINT) {
54552130Smckusick LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp);
54652130Smckusick lexint(unit);
54752130Smckusick }
54852130Smckusick }
54952130Smckusick
55052130Smckusick /*
55152130Smckusick * Ethernet interface transmitter interrupt.
55252130Smckusick * Start another output if more data to send.
55352130Smckusick */
lexint(unit)55452130Smckusick lexint(unit)
55552130Smckusick register int unit;
55652130Smckusick {
55752130Smckusick register struct le_softc *le = &le_softc[unit];
55852130Smckusick register int bix = le->sc_tmd;
55956819Sralph register volatile void *tmd;
56052130Smckusick
56152130Smckusick if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) {
56252130Smckusick le->sc_xint++;
56352130Smckusick return;
56452130Smckusick }
56552130Smckusick LENEXTTMP;
56656819Sralph while (bix != le->sc_tmdnext && (LER2V_tmd1(tmd) & LE_OWN) == 0) {
56752130Smckusick le->sc_tmd = bix;
56856819Sralph if ((LER2V_tmd1(tmd) & LE_ERR) || (LER2V_tmd3(tmd) & LE_TBUFF)) {
56952130Smckusick lexerror(unit);
57052130Smckusick le->sc_if.if_oerrors++;
57156819Sralph if (LER2V_tmd3(tmd) & (LE_TBUFF|LE_UFLO)) {
57252130Smckusick le->sc_uflo++;
57352130Smckusick lereset(unit);
57452130Smckusick break;
57552130Smckusick }
57656819Sralph else if (LER2V_tmd3(tmd) & LE_LCOL)
57752130Smckusick le->sc_if.if_collisions++;
57856819Sralph else if (LER2V_tmd3(tmd) & LE_RTRY)
57952130Smckusick le->sc_if.if_collisions += 16;
58052130Smckusick }
58156819Sralph else if (LER2V_tmd1(tmd) & LE_ONE)
58252130Smckusick le->sc_if.if_collisions++;
58356819Sralph else if (LER2V_tmd1(tmd) & LE_MORE)
58452130Smckusick /* what is the real number? */
58552130Smckusick le->sc_if.if_collisions += 2;
58652130Smckusick else
58752130Smckusick le->sc_if.if_opackets++;
58852130Smckusick LENEXTTMP;
58952130Smckusick }
59052130Smckusick if (bix == le->sc_tmdnext)
59152130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE;
59252130Smckusick (void) lestart(&le->sc_if);
59352130Smckusick }
59452130Smckusick
59552130Smckusick #define LENEXTRMP \
59656819Sralph if (++bix == LERBUF) \
59756819Sralph bix = 0; \
59856819Sralph rmd = LER2_RMDADDR(le->sc_r2, bix)
59952130Smckusick
60052130Smckusick /*
60152130Smckusick * Ethernet interface receiver interrupt.
60252130Smckusick * If input error just drop packet.
60352130Smckusick * Decapsulate packet based on type and pass to type specific
60452130Smckusick * higher-level input routine.
60552130Smckusick */
lerint(unit)60652130Smckusick lerint(unit)
60752130Smckusick int unit;
60852130Smckusick {
60952130Smckusick register struct le_softc *le = &le_softc[unit];
61052130Smckusick register int bix = le->sc_rmd;
61156819Sralph register volatile void *rmd = LER2_RMDADDR(le->sc_r2, bix);
61252130Smckusick
61352130Smckusick /*
61452130Smckusick * Out of sync with hardware, should never happen?
61552130Smckusick */
61656819Sralph if (LER2V_rmd1(rmd) & LE_OWN) {
61759836Sralph le->sc_rown++;
61852130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
61952130Smckusick return;
62052130Smckusick }
62152130Smckusick
62252130Smckusick /*
62352130Smckusick * Process all buffers with valid data
62452130Smckusick */
62556819Sralph while ((LER2V_rmd1(rmd) & LE_OWN) == 0) {
62656819Sralph int len = LER2V_rmd3(rmd);
62752130Smckusick
62852130Smckusick /* Clear interrupt to avoid race condition */
62952130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
63052130Smckusick
63156819Sralph if (LER2V_rmd1(rmd) & LE_ERR) {
63252130Smckusick le->sc_rmd = bix;
63352130Smckusick lererror(unit, "bad packet");
63452130Smckusick le->sc_if.if_ierrors++;
63556819Sralph } else if ((LER2V_rmd1(rmd) & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
63652130Smckusick /*
63752130Smckusick * Find the end of the packet so we can see how long
63852130Smckusick * it was. We still throw it away.
63952130Smckusick */
64052130Smckusick do {
64152130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA,
64252130Smckusick le->sc_r1->ler1_rdp);
64356819Sralph LER2_rmd3(rmd, 0);
64456819Sralph LER2_rmd1(rmd, LE_OWN);
64552130Smckusick LENEXTRMP;
64656819Sralph } while (!(LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
64752130Smckusick le->sc_rmd = bix;
64852130Smckusick lererror(unit, "chained buffer");
64952130Smckusick le->sc_rxlen++;
65052130Smckusick /*
65152130Smckusick * If search terminated without successful completion
65252130Smckusick * we reset the hardware (conservative).
65352130Smckusick */
65456819Sralph if ((LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) !=
65552130Smckusick LE_ENP) {
65652130Smckusick lereset(unit);
65752130Smckusick return;
65852130Smckusick }
65952130Smckusick } else
66056819Sralph leread(unit, LER2_RBUFADDR(le->sc_r2, bix), len);
66156819Sralph LER2_rmd3(rmd, 0);
66256819Sralph LER2_rmd1(rmd, LE_OWN);
66352130Smckusick LENEXTRMP;
66452130Smckusick }
66552130Smckusick MachEmptyWriteBuffer(); /* Paranoia */
66652130Smckusick le->sc_rmd = bix;
66752130Smckusick }
66852130Smckusick
66952130Smckusick /*
67052130Smckusick * Look at the packet in network buffer memory so we can be smart about how
67152130Smckusick * we copy the data into mbufs.
67252130Smckusick * This needs work since we can't just read network buffer memory like
67352130Smckusick * regular memory.
67452130Smckusick */
leread(unit,buf,len)67552130Smckusick leread(unit, buf, len)
67652130Smckusick int unit;
67756819Sralph volatile void *buf;
67852130Smckusick int len;
67952130Smckusick {
68052130Smckusick register struct le_softc *le = &le_softc[unit];
68152130Smckusick struct ether_header et;
68263635Smckusick struct mbuf *m;
68359836Sralph int off, resid, flags;
68456819Sralph u_short sbuf[2], eth_type;
68552695Sralph extern struct mbuf *leget();
68652130Smckusick
68752130Smckusick le->sc_if.if_ipackets++;
68856819Sralph (*le->sc_copyfrombuf)(buf, 0, (char *)&et, sizeof (et));
68956819Sralph eth_type = ntohs(et.ether_type);
69052130Smckusick /* adjust input length to account for header and CRC */
69152130Smckusick len = len - sizeof(struct ether_header) - 4;
69252130Smckusick
69356819Sralph if (eth_type >= ETHERTYPE_TRAIL &&
69456819Sralph eth_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
69556819Sralph off = (eth_type - ETHERTYPE_TRAIL) * 512;
69652130Smckusick if (off >= ETHERMTU)
69752130Smckusick return; /* sanity */
69856819Sralph (*le->sc_copyfrombuf)(buf, sizeof (et) + off, (char *)sbuf,
69956819Sralph sizeof (sbuf));
70056819Sralph eth_type = ntohs(sbuf[0]);
70152130Smckusick resid = ntohs(sbuf[1]);
70252130Smckusick if (off + resid > len)
70352130Smckusick return; /* sanity */
70452130Smckusick len = off + resid;
70552130Smckusick } else
70652130Smckusick off = 0;
70752130Smckusick
70852130Smckusick if (len <= 0) {
70952130Smckusick if (ledebug)
71052130Smckusick log(LOG_WARNING,
71152130Smckusick "le%d: ierror(runt packet): from %s: len=%d\n",
71252130Smckusick unit, ether_sprintf(et.ether_shost), len);
71352130Smckusick le->sc_runt++;
71452130Smckusick le->sc_if.if_ierrors++;
71552130Smckusick return;
71652130Smckusick }
71759836Sralph flags = 0;
71859836Sralph if (bcmp((caddr_t)etherbroadcastaddr,
71959836Sralph (caddr_t)et.ether_dhost, sizeof(etherbroadcastaddr)) == 0)
72059836Sralph flags |= M_BCAST;
72159836Sralph if (et.ether_dhost[0] & 1)
72259836Sralph flags |= M_MCAST;
72352130Smckusick
72463635Smckusick /*
72563635Smckusick * Pull packet off interface. Off is nonzero if packet
72663635Smckusick * has trailing header; leget will then force this header
72763635Smckusick * information to be at the front, but we still have to drop
72863635Smckusick * the type and length which are at the front of any trailer data.
72963635Smckusick */
73063635Smckusick m = leget(le, buf, len, off, &le->sc_if);
73163635Smckusick if (m == 0)
73263635Smckusick return;
73359836Sralph #if NBPFILTER > 0
73452130Smckusick /*
73559836Sralph * Check if there's a bpf filter listening on this interface.
73659836Sralph * If so, hand off the raw packet to enet.
73759836Sralph */
73859836Sralph if (le->sc_if.if_bpf) {
73963635Smckusick bpf_mtap(le->sc_if.if_bpf, m);
74059836Sralph
74159836Sralph /*
74259836Sralph * Keep the packet if it's a broadcast or has our
74359836Sralph * physical ethernet address (or if we support
74459836Sralph * multicast and it's one).
74559836Sralph */
74659836Sralph if (
74759836Sralph #ifdef MULTICAST
74859836Sralph (flags & (M_BCAST | M_MCAST)) == 0 &&
74959836Sralph #else
75059836Sralph (flags & M_BCAST) == 0 &&
75159836Sralph #endif
75259836Sralph bcmp(et.ether_dhost, le->sc_addr,
75363635Smckusick sizeof(et.ether_dhost)) != 0) {
75463635Smckusick m_freem(m);
75559836Sralph return;
75663635Smckusick }
75759836Sralph }
75859836Sralph #endif
75959836Sralph m->m_flags |= flags;
76056819Sralph et.ether_type = eth_type;
76152130Smckusick ether_input(&le->sc_if, &et, m);
76252130Smckusick }
76352130Smckusick
76452130Smckusick /*
76552130Smckusick * Routine to copy from mbuf chain to transmit buffer in
76652130Smckusick * network buffer memory.
76752130Smckusick */
76856819Sralph leput(le, lebuf, m)
76956819Sralph struct le_softc *le;
77056819Sralph register volatile void *lebuf;
77152130Smckusick register struct mbuf *m;
77252130Smckusick {
77352130Smckusick register struct mbuf *mp;
77452695Sralph register int len, tlen = 0;
77556819Sralph register int boff = 0;
77652130Smckusick
77752130Smckusick for (mp = m; mp; mp = mp->m_next) {
77852130Smckusick len = mp->m_len;
77952130Smckusick if (len == 0)
78052130Smckusick continue;
78156819Sralph (*le->sc_copytobuf)(mtod(mp, char *), lebuf, boff, len);
78252130Smckusick tlen += len;
78356819Sralph boff += len;
78452130Smckusick }
78552130Smckusick m_freem(m);
78652695Sralph if (tlen < LEMINSIZE) {
78756819Sralph (*le->sc_zerobuf)(lebuf, boff, LEMINSIZE - tlen);
78852130Smckusick tlen = LEMINSIZE;
78952695Sralph }
79052130Smckusick return(tlen);
79152130Smckusick }
79252130Smckusick
79352130Smckusick /*
79452130Smckusick * Routine to copy from network buffer memory into mbufs.
79552130Smckusick */
79652130Smckusick struct mbuf *
leget(le,lebuf,totlen,off,ifp)79763635Smckusick leget(le, lebuf, totlen, off, ifp)
79856819Sralph struct le_softc *le;
79956819Sralph volatile void *lebuf;
80052130Smckusick int totlen, off;
80152130Smckusick struct ifnet *ifp;
80252130Smckusick {
80352130Smckusick register struct mbuf *m;
80452130Smckusick struct mbuf *top = 0, **mp = ⊤
80556819Sralph register int len, resid, boff;
80652130Smckusick
80752130Smckusick /* NOTE: sizeof(struct ether_header) should be even */
80856819Sralph boff = sizeof(struct ether_header);
80952130Smckusick if (off) {
81052130Smckusick /* NOTE: off should be even */
81156819Sralph boff += off + 2 * sizeof(u_short);
81252130Smckusick totlen -= 2 * sizeof(u_short);
81352130Smckusick resid = totlen - off;
81452130Smckusick } else
81552130Smckusick resid = totlen;
81652130Smckusick
81752130Smckusick MGETHDR(m, M_DONTWAIT, MT_DATA);
81852130Smckusick if (m == 0)
81952130Smckusick return (0);
82052130Smckusick m->m_pkthdr.rcvif = ifp;
82152130Smckusick m->m_pkthdr.len = totlen;
82252130Smckusick m->m_len = MHLEN;
82352130Smckusick
82452130Smckusick while (totlen > 0) {
82552130Smckusick if (top) {
82652130Smckusick MGET(m, M_DONTWAIT, MT_DATA);
82752130Smckusick if (m == 0) {
82852130Smckusick m_freem(top);
82952130Smckusick return (0);
83052130Smckusick }
83152130Smckusick m->m_len = MLEN;
83252130Smckusick }
83352130Smckusick
83452130Smckusick if (resid >= MINCLSIZE)
83552130Smckusick MCLGET(m, M_DONTWAIT);
83652130Smckusick if (m->m_flags & M_EXT)
83755745Sralph m->m_len = min(resid, MCLBYTES);
83852130Smckusick else if (resid < m->m_len) {
83952130Smckusick /*
84052130Smckusick * Place initial small packet/header at end of mbuf.
84152130Smckusick */
84252130Smckusick if (top == 0 && resid + max_linkhdr <= m->m_len)
84352130Smckusick m->m_data += max_linkhdr;
84452130Smckusick m->m_len = resid;
84552130Smckusick }
84652130Smckusick len = m->m_len;
84756819Sralph (*le->sc_copyfrombuf)(lebuf, boff, mtod(m, char *), len);
84856819Sralph boff += len;
84952130Smckusick *mp = m;
85052130Smckusick mp = &m->m_next;
85152130Smckusick totlen -= len;
85252130Smckusick resid -= len;
85352130Smckusick if (resid == 0) {
85456819Sralph boff = sizeof (struct ether_header);
85552130Smckusick resid = totlen;
85652130Smckusick }
85752130Smckusick }
85852130Smckusick return (top);
85952130Smckusick }
86052130Smckusick
86152130Smckusick /*
86252130Smckusick * Process an ioctl request.
86352130Smckusick */
leioctl(ifp,cmd,data)86452130Smckusick leioctl(ifp, cmd, data)
86552130Smckusick register struct ifnet *ifp;
86652130Smckusick int cmd;
86752130Smckusick caddr_t data;
86852130Smckusick {
86952130Smckusick register struct ifaddr *ifa = (struct ifaddr *)data;
87052130Smckusick struct le_softc *le = &le_softc[ifp->if_unit];
87152130Smckusick volatile struct lereg1 *ler1 = le->sc_r1;
87252130Smckusick int s, error = 0;
87352130Smckusick
87452130Smckusick s = splnet();
87552130Smckusick switch (cmd) {
87652130Smckusick
87752130Smckusick case SIOCSIFADDR:
87852130Smckusick ifp->if_flags |= IFF_UP;
87952130Smckusick switch (ifa->ifa_addr->sa_family) {
88052130Smckusick #ifdef INET
88152130Smckusick case AF_INET:
88252130Smckusick leinit(ifp->if_unit); /* before arpwhohas */
88352130Smckusick ((struct arpcom *)ifp)->ac_ipaddr =
88452130Smckusick IA_SIN(ifa)->sin_addr;
88552130Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
88652130Smckusick break;
88752130Smckusick #endif
88852130Smckusick #ifdef NS
88952130Smckusick case AF_NS:
89052130Smckusick {
89152130Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
89252130Smckusick
89352130Smckusick if (ns_nullhost(*ina))
89452130Smckusick ina->x_host = *(union ns_host *)(le->sc_addr);
89552130Smckusick else {
89652130Smckusick /*
89752130Smckusick * The manual says we can't change the address
89852130Smckusick * while the receiver is armed,
89952130Smckusick * so reset everything
90052130Smckusick */
90152130Smckusick ifp->if_flags &= ~IFF_RUNNING;
90259836Sralph LEWREG(LE_STOP, ler1->ler1_rdp);
90352130Smckusick bcopy((caddr_t)ina->x_host.c_host,
90452130Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr));
90552130Smckusick }
90652130Smckusick leinit(ifp->if_unit); /* does le_setaddr() */
90752130Smckusick break;
90852130Smckusick }
90952130Smckusick #endif
91052130Smckusick default:
91152130Smckusick leinit(ifp->if_unit);
91252130Smckusick break;
91352130Smckusick }
91452130Smckusick break;
91552130Smckusick
91659836Sralph #if defined (CCITT) && defined (LLC)
91759836Sralph case SIOCSIFCONF_X25:
91859836Sralph ifp->if_flags |= IFF_UP;
91959836Sralph ifa->ifa_rtrequest = cons_rtrequest;
92059836Sralph error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
92159836Sralph if (error == 0)
92259836Sralph leinit(ifp->if_unit);
92359836Sralph break;
92459836Sralph #endif /* CCITT && LLC */
92559836Sralph
92652130Smckusick case SIOCSIFFLAGS:
92752130Smckusick if ((ifp->if_flags & IFF_UP) == 0 &&
92852130Smckusick ifp->if_flags & IFF_RUNNING) {
92956819Sralph LEWREG(LE_STOP, ler1->ler1_rdp);
93052130Smckusick ifp->if_flags &= ~IFF_RUNNING;
93152130Smckusick } else if (ifp->if_flags & IFF_UP &&
93252130Smckusick (ifp->if_flags & IFF_RUNNING) == 0)
93352130Smckusick leinit(ifp->if_unit);
93452130Smckusick /*
93552130Smckusick * If the state of the promiscuous bit changes, the interface
93652130Smckusick * must be reset to effect the change.
93752130Smckusick */
93852130Smckusick if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) &&
93952130Smckusick (ifp->if_flags & IFF_RUNNING)) {
94052130Smckusick le->sc_iflags = ifp->if_flags;
94152130Smckusick lereset(ifp->if_unit);
94252130Smckusick lestart(ifp);
94352130Smckusick }
94452130Smckusick break;
94552130Smckusick
94659836Sralph #ifdef MULTICAST
94759836Sralph case SIOCADDMULTI:
94859836Sralph case SIOCDELMULTI:
94959836Sralph /* Update our multicast list */
95059836Sralph error = (cmd == SIOCADDMULTI) ?
95159836Sralph ether_addmulti((struct ifreq *)data, &le->sc_ac) :
95259836Sralph ether_delmulti((struct ifreq *)data, &le->sc_ac);
95359836Sralph
95459836Sralph if (error == ENETRESET) {
95559836Sralph /*
95659836Sralph * Multicast list has changed; set the hardware
95759836Sralph * filter accordingly.
95859836Sralph */
95959836Sralph lereset(ifp->if_unit);
96059836Sralph error = 0;
96159836Sralph }
96259836Sralph break;
96359836Sralph #endif
96459836Sralph
96552130Smckusick default:
96652130Smckusick error = EINVAL;
96752130Smckusick }
96852130Smckusick splx(s);
96952130Smckusick return (error);
97052130Smckusick }
97152130Smckusick
leerror(unit,stat)97252130Smckusick leerror(unit, stat)
97352130Smckusick int unit;
97452130Smckusick int stat;
97552130Smckusick {
97652130Smckusick if (!ledebug)
97752130Smckusick return;
97852130Smckusick
97952130Smckusick /*
98052130Smckusick * Not all transceivers implement heartbeat
98152130Smckusick * so we only log CERR once.
98252130Smckusick */
98352130Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr)
98452130Smckusick return;
98552130Smckusick log(LOG_WARNING,
98652130Smckusick "le%d: error: stat=%b\n", unit,
98752130Smckusick stat,
98852130Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");
98952130Smckusick }
99052130Smckusick
lererror(unit,msg)99152130Smckusick lererror(unit, msg)
99252130Smckusick int unit;
99352130Smckusick char *msg;
99452130Smckusick {
99552130Smckusick register struct le_softc *le = &le_softc[unit];
99656819Sralph register volatile void *rmd;
99754144Sralph u_char eaddr[6];
99852130Smckusick int len;
99952130Smckusick
100052130Smckusick if (!ledebug)
100152130Smckusick return;
100252130Smckusick
100356819Sralph rmd = LER2_RMDADDR(le->sc_r2, le->sc_rmd);
100456819Sralph len = LER2V_rmd3(rmd);
100556819Sralph if (len > 11)
100656819Sralph (*le->sc_copyfrombuf)(LER2_RBUFADDR(le->sc_r2, le->sc_rmd),
100756819Sralph 6, eaddr, 6);
100852130Smckusick log(LOG_WARNING,
100952130Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
101056819Sralph unit, msg,
101156819Sralph len > 11 ? ether_sprintf(eaddr) : "unknown",
101256819Sralph le->sc_rmd, len,
101356819Sralph LER2V_rmd1(rmd),
101452130Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");
101552130Smckusick }
101652130Smckusick
lexerror(unit)101752130Smckusick lexerror(unit)
101852130Smckusick int unit;
101952130Smckusick {
102052130Smckusick register struct le_softc *le = &le_softc[unit];
102156819Sralph register volatile void *tmd;
102254144Sralph u_char eaddr[6];
102352130Smckusick int len;
102452130Smckusick
102552130Smckusick if (!ledebug)
102652130Smckusick return;
102752130Smckusick
102856819Sralph tmd = LER2_TMDADDR(le->sc_r2, 0);
102956819Sralph len = -LER2V_tmd2(tmd);
103056819Sralph if (len > 5)
103156819Sralph (*le->sc_copyfrombuf)(LER2_TBUFADDR(le->sc_r2, 0), 0, eaddr, 6);
103252130Smckusick log(LOG_WARNING,
103352130Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n",
103456819Sralph unit,
103556819Sralph len > 5 ? ether_sprintf(eaddr) : "unknown",
103656819Sralph 0, len,
103756819Sralph LER2V_tmd1(tmd),
103852130Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP",
103956819Sralph LER2V_tmd3(tmd),
104052130Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
104152130Smckusick }
104256819Sralph
104356819Sralph /*
104456819Sralph * Write a lance register port, reading it back to ensure success. This seems
104556819Sralph * to be necessary during initialization, since the chip appears to be a bit
104656819Sralph * pokey sometimes.
104756819Sralph */
104856819Sralph static void
lewritereg(regptr,val)104956819Sralph lewritereg(regptr, val)
105056819Sralph register volatile u_short *regptr;
105156819Sralph register u_short val;
105256819Sralph {
105356819Sralph register int i = 0;
105456819Sralph
105556819Sralph while (*regptr != val) {
105656819Sralph *regptr = val;
105756819Sralph MachEmptyWriteBuffer();
105856819Sralph if (++i > 10000) {
105956819Sralph printf("le: Reg did not settle (to x%x): x%x\n",
106056819Sralph val, *regptr);
106156819Sralph return;
106256819Sralph }
106356819Sralph DELAY(100);
106456819Sralph }
106556819Sralph }
106656819Sralph
106756819Sralph /*
106856819Sralph * Routines for accessing the transmit and receive buffers. Unfortunately,
106956819Sralph * CPU addressing of these buffers is done in one of 3 ways:
107056819Sralph * - contiguous (for the 3max and turbochannel option card)
107156819Sralph * - gap2, which means shorts (2 bytes) interspersed with short (2 byte)
107256819Sralph * spaces (for the pmax)
107356819Sralph * - gap16, which means 16bytes interspersed with 16byte spaces
107456819Sralph * for buffers which must begin on a 32byte boundary (for 3min and maxine)
107556819Sralph * The buffer offset is the logical byte offset, assuming contiguous storage.
107656819Sralph */
107756819Sralph void
copytobuf_contig(from,lebuf,boff,len)107856819Sralph copytobuf_contig(from, lebuf, boff, len)
107956819Sralph char *from;
108056819Sralph volatile void *lebuf;
108156819Sralph int boff;
108256819Sralph int len;
108356819Sralph {
108456819Sralph
108556819Sralph /*
108656819Sralph * Just call bcopy() to do the work.
108756819Sralph */
108856819Sralph bcopy(from, ((char *)lebuf) + boff, len);
108956819Sralph }
109056819Sralph
109156819Sralph void
copyfrombuf_contig(lebuf,boff,to,len)109256819Sralph copyfrombuf_contig(lebuf, boff, to, len)
109356819Sralph volatile void *lebuf;
109456819Sralph int boff;
109556819Sralph char *to;
109656819Sralph int len;
109756819Sralph {
109856819Sralph
109956819Sralph /*
110056819Sralph * Just call bcopy() to do the work.
110156819Sralph */
110256819Sralph bcopy(((char *)lebuf) + boff, to, len);
110356819Sralph }
110456819Sralph
110556819Sralph void
bzerobuf_contig(lebuf,boff,len)110656819Sralph bzerobuf_contig(lebuf, boff, len)
110756819Sralph volatile void *lebuf;
110856819Sralph int boff;
110956819Sralph int len;
111056819Sralph {
111156819Sralph
111256819Sralph /*
111356819Sralph * Just let bzero() do the work
111456819Sralph */
111556819Sralph bzero(((char *)lebuf) + boff, len);
111656819Sralph }
111756819Sralph
111856819Sralph /*
111956819Sralph * For the pmax the buffer consists of shorts (2 bytes) interspersed with
112056819Sralph * short (2 byte) spaces and must be accessed with halfword load/stores.
112156819Sralph * (don't worry about doing an extra byte)
112256819Sralph */
112356819Sralph void
copytobuf_gap2(from,lebuf,boff,len)112456819Sralph copytobuf_gap2(from, lebuf, boff, len)
112556819Sralph register char *from;
112656819Sralph volatile void *lebuf;
112756819Sralph int boff;
112856819Sralph register int len;
112956819Sralph {
113056819Sralph register volatile u_short *bptr;
113156819Sralph register int xfer;
113256819Sralph
113356819Sralph if (boff & 0x1) {
113456819Sralph /* handle unaligned first byte */
113556819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1);
113656819Sralph *bptr = (*from++ << 8) | (*bptr & 0xff);
113756819Sralph bptr += 2;
113856819Sralph len--;
113956819Sralph } else
114056819Sralph bptr = ((volatile u_short *)lebuf) + boff;
114156819Sralph if ((unsigned)from & 0x1) {
114256819Sralph while (len > 1) {
114364894Sbostic *bptr = (from[1] << 8) | (from[0] & 0xff);
114456819Sralph bptr += 2;
114556819Sralph from += 2;
114656819Sralph len -= 2;
114756819Sralph }
114856819Sralph } else {
114956819Sralph /* optimize for aligned transfers */
115056819Sralph xfer = (int)((unsigned)len & ~0x1);
115156819Sralph CopyToBuffer((u_short *)from, bptr, xfer);
115256819Sralph bptr += xfer;
115356819Sralph from += xfer;
115456819Sralph len -= xfer;
115556819Sralph }
115656819Sralph if (len == 1)
115756819Sralph *bptr = (u_short)*from;
115856819Sralph }
115956819Sralph
116056819Sralph void
copyfrombuf_gap2(lebuf,boff,to,len)116156819Sralph copyfrombuf_gap2(lebuf, boff, to, len)
116256819Sralph volatile void *lebuf;
116356819Sralph int boff;
116456819Sralph register char *to;
116556819Sralph register int len;
116656819Sralph {
116756819Sralph register volatile u_short *bptr;
116856819Sralph register u_short tmp;
116956819Sralph register int xfer;
117056819Sralph
117156819Sralph if (boff & 0x1) {
117256819Sralph /* handle unaligned first byte */
117356819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1);
117456819Sralph *to++ = (*bptr >> 8) & 0xff;
117556819Sralph bptr += 2;
117656819Sralph len--;
117756819Sralph } else
117856819Sralph bptr = ((volatile u_short *)lebuf) + boff;
117956819Sralph if ((unsigned)to & 0x1) {
118056819Sralph while (len > 1) {
118156819Sralph tmp = *bptr;
118256819Sralph *to++ = tmp & 0xff;
118356819Sralph *to++ = (tmp >> 8) & 0xff;
118456819Sralph bptr += 2;
118556819Sralph len -= 2;
118656819Sralph }
118756819Sralph } else {
118856819Sralph /* optimize for aligned transfers */
118956819Sralph xfer = (int)((unsigned)len & ~0x1);
119056819Sralph CopyFromBuffer(bptr, to, xfer);
119156819Sralph bptr += xfer;
119256819Sralph to += xfer;
119356819Sralph len -= xfer;
119456819Sralph }
119556819Sralph if (len == 1)
119656819Sralph *to = *bptr & 0xff;
119756819Sralph }
119856819Sralph
119956819Sralph void
bzerobuf_gap2(lebuf,boff,len)120056819Sralph bzerobuf_gap2(lebuf, boff, len)
120156819Sralph volatile void *lebuf;
120256819Sralph int boff;
120356819Sralph int len;
120456819Sralph {
120556819Sralph register volatile u_short *bptr;
120656819Sralph
120756819Sralph if ((unsigned)boff & 0x1) {
120856819Sralph bptr = ((volatile u_short *)lebuf) + (boff - 1);
120956819Sralph *bptr &= 0xff;
121056819Sralph bptr += 2;
121156819Sralph len--;
121256819Sralph } else
121356819Sralph bptr = ((volatile u_short *)lebuf) + boff;
121456819Sralph while (len > 0) {
121556819Sralph *bptr = 0;
121656819Sralph bptr += 2;
121756819Sralph len -= 2;
121856819Sralph }
121956819Sralph }
122056819Sralph
122156819Sralph /*
122256819Sralph * For the 3min and maxine, the buffers are in main memory filled in with
122356819Sralph * 16byte blocks interspersed with 16byte spaces.
122456819Sralph */
122556819Sralph void
copytobuf_gap16(from,lebuf,boff,len)122656819Sralph copytobuf_gap16(from, lebuf, boff, len)
122756819Sralph register char *from;
122856819Sralph volatile void *lebuf;
122956819Sralph int boff;
123056819Sralph register int len;
123156819Sralph {
123256819Sralph register char *bptr;
123356819Sralph register int xfer;
123456819Sralph
123556819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f);
123656819Sralph boff &= 0xf;
123756819Sralph xfer = min(len, 16 - boff);
123856819Sralph while (len > 0) {
123956819Sralph bcopy(from, ((char *)bptr) + boff, xfer);
124056819Sralph from += xfer;
124156819Sralph bptr += 32;
124256819Sralph boff = 0;
124356819Sralph len -= xfer;
124456819Sralph xfer = min(len, 16);
124556819Sralph }
124656819Sralph }
124756819Sralph
124856819Sralph void
copyfrombuf_gap16(lebuf,boff,to,len)124956819Sralph copyfrombuf_gap16(lebuf, boff, to, len)
125056819Sralph volatile void *lebuf;
125156819Sralph int boff;
125256819Sralph register char *to;
125356819Sralph register int len;
125456819Sralph {
125556819Sralph register char *bptr;
125656819Sralph register int xfer;
125756819Sralph
125856819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f);
125956819Sralph boff &= 0xf;
126056819Sralph xfer = min(len, 16 - boff);
126156819Sralph while (len > 0) {
126256819Sralph bcopy(((char *)bptr) + boff, to, xfer);
126356819Sralph to += xfer;
126456819Sralph bptr += 32;
126556819Sralph boff = 0;
126656819Sralph len -= xfer;
126756819Sralph xfer = min(len, 16);
126856819Sralph }
126956819Sralph }
127056819Sralph
127156819Sralph void
bzerobuf_gap16(lebuf,boff,len)127256819Sralph bzerobuf_gap16(lebuf, boff, len)
127356819Sralph volatile void *lebuf;
127456819Sralph int boff;
127556819Sralph register int len;
127656819Sralph {
127756819Sralph register char *bptr;
127856819Sralph register int xfer;
127956819Sralph
128056819Sralph bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f);
128156819Sralph boff &= 0xf;
128256819Sralph xfer = min(len, 16 - boff);
128356819Sralph while (len > 0) {
128456819Sralph bzero(((char *)bptr) + boff, xfer);
128556819Sralph bptr += 32;
128656819Sralph boff = 0;
128756819Sralph len -= xfer;
128856819Sralph xfer = min(len, 16);
128956819Sralph }
129056819Sralph }
129156819Sralph #endif /* NLE */
1292