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