xref: /netbsd-src/sys/dev/ic/lemac.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /* $NetBSD: lemac.c,v 1.26 2004/10/30 18:08:37 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 1994, 1995, 1997 Matt Thomas <matt@3am-software.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*
28  * DEC EtherWORKS 3 Ethernet Controllers
29  *
30  * Written by Matt Thomas
31  * BPF support code stolen directly from if_ec.c
32  *
33  *   This driver supports the LEMAC DE203/204/205 cards.
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: lemac.c,v 1.26 2004/10/30 18:08:37 thorpej Exp $");
38 
39 #include "opt_inet.h"
40 #include "opt_ns.h"
41 #include "rnd.h"
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/mbuf.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/errno.h>
50 #include <sys/malloc.h>
51 #include <sys/device.h>
52 #if NRND > 0
53 #include <sys/rnd.h>
54 #endif
55 
56 #include <net/if.h>
57 #include <net/if_types.h>
58 #include <net/if_dl.h>
59 #include <net/route.h>
60 #include <net/if_ether.h>
61 #include <net/if_media.h>
62 
63 #ifdef INET
64 #include <netinet/in.h>
65 #include <netinet/in_systm.h>
66 #include <netinet/in_var.h>
67 #include <netinet/ip.h>
68 #include <netinet/if_inarp.h>
69 #endif
70 
71 #ifdef NS
72 #include <netns/ns.h>
73 #include <netns/ns_if.h>
74 #endif
75 
76 #include <machine/bus.h>
77 
78 #include <dev/ic/lemacreg.h>
79 #include <dev/ic/lemacvar.h>
80 #if 0
81 #include <i386/isa/decether.h>
82 #endif
83 
84 #include <uvm/uvm_extern.h>
85 
86 #include "bpfilter.h"
87 #if NBPFILTER > 0
88 #include <net/bpf.h>
89 #endif
90 
91 static void lemac_init(lemac_softc_t *sc);
92 static void lemac_ifstart(struct ifnet *ifp);
93 static void lemac_reset(lemac_softc_t *sc);
94 static void lemac_rne_intr(lemac_softc_t *sc);
95 static void lemac_tne_intr(lemac_softc_t *sc);
96 static void lemac_txd_intr(lemac_softc_t *sc, unsigned cs_value);
97 static void lemac_rxd_intr(lemac_softc_t *sc, unsigned cs_value);
98 static int  lemac_read_eeprom(lemac_softc_t *sc);
99 static void lemac_init_adapmem(lemac_softc_t *sc);
100 
101 static const u_int16_t lemac_allmulti_mctbl[LEMAC_MCTBL_SIZE/sizeof(u_int16_t)] =  {
102     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
103     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
104     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
105     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
106     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
107     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
108     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
109     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
110 };
111 
112 /*
113  * Some tuning/monitoring variables.
114  */
115 unsigned lemac_txmax = 16;
116 
117 static void
118 lemac_rxd_intr(
119     lemac_softc_t *sc,
120     unsigned cs_value)
121 {
122     /*
123      * Handle CS_RXD (Receiver disabled) here.
124      *
125      * Check Free Memory Queue Count. If not equal to zero
126      * then just turn Receiver back on. If it is equal to
127      * zero then check to see if transmitter is disabled.
128      * Process transmit TXD loop once more.  If all else
129      * fails then do software init (0xC0 to EEPROM Init)
130      * and rebuild Free Memory Queue.
131      */
132 
133     sc->sc_cntrs.cntr_rxd_intrs++;
134 
135     /*
136      *  Re-enable Receiver.
137      */
138 
139     cs_value &= ~LEMAC_CS_RXD;
140     LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value);
141 
142     if (LEMAC_INB(sc, LEMAC_REG_FMC) > 0)
143 	return;
144 
145     if (cs_value & LEMAC_CS_TXD)
146 	lemac_txd_intr(sc, cs_value);
147 
148     if ((LEMAC_INB(sc, LEMAC_REG_CS) & LEMAC_CS_RXD) == 0)
149 	return;
150 
151     printf("%s: fatal RXD error, attempting recovery\n", sc->sc_if.if_xname);
152 
153     lemac_reset(sc);
154     if (sc->sc_if.if_flags & IFF_UP) {
155 	lemac_init(sc);
156 	return;
157     }
158 
159     /*
160      *  Error during initialization.  Mark card as disabled.
161      */
162     printf("%s: recovery failed -- board disabled\n", sc->sc_if.if_xname);
163 }
164 
165 static void
166 lemac_tne_intr(
167     lemac_softc_t *sc)
168 {
169     unsigned txcount = LEMAC_INB(sc, LEMAC_REG_TDC);
170 
171     sc->sc_cntrs.cntr_tne_intrs++;
172     while (txcount-- > 0) {
173 	unsigned txsts = LEMAC_INB(sc, LEMAC_REG_TDQ);
174 	sc->sc_if.if_opackets++;		/* another one done */
175 	if ((txsts & (LEMAC_TDQ_LCL|LEMAC_TDQ_NCL))
176 	        || (txsts & LEMAC_TDQ_COL) == LEMAC_TDQ_EXCCOL) {
177 	    if (txsts & LEMAC_TDQ_NCL)
178 		sc->sc_flags &= ~LEMAC_LINKUP;
179 	    sc->sc_if.if_oerrors++;
180 	} else {
181 	    sc->sc_flags |= LEMAC_LINKUP;
182 	    if ((txsts & LEMAC_TDQ_COL) != LEMAC_TDQ_NOCOL)
183 		sc->sc_if.if_collisions++;
184 	}
185     }
186     sc->sc_if.if_flags &= ~IFF_OACTIVE;
187     lemac_ifstart(&sc->sc_if);
188 }
189 
190 static void
191 lemac_txd_intr(
192     lemac_softc_t *sc,
193     unsigned cs_value)
194 {
195     /*
196      * Read transmit status, remove transmit buffer from
197      * transmit queue and place on free memory queue,
198      * then reset transmitter.
199      * Increment appropriate counters.
200      */
201 
202     sc->sc_cntrs.cntr_txd_intrs++;
203     if (sc->sc_txctl & LEMAC_TX_STP) {
204 	sc->sc_if.if_oerrors++;
205 	/* return page to free queue */
206 	LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ));
207     }
208 
209     /* Turn back on transmitter if disabled */
210     LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value & ~LEMAC_CS_TXD);
211     sc->sc_if.if_flags &= ~IFF_OACTIVE;
212 }
213 
214 static int
215 lemac_read_eeprom(
216     lemac_softc_t *sc)
217 {
218     int	word_off, cksum;
219 
220     u_char *ep;
221 
222     cksum = 0;
223     ep = sc->sc_eeprom;
224     for (word_off = 0; word_off < LEMAC_EEP_SIZE / 2; word_off++) {
225 	LEMAC_OUTB(sc, LEMAC_REG_PI1, word_off);
226 	LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEREAD);
227 
228 	DELAY(LEMAC_EEP_DELAY);
229 
230 	*ep = LEMAC_INB(sc, LEMAC_REG_EE1);	cksum += *ep++;
231 	*ep = LEMAC_INB(sc, LEMAC_REG_EE2);	cksum += *ep++;
232     }
233 
234     /*
235      *  Set up Transmit Control Byte for use later during transmit.
236      */
237 
238     sc->sc_txctl |= LEMAC_TX_FLAGS;
239 
240     if ((sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_SQE) == 0)
241 	sc->sc_txctl &= ~LEMAC_TX_SQE;
242 
243     if (sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_LAB)
244 	sc->sc_txctl |= LEMAC_TX_LAB;
245 
246     memcpy(sc->sc_prodname, &sc->sc_eeprom[LEMAC_EEP_PRDNM], LEMAC_EEP_PRDNMSZ);
247     sc->sc_prodname[LEMAC_EEP_PRDNMSZ] = '\0';
248 
249     return cksum % 256;
250 }
251 
252 static void
253 lemac_init_adapmem(
254     lemac_softc_t *sc)
255 {
256     int pg, conf;
257 
258     conf = LEMAC_INB(sc, LEMAC_REG_CNF);
259 
260     if ((sc->sc_eeprom[LEMAC_EEP_SETUP] & LEMAC_EEP_ST_DRAM) == 0) {
261 	sc->sc_lastpage = 63;
262 	conf &= ~LEMAC_CNF_DRAM;
263     } else {
264 	sc->sc_lastpage = 127;
265 	conf |= LEMAC_CNF_DRAM;
266     }
267 
268     LEMAC_OUTB(sc, LEMAC_REG_CNF, conf);
269 
270     for (pg = 1; pg <= sc->sc_lastpage; pg++)
271 	LEMAC_OUTB(sc, LEMAC_REG_FMQ, pg);
272 }
273 
274 static void
275 lemac_input(
276     lemac_softc_t *sc,
277     bus_addr_t offset,
278     size_t length)
279 {
280     struct ether_header eh;
281     struct mbuf *m;
282 
283     if (length - sizeof(eh) > ETHERMTU
284 	    || length - sizeof(eh) < ETHERMIN) {
285 	sc->sc_if.if_ierrors++;
286 	return;
287     }
288     if (LEMAC_USE_PIO_MODE(sc)) {
289 	LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(eh), (void *) &eh);
290     } else {
291 	LEMAC_GETBUF16(sc, offset, sizeof(eh) / 2, (void *) &eh);
292     }
293 
294     MGETHDR(m, M_DONTWAIT, MT_DATA);
295     if (m == NULL) {
296 	sc->sc_if.if_ierrors++;
297 	return;
298     }
299     if (length + 2 > MHLEN) {
300 	MCLGET(m, M_DONTWAIT);
301 	if ((m->m_flags & M_EXT) == 0) {
302 	    m_free(m);
303 	    sc->sc_if.if_ierrors++;
304 	    return;
305 	}
306     }
307     m->m_data += 2;
308     memcpy(m->m_data, (caddr_t)&eh, sizeof(eh));
309     if (LEMAC_USE_PIO_MODE(sc)) {
310 	LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh),
311 		   mtod(m, caddr_t) + sizeof(eh));
312     } else {
313 	LEMAC_GETBUF16(sc, offset + sizeof(eh), (length - sizeof(eh)) / 2,
314 		      (void *) (mtod(m, caddr_t) + sizeof(eh)));
315 	if (length & 1)
316 	    m->m_data[length - 1] = LEMAC_GET8(sc, offset + length - 1);
317     }
318 #if NBPFILTER > 0
319     if (sc->sc_if.if_bpf != NULL) {
320 	m->m_pkthdr.len = m->m_len = length;
321 	bpf_mtap(sc->sc_if.if_bpf, m);
322     }
323     /*
324      * If this is single cast but not to us
325      * drop it!
326      */
327     if ((eh.ether_dhost[0] & 1) == 0
328 	   && !LEMAC_ADDREQUAL(eh.ether_dhost, sc->sc_enaddr)) {
329 	m_freem(m);
330 	return;
331     }
332 #endif
333     m->m_pkthdr.len = m->m_len = length;
334     m->m_pkthdr.rcvif = &sc->sc_if;
335     (*sc->sc_if.if_input)(&sc->sc_if, m);
336 }
337 
338 static void
339 lemac_rne_intr(
340     lemac_softc_t *sc)
341 {
342     int rxcount;
343 
344     sc->sc_cntrs.cntr_rne_intrs++;
345     rxcount = LEMAC_INB(sc, LEMAC_REG_RQC);
346     while (rxcount--) {
347 	unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ);
348 	u_int32_t rxlen;
349 
350 	sc->sc_if.if_ipackets++;
351 	if (LEMAC_USE_PIO_MODE(sc)) {
352 	    LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg);
353 	    LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
354 	    LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
355 	    LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen), (void *) &rxlen);
356 	} else {
357 	    LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg);
358 	    rxlen = LEMAC_GET32(sc, 0);
359 	}
360 	if (rxlen & LEMAC_RX_OK) {
361 	    sc->sc_flags |= LEMAC_LINKUP;
362 	    /*
363 	     * Get receive length - subtract out checksum.
364 	     */
365 	    rxlen = ((rxlen >> 8) & 0x7FF) - 4;
366 	    lemac_input(sc, sizeof(rxlen), rxlen);
367 	} else {
368 	    sc->sc_if.if_ierrors++;
369 	}
370 	LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg);  /* Return this page to Free Memory Queue */
371     }  /* end while (recv_count--) */
372 
373     return;
374 }
375 
376 /*
377  *  This is the standard method of reading the DEC Address ROMS.
378  *  I don't understand it but it does work.
379  */
380 static int
381 lemac_read_macaddr(
382     unsigned char *hwaddr,
383     const bus_space_tag_t iot,
384     const bus_space_handle_t ioh,
385     const bus_addr_t ioreg,
386     int skippat)
387 {
388     int cksum, rom_cksum;
389     unsigned char addrbuf[6];
390 
391     if (!skippat) {
392 	int idx, idx2, found, octet;
393 	static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
394 	idx2 = found = 0;
395 
396 	for (idx = 0; idx < 32; idx++) {
397 	    octet = bus_space_read_1(iot, ioh, ioreg);
398 
399 	    if (octet == testpat[idx2]) {
400 		if (++idx2 == sizeof(testpat)) {
401 		    ++found;
402 		    break;
403 		}
404 	    } else {
405 		idx2 = 0;
406 	    }
407 	}
408 
409 	if (!found)
410 	    return -1;
411     }
412 
413     if (hwaddr == NULL)
414 	hwaddr = addrbuf;
415 
416     cksum = 0;
417     hwaddr[0] = bus_space_read_1(iot, ioh, ioreg);
418     hwaddr[1] = bus_space_read_1(iot, ioh, ioreg);
419 
420     /* hardware address can't be multicast */
421     if (hwaddr[0] & 1)
422 	return -1;
423 
424     cksum = *(u_short *) &hwaddr[0];
425 
426     hwaddr[2] = bus_space_read_1(iot, ioh, ioreg);
427     hwaddr[3] = bus_space_read_1(iot, ioh, ioreg);
428     cksum *= 2;
429     if (cksum > 65535) cksum -= 65535;
430     cksum += *(u_short *) &hwaddr[2];
431     if (cksum > 65535) cksum -= 65535;
432 
433     hwaddr[4] = bus_space_read_1(iot, ioh, ioreg);
434     hwaddr[5] = bus_space_read_1(iot, ioh, ioreg);
435     cksum *= 2;
436     if (cksum > 65535) cksum -= 65535;
437     cksum += *(u_short *) &hwaddr[4];
438     if (cksum >= 65535) cksum -= 65535;
439 
440     /* 00-00-00 is an illegal OUI */
441     if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0)
442 	return -1;
443 
444     rom_cksum = bus_space_read_1(iot, ioh, ioreg);
445     rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8;
446 
447     if (cksum != rom_cksum)
448 	return -1;
449     return 0;
450 }
451 
452 static void
453 lemac_multicast_op(
454     u_int16_t *mctbl,
455     const u_char *mca,
456     int enable)
457 {
458     u_int idx, bit, crc;
459 
460     crc = ether_crc32_le(mca, ETHER_ADDR_LEN);
461 
462     /*
463      * The following two lines convert the N bit index into a longword index
464      * and a longword mask.
465      */
466 #if LEMAC_MCTBL_BITS < 0
467     crc >>= (32 + LEMAC_MCTBL_BITS);
468     crc &= (1 << -LEMAC_MCTBL_BITS) - 1;
469 #else
470     crc &= (1 << LEMAC_MCTBL_BITS) - 1;
471 #endif
472     bit = 1 << (crc & 0x0F);
473     idx = crc >> 4;
474 
475     /*
476      * Set or clear hash filter bit in our table.
477      */
478     if (enable) {
479 	mctbl[idx] |= bit;		/* Set Bit */
480     } else {
481 	mctbl[idx] &= ~bit;		/* Clear Bit */
482     }
483 }
484 
485 static void
486 lemac_multicast_filter(
487     lemac_softc_t *sc)
488 {
489     struct ether_multistep step;
490     struct ether_multi *enm;
491 
492     memset(sc->sc_mctbl, 0, LEMAC_MCTBL_BITS / 8);
493 
494     lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, TRUE);
495 
496     ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
497     while (enm != NULL) {
498 	if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
499 	    sc->sc_flags |= LEMAC_ALLMULTI;
500 	    sc->sc_if.if_flags |= IFF_ALLMULTI;
501 	    return;
502 	}
503 	lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
504 	ETHER_NEXT_MULTI(step, enm);
505     }
506     sc->sc_flags &= ~LEMAC_ALLMULTI;
507     sc->sc_if.if_flags &= ~IFF_ALLMULTI;
508 }
509 
510 /*
511  * Do a hard reset of the board;
512  */
513 static void
514 lemac_reset(
515     lemac_softc_t * const sc)
516 {
517     unsigned data;
518 
519     /*
520      * Initialize board..
521      */
522     sc->sc_flags &= ~LEMAC_LINKUP;
523     sc->sc_if.if_flags &= ~IFF_OACTIVE;
524     LEMAC_INTR_DISABLE(sc);
525 
526     LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
527     DELAY(LEMAC_EEP_DELAY);
528 
529     /*
530      * Read EEPROM information.  NOTE - the placement of this function
531      * is important because functions hereafter may rely on information
532      * read from the EEPROM.
533      */
534     if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
535 	printf("%s: reset: EEPROM checksum failed (0x%x)\n",
536 	       sc->sc_if.if_xname, data);
537 	return;
538     }
539 
540     /*
541      * Update the control register to reflect the media choice
542      */
543     data = LEMAC_INB(sc, LEMAC_REG_CTL);
544     if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
545 	data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
546 	data |= sc->sc_ctlmode;
547 	LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
548     }
549 
550     /*
551      *  Force to 2K mode if not already configured.
552      */
553 
554     data = LEMAC_INB(sc, LEMAC_REG_MBR);
555     if (LEMAC_IS_2K_MODE(data)) {
556 	sc->sc_flags |= LEMAC_2K_MODE;
557     } else if (LEMAC_IS_64K_MODE(data)) {
558 	data = (((data * 2) & 0xF) << 4);
559 	sc->sc_flags |= LEMAC_WAS_64K_MODE;
560 	LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
561     } else if (LEMAC_IS_32K_MODE(data)) {
562 	data = ((data & 0xF) << 4);
563 	sc->sc_flags |= LEMAC_WAS_32K_MODE;
564 	LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
565     } else {
566 	sc->sc_flags |= LEMAC_PIO_MODE;
567 	/* PIO mode */
568     }
569 
570     /*
571      *  Initialize Free Memory Queue, Init mcast table with broadcast.
572      */
573 
574     lemac_init_adapmem(sc);
575     sc->sc_flags |= LEMAC_ALIVE;
576 }
577 
578 static void
579 lemac_init(
580     lemac_softc_t * const sc)
581 {
582     if ((sc->sc_flags & LEMAC_ALIVE) == 0)
583 	return;
584 
585     /*
586      * If the interface has the up flag
587      */
588     if (sc->sc_if.if_flags & IFF_UP) {
589 	int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS);
590 	LEMAC_OUTB(sc, LEMAC_REG_CS, saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
591 	LEMAC_OUTB(sc, LEMAC_REG_PA0, sc->sc_enaddr[0]);
592 	LEMAC_OUTB(sc, LEMAC_REG_PA1, sc->sc_enaddr[1]);
593 	LEMAC_OUTB(sc, LEMAC_REG_PA2, sc->sc_enaddr[2]);
594 	LEMAC_OUTB(sc, LEMAC_REG_PA3, sc->sc_enaddr[3]);
595 	LEMAC_OUTB(sc, LEMAC_REG_PA4, sc->sc_enaddr[4]);
596 	LEMAC_OUTB(sc, LEMAC_REG_PA5, sc->sc_enaddr[5]);
597 
598 	LEMAC_OUTB(sc, LEMAC_REG_IC, LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
599 
600 	if (sc->sc_if.if_flags & IFF_PROMISC) {
601 	    LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE | LEMAC_CS_PME);
602 	} else {
603 	    LEMAC_INTR_DISABLE(sc);
604 	    lemac_multicast_filter(sc);
605 	    if (sc->sc_flags & LEMAC_ALLMULTI)
606 		memcpy(sc->sc_mctbl, lemac_allmulti_mctbl,
607 		       sizeof(sc->sc_mctbl));
608 	    if (LEMAC_USE_PIO_MODE(sc)) {
609 		LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
610 		LEMAC_OUTB(sc, LEMAC_REG_PI1, LEMAC_MCTBL_OFF & 0xFF);
611 		LEMAC_OUTB(sc, LEMAC_REG_PI2, LEMAC_MCTBL_OFF >> 8);
612 		LEMAC_OUTSB(sc, LEMAC_REG_DAT, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
613 	    } else {
614 		LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
615 		LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
616 	    }
617 
618 	    LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
619 	}
620 
621 	LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
622 
623 	LEMAC_INTR_ENABLE(sc);
624 	sc->sc_if.if_flags |= IFF_RUNNING;
625 	lemac_ifstart(&sc->sc_if);
626     } else {
627 	LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
628 
629 	LEMAC_INTR_DISABLE(sc);
630 	sc->sc_if.if_flags &= ~IFF_RUNNING;
631     }
632 }
633 
634 static void
635 lemac_ifstart(
636     struct ifnet *ifp)
637 {
638     lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
639 
640     if ((ifp->if_flags & IFF_RUNNING) == 0)
641 	return;
642 
643     LEMAC_INTR_DISABLE(sc);
644 
645     for (;;) {
646 	struct mbuf *m;
647 	struct mbuf *m0;
648 	int tx_pg;
649 
650 	IFQ_POLL(&ifp->if_snd, m);
651 	if (m == NULL)
652 	    break;
653 
654 	if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC)) >= lemac_txmax) {
655 	    sc->sc_cntrs.cntr_txfull++;
656 	    ifp->if_flags |= IFF_OACTIVE;
657 	    break;
658 	}
659 
660 	/*
661 	 * get free memory page
662 	 */
663 	tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
664 	/*
665 	 * Check for good transmit page.
666 	 */
667 	if (tx_pg == 0 || tx_pg > sc->sc_lastpage) {
668 	    sc->sc_cntrs.cntr_txnospc++;
669 	    ifp->if_flags |= IFF_OACTIVE;
670 	    break;
671 	}
672 
673 	IFQ_DEQUEUE(&ifp->if_snd, m);
674 
675 	/*
676 	 * The first four bytes of each transmit buffer are for
677 	 * control information.  The first byte is the control
678 	 * byte, then the length (why not word aligned?), then
679 	 * the offset to the buffer.
680 	 */
681 
682 	if (LEMAC_USE_PIO_MODE(sc)) {
683 	    LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg);	/* Shift 2K window. */
684 	    LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
685 	    LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
686 	    LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl);
687 	    LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 0) & 0xFF);
688 	    LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 8) & 0xFF);
689 	    LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ);
690 	    for (m0 = m; m0 != NULL; m0 = m0->m_next)
691 		LEMAC_OUTSB(sc, LEMAC_REG_DAT, m0->m_len, m0->m_data);
692 	} else {
693 	    bus_size_t txoff = /* (mtod(m, u_int32_t) & (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ;
694 	    LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg);	/* Shift 2K window. */
695 	    LEMAC_PUT8(sc, 0, sc->sc_txctl);
696 	    LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF);
697 	    LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF);
698 	    LEMAC_PUT8(sc, 3, txoff);
699 
700 	    /*
701 	     * Copy the packet to the board
702 	     */
703 	    for (m0 = m; m0 != NULL; m0 = m0->m_next) {
704 #if 0
705 		LEMAC_PUTBUF8(sc, txoff, m0->m_len, m0->m_data);
706 		txoff += m0->m_len;
707 #else
708 		const u_int8_t *cp = m0->m_data;
709 		int len = m0->m_len;
710 #if 0
711 		if ((txoff & 3) == (((long)cp) & 3) && len >= 4) {
712 		    if (txoff & 3) {
713 			int alen = (~txoff & 3);
714 			LEMAC_PUTBUF8(sc, txoff, alen, cp);
715 			cp += alen; txoff += alen; len -= alen;
716 		    }
717 		    if (len >= 4) {
718 			LEMAC_PUTBUF32(sc, txoff, len / 4, cp);
719 			cp += len & ~3; txoff += len & ~3; len &= 3;
720 		    }
721 		}
722 #endif
723 		if ((txoff & 1) == (((long)cp) & 1) && len >= 2) {
724 		    if (txoff & 1) {
725 			int alen = (~txoff & 1);
726 			LEMAC_PUTBUF8(sc, txoff, alen, cp);
727 			cp += alen; txoff += alen; len -= alen;
728 		    }
729 		    if (len >= 2) {
730 			LEMAC_PUTBUF16(sc, txoff, len / 2, (void *) cp);
731 			cp += len & ~1; txoff += len & ~1; len &= 1;
732 		    }
733 		}
734 		if (len > 0) {
735 		    LEMAC_PUTBUF8(sc, txoff, len, cp);
736 		    txoff += len;
737 		}
738 #endif
739 	    }
740 	}
741 
742 	LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg);	/* tell chip to transmit this packet */
743 #if NBPFILTER > 0
744 	if (sc->sc_if.if_bpf != NULL)
745 	    bpf_mtap(sc->sc_if.if_bpf, m);
746 #endif
747 	m_freem(m);			/* free the mbuf */
748     }
749     LEMAC_INTR_ENABLE(sc);
750 }
751 
752 static int
753 lemac_ifioctl(
754     struct ifnet *ifp,
755     u_long cmd,
756     caddr_t data)
757 {
758     lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
759     int s;
760     int error = 0;
761 
762     s = splnet();
763 
764     switch (cmd) {
765 	case SIOCSIFADDR: {
766 	    struct ifaddr *ifa = (struct ifaddr *)data;
767 
768 	    ifp->if_flags |= IFF_UP;
769 	    lemac_init(sc);
770 	    switch (ifa->ifa_addr->sa_family) {
771 #ifdef INET
772 		case AF_INET: {
773 		    arp_ifinit(&sc->sc_if, ifa);
774 		    break;
775 		}
776 #endif /* INET */
777 
778 #ifdef NS
779 		/* This magic copied from if_is.c; I don't use XNS,
780 		 * so I have no way of telling if this actually
781 		 * works or not.
782 		 */
783 		case AF_NS: {
784 		    struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
785 		    if (ns_nullhost(*ina)) {
786 			ina->x_host = *(union ns_host *)sc->sc_enaddr;
787 		    } else {
788 			memcpy(sc->sc_enaddr, (caddr_t)ina->x_host.c_host,
789 			      ifp->if_addrlen);
790 		    }
791 		    break;
792 		}
793 #endif /* NS */
794 
795 		default: {
796 		    break;
797 		}
798 	    }
799 	    break;
800 	}
801 
802 	case SIOCSIFFLAGS: {
803 	    lemac_init(sc);
804 	    break;
805 	}
806 
807 	case SIOCADDMULTI:
808 	case SIOCDELMULTI: {
809 	    /*
810 	     * Update multicast listeners
811 	     */
812 	    if (cmd == SIOCADDMULTI)
813 		error = ether_addmulti((struct ifreq *)data, &sc->sc_ec);
814 	    else
815 		error = ether_delmulti((struct ifreq *)data, &sc->sc_ec);
816 
817 	    if (error == ENETRESET) {
818 		/* reset multicast filtering */
819 		if (ifp->if_flags & IFF_RUNNING)
820 		    lemac_init(sc);
821 		error = 0;
822 	    }
823 	    break;
824 	}
825 
826 	case SIOCSIFMEDIA:
827 	case SIOCGIFMEDIA: {
828 	    error = ifmedia_ioctl(ifp, (struct ifreq *)data,
829 				  &sc->sc_ifmedia, cmd);
830 	    break;
831 	}
832 
833 	default: {
834 	    error = EINVAL;
835 	    break;
836 	}
837     }
838 
839     splx(s);
840     return error;
841 }
842 
843 static int
844 lemac_ifmedia_change(
845     struct ifnet * const ifp)
846 {
847     lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
848     unsigned new_ctl;
849 
850     switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
851 	case IFM_10_T: new_ctl = LEMAC_CTL_APD; break;
852 	case IFM_10_2:
853 	case IFM_10_5: new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL; break;
854 	case IFM_AUTO: new_ctl = 0; break;
855 	default:       return EINVAL;
856     }
857     if (sc->sc_ctlmode != new_ctl) {
858 	sc->sc_ctlmode = new_ctl;
859 	lemac_reset(sc);
860 	if (sc->sc_if.if_flags & IFF_UP)
861 	    lemac_init(sc);
862     }
863     return 0;
864 }
865 
866 /*
867  * Media status callback
868  */
869 static void
870 lemac_ifmedia_status(
871     struct ifnet * const ifp,
872     struct ifmediareq *req)
873 {
874     lemac_softc_t *sc = LEMAC_IFP_TO_SOFTC(ifp);
875     unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF);
876 
877     req->ifm_status = IFM_AVALID;
878     if (sc->sc_flags & LEMAC_LINKUP)
879 	req->ifm_status |= IFM_ACTIVE;
880 
881     if (sc->sc_ctlmode & LEMAC_CTL_APD) {
882 	if (sc->sc_ctlmode & LEMAC_CTL_PSL) {
883 	    req->ifm_active = IFM_10_5;
884 	} else {
885 	    req->ifm_active = IFM_10_T;
886 	}
887     } else {
888 	/*
889 	 * The link bit of the configuration register reflects the
890 	 * current media choice when auto-port is enabled.
891 	 */
892 	if (data & LEMAC_CNF_NOLINK) {
893 	    req->ifm_active = IFM_10_5;
894 	} else {
895 	    req->ifm_active = IFM_10_T;
896 	}
897     }
898 
899     req->ifm_active |= IFM_ETHER;
900 }
901 
902 int
903 lemac_port_check(
904     const bus_space_tag_t iot,
905     const bus_space_handle_t ioh)
906 {
907     unsigned char hwaddr[6];
908 
909     if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0)
910 	return 1;
911     if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0)
912 	return 1;
913     return 0;
914 }
915 
916 void
917 lemac_info_get(
918     const bus_space_tag_t iot,
919     const bus_space_handle_t ioh,
920     bus_addr_t *maddr_p,
921     bus_size_t *msize_p,
922     int *irq_p)
923 {
924     unsigned data;
925 
926     *irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC) & LEMAC_IC_IRQMSK);
927 
928     data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR);
929     if (LEMAC_IS_2K_MODE(data)) {
930 	*maddr_p = data * (2 * 1024) + (512 * 1024);
931 	*msize_p =  2 * 1024;
932     } else if (LEMAC_IS_64K_MODE(data)) {
933 	*maddr_p = data * 64 * 1024;
934 	*msize_p = 64 * 1024;
935     } else if (LEMAC_IS_32K_MODE(data)) {
936 	*maddr_p = data * 32 * 1024;
937 	*msize_p = 32* 1024;
938     } else {
939 	*maddr_p = 0;
940 	*msize_p = 0;
941     }
942 }
943 
944 /*
945  * What to do upon receipt of an interrupt.
946  */
947 int
948 lemac_intr(
949     void *arg)
950 {
951     lemac_softc_t * const sc = arg;
952     int cs_value;
953 
954     LEMAC_INTR_DISABLE(sc);	/* Mask interrupts */
955 
956     /*
957      * Determine cause of interrupt.  Receive events take
958      * priority over Transmit.
959      */
960 
961     cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
962 
963     /*
964      * Check for Receive Queue not being empty.
965      * Check for Transmit Done Queue not being empty.
966      */
967 
968     if (cs_value & LEMAC_CS_RNE)
969 	lemac_rne_intr(sc);
970     if (cs_value & LEMAC_CS_TNE)
971 	lemac_tne_intr(sc);
972 
973     /*
974      * Check for Transmitter Disabled.
975      * Check for Receiver Disabled.
976      */
977 
978     if (cs_value & LEMAC_CS_TXD)
979 	lemac_txd_intr(sc, cs_value);
980     if (cs_value & LEMAC_CS_RXD)
981 	lemac_rxd_intr(sc, cs_value);
982 
983     /*
984      * Toggle LED and unmask interrupts.
985      */
986 
987     sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS);
988 
989     LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
990     LEMAC_INTR_ENABLE(sc);		/* Unmask interrupts */
991 
992 #if NRND > 0
993     if (cs_value)
994         rnd_add_uint32(&sc->rnd_source, cs_value);
995 #endif
996 
997     return 1;
998 }
999 
1000 void
1001 lemac_shutdown(
1002     void *arg)
1003 {
1004     lemac_reset((lemac_softc_t *) arg);
1005 }
1006 
1007 static const char * const lemac_modes[4] = {
1008     "PIO mode (internal 2KB window)",
1009     "2KB window",
1010     "changed 32KB window to 2KB",
1011     "changed 64KB window to 2KB",
1012 };
1013 
1014 void
1015 lemac_ifattach(
1016     lemac_softc_t *sc)
1017 {
1018     struct ifnet * const ifp = &sc->sc_if;
1019 
1020     strcpy(ifp->if_xname, sc->sc_dv.dv_xname);
1021 
1022     lemac_reset(sc);
1023 
1024     (void) lemac_read_macaddr(sc->sc_enaddr, sc->sc_iot, sc->sc_ioh,
1025 			      LEMAC_REG_APD, 0);
1026 
1027     printf(": %s\n", sc->sc_prodname);
1028 
1029     printf("%s: address %s, %dKB RAM, %s\n",
1030 	   ifp->if_xname,
1031 	   ether_sprintf(sc->sc_enaddr),
1032 	   sc->sc_lastpage * 2 + 2,
1033 	   lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
1034 
1035     ifp->if_softc = (void *) sc;
1036     ifp->if_start = lemac_ifstart;
1037     ifp->if_ioctl = lemac_ifioctl;
1038 
1039     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX
1040 #ifdef IFF_NOTRAILERS
1041 	| IFF_NOTRAILERS
1042 #endif
1043 	| IFF_MULTICAST;
1044 
1045     if (sc->sc_flags & LEMAC_ALIVE) {
1046 	int media;
1047 
1048 	IFQ_SET_READY(&ifp->if_snd);
1049 
1050 	if_attach(ifp);
1051 	ether_ifattach(ifp, sc->sc_enaddr);
1052 
1053 #if NRND > 0
1054 	rnd_attach_source(&sc->rnd_source, sc->sc_dv.dv_xname,
1055 			  RND_TYPE_NET, 0);
1056 #endif
1057 
1058 	ifmedia_init(&sc->sc_ifmedia, 0,
1059 		     lemac_ifmedia_change,
1060 		     lemac_ifmedia_status);
1061 	if (sc->sc_prodname[4] == '5')	/* DE205 is UTP/AUI */
1062 	    ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
1063 	if (sc->sc_prodname[4] != '3')	/* DE204 & 205 have UTP */
1064 	    ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, 0);
1065 	if (sc->sc_prodname[4] != '4')	/* DE203 & 205 have BNC */
1066 	    ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, 0);
1067 	switch (sc->sc_prodname[4]) {
1068 	    case '3': media = IFM_10_5; break;
1069 	    case '4': media = IFM_10_T; break;
1070 	    default:  media = IFM_AUTO; break;
1071 	}
1072 	ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
1073     } else {
1074 	printf("%s: disabled due to error\n", ifp->if_xname);
1075     }
1076 }
1077