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