lemac.c revision 1.1 1 /* $NetBSD: lemac.c,v 1.1 1997/07/31 21:54:58 matt 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 withough 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/param.h>
37 #include <sys/systm.h>
38 #include <sys/mbuf.h>
39 #include <sys/protosw.h>
40 #include <sys/socket.h>
41 #include <sys/sockio.h>
42 #include <sys/errno.h>
43 #include <sys/malloc.h>
44 #include <sys/device.h>
45
46 #include <net/if.h>
47 #include <net/if_types.h>
48 #include <net/if_dl.h>
49 #include <net/route.h>
50 #include <net/if_ether.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_inarp.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/ic/lemacreg.h>
69 #include <dev/ic/lemacvar.h>
70 #if 0
71 #include <i386/isa/decether.h>
72 #endif
73
74 #include <vm/vm.h>
75
76 #include "bpfilter.h"
77 #if NBPFILTER > 0
78 #include <net/bpf.h>
79 #endif
80
81 struct cfdriver lc_cd = {
82 NULL, "lc", DV_IFNET
83 };
84
85
86 static void lemac_init(lemac_softc_t *sc);
87 static void lemac_ifstart(struct ifnet *ifp);
88 static void lemac_reset(lemac_softc_t *sc);
89 static void lemac_rne_intr(lemac_softc_t *sc);
90 static void lemac_tne_intr(lemac_softc_t *sc);
91 static void lemac_txd_intr(lemac_softc_t *sc, unsigned cs_value);
92 static void lemac_rxd_intr(lemac_softc_t *sc, unsigned cs_value);
93 static int lemac_read_eeprom(lemac_softc_t *sc);
94 static void lemac_init_adapmem(lemac_softc_t *sc);
95
96 static const u_int16_t lemac_allmulti_mctbl[16] = {
97 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
98 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
99 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
100 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
101 };
102
103 /*
104 * Some tuning/monitoring variables.
105 */
106 unsigned lemac_txmax = 16;
107
108 static void
110 lemac_rxd_intr(
111 lemac_softc_t *sc,
112 unsigned cs_value)
113 {
114 /*
115 * Handle CS_RXD (Receiver disabled) here.
116 *
117 * Check Free Memory Queue Count. If not equal to zero
118 * then just turn Receiver back on. If it is equal to
119 * zero then check to see if transmitter is disabled.
120 * Process transmit TXD loop once more. If all else
121 * fails then do software init (0xC0 to EEPROM Init)
122 * and rebuild Free Memory Queue.
123 */
124
125 sc->sc_cntrs.cntr_rxd_intrs++;
126
127 /*
128 * Re-enable Receiver.
129 */
130
131 cs_value &= ~LEMAC_CS_RXD;
132 LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value);
133
134 if (LEMAC_INB(sc, LEMAC_REG_FMC) > 0)
135 return;
136
137 if (cs_value & LEMAC_CS_TXD)
138 lemac_txd_intr(sc, cs_value);
139
140 if ((LEMAC_INB(sc, LEMAC_REG_CS) & LEMAC_CS_RXD) == 0)
141 return;
142
143 printf("%s: fatal RXD error, attempting recovery\n", sc->sc_if.if_xname);
144
145 lemac_reset(sc);
146 if (sc->sc_if.if_flags & IFF_UP) {
147 lemac_init(sc);
148 return;
149 }
150
151 /*
152 * Error during initializion. Mark card as disabled.
153 */
154 printf("%s: recovery failed -- board disabled\n", sc->sc_if.if_xname);
155 }
156
157 static void
159 lemac_tne_intr(
160 lemac_softc_t *sc)
161 {
162 unsigned txcount = LEMAC_INB(sc, LEMAC_REG_TDC);
163
164 sc->sc_cntrs.cntr_tne_intrs++;
165 while (txcount-- > 0) {
166 unsigned txsts = LEMAC_INB(sc, LEMAC_REG_TDQ);
167 sc->sc_if.if_opackets++; /* another one done */
168 if ((txsts & (LEMAC_TDQ_LCL|LEMAC_TDQ_NCL))
169 || (txsts & LEMAC_TDQ_COL) == LEMAC_TDQ_EXCCOL) {
170 if (txsts & LEMAC_TDQ_NCL)
171 sc->sc_flags &= ~LEMAC_LINKUP;
172 sc->sc_if.if_oerrors++;
173 } else {
174 sc->sc_flags |= LEMAC_LINKUP;
175 if ((txsts & LEMAC_TDQ_COL) != LEMAC_TDQ_NOCOL)
176 sc->sc_if.if_collisions++;
177 }
178 }
179 sc->sc_if.if_flags &= ~IFF_OACTIVE;
180 lemac_ifstart(&sc->sc_if);
181 }
182
183 static void
184 lemac_txd_intr(
185 lemac_softc_t *sc,
186 unsigned cs_value)
187 {
188 /*
189 * Read transmit status, remove transmit buffer from
190 * transmit queue and place on free memory queue,
191 * then reset transmitter.
192 * Increment appropriate counters.
193 */
194
195 sc->sc_cntrs.cntr_txd_intrs++;
196 if (sc->sc_txctl & LEMAC_TX_STP) {
197 sc->sc_if.if_oerrors++;
198 /* return page to free queue */
199 LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ));
200 }
201
202 /* Turn back on transmitter if disabled */
203 LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value & ~LEMAC_CS_TXD);
204 sc->sc_if.if_flags &= ~IFF_OACTIVE;
205 }
206
207 static int
209 lemac_read_eeprom(
210 lemac_softc_t *sc)
211 {
212 int word_off, cksum;
213
214 u_char *ep;
215
216 cksum = 0;
217 ep = sc->sc_eeprom;
218 for (word_off = 0; word_off < LEMAC_EEP_SIZE / 2; word_off++) {
219 LEMAC_OUTB(sc, LEMAC_REG_PI1, word_off);
220 LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEREAD);
221
222 DELAY(LEMAC_EEP_DELAY);
223
224 *ep = LEMAC_INB(sc, LEMAC_REG_EE1); cksum += *ep++;
225 *ep = LEMAC_INB(sc, LEMAC_REG_EE2); cksum += *ep++;
226 }
227
228 /*
229 * Set up Transmit Control Byte for use later during transmit.
230 */
231
232 sc->sc_txctl |= LEMAC_TX_FLAGS;
233
234 if ((sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_SQE) == 0)
235 sc->sc_txctl &= ~LEMAC_TX_SQE;
236
237 if (sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_LAB)
238 sc->sc_txctl |= LEMAC_TX_LAB;
239
240 bcopy(&sc->sc_eeprom[LEMAC_EEP_PRDNM], sc->sc_prodname, LEMAC_EEP_PRDNMSZ);
241 sc->sc_prodname[LEMAC_EEP_PRDNMSZ] = '\0';
242
243 return cksum % 256;
244 }
245
246 static void
248 lemac_init_adapmem(
249 lemac_softc_t *sc)
250 {
251 int pg, conf;
252
253 conf = LEMAC_INB(sc, LEMAC_REG_CNF);
254
255 if ((sc->sc_eeprom[LEMAC_EEP_SETUP] & LEMAC_EEP_ST_DRAM) == 0) {
256 sc->sc_lastpage = 63;
257 conf &= ~LEMAC_CNF_DRAM;
258 } else {
259 sc->sc_lastpage = 127;
260 conf |= LEMAC_CNF_DRAM;
261 }
262
263 LEMAC_OUTB(sc, LEMAC_REG_CNF, conf);
264
265 for (pg = 1; pg <= sc->sc_lastpage; pg++)
266 LEMAC_OUTB(sc, LEMAC_REG_FMQ, pg);
267 }
268
269 static void
271 lemac_input(
272 lemac_softc_t *sc,
273 bus_addr_t offset,
274 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 /*
291 * If this is single cast but not to us
292 * drop it!
293 */
294 if ((eh.ether_dhost[0] & 1) == 0
295 #if NBPFILTER > 0
296 && (sc->sc_if.if_flags & IFF_PROMISC) == 0
297 #endif
298 && !LEMAC_ADDREQUAL(eh.ether_dhost, LLADDR(sc->sc_if.if_sadl)))
299 return;
300
301 MGETHDR(m, M_DONTWAIT, MT_DATA);
302 if (m == NULL) {
303 sc->sc_if.if_ierrors++;
304 return;
305 }
306 if (length + 2 > MHLEN) {
307 MCLGET(m, M_DONTWAIT);
308 if ((m->m_flags & M_EXT) == 0) {
309 m_free(m);
310 sc->sc_if.if_ierrors++;
311 return;
312 }
313 }
314 m->m_data += 2;
315 bcopy((caddr_t)&eh, m->m_data, sizeof(eh));
316 if (LEMAC_USE_PIO_MODE(sc)) {
317 LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh),
318 mtod(m, caddr_t) + sizeof(eh));
319 } else {
320 LEMAC_GETBUF16(sc, offset + sizeof(eh), (length - sizeof(eh)) / 2,
321 (void *) (mtod(m, caddr_t) + sizeof(eh)));
322 if (length & 1)
323 m->m_data[length - 1] = LEMAC_GET8(sc, offset + length - 1);
324 }
325 #if NBPFILTER > 0
326 if (sc->sc_if.if_bpf != NULL) {
327 m->m_pkthdr.len = m->m_len = length;
328 bpf_mtap(sc->sc_if.if_bpf, m);
329 }
330 /*
331 * If this is single cast but not to us
332 * drop it!
333 */
334 if ((eh.ether_dhost[0] & 1) == 0
335 && !LEMAC_ADDREQUAL(eh.ether_dhost, LLADDR(sc->sc_if.if_sadl))) {
336 m_freem(m);
337 return;
338 }
339 #endif
340 m->m_pkthdr.len = m->m_len = length - sizeof(eh);
341 m->m_data += sizeof(eh);
342 m->m_pkthdr.rcvif = &sc->sc_if;
343 ether_input(&sc->sc_if, &eh, m);
344 }
345
346 static void
348 lemac_rne_intr(
349 lemac_softc_t *sc)
350 {
351 int rxcount;
352
353 sc->sc_cntrs.cntr_rne_intrs++;
354 rxcount = LEMAC_INB(sc, LEMAC_REG_RQC);
355 while (rxcount--) {
356 unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ);
357 u_int32_t rxlen;
358
359 sc->sc_if.if_ipackets++;
360 if (LEMAC_USE_PIO_MODE(sc)) {
361 LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg);
362 LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
363 LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
364 LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen), (void *) &rxlen);
365 } else {
366 LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg);
367 rxlen = LEMAC_GET32(sc, 0);
368 }
369 if (rxlen & LEMAC_RX_OK) {
370 sc->sc_flags |= LEMAC_LINKUP;
371 /*
372 * Get receive length - subtract out checksum.
373 */
374 rxlen = ((rxlen >> 8) & 0x7FF) - 4;
375 lemac_input(sc, sizeof(rxlen), rxlen);
376 } else {
377 sc->sc_if.if_ierrors++;
378 }
379 LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg); /* Return this page to Free Memory Queue */
380 } /* end while (recv_count--) */
381
382 return;
383 }
384
385 /*
387 * This is the standard method of reading the DEC Address ROMS.
388 * I don't understand it but it does work.
389 */
390 static int
391 lemac_read_macaddr(
392 unsigned char *hwaddr,
393 const bus_space_tag_t iot,
394 const bus_space_handle_t ioh,
395 const bus_addr_t ioreg,
396 int skippat)
397 {
398 int cksum, rom_cksum;
399 unsigned char addrbuf[6];
400
401 if (!skippat) {
402 int idx, idx2, found, octet;
403 static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
404 idx2 = found = 0;
405
406 for (idx = 0; idx < 32; idx++) {
407 octet = bus_space_read_1(iot, ioh, ioreg);
408
409 if (octet == testpat[idx2]) {
410 if (++idx2 == sizeof(testpat)) {
411 ++found;
412 break;
413 }
414 } else {
415 idx2 = 0;
416 }
417 }
418
419 if (!found)
420 return -1;
421 }
422
423 if (hwaddr == NULL)
424 hwaddr = addrbuf;
425
426 cksum = 0;
427 hwaddr[0] = bus_space_read_1(iot, ioh, ioreg);
428 hwaddr[1] = bus_space_read_1(iot, ioh, ioreg);
429
430 /* hardware adddress can't be multicast */
431 if (hwaddr[0] & 1)
432 return -1;
433
434 cksum = *(u_short *) &hwaddr[0];
435
436 hwaddr[2] = bus_space_read_1(iot, ioh, ioreg);
437 hwaddr[3] = bus_space_read_1(iot, ioh, ioreg);
438 cksum *= 2;
439 if (cksum > 65535) cksum -= 65535;
440 cksum += *(u_short *) &hwaddr[2];
441 if (cksum > 65535) cksum -= 65535;
442
443 hwaddr[4] = bus_space_read_1(iot, ioh, ioreg);
444 hwaddr[5] = bus_space_read_1(iot, ioh, ioreg);
445 cksum *= 2;
446 if (cksum > 65535) cksum -= 65535;
447 cksum += *(u_short *) &hwaddr[4];
448 if (cksum >= 65535) cksum -= 65535;
449
450 /* 00-00-00 is an illegal OUI */
451 if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0)
452 return -1;
453
454 rom_cksum = bus_space_read_1(iot, ioh, ioreg);
455 rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8;
456
457 if (cksum != rom_cksum)
458 return -1;
459 return 0;
460 }
461
462 static void
464 lemac_multicast_op(
465 u_int16_t *mctbl,
466 const u_char *mca,
467 int enable)
468 {
469 u_int idx, bit, data, crc = 0xFFFFFFFFUL;
470
471 for (idx = 0; idx < 6; idx++)
472 for (data = *mca++, bit = 0; bit < 8; bit++, data >>= 1)
473 crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LEMAC_CRC32_POLY : 0);
474 /*
475 * The following two lines convert the N bit index into a longword index
476 * and a longword mask.
477 */
478 #if LEMAC_MCTBL_BITS < 0
479 crc >>= (32 + LEMAC_MCTBL_BITS);
480 crc &= (1 << -LEMAC_MCTBL_BITS) - 1;
481 #else
482 crc &= (1 << LEMAC_MCTBL_BITS) - 1;
483 #endif
484 bit = 1 << (crc & 0x0F);
485 idx = crc >> 4;
486
487 /*
488 * Set or clear hash filter bit in our table.
489 */
490 if (enable) {
491 mctbl[idx] |= bit; /* Set Bit */
492 } else {
493 mctbl[idx] &= ~bit; /* Clear Bit */
494 }
495 }
496
497 static void
499 lemac_multicast_filter(
500 lemac_softc_t *sc)
501 {
502 struct ether_multistep step;
503 struct ether_multi *enm;
504
505 bzero(sc->sc_mctbl, LEMAC_MCTBL_BITS / 8);
506
507 lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, TRUE);
508
509 ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
510 while (enm != NULL) {
511 if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
512 sc->sc_flags |= LEMAC_ALLMULTI;
513 sc->sc_if.if_flags |= IFF_ALLMULTI;
514 return;
515 }
516 lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
517 ETHER_NEXT_MULTI(step, enm);
518 }
519 sc->sc_flags &= ~LEMAC_ALLMULTI;
520 sc->sc_if.if_flags &= ~IFF_ALLMULTI;
521 }
522
523 /*
525 * Do a hard reset of the board;
526 */
527 static void
528 lemac_reset(
529 lemac_softc_t * const sc)
530 {
531 unsigned data;
532
533 /*
534 * Initialize board..
535 */
536 sc->sc_flags &= ~LEMAC_LINKUP;
537 sc->sc_if.if_flags &= ~IFF_OACTIVE;
538 LEMAC_INTR_DISABLE(sc);
539
540 LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
541 DELAY(LEMAC_EEP_DELAY);
542
543 /*
544 * Read EEPROM information. NOTE - the placement of this function
545 * is important because functions hereafter may rely on information
546 * read from the EEPROM.
547 */
548 if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
549 printf("%s: reset: EEPROM checksum failed (0x%x)\n",
550 sc->sc_if.if_xname, data);
551 return;
552 }
553
554 /*
555 * Update the control register to reflect the media choice
556 */
557 data = LEMAC_INB(sc, LEMAC_REG_CTL);
558 if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
559 data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
560 data |= sc->sc_ctlmode;
561 LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
562 }
563
564 /*
565 * Force to 2K mode if not already configured.
566 */
567
568 data = LEMAC_INB(sc, LEMAC_REG_MBR);
569 if (LEMAC_IS_2K_MODE(data)) {
570 sc->sc_flags |= LEMAC_2K_MODE;
571 } else if (LEMAC_IS_64K_MODE(data)) {
572 data = (((data * 2) & 0xF) << 4);
573 sc->sc_flags |= LEMAC_WAS_64K_MODE;
574 LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
575 } else if (LEMAC_IS_32K_MODE(data)) {
576 data = ((data & 0xF) << 4);
577 sc->sc_flags |= LEMAC_WAS_32K_MODE;
578 LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
579 } else {
580 sc->sc_flags |= LEMAC_PIO_MODE;
581 /* PIO mode */
582 }
583
584 /*
585 * Initialize Free Memory Queue, Init mcast table with broadcast.
586 */
587
588 lemac_init_adapmem(sc);
589 sc->sc_flags |= LEMAC_ALIVE;
590 }
591
592 static void
594 lemac_init(
595 lemac_softc_t * const sc)
596 {
597 if ((sc->sc_flags & LEMAC_ALIVE) == 0)
598 return;
599
600 /*
601 * If the interface has the up flag
602 */
603 if (sc->sc_if.if_flags & IFF_UP) {
604 int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS);
605 LEMAC_OUTB(sc, LEMAC_REG_CS, saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
606 LEMAC_OUTB(sc, LEMAC_REG_PA0, LLADDR(sc->sc_if.if_sadl)[0]);
607 LEMAC_OUTB(sc, LEMAC_REG_PA1, LLADDR(sc->sc_if.if_sadl)[1]);
608 LEMAC_OUTB(sc, LEMAC_REG_PA2, LLADDR(sc->sc_if.if_sadl)[2]);
609 LEMAC_OUTB(sc, LEMAC_REG_PA3, LLADDR(sc->sc_if.if_sadl)[3]);
610 LEMAC_OUTB(sc, LEMAC_REG_PA4, LLADDR(sc->sc_if.if_sadl)[4]);
611 LEMAC_OUTB(sc, LEMAC_REG_PA5, LLADDR(sc->sc_if.if_sadl)[5]);
612
613 LEMAC_OUTB(sc, LEMAC_REG_IC, LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
614
615 if (sc->sc_if.if_flags & IFF_PROMISC) {
616 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE | LEMAC_CS_PME);
617 } else {
618 LEMAC_INTR_DISABLE(sc);
619 lemac_multicast_filter(sc);
620 if (sc->sc_flags & LEMAC_ALLMULTI)
621 bcopy(lemac_allmulti_mctbl, sc->sc_mctbl, sizeof(sc->sc_mctbl));
622 if (LEMAC_USE_PIO_MODE(sc)) {
623 LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
624 LEMAC_OUTB(sc, LEMAC_REG_PI1, LEMAC_MCTBL_OFF & 0xFF);
625 LEMAC_OUTB(sc, LEMAC_REG_PI2, LEMAC_MCTBL_OFF >> 8);
626 LEMAC_OUTSB(sc, LEMAC_REG_DAT, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
627 } else {
628 LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
629 LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
630 }
631
632 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
633 }
634
635 LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
636
637 LEMAC_INTR_ENABLE(sc);
638 sc->sc_if.if_flags |= IFF_RUNNING;
639 lemac_ifstart(&sc->sc_if);
640 } else {
641 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
642
643 LEMAC_INTR_DISABLE(sc);
644 sc->sc_if.if_flags &= ~IFF_RUNNING;
645 }
646 }
647
648 static void
650 lemac_ifstart(
651 struct ifnet *ifp)
652 {
653 lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
654 struct ifqueue * const ifq = &ifp->if_snd;
655
656 if ((ifp->if_flags & IFF_RUNNING) == 0)
657 return;
658
659 LEMAC_INTR_DISABLE(sc);
660
661 while (ifq->ifq_head != NULL) {
662 struct mbuf *m;
663 struct mbuf *m0;
664 int tx_pg;
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 IF_DEQUEUE(ifq, 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 *)LLADDR(ifp->if_sadl);
800 } else {
801 bcopy((caddr_t)ina->x_host.c_host,
802 LLADDR(ifp->if_sadl), 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 return 1;
1009 }
1010
1011 void
1012 lemac_shutdown(
1013 void *arg)
1014 {
1015 lemac_reset((lemac_softc_t *) arg);
1016 }
1017
1018 static const char * const lemac_modes[4] = {
1020 "PIO mode (internal 2KB window)",
1021 "2KB window",
1022 "changed 32KB window to 2KB",
1023 "changed 64KB window to 2KB",
1024 };
1025
1026 void
1027 lemac_ifattach(
1028 lemac_softc_t *sc)
1029 {
1030 struct ifnet * const ifp = &sc->sc_if;
1031
1032 bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
1033
1034 lemac_reset(sc);
1035
1036 (void) lemac_read_macaddr(sc->sc_enaddr, sc->sc_iot, sc->sc_ioh,
1037 LEMAC_REG_APD, 0);
1038
1039 printf(": %s\n", sc->sc_prodname);
1040
1041 printf("%s: address %s, %dKB RAM, %s\n",
1042 ifp->if_xname,
1043 ether_sprintf(sc->sc_enaddr),
1044 sc->sc_lastpage * 2 + 2,
1045 lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
1046
1047 ifp->if_baudrate = 10000000;
1048 ifp->if_softc = (void *) sc;
1049 ifp->if_start = lemac_ifstart;
1050 ifp->if_output = ether_output;
1051 ifp->if_ioctl = lemac_ifioctl;
1052
1053 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX
1054 #ifdef IFF_NOTRAILERS
1055 | IFF_NOTRAILERS
1056 #endif
1057 | IFF_MULTICAST;
1058
1059 if (sc->sc_flags & LEMAC_ALIVE) {
1060 int media;
1061
1062 if_attach(ifp);
1063 ether_ifattach(ifp, sc->sc_enaddr);
1064
1065 #if NBPFILTER > 0
1066 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
1067 #endif
1068 ifmedia_init(&sc->sc_ifmedia, 0,
1069 lemac_ifmedia_change,
1070 lemac_ifmedia_status);
1071 if (sc->sc_prodname[4] == '5') /* DE205 is UTP/AUI */
1072 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
1073 if (sc->sc_prodname[4] != '3') /* DE204 & 205 have UTP */
1074 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, 0);
1075 if (sc->sc_prodname[4] != '4') /* DE203 & 205 have BNC */
1076 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, 0);
1077 switch (sc->sc_prodname[4]) {
1078 case '3': media = IFM_10_5; break;
1079 case '4': media = IFM_10_T; break;
1080 default: media = IFM_AUTO; break;
1081 }
1082 ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
1083 } else {
1084 printf("%s: disabled due to error\n", ifp->if_xname);
1085 }
1086 }
1087