1 /* $OpenBSD: lemac.c,v 1.5 2003/10/30 02:30:48 itojun 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_types.h>
49 #include <net/if_dl.h>
50 #include <net/route.h>
51 #include <net/if_media.h>
52 
53 #ifdef INET
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/in_var.h>
57 #include <netinet/ip.h>
58 #include <netinet/if_ether.h>
59 #endif
60 
61 #ifdef NS
62 #include <netns/ns.h>
63 #include <netns/ns_if.h>
64 #endif
65 
66 #include <machine/bus.h>
67 
68 #include <dev/rndvar.h>
69 #include <dev/ic/lemacreg.h>
70 #include <dev/ic/lemacvar.h>
71 
72 #if 0
73 #include <uvm/uvm_extern.h>
74 #endif
75 
76 #include "bpfilter.h"
77 #if NBPFILTER > 0
78 #include <net/bpf.h>
79 #endif
80 
81 int	lemac_ifioctl(struct ifnet *, u_long, caddr_t);
82 int	lemac_ifmedia_change(struct ifnet *const);
83 void	lemac_ifmedia_status(struct ifnet *const, struct ifmediareq *);
84 void	lemac_ifstart(struct ifnet *);
85 void	lemac_init(struct lemac_softc *);
86 void	lemac_init_adapmem(struct lemac_softc *);
87 void	lemac_input(struct lemac_softc *, bus_addr_t, size_t);
88 void	lemac_multicast_filter(struct lemac_softc *);
89 void	lemac_multicast_op(u_int16_t *, const u_char *, int);
90 int	lemac_read_eeprom(struct lemac_softc *);
91 int	lemac_read_macaddr(unsigned char *, const bus_space_tag_t,
92     const bus_space_handle_t, const bus_addr_t, int);
93 void	lemac_reset(struct lemac_softc *);
94 void	lemac_rne_intr(struct lemac_softc *);
95 void	lemac_rxd_intr(struct lemac_softc *, unsigned);
96 void	lemac_tne_intr(struct lemac_softc *);
97 void	lemac_txd_intr(struct lemac_softc *, unsigned);
98 
99 struct cfdriver lc_cd = {
100 	NULL, "lc", DV_IFNET
101 };
102 
103 static const u_int16_t lemac_allmulti_mctbl[LEMAC_MCTBL_SIZE/sizeof(u_int16_t)] = {
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 	0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
111 	0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
112 };
113 
114 /*
115  * Some tuning/monitoring variables.
116  */
117 unsigned lemac_txmax = 16;
118 
119 void
lemac_rxd_intr(struct lemac_softc * sc,unsigned cs_value)120 lemac_rxd_intr(struct lemac_softc *sc, 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",
152 	    sc->sc_if.if_xname);
153 
154 	lemac_reset(sc);
155 	if (sc->sc_if.if_flags & IFF_UP) {
156 		lemac_init(sc);
157 		return;
158 	}
159 
160 	/*
161 	 *  Error during initialization.  Mark card as disabled.
162 	 */
163 	printf("%s: recovery failed -- board disabled\n", sc->sc_if.if_xname);
164 }
165 
166 void
lemac_tne_intr(struct lemac_softc * sc)167 lemac_tne_intr(struct lemac_softc *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 void
lemac_txd_intr(struct lemac_softc * sc,unsigned cs_value)191 lemac_txd_intr(struct lemac_softc *sc, unsigned cs_value)
192 {
193 	/*
194 	 * Read transmit status, remove transmit buffer from
195 	 * transmit queue and place on free memory queue,
196 	 * then reset transmitter.
197 	 * Increment appropriate counters.
198 	 */
199 
200 	sc->sc_cntrs.cntr_txd_intrs++;
201 	if (sc->sc_txctl & LEMAC_TX_STP) {
202 		sc->sc_if.if_oerrors++;
203 		/* return page to free queue */
204 		LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ));
205 	}
206 
207 	/* Turn back on transmitter if disabled */
208 	LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value & ~LEMAC_CS_TXD);
209 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
210 }
211 
212 int
lemac_read_eeprom(struct lemac_softc * sc)213 lemac_read_eeprom(struct lemac_softc *sc)
214 {
215 	int	word_off, cksum;
216 
217 	u_char *ep;
218 
219 	cksum = 0;
220 	ep = sc->sc_eeprom;
221 	for (word_off = 0; word_off < LEMAC_EEP_SIZE / 2; word_off++) {
222 		LEMAC_OUTB(sc, LEMAC_REG_PI1, word_off);
223 		LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEREAD);
224 
225 		DELAY(LEMAC_EEP_DELAY);
226 
227 		*ep = LEMAC_INB(sc, LEMAC_REG_EE1);
228 		cksum += *ep++;
229 		*ep = LEMAC_INB(sc, LEMAC_REG_EE2);
230 		cksum += *ep++;
231 	}
232 
233 	/*
234 	 *  Set up Transmit Control Byte for use later during transmit.
235 	 */
236 
237 	sc->sc_txctl |= LEMAC_TX_FLAGS;
238 
239 	if ((sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_SQE) == 0)
240 		sc->sc_txctl &= ~LEMAC_TX_SQE;
241 
242 	if (sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_LAB)
243 		sc->sc_txctl |= LEMAC_TX_LAB;
244 
245 	bcopy(&sc->sc_eeprom[LEMAC_EEP_PRDNM], sc->sc_prodname,
246 	    LEMAC_EEP_PRDNMSZ);
247 	sc->sc_prodname[LEMAC_EEP_PRDNMSZ] = '\0';
248 
249 	return (cksum % 256);
250 }
251 
252 void
lemac_init_adapmem(struct lemac_softc * sc)253 lemac_init_adapmem(struct lemac_softc *sc)
254 {
255 	int pg, conf;
256 
257 	conf = LEMAC_INB(sc, LEMAC_REG_CNF);
258 
259 	if ((sc->sc_eeprom[LEMAC_EEP_SETUP] & LEMAC_EEP_ST_DRAM) == 0) {
260 		sc->sc_lastpage = 63;
261 		conf &= ~LEMAC_CNF_DRAM;
262 	} else {
263 		sc->sc_lastpage = 127;
264 		conf |= LEMAC_CNF_DRAM;
265 	}
266 
267 	LEMAC_OUTB(sc, LEMAC_REG_CNF, conf);
268 
269 	for (pg = 1; pg <= sc->sc_lastpage; pg++)
270 		LEMAC_OUTB(sc, LEMAC_REG_FMQ, pg);
271 }
272 
273 void
lemac_input(struct lemac_softc * sc,bus_addr_t offset,size_t length)274 lemac_input(struct lemac_softc *sc, bus_addr_t offset, size_t length)
275 {
276 	struct ether_header eh;
277 	struct mbuf *m;
278 
279 	if (length - sizeof(eh) > ETHERMTU ||
280 	    length - sizeof(eh) < ETHERMIN) {
281 		sc->sc_if.if_ierrors++;
282 		return;
283 	}
284 	if (LEMAC_USE_PIO_MODE(sc)) {
285 		LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(eh), (void *)&eh);
286 	} else {
287 		LEMAC_GETBUF16(sc, offset, sizeof(eh) / 2, (void *)&eh);
288 	}
289 
290 	MGETHDR(m, M_DONTWAIT, MT_DATA);
291 	if (m == NULL) {
292 		sc->sc_if.if_ierrors++;
293 		return;
294 	}
295 	if (length + 2 > MHLEN) {
296 		MCLGET(m, M_DONTWAIT);
297 		if ((m->m_flags & M_EXT) == 0) {
298 			m_free(m);
299 			sc->sc_if.if_ierrors++;
300 			return;
301 		}
302 	}
303 	m->m_data += 2;
304 	bcopy((caddr_t)&eh, m->m_data, sizeof(eh));
305 	if (LEMAC_USE_PIO_MODE(sc)) {
306 		LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh),
307 		    mtod(m, caddr_t) + sizeof(eh));
308 	} else {
309 		LEMAC_GETBUF16(sc, offset + sizeof(eh),
310 		    (length - sizeof(eh)) / 2,
311 		    (void *)(mtod(m, caddr_t) + sizeof(eh)));
312 		if (length & 1)
313 			m->m_data[length - 1] = LEMAC_GET8(sc,
314 			    offset + length - 1);
315 	}
316 #if NBPFILTER > 0
317 	if (sc->sc_if.if_bpf != NULL) {
318 		m->m_pkthdr.len = m->m_len = length;
319 		bpf_mtap(sc->sc_if.if_bpf, m);
320 	}
321 
322 	/*
323 	 * If this is single cast but not to us
324 	 * drop it!
325 	 */
326 	if ((eh.ether_dhost[0] & 1) == 0 &&
327 	    !LEMAC_ADDREQUAL(eh.ether_dhost, sc->sc_arpcom.ac_enaddr)) {
328 		m_freem(m);
329 		return;
330 	}
331 #endif
332 	m->m_pkthdr.len = m->m_len = length;
333 	m->m_pkthdr.rcvif = &sc->sc_if;
334 	ether_input_mbuf(&sc->sc_if, m);
335 }
336 
337 void
lemac_rne_intr(struct lemac_softc * sc)338 lemac_rne_intr(struct lemac_softc *sc)
339 {
340 	int rxcount;
341 
342 	sc->sc_cntrs.cntr_rne_intrs++;
343 	rxcount = LEMAC_INB(sc, LEMAC_REG_RQC);
344 	while (rxcount--) {
345 		unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ);
346 		u_int32_t rxlen;
347 
348 		sc->sc_if.if_ipackets++;
349 		if (LEMAC_USE_PIO_MODE(sc)) {
350 			LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg);
351 			LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
352 			LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
353 			LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen),
354 			    (void *)&rxlen);
355 		} else {
356 			LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg);
357 			rxlen = LEMAC_GET32(sc, 0);
358 		}
359 		if (rxlen & LEMAC_RX_OK) {
360 			sc->sc_flags |= LEMAC_LINKUP;
361 			/*
362 			 * Get receive length - subtract out checksum.
363 			 */
364 			rxlen = ((rxlen >> 8) & 0x7FF) - 4;
365 			lemac_input(sc, sizeof(rxlen), rxlen);
366 		} else {
367 			sc->sc_if.if_ierrors++;
368 		}
369 		/* Return this page to Free Memory Queue */
370 		LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg);
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 int
lemac_read_macaddr(unsigned char * hwaddr,const bus_space_tag_t iot,const bus_space_handle_t ioh,const bus_addr_t ioreg,int skippat)381 lemac_read_macaddr(unsigned char *hwaddr, const bus_space_tag_t iot,
382     const bus_space_handle_t ioh, const bus_addr_t ioreg, int skippat)
383 {
384 	int cksum, rom_cksum;
385 	unsigned char addrbuf[6];
386 
387 	if (!skippat) {
388 		int idx, idx2, found, octet;
389 		static u_char testpat[] = {
390 			0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA
391 		};
392 		idx2 = found = 0;
393 
394 		for (idx = 0; idx < 32; idx++) {
395 			octet = bus_space_read_1(iot, ioh, ioreg);
396 
397 			if (octet == testpat[idx2]) {
398 				if (++idx2 == sizeof(testpat)) {
399 					++found;
400 					break;
401 				}
402 			} else {
403 				idx2 = 0;
404 			}
405 		}
406 
407 		if (!found)
408 			return (-1);
409 	}
410 
411 	if (hwaddr == NULL)
412 		hwaddr = addrbuf;
413 
414 	cksum = 0;
415 	hwaddr[0] = bus_space_read_1(iot, ioh, ioreg);
416 	hwaddr[1] = bus_space_read_1(iot, ioh, ioreg);
417 
418 	/* hardware address can't be multicast */
419 	if (hwaddr[0] & 1)
420 		return (-1);
421 
422 	cksum = *(u_short *)&hwaddr[0];
423 
424 	hwaddr[2] = bus_space_read_1(iot, ioh, ioreg);
425 	hwaddr[3] = bus_space_read_1(iot, ioh, ioreg);
426 	cksum *= 2;
427 	if (cksum > 65535)
428 		cksum -= 65535;
429 	cksum += *(u_short *)&hwaddr[2];
430 	if (cksum > 65535)
431 		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)
437 		cksum -= 65535;
438 	cksum += *(u_short *)&hwaddr[4];
439 	if (cksum >= 65535)
440 		cksum -= 65535;
441 
442 	/* 00-00-00 is an illegal OUI */
443 	if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0)
444 		return (-1);
445 
446 	rom_cksum = bus_space_read_1(iot, ioh, ioreg);
447 	rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8;
448 
449 	if (cksum != rom_cksum)
450 		return (-1);
451 	return (0);
452 }
453 
454 void
lemac_multicast_op(u_int16_t * mctbl,const u_char * mca,int enable)455 lemac_multicast_op(u_int16_t *mctbl, const u_char *mca, int enable)
456 {
457 	u_int idx, bit, crc;
458 
459 	crc = ether_crc32_le(mca, ETHER_ADDR_LEN);
460 
461 	/*
462 	 * The following two lines convert the N bit index into a
463 	 * longword index and a longword mask.
464 	 */
465 #if LEMAC_MCTBL_BITS < 0
466 	crc >>= (32 + LEMAC_MCTBL_BITS);
467 	crc &= (1 << -LEMAC_MCTBL_BITS) - 1;
468 #else
469 	crc &= (1 << LEMAC_MCTBL_BITS) - 1;
470 #endif
471 	bit = 1 << (crc & 0x0F);
472 	idx = crc >> 4;
473 
474 	/*
475 	 * Set or clear hash filter bit in our table.
476 	 */
477 	if (enable) {
478 		mctbl[idx] |= bit;		/* Set Bit */
479 	} else {
480 		mctbl[idx] &= ~bit;		/* Clear Bit */
481 	}
482 }
483 
484 void
lemac_multicast_filter(struct lemac_softc * sc)485 lemac_multicast_filter(struct lemac_softc *sc)
486 {
487 #if 0
488 	struct ether_multistep step;
489 	struct ether_multi *enm;
490 #endif
491 
492 	bzero(sc->sc_mctbl, LEMAC_MCTBL_BITS / 8);
493 
494 	lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, 1);
495 
496 #if 0
497 	ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
498 	while (enm != NULL) {
499 		if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
500 			sc->sc_flags |= LEMAC_ALLMULTI;
501 			sc->sc_if.if_flags |= IFF_ALLMULTI;
502 			return;
503 		}
504 		lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
505 		ETHER_NEXT_MULTI(step, enm);
506 	}
507 #endif
508 	sc->sc_flags &= ~LEMAC_ALLMULTI;
509 	sc->sc_if.if_flags &= ~IFF_ALLMULTI;
510 }
511 
512 /*
513  * Do a hard reset of the board;
514  */
515 void
lemac_reset(struct lemac_softc * const sc)516 lemac_reset(struct lemac_softc *const sc)
517 {
518 	unsigned data;
519 
520 	/*
521 	 * Initialize board..
522 	 */
523 	sc->sc_flags &= ~LEMAC_LINKUP;
524 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
525 	LEMAC_INTR_DISABLE(sc);
526 
527 	LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
528 	DELAY(LEMAC_EEP_DELAY);
529 
530 	/*
531 	 * Read EEPROM information.  NOTE - the placement of this function
532 	 * is important because functions hereafter may rely on information
533 	 * read from the EEPROM.
534 	 */
535 	if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
536 		printf("%s: reset: EEPROM checksum failed (0x%x)\n",
537 		    sc->sc_if.if_xname, data);
538 		return;
539 	}
540 
541 	/*
542 	 * Update the control register to reflect the media choice
543 	 */
544 	data = LEMAC_INB(sc, LEMAC_REG_CTL);
545 	if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
546 		data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
547 		data |= sc->sc_ctlmode;
548 		LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
549 	}
550 
551 	/*
552 	 *  Force to 2K mode if not already configured.
553 	 */
554 
555 	data = LEMAC_INB(sc, LEMAC_REG_MBR);
556 	if (LEMAC_IS_2K_MODE(data)) {
557 		sc->sc_flags |= LEMAC_2K_MODE;
558 	} else if (LEMAC_IS_64K_MODE(data)) {
559 		data = (((data * 2) & 0xF) << 4);
560 		sc->sc_flags |= LEMAC_WAS_64K_MODE;
561 		LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
562 	} else if (LEMAC_IS_32K_MODE(data)) {
563 		data = ((data & 0xF) << 4);
564 		sc->sc_flags |= LEMAC_WAS_32K_MODE;
565 		LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
566 	} else {
567 		sc->sc_flags |= LEMAC_PIO_MODE;
568 		/* PIO mode */
569 	}
570 
571 	/*
572 	 *  Initialize Free Memory Queue, Init mcast table with broadcast.
573 	 */
574 
575 	lemac_init_adapmem(sc);
576 	sc->sc_flags |= LEMAC_ALIVE;
577 }
578 
579 void
lemac_init(struct lemac_softc * const sc)580 lemac_init(struct lemac_softc *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,
591 		    saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
592 		LEMAC_OUTB(sc, LEMAC_REG_PA0, sc->sc_arpcom.ac_enaddr[0]);
593 		LEMAC_OUTB(sc, LEMAC_REG_PA1, sc->sc_arpcom.ac_enaddr[1]);
594 		LEMAC_OUTB(sc, LEMAC_REG_PA2, sc->sc_arpcom.ac_enaddr[2]);
595 		LEMAC_OUTB(sc, LEMAC_REG_PA3, sc->sc_arpcom.ac_enaddr[3]);
596 		LEMAC_OUTB(sc, LEMAC_REG_PA4, sc->sc_arpcom.ac_enaddr[4]);
597 		LEMAC_OUTB(sc, LEMAC_REG_PA5, sc->sc_arpcom.ac_enaddr[5]);
598 
599 		LEMAC_OUTB(sc, LEMAC_REG_IC,
600 		    LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
601 
602 		if (sc->sc_if.if_flags & IFF_PROMISC) {
603 			LEMAC_OUTB(sc, LEMAC_REG_CS,
604 			    LEMAC_CS_MCE | LEMAC_CS_PME);
605 		} else {
606 			LEMAC_INTR_DISABLE(sc);
607 			lemac_multicast_filter(sc);
608 			if (sc->sc_flags & LEMAC_ALLMULTI)
609 				bcopy(lemac_allmulti_mctbl, sc->sc_mctbl,
610 				    sizeof(sc->sc_mctbl));
611 			if (LEMAC_USE_PIO_MODE(sc)) {
612 				LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
613 				LEMAC_OUTB(sc, LEMAC_REG_PI1,
614 				    LEMAC_MCTBL_OFF & 0xFF);
615 				LEMAC_OUTB(sc, LEMAC_REG_PI2,
616 				    LEMAC_MCTBL_OFF >> 8);
617 				LEMAC_OUTSB(sc, LEMAC_REG_DAT,
618 				    sizeof(sc->sc_mctbl),
619 				    (void *)sc->sc_mctbl);
620 			} else {
621 				LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
622 				LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF,
623 				    sizeof(sc->sc_mctbl),
624 				    (void *)sc->sc_mctbl);
625 			}
626 
627 			LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
628 		}
629 
630 		LEMAC_OUTB(sc, LEMAC_REG_CTL,
631 		    LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
632 
633 		LEMAC_INTR_ENABLE(sc);
634 		sc->sc_if.if_flags |= IFF_RUNNING;
635 		lemac_ifstart(&sc->sc_if);
636 	} else {
637 		LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
638 
639 		LEMAC_INTR_DISABLE(sc);
640 		sc->sc_if.if_flags &= ~IFF_RUNNING;
641 	}
642 }
643 
644 void
lemac_ifstart(struct ifnet * ifp)645 lemac_ifstart(struct ifnet *ifp)
646 {
647 	struct lemac_softc *const sc = LEMAC_IFP_TO_SOFTC(ifp);
648 
649 	if ((ifp->if_flags & IFF_RUNNING) == 0)
650 		return;
651 
652 	LEMAC_INTR_DISABLE(sc);
653 
654 	for (;;) {
655 		struct mbuf *m;
656 		struct mbuf *m0;
657 		int tx_pg;
658 
659 		IFQ_POLL(&ifp->if_snd, m);
660 		if (m == NULL)
661 			break;
662 
663 		if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC)) >=
664 		    lemac_txmax) {
665 			sc->sc_cntrs.cntr_txfull++;
666 			ifp->if_flags |= IFF_OACTIVE;
667 			break;
668 		}
669 
670 		/*
671 		 * get free memory page
672 		 */
673 		tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
674 
675 		/*
676 		 * Check for good transmit page.
677 		 */
678 		if (tx_pg == 0 || tx_pg > sc->sc_lastpage) {
679 			sc->sc_cntrs.cntr_txnospc++;
680 			ifp->if_flags |= IFF_OACTIVE;
681 			break;
682 		}
683 
684 		IFQ_DEQUEUE(&ifp->if_snd, m);
685 
686 		/*
687 		 * The first four bytes of each transmit buffer are for
688 		 * control information.  The first byte is the control
689 		 * byte, then the length (why not word aligned?), then
690 		 * the offset to the buffer.
691 		 */
692 
693 		if (LEMAC_USE_PIO_MODE(sc)) {
694 			/* Shift 2K window. */
695 			LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg);
696 			LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
697 			LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
698 			LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl);
699 			LEMAC_OUTB(sc, LEMAC_REG_DAT,
700 			    (m->m_pkthdr.len >> 0) & 0xFF);
701 			LEMAC_OUTB(sc, LEMAC_REG_DAT,
702 			    (m->m_pkthdr.len >> 8) & 0xFF);
703 			LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ);
704 			for (m0 = m; m0 != NULL; m0 = m0->m_next)
705 				LEMAC_OUTSB(sc, LEMAC_REG_DAT,
706 				    m0->m_len, m0->m_data);
707 		} else {
708 			bus_size_t txoff = /* (mtod(m, u_int32_t) &
709 			    (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ;
710 			/* Shift 2K window. */
711 			LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg);
712 			LEMAC_PUT8(sc, 0, sc->sc_txctl);
713 			LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF);
714 			LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF);
715 			LEMAC_PUT8(sc, 3, txoff);
716 
717 			/*
718 			 * Copy the packet to the board
719 			 */
720 			for (m0 = m; m0 != NULL; m0 = m0->m_next) {
721 #if 0
722 				LEMAC_PUTBUF8(sc, txoff, m0->m_len,
723 				    m0->m_data);
724 				txoff += m0->m_len;
725 #else
726 				const u_int8_t *cp = m0->m_data;
727 				int len = m0->m_len;
728 #if 0
729 				if ((txoff & 3) == (((long)cp) & 3) &&
730 				    len >= 4) {
731 					if (txoff & 3) {
732 						int alen = (~txoff & 3);
733 						LEMAC_PUTBUF8(sc, txoff, alen,
734 						    cp);
735 						cp += alen;
736 						txoff += alen;
737 						len -= alen;
738 					}
739 					if (len >= 4) {
740 						LEMAC_PUTBUF32(sc, txoff,
741 						    len / 4, cp);
742 						cp += len & ~3;
743 						txoff += len & ~3;
744 						len &= 3;
745 					}
746 				}
747 #endif
748 				if ((txoff & 1) == (((long)cp) & 1) &&
749 				    len >= 2) {
750 					if (txoff & 1) {
751 						int alen = (~txoff & 1);
752 						LEMAC_PUTBUF8(sc, txoff, alen,
753 						    cp);
754 						cp += alen;
755 						txoff += alen;
756 						len -= alen;
757 					}
758 					if (len >= 2) {
759 						LEMAC_PUTBUF16(sc, txoff,
760 						    len / 2, (void *)cp);
761 						cp += len & ~1;
762 						txoff += len & ~1;
763 						len &= 1;
764 					}
765 				}
766 				if (len > 0) {
767 					LEMAC_PUTBUF8(sc, txoff, len, cp);
768 					txoff += len;
769 				}
770 #endif
771 			}
772 		}
773 
774 		/* tell chip to transmit this packet */
775 		LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg);
776 #if NBPFILTER > 0
777 		if (sc->sc_if.if_bpf != NULL)
778 			bpf_mtap(sc->sc_if.if_bpf, m);
779 #endif
780 		m_freem(m);			/* free the mbuf */
781 	}
782 	LEMAC_INTR_ENABLE(sc);
783 }
784 
785 int
lemac_ifioctl(struct ifnet * ifp,u_long cmd,caddr_t data)786 lemac_ifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
787 {
788 	struct lemac_softc *const sc = LEMAC_IFP_TO_SOFTC(ifp);
789 	int s;
790 	int error = 0;
791 	struct ifaddr *ifa = (struct ifaddr *)data;
792 	struct ifreq *ifr = (struct ifreq *)data;
793 
794 	s = splnet();
795 
796 	if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
797 		splx(s);
798 		return (error);
799 	}
800 
801 	switch (cmd) {
802 	case SIOCSIFADDR:
803 		ifp->if_flags |= IFF_UP;
804 		lemac_init(sc);
805 		switch (ifa->ifa_addr->sa_family) {
806 #ifdef INET
807 		case AF_INET:
808 			arp_ifinit(&sc->sc_arpcom, ifa);
809 			break;
810 #endif /* INET */
811 
812 #ifdef NS
813 		/* This magic copied from if_is.c; I don't use XNS,
814 		 * so I have no way of telling if this actually
815 		 * works or not.
816 		 */
817 		case AF_NS: {
818 			struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
819 			if (ns_nullhost(*ina)) {
820 				ina->x_host =
821 				    *(union ns_host *)sc->sc_arpcom.ac_enaddr;
822 			} else {
823 				bcopy((caddr_t)ina->x_host.c_host,
824 				    sc->sc_arpcom.ac_enaddr, ifp->if_addrlen);
825 			}
826 			break;
827 		}
828 #endif /* NS */
829 
830 		default:
831 			break;
832 		}
833 		break;
834 
835 	case SIOCSIFFLAGS:
836 		lemac_init(sc);
837 		break;
838 
839 	case SIOCADDMULTI:
840 	case SIOCDELMULTI:
841 		/*
842 		 * Update multicast listeners
843 		 */
844 		error = (cmd == SIOCADDMULTI) ?
845 		    ether_addmulti(ifr, &sc->sc_arpcom) :
846 		    ether_delmulti(ifr, &sc->sc_arpcom);
847 
848 		if (error == ENETRESET) {
849 			/* Reset multicast filtering. */
850 			lemac_init(sc);
851 			error = 0;
852 		}
853 		break;
854 
855 	case SIOCSIFMEDIA:
856 	case SIOCGIFMEDIA:
857 		error = ifmedia_ioctl(ifp, (struct ifreq *)data,
858 		    &sc->sc_ifmedia, cmd);
859 		break;
860 
861 	case SIOCSIFMTU:
862 		if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
863 			error = EINVAL;
864 		} else if (ifp->if_mtu != ifr->ifr_mtu) {
865 			ifp->if_mtu = ifr->ifr_mtu;
866 		}
867 		break;
868 
869 	default:
870 		error = EINVAL;
871 		break;
872 	}
873 
874 	splx(s);
875 	return (error);
876 }
877 
878 int
lemac_ifmedia_change(struct ifnet * const ifp)879 lemac_ifmedia_change(struct ifnet *const ifp)
880 {
881 	struct lemac_softc *const sc = LEMAC_IFP_TO_SOFTC(ifp);
882 	unsigned new_ctl;
883 
884 	switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
885 	case IFM_10_T:
886 		new_ctl = LEMAC_CTL_APD;
887 		break;
888 	case IFM_10_2:
889 	case IFM_10_5:
890 		new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL;
891 		break;
892 	case IFM_AUTO:
893 		new_ctl = 0;
894 		break;
895 	default:
896 		return (EINVAL);
897 	}
898 	if (sc->sc_ctlmode != new_ctl) {
899 		sc->sc_ctlmode = new_ctl;
900 		lemac_reset(sc);
901 		if (sc->sc_if.if_flags & IFF_UP)
902 			lemac_init(sc);
903 	}
904 	return (0);
905 }
906 
907 /*
908  * Media status callback
909  */
910 void
lemac_ifmedia_status(struct ifnet * const ifp,struct ifmediareq * req)911 lemac_ifmedia_status(struct ifnet *const ifp, struct ifmediareq *req)
912 {
913 	struct lemac_softc *sc = LEMAC_IFP_TO_SOFTC(ifp);
914 	unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF);
915 
916 	req->ifm_status = IFM_AVALID;
917 	if (sc->sc_flags & LEMAC_LINKUP)
918 		req->ifm_status |= IFM_ACTIVE;
919 
920 	if (sc->sc_ctlmode & LEMAC_CTL_APD) {
921 		if (sc->sc_ctlmode & LEMAC_CTL_PSL) {
922 			req->ifm_active = IFM_10_5;
923 		} else {
924 			req->ifm_active = IFM_10_T;
925 		}
926 	} else {
927 		/*
928 		 * The link bit of the configuration register reflects the
929 		 * current media choice when auto-port is enabled.
930 		 */
931 		if (data & LEMAC_CNF_NOLINK) {
932 			req->ifm_active = IFM_10_5;
933 		} else {
934 			req->ifm_active = IFM_10_T;
935 		}
936 	}
937 
938 	req->ifm_active |= IFM_ETHER;
939 }
940 
941 int
lemac_port_check(const bus_space_tag_t iot,const bus_space_handle_t ioh)942 lemac_port_check(const bus_space_tag_t iot, const bus_space_handle_t ioh)
943 {
944 	unsigned char hwaddr[6];
945 
946 	if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0)
947 		return (1);
948 	if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0)
949 		return (1);
950 	return (0);
951 }
952 
953 void
lemac_info_get(const bus_space_tag_t iot,const bus_space_handle_t ioh,bus_addr_t * maddr_p,bus_size_t * msize_p,int * irq_p)954 lemac_info_get(const bus_space_tag_t iot, const bus_space_handle_t ioh,
955     bus_addr_t *maddr_p, bus_size_t *msize_p, int *irq_p)
956 {
957 	unsigned data;
958 
959 	*irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC) &
960 	    LEMAC_IC_IRQMSK);
961 
962 	data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR);
963 	if (LEMAC_IS_2K_MODE(data)) {
964 		*maddr_p = data * (2 * 1024) + (512 * 1024);
965 		*msize_p =  2 * 1024;
966 	} else if (LEMAC_IS_64K_MODE(data)) {
967 		*maddr_p = data * 64 * 1024;
968 		*msize_p = 64 * 1024;
969 	} else if (LEMAC_IS_32K_MODE(data)) {
970 		*maddr_p = data * 32 * 1024;
971 		*msize_p = 32* 1024;
972 	} else {
973 		*maddr_p = 0;
974 		*msize_p = 0;
975 	}
976 }
977 
978 /*
979  * What to do upon receipt of an interrupt.
980  */
981 int
lemac_intr(void * arg)982 lemac_intr(void *arg)
983 {
984 	struct lemac_softc *const sc = arg;
985 	int cs_value;
986 
987 	LEMAC_INTR_DISABLE(sc);	/* Mask interrupts */
988 
989 	/*
990 	 * Determine cause of interrupt.  Receive events take
991 	 * priority over Transmit.
992 	 */
993 
994 	cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
995 
996 	/*
997 	 * Check for Receive Queue not being empty.
998 	 * Check for Transmit Done Queue not being empty.
999 	 */
1000 
1001 	if (cs_value & LEMAC_CS_RNE)
1002 		lemac_rne_intr(sc);
1003 	if (cs_value & LEMAC_CS_TNE)
1004 		lemac_tne_intr(sc);
1005 
1006 	/*
1007 	 * Check for Transmitter Disabled.
1008 	 * Check for Receiver Disabled.
1009 	 */
1010 
1011 	if (cs_value & LEMAC_CS_TXD)
1012 		lemac_txd_intr(sc, cs_value);
1013 	if (cs_value & LEMAC_CS_RXD)
1014 		lemac_rxd_intr(sc, cs_value);
1015 
1016 	/*
1017 	 * Toggle LED and unmask interrupts.
1018 	 */
1019 
1020 	sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS);
1021 
1022 	LEMAC_OUTB(sc, LEMAC_REG_CTL,
1023 	    LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
1024 	LEMAC_INTR_ENABLE(sc);		/* Unmask interrupts */
1025 
1026 #ifdef __MirBSD__
1027 	if (cs_value)
1028 		rnd_lopool_addv(cs_value);
1029 #if 0
1030 		rnd_add_uint32(&sc->rnd_source, cs_value);
1031 #endif
1032 #endif
1033 
1034 	return (1);
1035 }
1036 
1037 void
lemac_shutdown(void * arg)1038 lemac_shutdown(void *arg)
1039 {
1040 	lemac_reset((struct lemac_softc *)arg);
1041 }
1042 
1043 const char *const lemac_modes[4] = {
1044 	"PIO mode (internal 2KB window)",
1045 	"2KB window",
1046 	"changed 32KB window to 2KB",
1047 	"changed 64KB window to 2KB",
1048 };
1049 
1050 void
lemac_ifattach(struct lemac_softc * sc)1051 lemac_ifattach(struct lemac_softc *sc)
1052 {
1053 	struct ifnet *const ifp = &sc->sc_if;
1054 
1055 	bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
1056 
1057 	lemac_reset(sc);
1058 
1059 	lemac_read_macaddr(sc->sc_arpcom.ac_enaddr, sc->sc_iot, sc->sc_ioh,
1060 	    LEMAC_REG_APD, 0);
1061 
1062 	printf(": %s\n", sc->sc_prodname);
1063 
1064 	printf("%s: address %s, %dKB RAM, %s\n", ifp->if_xname,
1065 	    ether_sprintf(sc->sc_arpcom.ac_enaddr), sc->sc_lastpage * 2 + 2,
1066 	    lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
1067 
1068 	ifp->if_softc = (void *)sc;
1069 	ifp->if_start = lemac_ifstart;
1070 	ifp->if_ioctl = lemac_ifioctl;
1071 
1072 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX
1073 #ifdef IFF_NOTRAILERS
1074 		| IFF_NOTRAILERS
1075 #endif
1076 		| IFF_MULTICAST;
1077 
1078 	if (sc->sc_flags & LEMAC_ALIVE) {
1079 		int media;
1080 
1081 		IFQ_SET_READY(&ifp->if_snd);
1082 
1083 		if_attach(ifp);
1084 		ether_ifattach(ifp);
1085 
1086 #if 0
1087 		rnd_attach_source(&sc->rnd_source, sc->sc_dv.dv_xname,
1088 		    RND_TYPE_NET, 0);
1089 #endif
1090 
1091 		ifmedia_init(&sc->sc_ifmedia, 0, lemac_ifmedia_change,
1092 		    lemac_ifmedia_status);
1093 		if (sc->sc_prodname[4] == '5')	/* DE205 is UTP/AUI */
1094 			ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0,
1095 			    0);
1096 		if (sc->sc_prodname[4] != '3')	/* DE204 & 205 have UTP */
1097 			ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0,
1098 			    0);
1099 		if (sc->sc_prodname[4] != '4')	/* DE203 & 205 have BNC */
1100 			ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0,
1101 			    0);
1102 		switch (sc->sc_prodname[4]) {
1103 		case '3':
1104 			media = IFM_10_5;
1105 			break;
1106 		case '4':
1107 			media = IFM_10_T;
1108 			break;
1109 		default:
1110 			media = IFM_AUTO;
1111 			break;
1112 		}
1113 		ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
1114 	} else {
1115 		printf("%s: disabled due to error\n", ifp->if_xname);
1116 	}
1117 }
1118