Annotation of sys/dev/ic/hme.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hme.c,v 1.46 2006/12/21 22:13:36 jason Exp $ */
! 2: /* $NetBSD: hme.c,v 1.21 2001/07/07 15:59:37 thorpej Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1999 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Paul Kranenburg.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * HME Ethernet module driver.
! 42: */
! 43:
! 44: #include "bpfilter.h"
! 45: #include "vlan.h"
! 46:
! 47: #undef HMEDEBUG
! 48:
! 49: #include <sys/param.h>
! 50: #include <sys/systm.h>
! 51: #include <sys/kernel.h>
! 52: #include <sys/mbuf.h>
! 53: #include <sys/syslog.h>
! 54: #include <sys/socket.h>
! 55: #include <sys/device.h>
! 56: #include <sys/malloc.h>
! 57: #include <sys/ioctl.h>
! 58: #include <sys/errno.h>
! 59:
! 60: #include <net/if.h>
! 61: #include <net/if_dl.h>
! 62: #include <net/if_media.h>
! 63:
! 64: #ifdef INET
! 65: #include <netinet/in.h>
! 66: #include <netinet/in_systm.h>
! 67: #include <netinet/in_var.h>
! 68: #include <netinet/ip.h>
! 69: #include <netinet/if_ether.h>
! 70: #include <netinet/tcp.h>
! 71: #include <netinet/udp.h>
! 72: #endif
! 73:
! 74: #if NBPFILTER > 0
! 75: #include <net/bpf.h>
! 76: #endif
! 77:
! 78: #include <dev/mii/mii.h>
! 79: #include <dev/mii/miivar.h>
! 80:
! 81: #include <machine/bus.h>
! 82:
! 83: #include <dev/ic/hmereg.h>
! 84: #include <dev/ic/hmevar.h>
! 85:
! 86: struct cfdriver hme_cd = {
! 87: NULL, "hme", DV_IFNET
! 88: };
! 89:
! 90: #define HME_RX_OFFSET 2
! 91:
! 92: void hme_start(struct ifnet *);
! 93: void hme_stop(struct hme_softc *);
! 94: int hme_ioctl(struct ifnet *, u_long, caddr_t);
! 95: void hme_tick(void *);
! 96: void hme_watchdog(struct ifnet *);
! 97: void hme_shutdown(void *);
! 98: void hme_init(struct hme_softc *);
! 99: void hme_meminit(struct hme_softc *);
! 100: void hme_mifinit(struct hme_softc *);
! 101: void hme_reset(struct hme_softc *);
! 102: void hme_setladrf(struct hme_softc *);
! 103: int hme_newbuf(struct hme_softc *, struct hme_sxd *, int);
! 104: int hme_encap(struct hme_softc *, struct mbuf *, int *);
! 105:
! 106: /* MII methods & callbacks */
! 107: static int hme_mii_readreg(struct device *, int, int);
! 108: static void hme_mii_writereg(struct device *, int, int, int);
! 109: static void hme_mii_statchg(struct device *);
! 110:
! 111: int hme_mediachange(struct ifnet *);
! 112: void hme_mediastatus(struct ifnet *, struct ifmediareq *);
! 113:
! 114: int hme_eint(struct hme_softc *, u_int);
! 115: int hme_rint(struct hme_softc *);
! 116: int hme_tint(struct hme_softc *);
! 117: /* TCP/UDP checksum offload support */
! 118: void hme_rxcksum(struct mbuf *, u_int32_t);
! 119:
! 120: void
! 121: hme_config(sc)
! 122: struct hme_softc *sc;
! 123: {
! 124: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 125: struct mii_data *mii = &sc->sc_mii;
! 126: struct mii_softc *child;
! 127: bus_dma_tag_t dmatag = sc->sc_dmatag;
! 128: bus_dma_segment_t seg;
! 129: bus_size_t size;
! 130: int rseg, error, i;
! 131:
! 132: /*
! 133: * HME common initialization.
! 134: *
! 135: * hme_softc fields that must be initialized by the front-end:
! 136: *
! 137: * the bus tag:
! 138: * sc_bustag
! 139: *
! 140: * the dma bus tag:
! 141: * sc_dmatag
! 142: *
! 143: * the bus handles:
! 144: * sc_seb (Shared Ethernet Block registers)
! 145: * sc_erx (Receiver Unit registers)
! 146: * sc_etx (Transmitter Unit registers)
! 147: * sc_mac (MAC registers)
! 148: * sc_mif (Management Interface registers)
! 149: *
! 150: * the maximum bus burst size:
! 151: * sc_burst
! 152: *
! 153: * the local Ethernet address:
! 154: * sc_arpcom.ac_enaddr
! 155: *
! 156: */
! 157:
! 158: /* Make sure the chip is stopped. */
! 159: hme_stop(sc);
! 160:
! 161: for (i = 0; i < HME_TX_RING_SIZE; i++) {
! 162: if (bus_dmamap_create(sc->sc_dmatag, MCLBYTES, 1,
! 163: MCLBYTES, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
! 164: &sc->sc_txd[i].sd_map) != 0) {
! 165: sc->sc_txd[i].sd_map = NULL;
! 166: goto fail;
! 167: }
! 168: }
! 169: for (i = 0; i < HME_RX_RING_SIZE; i++) {
! 170: if (bus_dmamap_create(sc->sc_dmatag, MCLBYTES, 1,
! 171: MCLBYTES, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
! 172: &sc->sc_rxd[i].sd_map) != 0) {
! 173: sc->sc_rxd[i].sd_map = NULL;
! 174: goto fail;
! 175: }
! 176: }
! 177: if (bus_dmamap_create(sc->sc_dmatag, MCLBYTES, 1, MCLBYTES, 0,
! 178: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_rxmap_spare) != 0) {
! 179: sc->sc_rxmap_spare = NULL;
! 180: goto fail;
! 181: }
! 182:
! 183: /*
! 184: * Allocate DMA capable memory
! 185: * Buffer descriptors must be aligned on a 2048 byte boundary;
! 186: * take this into account when calculating the size. Note that
! 187: * the maximum number of descriptors (256) occupies 2048 bytes,
! 188: * so we allocate that much regardless of the number of descriptors.
! 189: */
! 190: size = (HME_XD_SIZE * HME_RX_RING_MAX) + /* RX descriptors */
! 191: (HME_XD_SIZE * HME_TX_RING_MAX); /* TX descriptors */
! 192:
! 193: /* Allocate DMA buffer */
! 194: if ((error = bus_dmamem_alloc(dmatag, size, 2048, 0, &seg, 1, &rseg,
! 195: BUS_DMA_NOWAIT)) != 0) {
! 196: printf("\n%s: DMA buffer alloc error %d\n",
! 197: sc->sc_dev.dv_xname, error);
! 198: return;
! 199: }
! 200:
! 201: /* Map DMA memory in CPU addressable space */
! 202: if ((error = bus_dmamem_map(dmatag, &seg, rseg, size,
! 203: &sc->sc_rb.rb_membase, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
! 204: printf("\n%s: DMA buffer map error %d\n",
! 205: sc->sc_dev.dv_xname, error);
! 206: bus_dmamap_unload(dmatag, sc->sc_dmamap);
! 207: bus_dmamem_free(dmatag, &seg, rseg);
! 208: return;
! 209: }
! 210:
! 211: if ((error = bus_dmamap_create(dmatag, size, 1, size, 0,
! 212: BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
! 213: printf("\n%s: DMA map create error %d\n",
! 214: sc->sc_dev.dv_xname, error);
! 215: return;
! 216: }
! 217:
! 218: /* Load the buffer */
! 219: if ((error = bus_dmamap_load(dmatag, sc->sc_dmamap,
! 220: sc->sc_rb.rb_membase, size, NULL,
! 221: BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
! 222: printf("\n%s: DMA buffer map load error %d\n",
! 223: sc->sc_dev.dv_xname, error);
! 224: bus_dmamem_free(dmatag, &seg, rseg);
! 225: return;
! 226: }
! 227: sc->sc_rb.rb_dmabase = sc->sc_dmamap->dm_segs[0].ds_addr;
! 228:
! 229: printf(", address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
! 230:
! 231: /* Initialize ifnet structure. */
! 232: strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, sizeof ifp->if_xname);
! 233: ifp->if_softc = sc;
! 234: ifp->if_start = hme_start;
! 235: ifp->if_ioctl = hme_ioctl;
! 236: ifp->if_watchdog = hme_watchdog;
! 237: ifp->if_flags =
! 238: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
! 239: sc->sc_if_flags = ifp->if_flags;
! 240: IFQ_SET_READY(&ifp->if_snd);
! 241: ifp->if_capabilities = IFCAP_VLAN_MTU;
! 242:
! 243: /* Initialize ifmedia structures and MII info */
! 244: mii->mii_ifp = ifp;
! 245: mii->mii_readreg = hme_mii_readreg;
! 246: mii->mii_writereg = hme_mii_writereg;
! 247: mii->mii_statchg = hme_mii_statchg;
! 248:
! 249: ifmedia_init(&mii->mii_media, IFM_IMASK,
! 250: hme_mediachange, hme_mediastatus);
! 251:
! 252: hme_mifinit(sc);
! 253:
! 254: if (sc->sc_tcvr == -1)
! 255: mii_attach(&sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY,
! 256: MII_OFFSET_ANY, 0);
! 257: else
! 258: mii_attach(&sc->sc_dev, mii, 0xffffffff, sc->sc_tcvr,
! 259: MII_OFFSET_ANY, 0);
! 260:
! 261: child = LIST_FIRST(&mii->mii_phys);
! 262: if (child == NULL) {
! 263: /* No PHY attached */
! 264: ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
! 265: ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
! 266: } else {
! 267: /*
! 268: * Walk along the list of attached MII devices and
! 269: * establish an `MII instance' to `phy number'
! 270: * mapping. We'll use this mapping in media change
! 271: * requests to determine which phy to use to program
! 272: * the MIF configuration register.
! 273: */
! 274: for (; child != NULL; child = LIST_NEXT(child, mii_list)) {
! 275: /*
! 276: * Note: we support just two PHYs: the built-in
! 277: * internal device and an external on the MII
! 278: * connector.
! 279: */
! 280: if (child->mii_phy > 1 || child->mii_inst > 1) {
! 281: printf("%s: cannot accommodate MII device %s"
! 282: " at phy %d, instance %d\n",
! 283: sc->sc_dev.dv_xname,
! 284: child->mii_dev.dv_xname,
! 285: child->mii_phy, child->mii_inst);
! 286: continue;
! 287: }
! 288:
! 289: sc->sc_phys[child->mii_inst] = child->mii_phy;
! 290: }
! 291:
! 292: /*
! 293: * XXX - we can really do the following ONLY if the
! 294: * phy indeed has the auto negotiation capability!!
! 295: */
! 296: ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO);
! 297: }
! 298:
! 299: /* Attach the interface. */
! 300: if_attach(ifp);
! 301: ether_ifattach(ifp);
! 302:
! 303: sc->sc_sh = shutdownhook_establish(hme_shutdown, sc);
! 304: if (sc->sc_sh == NULL)
! 305: panic("hme_config: can't establish shutdownhook");
! 306:
! 307: timeout_set(&sc->sc_tick_ch, hme_tick, sc);
! 308: return;
! 309:
! 310: fail:
! 311: if (sc->sc_rxmap_spare != NULL)
! 312: bus_dmamap_destroy(sc->sc_dmatag, sc->sc_rxmap_spare);
! 313: for (i = 0; i < HME_TX_RING_SIZE; i++)
! 314: if (sc->sc_txd[i].sd_map != NULL)
! 315: bus_dmamap_destroy(sc->sc_dmatag, sc->sc_txd[i].sd_map);
! 316: for (i = 0; i < HME_RX_RING_SIZE; i++)
! 317: if (sc->sc_rxd[i].sd_map != NULL)
! 318: bus_dmamap_destroy(sc->sc_dmatag, sc->sc_rxd[i].sd_map);
! 319: }
! 320:
! 321: void
! 322: hme_tick(arg)
! 323: void *arg;
! 324: {
! 325: struct hme_softc *sc = arg;
! 326: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 327: bus_space_tag_t t = sc->sc_bustag;
! 328: bus_space_handle_t mac = sc->sc_mac;
! 329: int s;
! 330:
! 331: s = splnet();
! 332: /*
! 333: * Unload collision counters
! 334: */
! 335: ifp->if_collisions +=
! 336: bus_space_read_4(t, mac, HME_MACI_NCCNT) +
! 337: bus_space_read_4(t, mac, HME_MACI_FCCNT) +
! 338: bus_space_read_4(t, mac, HME_MACI_EXCNT) +
! 339: bus_space_read_4(t, mac, HME_MACI_LTCNT);
! 340:
! 341: /*
! 342: * then clear the hardware counters.
! 343: */
! 344: bus_space_write_4(t, mac, HME_MACI_NCCNT, 0);
! 345: bus_space_write_4(t, mac, HME_MACI_FCCNT, 0);
! 346: bus_space_write_4(t, mac, HME_MACI_EXCNT, 0);
! 347: bus_space_write_4(t, mac, HME_MACI_LTCNT, 0);
! 348:
! 349: mii_tick(&sc->sc_mii);
! 350: splx(s);
! 351:
! 352: timeout_add(&sc->sc_tick_ch, hz);
! 353: }
! 354:
! 355: void
! 356: hme_reset(sc)
! 357: struct hme_softc *sc;
! 358: {
! 359: int s;
! 360:
! 361: s = splnet();
! 362: hme_init(sc);
! 363: splx(s);
! 364: }
! 365:
! 366: void
! 367: hme_stop(sc)
! 368: struct hme_softc *sc;
! 369: {
! 370: bus_space_tag_t t = sc->sc_bustag;
! 371: bus_space_handle_t seb = sc->sc_seb;
! 372: int n;
! 373:
! 374: timeout_del(&sc->sc_tick_ch);
! 375: mii_down(&sc->sc_mii);
! 376:
! 377: /* Mask all interrupts */
! 378: bus_space_write_4(t, seb, HME_SEBI_IMASK, 0xffffffff);
! 379:
! 380: /* Reset transmitter and receiver */
! 381: bus_space_write_4(t, seb, HME_SEBI_RESET,
! 382: (HME_SEB_RESET_ETX | HME_SEB_RESET_ERX));
! 383:
! 384: for (n = 0; n < 20; n++) {
! 385: u_int32_t v = bus_space_read_4(t, seb, HME_SEBI_RESET);
! 386: if ((v & (HME_SEB_RESET_ETX | HME_SEB_RESET_ERX)) == 0)
! 387: break;
! 388: DELAY(20);
! 389: }
! 390: if (n >= 20)
! 391: printf("%s: hme_stop: reset failed\n", sc->sc_dev.dv_xname);
! 392:
! 393: for (n = 0; n < HME_TX_RING_SIZE; n++) {
! 394: if (sc->sc_txd[n].sd_loaded) {
! 395: bus_dmamap_sync(sc->sc_dmatag, sc->sc_txd[n].sd_map,
! 396: 0, sc->sc_txd[n].sd_map->dm_mapsize,
! 397: BUS_DMASYNC_POSTWRITE);
! 398: bus_dmamap_unload(sc->sc_dmatag, sc->sc_txd[n].sd_map);
! 399: sc->sc_txd[n].sd_loaded = 0;
! 400: }
! 401: if (sc->sc_txd[n].sd_mbuf != NULL) {
! 402: m_freem(sc->sc_txd[n].sd_mbuf);
! 403: sc->sc_txd[n].sd_mbuf = NULL;
! 404: }
! 405: }
! 406: }
! 407:
! 408: void
! 409: hme_meminit(sc)
! 410: struct hme_softc *sc;
! 411: {
! 412: bus_addr_t dma;
! 413: caddr_t p;
! 414: unsigned int i;
! 415: struct hme_ring *hr = &sc->sc_rb;
! 416:
! 417: p = hr->rb_membase;
! 418: dma = hr->rb_dmabase;
! 419:
! 420: /*
! 421: * Allocate transmit descriptors
! 422: */
! 423: hr->rb_txd = p;
! 424: hr->rb_txddma = dma;
! 425: p += HME_TX_RING_SIZE * HME_XD_SIZE;
! 426: dma += HME_TX_RING_SIZE * HME_XD_SIZE;
! 427: /* We have reserved descriptor space until the next 2048 byte boundary.*/
! 428: dma = (bus_addr_t)roundup((u_long)dma, 2048);
! 429: p = (caddr_t)roundup((u_long)p, 2048);
! 430:
! 431: /*
! 432: * Allocate receive descriptors
! 433: */
! 434: hr->rb_rxd = p;
! 435: hr->rb_rxddma = dma;
! 436: p += HME_RX_RING_SIZE * HME_XD_SIZE;
! 437: dma += HME_RX_RING_SIZE * HME_XD_SIZE;
! 438: /* Again move forward to the next 2048 byte boundary.*/
! 439: dma = (bus_addr_t)roundup((u_long)dma, 2048);
! 440: p = (caddr_t)roundup((u_long)p, 2048);
! 441:
! 442: /*
! 443: * Initialize transmit descriptors
! 444: */
! 445: for (i = 0; i < HME_TX_RING_SIZE; i++) {
! 446: HME_XD_SETADDR(sc->sc_pci, hr->rb_txd, i, 0);
! 447: HME_XD_SETFLAGS(sc->sc_pci, hr->rb_txd, i, 0);
! 448: sc->sc_txd[i].sd_mbuf = NULL;
! 449: }
! 450:
! 451: /*
! 452: * Initialize receive descriptors
! 453: */
! 454: for (i = 0; i < HME_RX_RING_SIZE; i++) {
! 455: if (hme_newbuf(sc, &sc->sc_rxd[i], 1)) {
! 456: printf("%s: rx allocation failed\n",
! 457: sc->sc_dev.dv_xname);
! 458: break;
! 459: }
! 460: HME_XD_SETADDR(sc->sc_pci, hr->rb_rxd, i,
! 461: sc->sc_rxd[i].sd_map->dm_segs[0].ds_addr);
! 462: HME_XD_SETFLAGS(sc->sc_pci, hr->rb_rxd, i,
! 463: HME_XD_OWN | HME_XD_ENCODE_RSIZE(HME_RX_PKTSIZE));
! 464: }
! 465:
! 466: sc->sc_tx_prod = sc->sc_tx_cons = sc->sc_tx_cnt = 0;
! 467: sc->sc_last_rd = 0;
! 468: }
! 469:
! 470: /*
! 471: * Initialization of interface; set up initialization block
! 472: * and transmit/receive descriptor rings.
! 473: */
! 474: void
! 475: hme_init(sc)
! 476: struct hme_softc *sc;
! 477: {
! 478: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 479: bus_space_tag_t t = sc->sc_bustag;
! 480: bus_space_handle_t seb = sc->sc_seb;
! 481: bus_space_handle_t etx = sc->sc_etx;
! 482: bus_space_handle_t erx = sc->sc_erx;
! 483: bus_space_handle_t mac = sc->sc_mac;
! 484: u_int8_t *ea;
! 485: u_int32_t v, n;
! 486:
! 487: /*
! 488: * Initialization sequence. The numbered steps below correspond
! 489: * to the sequence outlined in section 6.3.5.1 in the Ethernet
! 490: * Channel Engine manual (part of the PCIO manual).
! 491: * See also the STP2002-STQ document from Sun Microsystems.
! 492: */
! 493:
! 494: /* step 1 & 2. Reset the Ethernet Channel */
! 495: hme_stop(sc);
! 496:
! 497: /* Re-initialize the MIF */
! 498: hme_mifinit(sc);
! 499:
! 500: /* Call MI reset function if any */
! 501: if (sc->sc_hwreset)
! 502: (*sc->sc_hwreset)(sc);
! 503:
! 504: #if 0
! 505: /* Mask all MIF interrupts, just in case */
! 506: bus_space_write_4(t, mif, HME_MIFI_IMASK, 0xffff);
! 507: #endif
! 508:
! 509: /* step 3. Setup data structures in host memory */
! 510: hme_meminit(sc);
! 511:
! 512: /* step 4. TX MAC registers & counters */
! 513: bus_space_write_4(t, mac, HME_MACI_NCCNT, 0);
! 514: bus_space_write_4(t, mac, HME_MACI_FCCNT, 0);
! 515: bus_space_write_4(t, mac, HME_MACI_EXCNT, 0);
! 516: bus_space_write_4(t, mac, HME_MACI_LTCNT, 0);
! 517: bus_space_write_4(t, mac, HME_MACI_TXSIZE, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
! 518:
! 519: /* Load station MAC address */
! 520: ea = sc->sc_arpcom.ac_enaddr;
! 521: bus_space_write_4(t, mac, HME_MACI_MACADDR0, (ea[0] << 8) | ea[1]);
! 522: bus_space_write_4(t, mac, HME_MACI_MACADDR1, (ea[2] << 8) | ea[3]);
! 523: bus_space_write_4(t, mac, HME_MACI_MACADDR2, (ea[4] << 8) | ea[5]);
! 524:
! 525: /*
! 526: * Init seed for backoff
! 527: * (source suggested by manual: low 10 bits of MAC address)
! 528: */
! 529: v = ((ea[4] << 8) | ea[5]) & 0x3fff;
! 530: bus_space_write_4(t, mac, HME_MACI_RANDSEED, v);
! 531:
! 532:
! 533: /* Note: Accepting power-on default for other MAC registers here.. */
! 534:
! 535:
! 536: /* step 5. RX MAC registers & counters */
! 537: hme_setladrf(sc);
! 538:
! 539: /* step 6 & 7. Program Descriptor Ring Base Addresses */
! 540: bus_space_write_4(t, etx, HME_ETXI_RING, sc->sc_rb.rb_txddma);
! 541: bus_space_write_4(t, etx, HME_ETXI_RSIZE, HME_TX_RING_SIZE);
! 542:
! 543: bus_space_write_4(t, erx, HME_ERXI_RING, sc->sc_rb.rb_rxddma);
! 544: bus_space_write_4(t, mac, HME_MACI_RXSIZE, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
! 545:
! 546: /* step 8. Global Configuration & Interrupt Mask */
! 547: bus_space_write_4(t, seb, HME_SEBI_IMASK,
! 548: ~(HME_SEB_STAT_HOSTTOTX | HME_SEB_STAT_RXTOHOST |
! 549: HME_SEB_STAT_TXALL | HME_SEB_STAT_TXPERR |
! 550: HME_SEB_STAT_RCNTEXP | HME_SEB_STAT_ALL_ERRORS));
! 551:
! 552: switch (sc->sc_burst) {
! 553: default:
! 554: v = 0;
! 555: break;
! 556: case 16:
! 557: v = HME_SEB_CFG_BURST16;
! 558: break;
! 559: case 32:
! 560: v = HME_SEB_CFG_BURST32;
! 561: break;
! 562: case 64:
! 563: v = HME_SEB_CFG_BURST64;
! 564: break;
! 565: }
! 566: bus_space_write_4(t, seb, HME_SEBI_CFG, v);
! 567:
! 568: /* step 9. ETX Configuration: use mostly default values */
! 569:
! 570: /* Enable DMA */
! 571: v = bus_space_read_4(t, etx, HME_ETXI_CFG);
! 572: v |= HME_ETX_CFG_DMAENABLE;
! 573: bus_space_write_4(t, etx, HME_ETXI_CFG, v);
! 574:
! 575: /* Transmit Descriptor ring size: in increments of 16 */
! 576: bus_space_write_4(t, etx, HME_ETXI_RSIZE, HME_TX_RING_SIZE / 16 - 1);
! 577:
! 578: /* step 10. ERX Configuration */
! 579: v = bus_space_read_4(t, erx, HME_ERXI_CFG);
! 580: v &= ~HME_ERX_CFG_RINGSIZE256;
! 581: #if HME_RX_RING_SIZE == 32
! 582: v |= HME_ERX_CFG_RINGSIZE32;
! 583: #elif HME_RX_RING_SIZE == 64
! 584: v |= HME_ERX_CFG_RINGSIZE64;
! 585: #elif HME_RX_RING_SIZE == 128
! 586: v |= HME_ERX_CFG_RINGSIZE128;
! 587: #elif HME_RX_RING_SIZE == 256
! 588: v |= HME_ERX_CFG_RINGSIZE256;
! 589: #else
! 590: # error "RX ring size must be 32, 64, 128, or 256"
! 591: #endif
! 592: /* Enable DMA */
! 593: v |= HME_ERX_CFG_DMAENABLE | (HME_RX_OFFSET << 3);
! 594: /* RX TCP/UDP cksum offset */
! 595: n = (ETHER_HDR_LEN + sizeof(struct ip)) / 2;
! 596: n = (n << HME_ERX_CFG_CSUM_SHIFT) & HME_ERX_CFG_CSUMSTART;
! 597: v |= n;
! 598: bus_space_write_4(t, erx, HME_ERXI_CFG, v);
! 599:
! 600: /* step 11. XIF Configuration */
! 601: v = bus_space_read_4(t, mac, HME_MACI_XIF);
! 602: v |= HME_MAC_XIF_OE;
! 603: bus_space_write_4(t, mac, HME_MACI_XIF, v);
! 604:
! 605: /* step 12. RX_MAC Configuration Register */
! 606: v = bus_space_read_4(t, mac, HME_MACI_RXCFG);
! 607: v |= HME_MAC_RXCFG_ENABLE;
! 608: bus_space_write_4(t, mac, HME_MACI_RXCFG, v);
! 609:
! 610: /* step 13. TX_MAC Configuration Register */
! 611: v = bus_space_read_4(t, mac, HME_MACI_TXCFG);
! 612: v |= (HME_MAC_TXCFG_ENABLE | HME_MAC_TXCFG_DGIVEUP);
! 613: bus_space_write_4(t, mac, HME_MACI_TXCFG, v);
! 614:
! 615: /* step 14. Issue Transmit Pending command */
! 616:
! 617: /* Call MI initialization function if any */
! 618: if (sc->sc_hwinit)
! 619: (*sc->sc_hwinit)(sc);
! 620:
! 621: /* Set the current media. */
! 622: mii_mediachg(&sc->sc_mii);
! 623:
! 624: /* Start the one second timer. */
! 625: timeout_add(&sc->sc_tick_ch, hz);
! 626:
! 627: ifp->if_flags |= IFF_RUNNING;
! 628: ifp->if_flags &= ~IFF_OACTIVE;
! 629: sc->sc_if_flags = ifp->if_flags;
! 630: ifp->if_timer = 0;
! 631: hme_start(ifp);
! 632: }
! 633:
! 634: void
! 635: hme_start(ifp)
! 636: struct ifnet *ifp;
! 637: {
! 638: struct hme_softc *sc = (struct hme_softc *)ifp->if_softc;
! 639: struct mbuf *m;
! 640: int bix, cnt = 0;
! 641:
! 642: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 643: return;
! 644:
! 645: bix = sc->sc_tx_prod;
! 646: while (sc->sc_txd[bix].sd_mbuf == NULL) {
! 647: IFQ_POLL(&ifp->if_snd, m);
! 648: if (m == NULL)
! 649: break;
! 650:
! 651: #if NBPFILTER > 0
! 652: /*
! 653: * If BPF is listening on this interface, let it see the
! 654: * packet before we commit it to the wire.
! 655: */
! 656: if (ifp->if_bpf)
! 657: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 658: #endif
! 659:
! 660: if (hme_encap(sc, m, &bix)) {
! 661: ifp->if_flags |= IFF_OACTIVE;
! 662: break;
! 663: }
! 664:
! 665: IFQ_DEQUEUE(&ifp->if_snd, m);
! 666:
! 667: bus_space_write_4(sc->sc_bustag, sc->sc_etx, HME_ETXI_PENDING,
! 668: HME_ETX_TP_DMAWAKEUP);
! 669: cnt++;
! 670: }
! 671:
! 672: if (cnt != 0) {
! 673: sc->sc_tx_prod = bix;
! 674: ifp->if_timer = 5;
! 675: }
! 676: }
! 677:
! 678: /*
! 679: * Transmit interrupt.
! 680: */
! 681: int
! 682: hme_tint(sc)
! 683: struct hme_softc *sc;
! 684: {
! 685: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 686: unsigned int ri, txflags;
! 687: struct hme_sxd *sd;
! 688: int cnt = sc->sc_tx_cnt;
! 689:
! 690: /* Fetch current position in the transmit ring */
! 691: ri = sc->sc_tx_cons;
! 692: sd = &sc->sc_txd[ri];
! 693:
! 694: for (;;) {
! 695: if (cnt <= 0)
! 696: break;
! 697:
! 698: txflags = HME_XD_GETFLAGS(sc->sc_pci, sc->sc_rb.rb_txd, ri);
! 699:
! 700: if (txflags & HME_XD_OWN)
! 701: break;
! 702:
! 703: ifp->if_flags &= ~IFF_OACTIVE;
! 704: if (txflags & HME_XD_EOP)
! 705: ifp->if_opackets++;
! 706:
! 707: bus_dmamap_sync(sc->sc_dmatag, sd->sd_map,
! 708: 0, sd->sd_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
! 709: bus_dmamap_unload(sc->sc_dmatag, sd->sd_map);
! 710: sd->sd_loaded = 0;
! 711:
! 712: if (sd->sd_mbuf != NULL) {
! 713: m_freem(sd->sd_mbuf);
! 714: sd->sd_mbuf = NULL;
! 715: }
! 716:
! 717: if (++ri == HME_TX_RING_SIZE) {
! 718: ri = 0;
! 719: sd = sc->sc_txd;
! 720: } else
! 721: sd++;
! 722:
! 723: --cnt;
! 724: }
! 725:
! 726: sc->sc_tx_cnt = cnt;
! 727: ifp->if_timer = cnt > 0 ? 5 : 0;
! 728:
! 729: /* Update ring */
! 730: sc->sc_tx_cons = ri;
! 731:
! 732: hme_start(ifp);
! 733:
! 734: return (1);
! 735: }
! 736:
! 737: /*
! 738: * XXX layering violation
! 739: *
! 740: * If we can have additional csum data member in 'struct pkthdr' for
! 741: * these incomplete checksum offload capable hardware, things would be
! 742: * much simpler. That member variable will carry partial checksum
! 743: * data and it may be evaluated in TCP/UDP input handler after
! 744: * computing pseudo header checksumming.
! 745: */
! 746: void
! 747: hme_rxcksum(struct mbuf *m, u_int32_t flags)
! 748: {
! 749: struct ether_header *eh;
! 750: struct ip *ip;
! 751: struct udphdr *uh;
! 752: int32_t hlen, len, pktlen;
! 753: u_int16_t cksum, *opts;
! 754: u_int32_t temp32;
! 755: union pseudoh {
! 756: struct hdr {
! 757: u_int16_t len;
! 758: u_int8_t ttl;
! 759: u_int8_t proto;
! 760: u_int32_t src;
! 761: u_int32_t dst;
! 762: } h;
! 763: u_int16_t w[6];
! 764: } ph;
! 765:
! 766: pktlen = m->m_pkthdr.len;
! 767: if (pktlen < sizeof(struct ether_header))
! 768: return;
! 769: eh = mtod(m, struct ether_header *);
! 770: if (eh->ether_type != htons(ETHERTYPE_IP))
! 771: return;
! 772: ip = (struct ip *)(eh + 1);
! 773: if (ip->ip_v != IPVERSION)
! 774: return;
! 775:
! 776: hlen = ip->ip_hl << 2;
! 777: pktlen -= sizeof(struct ether_header);
! 778: if (hlen < sizeof(struct ip))
! 779: return;
! 780: if (ntohs(ip->ip_len) < hlen)
! 781: return;
! 782: if (ntohs(ip->ip_len) != pktlen)
! 783: return;
! 784: if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
! 785: return; /* can't handle fragmented packet */
! 786:
! 787: switch (ip->ip_p) {
! 788: case IPPROTO_TCP:
! 789: if (pktlen < (hlen + sizeof(struct tcphdr)))
! 790: return;
! 791: break;
! 792: case IPPROTO_UDP:
! 793: if (pktlen < (hlen + sizeof(struct udphdr)))
! 794: return;
! 795: uh = (struct udphdr *)((caddr_t)ip + hlen);
! 796: if (uh->uh_sum == 0)
! 797: return; /* no checksum */
! 798: break;
! 799: default:
! 800: return;
! 801: }
! 802:
! 803: cksum = htons(~(flags & HME_XD_RXCKSUM));
! 804: /* cksum fixup for IP options */
! 805: len = hlen - sizeof(struct ip);
! 806: if (len > 0) {
! 807: opts = (u_int16_t *)(ip + 1);
! 808: for (; len > 0; len -= sizeof(u_int16_t), opts++) {
! 809: temp32 = cksum - *opts;
! 810: temp32 = (temp32 >> 16) + (temp32 & 65535);
! 811: cksum = temp32 & 65535;
! 812: }
! 813: }
! 814: /* cksum fixup for pseudo-header, replace with in_cksum_phdr()? */
! 815: ph.h.len = htons(ntohs(ip->ip_len) - hlen);
! 816: ph.h.ttl = 0;
! 817: ph.h.proto = ip->ip_p;
! 818: ph.h.src = ip->ip_src.s_addr;
! 819: ph.h.dst = ip->ip_dst.s_addr;
! 820: temp32 = cksum;
! 821: opts = &ph.w[0];
! 822: temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5];
! 823: temp32 = (temp32 >> 16) + (temp32 & 65535);
! 824: temp32 += (temp32 >> 16);
! 825: cksum = ~temp32;
! 826: if (cksum == 0) {
! 827: m->m_pkthdr.csum_flags |=
! 828: M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
! 829: }
! 830: }
! 831:
! 832: /*
! 833: * Receive interrupt.
! 834: */
! 835: int
! 836: hme_rint(sc)
! 837: struct hme_softc *sc;
! 838: {
! 839: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 840: struct mbuf *m;
! 841: struct hme_sxd *sd;
! 842: unsigned int ri, len;
! 843: u_int32_t flags;
! 844:
! 845: ri = sc->sc_last_rd;
! 846: sd = &sc->sc_rxd[ri];
! 847:
! 848: /*
! 849: * Process all buffers with valid data.
! 850: */
! 851: for (;;) {
! 852: flags = HME_XD_GETFLAGS(sc->sc_pci, sc->sc_rb.rb_rxd, ri);
! 853: if (flags & HME_XD_OWN)
! 854: break;
! 855:
! 856: if (flags & HME_XD_OFL) {
! 857: printf("%s: buffer overflow, ri=%d; flags=0x%x\n",
! 858: sc->sc_dev.dv_xname, ri, flags);
! 859: goto again;
! 860: }
! 861:
! 862: m = sd->sd_mbuf;
! 863: len = HME_XD_DECODE_RSIZE(flags);
! 864: m->m_pkthdr.len = m->m_len = len;
! 865:
! 866: if (hme_newbuf(sc, sd, 0)) {
! 867: /*
! 868: * Allocation of new mbuf cluster failed, leave the
! 869: * old one in place and keep going.
! 870: */
! 871: ifp->if_ierrors++;
! 872: goto again;
! 873: }
! 874:
! 875: ifp->if_ipackets++;
! 876: hme_rxcksum(m, flags);
! 877:
! 878: #if NBPFILTER > 0
! 879: if (ifp->if_bpf)
! 880: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 881: #endif
! 882:
! 883: ether_input_mbuf(ifp, m);
! 884:
! 885: again:
! 886: HME_XD_SETADDR(sc->sc_pci, sc->sc_rb.rb_rxd, ri,
! 887: sd->sd_map->dm_segs[0].ds_addr);
! 888: HME_XD_SETFLAGS(sc->sc_pci, sc->sc_rb.rb_rxd, ri,
! 889: HME_XD_OWN | HME_XD_ENCODE_RSIZE(HME_RX_PKTSIZE));
! 890:
! 891: if (++ri == HME_RX_RING_SIZE) {
! 892: ri = 0;
! 893: sd = sc->sc_rxd;
! 894: } else
! 895: sd++;
! 896: }
! 897:
! 898: sc->sc_last_rd = ri;
! 899: return (1);
! 900: }
! 901:
! 902: int
! 903: hme_eint(sc, status)
! 904: struct hme_softc *sc;
! 905: u_int status;
! 906: {
! 907: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 908:
! 909: if (status & HME_SEB_STAT_MIFIRQ) {
! 910: printf("%s: XXXlink status changed\n", sc->sc_dev.dv_xname);
! 911: status &= ~HME_SEB_STAT_MIFIRQ;
! 912: }
! 913:
! 914: if (status & HME_SEB_STAT_DTIMEXP) {
! 915: ifp->if_oerrors++;
! 916: status &= ~HME_SEB_STAT_DTIMEXP;
! 917: }
! 918:
! 919: if (status & HME_SEB_STAT_NORXD) {
! 920: ifp->if_ierrors++;
! 921: status &= ~HME_SEB_STAT_NORXD;
! 922: }
! 923:
! 924: status &= ~(HME_SEB_STAT_RXTOHOST | HME_SEB_STAT_GOTFRAME |
! 925: HME_SEB_STAT_SENTFRAME | HME_SEB_STAT_HOSTTOTX |
! 926: HME_SEB_STAT_TXALL);
! 927:
! 928: if (status == 0)
! 929: return (1);
! 930:
! 931: #ifdef HME_DEBUG
! 932: printf("%s: status=%b\n", sc->sc_dev.dv_xname, status, HME_SEB_STAT_BITS);
! 933: #endif
! 934: return (1);
! 935: }
! 936:
! 937: int
! 938: hme_intr(v)
! 939: void *v;
! 940: {
! 941: struct hme_softc *sc = (struct hme_softc *)v;
! 942: bus_space_tag_t t = sc->sc_bustag;
! 943: bus_space_handle_t seb = sc->sc_seb;
! 944: u_int32_t status;
! 945: int r = 0;
! 946:
! 947: status = bus_space_read_4(t, seb, HME_SEBI_STAT);
! 948:
! 949: if ((status & HME_SEB_STAT_ALL_ERRORS) != 0)
! 950: r |= hme_eint(sc, status);
! 951:
! 952: if ((status & (HME_SEB_STAT_TXALL | HME_SEB_STAT_HOSTTOTX)) != 0)
! 953: r |= hme_tint(sc);
! 954:
! 955: if ((status & HME_SEB_STAT_RXTOHOST) != 0)
! 956: r |= hme_rint(sc);
! 957:
! 958: return (r);
! 959: }
! 960:
! 961:
! 962: void
! 963: hme_watchdog(ifp)
! 964: struct ifnet *ifp;
! 965: {
! 966: struct hme_softc *sc = ifp->if_softc;
! 967:
! 968: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
! 969: ifp->if_oerrors++;
! 970:
! 971: hme_reset(sc);
! 972: }
! 973:
! 974: /*
! 975: * Initialize the MII Management Interface
! 976: */
! 977: void
! 978: hme_mifinit(sc)
! 979: struct hme_softc *sc;
! 980: {
! 981: bus_space_tag_t t = sc->sc_bustag;
! 982: bus_space_handle_t mif = sc->sc_mif;
! 983: bus_space_handle_t mac = sc->sc_mac;
! 984: int phy;
! 985: u_int32_t v;
! 986:
! 987: v = bus_space_read_4(t, mif, HME_MIFI_CFG);
! 988: phy = HME_PHYAD_EXTERNAL;
! 989: if (v & HME_MIF_CFG_MDI1)
! 990: phy = sc->sc_tcvr = HME_PHYAD_EXTERNAL;
! 991: else if (v & HME_MIF_CFG_MDI0)
! 992: phy = sc->sc_tcvr = HME_PHYAD_INTERNAL;
! 993: else
! 994: sc->sc_tcvr = -1;
! 995:
! 996: /* Configure the MIF in frame mode, no poll, current phy select */
! 997: v = 0;
! 998: if (phy == HME_PHYAD_EXTERNAL)
! 999: v |= HME_MIF_CFG_PHY;
! 1000: bus_space_write_4(t, mif, HME_MIFI_CFG, v);
! 1001:
! 1002: /* If an external transceiver is selected, enable its MII drivers */
! 1003: v = bus_space_read_4(t, mac, HME_MACI_XIF);
! 1004: v &= ~HME_MAC_XIF_MIIENABLE;
! 1005: if (phy == HME_PHYAD_EXTERNAL)
! 1006: v |= HME_MAC_XIF_MIIENABLE;
! 1007: bus_space_write_4(t, mac, HME_MACI_XIF, v);
! 1008: }
! 1009:
! 1010: /*
! 1011: * MII interface
! 1012: */
! 1013: static int
! 1014: hme_mii_readreg(self, phy, reg)
! 1015: struct device *self;
! 1016: int phy, reg;
! 1017: {
! 1018: struct hme_softc *sc = (struct hme_softc *)self;
! 1019: bus_space_tag_t t = sc->sc_bustag;
! 1020: bus_space_handle_t mif = sc->sc_mif;
! 1021: bus_space_handle_t mac = sc->sc_mac;
! 1022: u_int32_t v, xif_cfg, mifi_cfg;
! 1023: int n;
! 1024:
! 1025: if (phy != HME_PHYAD_EXTERNAL && phy != HME_PHYAD_INTERNAL)
! 1026: return (0);
! 1027:
! 1028: /* Select the desired PHY in the MIF configuration register */
! 1029: v = mifi_cfg = bus_space_read_4(t, mif, HME_MIFI_CFG);
! 1030: v &= ~HME_MIF_CFG_PHY;
! 1031: if (phy == HME_PHYAD_EXTERNAL)
! 1032: v |= HME_MIF_CFG_PHY;
! 1033: bus_space_write_4(t, mif, HME_MIFI_CFG, v);
! 1034:
! 1035: /* Enable MII drivers on external transceiver */
! 1036: v = xif_cfg = bus_space_read_4(t, mac, HME_MACI_XIF);
! 1037: if (phy == HME_PHYAD_EXTERNAL)
! 1038: v |= HME_MAC_XIF_MIIENABLE;
! 1039: else
! 1040: v &= ~HME_MAC_XIF_MIIENABLE;
! 1041: bus_space_write_4(t, mac, HME_MACI_XIF, v);
! 1042:
! 1043: /* Construct the frame command */
! 1044: v = (MII_COMMAND_START << HME_MIF_FO_ST_SHIFT) |
! 1045: HME_MIF_FO_TAMSB |
! 1046: (MII_COMMAND_READ << HME_MIF_FO_OPC_SHIFT) |
! 1047: (phy << HME_MIF_FO_PHYAD_SHIFT) |
! 1048: (reg << HME_MIF_FO_REGAD_SHIFT);
! 1049:
! 1050: bus_space_write_4(t, mif, HME_MIFI_FO, v);
! 1051: for (n = 0; n < 100; n++) {
! 1052: DELAY(1);
! 1053: v = bus_space_read_4(t, mif, HME_MIFI_FO);
! 1054: if (v & HME_MIF_FO_TALSB) {
! 1055: v &= HME_MIF_FO_DATA;
! 1056: goto out;
! 1057: }
! 1058: }
! 1059:
! 1060: v = 0;
! 1061: printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname);
! 1062:
! 1063: out:
! 1064: /* Restore MIFI_CFG register */
! 1065: bus_space_write_4(t, mif, HME_MIFI_CFG, mifi_cfg);
! 1066: /* Restore XIF register */
! 1067: bus_space_write_4(t, mac, HME_MACI_XIF, xif_cfg);
! 1068: return (v);
! 1069: }
! 1070:
! 1071: static void
! 1072: hme_mii_writereg(self, phy, reg, val)
! 1073: struct device *self;
! 1074: int phy, reg, val;
! 1075: {
! 1076: struct hme_softc *sc = (void *)self;
! 1077: bus_space_tag_t t = sc->sc_bustag;
! 1078: bus_space_handle_t mif = sc->sc_mif;
! 1079: bus_space_handle_t mac = sc->sc_mac;
! 1080: u_int32_t v, xif_cfg, mifi_cfg;
! 1081: int n;
! 1082:
! 1083: /* We can at most have two PHYs */
! 1084: if (phy != HME_PHYAD_EXTERNAL && phy != HME_PHYAD_INTERNAL)
! 1085: return;
! 1086:
! 1087: /* Select the desired PHY in the MIF configuration register */
! 1088: v = mifi_cfg = bus_space_read_4(t, mif, HME_MIFI_CFG);
! 1089: v &= ~HME_MIF_CFG_PHY;
! 1090: if (phy == HME_PHYAD_EXTERNAL)
! 1091: v |= HME_MIF_CFG_PHY;
! 1092: bus_space_write_4(t, mif, HME_MIFI_CFG, v);
! 1093:
! 1094: /* Enable MII drivers on external transceiver */
! 1095: v = xif_cfg = bus_space_read_4(t, mac, HME_MACI_XIF);
! 1096: if (phy == HME_PHYAD_EXTERNAL)
! 1097: v |= HME_MAC_XIF_MIIENABLE;
! 1098: else
! 1099: v &= ~HME_MAC_XIF_MIIENABLE;
! 1100: bus_space_write_4(t, mac, HME_MACI_XIF, v);
! 1101:
! 1102: /* Construct the frame command */
! 1103: v = (MII_COMMAND_START << HME_MIF_FO_ST_SHIFT) |
! 1104: HME_MIF_FO_TAMSB |
! 1105: (MII_COMMAND_WRITE << HME_MIF_FO_OPC_SHIFT) |
! 1106: (phy << HME_MIF_FO_PHYAD_SHIFT) |
! 1107: (reg << HME_MIF_FO_REGAD_SHIFT) |
! 1108: (val & HME_MIF_FO_DATA);
! 1109:
! 1110: bus_space_write_4(t, mif, HME_MIFI_FO, v);
! 1111: for (n = 0; n < 100; n++) {
! 1112: DELAY(1);
! 1113: v = bus_space_read_4(t, mif, HME_MIFI_FO);
! 1114: if (v & HME_MIF_FO_TALSB)
! 1115: goto out;
! 1116: }
! 1117:
! 1118: printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname);
! 1119: out:
! 1120: /* Restore MIFI_CFG register */
! 1121: bus_space_write_4(t, mif, HME_MIFI_CFG, mifi_cfg);
! 1122: /* Restore XIF register */
! 1123: bus_space_write_4(t, mac, HME_MACI_XIF, xif_cfg);
! 1124: }
! 1125:
! 1126: static void
! 1127: hme_mii_statchg(dev)
! 1128: struct device *dev;
! 1129: {
! 1130: struct hme_softc *sc = (void *)dev;
! 1131: bus_space_tag_t t = sc->sc_bustag;
! 1132: bus_space_handle_t mac = sc->sc_mac;
! 1133: u_int32_t v;
! 1134:
! 1135: #ifdef HMEDEBUG
! 1136: if (sc->sc_debug)
! 1137: printf("hme_mii_statchg: status change\n", phy);
! 1138: #endif
! 1139:
! 1140: /* Set the MAC Full Duplex bit appropriately */
! 1141: /* Apparently the hme chip is SIMPLEX if working in full duplex mode,
! 1142: but not otherwise. */
! 1143: v = bus_space_read_4(t, mac, HME_MACI_TXCFG);
! 1144: if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0) {
! 1145: v |= HME_MAC_TXCFG_FULLDPLX;
! 1146: sc->sc_arpcom.ac_if.if_flags |= IFF_SIMPLEX;
! 1147: } else {
! 1148: v &= ~HME_MAC_TXCFG_FULLDPLX;
! 1149: sc->sc_arpcom.ac_if.if_flags &= ~IFF_SIMPLEX;
! 1150: }
! 1151: sc->sc_if_flags = sc->sc_arpcom.ac_if.if_flags;
! 1152: bus_space_write_4(t, mac, HME_MACI_TXCFG, v);
! 1153: }
! 1154:
! 1155: int
! 1156: hme_mediachange(ifp)
! 1157: struct ifnet *ifp;
! 1158: {
! 1159: struct hme_softc *sc = ifp->if_softc;
! 1160: bus_space_tag_t t = sc->sc_bustag;
! 1161: bus_space_handle_t mif = sc->sc_mif;
! 1162: bus_space_handle_t mac = sc->sc_mac;
! 1163: int instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media);
! 1164: int phy = sc->sc_phys[instance];
! 1165: u_int32_t v;
! 1166:
! 1167: #ifdef HMEDEBUG
! 1168: if (sc->sc_debug)
! 1169: printf("hme_mediachange: phy = %d\n", phy);
! 1170: #endif
! 1171: if (IFM_TYPE(sc->sc_media.ifm_media) != IFM_ETHER)
! 1172: return (EINVAL);
! 1173:
! 1174: /* Select the current PHY in the MIF configuration register */
! 1175: v = bus_space_read_4(t, mif, HME_MIFI_CFG);
! 1176: v &= ~HME_MIF_CFG_PHY;
! 1177: if (phy == HME_PHYAD_EXTERNAL)
! 1178: v |= HME_MIF_CFG_PHY;
! 1179: bus_space_write_4(t, mif, HME_MIFI_CFG, v);
! 1180:
! 1181: /* If an external transceiver is selected, enable its MII drivers */
! 1182: v = bus_space_read_4(t, mac, HME_MACI_XIF);
! 1183: v &= ~HME_MAC_XIF_MIIENABLE;
! 1184: if (phy == HME_PHYAD_EXTERNAL)
! 1185: v |= HME_MAC_XIF_MIIENABLE;
! 1186: bus_space_write_4(t, mac, HME_MACI_XIF, v);
! 1187:
! 1188: return (mii_mediachg(&sc->sc_mii));
! 1189: }
! 1190:
! 1191: void
! 1192: hme_mediastatus(ifp, ifmr)
! 1193: struct ifnet *ifp;
! 1194: struct ifmediareq *ifmr;
! 1195: {
! 1196: struct hme_softc *sc = ifp->if_softc;
! 1197:
! 1198: if ((ifp->if_flags & IFF_UP) == 0)
! 1199: return;
! 1200:
! 1201: mii_pollstat(&sc->sc_mii);
! 1202: ifmr->ifm_active = sc->sc_mii.mii_media_active;
! 1203: ifmr->ifm_status = sc->sc_mii.mii_media_status;
! 1204: }
! 1205:
! 1206: /*
! 1207: * Process an ioctl request.
! 1208: */
! 1209: int
! 1210: hme_ioctl(ifp, cmd, data)
! 1211: struct ifnet *ifp;
! 1212: u_long cmd;
! 1213: caddr_t data;
! 1214: {
! 1215: struct hme_softc *sc = ifp->if_softc;
! 1216: struct ifaddr *ifa = (struct ifaddr *)data;
! 1217: struct ifreq *ifr = (struct ifreq *)data;
! 1218: int s, error = 0;
! 1219:
! 1220: s = splnet();
! 1221:
! 1222: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 1223: splx(s);
! 1224: return (error);
! 1225: }
! 1226:
! 1227: switch (cmd) {
! 1228:
! 1229: case SIOCSIFADDR:
! 1230: switch (ifa->ifa_addr->sa_family) {
! 1231: #ifdef INET
! 1232: case AF_INET:
! 1233: if (ifp->if_flags & IFF_UP)
! 1234: hme_setladrf(sc);
! 1235: else {
! 1236: ifp->if_flags |= IFF_UP;
! 1237: hme_init(sc);
! 1238: }
! 1239: arp_ifinit(&sc->sc_arpcom, ifa);
! 1240: break;
! 1241: #endif
! 1242: default:
! 1243: hme_init(sc);
! 1244: break;
! 1245: }
! 1246: break;
! 1247:
! 1248: case SIOCSIFFLAGS:
! 1249: if ((ifp->if_flags & IFF_UP) == 0 &&
! 1250: (ifp->if_flags & IFF_RUNNING) != 0) {
! 1251: /*
! 1252: * If interface is marked down and it is running, then
! 1253: * stop it.
! 1254: */
! 1255: hme_stop(sc);
! 1256: ifp->if_flags &= ~IFF_RUNNING;
! 1257: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 1258: (ifp->if_flags & IFF_RUNNING) == 0) {
! 1259: /*
! 1260: * If interface is marked up and it is stopped, then
! 1261: * start it.
! 1262: */
! 1263: hme_init(sc);
! 1264: } else if ((ifp->if_flags & IFF_UP) != 0) {
! 1265: /*
! 1266: * If setting debug or promiscuous mode, do not reset
! 1267: * the chip; for everything else, call hme_init()
! 1268: * which will trigger a reset.
! 1269: */
! 1270: #define RESETIGN (IFF_CANTCHANGE | IFF_DEBUG)
! 1271: if (ifp->if_flags == sc->sc_if_flags)
! 1272: break;
! 1273: if ((ifp->if_flags & (~RESETIGN))
! 1274: == (sc->sc_if_flags & (~RESETIGN)))
! 1275: hme_setladrf(sc);
! 1276: else
! 1277: hme_init(sc);
! 1278: #undef RESETIGN
! 1279: }
! 1280: #ifdef HMEDEBUG
! 1281: sc->sc_debug = (ifp->if_flags & IFF_DEBUG) != 0 ? 1 : 0;
! 1282: #endif
! 1283: break;
! 1284:
! 1285: case SIOCADDMULTI:
! 1286: case SIOCDELMULTI:
! 1287: error = (cmd == SIOCADDMULTI) ?
! 1288: ether_addmulti(ifr, &sc->sc_arpcom) :
! 1289: ether_delmulti(ifr, &sc->sc_arpcom);
! 1290:
! 1291: if (error == ENETRESET) {
! 1292: /*
! 1293: * Multicast list has changed; set the hardware filter
! 1294: * accordingly.
! 1295: */
! 1296: if (ifp->if_flags & IFF_RUNNING)
! 1297: hme_setladrf(sc);
! 1298: error = 0;
! 1299: }
! 1300: break;
! 1301:
! 1302: case SIOCGIFMEDIA:
! 1303: case SIOCSIFMEDIA:
! 1304: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
! 1305: break;
! 1306:
! 1307: default:
! 1308: error = ENOTTY;
! 1309: break;
! 1310: }
! 1311:
! 1312: sc->sc_if_flags = ifp->if_flags;
! 1313: splx(s);
! 1314: return (error);
! 1315: }
! 1316:
! 1317: void
! 1318: hme_shutdown(arg)
! 1319: void *arg;
! 1320: {
! 1321: hme_stop((struct hme_softc *)arg);
! 1322: }
! 1323:
! 1324: /*
! 1325: * Set up the logical address filter.
! 1326: */
! 1327: void
! 1328: hme_setladrf(sc)
! 1329: struct hme_softc *sc;
! 1330: {
! 1331: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1332: struct ether_multi *enm;
! 1333: struct ether_multistep step;
! 1334: struct arpcom *ac = &sc->sc_arpcom;
! 1335: bus_space_tag_t t = sc->sc_bustag;
! 1336: bus_space_handle_t mac = sc->sc_mac;
! 1337: u_int32_t hash[4];
! 1338: u_int32_t v, crc;
! 1339:
! 1340: /* Clear hash table */
! 1341: hash[3] = hash[2] = hash[1] = hash[0] = 0;
! 1342:
! 1343: /* Get current RX configuration */
! 1344: v = bus_space_read_4(t, mac, HME_MACI_RXCFG);
! 1345:
! 1346: if ((ifp->if_flags & IFF_PROMISC) != 0) {
! 1347: /* Turn on promiscuous mode; turn off the hash filter */
! 1348: v |= HME_MAC_RXCFG_PMISC;
! 1349: v &= ~HME_MAC_RXCFG_HENABLE;
! 1350: ifp->if_flags |= IFF_ALLMULTI;
! 1351: goto chipit;
! 1352: }
! 1353:
! 1354: /* Turn off promiscuous mode; turn on the hash filter */
! 1355: v &= ~HME_MAC_RXCFG_PMISC;
! 1356: v |= HME_MAC_RXCFG_HENABLE;
! 1357:
! 1358: /*
! 1359: * Set up multicast address filter by passing all multicast addresses
! 1360: * through a crc generator, and then using the high order 6 bits as an
! 1361: * index into the 64 bit logical address filter. The high order bit
! 1362: * selects the word, while the rest of the bits select the bit within
! 1363: * the word.
! 1364: */
! 1365:
! 1366: ETHER_FIRST_MULTI(step, ac, enm);
! 1367: while (enm != NULL) {
! 1368: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
! 1369: /*
! 1370: * We must listen to a range of multicast addresses.
! 1371: * For now, just accept all multicasts, rather than
! 1372: * trying to set only those filter bits needed to match
! 1373: * the range. (At this time, the only use of address
! 1374: * ranges is for IP multicast routing, for which the
! 1375: * range is big enough to require all bits set.)
! 1376: */
! 1377: hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
! 1378: ifp->if_flags |= IFF_ALLMULTI;
! 1379: goto chipit;
! 1380: }
! 1381:
! 1382: crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN)>> 26;
! 1383:
! 1384: /* Set the corresponding bit in the filter. */
! 1385: hash[crc >> 4] |= 1 << (crc & 0xf);
! 1386:
! 1387: ETHER_NEXT_MULTI(step, enm);
! 1388: }
! 1389:
! 1390: ifp->if_flags &= ~IFF_ALLMULTI;
! 1391:
! 1392: chipit:
! 1393: /* Now load the hash table into the chip */
! 1394: bus_space_write_4(t, mac, HME_MACI_HASHTAB0, hash[0]);
! 1395: bus_space_write_4(t, mac, HME_MACI_HASHTAB1, hash[1]);
! 1396: bus_space_write_4(t, mac, HME_MACI_HASHTAB2, hash[2]);
! 1397: bus_space_write_4(t, mac, HME_MACI_HASHTAB3, hash[3]);
! 1398: bus_space_write_4(t, mac, HME_MACI_RXCFG, v);
! 1399: }
! 1400:
! 1401: int
! 1402: hme_encap(sc, mhead, bixp)
! 1403: struct hme_softc *sc;
! 1404: struct mbuf *mhead;
! 1405: int *bixp;
! 1406: {
! 1407: struct hme_sxd *sd;
! 1408: struct mbuf *m;
! 1409: int frag, cur, cnt = 0;
! 1410: u_int32_t flags;
! 1411: struct hme_ring *hr = &sc->sc_rb;
! 1412:
! 1413: cur = frag = *bixp;
! 1414: sd = &sc->sc_txd[frag];
! 1415:
! 1416: for (m = mhead; m != NULL; m = m->m_next) {
! 1417: if (m->m_len == 0)
! 1418: continue;
! 1419:
! 1420: if ((HME_TX_RING_SIZE - (sc->sc_tx_cnt + cnt)) < 5)
! 1421: goto err;
! 1422:
! 1423: if (bus_dmamap_load(sc->sc_dmatag, sd->sd_map,
! 1424: mtod(m, caddr_t), m->m_len, NULL, BUS_DMA_NOWAIT) != 0)
! 1425: goto err;
! 1426:
! 1427: sd->sd_loaded = 1;
! 1428: bus_dmamap_sync(sc->sc_dmatag, sd->sd_map, 0,
! 1429: sd->sd_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 1430:
! 1431: sd->sd_mbuf = NULL;
! 1432:
! 1433: flags = HME_XD_ENCODE_TSIZE(m->m_len);
! 1434: if (cnt == 0)
! 1435: flags |= HME_XD_SOP;
! 1436: else
! 1437: flags |= HME_XD_OWN;
! 1438:
! 1439: HME_XD_SETADDR(sc->sc_pci, hr->rb_txd, frag,
! 1440: sd->sd_map->dm_segs[0].ds_addr);
! 1441: HME_XD_SETFLAGS(sc->sc_pci, hr->rb_txd, frag, flags);
! 1442:
! 1443: cur = frag;
! 1444: cnt++;
! 1445: if (++frag == HME_TX_RING_SIZE) {
! 1446: frag = 0;
! 1447: sd = sc->sc_txd;
! 1448: } else
! 1449: sd++;
! 1450: }
! 1451:
! 1452: /* Set end of packet on last descriptor. */
! 1453: flags = HME_XD_GETFLAGS(sc->sc_pci, hr->rb_txd, cur);
! 1454: flags |= HME_XD_EOP;
! 1455: HME_XD_SETFLAGS(sc->sc_pci, hr->rb_txd, cur, flags);
! 1456: sc->sc_txd[cur].sd_mbuf = mhead;
! 1457:
! 1458: /* Give first frame over to the hardware. */
! 1459: flags = HME_XD_GETFLAGS(sc->sc_pci, hr->rb_txd, (*bixp));
! 1460: flags |= HME_XD_OWN;
! 1461: HME_XD_SETFLAGS(sc->sc_pci, hr->rb_txd, (*bixp), flags);
! 1462:
! 1463: sc->sc_tx_cnt += cnt;
! 1464: *bixp = frag;
! 1465:
! 1466: /* sync descriptors */
! 1467:
! 1468: return (0);
! 1469:
! 1470: err:
! 1471: /*
! 1472: * Invalidate the stuff we may have already put into place. We
! 1473: * will be called again to queue it later.
! 1474: */
! 1475: for (; cnt > 0; cnt--) {
! 1476: if (--frag == -1)
! 1477: frag = HME_TX_RING_SIZE - 1;
! 1478: sd = &sc->sc_txd[frag];
! 1479: bus_dmamap_sync(sc->sc_dmatag, sd->sd_map, 0,
! 1480: sd->sd_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
! 1481: bus_dmamap_unload(sc->sc_dmatag, sd->sd_map);
! 1482: sd->sd_loaded = 0;
! 1483: sd->sd_mbuf = NULL;
! 1484: }
! 1485: return (ENOBUFS);
! 1486: }
! 1487:
! 1488: int
! 1489: hme_newbuf(sc, d, freeit)
! 1490: struct hme_softc *sc;
! 1491: struct hme_sxd *d;
! 1492: int freeit;
! 1493: {
! 1494: struct mbuf *m;
! 1495: bus_dmamap_t map;
! 1496:
! 1497: /*
! 1498: * All operations should be on local variables and/or rx spare map
! 1499: * until we're sure everything is a success.
! 1500: */
! 1501:
! 1502: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1503: if (m == NULL)
! 1504: return (ENOBUFS);
! 1505: m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if;
! 1506:
! 1507: MCLGET(m, M_DONTWAIT);
! 1508: if ((m->m_flags & M_EXT) == 0) {
! 1509: m_freem(m);
! 1510: return (ENOBUFS);
! 1511: }
! 1512:
! 1513: if (bus_dmamap_load(sc->sc_dmatag, sc->sc_rxmap_spare,
! 1514: mtod(m, caddr_t), MCLBYTES - HME_RX_OFFSET, NULL,
! 1515: BUS_DMA_NOWAIT) != 0) {
! 1516: m_freem(m);
! 1517: return (ENOBUFS);
! 1518: }
! 1519:
! 1520: /*
! 1521: * At this point we have a new buffer loaded into the spare map.
! 1522: * Just need to clear out the old mbuf/map and put the new one
! 1523: * in place.
! 1524: */
! 1525:
! 1526: if (d->sd_loaded) {
! 1527: bus_dmamap_sync(sc->sc_dmatag, d->sd_map,
! 1528: 0, d->sd_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 1529: bus_dmamap_unload(sc->sc_dmatag, d->sd_map);
! 1530: d->sd_loaded = 0;
! 1531: }
! 1532:
! 1533: if ((d->sd_mbuf != NULL) && freeit) {
! 1534: m_freem(d->sd_mbuf);
! 1535: d->sd_mbuf = NULL;
! 1536: }
! 1537:
! 1538: map = d->sd_map;
! 1539: d->sd_map = sc->sc_rxmap_spare;
! 1540: sc->sc_rxmap_spare = map;
! 1541:
! 1542: d->sd_loaded = 1;
! 1543:
! 1544: bus_dmamap_sync(sc->sc_dmatag, d->sd_map, 0, d->sd_map->dm_mapsize,
! 1545: BUS_DMASYNC_PREREAD);
! 1546:
! 1547: m->m_data += HME_RX_OFFSET;
! 1548: d->sd_mbuf = m;
! 1549: return (0);
! 1550: }
CVSweb