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