Annotation of sys/dev/ic/aic6915.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: aic6915.c,v 1.3 2006/12/15 15:28:27 martin Exp $ */
! 2: /* $NetBSD: aic6915.c,v 1.15 2005/12/24 20:27:29 perry Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2001 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Jason R. Thorpe.
! 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: * Device driver for the Adaptec AIC-6915 (``Starfire'')
! 42: * 10/100 Ethernet controller.
! 43: */
! 44:
! 45: #include "bpfilter.h"
! 46:
! 47: #include <sys/param.h>
! 48: #include <sys/endian.h>
! 49: #include <sys/systm.h>
! 50: #include <sys/timeout.h>
! 51: #include <sys/mbuf.h>
! 52: #include <sys/malloc.h>
! 53: #include <sys/kernel.h>
! 54: #include <sys/socket.h>
! 55: #include <sys/ioctl.h>
! 56: #include <sys/errno.h>
! 57: #include <sys/device.h>
! 58:
! 59: #include <uvm/uvm_extern.h>
! 60:
! 61: #include <net/if.h>
! 62: #include <net/if_dl.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: #endif
! 71:
! 72: #include <net/if_media.h>
! 73:
! 74: #if NBPFILTER > 0
! 75: #include <net/bpf.h>
! 76: #endif
! 77:
! 78: #include <machine/bus.h>
! 79: #include <machine/intr.h>
! 80:
! 81: #include <dev/mii/miivar.h>
! 82:
! 83: #include <dev/ic/aic6915.h>
! 84:
! 85: void sf_start(struct ifnet *);
! 86: void sf_watchdog(struct ifnet *);
! 87: int sf_ioctl(struct ifnet *, u_long, caddr_t);
! 88: int sf_init(struct ifnet *);
! 89: void sf_stop(struct ifnet *, int);
! 90:
! 91: void sf_shutdown(void *);
! 92:
! 93: void sf_txintr(struct sf_softc *);
! 94: void sf_rxintr(struct sf_softc *);
! 95: void sf_stats_update(struct sf_softc *);
! 96:
! 97: void sf_reset(struct sf_softc *);
! 98: void sf_macreset(struct sf_softc *);
! 99: void sf_rxdrain(struct sf_softc *);
! 100: int sf_add_rxbuf(struct sf_softc *, int);
! 101: uint8_t sf_read_eeprom(struct sf_softc *, int);
! 102: void sf_set_filter(struct sf_softc *);
! 103:
! 104: int sf_mii_read(struct device *, int, int);
! 105: void sf_mii_write(struct device *, int, int, int);
! 106: void sf_mii_statchg(struct device *);
! 107:
! 108: void sf_tick(void *);
! 109:
! 110: int sf_mediachange(struct ifnet *);
! 111: void sf_mediastatus(struct ifnet *, struct ifmediareq *);
! 112:
! 113: uint32_t sf_reg_read(struct sf_softc *, bus_addr_t);
! 114: void sf_reg_write(struct sf_softc *, bus_addr_t , uint32_t);
! 115:
! 116: void sf_set_filter_perfect(struct sf_softc *, int , uint8_t *);
! 117: void sf_set_filter_hash(struct sf_softc *, uint8_t *);
! 118:
! 119: struct cfdriver sf_cd = {
! 120: NULL, "sf", DV_IFNET
! 121: };
! 122:
! 123: #define sf_funcreg_read(sc, reg) \
! 124: bus_space_read_4((sc)->sc_st, (sc)->sc_sh_func, (reg))
! 125: #define sf_funcreg_write(sc, reg, val) \
! 126: bus_space_write_4((sc)->sc_st, (sc)->sc_sh_func, (reg), (val))
! 127:
! 128: uint32_t
! 129: sf_reg_read(struct sf_softc *sc, bus_addr_t reg)
! 130: {
! 131:
! 132: if (__predict_false(sc->sc_iomapped)) {
! 133: bus_space_write_4(sc->sc_st, sc->sc_sh, SF_IndirectIoAccess,
! 134: reg);
! 135: return (bus_space_read_4(sc->sc_st, sc->sc_sh,
! 136: SF_IndirectIoDataPort));
! 137: }
! 138:
! 139: return (bus_space_read_4(sc->sc_st, sc->sc_sh, reg));
! 140: }
! 141:
! 142: void
! 143: sf_reg_write(struct sf_softc *sc, bus_addr_t reg, uint32_t val)
! 144: {
! 145:
! 146: if (__predict_false(sc->sc_iomapped)) {
! 147: bus_space_write_4(sc->sc_st, sc->sc_sh, SF_IndirectIoAccess,
! 148: reg);
! 149: bus_space_write_4(sc->sc_st, sc->sc_sh, SF_IndirectIoDataPort,
! 150: val);
! 151: return;
! 152: }
! 153:
! 154: bus_space_write_4(sc->sc_st, sc->sc_sh, reg, val);
! 155: }
! 156:
! 157: #define sf_genreg_read(sc, reg) \
! 158: sf_reg_read((sc), (reg) + SF_GENREG_OFFSET)
! 159: #define sf_genreg_write(sc, reg, val) \
! 160: sf_reg_write((sc), (reg) + SF_GENREG_OFFSET, (val))
! 161:
! 162: /*
! 163: * sf_attach:
! 164: *
! 165: * Attach a Starfire interface to the system.
! 166: */
! 167: void
! 168: sf_attach(struct sf_softc *sc)
! 169: {
! 170: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 171: int i, rseg, error;
! 172: bus_dma_segment_t seg;
! 173: u_int8_t enaddr[ETHER_ADDR_LEN];
! 174:
! 175: timeout_set(&sc->sc_mii_timeout, sf_tick, sc);
! 176:
! 177: /*
! 178: * If we're I/O mapped, the functional register handle is
! 179: * the same as the base handle. If we're memory mapped,
! 180: * carve off a chunk of the register space for the functional
! 181: * registers, to save on arithmetic later.
! 182: */
! 183: if (sc->sc_iomapped)
! 184: sc->sc_sh_func = sc->sc_sh;
! 185: else {
! 186: if ((error = bus_space_subregion(sc->sc_st, sc->sc_sh,
! 187: SF_GENREG_OFFSET, SF_FUNCREG_SIZE, &sc->sc_sh_func)) != 0) {
! 188: printf("%s: unable to sub-region functional "
! 189: "registers, error = %d\n", sc->sc_dev.dv_xname,
! 190: error);
! 191: return;
! 192: }
! 193: }
! 194:
! 195: /*
! 196: * Initialize the transmit threshold for this interface. The
! 197: * manual describes the default as 4 * 16 bytes. We start out
! 198: * at 10 * 16 bytes, to avoid a bunch of initial underruns on
! 199: * several platforms.
! 200: */
! 201: sc->sc_txthresh = 10;
! 202:
! 203: /*
! 204: * Allocate the control data structures, and create and load the
! 205: * DMA map for it.
! 206: */
! 207: if ((error = bus_dmamem_alloc(sc->sc_dmat,
! 208: sizeof(struct sf_control_data), PAGE_SIZE, 0, &seg, 1, &rseg,
! 209: BUS_DMA_NOWAIT)) != 0) {
! 210: printf("%s: unable to allocate control data, error = %d\n",
! 211: sc->sc_dev.dv_xname, error);
! 212: goto fail_0;
! 213: }
! 214:
! 215: if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
! 216: sizeof(struct sf_control_data), (caddr_t *)&sc->sc_control_data,
! 217: BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
! 218: printf("%s: unable to map control data, error = %d\n",
! 219: sc->sc_dev.dv_xname, error);
! 220: goto fail_1;
! 221: }
! 222:
! 223: if ((error = bus_dmamap_create(sc->sc_dmat,
! 224: sizeof(struct sf_control_data), 1,
! 225: sizeof(struct sf_control_data), 0, BUS_DMA_NOWAIT,
! 226: &sc->sc_cddmamap)) != 0) {
! 227: printf("%s: unable to create control data DMA map, "
! 228: "error = %d\n", sc->sc_dev.dv_xname, error);
! 229: goto fail_2;
! 230: }
! 231:
! 232: if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap,
! 233: sc->sc_control_data, sizeof(struct sf_control_data), NULL,
! 234: BUS_DMA_NOWAIT)) != 0) {
! 235: printf("%s: unable to load control data DMA map, error = %d\n",
! 236: sc->sc_dev.dv_xname, error);
! 237: goto fail_3;
! 238: }
! 239:
! 240: /*
! 241: * Create the transmit buffer DMA maps.
! 242: */
! 243: for (i = 0; i < SF_NTXDESC; i++) {
! 244: if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
! 245: SF_NTXFRAGS, MCLBYTES, 0, BUS_DMA_NOWAIT,
! 246: &sc->sc_txsoft[i].ds_dmamap)) != 0) {
! 247: printf("%s: unable to create tx DMA map %d, "
! 248: "error = %d\n", sc->sc_dev.dv_xname, i, error);
! 249: goto fail_4;
! 250: }
! 251: }
! 252:
! 253: /*
! 254: * Create the receive buffer DMA maps.
! 255: */
! 256: for (i = 0; i < SF_NRXDESC; i++) {
! 257: if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
! 258: MCLBYTES, 0, BUS_DMA_NOWAIT,
! 259: &sc->sc_rxsoft[i].ds_dmamap)) != 0) {
! 260: printf("%s: unable to create rx DMA map %d, "
! 261: "error = %d\n", sc->sc_dev.dv_xname, i, error);
! 262: goto fail_5;
! 263: }
! 264: }
! 265:
! 266: /*
! 267: * Reset the chip to a known state.
! 268: */
! 269: sf_reset(sc);
! 270:
! 271: /*
! 272: * Read the Ethernet address from the EEPROM.
! 273: */
! 274: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 275: enaddr[i] = sf_read_eeprom(sc, (15 + (ETHER_ADDR_LEN - 1)) - i);
! 276:
! 277: printf(", address %s\n", ether_sprintf(enaddr));
! 278:
! 279: #ifdef DEBUG
! 280: if (sf_funcreg_read(sc, SF_PciDeviceConfig) & PDC_System64)
! 281: printf("%s: 64-bit PCI slot detected\n", sc->sc_dev.dv_xname);
! 282: #endif
! 283:
! 284: /*
! 285: * Initialize our media structures and probe the MII.
! 286: */
! 287: sc->sc_mii.mii_ifp = ifp;
! 288: sc->sc_mii.mii_readreg = sf_mii_read;
! 289: sc->sc_mii.mii_writereg = sf_mii_write;
! 290: sc->sc_mii.mii_statchg = sf_mii_statchg;
! 291: ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, sf_mediachange,
! 292: sf_mediastatus);
! 293: mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
! 294: MII_OFFSET_ANY, 0);
! 295: if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
! 296: ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
! 297: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
! 298: } else
! 299: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
! 300: bcopy(enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
! 301: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 302: ifp = &sc->sc_arpcom.ac_if;
! 303: ifp->if_softc = sc;
! 304: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 305: ifp->if_ioctl = sf_ioctl;
! 306: ifp->if_start = sf_start;
! 307: ifp->if_watchdog = sf_watchdog;
! 308: IFQ_SET_MAXLEN(&ifp->if_snd, SF_NTXDESC_MASK);
! 309: IFQ_SET_READY(&ifp->if_snd);
! 310:
! 311: /*
! 312: * Attach the interface.
! 313: */
! 314: if_attach(ifp);
! 315: ether_ifattach(ifp);
! 316:
! 317: /*
! 318: * Make sure the interface is shutdown during reboot.
! 319: */
! 320: sc->sc_sdhook = shutdownhook_establish(sf_shutdown, sc);
! 321: if (sc->sc_sdhook == NULL)
! 322: printf("%s: WARNING: unable to establish shutdown hook\n",
! 323: sc->sc_dev.dv_xname);
! 324: return;
! 325:
! 326: /*
! 327: * Free any resources we've allocated during the failed attach
! 328: * attempt. Do this in reverse order an fall through.
! 329: */
! 330: fail_5:
! 331: for (i = 0; i < SF_NRXDESC; i++) {
! 332: if (sc->sc_rxsoft[i].ds_dmamap != NULL)
! 333: bus_dmamap_destroy(sc->sc_dmat,
! 334: sc->sc_rxsoft[i].ds_dmamap);
! 335: }
! 336: fail_4:
! 337: for (i = 0; i < SF_NTXDESC; i++) {
! 338: if (sc->sc_txsoft[i].ds_dmamap != NULL)
! 339: bus_dmamap_destroy(sc->sc_dmat,
! 340: sc->sc_txsoft[i].ds_dmamap);
! 341: }
! 342: bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap);
! 343: fail_3:
! 344: bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap);
! 345: fail_2:
! 346: bus_dmamem_unmap(sc->sc_dmat, (caddr_t) sc->sc_control_data,
! 347: sizeof(struct sf_control_data));
! 348: fail_1:
! 349: bus_dmamem_free(sc->sc_dmat, &seg, rseg);
! 350: fail_0:
! 351: return;
! 352: }
! 353:
! 354: /*
! 355: * sf_shutdown:
! 356: *
! 357: * Shutdown hook -- make sure the interface is stopped at reboot.
! 358: */
! 359: void
! 360: sf_shutdown(void *arg)
! 361: {
! 362: struct sf_softc *sc = arg;
! 363:
! 364: sf_stop(&sc->sc_arpcom.ac_if, 1);
! 365: }
! 366:
! 367: /*
! 368: * sf_start: [ifnet interface function]
! 369: *
! 370: * Start packet transmission on the interface.
! 371: */
! 372: void
! 373: sf_start(struct ifnet *ifp)
! 374: {
! 375: struct sf_softc *sc = ifp->if_softc;
! 376: struct mbuf *m0, *m;
! 377: struct sf_txdesc0 *txd;
! 378: struct sf_descsoft *ds;
! 379: bus_dmamap_t dmamap;
! 380: int error, producer, last = -1, opending, seg;
! 381:
! 382: /*
! 383: * Remember the previous number of pending transmits.
! 384: */
! 385: opending = sc->sc_txpending;
! 386:
! 387: /*
! 388: * Find out where we're sitting.
! 389: */
! 390: producer = SF_TXDINDEX_TO_HOST(
! 391: TDQPI_HiPrTxProducerIndex_get(
! 392: sf_funcreg_read(sc, SF_TxDescQueueProducerIndex)));
! 393:
! 394: /*
! 395: * Loop through the send queue, setting up transmit descriptors
! 396: * until we drain the queue, or use up all available transmit
! 397: * descriptors. Leave a blank one at the end for sanity's sake.
! 398: */
! 399: while (sc->sc_txpending < (SF_NTXDESC - 1)) {
! 400: /*
! 401: * Grab a packet off the queue.
! 402: */
! 403: IFQ_POLL(&ifp->if_snd, m0);
! 404: if (m0 == NULL)
! 405: break;
! 406: m = NULL;
! 407:
! 408: /*
! 409: * Get the transmit descriptor.
! 410: */
! 411: txd = &sc->sc_txdescs[producer];
! 412: ds = &sc->sc_txsoft[producer];
! 413: dmamap = ds->ds_dmamap;
! 414:
! 415: /*
! 416: * Load the DMA map. If this fails, the packet either
! 417: * didn't fit in the allotted number of frags, or we were
! 418: * short on resources. In this case, we'll copy and try
! 419: * again.
! 420: */
! 421: if (bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
! 422: BUS_DMA_WRITE|BUS_DMA_NOWAIT) != 0) {
! 423: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 424: if (m == NULL) {
! 425: printf("%s: unable to allocate Tx mbuf\n",
! 426: sc->sc_dev.dv_xname);
! 427: break;
! 428: }
! 429: if (m0->m_pkthdr.len > MHLEN) {
! 430: MCLGET(m, M_DONTWAIT);
! 431: if ((m->m_flags & M_EXT) == 0) {
! 432: printf("%s: unable to allocate Tx "
! 433: "cluster\n", sc->sc_dev.dv_xname);
! 434: m_freem(m);
! 435: break;
! 436: }
! 437: }
! 438: m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
! 439: m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
! 440: error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap,
! 441: m, BUS_DMA_WRITE|BUS_DMA_NOWAIT);
! 442: if (error) {
! 443: printf("%s: unable to load Tx buffer, "
! 444: "error = %d\n", sc->sc_dev.dv_xname, error);
! 445: break;
! 446: }
! 447: }
! 448:
! 449: /*
! 450: * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET.
! 451: */
! 452: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 453: if (m != NULL) {
! 454: m_freem(m0);
! 455: m0 = m;
! 456: }
! 457:
! 458: /* Initialize the descriptor. */
! 459: txd->td_word0 =
! 460: htole32(TD_W0_ID | TD_W0_CRCEN | m0->m_pkthdr.len);
! 461: if (producer == (SF_NTXDESC - 1))
! 462: txd->td_word0 |= TD_W0_END;
! 463: txd->td_word1 = htole32(dmamap->dm_nsegs);
! 464: for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
! 465: txd->td_frags[seg].fr_addr =
! 466: htole32(dmamap->dm_segs[seg].ds_addr);
! 467: txd->td_frags[seg].fr_len =
! 468: htole32(dmamap->dm_segs[seg].ds_len);
! 469: }
! 470:
! 471: /* Sync the descriptor and the DMA map. */
! 472: SF_CDTXDSYNC(sc, producer, BUS_DMASYNC_PREWRITE);
! 473: bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
! 474: BUS_DMASYNC_PREWRITE);
! 475:
! 476: /*
! 477: * Store a pointer to the packet so we can free it later.
! 478: */
! 479: ds->ds_mbuf = m0;
! 480:
! 481: /* Advance the Tx pointer. */
! 482: sc->sc_txpending++;
! 483: last = producer;
! 484: producer = SF_NEXTTX(producer);
! 485:
! 486: #if NBPFILTER > 0
! 487: /*
! 488: * Pass the packet to any BPF listeners.
! 489: */
! 490: if (ifp->if_bpf)
! 491: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 492: #endif
! 493: }
! 494:
! 495: if (sc->sc_txpending == (SF_NTXDESC - 1)) {
! 496: /* No more slots left; notify upper layer. */
! 497: ifp->if_flags |= IFF_OACTIVE;
! 498: }
! 499:
! 500: if (sc->sc_txpending != opending) {
! 501: KASSERT(last != -1);
! 502: /*
! 503: * We enqueued packets. Cause a transmit interrupt to
! 504: * happen on the last packet we enqueued, and give the
! 505: * new descriptors to the chip by writing the new
! 506: * producer index.
! 507: */
! 508: sc->sc_txdescs[last].td_word0 |= TD_W0_INTR;
! 509: SF_CDTXDSYNC(sc, last, BUS_DMASYNC_PREWRITE);
! 510:
! 511: sf_funcreg_write(sc, SF_TxDescQueueProducerIndex,
! 512: TDQPI_HiPrTxProducerIndex(SF_TXDINDEX_TO_CHIP(producer)));
! 513:
! 514: /* Set a watchdog timer in case the chip flakes out. */
! 515: ifp->if_timer = 5;
! 516: }
! 517: }
! 518:
! 519: /*
! 520: * sf_watchdog: [ifnet interface function]
! 521: *
! 522: * Watchdog timer handler.
! 523: */
! 524: void
! 525: sf_watchdog(struct ifnet *ifp)
! 526: {
! 527: struct sf_softc *sc = ifp->if_softc;
! 528:
! 529: printf("%s: device timeout\n", sc->sc_dev.dv_xname);
! 530: ifp->if_oerrors++;
! 531:
! 532: (void) sf_init(ifp);
! 533:
! 534: /* Try to get more packets going. */
! 535: sf_start(ifp);
! 536: }
! 537:
! 538: /*
! 539: * sf_ioctl: [ifnet interface function]
! 540: *
! 541: * Handle control requests from the operator.
! 542: */
! 543: int
! 544: sf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 545: {
! 546: struct sf_softc *sc = (struct sf_softc *)ifp->if_softc;
! 547: struct ifaddr *ifa = (struct ifaddr *)data;
! 548: struct ifreq *ifr = (struct ifreq *) data;
! 549: int s, error = 0;
! 550:
! 551: s = splnet();
! 552:
! 553: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 554: splx(s);
! 555: return (error);
! 556: }
! 557:
! 558: switch (cmd) {
! 559: case SIOCSIFADDR:
! 560: ifp->if_flags |= IFF_UP;
! 561: if (!(ifp->if_flags & IFF_RUNNING))
! 562: sf_init(ifp);
! 563: #ifdef INET
! 564: if (ifa->ifa_addr->sa_family == AF_INET)
! 565: arp_ifinit(&sc->sc_arpcom, ifa);
! 566: #endif
! 567: break;
! 568:
! 569: case SIOCSIFFLAGS:
! 570: if (ifp->if_flags & IFF_UP) {
! 571: if (ifp->if_flags & IFF_RUNNING &&
! 572: ((ifp->if_flags ^ sc->sc_flags) &
! 573: IFF_PROMISC)) {
! 574: sf_set_filter(sc);
! 575: } else {
! 576: if (!(ifp->if_flags & IFF_RUNNING))
! 577: sf_init(ifp);
! 578: }
! 579: } else {
! 580: if (ifp->if_flags & IFF_RUNNING)
! 581: sf_stop(ifp, 1);
! 582: }
! 583: sc->sc_flags = ifp->if_flags;
! 584: break;
! 585:
! 586: case SIOCSIFMTU:
! 587: if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu)
! 588: error = EINVAL;
! 589: else if (ifp->if_mtu != ifr->ifr_mtu)
! 590: ifp->if_mtu = ifr->ifr_mtu;
! 591: break;
! 592:
! 593: case SIOCADDMULTI:
! 594: case SIOCDELMULTI:
! 595: ifr = (struct ifreq *)data;
! 596: error = (cmd == SIOCADDMULTI) ?
! 597: ether_addmulti(ifr, &sc->sc_arpcom) :
! 598: ether_delmulti(ifr, &sc->sc_arpcom);
! 599:
! 600: if (error == ENETRESET) {
! 601: if (ifp->if_flags & IFF_RUNNING)
! 602: sf_set_filter(sc);
! 603: error = 0;
! 604: }
! 605: break;
! 606:
! 607: case SIOCGIFMEDIA:
! 608: case SIOCSIFMEDIA:
! 609: error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
! 610: break;
! 611:
! 612: default:
! 613: error = ENOTTY;
! 614: }
! 615:
! 616: /* Try to get more packets going. */
! 617: sf_start(ifp);
! 618:
! 619: splx(s);
! 620: return (error);
! 621: }
! 622:
! 623: /*
! 624: * sf_intr:
! 625: *
! 626: * Interrupt service routine.
! 627: */
! 628: int
! 629: sf_intr(void *arg)
! 630: {
! 631: struct sf_softc *sc = arg;
! 632: uint32_t isr;
! 633: int handled = 0, wantinit = 0;
! 634:
! 635: for (;;) {
! 636: /* Reading clears all interrupts we're interested in. */
! 637: isr = sf_funcreg_read(sc, SF_InterruptStatus);
! 638: if ((isr & IS_PCIPadInt) == 0)
! 639: break;
! 640:
! 641: handled = 1;
! 642:
! 643: /* Handle receive interrupts. */
! 644: if (isr & IS_RxQ1DoneInt)
! 645: sf_rxintr(sc);
! 646:
! 647: /* Handle transmit completion interrupts. */
! 648: if (isr & (IS_TxDmaDoneInt|IS_TxQueueDoneInt))
! 649: sf_txintr(sc);
! 650:
! 651: /* Handle abnormal interrupts. */
! 652: if (isr & IS_AbnormalInterrupt) {
! 653: /* Statistics. */
! 654: if (isr & IS_StatisticWrapInt)
! 655: sf_stats_update(sc);
! 656:
! 657: /* DMA errors. */
! 658: if (isr & IS_DmaErrInt) {
! 659: wantinit = 1;
! 660: printf("%s: WARNING: DMA error\n",
! 661: sc->sc_dev.dv_xname);
! 662: }
! 663:
! 664: /* Transmit FIFO underruns. */
! 665: if (isr & IS_TxDataLowInt) {
! 666: if (sc->sc_txthresh < 0xff)
! 667: sc->sc_txthresh++;
! 668: #ifdef DEBUG
! 669: printf("%s: transmit FIFO underrun, new "
! 670: "threshold: %d bytes\n",
! 671: sc->sc_dev.dv_xname,
! 672: sc->sc_txthresh * 16);
! 673: #endif
! 674: sf_funcreg_write(sc, SF_TransmitFrameCSR,
! 675: sc->sc_TransmitFrameCSR |
! 676: TFCSR_TransmitThreshold(sc->sc_txthresh));
! 677: sf_funcreg_write(sc, SF_TxDescQueueCtrl,
! 678: sc->sc_TxDescQueueCtrl |
! 679: TDQC_TxHighPriorityFifoThreshold(
! 680: sc->sc_txthresh));
! 681: }
! 682: }
! 683: }
! 684:
! 685: if (handled) {
! 686: /* Reset the interface, if necessary. */
! 687: if (wantinit)
! 688: sf_init(&sc->sc_arpcom.ac_if);
! 689:
! 690: /* Try and get more packets going. */
! 691: sf_start(&sc->sc_arpcom.ac_if);
! 692: }
! 693:
! 694: return (handled);
! 695: }
! 696:
! 697: /*
! 698: * sf_txintr:
! 699: *
! 700: * Helper -- handle transmit completion interrupts.
! 701: */
! 702: void
! 703: sf_txintr(struct sf_softc *sc)
! 704: {
! 705: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 706: struct sf_descsoft *ds;
! 707: uint32_t cqci, tcd;
! 708: int consumer, producer, txidx;
! 709:
! 710: try_again:
! 711: cqci = sf_funcreg_read(sc, SF_CompletionQueueConsumerIndex);
! 712:
! 713: consumer = CQCI_TxCompletionConsumerIndex_get(cqci);
! 714: producer = CQPI_TxCompletionProducerIndex_get(
! 715: sf_funcreg_read(sc, SF_CompletionQueueProducerIndex));
! 716:
! 717: if (consumer == producer)
! 718: return;
! 719:
! 720: ifp->if_flags &= ~IFF_OACTIVE;
! 721:
! 722: while (consumer != producer) {
! 723: SF_CDTXCSYNC(sc, consumer, BUS_DMASYNC_POSTREAD);
! 724: tcd = letoh32(sc->sc_txcomp[consumer].tcd_word0);
! 725:
! 726: txidx = SF_TCD_INDEX_TO_HOST(TCD_INDEX(tcd));
! 727: #ifdef DIAGNOSTIC
! 728: if ((tcd & TCD_PR) == 0)
! 729: printf("%s: Tx queue mismatch, index %d\n",
! 730: sc->sc_dev.dv_xname, txidx);
! 731: #endif
! 732: /*
! 733: * NOTE: stats are updated later. We're just
! 734: * releasing packets that have been DMA'd to
! 735: * the chip.
! 736: */
! 737: ds = &sc->sc_txsoft[txidx];
! 738: SF_CDTXDSYNC(sc, txidx, BUS_DMASYNC_POSTWRITE);
! 739: bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap,
! 740: 0, ds->ds_dmamap->dm_mapsize,
! 741: BUS_DMASYNC_POSTWRITE);
! 742: m_freem(ds->ds_mbuf);
! 743: ds->ds_mbuf = NULL;
! 744:
! 745: consumer = SF_NEXTTCD(consumer);
! 746: sc->sc_txpending--;
! 747: }
! 748:
! 749: /* XXXJRT -- should be KDASSERT() */
! 750: KASSERT(sc->sc_txpending >= 0);
! 751:
! 752: /* If all packets are done, cancel the watchdog timer. */
! 753: if (sc->sc_txpending == 0)
! 754: ifp->if_timer = 0;
! 755:
! 756: /* Update the consumer index. */
! 757: sf_funcreg_write(sc, SF_CompletionQueueConsumerIndex,
! 758: (cqci & ~CQCI_TxCompletionConsumerIndex(0x7ff)) |
! 759: CQCI_TxCompletionConsumerIndex(consumer));
! 760:
! 761: /* Double check for new completions. */
! 762: goto try_again;
! 763: }
! 764:
! 765: /*
! 766: * sf_rxintr:
! 767: *
! 768: * Helper -- handle receive interrupts.
! 769: */
! 770: void
! 771: sf_rxintr(struct sf_softc *sc)
! 772: {
! 773: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 774: struct sf_descsoft *ds;
! 775: struct sf_rcd_full *rcd;
! 776: struct mbuf *m;
! 777: uint32_t cqci, word0;
! 778: int consumer, producer, bufproducer, rxidx, len;
! 779:
! 780: try_again:
! 781: cqci = sf_funcreg_read(sc, SF_CompletionQueueConsumerIndex);
! 782:
! 783: consumer = CQCI_RxCompletionQ1ConsumerIndex_get(cqci);
! 784: producer = CQPI_RxCompletionQ1ProducerIndex_get(
! 785: sf_funcreg_read(sc, SF_CompletionQueueProducerIndex));
! 786: bufproducer = RXQ1P_RxDescQ1Producer_get(
! 787: sf_funcreg_read(sc, SF_RxDescQueue1Ptrs));
! 788:
! 789: if (consumer == producer)
! 790: return;
! 791:
! 792: while (consumer != producer) {
! 793: rcd = &sc->sc_rxcomp[consumer];
! 794: SF_CDRXCSYNC(sc, consumer,
! 795: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 796: SF_CDRXCSYNC(sc, consumer,
! 797: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 798:
! 799: word0 = letoh32(rcd->rcd_word0);
! 800: rxidx = RCD_W0_EndIndex(word0);
! 801:
! 802: ds = &sc->sc_rxsoft[rxidx];
! 803:
! 804: consumer = SF_NEXTRCD(consumer);
! 805: bufproducer = SF_NEXTRX(bufproducer);
! 806:
! 807: if ((word0 & RCD_W0_OK) == 0) {
! 808: SF_INIT_RXDESC(sc, rxidx);
! 809: continue;
! 810: }
! 811:
! 812: bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
! 813: ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 814:
! 815: /*
! 816: * No errors; receive the packet. Note that we have
! 817: * configured the Starfire to NOT transfer the CRC
! 818: * with the packet.
! 819: */
! 820: len = RCD_W0_Length(word0);
! 821:
! 822: #ifndef __STRICT_ALIGNMENT
! 823: /*
! 824: * Allocate a new mbuf cluster. If that fails, we are
! 825: * out of memory, and must drop the packet and recycle
! 826: * the buffer that's already attached to this descriptor.
! 827: */
! 828: m = ds->ds_mbuf;
! 829: if (sf_add_rxbuf(sc, rxidx) != 0) {
! 830: ifp->if_ierrors++;
! 831: SF_INIT_RXDESC(sc, rxidx);
! 832: bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
! 833: ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
! 834: continue;
! 835: }
! 836: #else
! 837: /*
! 838: * The Starfire's receive buffer must be 4-byte aligned.
! 839: * But this means that the data after the Ethernet header
! 840: * is misaligned. We must allocate a new buffer and
! 841: * copy the data, shifted forward 2 bytes.
! 842: */
! 843: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 844: if (m == NULL) {
! 845: dropit:
! 846: ifp->if_ierrors++;
! 847: SF_INIT_RXDESC(sc, rxidx);
! 848: bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
! 849: ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
! 850: continue;
! 851: }
! 852: if (len > (MHLEN - 2)) {
! 853: MCLGET(m, M_DONTWAIT);
! 854: if ((m->m_flags & M_EXT) == 0) {
! 855: m_freem(m);
! 856: goto dropit;
! 857: }
! 858: }
! 859: m->m_data += 2;
! 860:
! 861: /*
! 862: * Note that we use cluster for incoming frames, so the
! 863: * buffer is virtually contiguous.
! 864: */
! 865: memcpy(mtod(m, caddr_t), mtod(ds->ds_mbuf, caddr_t), len);
! 866:
! 867: /* Allow the receive descriptor to continue using its mbuf. */
! 868: SF_INIT_RXDESC(sc, rxidx);
! 869: bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
! 870: ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
! 871: #endif /* __STRICT_ALIGNMENT */
! 872:
! 873: m->m_pkthdr.rcvif = ifp;
! 874: m->m_pkthdr.len = m->m_len = len;
! 875:
! 876: #if NBPFILTER > 0
! 877: /*
! 878: * Pass this up to any BPF listeners.
! 879: */
! 880: if (ifp->if_bpf)
! 881: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 882: #endif /* NBPFILTER > 0 */
! 883:
! 884: /* Pass it on. */
! 885: ether_input_mbuf(ifp, m);
! 886: ifp->if_ipackets++;
! 887: }
! 888:
! 889: /* Update the chip's pointers. */
! 890: sf_funcreg_write(sc, SF_CompletionQueueConsumerIndex,
! 891: (cqci & ~CQCI_RxCompletionQ1ConsumerIndex(0x7ff)) |
! 892: CQCI_RxCompletionQ1ConsumerIndex(consumer));
! 893: sf_funcreg_write(sc, SF_RxDescQueue1Ptrs,
! 894: RXQ1P_RxDescQ1Producer(bufproducer));
! 895:
! 896: /* Double-check for any new completions. */
! 897: goto try_again;
! 898: }
! 899:
! 900: /*
! 901: * sf_tick:
! 902: *
! 903: * One second timer, used to tick the MII and update stats.
! 904: */
! 905: void
! 906: sf_tick(void *arg)
! 907: {
! 908: struct sf_softc *sc = arg;
! 909: int s;
! 910:
! 911: s = splnet();
! 912: mii_tick(&sc->sc_mii);
! 913: sf_stats_update(sc);
! 914: splx(s);
! 915:
! 916: timeout_add(&sc->sc_mii_timeout, hz);
! 917: }
! 918:
! 919: /*
! 920: * sf_stats_update:
! 921: *
! 922: * Read the statitistics counters.
! 923: */
! 924: void
! 925: sf_stats_update(struct sf_softc *sc)
! 926: {
! 927: struct sf_stats stats;
! 928: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 929: uint32_t *p;
! 930: u_int i;
! 931:
! 932: p = &stats.TransmitOKFrames;
! 933: for (i = 0; i < (sizeof(stats) / sizeof(uint32_t)); i++) {
! 934: *p++ = sf_genreg_read(sc,
! 935: SF_STATS_BASE + (i * sizeof(uint32_t)));
! 936: sf_genreg_write(sc, SF_STATS_BASE + (i * sizeof(uint32_t)), 0);
! 937: }
! 938:
! 939: ifp->if_opackets += stats.TransmitOKFrames;
! 940:
! 941: ifp->if_collisions += stats.SingleCollisionFrames +
! 942: stats.MultipleCollisionFrames;
! 943:
! 944: ifp->if_oerrors += stats.TransmitAbortDueToExcessiveCollisions +
! 945: stats.TransmitAbortDueToExcessingDeferral +
! 946: stats.FramesLostDueToInternalTransmitErrors;
! 947:
! 948: ifp->if_ipackets += stats.ReceiveOKFrames;
! 949:
! 950: ifp->if_ierrors += stats.ReceiveCRCErrors + stats.AlignmentErrors +
! 951: stats.ReceiveFramesTooLong + stats.ReceiveFramesTooShort +
! 952: stats.ReceiveFramesJabbersError +
! 953: stats.FramesLostDueToInternalReceiveErrors;
! 954: }
! 955:
! 956: /*
! 957: * sf_reset:
! 958: *
! 959: * Perform a soft reset on the Starfire.
! 960: */
! 961: void
! 962: sf_reset(struct sf_softc *sc)
! 963: {
! 964: int i;
! 965:
! 966: sf_funcreg_write(sc, SF_GeneralEthernetCtrl, 0);
! 967:
! 968: sf_macreset(sc);
! 969:
! 970: sf_funcreg_write(sc, SF_PciDeviceConfig, PDC_SoftReset);
! 971: for (i = 0; i < 1000; i++) {
! 972: delay(10);
! 973: if ((sf_funcreg_read(sc, SF_PciDeviceConfig) &
! 974: PDC_SoftReset) == 0)
! 975: break;
! 976: }
! 977:
! 978: if (i == 1000) {
! 979: printf("%s: reset failed to complete\n", sc->sc_dev.dv_xname);
! 980: sf_funcreg_write(sc, SF_PciDeviceConfig, 0);
! 981: }
! 982:
! 983: delay(1000);
! 984: }
! 985:
! 986: /*
! 987: * sf_macreset:
! 988: *
! 989: * Reset the MAC portion of the Starfire.
! 990: */
! 991: void
! 992: sf_macreset(struct sf_softc *sc)
! 993: {
! 994:
! 995: sf_genreg_write(sc, SF_MacConfig1, sc->sc_MacConfig1 | MC1_SoftRst);
! 996: delay(1000);
! 997: sf_genreg_write(sc, SF_MacConfig1, sc->sc_MacConfig1);
! 998: }
! 999:
! 1000: /*
! 1001: * sf_init: [ifnet interface function]
! 1002: *
! 1003: * Initialize the interface. Must be called at splnet().
! 1004: */
! 1005: int
! 1006: sf_init(struct ifnet *ifp)
! 1007: {
! 1008: struct sf_softc *sc = ifp->if_softc;
! 1009: struct sf_descsoft *ds;
! 1010: int error = 0;
! 1011: u_int i;
! 1012:
! 1013: /*
! 1014: * Cancel any pending I/O.
! 1015: */
! 1016: sf_stop(ifp, 0);
! 1017:
! 1018: /*
! 1019: * Reset the Starfire to a known state.
! 1020: */
! 1021: sf_reset(sc);
! 1022:
! 1023: /* Clear the stat counters. */
! 1024: for (i = 0; i < sizeof(struct sf_stats); i += sizeof(uint32_t))
! 1025: sf_genreg_write(sc, SF_STATS_BASE + i, 0);
! 1026:
! 1027: /*
! 1028: * Initialize the transmit descriptor ring.
! 1029: */
! 1030: memset(sc->sc_txdescs, 0, sizeof(sc->sc_txdescs));
! 1031: sf_funcreg_write(sc, SF_TxDescQueueHighAddr, 0);
! 1032: sf_funcreg_write(sc, SF_HiPrTxDescQueueBaseAddr, SF_CDTXDADDR(sc, 0));
! 1033: sf_funcreg_write(sc, SF_LoPrTxDescQueueBaseAddr, 0);
! 1034:
! 1035: /*
! 1036: * Initialize the transmit completion ring.
! 1037: */
! 1038: for (i = 0; i < SF_NTCD; i++) {
! 1039: sc->sc_txcomp[i].tcd_word0 = TCD_DMA_ID;
! 1040: SF_CDTXCSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 1041: }
! 1042: sf_funcreg_write(sc, SF_CompletionQueueHighAddr, 0);
! 1043: sf_funcreg_write(sc, SF_TxCompletionQueueCtrl, SF_CDTXCADDR(sc, 0));
! 1044:
! 1045: /*
! 1046: * Initialize the receive descriptor ring.
! 1047: */
! 1048: for (i = 0; i < SF_NRXDESC; i++) {
! 1049: ds = &sc->sc_rxsoft[i];
! 1050: if (ds->ds_mbuf == NULL) {
! 1051: if ((error = sf_add_rxbuf(sc, i)) != 0) {
! 1052: printf("%s: unable to allocate or map rx "
! 1053: "buffer %d, error = %d\n",
! 1054: sc->sc_dev.dv_xname, i, error);
! 1055: /*
! 1056: * XXX Should attempt to run with fewer receive
! 1057: * XXX buffers instead of just failing.
! 1058: */
! 1059: sf_rxdrain(sc);
! 1060: goto out;
! 1061: }
! 1062: } else
! 1063: SF_INIT_RXDESC(sc, i);
! 1064: }
! 1065: sf_funcreg_write(sc, SF_RxDescQueueHighAddress, 0);
! 1066: sf_funcreg_write(sc, SF_RxDescQueue1LowAddress, SF_CDRXDADDR(sc, 0));
! 1067: sf_funcreg_write(sc, SF_RxDescQueue2LowAddress, 0);
! 1068:
! 1069: /*
! 1070: * Initialize the receive completion ring.
! 1071: */
! 1072: for (i = 0; i < SF_NRCD; i++) {
! 1073: sc->sc_rxcomp[i].rcd_word0 = RCD_W0_ID;
! 1074: sc->sc_rxcomp[i].rcd_word1 = 0;
! 1075: sc->sc_rxcomp[i].rcd_word2 = 0;
! 1076: sc->sc_rxcomp[i].rcd_timestamp = 0;
! 1077: SF_CDRXCSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 1078: }
! 1079: sf_funcreg_write(sc, SF_RxCompletionQueue1Ctrl, SF_CDRXCADDR(sc, 0) |
! 1080: RCQ1C_RxCompletionQ1Type(3));
! 1081: sf_funcreg_write(sc, SF_RxCompletionQueue2Ctrl, 0);
! 1082:
! 1083: /*
! 1084: * Initialize the Tx CSR.
! 1085: */
! 1086: sc->sc_TransmitFrameCSR = 0;
! 1087: sf_funcreg_write(sc, SF_TransmitFrameCSR,
! 1088: sc->sc_TransmitFrameCSR |
! 1089: TFCSR_TransmitThreshold(sc->sc_txthresh));
! 1090:
! 1091: /*
! 1092: * Initialize the Tx descriptor control register.
! 1093: */
! 1094: sc->sc_TxDescQueueCtrl = TDQC_SkipLength(0) |
! 1095: TDQC_TxDmaBurstSize(4) | /* default */
! 1096: TDQC_MinFrameSpacing(3) | /* 128 bytes */
! 1097: TDQC_TxDescType(0);
! 1098: sf_funcreg_write(sc, SF_TxDescQueueCtrl,
! 1099: sc->sc_TxDescQueueCtrl |
! 1100: TDQC_TxHighPriorityFifoThreshold(sc->sc_txthresh));
! 1101:
! 1102: /*
! 1103: * Initialize the Rx descriptor control registers.
! 1104: */
! 1105: sf_funcreg_write(sc, SF_RxDescQueue1Ctrl,
! 1106: RDQ1C_RxQ1BufferLength(MCLBYTES) |
! 1107: RDQ1C_RxDescSpacing(0));
! 1108: sf_funcreg_write(sc, SF_RxDescQueue2Ctrl, 0);
! 1109:
! 1110: /*
! 1111: * Initialize the Tx descriptor producer indices.
! 1112: */
! 1113: sf_funcreg_write(sc, SF_TxDescQueueProducerIndex,
! 1114: TDQPI_HiPrTxProducerIndex(0) |
! 1115: TDQPI_LoPrTxProducerIndex(0));
! 1116:
! 1117: /*
! 1118: * Initialize the Rx descriptor producer indices.
! 1119: */
! 1120: sf_funcreg_write(sc, SF_RxDescQueue1Ptrs,
! 1121: RXQ1P_RxDescQ1Producer(SF_NRXDESC - 1));
! 1122: sf_funcreg_write(sc, SF_RxDescQueue2Ptrs,
! 1123: RXQ2P_RxDescQ2Producer(0));
! 1124:
! 1125: /*
! 1126: * Initialize the Tx and Rx completion queue consumer indices.
! 1127: */
! 1128: sf_funcreg_write(sc, SF_CompletionQueueConsumerIndex,
! 1129: CQCI_TxCompletionConsumerIndex(0) |
! 1130: CQCI_RxCompletionQ1ConsumerIndex(0));
! 1131: sf_funcreg_write(sc, SF_RxHiPrCompletionPtrs, 0);
! 1132:
! 1133: /*
! 1134: * Initialize the Rx DMA control register.
! 1135: */
! 1136: sf_funcreg_write(sc, SF_RxDmaCtrl,
! 1137: RDC_RxHighPriorityThreshold(6) | /* default */
! 1138: RDC_RxBurstSize(4)); /* default */
! 1139:
! 1140: /*
! 1141: * Set the receive filter.
! 1142: */
! 1143: sc->sc_RxAddressFilteringCtl = 0;
! 1144: sf_set_filter(sc);
! 1145:
! 1146: /*
! 1147: * Set MacConfig1. When we set the media, MacConfig1 will
! 1148: * actually be written and the MAC part reset.
! 1149: */
! 1150: sc->sc_MacConfig1 = MC1_PadEn;
! 1151:
! 1152: /*
! 1153: * Set the media.
! 1154: */
! 1155: mii_mediachg(&sc->sc_mii);
! 1156:
! 1157: /*
! 1158: * Initialize the interrupt register.
! 1159: */
! 1160: sc->sc_InterruptEn = IS_PCIPadInt | IS_RxQ1DoneInt |
! 1161: IS_TxQueueDoneInt | IS_TxDmaDoneInt | IS_DmaErrInt |
! 1162: IS_StatisticWrapInt;
! 1163: sf_funcreg_write(sc, SF_InterruptEn, sc->sc_InterruptEn);
! 1164:
! 1165: sf_funcreg_write(sc, SF_PciDeviceConfig, PDC_IntEnable |
! 1166: PDC_PCIMstDmaEn | (1 << PDC_FifoThreshold_SHIFT));
! 1167:
! 1168: /*
! 1169: * Start the transmit and receive processes.
! 1170: */
! 1171: sf_funcreg_write(sc, SF_GeneralEthernetCtrl,
! 1172: GEC_TxDmaEn|GEC_RxDmaEn|GEC_TransmitEn|GEC_ReceiveEn);
! 1173:
! 1174: /* Start the on second clock. */
! 1175: timeout_add(&sc->sc_mii_timeout, hz);
! 1176:
! 1177: /*
! 1178: * Note that the interface is now running.
! 1179: */
! 1180: ifp->if_flags |= IFF_RUNNING;
! 1181: ifp->if_flags &= ~IFF_OACTIVE;
! 1182:
! 1183: out:
! 1184: if (error) {
! 1185: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1186: ifp->if_timer = 0;
! 1187: printf("%s: interface not running\n", sc->sc_dev.dv_xname);
! 1188: }
! 1189: return (error);
! 1190: }
! 1191:
! 1192: /*
! 1193: * sf_rxdrain:
! 1194: *
! 1195: * Drain the receive queue.
! 1196: */
! 1197: void
! 1198: sf_rxdrain(struct sf_softc *sc)
! 1199: {
! 1200: struct sf_descsoft *ds;
! 1201: int i;
! 1202:
! 1203: for (i = 0; i < SF_NRXDESC; i++) {
! 1204: ds = &sc->sc_rxsoft[i];
! 1205: if (ds->ds_mbuf != NULL) {
! 1206: bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
! 1207: m_freem(ds->ds_mbuf);
! 1208: ds->ds_mbuf = NULL;
! 1209: }
! 1210: }
! 1211: }
! 1212:
! 1213: /*
! 1214: * sf_stop: [ifnet interface function]
! 1215: *
! 1216: * Stop transmission on the interface.
! 1217: */
! 1218: void
! 1219: sf_stop(struct ifnet *ifp, int disable)
! 1220: {
! 1221: struct sf_softc *sc = ifp->if_softc;
! 1222: struct sf_descsoft *ds;
! 1223: int i;
! 1224:
! 1225: /* Stop the one second clock. */
! 1226: timeout_del(&sc->sc_mii_timeout);
! 1227:
! 1228: /* Down the MII. */
! 1229: mii_down(&sc->sc_mii);
! 1230:
! 1231: /* Disable interrupts. */
! 1232: sf_funcreg_write(sc, SF_InterruptEn, 0);
! 1233:
! 1234: /* Stop the transmit and receive processes. */
! 1235: sf_funcreg_write(sc, SF_GeneralEthernetCtrl, 0);
! 1236:
! 1237: /*
! 1238: * Release any queued transmit buffers.
! 1239: */
! 1240: for (i = 0; i < SF_NTXDESC; i++) {
! 1241: ds = &sc->sc_txsoft[i];
! 1242: if (ds->ds_mbuf != NULL) {
! 1243: bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
! 1244: m_freem(ds->ds_mbuf);
! 1245: ds->ds_mbuf = NULL;
! 1246: }
! 1247: }
! 1248:
! 1249: if (disable)
! 1250: sf_rxdrain(sc);
! 1251:
! 1252: /*
! 1253: * Mark the interface down and cancel the watchdog timer.
! 1254: */
! 1255: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1256: ifp->if_timer = 0;
! 1257: }
! 1258:
! 1259: /*
! 1260: * sf_read_eeprom:
! 1261: *
! 1262: * Read from the Starfire EEPROM.
! 1263: */
! 1264: uint8_t
! 1265: sf_read_eeprom(struct sf_softc *sc, int offset)
! 1266: {
! 1267: uint32_t reg;
! 1268:
! 1269: reg = sf_genreg_read(sc, SF_EEPROM_BASE + (offset & ~3));
! 1270:
! 1271: return ((reg >> (8 * (offset & 3))) & 0xff);
! 1272: }
! 1273:
! 1274: /*
! 1275: * sf_add_rxbuf:
! 1276: *
! 1277: * Add a receive buffer to the indicated descriptor.
! 1278: */
! 1279: int
! 1280: sf_add_rxbuf(struct sf_softc *sc, int idx)
! 1281: {
! 1282: struct sf_descsoft *ds = &sc->sc_rxsoft[idx];
! 1283: struct mbuf *m;
! 1284: int error;
! 1285:
! 1286: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1287: if (m == NULL)
! 1288: return (ENOBUFS);
! 1289:
! 1290: MCLGET(m, M_DONTWAIT);
! 1291: if ((m->m_flags & M_EXT) == 0) {
! 1292: m_freem(m);
! 1293: return (ENOBUFS);
! 1294: }
! 1295:
! 1296: if (ds->ds_mbuf != NULL)
! 1297: bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
! 1298:
! 1299: ds->ds_mbuf = m;
! 1300:
! 1301: error = bus_dmamap_load(sc->sc_dmat, ds->ds_dmamap,
! 1302: m->m_ext.ext_buf, m->m_ext.ext_size, NULL,
! 1303: BUS_DMA_READ|BUS_DMA_NOWAIT);
! 1304: if (error) {
! 1305: printf("%s: can't load rx DMA map %d, error = %d\n",
! 1306: sc->sc_dev.dv_xname, idx, error);
! 1307: panic("sf_add_rxbuf"); /* XXX */
! 1308: }
! 1309:
! 1310: bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
! 1311: ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
! 1312:
! 1313: SF_INIT_RXDESC(sc, idx);
! 1314:
! 1315: return (0);
! 1316: }
! 1317:
! 1318: void
! 1319: sf_set_filter_perfect(struct sf_softc *sc, int slot, uint8_t *enaddr)
! 1320: {
! 1321: uint32_t reg0, reg1, reg2;
! 1322:
! 1323: reg0 = enaddr[5] | (enaddr[4] << 8);
! 1324: reg1 = enaddr[3] | (enaddr[2] << 8);
! 1325: reg2 = enaddr[1] | (enaddr[0] << 8);
! 1326:
! 1327: sf_genreg_write(sc, SF_PERFECT_BASE + (slot * 0x10) + 0, reg0);
! 1328: sf_genreg_write(sc, SF_PERFECT_BASE + (slot * 0x10) + 4, reg1);
! 1329: sf_genreg_write(sc, SF_PERFECT_BASE + (slot * 0x10) + 8, reg2);
! 1330: }
! 1331:
! 1332: void
! 1333: sf_set_filter_hash(struct sf_softc *sc, uint8_t *enaddr)
! 1334: {
! 1335: uint32_t hash, slot, reg;
! 1336:
! 1337: hash = ether_crc32_be(enaddr, ETHER_ADDR_LEN) >> 23;
! 1338: slot = hash >> 4;
! 1339:
! 1340: reg = sf_genreg_read(sc, SF_HASH_BASE + (slot * 0x10));
! 1341: reg |= 1 << (hash & 0xf);
! 1342: sf_genreg_write(sc, SF_HASH_BASE + (slot * 0x10), reg);
! 1343: }
! 1344:
! 1345: /*
! 1346: * sf_set_filter:
! 1347: *
! 1348: * Set the Starfire receive filter.
! 1349: */
! 1350: void
! 1351: sf_set_filter(struct sf_softc *sc)
! 1352: {
! 1353: struct arpcom *ac = &sc->sc_arpcom;
! 1354: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1355: struct ether_multi *enm;
! 1356: struct ether_multistep step;
! 1357: int i;
! 1358:
! 1359: /* Start by clearing the perfect and hash tables. */
! 1360: for (i = 0; i < SF_PERFECT_SIZE; i += sizeof(uint32_t))
! 1361: sf_genreg_write(sc, SF_PERFECT_BASE + i, 0);
! 1362:
! 1363: for (i = 0; i < SF_HASH_SIZE; i += sizeof(uint32_t))
! 1364: sf_genreg_write(sc, SF_HASH_BASE + i, 0);
! 1365:
! 1366: /*
! 1367: * Clear the perfect and hash mode bits.
! 1368: */
! 1369: sc->sc_RxAddressFilteringCtl &=
! 1370: ~(RAFC_PerfectFilteringMode(3) | RAFC_HashFilteringMode(3));
! 1371:
! 1372: if (ifp->if_flags & IFF_BROADCAST)
! 1373: sc->sc_RxAddressFilteringCtl |= RAFC_PassBroadcast;
! 1374: else
! 1375: sc->sc_RxAddressFilteringCtl &= ~RAFC_PassBroadcast;
! 1376:
! 1377: if (ifp->if_flags & IFF_PROMISC) {
! 1378: sc->sc_RxAddressFilteringCtl |= RAFC_PromiscuousMode;
! 1379: goto allmulti;
! 1380: } else
! 1381: sc->sc_RxAddressFilteringCtl &= ~RAFC_PromiscuousMode;
! 1382:
! 1383: /*
! 1384: * Set normal perfect filtering mode.
! 1385: */
! 1386: sc->sc_RxAddressFilteringCtl |= RAFC_PerfectFilteringMode(1);
! 1387:
! 1388: /*
! 1389: * First, write the station address to the perfect filter
! 1390: * table.
! 1391: */
! 1392: sf_set_filter_perfect(sc, 0, LLADDR(ifp->if_sadl));
! 1393:
! 1394: /*
! 1395: * Now set the hash bits for each multicast address in our
! 1396: * list.
! 1397: */
! 1398: ETHER_FIRST_MULTI(step, ac, enm);
! 1399: if (enm == NULL)
! 1400: goto done;
! 1401: while (enm != NULL) {
! 1402: if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
! 1403: /*
! 1404: * We must listen to a range of multicast addresses.
! 1405: * For now, just accept all multicasts, rather than
! 1406: * trying to set only those filter bits needed to match
! 1407: * the range. (At this time, the only use of address
! 1408: * ranges is for IP multicast routing, for which the
! 1409: * range is big enough to require all bits set.)
! 1410: */
! 1411: goto allmulti;
! 1412: }
! 1413: sf_set_filter_hash(sc, enm->enm_addrlo);
! 1414: ETHER_NEXT_MULTI(step, enm);
! 1415: }
! 1416:
! 1417: /*
! 1418: * Set "hash only multicast dest, match regardless of VLAN ID".
! 1419: */
! 1420: sc->sc_RxAddressFilteringCtl |= RAFC_HashFilteringMode(2);
! 1421: goto done;
! 1422:
! 1423: allmulti:
! 1424: /*
! 1425: * XXX RAFC_PassMulticast is sub-optimal if using VLAN mode.
! 1426: */
! 1427: sc->sc_RxAddressFilteringCtl |= RAFC_PassMulticast;
! 1428: ifp->if_flags |= IFF_ALLMULTI;
! 1429:
! 1430: done:
! 1431: sf_funcreg_write(sc, SF_RxAddressFilteringCtl,
! 1432: sc->sc_RxAddressFilteringCtl);
! 1433: }
! 1434:
! 1435: /*
! 1436: * sf_mii_read: [mii interface function]
! 1437: *
! 1438: * Read from the MII.
! 1439: */
! 1440: int
! 1441: sf_mii_read(struct device *self, int phy, int reg)
! 1442: {
! 1443: struct sf_softc *sc = (void *) self;
! 1444: uint32_t v;
! 1445: int i;
! 1446:
! 1447: for (i = 0; i < 1000; i++) {
! 1448: v = sf_genreg_read(sc, SF_MII_PHY_REG(phy, reg));
! 1449: if (v & MiiDataValid)
! 1450: break;
! 1451: delay(1);
! 1452: }
! 1453:
! 1454: if ((v & MiiDataValid) == 0)
! 1455: return (0);
! 1456:
! 1457: if (MiiRegDataPort(v) == 0xffff)
! 1458: return (0);
! 1459:
! 1460: return (MiiRegDataPort(v));
! 1461: }
! 1462:
! 1463: /*
! 1464: * sf_mii_write: [mii interface function]
! 1465: *
! 1466: * Write to the MII.
! 1467: */
! 1468: void
! 1469: sf_mii_write(struct device *self, int phy, int reg, int val)
! 1470: {
! 1471: struct sf_softc *sc = (void *) self;
! 1472: int i;
! 1473:
! 1474: sf_genreg_write(sc, SF_MII_PHY_REG(phy, reg), val);
! 1475:
! 1476: for (i = 0; i < 1000; i++) {
! 1477: if ((sf_genreg_read(sc, SF_MII_PHY_REG(phy, reg)) &
! 1478: MiiBusy) == 0)
! 1479: return;
! 1480: delay(1);
! 1481: }
! 1482:
! 1483: printf("%s: MII write timed out\n", sc->sc_dev.dv_xname);
! 1484: }
! 1485:
! 1486: /*
! 1487: * sf_mii_statchg: [mii interface function]
! 1488: *
! 1489: * Callback from the PHY when the media changes.
! 1490: */
! 1491: void
! 1492: sf_mii_statchg(struct device *self)
! 1493: {
! 1494: struct sf_softc *sc = (void *) self;
! 1495: uint32_t ipg;
! 1496:
! 1497: if (sc->sc_mii.mii_media_active & IFM_FDX) {
! 1498: sc->sc_MacConfig1 |= MC1_FullDuplex;
! 1499: ipg = 0x15;
! 1500: } else {
! 1501: sc->sc_MacConfig1 &= ~MC1_FullDuplex;
! 1502: ipg = 0x11;
! 1503: }
! 1504:
! 1505: sf_genreg_write(sc, SF_MacConfig1, sc->sc_MacConfig1);
! 1506: sf_macreset(sc);
! 1507:
! 1508: sf_genreg_write(sc, SF_BkToBkIPG, ipg);
! 1509: }
! 1510:
! 1511: /*
! 1512: * sf_mediastatus: [ifmedia interface function]
! 1513: *
! 1514: * Callback from ifmedia to request current media status.
! 1515: */
! 1516: void
! 1517: sf_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
! 1518: {
! 1519: struct sf_softc *sc = ifp->if_softc;
! 1520:
! 1521: mii_pollstat(&sc->sc_mii);
! 1522: ifmr->ifm_status = sc->sc_mii.mii_media_status;
! 1523: ifmr->ifm_active = sc->sc_mii.mii_media_active;
! 1524: }
! 1525:
! 1526: /*
! 1527: * sf_mediachange: [ifmedia interface function]
! 1528: *
! 1529: * Callback from ifmedia to request new media setting.
! 1530: */
! 1531: int
! 1532: sf_mediachange(struct ifnet *ifp)
! 1533: {
! 1534: struct sf_softc *sc = ifp->if_softc;
! 1535:
! 1536: if (ifp->if_flags & IFF_UP)
! 1537: mii_mediachg(&sc->sc_mii);
! 1538: return (0);
! 1539: }
CVSweb