Annotation of sys/dev/pci/if_ste.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_ste.c,v 1.40 2007/07/17 23:25:15 krw Exp $ */
! 2: /*
! 3: * Copyright (c) 1997, 1998, 1999
! 4: * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: * 3. All advertising materials mentioning features or use of this software
! 15: * must display the following acknowledgement:
! 16: * This product includes software developed by Bill Paul.
! 17: * 4. Neither the name of the author nor the names of any co-contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
! 25: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 26: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 27: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 28: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 29: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 30: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 31: * THE POSSIBILITY OF SUCH DAMAGE.
! 32: *
! 33: * $FreeBSD: src/sys/pci/if_ste.c,v 1.14 1999/12/07 20:14:42 wpaul Exp $
! 34: */
! 35:
! 36: #include "bpfilter.h"
! 37:
! 38: #include <sys/param.h>
! 39: #include <sys/systm.h>
! 40: #include <sys/mbuf.h>
! 41: #include <sys/protosw.h>
! 42: #include <sys/socket.h>
! 43: #include <sys/ioctl.h>
! 44: #include <sys/errno.h>
! 45: #include <sys/malloc.h>
! 46: #include <sys/kernel.h>
! 47: #include <sys/timeout.h>
! 48:
! 49: #include <net/if.h>
! 50: #include <net/if_dl.h>
! 51: #include <net/if_types.h>
! 52:
! 53: #ifdef INET
! 54: #include <netinet/in.h>
! 55: #include <netinet/in_systm.h>
! 56: #include <netinet/in_var.h>
! 57: #include <netinet/ip.h>
! 58: #include <netinet/if_ether.h>
! 59: #endif
! 60:
! 61: #include <net/if_media.h>
! 62:
! 63: #if NBPFILTER > 0
! 64: #include <net/bpf.h>
! 65: #endif
! 66:
! 67: #include <uvm/uvm_extern.h> /* for vtophys */
! 68:
! 69: #include <sys/device.h>
! 70:
! 71: #include <dev/mii/mii.h>
! 72: #include <dev/mii/miivar.h>
! 73:
! 74: #include <dev/pci/pcireg.h>
! 75: #include <dev/pci/pcivar.h>
! 76: #include <dev/pci/pcidevs.h>
! 77:
! 78: #define STE_USEIOSPACE
! 79:
! 80: #include <dev/pci/if_stereg.h>
! 81:
! 82: int ste_probe(struct device *, void *, void *);
! 83: void ste_attach(struct device *, struct device *, void *);
! 84: int ste_intr(void *);
! 85: void ste_shutdown(void *);
! 86: void ste_init(void *);
! 87: void ste_rxeoc(struct ste_softc *);
! 88: void ste_rxeof(struct ste_softc *);
! 89: void ste_txeoc(struct ste_softc *);
! 90: void ste_txeof(struct ste_softc *);
! 91: void ste_stats_update(void *);
! 92: void ste_stop(struct ste_softc *);
! 93: void ste_reset(struct ste_softc *);
! 94: int ste_ioctl(struct ifnet *, u_long, caddr_t);
! 95: int ste_encap(struct ste_softc *, struct ste_chain *,
! 96: struct mbuf *);
! 97: void ste_start(struct ifnet *);
! 98: void ste_watchdog(struct ifnet *);
! 99: int ste_newbuf(struct ste_softc *,
! 100: struct ste_chain_onefrag *,
! 101: struct mbuf *);
! 102: int ste_ifmedia_upd(struct ifnet *);
! 103: void ste_ifmedia_sts(struct ifnet *, struct ifmediareq *);
! 104:
! 105: void ste_mii_sync(struct ste_softc *);
! 106: void ste_mii_send(struct ste_softc *, u_int32_t, int);
! 107: int ste_mii_readreg(struct ste_softc *,
! 108: struct ste_mii_frame *);
! 109: int ste_mii_writereg(struct ste_softc *,
! 110: struct ste_mii_frame *);
! 111: int ste_miibus_readreg(struct device *, int, int);
! 112: void ste_miibus_writereg(struct device *, int, int, int);
! 113: void ste_miibus_statchg(struct device *);
! 114:
! 115: int ste_eeprom_wait(struct ste_softc *);
! 116: int ste_read_eeprom(struct ste_softc *, caddr_t, int,
! 117: int, int);
! 118: void ste_wait(struct ste_softc *);
! 119: void ste_setmulti(struct ste_softc *);
! 120: int ste_init_rx_list(struct ste_softc *);
! 121: void ste_init_tx_list(struct ste_softc *);
! 122:
! 123: #define STE_SETBIT4(sc, reg, x) \
! 124: CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | x)
! 125:
! 126: #define STE_CLRBIT4(sc, reg, x) \
! 127: CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~x)
! 128:
! 129: #define STE_SETBIT2(sc, reg, x) \
! 130: CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) | x)
! 131:
! 132: #define STE_CLRBIT2(sc, reg, x) \
! 133: CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) & ~x)
! 134:
! 135: #define STE_SETBIT1(sc, reg, x) \
! 136: CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) | x)
! 137:
! 138: #define STE_CLRBIT1(sc, reg, x) \
! 139: CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) & ~x)
! 140:
! 141:
! 142: #define MII_SET(x) STE_SETBIT1(sc, STE_PHYCTL, x)
! 143: #define MII_CLR(x) STE_CLRBIT1(sc, STE_PHYCTL, x)
! 144:
! 145: struct cfattach ste_ca = {
! 146: sizeof(struct ste_softc), ste_probe, ste_attach
! 147: };
! 148:
! 149: struct cfdriver ste_cd = {
! 150: 0, "ste", DV_IFNET
! 151: };
! 152:
! 153: /*
! 154: * Sync the PHYs by setting data bit and strobing the clock 32 times.
! 155: */
! 156: void
! 157: ste_mii_sync(struct ste_softc *sc)
! 158: {
! 159: int i;
! 160:
! 161: MII_SET(STE_PHYCTL_MDIR|STE_PHYCTL_MDATA);
! 162:
! 163: for (i = 0; i < 32; i++) {
! 164: MII_SET(STE_PHYCTL_MCLK);
! 165: DELAY(1);
! 166: MII_CLR(STE_PHYCTL_MCLK);
! 167: DELAY(1);
! 168: }
! 169:
! 170: return;
! 171: }
! 172:
! 173: /*
! 174: * Clock a series of bits through the MII.
! 175: */
! 176: void
! 177: ste_mii_send(struct ste_softc *sc, u_int32_t bits, int cnt)
! 178: {
! 179: int i;
! 180:
! 181: MII_CLR(STE_PHYCTL_MCLK);
! 182:
! 183: for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
! 184: if (bits & i) {
! 185: MII_SET(STE_PHYCTL_MDATA);
! 186: } else {
! 187: MII_CLR(STE_PHYCTL_MDATA);
! 188: }
! 189: DELAY(1);
! 190: MII_CLR(STE_PHYCTL_MCLK);
! 191: DELAY(1);
! 192: MII_SET(STE_PHYCTL_MCLK);
! 193: }
! 194: }
! 195:
! 196: /*
! 197: * Read an PHY register through the MII.
! 198: */
! 199: int
! 200: ste_mii_readreg(struct ste_softc *sc, struct ste_mii_frame *frame)
! 201: {
! 202: int ack, i, s;
! 203:
! 204: s = splnet();
! 205:
! 206: /*
! 207: * Set up frame for RX.
! 208: */
! 209: frame->mii_stdelim = STE_MII_STARTDELIM;
! 210: frame->mii_opcode = STE_MII_READOP;
! 211: frame->mii_turnaround = 0;
! 212: frame->mii_data = 0;
! 213:
! 214: CSR_WRITE_2(sc, STE_PHYCTL, 0);
! 215: /*
! 216: * Turn on data xmit.
! 217: */
! 218: MII_SET(STE_PHYCTL_MDIR);
! 219:
! 220: ste_mii_sync(sc);
! 221:
! 222: /*
! 223: * Send command/address info.
! 224: */
! 225: ste_mii_send(sc, frame->mii_stdelim, 2);
! 226: ste_mii_send(sc, frame->mii_opcode, 2);
! 227: ste_mii_send(sc, frame->mii_phyaddr, 5);
! 228: ste_mii_send(sc, frame->mii_regaddr, 5);
! 229:
! 230: /* Turn off xmit. */
! 231: MII_CLR(STE_PHYCTL_MDIR);
! 232:
! 233: /* Idle bit */
! 234: MII_CLR((STE_PHYCTL_MCLK|STE_PHYCTL_MDATA));
! 235: DELAY(1);
! 236: MII_SET(STE_PHYCTL_MCLK);
! 237: DELAY(1);
! 238:
! 239: /* Check for ack */
! 240: MII_CLR(STE_PHYCTL_MCLK);
! 241: DELAY(1);
! 242: ack = CSR_READ_2(sc, STE_PHYCTL) & STE_PHYCTL_MDATA;
! 243: MII_SET(STE_PHYCTL_MCLK);
! 244: DELAY(1);
! 245:
! 246: /*
! 247: * Now try reading data bits. If the ack failed, we still
! 248: * need to clock through 16 cycles to keep the PHY(s) in sync.
! 249: */
! 250: if (ack) {
! 251: for(i = 0; i < 16; i++) {
! 252: MII_CLR(STE_PHYCTL_MCLK);
! 253: DELAY(1);
! 254: MII_SET(STE_PHYCTL_MCLK);
! 255: DELAY(1);
! 256: }
! 257: goto fail;
! 258: }
! 259:
! 260: for (i = 0x8000; i; i >>= 1) {
! 261: MII_CLR(STE_PHYCTL_MCLK);
! 262: DELAY(1);
! 263: if (!ack) {
! 264: if (CSR_READ_2(sc, STE_PHYCTL) & STE_PHYCTL_MDATA)
! 265: frame->mii_data |= i;
! 266: DELAY(1);
! 267: }
! 268: MII_SET(STE_PHYCTL_MCLK);
! 269: DELAY(1);
! 270: }
! 271:
! 272: fail:
! 273:
! 274: MII_CLR(STE_PHYCTL_MCLK);
! 275: DELAY(1);
! 276: MII_SET(STE_PHYCTL_MCLK);
! 277: DELAY(1);
! 278:
! 279: splx(s);
! 280:
! 281: if (ack)
! 282: return(1);
! 283: return(0);
! 284: }
! 285:
! 286: /*
! 287: * Write to a PHY register through the MII.
! 288: */
! 289: int
! 290: ste_mii_writereg(struct ste_softc *sc, struct ste_mii_frame *frame)
! 291: {
! 292: int s;
! 293:
! 294: s = splnet();
! 295: /*
! 296: * Set up frame for TX.
! 297: */
! 298:
! 299: frame->mii_stdelim = STE_MII_STARTDELIM;
! 300: frame->mii_opcode = STE_MII_WRITEOP;
! 301: frame->mii_turnaround = STE_MII_TURNAROUND;
! 302:
! 303: /*
! 304: * Turn on data output.
! 305: */
! 306: MII_SET(STE_PHYCTL_MDIR);
! 307:
! 308: ste_mii_sync(sc);
! 309:
! 310: ste_mii_send(sc, frame->mii_stdelim, 2);
! 311: ste_mii_send(sc, frame->mii_opcode, 2);
! 312: ste_mii_send(sc, frame->mii_phyaddr, 5);
! 313: ste_mii_send(sc, frame->mii_regaddr, 5);
! 314: ste_mii_send(sc, frame->mii_turnaround, 2);
! 315: ste_mii_send(sc, frame->mii_data, 16);
! 316:
! 317: /* Idle bit. */
! 318: MII_SET(STE_PHYCTL_MCLK);
! 319: DELAY(1);
! 320: MII_CLR(STE_PHYCTL_MCLK);
! 321: DELAY(1);
! 322:
! 323: /*
! 324: * Turn off xmit.
! 325: */
! 326: MII_CLR(STE_PHYCTL_MDIR);
! 327:
! 328: splx(s);
! 329:
! 330: return(0);
! 331: }
! 332:
! 333: int
! 334: ste_miibus_readreg(struct device *self, int phy, int reg)
! 335: {
! 336: struct ste_softc *sc = (struct ste_softc *)self;
! 337: struct ste_mii_frame frame;
! 338:
! 339: if (sc->ste_one_phy && phy != 0)
! 340: return (0);
! 341:
! 342: bzero((char *)&frame, sizeof(frame));
! 343:
! 344: frame.mii_phyaddr = phy;
! 345: frame.mii_regaddr = reg;
! 346: ste_mii_readreg(sc, &frame);
! 347:
! 348: return(frame.mii_data);
! 349: }
! 350:
! 351: void
! 352: ste_miibus_writereg(struct device *self, int phy, int reg, int data)
! 353: {
! 354: struct ste_softc *sc = (struct ste_softc *)self;
! 355: struct ste_mii_frame frame;
! 356:
! 357: bzero((char *)&frame, sizeof(frame));
! 358:
! 359: frame.mii_phyaddr = phy;
! 360: frame.mii_regaddr = reg;
! 361: frame.mii_data = data;
! 362:
! 363: ste_mii_writereg(sc, &frame);
! 364:
! 365: return;
! 366: }
! 367:
! 368: void
! 369: ste_miibus_statchg(struct device *self)
! 370: {
! 371: struct ste_softc *sc = (struct ste_softc *)self;
! 372: struct mii_data *mii;
! 373: int fdx, fcur;
! 374:
! 375: mii = &sc->sc_mii;
! 376:
! 377: fcur = CSR_READ_2(sc, STE_MACCTL0) & STE_MACCTL0_FULLDUPLEX;
! 378: fdx = (mii->mii_media_active & IFM_GMASK) == IFM_FDX;
! 379:
! 380: if ((fcur && fdx) || (! fcur && ! fdx))
! 381: return;
! 382:
! 383: STE_SETBIT4(sc, STE_DMACTL,
! 384: STE_DMACTL_RXDMA_STALL |STE_DMACTL_TXDMA_STALL);
! 385: ste_wait(sc);
! 386:
! 387: if (fdx)
! 388: STE_SETBIT2(sc, STE_MACCTL0, STE_MACCTL0_FULLDUPLEX);
! 389: else
! 390: STE_CLRBIT2(sc, STE_MACCTL0, STE_MACCTL0_FULLDUPLEX);
! 391:
! 392: STE_SETBIT4(sc, STE_DMACTL,
! 393: STE_DMACTL_RXDMA_UNSTALL | STE_DMACTL_TXDMA_UNSTALL);
! 394:
! 395: return;
! 396: }
! 397:
! 398: int
! 399: ste_ifmedia_upd(struct ifnet *ifp)
! 400: {
! 401: struct ste_softc *sc;
! 402: struct mii_data *mii;
! 403:
! 404: sc = ifp->if_softc;
! 405: mii = &sc->sc_mii;
! 406: sc->ste_link = 0;
! 407: if (mii->mii_instance) {
! 408: struct mii_softc *miisc;
! 409: LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
! 410: mii_phy_reset(miisc);
! 411: }
! 412: mii_mediachg(mii);
! 413:
! 414: return(0);
! 415: }
! 416:
! 417: void
! 418: ste_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
! 419: {
! 420: struct ste_softc *sc;
! 421: struct mii_data *mii;
! 422:
! 423: sc = ifp->if_softc;
! 424: mii = &sc->sc_mii;
! 425:
! 426: mii_pollstat(mii);
! 427: ifmr->ifm_active = mii->mii_media_active;
! 428: ifmr->ifm_status = mii->mii_media_status;
! 429:
! 430: return;
! 431: }
! 432:
! 433: void
! 434: ste_wait(struct ste_softc *sc)
! 435: {
! 436: int i;
! 437:
! 438: for (i = 0; i < STE_TIMEOUT; i++) {
! 439: if (!(CSR_READ_4(sc, STE_DMACTL) & STE_DMACTL_DMA_HALTINPROG))
! 440: break;
! 441: }
! 442:
! 443: if (i == STE_TIMEOUT)
! 444: printf("%s: command never completed!\n", sc->sc_dev.dv_xname);
! 445:
! 446: return;
! 447: }
! 448:
! 449: /*
! 450: * The EEPROM is slow: give it time to come ready after issuing
! 451: * it a command.
! 452: */
! 453: int
! 454: ste_eeprom_wait(struct ste_softc *sc)
! 455: {
! 456: int i;
! 457:
! 458: DELAY(1000);
! 459:
! 460: for (i = 0; i < 100; i++) {
! 461: if (CSR_READ_2(sc, STE_EEPROM_CTL) & STE_EECTL_BUSY)
! 462: DELAY(1000);
! 463: else
! 464: break;
! 465: }
! 466:
! 467: if (i == 100) {
! 468: printf("%s: eeprom failed to come ready\n",
! 469: sc->sc_dev.dv_xname);
! 470: return(1);
! 471: }
! 472:
! 473: return(0);
! 474: }
! 475:
! 476: /*
! 477: * Read a sequence of words from the EEPROM. Note that ethernet address
! 478: * data is stored in the EEPROM in network byte order.
! 479: */
! 480: int
! 481: ste_read_eeprom(struct ste_softc *sc, caddr_t dest, int off, int cnt, int swap)
! 482: {
! 483: int err = 0, i;
! 484: u_int16_t word = 0, *ptr;
! 485:
! 486: if (ste_eeprom_wait(sc))
! 487: return(1);
! 488:
! 489: for (i = 0; i < cnt; i++) {
! 490: CSR_WRITE_2(sc, STE_EEPROM_CTL, STE_EEOPCODE_READ | (off + i));
! 491: err = ste_eeprom_wait(sc);
! 492: if (err)
! 493: break;
! 494: word = CSR_READ_2(sc, STE_EEPROM_DATA);
! 495: ptr = (u_int16_t *)(dest + (i * 2));
! 496: if (swap)
! 497: *ptr = ntohs(word);
! 498: else
! 499: *ptr = word;
! 500: }
! 501:
! 502: return(err ? 1 : 0);
! 503: }
! 504:
! 505: void
! 506: ste_setmulti(struct ste_softc *sc)
! 507: {
! 508: struct ifnet *ifp;
! 509: struct arpcom *ac = &sc->arpcom;
! 510: struct ether_multi *enm;
! 511: struct ether_multistep step;
! 512: int h = 0;
! 513: u_int32_t hashes[2] = { 0, 0 };
! 514:
! 515: ifp = &sc->arpcom.ac_if;
! 516: allmulti:
! 517: if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
! 518: STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_ALLMULTI);
! 519: STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_MULTIHASH);
! 520: return;
! 521: }
! 522:
! 523: /* first, zot all the existing hash bits */
! 524: CSR_WRITE_2(sc, STE_MAR0, 0);
! 525: CSR_WRITE_2(sc, STE_MAR1, 0);
! 526: CSR_WRITE_2(sc, STE_MAR2, 0);
! 527: CSR_WRITE_2(sc, STE_MAR3, 0);
! 528:
! 529: /* now program new ones */
! 530: ETHER_FIRST_MULTI(step, ac, enm);
! 531: while (enm != NULL) {
! 532: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
! 533: ifp->if_flags |= IFF_ALLMULTI;
! 534: goto allmulti;
! 535: }
! 536: h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) & 0x3F;
! 537: if (h < 32)
! 538: hashes[0] |= (1 << h);
! 539: else
! 540: hashes[1] |= (1 << (h - 32));
! 541: ETHER_NEXT_MULTI(step, enm);
! 542: }
! 543:
! 544: CSR_WRITE_2(sc, STE_MAR0, hashes[0] & 0xFFFF);
! 545: CSR_WRITE_2(sc, STE_MAR1, (hashes[0] >> 16) & 0xFFFF);
! 546: CSR_WRITE_2(sc, STE_MAR2, hashes[1] & 0xFFFF);
! 547: CSR_WRITE_2(sc, STE_MAR3, (hashes[1] >> 16) & 0xFFFF);
! 548: STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_ALLMULTI);
! 549: STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_MULTIHASH);
! 550:
! 551: return;
! 552: }
! 553:
! 554: int
! 555: ste_intr(void *xsc)
! 556: {
! 557: struct ste_softc *sc;
! 558: struct ifnet *ifp;
! 559: u_int16_t status;
! 560: int claimed = 0;
! 561:
! 562: sc = xsc;
! 563: ifp = &sc->arpcom.ac_if;
! 564:
! 565: /* See if this is really our interrupt. */
! 566: if (!(CSR_READ_2(sc, STE_ISR) & STE_ISR_INTLATCH))
! 567: return claimed;
! 568:
! 569: for (;;) {
! 570: status = CSR_READ_2(sc, STE_ISR_ACK);
! 571:
! 572: if (!(status & STE_INTRS))
! 573: break;
! 574:
! 575: claimed = 1;
! 576:
! 577: if (status & STE_ISR_RX_DMADONE) {
! 578: ste_rxeoc(sc);
! 579: ste_rxeof(sc);
! 580: }
! 581:
! 582: if (status & STE_ISR_TX_DMADONE)
! 583: ste_txeof(sc);
! 584:
! 585: if (status & STE_ISR_TX_DONE)
! 586: ste_txeoc(sc);
! 587:
! 588: if (status & STE_ISR_STATS_OFLOW) {
! 589: timeout_del(&sc->sc_stats_tmo);
! 590: ste_stats_update(sc);
! 591: }
! 592:
! 593: if (status & STE_ISR_LINKEVENT)
! 594: mii_pollstat(&sc->sc_mii);
! 595:
! 596: if (status & STE_ISR_HOSTERR) {
! 597: ste_reset(sc);
! 598: ste_init(sc);
! 599: }
! 600: }
! 601:
! 602: /* Re-enable interrupts */
! 603: CSR_WRITE_2(sc, STE_IMR, STE_INTRS);
! 604:
! 605: if (ifp->if_flags & IFF_RUNNING && !IFQ_IS_EMPTY(&ifp->if_snd))
! 606: ste_start(ifp);
! 607:
! 608: return claimed;
! 609: }
! 610:
! 611: void
! 612: ste_rxeoc(struct ste_softc *sc)
! 613: {
! 614: struct ste_chain_onefrag *cur_rx;
! 615:
! 616: if (sc->ste_cdata.ste_rx_head->ste_ptr->ste_status == 0) {
! 617: cur_rx = sc->ste_cdata.ste_rx_head;
! 618: do {
! 619: cur_rx = cur_rx->ste_next;
! 620: /* If the ring is empty, just return. */
! 621: if (cur_rx == sc->ste_cdata.ste_rx_head)
! 622: return;
! 623: } while (cur_rx->ste_ptr->ste_status == 0);
! 624: if (sc->ste_cdata.ste_rx_head->ste_ptr->ste_status == 0) {
! 625: /* We've fallen behind the chip: catch it. */
! 626: sc->ste_cdata.ste_rx_head = cur_rx;
! 627: }
! 628: }
! 629: }
! 630:
! 631: /*
! 632: * A frame has been uploaded: pass the resulting mbuf chain up to
! 633: * the higher level protocols.
! 634: */
! 635: void
! 636: ste_rxeof(struct ste_softc *sc)
! 637: {
! 638: struct mbuf *m;
! 639: struct ifnet *ifp;
! 640: struct ste_chain_onefrag *cur_rx;
! 641: int total_len = 0, count=0;
! 642: u_int32_t rxstat;
! 643:
! 644: ifp = &sc->arpcom.ac_if;
! 645:
! 646: while((rxstat = sc->ste_cdata.ste_rx_head->ste_ptr->ste_status)
! 647: & STE_RXSTAT_DMADONE) {
! 648: if ((STE_RX_LIST_CNT - count) < 3)
! 649: break;
! 650:
! 651: cur_rx = sc->ste_cdata.ste_rx_head;
! 652: sc->ste_cdata.ste_rx_head = cur_rx->ste_next;
! 653:
! 654: /*
! 655: * If an error occurs, update stats, clear the
! 656: * status word and leave the mbuf cluster in place:
! 657: * it should simply get re-used next time this descriptor
! 658: * comes up in the ring.
! 659: */
! 660: if (rxstat & STE_RXSTAT_FRAME_ERR) {
! 661: ifp->if_ierrors++;
! 662: cur_rx->ste_ptr->ste_status = 0;
! 663: continue;
! 664: }
! 665:
! 666: /*
! 667: * If there error bit was not set, the upload complete
! 668: * bit should be set which means we have a valid packet.
! 669: * If not, something truly strange has happened.
! 670: */
! 671: if (!(rxstat & STE_RXSTAT_DMADONE)) {
! 672: printf("%s: bad receive status -- packet dropped",
! 673: sc->sc_dev.dv_xname);
! 674: ifp->if_ierrors++;
! 675: cur_rx->ste_ptr->ste_status = 0;
! 676: continue;
! 677: }
! 678:
! 679: /* No errors; receive the packet. */
! 680: m = cur_rx->ste_mbuf;
! 681: total_len = cur_rx->ste_ptr->ste_status & STE_RXSTAT_FRAMELEN;
! 682:
! 683: /*
! 684: * Try to conjure up a new mbuf cluster. If that
! 685: * fails, it means we have an out of memory condition and
! 686: * should leave the buffer in place and continue. This will
! 687: * result in a lost packet, but there's little else we
! 688: * can do in this situation.
! 689: */
! 690: if (ste_newbuf(sc, cur_rx, NULL) == ENOBUFS) {
! 691: ifp->if_ierrors++;
! 692: cur_rx->ste_ptr->ste_status = 0;
! 693: continue;
! 694: }
! 695:
! 696: m->m_pkthdr.rcvif = ifp;
! 697: m->m_pkthdr.len = m->m_len = total_len;
! 698:
! 699: ifp->if_ipackets++;
! 700:
! 701: #if NBPFILTER > 0
! 702: if (ifp->if_bpf)
! 703: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 704: #endif
! 705:
! 706: /* pass it on. */
! 707: ether_input_mbuf(ifp, m);
! 708:
! 709: cur_rx->ste_ptr->ste_status = 0;
! 710: count++;
! 711: }
! 712:
! 713: return;
! 714: }
! 715:
! 716: void
! 717: ste_txeoc(struct ste_softc *sc)
! 718: {
! 719: u_int8_t txstat;
! 720: struct ifnet *ifp;
! 721:
! 722: ifp = &sc->arpcom.ac_if;
! 723:
! 724: while ((txstat = CSR_READ_1(sc, STE_TX_STATUS)) &
! 725: STE_TXSTATUS_TXDONE) {
! 726: if (txstat & STE_TXSTATUS_UNDERRUN ||
! 727: txstat & STE_TXSTATUS_EXCESSCOLLS ||
! 728: txstat & STE_TXSTATUS_RECLAIMERR) {
! 729: ifp->if_oerrors++;
! 730: printf("%s: transmission error: %x\n",
! 731: sc->sc_dev.dv_xname, txstat);
! 732:
! 733: ste_reset(sc);
! 734: ste_init(sc);
! 735:
! 736: if (txstat & STE_TXSTATUS_UNDERRUN &&
! 737: sc->ste_tx_thresh < ETHER_MAX_DIX_LEN) {
! 738: sc->ste_tx_thresh += STE_MIN_FRAMELEN;
! 739: printf("%s: tx underrun, increasing tx"
! 740: " start threshold to %d bytes\n",
! 741: sc->sc_dev.dv_xname, sc->ste_tx_thresh);
! 742: }
! 743: CSR_WRITE_2(sc, STE_TX_STARTTHRESH, sc->ste_tx_thresh);
! 744: CSR_WRITE_2(sc, STE_TX_RECLAIM_THRESH,
! 745: (ETHER_MAX_DIX_LEN >> 4));
! 746: }
! 747: ste_init(sc);
! 748: CSR_WRITE_2(sc, STE_TX_STATUS, txstat);
! 749: }
! 750:
! 751: return;
! 752: }
! 753:
! 754: void
! 755: ste_txeof(struct ste_softc *sc)
! 756: {
! 757: struct ste_chain *cur_tx = NULL;
! 758: struct ifnet *ifp;
! 759: int idx;
! 760:
! 761: ifp = &sc->arpcom.ac_if;
! 762:
! 763: idx = sc->ste_cdata.ste_tx_cons;
! 764: while(idx != sc->ste_cdata.ste_tx_prod) {
! 765: cur_tx = &sc->ste_cdata.ste_tx_chain[idx];
! 766:
! 767: if (!(cur_tx->ste_ptr->ste_ctl & STE_TXCTL_DMADONE))
! 768: break;
! 769:
! 770: m_freem(cur_tx->ste_mbuf);
! 771: cur_tx->ste_mbuf = NULL;
! 772: ifp->if_flags &= ~IFF_OACTIVE;
! 773: ifp->if_opackets++;
! 774:
! 775: STE_INC(idx, STE_TX_LIST_CNT);
! 776: }
! 777:
! 778: sc->ste_cdata.ste_tx_cons = idx;
! 779: if (idx == sc->ste_cdata.ste_tx_prod)
! 780: ifp->if_timer = 0;
! 781:
! 782: return;
! 783: }
! 784:
! 785: void
! 786: ste_stats_update(void *xsc)
! 787: {
! 788: struct ste_softc *sc;
! 789: struct ifnet *ifp;
! 790: struct mii_data *mii;
! 791: int s;
! 792:
! 793: s = splnet();
! 794:
! 795: sc = xsc;
! 796: ifp = &sc->arpcom.ac_if;
! 797: mii = &sc->sc_mii;
! 798:
! 799: ifp->if_collisions += CSR_READ_1(sc, STE_LATE_COLLS)
! 800: + CSR_READ_1(sc, STE_MULTI_COLLS)
! 801: + CSR_READ_1(sc, STE_SINGLE_COLLS);
! 802:
! 803: if (!sc->ste_link) {
! 804: mii_pollstat(mii);
! 805: if (mii->mii_media_status & IFM_ACTIVE &&
! 806: IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
! 807: sc->ste_link++;
! 808: /*
! 809: * we don't get a call-back on re-init so do it
! 810: * otherwise we get stuck in the wrong link state
! 811: */
! 812: ste_miibus_statchg((struct device *)sc);
! 813: if (!IFQ_IS_EMPTY(&ifp->if_snd))
! 814: ste_start(ifp);
! 815: }
! 816: }
! 817:
! 818: timeout_add(&sc->sc_stats_tmo, hz);
! 819: splx(s);
! 820:
! 821: return;
! 822: }
! 823:
! 824: const struct pci_matchid ste_devices[] = {
! 825: { PCI_VENDOR_SUNDANCE, PCI_PRODUCT_SUNDANCE_ST201_1 },
! 826: { PCI_VENDOR_SUNDANCE, PCI_PRODUCT_SUNDANCE_ST201_2 },
! 827: { PCI_VENDOR_DLINK, PCI_PRODUCT_DLINK_550TX }
! 828: };
! 829:
! 830: /*
! 831: * Probe for a Sundance ST201 chip. Check the PCI vendor and device
! 832: * IDs against our list and return a device name if we find a match.
! 833: */
! 834: int
! 835: ste_probe(struct device *parent, void *match, void *aux)
! 836: {
! 837: return (pci_matchbyid((struct pci_attach_args *)aux, ste_devices,
! 838: sizeof(ste_devices)/sizeof(ste_devices[0])));
! 839: }
! 840:
! 841: /*
! 842: * Attach the interface. Allocate softc structures, do ifmedia
! 843: * setup and ethernet/BPF attach.
! 844: */
! 845: void
! 846: ste_attach(struct device *parent, struct device *self, void *aux)
! 847: {
! 848: const char *intrstr = NULL;
! 849: pcireg_t command;
! 850: struct ste_softc *sc = (struct ste_softc *)self;
! 851: struct pci_attach_args *pa = aux;
! 852: pci_chipset_tag_t pc = pa->pa_pc;
! 853: pci_intr_handle_t ih;
! 854: struct ifnet *ifp;
! 855: bus_size_t size;
! 856:
! 857: /*
! 858: * Handle power management nonsense.
! 859: */
! 860: command = pci_conf_read(pc, pa->pa_tag, STE_PCI_CAPID) & 0x000000FF;
! 861: if (command == 0x01) {
! 862:
! 863: command = pci_conf_read(pc, pa->pa_tag, STE_PCI_PWRMGMTCTRL);
! 864: if (command & STE_PSTATE_MASK) {
! 865: u_int32_t iobase, membase, irq;
! 866:
! 867: /* Save important PCI config data. */
! 868: iobase = pci_conf_read(pc, pa->pa_tag, STE_PCI_LOIO);
! 869: membase = pci_conf_read(pc, pa->pa_tag, STE_PCI_LOMEM);
! 870: irq = pci_conf_read(pc, pa->pa_tag, STE_PCI_INTLINE);
! 871:
! 872: /* Reset the power state. */
! 873: printf("%s: chip is in D%d power mode -- setting to D0\n",
! 874: sc->sc_dev.dv_xname, command & STE_PSTATE_MASK);
! 875: command &= 0xFFFFFFFC;
! 876: pci_conf_write(pc, pa->pa_tag, STE_PCI_PWRMGMTCTRL, command);
! 877:
! 878: /* Restore PCI config data. */
! 879: pci_conf_write(pc, pa->pa_tag, STE_PCI_LOIO, iobase);
! 880: pci_conf_write(pc, pa->pa_tag, STE_PCI_LOMEM, membase);
! 881: pci_conf_write(pc, pa->pa_tag, STE_PCI_INTLINE, irq);
! 882: }
! 883: }
! 884:
! 885: /*
! 886: * Only use one PHY since this chip reports multiple
! 887: * Note on the DFE-550 the PHY is at 1 on the DFE-580
! 888: * it is at 0 & 1. It is rev 0x12.
! 889: */
! 890: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_DLINK &&
! 891: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_DLINK_550TX &&
! 892: PCI_REVISION(pa->pa_class) == 0x12)
! 893: sc->ste_one_phy = 1;
! 894:
! 895: /*
! 896: * Map control/status registers.
! 897: */
! 898:
! 899: #ifdef STE_USEIOSPACE
! 900: if (pci_mapreg_map(pa, STE_PCI_LOIO,
! 901: PCI_MAPREG_TYPE_IO, 0,
! 902: &sc->ste_btag, &sc->ste_bhandle, NULL, &size, 0)) {
! 903: printf(": can't map i/o space\n");
! 904: return;
! 905: }
! 906: #else
! 907: if (pci_mapreg_map(pa, STE_PCI_LOMEM,
! 908: PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
! 909: &sc->ste_btag, &sc->ste_bhandle, NULL, &size, 0)) {
! 910: printf(": can't map mem space\n");
! 911: return;
! 912: }
! 913: #endif
! 914:
! 915: /* Allocate interrupt */
! 916: if (pci_intr_map(pa, &ih)) {
! 917: printf(": couldn't map interrupt\n");
! 918: goto fail_1;
! 919: }
! 920: intrstr = pci_intr_string(pc, ih);
! 921: sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, ste_intr, sc,
! 922: self->dv_xname);
! 923: if (sc->sc_ih == NULL) {
! 924: printf(": couldn't establish interrupt");
! 925: if (intrstr != NULL)
! 926: printf(" at %s", intrstr);
! 927: printf("\n");
! 928: goto fail_1;
! 929: }
! 930: printf(": %s", intrstr);
! 931:
! 932: /* Reset the adapter. */
! 933: ste_reset(sc);
! 934:
! 935: /*
! 936: * Get station address from the EEPROM.
! 937: */
! 938: if (ste_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr,
! 939: STE_EEADDR_NODE0, 3, 0)) {
! 940: printf(": failed to read station address\n");
! 941: goto fail_2;
! 942: }
! 943:
! 944: printf(", address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
! 945:
! 946: sc->ste_ldata_ptr = malloc(sizeof(struct ste_list_data) + 8,
! 947: M_DEVBUF, M_DONTWAIT);
! 948: if (sc->ste_ldata_ptr == NULL) {
! 949: printf(": no memory for list buffers!\n");
! 950: goto fail_2;
! 951: }
! 952:
! 953: sc->ste_ldata = (struct ste_list_data *)sc->ste_ldata_ptr;
! 954: bzero(sc->ste_ldata, sizeof(struct ste_list_data));
! 955:
! 956: ifp = &sc->arpcom.ac_if;
! 957: ifp->if_softc = sc;
! 958: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 959: ifp->if_ioctl = ste_ioctl;
! 960: ifp->if_start = ste_start;
! 961: ifp->if_watchdog = ste_watchdog;
! 962: ifp->if_baudrate = 10000000;
! 963: IFQ_SET_MAXLEN(&ifp->if_snd, STE_TX_LIST_CNT - 1);
! 964: IFQ_SET_READY(&ifp->if_snd);
! 965: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 966: ifp->if_capabilities = IFCAP_VLAN_MTU;
! 967:
! 968: sc->ste_tx_thresh = STE_TXSTART_THRESH;
! 969:
! 970: sc->sc_mii.mii_ifp = ifp;
! 971: sc->sc_mii.mii_readreg = ste_miibus_readreg;
! 972: sc->sc_mii.mii_writereg = ste_miibus_writereg;
! 973: sc->sc_mii.mii_statchg = ste_miibus_statchg;
! 974: ifmedia_init(&sc->sc_mii.mii_media, 0, ste_ifmedia_upd,ste_ifmedia_sts);
! 975: mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
! 976: 0);
! 977: if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
! 978: ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
! 979: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
! 980: } else
! 981: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
! 982:
! 983: /*
! 984: * Call MI attach routines.
! 985: */
! 986: if_attach(ifp);
! 987: ether_ifattach(ifp);
! 988:
! 989: shutdownhook_establish(ste_shutdown, sc);
! 990: return;
! 991:
! 992: fail_2:
! 993: pci_intr_disestablish(pc, sc->sc_ih);
! 994:
! 995: fail_1:
! 996: bus_space_unmap(sc->ste_btag, sc->ste_bhandle, size);
! 997: }
! 998:
! 999: int
! 1000: ste_newbuf(struct ste_softc *sc, struct ste_chain_onefrag *c, struct mbuf *m)
! 1001: {
! 1002: struct mbuf *m_new = NULL;
! 1003:
! 1004: if (m == NULL) {
! 1005: MGETHDR(m_new, M_DONTWAIT, MT_DATA);
! 1006: if (m_new == NULL)
! 1007: return(ENOBUFS);
! 1008: MCLGET(m_new, M_DONTWAIT);
! 1009: if (!(m_new->m_flags & M_EXT)) {
! 1010: m_freem(m_new);
! 1011: return(ENOBUFS);
! 1012: }
! 1013: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 1014: } else {
! 1015: m_new = m;
! 1016: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 1017: m_new->m_data = m_new->m_ext.ext_buf;
! 1018: }
! 1019:
! 1020: m_adj(m_new, ETHER_ALIGN);
! 1021:
! 1022: c->ste_mbuf = m_new;
! 1023: c->ste_ptr->ste_status = 0;
! 1024: c->ste_ptr->ste_frag.ste_addr = vtophys(mtod(m_new, vaddr_t));
! 1025: c->ste_ptr->ste_frag.ste_len = (ETHER_MAX_DIX_LEN + ETHER_VLAN_ENCAP_LEN) | STE_FRAG_LAST;
! 1026:
! 1027: return(0);
! 1028: }
! 1029:
! 1030: int
! 1031: ste_init_rx_list(struct ste_softc *sc)
! 1032: {
! 1033: struct ste_chain_data *cd;
! 1034: struct ste_list_data *ld;
! 1035: int i;
! 1036:
! 1037: cd = &sc->ste_cdata;
! 1038: ld = sc->ste_ldata;
! 1039:
! 1040: for (i = 0; i < STE_RX_LIST_CNT; i++) {
! 1041: cd->ste_rx_chain[i].ste_ptr = &ld->ste_rx_list[i];
! 1042: if (ste_newbuf(sc, &cd->ste_rx_chain[i], NULL) == ENOBUFS)
! 1043: return(ENOBUFS);
! 1044: if (i == (STE_RX_LIST_CNT - 1)) {
! 1045: cd->ste_rx_chain[i].ste_next =
! 1046: &cd->ste_rx_chain[0];
! 1047: ld->ste_rx_list[i].ste_next =
! 1048: vtophys((vaddr_t)&ld->ste_rx_list[0]);
! 1049: } else {
! 1050: cd->ste_rx_chain[i].ste_next =
! 1051: &cd->ste_rx_chain[i + 1];
! 1052: ld->ste_rx_list[i].ste_next =
! 1053: vtophys((vaddr_t)&ld->ste_rx_list[i + 1]);
! 1054: }
! 1055: ld->ste_rx_list[i].ste_status = 0;
! 1056: }
! 1057:
! 1058: cd->ste_rx_head = &cd->ste_rx_chain[0];
! 1059:
! 1060: return(0);
! 1061: }
! 1062:
! 1063: void
! 1064: ste_init_tx_list(struct ste_softc *sc)
! 1065: {
! 1066: struct ste_chain_data *cd;
! 1067: struct ste_list_data *ld;
! 1068: int i;
! 1069:
! 1070: cd = &sc->ste_cdata;
! 1071: ld = sc->ste_ldata;
! 1072: for (i = 0; i < STE_TX_LIST_CNT; i++) {
! 1073: cd->ste_tx_chain[i].ste_ptr = &ld->ste_tx_list[i];
! 1074: cd->ste_tx_chain[i].ste_phys = vtophys((vaddr_t)&ld->ste_tx_list[i]);
! 1075: if (i == (STE_TX_LIST_CNT - 1))
! 1076: cd->ste_tx_chain[i].ste_next =
! 1077: &cd->ste_tx_chain[0];
! 1078: else
! 1079: cd->ste_tx_chain[i].ste_next =
! 1080: &cd->ste_tx_chain[i + 1];
! 1081: }
! 1082:
! 1083: bzero((char *)ld->ste_tx_list,
! 1084: sizeof(struct ste_desc) * STE_TX_LIST_CNT);
! 1085:
! 1086: cd->ste_tx_prod = 0;
! 1087: cd->ste_tx_cons = 0;
! 1088:
! 1089: return;
! 1090: }
! 1091:
! 1092: void
! 1093: ste_init(void *xsc)
! 1094: {
! 1095: struct ste_softc *sc = (struct ste_softc *)xsc;
! 1096: struct ifnet *ifp = &sc->arpcom.ac_if;
! 1097: struct mii_data *mii;
! 1098: int i, s;
! 1099:
! 1100: s = splnet();
! 1101:
! 1102: ste_stop(sc);
! 1103:
! 1104: mii = &sc->sc_mii;
! 1105:
! 1106: /* Init our MAC address */
! 1107: for (i = 0; i < ETHER_ADDR_LEN; i++) {
! 1108: CSR_WRITE_1(sc, STE_PAR0 + i, sc->arpcom.ac_enaddr[i]);
! 1109: }
! 1110:
! 1111: /* Init RX list */
! 1112: if (ste_init_rx_list(sc) == ENOBUFS) {
! 1113: printf("%s: initialization failed: no "
! 1114: "memory for RX buffers\n", sc->sc_dev.dv_xname);
! 1115: ste_stop(sc);
! 1116: splx(s);
! 1117: return;
! 1118: }
! 1119:
! 1120: /* Set RX polling interval */
! 1121: CSR_WRITE_1(sc, STE_RX_DMAPOLL_PERIOD, 64);
! 1122:
! 1123: /* Init TX descriptors */
! 1124: ste_init_tx_list(sc);
! 1125:
! 1126: /* Set the TX freethresh value */
! 1127: CSR_WRITE_1(sc, STE_TX_DMABURST_THRESH, ETHER_MAX_DIX_LEN >> 8);
! 1128:
! 1129: /* Set the TX start threshold for best performance. */
! 1130: CSR_WRITE_2(sc, STE_TX_STARTTHRESH, sc->ste_tx_thresh);
! 1131:
! 1132: /* Set the TX reclaim threshold. */
! 1133: CSR_WRITE_1(sc, STE_TX_RECLAIM_THRESH, (ETHER_MAX_DIX_LEN >> 4));
! 1134:
! 1135: /* Set up the RX filter. */
! 1136: CSR_WRITE_1(sc, STE_RX_MODE, STE_RXMODE_UNICAST);
! 1137:
! 1138: /* If we want promiscuous mode, set the allframes bit. */
! 1139: if (ifp->if_flags & IFF_PROMISC) {
! 1140: STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_PROMISC);
! 1141: } else {
! 1142: STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_PROMISC);
! 1143: }
! 1144:
! 1145: /* Set capture broadcast bit to accept broadcast frames. */
! 1146: if (ifp->if_flags & IFF_BROADCAST) {
! 1147: STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_BROADCAST);
! 1148: } else {
! 1149: STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_BROADCAST);
! 1150: }
! 1151:
! 1152: ste_setmulti(sc);
! 1153:
! 1154: /* Load the address of the RX list. */
! 1155: STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
! 1156: ste_wait(sc);
! 1157: CSR_WRITE_4(sc, STE_RX_DMALIST_PTR,
! 1158: vtophys((vaddr_t)&sc->ste_ldata->ste_rx_list[0]));
! 1159: STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL);
! 1160: STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL);
! 1161:
! 1162: /* Set TX polling interval (defer until we TX first packet) */
! 1163: CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 0);
! 1164:
! 1165: /* Load address of the TX list */
! 1166: STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
! 1167: ste_wait(sc);
! 1168: CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, 0);
! 1169: STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
! 1170: STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
! 1171: ste_wait(sc);
! 1172: sc->ste_tx_prev=NULL;
! 1173:
! 1174: /* Enable receiver and transmitter */
! 1175: CSR_WRITE_2(sc, STE_MACCTL0, 0);
! 1176: CSR_WRITE_2(sc, STE_MACCTL1, 0);
! 1177: STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_TX_ENABLE);
! 1178: STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_RX_ENABLE);
! 1179:
! 1180: /* Enable stats counters. */
! 1181: STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_STATS_ENABLE);
! 1182:
! 1183: /* Enable interrupts. */
! 1184: CSR_WRITE_2(sc, STE_ISR, 0xFFFF);
! 1185: CSR_WRITE_2(sc, STE_IMR, STE_INTRS);
! 1186:
! 1187: /* Accept VLAN length packets */
! 1188: CSR_WRITE_2(sc, STE_MAX_FRAMELEN,
! 1189: ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
! 1190:
! 1191: ste_ifmedia_upd(ifp);
! 1192:
! 1193: ifp->if_flags |= IFF_RUNNING;
! 1194: ifp->if_flags &= ~IFF_OACTIVE;
! 1195:
! 1196: splx(s);
! 1197:
! 1198: timeout_set(&sc->sc_stats_tmo, ste_stats_update, sc);
! 1199: timeout_add(&sc->sc_stats_tmo, hz);
! 1200:
! 1201: return;
! 1202: }
! 1203:
! 1204: void
! 1205: ste_stop(struct ste_softc *sc)
! 1206: {
! 1207: int i;
! 1208: struct ifnet *ifp;
! 1209:
! 1210: ifp = &sc->arpcom.ac_if;
! 1211:
! 1212: timeout_del(&sc->sc_stats_tmo);
! 1213:
! 1214: ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
! 1215:
! 1216: CSR_WRITE_2(sc, STE_IMR, 0);
! 1217: STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_TX_DISABLE);
! 1218: STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_RX_DISABLE);
! 1219: STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_STATS_DISABLE);
! 1220: STE_SETBIT2(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
! 1221: STE_SETBIT2(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
! 1222: ste_wait(sc);
! 1223: /*
! 1224: * Try really hard to stop the RX engine or under heavy RX
! 1225: * data chip will write into de-allocated memory.
! 1226: */
! 1227: ste_reset(sc);
! 1228:
! 1229: sc->ste_link = 0;
! 1230:
! 1231: for (i = 0; i < STE_RX_LIST_CNT; i++) {
! 1232: if (sc->ste_cdata.ste_rx_chain[i].ste_mbuf != NULL) {
! 1233: m_freem(sc->ste_cdata.ste_rx_chain[i].ste_mbuf);
! 1234: sc->ste_cdata.ste_rx_chain[i].ste_mbuf = NULL;
! 1235: }
! 1236: }
! 1237:
! 1238: for (i = 0; i < STE_TX_LIST_CNT; i++) {
! 1239: if (sc->ste_cdata.ste_tx_chain[i].ste_mbuf != NULL) {
! 1240: m_freem(sc->ste_cdata.ste_tx_chain[i].ste_mbuf);
! 1241: sc->ste_cdata.ste_tx_chain[i].ste_mbuf = NULL;
! 1242: }
! 1243: }
! 1244:
! 1245: bzero(sc->ste_ldata, sizeof(struct ste_list_data));
! 1246:
! 1247: return;
! 1248: }
! 1249:
! 1250: void
! 1251: ste_reset(struct ste_softc *sc)
! 1252: {
! 1253: int i;
! 1254:
! 1255: STE_SETBIT4(sc, STE_ASICCTL,
! 1256: STE_ASICCTL_GLOBAL_RESET|STE_ASICCTL_RX_RESET|
! 1257: STE_ASICCTL_TX_RESET|STE_ASICCTL_DMA_RESET|
! 1258: STE_ASICCTL_FIFO_RESET|STE_ASICCTL_NETWORK_RESET|
! 1259: STE_ASICCTL_AUTOINIT_RESET|STE_ASICCTL_HOST_RESET|
! 1260: STE_ASICCTL_EXTRESET_RESET);
! 1261:
! 1262: DELAY(100000);
! 1263:
! 1264: for (i = 0; i < STE_TIMEOUT; i++) {
! 1265: if (!(CSR_READ_4(sc, STE_ASICCTL) & STE_ASICCTL_RESET_BUSY))
! 1266: break;
! 1267: }
! 1268:
! 1269: if (i == STE_TIMEOUT)
! 1270: printf("%s: global reset never completed\n",
! 1271: sc->sc_dev.dv_xname);
! 1272: }
! 1273:
! 1274: int
! 1275: ste_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
! 1276: {
! 1277: struct ste_softc *sc = ifp->if_softc;
! 1278: struct ifreq *ifr = (struct ifreq *) data;
! 1279: struct ifaddr *ifa = (struct ifaddr *)data;
! 1280: struct mii_data *mii;
! 1281: int s, error = 0;
! 1282:
! 1283: s = splnet();
! 1284:
! 1285: if ((error = ether_ioctl(ifp, &sc->arpcom, command, data)) > 0) {
! 1286: splx(s);
! 1287: return error;
! 1288: }
! 1289:
! 1290: switch(command) {
! 1291: case SIOCSIFADDR:
! 1292: ifp->if_flags |= IFF_UP;
! 1293: switch (ifa->ifa_addr->sa_family) {
! 1294: case AF_INET:
! 1295: ste_init(sc);
! 1296: arp_ifinit(&sc->arpcom, ifa);
! 1297: break;
! 1298: default:
! 1299: ste_init(sc);
! 1300: break;
! 1301: }
! 1302: break;
! 1303: case SIOCSIFFLAGS:
! 1304: if (ifp->if_flags & IFF_UP) {
! 1305: if (ifp->if_flags & IFF_RUNNING &&
! 1306: ifp->if_flags & IFF_PROMISC &&
! 1307: !(sc->ste_if_flags & IFF_PROMISC)) {
! 1308: STE_SETBIT1(sc, STE_RX_MODE,
! 1309: STE_RXMODE_PROMISC);
! 1310: } else if (ifp->if_flags & IFF_RUNNING &&
! 1311: !(ifp->if_flags & IFF_PROMISC) &&
! 1312: sc->ste_if_flags & IFF_PROMISC) {
! 1313: STE_CLRBIT1(sc, STE_RX_MODE,
! 1314: STE_RXMODE_PROMISC);
! 1315: }
! 1316: if (ifp->if_flags & IFF_RUNNING &&
! 1317: (ifp->if_flags ^ sc->ste_if_flags) & IFF_ALLMULTI)
! 1318: ste_setmulti(sc);
! 1319: if (!(ifp->if_flags & IFF_RUNNING)) {
! 1320: sc->ste_tx_thresh = STE_TXSTART_THRESH;
! 1321: ste_init(sc);
! 1322: }
! 1323: } else {
! 1324: if (ifp->if_flags & IFF_RUNNING)
! 1325: ste_stop(sc);
! 1326: }
! 1327: sc->ste_if_flags = ifp->if_flags;
! 1328: error = 0;
! 1329: break;
! 1330: case SIOCADDMULTI:
! 1331: case SIOCDELMULTI:
! 1332: error = (command == SIOCADDMULTI) ?
! 1333: ether_addmulti(ifr, &sc->arpcom) :
! 1334: ether_delmulti(ifr, &sc->arpcom);
! 1335:
! 1336: if (error == ENETRESET) {
! 1337: /*
! 1338: * Multicast list has changed; set the hardware
! 1339: * filter accordingly.
! 1340: */
! 1341: if (ifp->if_flags & IFF_RUNNING)
! 1342: ste_setmulti(sc);
! 1343: error = 0;
! 1344: }
! 1345: break;
! 1346: case SIOCGIFMEDIA:
! 1347: case SIOCSIFMEDIA:
! 1348: mii = &sc->sc_mii;
! 1349: error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
! 1350: break;
! 1351: default:
! 1352: error = ENOTTY;
! 1353: break;
! 1354: }
! 1355:
! 1356: splx(s);
! 1357:
! 1358: return(error);
! 1359: }
! 1360:
! 1361: int
! 1362: ste_encap(struct ste_softc *sc, struct ste_chain *c, struct mbuf *m_head)
! 1363: {
! 1364: int frag = 0;
! 1365: struct ste_frag *f = NULL;
! 1366: struct mbuf *m;
! 1367: struct ste_desc *d;
! 1368:
! 1369: d = c->ste_ptr;
! 1370: d->ste_ctl = 0;
! 1371:
! 1372: encap_retry:
! 1373: for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
! 1374: if (m->m_len != 0) {
! 1375: if (frag == STE_MAXFRAGS)
! 1376: break;
! 1377: f = &d->ste_frags[frag];
! 1378: f->ste_addr = vtophys(mtod(m, vaddr_t));
! 1379: f->ste_len = m->m_len;
! 1380: frag++;
! 1381: }
! 1382: }
! 1383:
! 1384: if (m != NULL) {
! 1385: struct mbuf *mn;
! 1386:
! 1387: /*
! 1388: * We ran out of segments. We have to recopy this
! 1389: * mbuf chain first. Bail out if we can't get the
! 1390: * new buffers.
! 1391: */
! 1392: MGETHDR(mn, M_DONTWAIT, MT_DATA);
! 1393: if (mn == NULL) {
! 1394: m_freem(m_head);
! 1395: return ENOMEM;
! 1396: }
! 1397: if (m_head->m_pkthdr.len > MHLEN) {
! 1398: MCLGET(mn, M_DONTWAIT);
! 1399: if ((mn->m_flags & M_EXT) == 0) {
! 1400: m_freem(mn);
! 1401: m_freem(m_head);
! 1402: return ENOMEM;
! 1403: }
! 1404: }
! 1405: m_copydata(m_head, 0, m_head->m_pkthdr.len,
! 1406: mtod(mn, caddr_t));
! 1407: mn->m_pkthdr.len = mn->m_len = m_head->m_pkthdr.len;
! 1408: m_freem(m_head);
! 1409: m_head = mn;
! 1410: goto encap_retry;
! 1411: }
! 1412:
! 1413: c->ste_mbuf = m_head;
! 1414: d->ste_frags[frag - 1].ste_len |= STE_FRAG_LAST;
! 1415: d->ste_ctl = 1;
! 1416:
! 1417: return(0);
! 1418: }
! 1419:
! 1420: void
! 1421: ste_start(struct ifnet *ifp)
! 1422: {
! 1423: struct ste_softc *sc;
! 1424: struct mbuf *m_head = NULL;
! 1425: struct ste_chain *cur_tx;
! 1426: int idx;
! 1427:
! 1428: sc = ifp->if_softc;
! 1429:
! 1430: if (!sc->ste_link)
! 1431: return;
! 1432:
! 1433: if (ifp->if_flags & IFF_OACTIVE)
! 1434: return;
! 1435:
! 1436: idx = sc->ste_cdata.ste_tx_prod;
! 1437:
! 1438: while(sc->ste_cdata.ste_tx_chain[idx].ste_mbuf == NULL) {
! 1439: /*
! 1440: * We cannot re-use the last (free) descriptor;
! 1441: * the chip may not have read its ste_next yet.
! 1442: */
! 1443: if (STE_NEXT(idx, STE_TX_LIST_CNT) ==
! 1444: sc->ste_cdata.ste_tx_cons) {
! 1445: ifp->if_flags |= IFF_OACTIVE;
! 1446: break;
! 1447: }
! 1448:
! 1449: IFQ_DEQUEUE(&ifp->if_snd, m_head);
! 1450: if (m_head == NULL)
! 1451: break;
! 1452:
! 1453: cur_tx = &sc->ste_cdata.ste_tx_chain[idx];
! 1454:
! 1455: if (ste_encap(sc, cur_tx, m_head) != 0)
! 1456: break;
! 1457:
! 1458: cur_tx->ste_ptr->ste_next = 0;
! 1459:
! 1460: if (sc->ste_tx_prev == NULL) {
! 1461: cur_tx->ste_ptr->ste_ctl = STE_TXCTL_DMAINTR | 1;
! 1462: /* Load address of the TX list */
! 1463: STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
! 1464: ste_wait(sc);
! 1465:
! 1466: CSR_WRITE_4(sc, STE_TX_DMALIST_PTR,
! 1467: vtophys((vaddr_t)&sc->ste_ldata->ste_tx_list[0]));
! 1468:
! 1469: /* Set TX polling interval to start TX engine */
! 1470: CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 64);
! 1471:
! 1472: STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
! 1473: ste_wait(sc);
! 1474: }else{
! 1475: cur_tx->ste_ptr->ste_ctl = STE_TXCTL_DMAINTR | 1;
! 1476: sc->ste_tx_prev->ste_ptr->ste_next
! 1477: = cur_tx->ste_phys;
! 1478: }
! 1479:
! 1480: sc->ste_tx_prev = cur_tx;
! 1481:
! 1482: #if NBPFILTER > 0
! 1483: /*
! 1484: * If there's a BPF listener, bounce a copy of this frame
! 1485: * to him.
! 1486: */
! 1487: if (ifp->if_bpf)
! 1488: bpf_mtap(ifp->if_bpf, cur_tx->ste_mbuf,
! 1489: BPF_DIRECTION_OUT);
! 1490: #endif
! 1491:
! 1492: STE_INC(idx, STE_TX_LIST_CNT);
! 1493: ifp->if_timer = 5;
! 1494: }
! 1495: sc->ste_cdata.ste_tx_prod = idx;
! 1496:
! 1497: return;
! 1498: }
! 1499:
! 1500: void
! 1501: ste_watchdog(struct ifnet *ifp)
! 1502: {
! 1503: struct ste_softc *sc;
! 1504:
! 1505: sc = ifp->if_softc;
! 1506:
! 1507: ifp->if_oerrors++;
! 1508: printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
! 1509:
! 1510: ste_txeoc(sc);
! 1511: ste_txeof(sc);
! 1512: ste_rxeoc(sc);
! 1513: ste_rxeof(sc);
! 1514: ste_reset(sc);
! 1515: ste_init(sc);
! 1516:
! 1517: if (!IFQ_IS_EMPTY(&ifp->if_snd))
! 1518: ste_start(ifp);
! 1519:
! 1520: return;
! 1521: }
! 1522:
! 1523: void
! 1524: ste_shutdown(void *v)
! 1525: {
! 1526: struct ste_softc *sc = (struct ste_softc *)v;
! 1527:
! 1528: ste_stop(sc);
! 1529: }
CVSweb