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