This source file includes following definitions.
- lemac_rxd_intr
- lemac_tne_intr
- lemac_txd_intr
- lemac_read_eeprom
- lemac_init_adapmem
- lemac_input
- lemac_rne_intr
- lemac_read_macaddr
- lemac_multicast_op
- lemac_multicast_filter
- lemac_reset
- lemac_init
- lemac_ifstart
- lemac_ifioctl
- lemac_ifmedia_change
- lemac_ifmedia_status
- lemac_port_check
- lemac_info_get
- lemac_intr
- lemac_shutdown
- lemac_ifattach
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/mbuf.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <sys/errno.h>
44 #include <sys/malloc.h>
45 #include <sys/device.h>
46
47 #include <net/if.h>
48 #include <net/if_types.h>
49 #include <net/if_dl.h>
50 #include <net/route.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_ether.h>
59 #endif
60
61 #include <machine/bus.h>
62
63 #include <dev/ic/lemacreg.h>
64 #include <dev/ic/lemacvar.h>
65
66 #if 0
67 #include <uvm/uvm_extern.h>
68 #endif
69
70 #include "bpfilter.h"
71 #if NBPFILTER > 0
72 #include <net/bpf.h>
73 #endif
74
75 int lemac_ifioctl(struct ifnet *, u_long, caddr_t);
76 int lemac_ifmedia_change(struct ifnet *const);
77 void lemac_ifmedia_status(struct ifnet *const, struct ifmediareq *);
78 void lemac_ifstart(struct ifnet *);
79 void lemac_init(struct lemac_softc *);
80 void lemac_init_adapmem(struct lemac_softc *);
81 void lemac_input(struct lemac_softc *, bus_size_t, size_t);
82 void lemac_multicast_filter(struct lemac_softc *);
83 void lemac_multicast_op(u_int16_t *, const u_char *, int);
84 int lemac_read_eeprom(struct lemac_softc *);
85 int lemac_read_macaddr(unsigned char *, const bus_space_tag_t,
86 const bus_space_handle_t, const bus_size_t, int);
87 void lemac_reset(struct lemac_softc *);
88 void lemac_rne_intr(struct lemac_softc *);
89 void lemac_rxd_intr(struct lemac_softc *, unsigned);
90 void lemac_tne_intr(struct lemac_softc *);
91 void lemac_txd_intr(struct lemac_softc *, unsigned);
92
93 struct cfdriver lc_cd = {
94 NULL, "lc", DV_IFNET
95 };
96
97 static const u_int16_t lemac_allmulti_mctbl[LEMAC_MCTBL_SIZE/sizeof(u_int16_t)] = {
98 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
99 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
100 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
101 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
102 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
103 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
104 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
105 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
106 };
107
108
109
110
111 unsigned lemac_txmax = 16;
112
113 void
114 lemac_rxd_intr(struct lemac_softc *sc, unsigned cs_value)
115 {
116
117
118
119
120
121
122
123
124
125
126
127 sc->sc_cntrs.cntr_rxd_intrs++;
128
129
130
131
132
133 cs_value &= ~LEMAC_CS_RXD;
134 LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value);
135
136 if (LEMAC_INB(sc, LEMAC_REG_FMC) > 0)
137 return;
138
139 if (cs_value & LEMAC_CS_TXD)
140 lemac_txd_intr(sc, cs_value);
141
142 if ((LEMAC_INB(sc, LEMAC_REG_CS) & LEMAC_CS_RXD) == 0)
143 return;
144
145 printf("%s: fatal RXD error, attempting recovery\n",
146 sc->sc_if.if_xname);
147
148 lemac_reset(sc);
149 if (sc->sc_if.if_flags & IFF_UP) {
150 lemac_init(sc);
151 return;
152 }
153
154
155
156
157 printf("%s: recovery failed -- board disabled\n", sc->sc_if.if_xname);
158 }
159
160 void
161 lemac_tne_intr(struct lemac_softc *sc)
162 {
163 unsigned txcount = LEMAC_INB(sc, LEMAC_REG_TDC);
164
165 sc->sc_cntrs.cntr_tne_intrs++;
166 while (txcount-- > 0) {
167 unsigned txsts = LEMAC_INB(sc, LEMAC_REG_TDQ);
168 sc->sc_if.if_opackets++;
169 if ((txsts & (LEMAC_TDQ_LCL|LEMAC_TDQ_NCL))
170 || (txsts & LEMAC_TDQ_COL) == LEMAC_TDQ_EXCCOL) {
171 if (txsts & LEMAC_TDQ_NCL)
172 sc->sc_flags &= ~LEMAC_LINKUP;
173 sc->sc_if.if_oerrors++;
174 } else {
175 sc->sc_flags |= LEMAC_LINKUP;
176 if ((txsts & LEMAC_TDQ_COL) != LEMAC_TDQ_NOCOL)
177 sc->sc_if.if_collisions++;
178 }
179 }
180 sc->sc_if.if_flags &= ~IFF_OACTIVE;
181 lemac_ifstart(&sc->sc_if);
182 }
183
184 void
185 lemac_txd_intr(struct lemac_softc *sc, unsigned cs_value)
186 {
187
188
189
190
191
192
193
194 sc->sc_cntrs.cntr_txd_intrs++;
195 if (sc->sc_txctl & LEMAC_TX_STP) {
196 sc->sc_if.if_oerrors++;
197
198 LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ));
199 }
200
201
202 LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value & ~LEMAC_CS_TXD);
203 sc->sc_if.if_flags &= ~IFF_OACTIVE;
204 }
205
206 int
207 lemac_read_eeprom(struct lemac_softc *sc)
208 {
209 int word_off, cksum;
210
211 u_char *ep;
212
213 cksum = 0;
214 ep = sc->sc_eeprom;
215 for (word_off = 0; word_off < LEMAC_EEP_SIZE / 2; word_off++) {
216 LEMAC_OUTB(sc, LEMAC_REG_PI1, word_off);
217 LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEREAD);
218
219 DELAY(LEMAC_EEP_DELAY);
220
221 *ep = LEMAC_INB(sc, LEMAC_REG_EE1);
222 cksum += *ep++;
223 *ep = LEMAC_INB(sc, LEMAC_REG_EE2);
224 cksum += *ep++;
225 }
226
227
228
229
230
231 sc->sc_txctl |= LEMAC_TX_FLAGS;
232
233 if ((sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_SQE) == 0)
234 sc->sc_txctl &= ~LEMAC_TX_SQE;
235
236 if (sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_LAB)
237 sc->sc_txctl |= LEMAC_TX_LAB;
238
239 bcopy(&sc->sc_eeprom[LEMAC_EEP_PRDNM], sc->sc_prodname,
240 LEMAC_EEP_PRDNMSZ);
241 sc->sc_prodname[LEMAC_EEP_PRDNMSZ] = '\0';
242
243 return (cksum % 256);
244 }
245
246 void
247 lemac_init_adapmem(struct lemac_softc *sc)
248 {
249 int pg, conf;
250
251 conf = LEMAC_INB(sc, LEMAC_REG_CNF);
252
253 if ((sc->sc_eeprom[LEMAC_EEP_SETUP] & LEMAC_EEP_ST_DRAM) == 0) {
254 sc->sc_lastpage = 63;
255 conf &= ~LEMAC_CNF_DRAM;
256 } else {
257 sc->sc_lastpage = 127;
258 conf |= LEMAC_CNF_DRAM;
259 }
260
261 LEMAC_OUTB(sc, LEMAC_REG_CNF, conf);
262
263 for (pg = 1; pg <= sc->sc_lastpage; pg++)
264 LEMAC_OUTB(sc, LEMAC_REG_FMQ, pg);
265 }
266
267 void
268 lemac_input(struct lemac_softc *sc, bus_size_t offset, size_t length)
269 {
270 struct ether_header eh;
271 struct mbuf *m;
272
273 if (length - sizeof(eh) > ETHERMTU ||
274 length - sizeof(eh) < ETHERMIN) {
275 sc->sc_if.if_ierrors++;
276 return;
277 }
278 if (LEMAC_USE_PIO_MODE(sc)) {
279 LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(eh), (void *)&eh);
280 } else {
281 LEMAC_GETBUF16(sc, offset, sizeof(eh) / 2, (void *)&eh);
282 }
283
284 MGETHDR(m, M_DONTWAIT, MT_DATA);
285 if (m == NULL) {
286 sc->sc_if.if_ierrors++;
287 return;
288 }
289 if (length + 2 > MHLEN) {
290 MCLGET(m, M_DONTWAIT);
291 if ((m->m_flags & M_EXT) == 0) {
292 m_free(m);
293 sc->sc_if.if_ierrors++;
294 return;
295 }
296 }
297 m->m_data += 2;
298 bcopy((caddr_t)&eh, m->m_data, sizeof(eh));
299 if (LEMAC_USE_PIO_MODE(sc)) {
300 LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh),
301 mtod(m, caddr_t) + sizeof(eh));
302 } else {
303 LEMAC_GETBUF16(sc, offset + sizeof(eh),
304 (length - sizeof(eh)) / 2,
305 (void *)(mtod(m, caddr_t) + sizeof(eh)));
306 if (length & 1)
307 m->m_data[length - 1] = LEMAC_GET8(sc,
308 offset + length - 1);
309 }
310 #if NBPFILTER > 0
311 if (sc->sc_if.if_bpf != NULL) {
312 m->m_pkthdr.len = m->m_len = length;
313 bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_IN);
314 }
315
316
317
318
319
320 if ((eh.ether_dhost[0] & 1) == 0 &&
321 !LEMAC_ADDREQUAL(eh.ether_dhost, sc->sc_arpcom.ac_enaddr)) {
322 m_freem(m);
323 return;
324 }
325 #endif
326 m->m_pkthdr.len = m->m_len = length;
327 m->m_pkthdr.rcvif = &sc->sc_if;
328 ether_input_mbuf(&sc->sc_if, m);
329 }
330
331 void
332 lemac_rne_intr(struct lemac_softc *sc)
333 {
334 int rxcount;
335
336 sc->sc_cntrs.cntr_rne_intrs++;
337 rxcount = LEMAC_INB(sc, LEMAC_REG_RQC);
338 while (rxcount--) {
339 unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ);
340 u_int32_t rxlen;
341
342 sc->sc_if.if_ipackets++;
343 if (LEMAC_USE_PIO_MODE(sc)) {
344 LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg);
345 LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
346 LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
347 LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen),
348 (void *)&rxlen);
349 } else {
350 LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg);
351 rxlen = LEMAC_GET32(sc, 0);
352 }
353 if (rxlen & LEMAC_RX_OK) {
354 sc->sc_flags |= LEMAC_LINKUP;
355
356
357
358 rxlen = ((rxlen >> 8) & 0x7FF) - 4;
359 lemac_input(sc, sizeof(rxlen), rxlen);
360 } else {
361 sc->sc_if.if_ierrors++;
362 }
363
364 LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg);
365 }
366
367 return;
368 }
369
370
371
372
373
374 int
375 lemac_read_macaddr(unsigned char *hwaddr, const bus_space_tag_t iot,
376 const bus_space_handle_t ioh, const bus_size_t ioreg, int skippat)
377 {
378 int cksum, rom_cksum;
379 unsigned char addrbuf[6];
380
381 if (!skippat) {
382 int idx, idx2, found, octet;
383 static u_char testpat[] = {
384 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA
385 };
386 idx2 = found = 0;
387
388 for (idx = 0; idx < 32; idx++) {
389 octet = bus_space_read_1(iot, ioh, ioreg);
390
391 if (octet == testpat[idx2]) {
392 if (++idx2 == sizeof(testpat)) {
393 ++found;
394 break;
395 }
396 } else {
397 idx2 = 0;
398 }
399 }
400
401 if (!found)
402 return (-1);
403 }
404
405 if (hwaddr == NULL)
406 hwaddr = addrbuf;
407
408 cksum = 0;
409 hwaddr[0] = bus_space_read_1(iot, ioh, ioreg);
410 hwaddr[1] = bus_space_read_1(iot, ioh, ioreg);
411
412
413 if (hwaddr[0] & 1)
414 return (-1);
415
416 #if BYTE_ORDER == LITTLE_ENDIAN
417 cksum = *(u_short *)&hwaddr[0];
418 #else
419 cksum = ((u_short)hwaddr[1] << 8) | (u_short)hwaddr[0];
420 #endif
421
422 hwaddr[2] = bus_space_read_1(iot, ioh, ioreg);
423 hwaddr[3] = bus_space_read_1(iot, ioh, ioreg);
424 cksum *= 2;
425 if (cksum > 65535)
426 cksum -= 65535;
427 #if BYTE_ORDER == LITTLE_ENDIAN
428 cksum += *(u_short *)&hwaddr[2];
429 #else
430 cksum += ((u_short)hwaddr[3] << 8) | (u_short)hwaddr[2];
431 #endif
432 if (cksum > 65535)
433 cksum -= 65535;
434
435 hwaddr[4] = bus_space_read_1(iot, ioh, ioreg);
436 hwaddr[5] = bus_space_read_1(iot, ioh, ioreg);
437 cksum *= 2;
438 if (cksum > 65535)
439 cksum -= 65535;
440 #if BYTE_ORDER == LITTLE_ENDIAN
441 cksum += *(u_short *)&hwaddr[4];
442 #else
443 cksum += ((u_short)hwaddr[5] << 8) | (u_short)hwaddr[4];
444 #endif
445 if (cksum >= 65535)
446 cksum -= 65535;
447
448
449 if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0)
450 return (-1);
451
452 rom_cksum = bus_space_read_1(iot, ioh, ioreg);
453 rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8;
454
455 if (cksum != rom_cksum)
456 return (-1);
457 return (0);
458 }
459
460 void
461 lemac_multicast_op(u_int16_t *mctbl, const u_char *mca, int enable)
462 {
463 u_int idx, bit, crc;
464
465 crc = ether_crc32_le(mca, ETHER_ADDR_LEN);
466
467
468
469
470
471 #if LEMAC_MCTBL_BITS < 0
472 crc >>= (32 + LEMAC_MCTBL_BITS);
473 crc &= (1 << -LEMAC_MCTBL_BITS) - 1;
474 #else
475 crc &= (1 << LEMAC_MCTBL_BITS) - 1;
476 #endif
477 bit = 1 << (crc & 0x0F);
478 idx = crc >> 4;
479
480
481
482
483 if (enable) {
484 mctbl[idx] |= bit;
485 } else {
486 mctbl[idx] &= ~bit;
487 }
488 }
489
490 void
491 lemac_multicast_filter(struct lemac_softc *sc)
492 {
493 #if 0
494 struct ether_multistep step;
495 struct ether_multi *enm;
496 #endif
497
498 bzero(sc->sc_mctbl, LEMAC_MCTBL_BITS / 8);
499
500 lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, 1);
501
502 #if 0
503 ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
504 while (enm != NULL) {
505 if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
506 sc->sc_flags |= LEMAC_ALLMULTI;
507 sc->sc_if.if_flags |= IFF_ALLMULTI;
508 return;
509 }
510 lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
511 ETHER_NEXT_MULTI(step, enm);
512 }
513 #endif
514 sc->sc_flags &= ~LEMAC_ALLMULTI;
515 sc->sc_if.if_flags &= ~IFF_ALLMULTI;
516 }
517
518
519
520
521 void
522 lemac_reset(struct lemac_softc *const sc)
523 {
524 unsigned data;
525
526
527
528
529 sc->sc_flags &= ~LEMAC_LINKUP;
530 sc->sc_if.if_flags &= ~IFF_OACTIVE;
531 LEMAC_INTR_DISABLE(sc);
532
533 LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
534 DELAY(LEMAC_EEP_DELAY);
535
536
537
538
539
540
541 if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
542 printf("%s: reset: EEPROM checksum failed (0x%x)\n",
543 sc->sc_if.if_xname, data);
544 return;
545 }
546
547
548
549
550 data = LEMAC_INB(sc, LEMAC_REG_CTL);
551 if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
552 data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
553 data |= sc->sc_ctlmode;
554 LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
555 }
556
557
558
559
560
561 data = LEMAC_INB(sc, LEMAC_REG_MBR);
562 if (LEMAC_IS_2K_MODE(data)) {
563 sc->sc_flags |= LEMAC_2K_MODE;
564 } else if (LEMAC_IS_64K_MODE(data)) {
565 data = (((data * 2) & 0xF) << 4);
566 sc->sc_flags |= LEMAC_WAS_64K_MODE;
567 LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
568 } else if (LEMAC_IS_32K_MODE(data)) {
569 data = ((data & 0xF) << 4);
570 sc->sc_flags |= LEMAC_WAS_32K_MODE;
571 LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
572 } else {
573 sc->sc_flags |= LEMAC_PIO_MODE;
574
575 }
576
577
578
579
580
581 lemac_init_adapmem(sc);
582 sc->sc_flags |= LEMAC_ALIVE;
583 }
584
585 void
586 lemac_init(struct lemac_softc *const sc)
587 {
588 if ((sc->sc_flags & LEMAC_ALIVE) == 0)
589 return;
590
591
592
593
594 if (sc->sc_if.if_flags & IFF_UP) {
595 int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS);
596 LEMAC_OUTB(sc, LEMAC_REG_CS,
597 saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
598 LEMAC_OUTB(sc, LEMAC_REG_PA0, sc->sc_arpcom.ac_enaddr[0]);
599 LEMAC_OUTB(sc, LEMAC_REG_PA1, sc->sc_arpcom.ac_enaddr[1]);
600 LEMAC_OUTB(sc, LEMAC_REG_PA2, sc->sc_arpcom.ac_enaddr[2]);
601 LEMAC_OUTB(sc, LEMAC_REG_PA3, sc->sc_arpcom.ac_enaddr[3]);
602 LEMAC_OUTB(sc, LEMAC_REG_PA4, sc->sc_arpcom.ac_enaddr[4]);
603 LEMAC_OUTB(sc, LEMAC_REG_PA5, sc->sc_arpcom.ac_enaddr[5]);
604
605 LEMAC_OUTB(sc, LEMAC_REG_IC,
606 LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
607
608 if (sc->sc_if.if_flags & IFF_PROMISC) {
609 LEMAC_OUTB(sc, LEMAC_REG_CS,
610 LEMAC_CS_MCE | LEMAC_CS_PME);
611 } else {
612 LEMAC_INTR_DISABLE(sc);
613 lemac_multicast_filter(sc);
614 if (sc->sc_flags & LEMAC_ALLMULTI)
615 bcopy(lemac_allmulti_mctbl, sc->sc_mctbl,
616 sizeof(sc->sc_mctbl));
617 if (LEMAC_USE_PIO_MODE(sc)) {
618 LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
619 LEMAC_OUTB(sc, LEMAC_REG_PI1,
620 LEMAC_MCTBL_OFF & 0xFF);
621 LEMAC_OUTB(sc, LEMAC_REG_PI2,
622 LEMAC_MCTBL_OFF >> 8);
623 LEMAC_OUTSB(sc, LEMAC_REG_DAT,
624 sizeof(sc->sc_mctbl),
625 (void *)sc->sc_mctbl);
626 } else {
627 LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
628 LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF,
629 sizeof(sc->sc_mctbl),
630 (void *)sc->sc_mctbl);
631 }
632
633 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
634 }
635
636 LEMAC_OUTB(sc, LEMAC_REG_CTL,
637 LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
638
639 LEMAC_INTR_ENABLE(sc);
640 sc->sc_if.if_flags |= IFF_RUNNING;
641 lemac_ifstart(&sc->sc_if);
642 } else {
643 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
644
645 LEMAC_INTR_DISABLE(sc);
646 sc->sc_if.if_flags &= ~IFF_RUNNING;
647 }
648 }
649
650 void
651 lemac_ifstart(struct ifnet *ifp)
652 {
653 struct lemac_softc *const sc = LEMAC_IFP_TO_SOFTC(ifp);
654
655 if ((ifp->if_flags & IFF_RUNNING) == 0)
656 return;
657
658 LEMAC_INTR_DISABLE(sc);
659
660 for (;;) {
661 struct mbuf *m;
662 struct mbuf *m0;
663 int tx_pg;
664
665 IFQ_POLL(&ifp->if_snd, m);
666 if (m == NULL)
667 break;
668
669 if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC)) >=
670 lemac_txmax) {
671 sc->sc_cntrs.cntr_txfull++;
672 ifp->if_flags |= IFF_OACTIVE;
673 break;
674 }
675
676
677
678
679 tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
680
681
682
683
684 if (tx_pg == 0 || tx_pg > sc->sc_lastpage) {
685 sc->sc_cntrs.cntr_txnospc++;
686 ifp->if_flags |= IFF_OACTIVE;
687 break;
688 }
689
690 IFQ_DEQUEUE(&ifp->if_snd, m);
691
692
693
694
695
696
697
698
699 if (LEMAC_USE_PIO_MODE(sc)) {
700
701 LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg);
702 LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
703 LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
704 LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl);
705 LEMAC_OUTB(sc, LEMAC_REG_DAT,
706 (m->m_pkthdr.len >> 0) & 0xFF);
707 LEMAC_OUTB(sc, LEMAC_REG_DAT,
708 (m->m_pkthdr.len >> 8) & 0xFF);
709 LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ);
710 for (m0 = m; m0 != NULL; m0 = m0->m_next)
711 LEMAC_OUTSB(sc, LEMAC_REG_DAT,
712 m0->m_len, m0->m_data);
713 } else {
714 bus_size_t txoff =
715 LEMAC_TX_HDRSZ;
716
717 LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg);
718 LEMAC_PUT8(sc, 0, sc->sc_txctl);
719 LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF);
720 LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF);
721 LEMAC_PUT8(sc, 3, txoff);
722
723
724
725
726 for (m0 = m; m0 != NULL; m0 = m0->m_next) {
727 #if 0
728 LEMAC_PUTBUF8(sc, txoff, m0->m_len,
729 m0->m_data);
730 txoff += m0->m_len;
731 #else
732 const u_int8_t *cp = m0->m_data;
733 int len = m0->m_len;
734 #if 0
735 if ((txoff & 3) == (((long)cp) & 3) &&
736 len >= 4) {
737 if (txoff & 3) {
738 int alen = (~txoff & 3);
739 LEMAC_PUTBUF8(sc, txoff, alen,
740 cp);
741 cp += alen;
742 txoff += alen;
743 len -= alen;
744 }
745 if (len >= 4) {
746 LEMAC_PUTBUF32(sc, txoff,
747 len / 4, cp);
748 cp += len & ~3;
749 txoff += len & ~3;
750 len &= 3;
751 }
752 }
753 #endif
754 if ((txoff & 1) == (((long)cp) & 1) &&
755 len >= 2) {
756 if (txoff & 1) {
757 int alen = (~txoff & 1);
758 LEMAC_PUTBUF8(sc, txoff, alen,
759 cp);
760 cp += alen;
761 txoff += alen;
762 len -= alen;
763 }
764 if (len >= 2) {
765 LEMAC_PUTBUF16(sc, txoff,
766 len / 2, (void *)cp);
767 cp += len & ~1;
768 txoff += len & ~1;
769 len &= 1;
770 }
771 }
772 if (len > 0) {
773 LEMAC_PUTBUF8(sc, txoff, len, cp);
774 txoff += len;
775 }
776 #endif
777 }
778 }
779
780
781 LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg);
782 #if NBPFILTER > 0
783 if (sc->sc_if.if_bpf != NULL)
784 bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT);
785 #endif
786 m_freem(m);
787 }
788 LEMAC_INTR_ENABLE(sc);
789 }
790
791 int
792 lemac_ifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
793 {
794 struct lemac_softc *const sc = LEMAC_IFP_TO_SOFTC(ifp);
795 int s;
796 int error = 0;
797 struct ifaddr *ifa = (struct ifaddr *)data;
798 struct ifreq *ifr = (struct ifreq *)data;
799
800 s = splnet();
801
802 if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
803 splx(s);
804 return (error);
805 }
806
807 switch (cmd) {
808 case SIOCSIFADDR:
809 ifp->if_flags |= IFF_UP;
810 lemac_init(sc);
811 switch (ifa->ifa_addr->sa_family) {
812 #ifdef INET
813 case AF_INET:
814 arp_ifinit(&sc->sc_arpcom, ifa);
815 break;
816 #endif
817
818 default:
819 break;
820 }
821 break;
822
823 case SIOCSIFFLAGS:
824 lemac_init(sc);
825 break;
826
827 case SIOCADDMULTI:
828 case SIOCDELMULTI:
829
830
831
832 error = (cmd == SIOCADDMULTI) ?
833 ether_addmulti(ifr, &sc->sc_arpcom) :
834 ether_delmulti(ifr, &sc->sc_arpcom);
835
836 if (error == ENETRESET) {
837
838 if (ifp->if_flags & IFF_RUNNING)
839 lemac_init(sc);
840 error = 0;
841 }
842 break;
843
844 case SIOCSIFMEDIA:
845 case SIOCGIFMEDIA:
846 error = ifmedia_ioctl(ifp, (struct ifreq *)data,
847 &sc->sc_ifmedia, cmd);
848 break;
849
850 case SIOCSIFMTU:
851 if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
852 error = EINVAL;
853 } else if (ifp->if_mtu != ifr->ifr_mtu) {
854 ifp->if_mtu = ifr->ifr_mtu;
855 }
856 break;
857
858 default:
859 error = EINVAL;
860 break;
861 }
862
863 splx(s);
864 return (error);
865 }
866
867 int
868 lemac_ifmedia_change(struct ifnet *const ifp)
869 {
870 struct lemac_softc *const sc = LEMAC_IFP_TO_SOFTC(ifp);
871 unsigned new_ctl;
872
873 switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
874 case IFM_10_T:
875 new_ctl = LEMAC_CTL_APD;
876 break;
877 case IFM_10_2:
878 case IFM_10_5:
879 new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL;
880 break;
881 case IFM_AUTO:
882 new_ctl = 0;
883 break;
884 default:
885 return (EINVAL);
886 }
887 if (sc->sc_ctlmode != new_ctl) {
888 sc->sc_ctlmode = new_ctl;
889 lemac_reset(sc);
890 if (sc->sc_if.if_flags & IFF_UP)
891 lemac_init(sc);
892 }
893 return (0);
894 }
895
896
897
898
899 void
900 lemac_ifmedia_status(struct ifnet *const ifp, struct ifmediareq *req)
901 {
902 struct lemac_softc *sc = LEMAC_IFP_TO_SOFTC(ifp);
903 unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF);
904
905 req->ifm_status = IFM_AVALID;
906 if (sc->sc_flags & LEMAC_LINKUP)
907 req->ifm_status |= IFM_ACTIVE;
908
909 if (sc->sc_ctlmode & LEMAC_CTL_APD) {
910 if (sc->sc_ctlmode & LEMAC_CTL_PSL) {
911 req->ifm_active = IFM_10_5;
912 } else {
913 req->ifm_active = IFM_10_T;
914 }
915 } else {
916
917
918
919
920 if (data & LEMAC_CNF_NOLINK) {
921 req->ifm_active = IFM_10_5;
922 } else {
923 req->ifm_active = IFM_10_T;
924 }
925 }
926
927 req->ifm_active |= IFM_ETHER;
928 }
929
930 int
931 lemac_port_check(const bus_space_tag_t iot, const bus_space_handle_t ioh)
932 {
933 unsigned char hwaddr[6];
934
935 if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0)
936 return (1);
937 if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0)
938 return (1);
939 return (0);
940 }
941
942 void
943 lemac_info_get(const bus_space_tag_t iot, const bus_space_handle_t ioh,
944 bus_addr_t *maddr_p, bus_size_t *msize_p, int *irq_p)
945 {
946 unsigned data;
947
948 *irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC) &
949 LEMAC_IC_IRQMSK);
950
951 data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR);
952 if (LEMAC_IS_2K_MODE(data)) {
953 *maddr_p = data * (2 * 1024) + (512 * 1024);
954 *msize_p = 2 * 1024;
955 } else if (LEMAC_IS_64K_MODE(data)) {
956 *maddr_p = data * 64 * 1024;
957 *msize_p = 64 * 1024;
958 } else if (LEMAC_IS_32K_MODE(data)) {
959 *maddr_p = data * 32 * 1024;
960 *msize_p = 32* 1024;
961 } else {
962 *maddr_p = 0;
963 *msize_p = 0;
964 }
965 }
966
967
968
969
970 int
971 lemac_intr(void *arg)
972 {
973 struct lemac_softc *const sc = arg;
974 int cs_value;
975
976 LEMAC_INTR_DISABLE(sc);
977
978
979
980
981
982
983 cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
984
985
986
987
988
989
990 if (cs_value & LEMAC_CS_RNE)
991 lemac_rne_intr(sc);
992 if (cs_value & LEMAC_CS_TNE)
993 lemac_tne_intr(sc);
994
995
996
997
998
999
1000 if (cs_value & LEMAC_CS_TXD)
1001 lemac_txd_intr(sc, cs_value);
1002 if (cs_value & LEMAC_CS_RXD)
1003 lemac_rxd_intr(sc, cs_value);
1004
1005
1006
1007
1008
1009 sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS);
1010
1011 LEMAC_OUTB(sc, LEMAC_REG_CTL,
1012 LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
1013 LEMAC_INTR_ENABLE(sc);
1014
1015 #if 0
1016 if (cs_value)
1017 rnd_add_uint32(&sc->rnd_source, cs_value);
1018 #endif
1019
1020 return (1);
1021 }
1022
1023 void
1024 lemac_shutdown(void *arg)
1025 {
1026 lemac_reset((struct lemac_softc *)arg);
1027 }
1028
1029 const char *const lemac_modes[4] = {
1030 "PIO mode (internal 2KB window)",
1031 "2KB window",
1032 "changed 32KB window to 2KB",
1033 "changed 64KB window to 2KB",
1034 };
1035
1036 void
1037 lemac_ifattach(struct lemac_softc *sc)
1038 {
1039 struct ifnet *const ifp = &sc->sc_if;
1040
1041 bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
1042
1043 lemac_reset(sc);
1044
1045 lemac_read_macaddr(sc->sc_arpcom.ac_enaddr, sc->sc_iot, sc->sc_ioh,
1046 LEMAC_REG_APD, 0);
1047
1048 printf(": %s\n", sc->sc_prodname);
1049
1050 printf("%s: address %s, %dKB RAM, %s\n", ifp->if_xname,
1051 ether_sprintf(sc->sc_arpcom.ac_enaddr), sc->sc_lastpage * 2 + 2,
1052 lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
1053
1054 ifp->if_softc = (void *)sc;
1055 ifp->if_start = lemac_ifstart;
1056 ifp->if_ioctl = lemac_ifioctl;
1057
1058 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX
1059 #ifdef IFF_NOTRAILERS
1060 | IFF_NOTRAILERS
1061 #endif
1062 | IFF_MULTICAST;
1063
1064 if (sc->sc_flags & LEMAC_ALIVE) {
1065 int media;
1066
1067 IFQ_SET_READY(&ifp->if_snd);
1068
1069 if_attach(ifp);
1070 ether_ifattach(ifp);
1071
1072 #if 0
1073 rnd_attach_source(&sc->rnd_source, sc->sc_dv.dv_xname,
1074 RND_TYPE_NET, 0);
1075 #endif
1076
1077 ifmedia_init(&sc->sc_ifmedia, 0, lemac_ifmedia_change,
1078 lemac_ifmedia_status);
1079 if (sc->sc_prodname[4] == '5')
1080 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0,
1081 0);
1082 if (sc->sc_prodname[4] != '3')
1083 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0,
1084 0);
1085 if (sc->sc_prodname[4] != '4')
1086 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0,
1087 0);
1088 switch (sc->sc_prodname[4]) {
1089 case '3':
1090 media = IFM_10_5;
1091 break;
1092 case '4':
1093 media = IFM_10_T;
1094 break;
1095 default:
1096 media = IFM_AUTO;
1097 break;
1098 }
1099 ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
1100 } else {
1101 printf("%s: disabled due to error\n", ifp->if_xname);
1102 }
1103 }