Annotation of sys/dev/ic/lemac.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: lemac.c,v 1.10 2006/04/16 16:32:08 miod Exp $ */
2: /* $NetBSD: lemac.c,v 1.20 2001/06/13 10:46:02 wiz Exp $ */
3:
4: /*-
5: * Copyright (c) 1994, 1995, 1997 Matt Thomas <matt@3am-software.com>
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. The name of the author may not be used to endorse or promote products
14: * derived from this software without specific prior written permission
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26: */
27:
28: /*
29: * DEC EtherWORKS 3 Ethernet Controllers
30: *
31: * Written by Matt Thomas
32: * BPF support code stolen directly from if_ec.c
33: *
34: * This driver supports the LEMAC DE203/204/205 cards.
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: * Some tuning/monitoring variables.
110: */
111: unsigned lemac_txmax = 16;
112:
113: void
114: lemac_rxd_intr(struct lemac_softc *sc, unsigned cs_value)
115: {
116: /*
117: * Handle CS_RXD (Receiver disabled) here.
118: *
119: * Check Free Memory Queue Count. If not equal to zero
120: * then just turn Receiver back on. If it is equal to
121: * zero then check to see if transmitter is disabled.
122: * Process transmit TXD loop once more. If all else
123: * fails then do software init (0xC0 to EEPROM Init)
124: * and rebuild Free Memory Queue.
125: */
126:
127: sc->sc_cntrs.cntr_rxd_intrs++;
128:
129: /*
130: * Re-enable Receiver.
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: * Error during initialization. Mark card as disabled.
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++; /* another one done */
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: * Read transmit status, remove transmit buffer from
189: * transmit queue and place on free memory queue,
190: * then reset transmitter.
191: * Increment appropriate counters.
192: */
193:
194: sc->sc_cntrs.cntr_txd_intrs++;
195: if (sc->sc_txctl & LEMAC_TX_STP) {
196: sc->sc_if.if_oerrors++;
197: /* return page to free queue */
198: LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ));
199: }
200:
201: /* Turn back on transmitter if disabled */
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: * Set up Transmit Control Byte for use later during transmit.
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: * If this is single cast but not to us
318: * drop it!
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: * Get receive length - subtract out checksum.
357: */
358: rxlen = ((rxlen >> 8) & 0x7FF) - 4;
359: lemac_input(sc, sizeof(rxlen), rxlen);
360: } else {
361: sc->sc_if.if_ierrors++;
362: }
363: /* Return this page to Free Memory Queue */
364: LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg);
365: } /* end while (recv_count--) */
366:
367: return;
368: }
369:
370: /*
371: * This is the standard method of reading the DEC Address ROMS.
372: * I don't understand it but it does work.
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: /* hardware address can't be multicast */
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: /* 00-00-00 is an illegal OUI */
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: * The following two lines convert the N bit index into a
469: * longword index and a longword mask.
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: * Set or clear hash filter bit in our table.
482: */
483: if (enable) {
484: mctbl[idx] |= bit; /* Set Bit */
485: } else {
486: mctbl[idx] &= ~bit; /* Clear 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: * Do a hard reset of the board;
520: */
521: void
522: lemac_reset(struct lemac_softc *const sc)
523: {
524: unsigned data;
525:
526: /*
527: * Initialize board..
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: * Read EEPROM information. NOTE - the placement of this function
538: * is important because functions hereafter may rely on information
539: * read from the EEPROM.
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: * Update the control register to reflect the media choice
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: * Force to 2K mode if not already configured.
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: /* PIO mode */
575: }
576:
577: /*
578: * Initialize Free Memory Queue, Init mcast table with broadcast.
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: * If the interface has the up flag
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: * get free memory page
678: */
679: tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
680:
681: /*
682: * Check for good transmit page.
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: * The first four bytes of each transmit buffer are for
694: * control information. The first byte is the control
695: * byte, then the length (why not word aligned?), then
696: * the offset to the buffer.
697: */
698:
699: if (LEMAC_USE_PIO_MODE(sc)) {
700: /* Shift 2K window. */
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 = /* (mtod(m, u_int32_t) &
715: (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ;
716: /* Shift 2K window. */
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: * Copy the packet to the board
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: /* tell chip to transmit this packet */
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); /* free the mbuf */
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 /* INET */
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: * Update multicast listeners
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: /* Reset multicast filtering. */
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: * Media status callback
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: * The link bit of the configuration register reflects the
918: * current media choice when auto-port is enabled.
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: * What to do upon receipt of an interrupt.
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); /* Mask interrupts */
977:
978: /*
979: * Determine cause of interrupt. Receive events take
980: * priority over Transmit.
981: */
982:
983: cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
984:
985: /*
986: * Check for Receive Queue not being empty.
987: * Check for Transmit Done Queue not being empty.
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: * Check for Transmitter Disabled.
997: * Check for Receiver Disabled.
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: * Toggle LED and unmask interrupts.
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); /* Unmask interrupts */
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') /* DE205 is UTP/AUI */
1080: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0,
1081: 0);
1082: if (sc->sc_prodname[4] != '3') /* DE204 & 205 have UTP */
1083: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0,
1084: 0);
1085: if (sc->sc_prodname[4] != '4') /* DE203 & 205 have BNC */
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: }
CVSweb