Annotation of sys/dev/isa/if_ef_isapnp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_ef_isapnp.c,v 1.21 2006/03/25 22:41:44 djm Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
! 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. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 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
! 18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 25: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 26: * POSSIBILITY OF SUCH DAMAGE.
! 27: */
! 28:
! 29: #include "bpfilter.h"
! 30:
! 31: #include <sys/param.h>
! 32: #include <sys/systm.h>
! 33: #include <sys/mbuf.h>
! 34: #include <sys/socket.h>
! 35: #include <sys/ioctl.h>
! 36: #include <sys/errno.h>
! 37: #include <sys/syslog.h>
! 38: #include <sys/selinfo.h>
! 39: #include <sys/device.h>
! 40: #include <sys/queue.h>
! 41: #include <sys/kernel.h>
! 42: #include <sys/timeout.h>
! 43:
! 44: #include <net/if.h>
! 45: #include <net/if_dl.h>
! 46: #include <net/if_types.h>
! 47: #include <net/netisr.h>
! 48: #include <net/if_media.h>
! 49:
! 50: #ifdef INET
! 51: #include <netinet/in.h>
! 52: #include <netinet/in_systm.h>
! 53: #include <netinet/in_var.h>
! 54: #include <netinet/ip.h>
! 55: #include <netinet/if_ether.h>
! 56: #endif
! 57:
! 58: #if NBPFILTER > 0
! 59: #include <net/bpf.h>
! 60: #endif
! 61:
! 62: #include <machine/cpu.h>
! 63: #include <machine/bus.h>
! 64: #include <machine/intr.h>
! 65:
! 66: #include <dev/mii/mii.h>
! 67: #include <dev/mii/miivar.h>
! 68: #include <dev/isa/isavar.h>
! 69: #include <dev/isa/isadmavar.h>
! 70: #include <dev/ic/elink3reg.h>
! 71:
! 72: #undef EF_DEBUG
! 73:
! 74: struct ef_softc {
! 75: struct device sc_dv;
! 76: bus_space_tag_t sc_iot;
! 77: bus_space_handle_t sc_ioh;
! 78: struct arpcom sc_arpcom;
! 79: struct mii_data sc_mii;
! 80: struct timeout sc_tick_tmo;
! 81: void * sc_ih;
! 82: int sc_tx_start_thresh;
! 83: int sc_tx_succ_ok;
! 84: int sc_busmaster;
! 85: };
! 86:
! 87: #define EF_W0_EEPROM_COMMAND 0x200a
! 88: #define EF_EEPROM_BUSY (1 << 9)
! 89: #define EF_EEPROM_READ (1 << 7)
! 90: #define EF_W0_EEPROM_DATA 0x200c
! 91:
! 92: #define EF_W1_TX_PIO_WR_1 0x10
! 93: #define EF_W1_RX_PIO_RR_1 0x10
! 94: #define EF_W1_RX_ERRORS 0x14
! 95: #define EF_W1_RX_STATUS 0x18
! 96: #define EF_W1_TX_STATUS 0x1b
! 97: #define EF_W1_FREE_TX 0x1c
! 98:
! 99: #define EF_W4_MEDIA 0x0a
! 100: #define EF_MEDIA_SQE 0x0008 /* sqe error for aui */
! 101: #define EF_MEDIA_TP 0x00c0 /* link/jabber, 10baseT */
! 102: #define EF_MEDIA_LNK 0x0080 /* linkbeat, 100baseTX/FX */
! 103: #define EF_MEDIA_LNKBEAT 0x0800
! 104:
! 105: /* Window 4: EP_W4_CTRLR_STATUS: mii manipulation */
! 106: #define EF_MII_CLK 0x01 /* clock bit */
! 107: #define EF_MII_DATA 0x02 /* data bit */
! 108: #define EF_MII_DIR 0x04 /* direction */
! 109:
! 110: int ef_isapnp_match(struct device *, void *, void *);
! 111: void ef_isapnp_attach(struct device *, struct device *, void *);
! 112:
! 113: void efstart(struct ifnet *);
! 114: int efioctl(struct ifnet *, u_long, caddr_t);
! 115: void efwatchdog(struct ifnet *);
! 116: void efreset(struct ef_softc *);
! 117: void efstop(struct ef_softc *);
! 118: void efsetmulti(struct ef_softc *);
! 119: int efbusyeeprom(struct ef_softc *);
! 120: int efintr(void *);
! 121: void efinit(struct ef_softc *);
! 122: void efcompletecmd(struct ef_softc *, u_int, u_int);
! 123: void eftxstat(struct ef_softc *);
! 124: void efread(struct ef_softc *);
! 125: struct mbuf *efget(struct ef_softc *, int totlen);
! 126:
! 127: void ef_miibus_writereg(struct device *, int, int, int);
! 128: void ef_miibus_statchg(struct device *);
! 129: int ef_miibus_readreg(struct device *, int, int);
! 130: void ef_mii_writeb(struct ef_softc *, int);
! 131: void ef_mii_sync(struct ef_softc *);
! 132: int ef_ifmedia_upd(struct ifnet *);
! 133: void ef_ifmedia_sts(struct ifnet *, struct ifmediareq *);
! 134: void ef_tick(void *);
! 135:
! 136: struct cfdriver ef_cd = {
! 137: NULL, "ef", DV_IFNET
! 138: };
! 139:
! 140: struct cfattach ef_isapnp_ca = {
! 141: sizeof(struct ef_softc), ef_isapnp_match, ef_isapnp_attach
! 142: };
! 143:
! 144: int
! 145: ef_isapnp_match(parent, match, aux)
! 146: struct device *parent;
! 147: void *match, *aux;
! 148: {
! 149: return (1);
! 150: }
! 151:
! 152: void
! 153: ef_isapnp_attach(parent, self, aux)
! 154: struct device *parent, *self;
! 155: void *aux;
! 156: {
! 157: struct ef_softc *sc = (void *)self;
! 158: struct isa_attach_args *ia = aux;
! 159: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 160: bus_space_tag_t iot;
! 161: bus_space_handle_t ioh;
! 162: int i;
! 163: u_int16_t x;
! 164: u_int32_t cfg;
! 165:
! 166: sc->sc_iot = iot = ia->ia_iot;
! 167: sc->sc_ioh = ioh = ia->ipa_io[0].h;
! 168:
! 169: efcompletecmd(sc, EP_COMMAND, GLOBAL_RESET);
! 170: DELAY(1500);
! 171:
! 172: for (i = 0; i < 3; i++) {
! 173: if (efbusyeeprom(sc))
! 174: return;
! 175:
! 176: bus_space_write_2(iot, ioh, EF_W0_EEPROM_COMMAND,
! 177: EF_EEPROM_READ | i);
! 178:
! 179: if (efbusyeeprom(sc))
! 180: return;
! 181:
! 182: x = bus_space_read_2(iot, ioh, EF_W0_EEPROM_DATA);
! 183:
! 184: sc->sc_arpcom.ac_enaddr[(i << 1)] = x >> 8;
! 185: sc->sc_arpcom.ac_enaddr[(i << 1) + 1] = x;
! 186: }
! 187:
! 188: printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
! 189:
! 190: GO_WINDOW(3);
! 191: cfg = bus_space_read_4(iot, ioh, EP_W3_INTERNAL_CONFIG);
! 192: cfg &= ~(0x00f00000);
! 193: cfg |= (0x06 << 20);
! 194: bus_space_write_4(iot, ioh, EP_W3_INTERNAL_CONFIG, cfg);
! 195:
! 196: sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
! 197: IPL_NET, efintr, sc, sc->sc_dv.dv_xname);
! 198:
! 199: if (ia->ia_drq != DRQUNK)
! 200: isadma_cascade(ia->ia_drq);
! 201:
! 202: timeout_set(&sc->sc_tick_tmo, ef_tick, sc);
! 203:
! 204: bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
! 205: ifp->if_softc = sc;
! 206: ifp->if_start = efstart;
! 207: ifp->if_ioctl = efioctl;
! 208: ifp->if_watchdog = efwatchdog;
! 209: ifp->if_flags =
! 210: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
! 211: IFQ_SET_READY(&ifp->if_snd);
! 212:
! 213: sc->sc_mii.mii_ifp = ifp;
! 214: sc->sc_mii.mii_readreg = ef_miibus_readreg;
! 215: sc->sc_mii.mii_writereg = ef_miibus_writereg;
! 216: sc->sc_mii.mii_statchg = ef_miibus_statchg;
! 217: ifmedia_init(&sc->sc_mii.mii_media, 0, ef_ifmedia_upd, ef_ifmedia_sts);
! 218: mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
! 219: 0);
! 220: if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
! 221: ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
! 222: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
! 223: } else
! 224: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
! 225:
! 226: if_attach(ifp);
! 227: ether_ifattach(ifp);
! 228:
! 229: sc->sc_tx_start_thresh = 20;
! 230:
! 231: efcompletecmd(sc, EP_COMMAND, RX_RESET);
! 232: efcompletecmd(sc, EP_COMMAND, TX_RESET);
! 233: }
! 234:
! 235: void
! 236: efstart(ifp)
! 237: struct ifnet *ifp;
! 238: {
! 239: struct ef_softc *sc = ifp->if_softc;
! 240: bus_space_tag_t iot = sc->sc_iot;
! 241: bus_space_handle_t ioh = sc->sc_ioh;
! 242: struct mbuf *m, *m0;
! 243: int s, len, pad, i;
! 244: int fillcnt = 0;
! 245: u_int32_t filler = 0;
! 246:
! 247: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 248: return;
! 249:
! 250: startagain:
! 251: IFQ_POLL(&ifp->if_snd, m0);
! 252: if (m0 == NULL)
! 253: return;
! 254:
! 255: if ((m0->m_flags & M_PKTHDR) == 0)
! 256: panic("efstart: no header mbuf");
! 257: len = m0->m_pkthdr.len;
! 258: pad = (4 - len) & 3;
! 259:
! 260: if (len + pad > ETHER_MAX_LEN) {
! 261: ifp->if_oerrors++;
! 262: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 263: m_freem(m0);
! 264: goto startagain;
! 265: }
! 266:
! 267: if (bus_space_read_2(iot, ioh, EF_W1_FREE_TX) < len + pad + 4) {
! 268: bus_space_write_2(iot, ioh, EP_COMMAND,
! 269: SET_TX_AVAIL_THRESH | ((len + pad) >> 2));
! 270: ifp->if_flags |= IFF_OACTIVE;
! 271: return;
! 272: } else {
! 273: bus_space_write_2(iot, ioh, EP_COMMAND,
! 274: SET_TX_AVAIL_THRESH | EP_THRESH_DISABLE);
! 275: }
! 276:
! 277: bus_space_write_2(iot, ioh, EP_COMMAND, SET_TX_START_THRESH |
! 278: ((len / 4 + sc->sc_tx_start_thresh)));
! 279:
! 280: #if NBPFILTER
! 281: if (ifp->if_bpf)
! 282: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 283: #endif
! 284:
! 285: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 286: if (m0 == NULL) /* XXX not needed */
! 287: return;
! 288:
! 289: s = splhigh();
! 290:
! 291: bus_space_write_4(iot, ioh, EF_W1_TX_PIO_WR_1, len);
! 292: for (m = m0; m; ) {
! 293: if (fillcnt) {
! 294: while (m->m_len && fillcnt < 4) {
! 295: fillcnt++;
! 296: filler >>= 8;
! 297: filler |= m->m_data[0] << 24;
! 298: m->m_data++;
! 299: m->m_len--;
! 300: }
! 301: if (fillcnt == 4) {
! 302: bus_space_write_4(iot, ioh,
! 303: EF_W1_TX_PIO_WR_1, filler);
! 304: filler = 0;
! 305: fillcnt = 0;
! 306: }
! 307: }
! 308:
! 309: if (m->m_len & ~3)
! 310: bus_space_write_multi_4(iot, ioh,
! 311: EF_W1_TX_PIO_WR_1, (u_int32_t *)m->m_data,
! 312: m->m_len >> 2);
! 313: for (i = 0; i < (m->m_len & 3); i++) {
! 314: fillcnt++;
! 315: filler >>= 8;
! 316: filler |= m->m_data[(m->m_len & ~3) + i] << 24;
! 317: }
! 318: MFREE(m, m0);
! 319: m = m0;
! 320: }
! 321:
! 322: if (fillcnt) {
! 323: bus_space_write_4(iot, ioh, EF_W1_TX_PIO_WR_1,
! 324: filler >> (32 - (8 * fillcnt)));
! 325: fillcnt = 0;
! 326: filler = 0;
! 327: }
! 328:
! 329: splx(s);
! 330:
! 331: ifp->if_opackets++;
! 332:
! 333: goto startagain;
! 334: }
! 335:
! 336: int
! 337: efioctl(ifp, cmd, data)
! 338: struct ifnet *ifp;
! 339: u_long cmd;
! 340: caddr_t data;
! 341: {
! 342: struct ef_softc *sc = ifp->if_softc;
! 343: struct ifaddr *ifa = (struct ifaddr *)data;
! 344: struct ifreq *ifr = (struct ifreq *)data;
! 345: int s, error = 0;
! 346:
! 347: s = splnet();
! 348:
! 349: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 350: splx(s);
! 351: return (error);
! 352: }
! 353:
! 354: switch (cmd) {
! 355: case SIOCSIFADDR:
! 356: ifp->if_flags |= IFF_UP;
! 357: switch (ifa->ifa_addr->sa_family) {
! 358: #ifdef INET
! 359: case AF_INET:
! 360: efinit(sc);
! 361: arp_ifinit(&sc->sc_arpcom, ifa);
! 362: break;
! 363: #endif
! 364: default:
! 365: efinit(sc);
! 366: break;
! 367: }
! 368: break;
! 369: case SIOCSIFMEDIA:
! 370: case SIOCGIFMEDIA:
! 371: error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
! 372: break;
! 373: case SIOCSIFFLAGS:
! 374: if ((ifp->if_flags & IFF_UP) == 0 &&
! 375: (ifp->if_flags & IFF_RUNNING) != 0) {
! 376: efstop(sc);
! 377: ifp->if_flags &= ~IFF_RUNNING;
! 378: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 379: (ifp->if_flags & IFF_RUNNING) == 0) {
! 380: efinit(sc);
! 381: }
! 382: efsetmulti(sc);
! 383: break;
! 384:
! 385: case SIOCADDMULTI:
! 386: case SIOCDELMULTI:
! 387: error = (cmd == SIOCADDMULTI) ?
! 388: ether_addmulti(ifr, &sc->sc_arpcom) :
! 389: ether_delmulti(ifr, &sc->sc_arpcom);
! 390:
! 391: if (error == ENETRESET) {
! 392: if (ifp->if_flags & IFF_RUNNING)
! 393: efreset(sc);
! 394: error = 0;
! 395: }
! 396: efsetmulti(sc);
! 397: break;
! 398: default:
! 399: error = EINVAL;
! 400: break;
! 401: }
! 402:
! 403: splx(s);
! 404: return (error);
! 405: }
! 406:
! 407: void
! 408: efinit(sc)
! 409: struct ef_softc *sc;
! 410: {
! 411: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 412: bus_space_tag_t iot = sc->sc_iot;
! 413: bus_space_handle_t ioh = sc->sc_ioh;
! 414: int i, s;
! 415:
! 416: s = splnet();
! 417:
! 418: efstop(sc);
! 419:
! 420: while (bus_space_read_2(iot, ioh, EP_STATUS) & S_COMMAND_IN_PROGRESS)
! 421: ;
! 422:
! 423: GO_WINDOW(2);
! 424: for (i = 0; i < 6; i++)
! 425: bus_space_write_1(iot, ioh, EP_W2_ADDR_0 + i,
! 426: sc->sc_arpcom.ac_enaddr[i]);
! 427: for (i = 0; i < 3; i += 2)
! 428: bus_space_write_2(iot, ioh, EP_W2_RECVMASK_0 + (i * 2), 0);
! 429:
! 430: efcompletecmd(sc, EP_COMMAND, RX_RESET);
! 431: efcompletecmd(sc, EP_COMMAND, TX_RESET);
! 432:
! 433: bus_space_write_2(iot, ioh, EP_COMMAND,
! 434: SET_TX_AVAIL_THRESH | (ETHER_MAX_DIX_LEN >> 2));
! 435:
! 436: efsetmulti(sc);
! 437:
! 438: bus_space_write_2(iot, ioh, EP_COMMAND, STATUS_ENABLE | 0);
! 439:
! 440: GO_WINDOW(6);
! 441: for (i = 0; i < 10; i++)
! 442: (void)bus_space_read_1(iot, ioh, i);
! 443: (void)bus_space_read_2(iot, ioh, 10);
! 444: (void)bus_space_read_2(iot, ioh, 12);
! 445: GO_WINDOW(4);
! 446: (void)bus_space_read_1(iot, ioh, 12);
! 447: bus_space_write_2(iot, ioh, EP_W4_NET_DIAG, 0x0040);
! 448:
! 449: GO_WINDOW(7);
! 450:
! 451: efsetmulti(sc);
! 452:
! 453: bus_space_write_2(iot, ioh, EP_COMMAND, RX_ENABLE);
! 454: bus_space_write_2(iot, ioh, EP_COMMAND, TX_ENABLE);
! 455:
! 456: bus_space_write_2(iot, ioh, EP_COMMAND, STATUS_ENABLE |
! 457: S_CARD_FAILURE | S_INT_RQD | S_UPD_STATS | S_TX_COMPLETE |
! 458: S_TX_AVAIL | S_RX_COMPLETE |
! 459: (sc->sc_busmaster ? S_DMA_DONE : 0));
! 460: bus_space_write_2(iot, ioh, EP_COMMAND, ACK_INTR |
! 461: S_INTR_LATCH | S_TX_AVAIL | S_RX_EARLY | S_INT_RQD);
! 462: bus_space_write_2(iot, ioh, EP_COMMAND, SET_INTR_MASK |
! 463: S_INTR_LATCH | S_TX_AVAIL | S_RX_COMPLETE | S_UPD_STATS |
! 464: (sc->sc_busmaster ? S_DMA_DONE : 0) | S_UP_COMPLETE |
! 465: S_DOWN_COMPLETE | S_CARD_FAILURE | S_TX_COMPLETE);
! 466:
! 467: mii_mediachg(&sc->sc_mii);
! 468:
! 469: ifp->if_flags |= IFF_RUNNING;
! 470: ifp->if_flags &= ~IFF_OACTIVE;
! 471:
! 472: splx(s);
! 473:
! 474: timeout_add(&sc->sc_tick_tmo, hz);
! 475:
! 476: efstart(ifp);
! 477: }
! 478:
! 479: void
! 480: efreset(sc)
! 481: struct ef_softc *sc;
! 482: {
! 483: int s;
! 484:
! 485: s = splnet();
! 486: efstop(sc);
! 487: efinit(sc);
! 488: splx(s);
! 489: }
! 490:
! 491: void
! 492: efstop(sc)
! 493: struct ef_softc *sc;
! 494: {
! 495: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 496: bus_space_tag_t iot = sc->sc_iot;
! 497: bus_space_handle_t ioh = sc->sc_ioh;
! 498:
! 499: ifp->if_timer = 0;
! 500: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 501:
! 502: timeout_del(&sc->sc_tick_tmo);
! 503:
! 504: bus_space_write_2(iot, ioh, EP_COMMAND, RX_DISABLE);
! 505: efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
! 506:
! 507: bus_space_write_2(iot, ioh, EP_COMMAND, TX_DISABLE);
! 508: bus_space_write_2(iot, ioh, EP_COMMAND, STOP_TRANSCEIVER);
! 509:
! 510: efcompletecmd(sc, EP_COMMAND, RX_RESET);
! 511: efcompletecmd(sc, EP_COMMAND, TX_RESET);
! 512:
! 513: bus_space_write_2(iot, ioh, EP_COMMAND, C_INTR_LATCH);
! 514: bus_space_write_2(iot, ioh, EP_COMMAND, SET_RD_0_MASK);
! 515: bus_space_write_2(iot, ioh, EP_COMMAND, SET_INTR_MASK);
! 516: bus_space_write_2(iot, ioh, EP_COMMAND, SET_RX_FILTER);
! 517: }
! 518:
! 519: void
! 520: efcompletecmd(sc, cmd, arg)
! 521: struct ef_softc *sc;
! 522: u_int cmd, arg;
! 523: {
! 524: bus_space_tag_t iot = sc->sc_iot;
! 525: bus_space_handle_t ioh = sc->sc_ioh;
! 526:
! 527: bus_space_write_2(iot, ioh, cmd, arg);
! 528: while (bus_space_read_2(iot, ioh, EP_STATUS) & S_COMMAND_IN_PROGRESS)
! 529: ;
! 530: }
! 531:
! 532: int
! 533: efintr(vsc)
! 534: void *vsc;
! 535: {
! 536: struct ef_softc *sc = vsc;
! 537: bus_space_tag_t iot = sc->sc_iot;
! 538: bus_space_handle_t ioh = sc->sc_ioh;
! 539: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 540: u_int16_t status;
! 541: int r = 0;
! 542:
! 543: status = bus_space_read_2(iot, ioh, EP_STATUS);
! 544:
! 545: do {
! 546: if (status & S_RX_COMPLETE) {
! 547: r = 1;
! 548: bus_space_write_2(iot, ioh, EP_STATUS, C_RX_COMPLETE);
! 549: efread(sc);
! 550: }
! 551: if (status & S_TX_AVAIL) {
! 552: bus_space_write_2(iot, ioh, EP_STATUS, C_TX_AVAIL);
! 553: r = 1;
! 554: sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
! 555: efstart(&sc->sc_arpcom.ac_if);
! 556: }
! 557: if (status & S_CARD_FAILURE) {
! 558: r = 1;
! 559: efreset(sc);
! 560: printf("%s: adapter failure (%x)\n",
! 561: sc->sc_dv.dv_xname, status);
! 562: bus_space_write_2(iot, ioh, EP_COMMAND,
! 563: C_CARD_FAILURE);
! 564: return (1);
! 565: }
! 566: if (status & S_TX_COMPLETE) {
! 567: r = 1;
! 568: eftxstat(sc);
! 569: efstart(ifp);
! 570: }
! 571: bus_space_write_2(iot, ioh, EP_COMMAND,
! 572: C_INTR_LATCH | C_INT_RQD);
! 573: } while ((status = bus_space_read_2(iot, ioh, EP_STATUS)) &
! 574: (S_INT_RQD | S_RX_COMPLETE));
! 575:
! 576: return (r);
! 577: }
! 578:
! 579: void
! 580: eftxstat(sc)
! 581: struct ef_softc *sc;
! 582: {
! 583: bus_space_tag_t iot = sc->sc_iot;
! 584: bus_space_handle_t ioh = sc->sc_ioh;
! 585: int i;
! 586:
! 587: while ((i = bus_space_read_1(iot, ioh, EF_W1_TX_STATUS)) &
! 588: TXS_COMPLETE) {
! 589: bus_space_write_1(iot, ioh, EF_W1_TX_STATUS, 0);
! 590:
! 591: if (i & TXS_JABBER) {
! 592: sc->sc_arpcom.ac_if.if_oerrors++;
! 593: #ifdef EF_DEBUG
! 594: if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
! 595: printf("%s: jabber (%x)\n",
! 596: sc->sc_dv.dv_xname, i);
! 597: #endif
! 598: efreset(sc);
! 599: }
! 600: else if (i & TXS_UNDERRUN) {
! 601: sc->sc_arpcom.ac_if.if_oerrors++;
! 602: #ifdef EF_DEBUG
! 603: if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
! 604: printf("%s: fifo underrun (%x) @%d\n",
! 605: sc->sc_dv.dv_xname, i,
! 606: sc->sc_tx_start_thresh);
! 607: #endif
! 608: if (sc->sc_tx_succ_ok < 100)
! 609: sc->sc_tx_start_thresh = min(ETHER_MAX_LEN,
! 610: sc->sc_tx_start_thresh + 20);
! 611: sc->sc_tx_succ_ok = 0;
! 612: efreset(sc);
! 613: }
! 614: else if (i & TXS_MAX_COLLISION) {
! 615: sc->sc_arpcom.ac_if.if_collisions++;
! 616: bus_space_write_2(iot, ioh, EP_COMMAND, TX_ENABLE);
! 617: sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
! 618: }
! 619: else
! 620: sc->sc_tx_succ_ok = (sc->sc_tx_succ_ok + 1) & 127;
! 621: }
! 622: }
! 623:
! 624: int
! 625: efbusyeeprom(sc)
! 626: struct ef_softc *sc;
! 627: {
! 628: int i = 100, j;
! 629:
! 630: while (i--) {
! 631: j = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
! 632: EF_W0_EEPROM_COMMAND);
! 633: if (j & EF_EEPROM_BUSY)
! 634: delay(100);
! 635: else
! 636: break;
! 637: }
! 638: if (i == 0) {
! 639: printf("%s: eeprom failed to come ready\n",
! 640: sc->sc_dv.dv_xname);
! 641: return (1);
! 642: }
! 643:
! 644: return (0);
! 645: }
! 646:
! 647: void
! 648: efwatchdog(ifp)
! 649: struct ifnet *ifp;
! 650: {
! 651: struct ef_softc *sc = ifp->if_softc;
! 652:
! 653: printf("%s: device timeout\n", sc->sc_dv.dv_xname);
! 654: sc->sc_arpcom.ac_if.if_oerrors++;
! 655: efreset(sc);
! 656: }
! 657:
! 658: void
! 659: efsetmulti(sc)
! 660: struct ef_softc *sc;
! 661: {
! 662: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 663: struct arpcom *ac = &sc->sc_arpcom;
! 664: bus_space_tag_t iot = sc->sc_iot;
! 665: bus_space_handle_t ioh = sc->sc_ioh;
! 666: struct ether_multi *enm;
! 667: struct ether_multistep step;
! 668: u_int16_t cmd = SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST;
! 669: int mcnt = 0;
! 670:
! 671: ETHER_FIRST_MULTI(step, ac, enm);
! 672: while (enm != NULL) {
! 673: mcnt++;
! 674: ETHER_NEXT_MULTI(step, enm);
! 675: }
! 676: if (mcnt || ifp->if_flags & IFF_ALLMULTI)
! 677: cmd |= FIL_MULTICAST;
! 678:
! 679: if (ifp->if_flags & IFF_PROMISC)
! 680: cmd |= FIL_PROMISC;
! 681:
! 682: bus_space_write_2(iot, ioh, EP_COMMAND, cmd);
! 683: }
! 684:
! 685: void
! 686: efread(sc)
! 687: struct ef_softc *sc;
! 688: {
! 689: bus_space_tag_t iot = sc->sc_iot;
! 690: bus_space_handle_t ioh = sc->sc_ioh;
! 691: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 692: struct mbuf *m;
! 693: int len;
! 694:
! 695: len = bus_space_read_2(iot, ioh, EF_W1_RX_STATUS);
! 696:
! 697: #ifdef EF_DEBUG
! 698: if (ifp->if_flags & IFF_DEBUG) {
! 699: int err = len & ERR_MASK;
! 700: char *s = NULL;
! 701:
! 702: if (len & ERR_INCOMPLETE)
! 703: s = "incomplete packet";
! 704: else if (err == ERR_OVERRUN)
! 705: s = "packet overrun";
! 706: else if (err == ERR_RUNT)
! 707: s = "runt packet";
! 708: else if (err == ERR_ALIGNMENT)
! 709: s = "bad alignment";
! 710: else if (err == ERR_CRC)
! 711: s = "bad crc";
! 712: else if (err == ERR_OVERSIZE)
! 713: s = "oversized packet";
! 714: else if (err == ERR_DRIBBLE)
! 715: s = "dribble bits";
! 716:
! 717: if (s)
! 718: printf("%s: %s\n", sc->sc_dv.dv_xname, s);
! 719: }
! 720: #endif
! 721:
! 722: if (len & ERR_INCOMPLETE)
! 723: return;
! 724:
! 725: if (len & ERR_RX) {
! 726: ifp->if_ierrors++;
! 727: efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
! 728: return;
! 729: }
! 730:
! 731: len &= RX_BYTES_MASK;
! 732: m = efget(sc, len);
! 733: if (m == NULL) {
! 734: ifp->if_ierrors++;
! 735: efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
! 736: return;
! 737: }
! 738:
! 739: ifp->if_ipackets++;
! 740:
! 741: #if NBPFILTER > 0
! 742: if (ifp->if_bpf)
! 743: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 744: #endif
! 745:
! 746: ether_input_mbuf(ifp, m);
! 747: }
! 748:
! 749: struct mbuf *
! 750: efget(sc, totlen)
! 751: struct ef_softc *sc;
! 752: int totlen;
! 753: {
! 754: bus_space_tag_t iot = sc->sc_iot;
! 755: bus_space_handle_t ioh = sc->sc_ioh;
! 756: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 757: struct mbuf *top, **mp, *m;
! 758: int len, pad, s;
! 759:
! 760: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 761: if (m == NULL)
! 762: return (NULL);
! 763: m->m_pkthdr.rcvif = ifp;
! 764: m->m_pkthdr.len = totlen;
! 765: pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
! 766: m->m_data += pad;
! 767: len = MHLEN -pad;
! 768: top = 0;
! 769: mp = ⊤
! 770:
! 771: s = splhigh();
! 772:
! 773: while (totlen > 0) {
! 774: if (top) {
! 775: MGET(m, M_DONTWAIT, MT_DATA);
! 776: if (m == NULL) {
! 777: m_freem(top);
! 778: splx(s);
! 779: return (NULL);
! 780: }
! 781: len = MLEN;
! 782: }
! 783: if (top && totlen >= MINCLSIZE) {
! 784: MCLGET(m, M_DONTWAIT);
! 785: if (m->m_flags & M_EXT)
! 786: len = MCLBYTES;
! 787: }
! 788: len = min(totlen, len);
! 789: if (len > 1) {
! 790: len &= ~1;
! 791: bus_space_read_raw_multi_2(iot, ioh,
! 792: EF_W1_RX_PIO_RR_1, mtod(m, u_int8_t *),
! 793: len);
! 794: } else
! 795: *(mtod(m, u_int8_t *)) =
! 796: bus_space_read_1(iot, ioh, EF_W1_RX_PIO_RR_1);
! 797:
! 798: m->m_len = len;
! 799: totlen -= len;
! 800: *mp = m;
! 801: mp = &m->m_next;
! 802: }
! 803:
! 804: efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
! 805:
! 806: splx(s);
! 807:
! 808: return (top);
! 809: }
! 810:
! 811: #define MII_SET(sc, x) \
! 812: bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS, \
! 813: bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS) \
! 814: | (x))
! 815:
! 816: #define MII_CLR(sc, x) \
! 817: bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS, \
! 818: bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS) \
! 819: & (~(x)))
! 820:
! 821: void
! 822: ef_mii_writeb(sc, b)
! 823: struct ef_softc *sc;
! 824: int b;
! 825: {
! 826: MII_CLR(sc, EF_MII_CLK);
! 827:
! 828: if (b)
! 829: MII_SET(sc, EF_MII_DATA);
! 830: else
! 831: MII_CLR(sc, EF_MII_DATA);
! 832:
! 833: MII_CLR(sc, EF_MII_CLK);
! 834: DELAY(1);
! 835: MII_SET(sc, EF_MII_CLK);
! 836: DELAY(1);
! 837: }
! 838:
! 839: void
! 840: ef_mii_sync(sc)
! 841: struct ef_softc *sc;
! 842: {
! 843: int i;
! 844:
! 845: for (i = 0; i < 32; i++)
! 846: ef_mii_writeb(sc, 1);
! 847: }
! 848:
! 849: int
! 850: ef_miibus_readreg(dev, phy, reg)
! 851: struct device *dev;
! 852: int phy, reg;
! 853: {
! 854: struct ef_softc *sc = (struct ef_softc *)dev;
! 855: int i, ack, s, val = 0;
! 856:
! 857: s = splnet();
! 858:
! 859: GO_WINDOW(4);
! 860: bus_space_write_2(sc->sc_iot, sc->sc_ioh, EP_W4_CTRLR_STATUS, 0);
! 861:
! 862: /* Turn on xmit */
! 863: MII_SET(sc, EF_MII_DIR);
! 864: MII_CLR(sc, EF_MII_CLK);
! 865:
! 866: ef_mii_sync(sc);
! 867:
! 868: /* Transmit start sequence */
! 869: ef_mii_writeb(sc, 0);
! 870: ef_mii_writeb(sc, 1);
! 871:
! 872: /* Transmit read sequence */
! 873: ef_mii_writeb(sc, 1);
! 874: ef_mii_writeb(sc, 0);
! 875:
! 876: /* Transmit phy addr */
! 877: for (i = 0x10; i; i >>= 1)
! 878: ef_mii_writeb(sc, (phy & i) ? 1 : 0);
! 879:
! 880: /* Transmit reg addr */
! 881: for (i = 0x10; i; i >>= 1)
! 882: ef_mii_writeb(sc, (reg & i) ? 1 : 0);
! 883:
! 884: /* First cycle of turnaround */
! 885: MII_CLR(sc, EF_MII_CLK | EF_MII_DATA);
! 886: DELAY(1);
! 887: MII_SET(sc, EF_MII_CLK);
! 888: DELAY(1);
! 889:
! 890: /* Turn off xmit */
! 891: MII_CLR(sc, EF_MII_DIR);
! 892:
! 893: /* Second cycle of turnaround */
! 894: MII_CLR(sc, EF_MII_CLK);
! 895: DELAY(1);
! 896: MII_SET(sc, EF_MII_CLK);
! 897: DELAY(1);
! 898: ack = bus_space_read_2(sc->sc_iot, sc->sc_ioh, EP_W4_CTRLR_STATUS) &
! 899: EF_MII_DATA;
! 900:
! 901: /* Read 16bit data */
! 902: for (i = 0x8000; i; i >>= 1) {
! 903: MII_CLR(sc, EF_MII_CLK);
! 904: DELAY(1);
! 905: if (bus_space_read_2(sc->sc_iot, sc->sc_ioh,
! 906: EP_W4_CTRLR_STATUS) & EF_MII_DATA)
! 907: val |= i;
! 908: MII_SET(sc, EF_MII_CLK);
! 909: DELAY(1);
! 910: }
! 911:
! 912: MII_CLR(sc, EF_MII_CLK);
! 913: DELAY(1);
! 914: MII_SET(sc, EF_MII_CLK);
! 915: DELAY(1);
! 916:
! 917: splx(s);
! 918:
! 919: return (val);
! 920: }
! 921:
! 922: void
! 923: ef_miibus_writereg(dev, phy, reg, val)
! 924: struct device *dev;
! 925: int phy, reg, val;
! 926: {
! 927: struct ef_softc *sc = (struct ef_softc *)dev;
! 928: int s, i;
! 929:
! 930: s = splnet();
! 931:
! 932: GO_WINDOW(4);
! 933: bus_space_write_2(sc->sc_iot, sc->sc_ioh, EP_W4_CTRLR_STATUS, 0);
! 934:
! 935: /* Turn on xmit */
! 936: MII_SET(sc, EF_MII_DIR);
! 937:
! 938: ef_mii_sync(sc);
! 939:
! 940: ef_mii_writeb(sc, 0);
! 941: ef_mii_writeb(sc, 1);
! 942: ef_mii_writeb(sc, 0);
! 943: ef_mii_writeb(sc, 1);
! 944:
! 945: for (i = 0x10; i; i >>= 1)
! 946: ef_mii_writeb(sc, (phy & i) ? 1 : 0);
! 947:
! 948: for (i = 0x10; i; i >>= 1)
! 949: ef_mii_writeb(sc, (reg & i) ? 1 : 0);
! 950:
! 951: ef_mii_writeb(sc, 1);
! 952: ef_mii_writeb(sc, 0);
! 953:
! 954: for (i = 0x8000; i; i >>= 1)
! 955: ef_mii_writeb(sc, (val & i) ? 1 : 0);
! 956:
! 957: splx(s);
! 958: }
! 959:
! 960: int
! 961: ef_ifmedia_upd(ifp)
! 962: struct ifnet *ifp;
! 963: {
! 964: struct ef_softc *sc = ifp->if_softc;
! 965:
! 966: mii_mediachg(&sc->sc_mii);
! 967: return (0);
! 968: }
! 969:
! 970: void
! 971: ef_ifmedia_sts(ifp, ifmr)
! 972: struct ifnet *ifp;
! 973: struct ifmediareq *ifmr;
! 974: {
! 975: struct ef_softc *sc = ifp->if_softc;
! 976:
! 977: mii_pollstat(&sc->sc_mii);
! 978: ifmr->ifm_status = sc->sc_mii.mii_media_status;
! 979: ifmr->ifm_active = sc->sc_mii.mii_media_active;
! 980: }
! 981:
! 982: void
! 983: ef_miibus_statchg(self)
! 984: struct device *self;
! 985: {
! 986: struct ef_softc *sc = (struct ef_softc *)self;
! 987: int s;
! 988:
! 989: s = splnet();
! 990: GO_WINDOW(3);
! 991: /* Set duplex bit appropriately */
! 992: if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX)
! 993: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
! 994: EP_W3_MAC_CONTROL, 0x20);
! 995: else
! 996: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
! 997: EP_W3_MAC_CONTROL, 0x00);
! 998: GO_WINDOW(7);
! 999: splx(s);
! 1000: }
! 1001:
! 1002: void
! 1003: ef_tick(v)
! 1004: void *v;
! 1005: {
! 1006: struct ef_softc *sc = v;
! 1007: int s;
! 1008:
! 1009: s = splnet();
! 1010: mii_tick(&sc->sc_mii);
! 1011: splx(s);
! 1012: timeout_add(&sc->sc_tick_tmo, hz);
! 1013: }
CVSweb