Annotation of sys/dev/ic/lemac.c, Revision 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