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