Annotation of sys/arch/sparc/dev/hme.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hme.c,v 1.55 2006/06/25 21:53:44 brad Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1998 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: /*
! 30: * Driver for the Happy Meal (hme) ethernet boards
! 31: * Based on information gleaned from reading the
! 32: * S/Linux driver by David Miller
! 33: *
! 34: * Thanks go to the University of North Carolina at Greensboro, Systems
! 35: * and Networks Department for some of the resources used to develop
! 36: * this driver.
! 37: */
! 38:
! 39: #include "bpfilter.h"
! 40: #include "vlan.h"
! 41:
! 42: #include <sys/param.h>
! 43: #include <sys/systm.h>
! 44: #include <sys/kernel.h>
! 45: #include <sys/errno.h>
! 46: #include <sys/ioctl.h>
! 47: #include <sys/mbuf.h>
! 48: #include <sys/socket.h>
! 49: #include <sys/syslog.h>
! 50: #include <sys/device.h>
! 51: #include <sys/malloc.h>
! 52:
! 53: #include <net/if.h>
! 54: #include <net/if_dl.h>
! 55: #include <net/if_types.h>
! 56: #include <net/netisr.h>
! 57: #include <net/if_media.h>
! 58:
! 59: #ifdef INET
! 60: #include <netinet/in.h>
! 61: #include <netinet/in_systm.h>
! 62: #include <netinet/in_var.h>
! 63: #include <netinet/ip.h>
! 64: #include <netinet/if_ether.h>
! 65: #include <netinet/tcp.h>
! 66: #include <netinet/udp.h>
! 67: #endif
! 68:
! 69: #if NBPFILTER > 0
! 70: #include <net/bpf.h>
! 71: #include <net/bpfdesc.h>
! 72: #endif
! 73:
! 74: #include <machine/autoconf.h>
! 75: #include <sparc/cpu.h>
! 76: #include <sparc/sparc/cpuvar.h>
! 77: #include <sparc/dev/sbusvar.h>
! 78: #include <sparc/dev/dmareg.h> /* for SBUS_BURST_* */
! 79: #include <dev/mii/mii.h>
! 80: #include <dev/mii/miivar.h>
! 81: #include <sparc/dev/hmereg.h>
! 82: #include <sparc/dev/hmevar.h>
! 83:
! 84: int hmematch(struct device *, void *, void *);
! 85: void hmeattach(struct device *, struct device *, void *);
! 86: void hmewatchdog(struct ifnet *);
! 87: int hmeintr(void *);
! 88: int hmeioctl(struct ifnet *, u_long, caddr_t);
! 89: void hmereset(struct hme_softc *);
! 90: void hmestart(struct ifnet *);
! 91: void hmestop(struct hme_softc *);
! 92: void hmeinit(struct hme_softc *);
! 93: void hme_meminit(struct hme_softc *);
! 94:
! 95: void hme_tcvr_bb_writeb(struct hme_softc *, int);
! 96: int hme_tcvr_bb_readb(struct hme_softc *, int);
! 97:
! 98: void hme_poll_stop(struct hme_softc *sc);
! 99:
! 100: int hme_rint(struct hme_softc *);
! 101: int hme_tint(struct hme_softc *);
! 102: int hme_mint(struct hme_softc *, u_int32_t);
! 103: int hme_eint(struct hme_softc *, u_int32_t);
! 104:
! 105: /* TCP/UDP checksum offload support */
! 106: void hme_rxcksum(struct mbuf *, u_int32_t);
! 107:
! 108: void hme_reset_rx(struct hme_softc *);
! 109: void hme_reset_tx(struct hme_softc *);
! 110:
! 111: void hme_read(struct hme_softc *, int, int, u_int32_t);
! 112: int hme_put(struct hme_softc *, int, struct mbuf *);
! 113:
! 114: /*
! 115: * ifmedia glue
! 116: */
! 117: int hme_mediachange(struct ifnet *);
! 118: void hme_mediastatus(struct ifnet *, struct ifmediareq *);
! 119:
! 120: /*
! 121: * mii glue
! 122: */
! 123: int hme_mii_read(struct device *, int, int);
! 124: void hme_mii_write(struct device *, int, int, int);
! 125: void hme_mii_statchg(struct device *);
! 126:
! 127: void hme_mcreset(struct hme_softc *);
! 128:
! 129: struct cfattach hme_ca = {
! 130: sizeof (struct hme_softc), hmematch, hmeattach
! 131: };
! 132:
! 133: struct cfdriver hme_cd = {
! 134: NULL, "hme", DV_IFNET
! 135: };
! 136:
! 137: int
! 138: hmematch(parent, vcf, aux)
! 139: struct device *parent;
! 140: void *vcf, *aux;
! 141: {
! 142: struct cfdata *cf = vcf;
! 143: struct confargs *ca = aux;
! 144: register struct romaux *ra = &ca->ca_ra;
! 145:
! 146: if (strcmp(cf->cf_driver->cd_name, ra->ra_name) &&
! 147: strcmp("SUNW,hme", ra->ra_name) &&
! 148: strcmp("SUNW,qfe", ra->ra_name)) {
! 149: return (0);
! 150: }
! 151: if (!sbus_testdma((struct sbus_softc *)parent, ca))
! 152: return(0);
! 153: return (1);
! 154: }
! 155:
! 156: void
! 157: hmeattach(parent, self, aux)
! 158: struct device *parent, *self;
! 159: void *aux;
! 160: {
! 161: struct confargs *ca = aux;
! 162: struct hme_softc *sc = (struct hme_softc *)self;
! 163: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 164: int pri;
! 165: struct bootpath *bp;
! 166: /* XXX the following declaration should be elsewhere */
! 167: extern void myetheraddr(u_char *);
! 168:
! 169: if (ca->ca_ra.ra_nintr != 1) {
! 170: printf(": expected 1 interrupt, got %d\n",
! 171: ca->ca_ra.ra_nintr);
! 172: return;
! 173: }
! 174: pri = ca->ca_ra.ra_intr[0].int_pri;
! 175:
! 176: /* map registers */
! 177: if (ca->ca_ra.ra_nreg != 5) {
! 178: printf(": expected 5 registers, got %d\n", ca->ca_ra.ra_nreg);
! 179: return;
! 180: }
! 181: sc->sc_gr = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
! 182: ca->ca_ra.ra_reg[0].rr_len);
! 183: sc->sc_txr = mapiodev(&(ca->ca_ra.ra_reg[1]), 0,
! 184: ca->ca_ra.ra_reg[1].rr_len);
! 185: sc->sc_rxr = mapiodev(&(ca->ca_ra.ra_reg[2]), 0,
! 186: ca->ca_ra.ra_reg[2].rr_len);
! 187: sc->sc_cr = mapiodev(&(ca->ca_ra.ra_reg[3]), 0,
! 188: ca->ca_ra.ra_reg[3].rr_len);
! 189: sc->sc_tcvr = mapiodev(&(ca->ca_ra.ra_reg[4]), 0,
! 190: ca->ca_ra.ra_reg[4].rr_len);
! 191:
! 192: sc->sc_node = ca->ca_ra.ra_node;
! 193:
! 194: sc->sc_rev = getpropint(ca->ca_ra.ra_node, "hm-rev", -1);
! 195: if (sc->sc_rev == 0xff)
! 196: sc->sc_rev = 0xa0;
! 197: if (sc->sc_rev == 0x20 || sc->sc_rev == 0x21)
! 198: sc->sc_flags = HME_FLAG_20_21;
! 199: else if (sc->sc_rev != 0xa0)
! 200: sc->sc_flags = HME_FLAG_NOT_A0;
! 201:
! 202: sc->sc_burst = getpropint(ca->ca_ra.ra_node, "burst-sizes", -1);
! 203: if (sc->sc_burst == -1)
! 204: sc->sc_burst = ((struct sbus_softc *)parent)->sc_burst;
! 205:
! 206: /* Clamp at parent's burst sizes */
! 207: sc->sc_burst &= ((struct sbus_softc *)parent)->sc_burst;
! 208:
! 209: hme_meminit(sc);
! 210:
! 211: sc->sc_ih.ih_fun = hmeintr;
! 212: sc->sc_ih.ih_arg = sc;
! 213: intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih, IPL_NET,
! 214: self->dv_xname);
! 215:
! 216: /*
! 217: * Get MAC address from card if 'local-mac-address' property exists.
! 218: * Otherwise, use the machine's builtin MAC.
! 219: */
! 220: if (getprop(ca->ca_ra.ra_node, "local-mac-address",
! 221: sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN) <= 0) {
! 222: myetheraddr(sc->sc_arpcom.ac_enaddr);
! 223: }
! 224:
! 225: printf(" pri %d: address %s rev %d\n", pri,
! 226: ether_sprintf(sc->sc_arpcom.ac_enaddr), sc->sc_rev);
! 227:
! 228: sc->sc_mii.mii_ifp = ifp;
! 229: sc->sc_mii.mii_readreg = hme_mii_read;
! 230: sc->sc_mii.mii_writereg = hme_mii_write;
! 231: sc->sc_mii.mii_statchg = hme_mii_statchg;
! 232: ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, hme_mediachange,
! 233: hme_mediastatus);
! 234: mii_phy_probe(self, &sc->sc_mii, 0xffffffff);
! 235:
! 236: if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
! 237: ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE,
! 238: 0, NULL);
! 239: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);
! 240: }
! 241: else
! 242: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
! 243:
! 244: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 245: ifp->if_softc = sc;
! 246: ifp->if_start = hmestart;
! 247: ifp->if_ioctl = hmeioctl;
! 248: ifp->if_watchdog = hmewatchdog;
! 249: ifp->if_flags =
! 250: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
! 251: sc->sc_if_flags = ifp->if_flags;
! 252: ifp->if_capabilities = IFCAP_VLAN_MTU;
! 253: IFQ_SET_MAXLEN(&ifp->if_snd, HME_TX_RING_SIZE);
! 254: IFQ_SET_READY(&ifp->if_snd);
! 255:
! 256: /* Attach the interface. */
! 257: if_attach(ifp);
! 258: ether_ifattach(ifp);
! 259:
! 260: bp = ca->ca_ra.ra_bp;
! 261: if (bp != NULL && sc->sc_dev.dv_unit == bp->val[1] &&
! 262: ((strcmp(bp->name, hme_cd.cd_name) == 0) ||
! 263: (strcmp(bp->name, "qfe") == 0) ||
! 264: (strcmp(bp->name, "SUNW,hme") == 0)))
! 265: bp->dev = &sc->sc_dev;
! 266: }
! 267:
! 268: /*
! 269: * Start output on interface.
! 270: * We make two assumptions here:
! 271: * 1) that the current priority is set to splnet _before_ this code
! 272: * is called *and* is returned to the appropriate priority after
! 273: * return
! 274: * 2) that the IFF_OACTIVE flag is checked before this code is called
! 275: * (i.e. that the output part of the interface is idle)
! 276: */
! 277: void
! 278: hmestart(ifp)
! 279: struct ifnet *ifp;
! 280: {
! 281: struct hme_softc *sc = ifp->if_softc;
! 282: struct mbuf *m;
! 283: int bix, len;
! 284:
! 285: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 286: return;
! 287:
! 288: bix = sc->sc_last_td;
! 289:
! 290: for (;;) {
! 291: IFQ_DEQUEUE(&ifp->if_snd, m);
! 292: if (m == NULL)
! 293: break;
! 294: #if NBPFILTER > 0
! 295: /*
! 296: * If BPF is listening on this interface, let it see the
! 297: * packet before we commit it to the wire.
! 298: */
! 299: if (ifp->if_bpf)
! 300: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 301: #endif
! 302:
! 303: /*
! 304: * Copy the mbuf chain into the transmit buffer.
! 305: */
! 306: len = hme_put(sc, bix, m);
! 307:
! 308: /*
! 309: * Initialize transmit registers and start transmission.
! 310: */
! 311: sc->sc_desc->hme_txd[bix].tx_flags =
! 312: HME_TXD_OWN | HME_TXD_SOP | HME_TXD_EOP |
! 313: (len & HME_TXD_SIZE);
! 314: sc->sc_txr->tx_pnding = TXR_TP_DMAWAKEUP;
! 315:
! 316: if (++bix == HME_TX_RING_SIZE)
! 317: bix = 0;
! 318:
! 319: if (++sc->sc_no_td == HME_TX_RING_SIZE) {
! 320: ifp->if_flags |= IFF_OACTIVE;
! 321: break;
! 322: }
! 323: }
! 324:
! 325: sc->sc_last_td = bix;
! 326: }
! 327:
! 328: #define MAX_STOP_TRIES 16
! 329:
! 330: void
! 331: hmestop(sc)
! 332: struct hme_softc *sc;
! 333: {
! 334: int tries = 0;
! 335:
! 336: sc->sc_gr->reset = GR_RESET_ALL;
! 337: while (sc->sc_gr->reset && (++tries != MAX_STOP_TRIES))
! 338: DELAY(20);
! 339: if (tries == MAX_STOP_TRIES)
! 340: printf("%s: stop failed\n", sc->sc_dev.dv_xname);
! 341: sc->sc_mii.mii_media_status &= ~IFM_ACTIVE;
! 342: }
! 343:
! 344: /*
! 345: * Reset interface.
! 346: */
! 347: void
! 348: hmereset(sc)
! 349: struct hme_softc *sc;
! 350: {
! 351: int s;
! 352:
! 353: s = splnet();
! 354: hmestop(sc);
! 355: hmeinit(sc);
! 356: splx(s);
! 357: }
! 358:
! 359: /*
! 360: * Device timeout/watchdog routine. Entered if the device neglects to generate
! 361: * an interrupt after a transmit has been started on it.
! 362: */
! 363: void
! 364: hmewatchdog(ifp)
! 365: struct ifnet *ifp;
! 366: {
! 367: struct hme_softc *sc = ifp->if_softc;
! 368:
! 369: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
! 370: ++sc->sc_arpcom.ac_if.if_oerrors;
! 371:
! 372: hmereset(sc);
! 373: }
! 374:
! 375: int
! 376: hmeioctl(ifp, cmd, data)
! 377: struct ifnet *ifp;
! 378: u_long cmd;
! 379: caddr_t data;
! 380: {
! 381: struct hme_softc *sc = ifp->if_softc;
! 382: struct ifaddr *ifa = (struct ifaddr *)data;
! 383: struct ifreq *ifr = (struct ifreq *)data;
! 384: int s, error = 0;
! 385:
! 386: s = splnet();
! 387:
! 388: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 389: splx(s);
! 390: return (error);
! 391: }
! 392:
! 393: switch (cmd) {
! 394: case SIOCSIFADDR:
! 395: switch (ifa->ifa_addr->sa_family) {
! 396: #ifdef INET
! 397: case AF_INET:
! 398: if (ifp->if_flags & IFF_UP)
! 399: hme_mcreset(sc);
! 400: else {
! 401: ifp->if_flags |= IFF_UP;
! 402: hmeinit(sc);
! 403: }
! 404: arp_ifinit(&sc->sc_arpcom, ifa);
! 405: break;
! 406: #endif /* INET */
! 407: default:
! 408: ifp->if_flags |= IFF_UP;
! 409: hmeinit(sc);
! 410: break;
! 411: }
! 412: break;
! 413:
! 414: case SIOCSIFFLAGS:
! 415: if ((ifp->if_flags & IFF_UP) == 0 &&
! 416: (ifp->if_flags & IFF_RUNNING) != 0) {
! 417: /*
! 418: * If interface is marked down and it is running, then
! 419: * stop it.
! 420: */
! 421: hmestop(sc);
! 422: ifp->if_flags &= ~IFF_RUNNING;
! 423: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 424: (ifp->if_flags & IFF_RUNNING) == 0) {
! 425: /*
! 426: * If interface is marked up and it is stopped, then
! 427: * start it.
! 428: */
! 429: hmeinit(sc);
! 430: } else {
! 431: /*
! 432: * If setting debug or promiscuous mode, do not reset
! 433: * the chip; for everything else, call hmeinit()
! 434: * which will trigger a reset.
! 435: */
! 436: #define RESETIGN (IFF_CANTCHANGE | IFF_DEBUG)
! 437: if (ifp->if_flags == sc->sc_if_flags)
! 438: break;
! 439: if ((ifp->if_flags & (~RESETIGN))
! 440: == (sc->sc_if_flags & (~RESETIGN)))
! 441: hme_mcreset(sc);
! 442: else
! 443: hmeinit(sc);
! 444: #undef RESETIGN
! 445: }
! 446: break;
! 447:
! 448: case SIOCADDMULTI:
! 449: case SIOCDELMULTI:
! 450: error = (cmd == SIOCADDMULTI) ?
! 451: ether_addmulti(ifr, &sc->sc_arpcom):
! 452: ether_delmulti(ifr, &sc->sc_arpcom);
! 453:
! 454: if (error == ENETRESET) {
! 455: /*
! 456: * Multicast list has changed; set the hardware filter
! 457: * accordingly.
! 458: */
! 459: if (ifp->if_flags & IFF_RUNNING)
! 460: hme_mcreset(sc);
! 461: error = 0;
! 462: }
! 463: break;
! 464: case SIOCGIFMEDIA:
! 465: case SIOCSIFMEDIA:
! 466: error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
! 467: break;
! 468: default:
! 469: error = ENOTTY;
! 470: }
! 471:
! 472: sc->sc_if_flags = ifp->if_flags;
! 473: splx(s);
! 474: return (error);
! 475: }
! 476:
! 477: void
! 478: hme_meminit(sc)
! 479: struct hme_softc *sc;
! 480: {
! 481: struct hme_desc *desc;
! 482: int i;
! 483:
! 484: if (sc->sc_desc_dva == NULL)
! 485: sc->sc_desc_dva = (struct hme_desc *) dvma_malloc(
! 486: sizeof(struct hme_desc), &sc->sc_desc, M_NOWAIT);
! 487: if (sc->sc_bufs_dva == NULL)
! 488: sc->sc_bufs_dva = (struct hme_bufs *) dvma_malloc(
! 489: sizeof(struct hme_bufs), &sc->sc_bufs, M_NOWAIT);
! 490:
! 491: desc = sc->sc_desc;
! 492:
! 493: /*
! 494: * Setup TX descriptors
! 495: */
! 496: sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
! 497: for (i = 0; i < HME_TX_RING_SIZE; i++) {
! 498: desc->hme_txd[i].tx_addr =
! 499: (u_int32_t)sc->sc_bufs_dva->tx_buf[i];
! 500: desc->hme_txd[i].tx_flags = 0;
! 501: }
! 502:
! 503: /*
! 504: * Setup RX descriptors
! 505: */
! 506: sc->sc_last_rd = 0;
! 507: for (i = 0; i < HME_RX_RING_SIZE; i++) {
! 508: desc->hme_rxd[i].rx_addr =
! 509: (u_int32_t)sc->sc_bufs_dva->rx_buf[i];
! 510: desc->hme_rxd[i].rx_flags = HME_RXD_OWN |
! 511: ((HME_RX_PKT_BUF_SZ - HME_RX_OFFSET) << 16);
! 512: }
! 513: }
! 514:
! 515: void
! 516: hmeinit(sc)
! 517: struct hme_softc *sc;
! 518: {
! 519: u_int32_t c, n;
! 520: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 521: struct hme_tcvr *tcvr = sc->sc_tcvr;
! 522: struct hme_cr *cr = sc->sc_cr;
! 523: struct hme_gr *gr = sc->sc_gr;
! 524: struct hme_txr *txr = sc->sc_txr;
! 525: struct hme_rxr *rxr = sc->sc_rxr;
! 526:
! 527: hme_poll_stop(sc);
! 528: hmestop(sc);
! 529:
! 530: hme_meminit(sc);
! 531:
! 532: tcvr->int_mask = 0xffff;
! 533:
! 534: c = tcvr->cfg;
! 535: if (sc->sc_flags & HME_FLAG_FENABLE)
! 536: tcvr->cfg = c & ~(TCVR_CFG_BENABLE);
! 537: else
! 538: tcvr->cfg = c | TCVR_CFG_BENABLE;
! 539:
! 540: hme_reset_tx(sc);
! 541: hme_reset_rx(sc);
! 542:
! 543: cr->rand_seed = sc->sc_arpcom.ac_enaddr[5] |
! 544: ((sc->sc_arpcom.ac_enaddr[4] << 8) & 0x3f00);
! 545: cr->mac_addr0 = (sc->sc_arpcom.ac_enaddr[0] << 8) |
! 546: sc->sc_arpcom.ac_enaddr[1];
! 547: cr->mac_addr1 = (sc->sc_arpcom.ac_enaddr[2] << 8) |
! 548: sc->sc_arpcom.ac_enaddr[3];
! 549: cr->mac_addr2 = (sc->sc_arpcom.ac_enaddr[4] << 8) |
! 550: sc->sc_arpcom.ac_enaddr[5];
! 551: cr->tx_pkt_max = cr->rx_pkt_max = ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN;
! 552:
! 553: cr->jsize = HME_DEFAULT_JSIZE;
! 554: cr->ipkt_gap1 = HME_DEFAULT_IPKT_GAP1;
! 555: cr->ipkt_gap2 = HME_DEFAULT_IPKT_GAP2;
! 556:
! 557: rxr->rx_ring = (u_int32_t)sc->sc_desc_dva->hme_rxd;
! 558: txr->tx_ring = (u_int32_t)sc->sc_desc_dva->hme_txd;
! 559:
! 560: if (sc->sc_burst & SBUS_BURST_64)
! 561: gr->cfg = GR_CFG_BURST64;
! 562: else if (sc->sc_burst & SBUS_BURST_32)
! 563: gr->cfg = GR_CFG_BURST32;
! 564: else if (sc->sc_burst & SBUS_BURST_16)
! 565: gr->cfg = GR_CFG_BURST16;
! 566: else {
! 567: printf("%s: burst size unknown\n", sc->sc_dev.dv_xname);
! 568: gr->cfg = 0;
! 569: }
! 570:
! 571: gr->imask = GR_IMASK_SENTFRAME | GR_IMASK_TXPERR |
! 572: GR_IMASK_GOTFRAME | GR_IMASK_RCNTEXP;
! 573:
! 574: txr->tx_rsize = (HME_TX_RING_SIZE >> TXR_RSIZE_SHIFT) - 1;
! 575: txr->cfg |= TXR_CFG_DMAENABLE;
! 576:
! 577: c = RXR_CFG_DMAENABLE | (HME_RX_OFFSET << 3);
! 578: /* RX TCP/UDP cksum offset */
! 579: n = (ETHER_HDR_LEN + sizeof(struct ip)) / 2;
! 580: n = (n << RXR_CFG_CSUM_SHIFT) & RXR_CFG_CSUMSTART;
! 581: c |= n;
! 582: #if HME_RX_RING_SIZE == 32
! 583: c |= RXR_CFG_RINGSIZE32;
! 584: #elif HME_RX_RING_SIZE == 64
! 585: c |= RXR_CFG_RINGSIZE64;
! 586: #elif HME_RX_RING_SIZE == 128
! 587: c |= RXR_CFG_RINGSIZE128;
! 588: #elif HME_RX_RING_SIZE == 256
! 589: c |= RXR_CFG_RINGSIZE256;
! 590: #else
! 591: #error "HME_RX_RING_SIZE must be 32, 64, 128, or 256."
! 592: #endif
! 593: rxr->cfg = c;
! 594: DELAY(20);
! 595: if (c != rxr->cfg) /* the receiver sometimes misses bits */
! 596: printf("%s: setting rxreg->cfg failed.\n", sc->sc_dev.dv_xname);
! 597:
! 598: cr->rx_cfg = 0;
! 599: hme_mcreset(sc);
! 600: DELAY(10);
! 601:
! 602: cr->tx_cfg |= CR_TXCFG_DGIVEUP;
! 603:
! 604: c = CR_XCFG_ODENABLE;
! 605: if (sc->sc_flags & HME_FLAG_LANCE)
! 606: c |= (HME_DEFAULT_IPKT_GAP0 << 5) | CR_XCFG_LANCE;
! 607: cr->xif_cfg = c;
! 608:
! 609: cr->tx_cfg |= CR_TXCFG_ENABLE; /* enable tx */
! 610: cr->rx_cfg |= CR_RXCFG_ENABLE; /* enable rx */
! 611:
! 612: mii_mediachg(&sc->sc_mii);
! 613:
! 614: ifp->if_flags |= IFF_RUNNING;
! 615: ifp->if_flags &= ~IFF_OACTIVE;
! 616: sc->sc_if_flags = ifp->if_flags;
! 617: ifp->if_timer = 0;
! 618: }
! 619:
! 620: void
! 621: hme_poll_stop(sc)
! 622: struct hme_softc *sc;
! 623: {
! 624: struct hme_tcvr *tcvr = sc->sc_tcvr;
! 625:
! 626: /* if not polling, or polling not enabled, we're done. */
! 627: if ((sc->sc_flags & (HME_FLAG_POLLENABLE | HME_FLAG_POLL)) !=
! 628: (HME_FLAG_POLLENABLE | HME_FLAG_POLL))
! 629: return;
! 630:
! 631: /* Turn off MIF interrupts, and disable polling */
! 632: tcvr->int_mask = 0xffff;
! 633: tcvr->cfg &= ~(TCVR_CFG_PENABLE);
! 634: sc->sc_flags &= ~(HME_FLAG_POLL);
! 635: DELAY(200);
! 636: }
! 637:
! 638: #define RESET_TRIES 32
! 639:
! 640: void
! 641: hme_reset_tx(sc)
! 642: struct hme_softc *sc;
! 643: {
! 644: int tries = RESET_TRIES;
! 645: struct hme_cr *cr = sc->sc_cr;
! 646:
! 647: cr->tx_swreset = 0;
! 648: while (--tries && (cr->tx_swreset & 1))
! 649: DELAY(20);
! 650:
! 651: if (!tries)
! 652: printf("%s: reset tx failed\n", sc->sc_dev.dv_xname);
! 653: }
! 654:
! 655: void
! 656: hme_reset_rx(sc)
! 657: struct hme_softc *sc;
! 658: {
! 659: int tries = RESET_TRIES;
! 660: struct hme_cr *cr = sc->sc_cr;
! 661:
! 662: cr->rx_swreset = 0;
! 663: while (--tries && (cr->rx_swreset & 1))
! 664: DELAY(20);
! 665:
! 666: if (!tries)
! 667: printf("%s: reset rx failed\n", sc->sc_dev.dv_xname);
! 668: }
! 669:
! 670: /*
! 671: * mif interrupt
! 672: */
! 673: int
! 674: hme_mint(sc, why)
! 675: struct hme_softc *sc;
! 676: u_int32_t why;
! 677: {
! 678: printf("%s: link status changed\n", sc->sc_dev.dv_xname);
! 679: hme_poll_stop(sc);
! 680: return (1);
! 681: }
! 682:
! 683: /*
! 684: * transmit interrupt
! 685: */
! 686: int
! 687: hme_tint(sc)
! 688: struct hme_softc *sc;
! 689: {
! 690: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 691: struct hme_cr *cr = sc->sc_cr;
! 692: int bix;
! 693: struct hme_txd txd;
! 694:
! 695: /*
! 696: * Get collision counters
! 697: */
! 698: ifp->if_collisions += cr->ex_ctr + cr->lt_ctr + cr->fc_ctr + cr->nc_ctr;
! 699: cr->ex_ctr = 0;
! 700: cr->lt_ctr = 0;
! 701: cr->fc_ctr = 0;
! 702: cr->nc_ctr = 0;
! 703:
! 704: bix = sc->sc_first_td;
! 705:
! 706: for (;;) {
! 707: if (sc->sc_no_td <= 0)
! 708: break;
! 709:
! 710: bcopy(&sc->sc_desc->hme_txd[bix], &txd, sizeof(txd));
! 711:
! 712: if (txd.tx_flags & HME_TXD_OWN)
! 713: break;
! 714:
! 715: ifp->if_flags &= ~IFF_OACTIVE;
! 716: ifp->if_opackets++;
! 717:
! 718: if (++bix == HME_TX_RING_SIZE)
! 719: bix = 0;
! 720:
! 721: --sc->sc_no_td;
! 722: }
! 723:
! 724: sc->sc_first_td = bix;
! 725:
! 726: hmestart(ifp);
! 727:
! 728: if (sc->sc_no_td == 0)
! 729: ifp->if_timer = 0;
! 730:
! 731: return (1);
! 732: }
! 733:
! 734: /*
! 735: * XXX layering violation
! 736: *
! 737: * If we can have additional csum data member in 'struct pkthdr' for
! 738: * these incomplete checksum offload capable hardware, things would be
! 739: * much simpler. That member variable will carry partial checksum
! 740: * data and it may be evaluated in TCP/UDP input handler after
! 741: * computing pseudo header checksumming.
! 742: */
! 743: void
! 744: hme_rxcksum(struct mbuf *m, u_int32_t flags)
! 745: {
! 746: struct ether_header *eh;
! 747: struct ip *ip;
! 748: struct udphdr *uh;
! 749: int32_t hlen, len, pktlen;
! 750: u_int16_t cksum, *opts;
! 751: u_int32_t temp32;
! 752: union pseudoh {
! 753: struct hdr {
! 754: u_int16_t len;
! 755: u_int8_t ttl;
! 756: u_int8_t proto;
! 757: u_int32_t src;
! 758: u_int32_t dst;
! 759: } h;
! 760: u_int16_t w[6];
! 761: } ph;
! 762:
! 763: pktlen = m->m_pkthdr.len;
! 764: if (pktlen < sizeof(struct ether_header))
! 765: return;
! 766: eh = mtod(m, struct ether_header *);
! 767: if (eh->ether_type != htons(ETHERTYPE_IP))
! 768: return;
! 769: ip = (struct ip *)(eh + 1);
! 770: if (ip->ip_v != IPVERSION)
! 771: return;
! 772:
! 773: hlen = ip->ip_hl << 2;
! 774: pktlen -= sizeof(struct ether_header);
! 775: if (hlen < sizeof(struct ip))
! 776: return;
! 777: if (ntohs(ip->ip_len) < hlen)
! 778: return;
! 779: if (ntohs(ip->ip_len) != pktlen)
! 780: return;
! 781: if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
! 782: return; /* can't handle fragmented packet */
! 783:
! 784: switch (ip->ip_p) {
! 785: case IPPROTO_TCP:
! 786: if (pktlen < (hlen + sizeof(struct tcphdr)))
! 787: return;
! 788: break;
! 789: case IPPROTO_UDP:
! 790: if (pktlen < (hlen + sizeof(struct udphdr)))
! 791: return;
! 792: uh = (struct udphdr *)((caddr_t)ip + hlen);
! 793: if (uh->uh_sum == 0)
! 794: return; /* no checksum */
! 795: break;
! 796: default:
! 797: return;
! 798: }
! 799:
! 800: cksum = htons(~(flags & HME_RXD_CSUM));
! 801: /* cksum fixup for IP options */
! 802: len = hlen - sizeof(struct ip);
! 803: if (len > 0) {
! 804: opts = (u_int16_t *)(ip + 1);
! 805: for (; len > 0; len -= sizeof(u_int16_t), opts++) {
! 806: temp32 = cksum - *opts;
! 807: temp32 = (temp32 >> 16) + (temp32 & 65535);
! 808: cksum = temp32 & 65535;
! 809: }
! 810: }
! 811: /* cksum fixup for pseudo-header, replace with in_cksum_phdr()? */
! 812: ph.h.len = htons(ntohs(ip->ip_len) - hlen);
! 813: ph.h.ttl = 0;
! 814: ph.h.proto = ip->ip_p;
! 815: ph.h.src = ip->ip_src.s_addr;
! 816: ph.h.dst = ip->ip_dst.s_addr;
! 817: temp32 = cksum;
! 818: opts = &ph.w[0];
! 819: temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5];
! 820: temp32 = (temp32 >> 16) + (temp32 & 65535);
! 821: temp32 += (temp32 >> 16);
! 822: cksum = ~temp32;
! 823: if (cksum == 0) {
! 824: m->m_pkthdr.csum_flags |=
! 825: M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
! 826: }
! 827: }
! 828:
! 829: int
! 830: hme_rint(sc)
! 831: struct hme_softc *sc;
! 832: {
! 833: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 834: int bix, len;
! 835: struct hme_rxd rxd;
! 836:
! 837: bix = sc->sc_last_rd;
! 838:
! 839: for (;;) {
! 840: bcopy(&sc->sc_desc->hme_rxd[bix], &rxd, sizeof(rxd));
! 841: len = rxd.rx_flags >> 16;
! 842:
! 843: if (rxd.rx_flags & HME_RXD_OWN)
! 844: break;
! 845:
! 846: if (rxd.rx_flags & HME_RXD_OVERFLOW)
! 847: ifp->if_ierrors++;
! 848: else
! 849: hme_read(sc, bix, len, rxd.rx_flags);
! 850:
! 851: rxd.rx_flags = HME_RXD_OWN |
! 852: ((HME_RX_PKT_BUF_SZ - HME_RX_OFFSET) << 16);
! 853: bcopy(&rxd, &sc->sc_desc->hme_rxd[bix], sizeof(rxd));
! 854:
! 855: if (++bix == HME_RX_RING_SIZE)
! 856: bix = 0;
! 857: }
! 858:
! 859: sc->sc_last_rd = bix;
! 860:
! 861: return (1);
! 862: }
! 863:
! 864: /*
! 865: * error interrupt
! 866: */
! 867: int
! 868: hme_eint(sc, why)
! 869: struct hme_softc *sc;
! 870: u_int32_t why;
! 871: {
! 872: if (why & GR_STAT_NORXD) {
! 873: sc->sc_arpcom.ac_if.if_ierrors++;
! 874: why &= ~GR_STAT_NORXD;
! 875: }
! 876: if (why & GR_STAT_DTIMEXP) {
! 877: sc->sc_arpcom.ac_if.if_oerrors++;
! 878: why &= ~GR_STAT_DTIMEXP;
! 879: }
! 880:
! 881: if (why & GR_STAT_ALL_ERRORS) {
! 882: printf("%s: stat=%b, resetting.\n", sc->sc_dev.dv_xname,
! 883: why, GR_STAT_BITS);
! 884: hmereset(sc);
! 885: }
! 886:
! 887: return (1);
! 888: }
! 889:
! 890: /*
! 891: * Interrupt handler
! 892: */
! 893: int
! 894: hmeintr(v)
! 895: void *v;
! 896: {
! 897: struct hme_softc *sc = (struct hme_softc *)v;
! 898: struct hme_gr *gr = sc->sc_gr;
! 899: u_int32_t why;
! 900: int r = 0;
! 901:
! 902: why = gr->stat;
! 903:
! 904: if (why & GR_STAT_ALL_ERRORS)
! 905: r |= hme_eint(sc, why);
! 906:
! 907: if (why & GR_STAT_MIFIRQ)
! 908: r |= hme_mint(sc, why);
! 909:
! 910: if (why & (GR_STAT_TXALL | GR_STAT_HOSTTOTX))
! 911: r |= hme_tint(sc);
! 912:
! 913: if (why & GR_STAT_RXTOHOST)
! 914: r |= hme_rint(sc);
! 915:
! 916: return (r);
! 917: }
! 918:
! 919: int
! 920: hme_put(sc, idx, m)
! 921: struct hme_softc *sc;
! 922: int idx;
! 923: struct mbuf *m;
! 924: {
! 925: struct mbuf *n;
! 926: u_int8_t *buf = sc->sc_bufs->tx_buf[idx];
! 927: int len, tlen = 0;
! 928:
! 929: for (; m; m = n) {
! 930: len = m->m_len;
! 931: if (len == 0) {
! 932: MFREE(m, n);
! 933: continue;
! 934: }
! 935: bcopy(mtod(m, caddr_t), buf, len);
! 936: buf += len;
! 937: tlen += len;
! 938: MFREE(m, n);
! 939: }
! 940: return (tlen);
! 941: }
! 942:
! 943: void
! 944: hme_read(sc, idx, len, flags)
! 945: struct hme_softc *sc;
! 946: int idx, len;
! 947: u_int32_t flags;
! 948: {
! 949: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 950: struct mbuf *m;
! 951:
! 952: if (len <= sizeof(struct ether_header) ||
! 953: len > ETHERMTU + sizeof(struct ether_header)) {
! 954: printf("%s: invalid packet size %d; dropping\n",
! 955: ifp->if_xname, len);
! 956: ifp->if_ierrors++;
! 957: return;
! 958: }
! 959:
! 960: /* Pull packet off interface. */
! 961: m = m_devget(sc->sc_bufs->rx_buf[idx], len + HME_RX_OFFSET, 0,
! 962: &sc->sc_arpcom.ac_if, NULL);
! 963: if (m == NULL) {
! 964: ifp->if_ierrors++;
! 965: return;
! 966: }
! 967: m_adj(m, HME_RX_OFFSET);
! 968:
! 969: ifp->if_ipackets++;
! 970: hme_rxcksum(m, flags);
! 971:
! 972: #if NBPFILTER > 0
! 973: /*
! 974: * Check if there's a BPF listener on this interface.
! 975: * If so, hand off the raw packet to BPF.
! 976: */
! 977: if (ifp->if_bpf)
! 978: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 979: #endif
! 980: /* Pass the packet up. */
! 981: ether_input_mbuf(ifp, m);
! 982: }
! 983:
! 984: /*
! 985: * Program the multicast receive filter.
! 986: */
! 987: void
! 988: hme_mcreset(sc)
! 989: struct hme_softc *sc;
! 990: {
! 991: struct arpcom *ac = &sc->sc_arpcom;
! 992: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 993: struct hme_cr *cr = sc->sc_cr;
! 994: u_int32_t crc;
! 995: u_int16_t hash[4];
! 996: u_int8_t octet;
! 997: int i, j;
! 998: struct ether_multi *enm;
! 999: struct ether_multistep step;
! 1000:
! 1001: if (ifp->if_flags & IFF_PROMISC) {
! 1002: cr->rx_cfg |= CR_RXCFG_PMISC;
! 1003: return;
! 1004: }
! 1005: else
! 1006: cr->rx_cfg &= ~CR_RXCFG_PMISC;
! 1007:
! 1008: if (ifp->if_flags & IFF_ALLMULTI) {
! 1009: cr->htable3 = 0xffff;
! 1010: cr->htable2 = 0xffff;
! 1011: cr->htable1 = 0xffff;
! 1012: cr->htable0 = 0xffff;
! 1013: cr->rx_cfg |= CR_RXCFG_HENABLE;
! 1014: return;
! 1015: }
! 1016:
! 1017: hash[3] = hash[2] = hash[1] = hash[0] = 0;
! 1018:
! 1019: ETHER_FIRST_MULTI(step, ac, enm);
! 1020: while (enm != NULL) {
! 1021: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
! 1022: /*
! 1023: * We must listen to a range of multicast
! 1024: * addresses. For now, just accept all
! 1025: * multicasts, rather than trying to set only
! 1026: * those filter bits needed to match the range.
! 1027: * (At this time, the only use of address
! 1028: * ranges is for IP multicast routing, for
! 1029: * which the range is big enough to require
! 1030: * all bits set.)
! 1031: */
! 1032: cr->htable3 = 0xffff;
! 1033: cr->htable2 = 0xffff;
! 1034: cr->htable1 = 0xffff;
! 1035: cr->htable0 = 0xffff;
! 1036: cr->rx_cfg |= CR_RXCFG_HENABLE;
! 1037: ifp->if_flags |= IFF_ALLMULTI;
! 1038: return;
! 1039: }
! 1040:
! 1041: crc = 0xffffffff;
! 1042:
! 1043: for (i = 0; i < ETHER_ADDR_LEN; i++) {
! 1044: octet = enm->enm_addrlo[i];
! 1045:
! 1046: for (j = 0; j < 8; j++) {
! 1047: if ((crc & 1) ^ (octet & 1)) {
! 1048: crc >>= 1;
! 1049: crc ^= ETHER_CRC_POLY_LE;
! 1050: }
! 1051: else
! 1052: crc >>= 1;
! 1053: octet >>= 1;
! 1054: }
! 1055: }
! 1056:
! 1057: crc >>=26;
! 1058: hash[crc >> 4] |= 1 << (crc & 0xf);
! 1059: ETHER_NEXT_MULTI(step, enm);
! 1060: }
! 1061: cr->htable3 = hash[3];
! 1062: cr->htable2 = hash[2];
! 1063: cr->htable1 = hash[1];
! 1064: cr->htable0 = hash[0];
! 1065: cr->rx_cfg |= CR_RXCFG_HENABLE;
! 1066: ifp->if_flags &= ~IFF_ALLMULTI;
! 1067: }
! 1068:
! 1069: /*
! 1070: * Writing to the serial BitBang, is a matter of putting the bit
! 1071: * into the data register, then strobing the clock.
! 1072: */
! 1073: void
! 1074: hme_tcvr_bb_writeb(sc, b)
! 1075: struct hme_softc *sc;
! 1076: int b;
! 1077: {
! 1078: sc->sc_tcvr->bb_data = b & 0x1;
! 1079: sc->sc_tcvr->bb_clock = 0;
! 1080: sc->sc_tcvr->bb_clock = 1;
! 1081: }
! 1082:
! 1083: /*
! 1084: * Read a bit from a PHY, if the PHY is not our internal or external
! 1085: * phy addr, just return all zero's.
! 1086: */
! 1087: int
! 1088: hme_tcvr_bb_readb(sc, phy)
! 1089: struct hme_softc *sc;
! 1090: int phy;
! 1091: {
! 1092: int ret;
! 1093:
! 1094: sc->sc_tcvr->bb_clock = 0;
! 1095: DELAY(10);
! 1096:
! 1097: if (phy == TCVR_PHYADDR_ITX)
! 1098: ret = sc->sc_tcvr->cfg & TCVR_CFG_MDIO0;
! 1099: else if (phy == TCVR_PHYADDR_ETX)
! 1100: ret = sc->sc_tcvr->cfg & TCVR_CFG_MDIO1;
! 1101: else
! 1102: ret = 0;
! 1103:
! 1104: sc->sc_tcvr->bb_clock = 1;
! 1105:
! 1106: return ((ret) ? 1 : 0);
! 1107: }
! 1108:
! 1109: void
! 1110: hme_mii_write(self, phy, reg, val)
! 1111: struct device *self;
! 1112: int phy, reg, val;
! 1113: {
! 1114: struct hme_softc *sc = (struct hme_softc *)self;
! 1115: struct hme_tcvr *tcvr = sc->sc_tcvr;
! 1116: int tries = 16, i;
! 1117:
! 1118: if (sc->sc_flags & HME_FLAG_FENABLE) {
! 1119: tcvr->frame = (FRAME_WRITE | phy << 23) |
! 1120: ((reg & 0xff) << 18) | (val & 0xffff);
! 1121: while (!(tcvr->frame & 0x10000) && (tries != 0)) {
! 1122: tries--;
! 1123: DELAY(200);
! 1124: }
! 1125: if (!tries)
! 1126: printf("%s: mii_write failed\n", sc->sc_dev.dv_xname);
! 1127: return;
! 1128: }
! 1129:
! 1130: tcvr->bb_oenab = 1;
! 1131:
! 1132: for (i = 0; i < 32; i++)
! 1133: hme_tcvr_bb_writeb(sc, 1);
! 1134:
! 1135: hme_tcvr_bb_writeb(sc, (MII_COMMAND_START >> 1) & 1);
! 1136: hme_tcvr_bb_writeb(sc, MII_COMMAND_START & 1);
! 1137: hme_tcvr_bb_writeb(sc, (MII_COMMAND_WRITE >> 1) & 1);
! 1138: hme_tcvr_bb_writeb(sc, MII_COMMAND_WRITE & 1);
! 1139:
! 1140: for (i = 4; i >= 0; i--)
! 1141: hme_tcvr_bb_writeb(sc, (phy >> i) & 1);
! 1142:
! 1143: for (i = 4; i >= 0; i--)
! 1144: hme_tcvr_bb_writeb(sc, (reg >> i) & 1);
! 1145:
! 1146: for (i = 15; i >= 0; i--)
! 1147: hme_tcvr_bb_writeb(sc, (reg >> i) & 1);
! 1148:
! 1149: tcvr->bb_oenab = 0;
! 1150: }
! 1151:
! 1152: int
! 1153: hme_mii_read(self, phy, reg)
! 1154: struct device *self;
! 1155: int phy, reg;
! 1156: {
! 1157: struct hme_softc *sc = (struct hme_softc *)self;
! 1158: struct hme_tcvr *tcvr = sc->sc_tcvr;
! 1159: int tries = 16, i, ret = 0;
! 1160:
! 1161: /* Use the frame if possible */
! 1162: if (sc->sc_flags & HME_FLAG_FENABLE) {
! 1163: tcvr->frame = (FRAME_READ | phy << 23) |
! 1164: ((reg & 0xff) << 18);
! 1165: while (!(tcvr->frame & 0x10000) && (tries != 0)) {
! 1166: tries--;
! 1167: DELAY(20);
! 1168: }
! 1169: if (!tries) {
! 1170: printf("%s: mii_read failed\n", sc->sc_dev.dv_xname);
! 1171: return (0);
! 1172: }
! 1173: return (tcvr->frame & 0xffff);
! 1174: }
! 1175:
! 1176: tcvr->bb_oenab = 1;
! 1177:
! 1178: for (i = 0; i < 32; i++) /* make bitbang idle */
! 1179: hme_tcvr_bb_writeb(sc, 1);
! 1180:
! 1181: hme_tcvr_bb_writeb(sc, (MII_COMMAND_START >> 1) & 1);
! 1182: hme_tcvr_bb_writeb(sc, MII_COMMAND_START & 1);
! 1183: hme_tcvr_bb_writeb(sc, (MII_COMMAND_READ >> 1) & 1);
! 1184: hme_tcvr_bb_writeb(sc, MII_COMMAND_READ & 1);
! 1185:
! 1186: for (i = 4; i >= 0; i--)
! 1187: hme_tcvr_bb_writeb(sc, (phy >> i) & 1);
! 1188:
! 1189: for (i = 4; i >= 0; i--)
! 1190: hme_tcvr_bb_writeb(sc, (reg >> i) & 1);
! 1191:
! 1192: tcvr->bb_oenab = 0; /* turn off bitbang intrs */
! 1193:
! 1194: hme_tcvr_bb_readb(sc, phy); /* ignore... */
! 1195:
! 1196: for (i = 15; i >= 15; i--) /* read value */
! 1197: ret |= hme_tcvr_bb_readb(sc, phy) << i;
! 1198:
! 1199: hme_tcvr_bb_readb(sc, phy); /* ignore... */
! 1200: hme_tcvr_bb_readb(sc, phy); /* ignore... */
! 1201: hme_tcvr_bb_readb(sc, phy); /* ignore... */
! 1202:
! 1203: return (ret);
! 1204: }
! 1205:
! 1206: int
! 1207: hme_mediachange(ifp)
! 1208: struct ifnet *ifp;
! 1209: {
! 1210: if (ifp->if_flags & IFF_UP)
! 1211: hmeinit(ifp->if_softc);
! 1212: return (0);
! 1213: }
! 1214:
! 1215: void
! 1216: hme_mediastatus(ifp, ifmr)
! 1217: struct ifnet *ifp;
! 1218: struct ifmediareq *ifmr;
! 1219: {
! 1220: struct hme_softc *sc = (struct hme_softc *)ifp->if_softc;
! 1221:
! 1222: mii_pollstat(&sc->sc_mii);
! 1223: ifmr->ifm_active = sc->sc_mii.mii_media_active;
! 1224: ifmr->ifm_status = sc->sc_mii.mii_media_status;
! 1225: }
! 1226:
! 1227: void
! 1228: hme_mii_statchg(self)
! 1229: struct device *self;
! 1230: {
! 1231: struct hme_softc *sc = (struct hme_softc *)self;
! 1232: struct hme_cr *cr = sc->sc_cr;
! 1233:
! 1234: /* Apparently the hme chip is SIMPLEX if working in full duplex mode,
! 1235: but not otherwise. */
! 1236: if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0) {
! 1237: cr->tx_cfg |= CR_TXCFG_FULLDPLX;
! 1238: sc->sc_arpcom.ac_if.if_flags |= IFF_SIMPLEX;
! 1239: } else {
! 1240: cr->tx_cfg &= ~CR_TXCFG_FULLDPLX;
! 1241: sc->sc_arpcom.ac_if.if_flags &= ~IFF_SIMPLEX;
! 1242: }
! 1243: sc->sc_if_flags = sc->sc_arpcom.ac_if.if_flags;
! 1244: }
CVSweb