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