Date: Fri, 24 Sep 2004 15:41:28 +0200 From: "Thomas" <news@undercover.dk> To: <freebsd-net@freebsd.org> Subject: Driver for SURECOM EP-320X-S 100/10M Ethernet PCI Adapter Message-ID: <002301c4a23c$3222b790$1b6d18ac@TBS0016>
next in thread | raw e-mail | index | archive | help
Hi All I have a Surecom Ethernet Adapter where there's a FreeBSD driver available for download at the manufactors website. However I think it is for FreeBSD 4.x because it won't compile on my FreeBSD 5.2.1-release system. Is anybody up for converting the driver to 5.x, or does anybody know if there's an alternate driver for this NIC? Thanks. Driver consists of 2 files: if_fet.c & if_fetreg.h (see below): if_fet.c -------------------------------------------------------------- /* * fast ethernet PCI NIC driver */ #include "bpfilter.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/sockio.h> #include <sys/mbuf.h> #include <sys/malloc.h> #include <sys/kernel.h> #include <sys/socket.h> #include <net/if.h> #include <net/if_arp.h> #include <net/ethernet.h> #include <net/if_dl.h> #include <net/if_media.h> #if NBPFILTER > 0 #include <net/bpf.h> #endif #include <vm/vm.h> /* for vtophys */ #include <vm/pmap.h> /* for vtophys */ #include <machine/clock.h> /* for DELAY */ #include <machine/bus_memio.h> #include <machine/bus_pio.h> #include <machine/bus.h> #include <pci/pcireg.h> #include <pci/pcivar.h> /* #define FET_USEIOSPACE */ static int FET_USEIOSPACE=1; #include <pci/if_fetreg.h> #ifndef lint static const char rcsid[] = "$Id: if_fet.c,v 1.30 2000/12/29 09:28:52 wpaul Exp $"; #endif /* * Various supported device vendors/types and their names. */ struct fet_type *fet_info_tmp; static struct fet_type fet_devs[] = { { FETVENDORID, ID0, "100/10M Ethernet PCI Adapter" }, { FETVENDORID, ID1, "100/10M Ethernet PCI Adapter" }, { FETVENDORID, ID2, "1000/100/10M Ethernet PCI Adapter" }, { 0, 0, NULL } }; /* * Various supported PHY vendors/types and their names. Note that * this driver will work with pretty much any MII-compliant PHY, * so failure to positively identify the chip is not a fatal error. */ static struct fet_type fet_phys[] = { { MysonPHYID0, MysonPHYID0, "<MYSON MTD981>"}, { SeeqPHYID0, SeeqPHYID0, "<SEEQ 80225>" }, { AhdocPHYID0, AhdocPHYID0, "<AHDOC 101>" }, { MarvellPHYID0, MarvellPHYID0, "<MARVELL 88E1000>"}, { LevelOnePHYID0, LevelOnePHYID0, "<LevelOne LXT1000>"}, { 0, 0, "<MII-compliant physical interface>" } }; static unsigned long fet_count = 0; static const char *fet_probe __P((pcici_t, pcidi_t)); static void fet_attach __P((pcici_t, int)); static int fet_newbuf __P((struct fet_softc *, struct fet_chain_onefrag *)); static int fet_encap __P((struct fet_softc *, struct fet_chain *, struct mbuf *)); static void fet_rxeof __P((struct fet_softc *)); static void fet_txeof __P((struct fet_softc *)); static void fet_txeoc __P((struct fet_softc *)); static void fet_intr __P((void *)); static void fet_start __P((struct ifnet *)); static int fet_ioctl __P((struct ifnet *, u_long, caddr_t)); static void fet_init __P((void *)); static void fet_stop __P((struct fet_softc *)); static void fet_watchdog __P((struct ifnet *)); static void fet_shutdown __P((int, void *)); static int fet_ifmedia_upd __P((struct ifnet *)); static void fet_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); static u_int16_t fet_phy_readreg __P((struct fet_softc *, int)); static void fet_phy_writereg __P((struct fet_softc *, int, int)); static void fet_autoneg_xmit __P((struct fet_softc *)); static void fet_autoneg_mii __P((struct fet_softc *, int, int)); static void fet_setmode_mii __P((struct fet_softc *, int)); static void fet_getmode_mii __P((struct fet_softc *)); static void fet_setcfg __P((struct fet_softc *, int)); static u_int8_t fet_calchash __P((caddr_t)); static void fet_setmulti __P((struct fet_softc *)); static void fet_reset __P((struct fet_softc *)); static int fet_list_rx_init __P((struct fet_softc *)); static int fet_list_tx_init __P((struct fet_softc *)); static long fet_send_cmd_to_phy __P((struct fet_softc *, int, int)); #define FET_SETBIT(sc, reg, x) CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | x) #define FET_CLRBIT(sc, reg, x) CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~x) static long fet_send_cmd_to_phy(sc, opcode, regad) struct fet_softc *sc; int opcode; int regad; { long miir; int i; int mask, data; /* enable MII output */ miir=CSR_READ_4(sc, FET_MANAGEMENT); miir&=0xfffffff0; miir|=FET_MASK_MIIR_MII_WRITE+FET_MASK_MIIR_MII_MDO; /* send 32 1's preamble */ for (i=0;i<32;i++) { /* low MDC; MDO is already high (miir) */ miir&=~FET_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, FET_MANAGEMENT, miir); /* high MDC */ miir|=FET_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, FET_MANAGEMENT, miir); } /* calculate ST+OP+PHYAD+REGAD+TA */ data=opcode|(sc->fet_phy_addr<<7)|(regad<<2); /* sent out */ mask=0x8000; while (mask) { /* low MDC, prepare MDO */ miir&=~(FET_MASK_MIIR_MII_MDC+FET_MASK_MIIR_MII_MDO); if (mask & data) miir|=FET_MASK_MIIR_MII_MDO; CSR_WRITE_4(sc, FET_MANAGEMENT, miir); /* high MDC */ miir|=FET_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, FET_MANAGEMENT, miir); DELAY(30); /* next */ mask>>=1; if (mask==0x2 && opcode==FET_OP_READ) miir&=~FET_MASK_MIIR_MII_WRITE; } return miir; } static u_int16_t fet_phy_readreg(sc, reg) struct fet_softc *sc; int reg; { long miir; int mask, data; if (sc->fet_info->fet_did == ID1) data = CSR_READ_2(sc, FET_PHYBASE+reg*2); else { miir=fet_send_cmd_to_phy(sc, FET_OP_READ, reg); /* read data */ mask=0x8000; data=0; while (mask) { /* low MDC */ miir&=~FET_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, FET_MANAGEMENT, miir); /* read MDI */ miir=CSR_READ_4(sc, FET_MANAGEMENT); if (miir & FET_MASK_MIIR_MII_MDI) data|=mask; /* high MDC, and wait */ miir|=FET_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, FET_MANAGEMENT, miir); DELAY(30); /* next */ mask>>=1; } /* low MDC */ miir&=~FET_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, FET_MANAGEMENT, miir); } return (u_int16_t)data; } static void fet_phy_writereg(sc, reg, data) struct fet_softc *sc; int reg; int data; { long miir; int mask; if (sc->fet_info->fet_did == ID1) CSR_WRITE_2(sc, FET_PHYBASE+reg*2, data); else { miir=fet_send_cmd_to_phy(sc, FET_OP_WRITE, reg); /* write data */ mask=0x8000; while (mask) { /* low MDC, prepare MDO */ miir&=~(FET_MASK_MIIR_MII_MDC+FET_MASK_MIIR_MII_MDO); if (mask&data) miir|=FET_MASK_MIIR_MII_MDO; CSR_WRITE_4(sc, FET_MANAGEMENT, miir); DELAY(1); /* high MDC */ miir|=FET_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, FET_MANAGEMENT, miir); DELAY(1); /* next */ mask>>=1; } /* low MDC */ miir&=~FET_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, FET_MANAGEMENT, miir); } return; } static u_int8_t fet_calchash(addr) caddr_t addr; { u_int32_t crc, carry; int i, j; u_int8_t c; /* Compute CRC for the address value. */ crc = 0xFFFFFFFF; /* initial value */ for (i = 0; i < 6; i++) { c = *(addr + i); for (j = 0; j < 8; j++) { carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); crc <<= 1; c >>= 1; if (carry) crc = (crc ^ 0x04c11db6) | carry; } } /* * return the filter bit position * Note: I arrived at the following nonsense * through experimentation. It's not the usual way to * generate the bit position but it's the only thing * I could come up with that works. */ return(~(crc >> 26) & 0x0000003F); } /* * Program the 64-bit multicast hash filter. */ static void fet_setmulti(sc) struct fet_softc *sc; { struct ifnet *ifp; int h = 0; u_int32_t hashes[2] = { 0, 0 }; struct ifmultiaddr *ifma; u_int32_t rxfilt; int mcnt = 0; ifp = &sc->arpcom.ac_if; rxfilt = CSR_READ_4(sc, FET_TCRRCR); if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { rxfilt |= FET_AM; CSR_WRITE_4(sc, FET_TCRRCR, rxfilt); CSR_WRITE_4(sc, FET_MAR0, 0xFFFFFFFF); CSR_WRITE_4(sc, FET_MAR1, 0xFFFFFFFF); return; } /* first, zot all the existing hash bits */ CSR_WRITE_4(sc, FET_MAR0, 0); CSR_WRITE_4(sc, FET_MAR1, 0); /* now program new ones */ for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; ifma = ifma->ifma_link.le_next) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = fet_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); if (h < 32) hashes[0] |= (1 << h); else hashes[1] |= (1 << (h - 32)); mcnt++; } if (mcnt) rxfilt |= FET_AM; else rxfilt &= ~FET_AM; CSR_WRITE_4(sc, FET_MAR0, hashes[0]); CSR_WRITE_4(sc, FET_MAR1, hashes[1]); CSR_WRITE_4(sc, FET_TCRRCR, rxfilt); return; } /* * Initiate an autonegotiation session. */ static void fet_autoneg_xmit(sc) struct fet_softc *sc; { u_int16_t phy_sts; fet_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); DELAY(500); while(fet_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); phy_sts = fet_phy_readreg(sc, PHY_BMCR); phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; fet_phy_writereg(sc, PHY_BMCR, phy_sts); return; } /* * Invoke autonegotiation on a PHY. */ static void fet_autoneg_mii(sc, flag, verbose) struct fet_softc *sc; int flag; int verbose; { u_int16_t phy_sts = 0, media, advert, ability; u_int16_t ability2 = 0; struct ifnet *ifp; struct ifmedia *ifm; ifm = &sc->ifmedia; ifp = &sc->arpcom.ac_if; ifm->ifm_media = IFM_ETHER | IFM_AUTO; #ifndef FORCE_AUTONEG_TFOUR /* * First, see if autoneg is supported. If not, there's * no point in continuing. */ phy_sts = fet_phy_readreg(sc, PHY_BMSR); if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { if (verbose) printf("fet%d: autonegotiation not supported\n", sc->fet_unit); ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; return; } #endif switch (flag) { case FET_FLAG_FORCEDELAY: /* * XXX Never use this option anywhere but in the probe * routine: making the kernel stop dead in its tracks * for three whole seconds after we've gone multi-user * is really bad manners. */ fet_autoneg_xmit(sc); DELAY(5000000); break; case FET_FLAG_SCHEDDELAY: /* * Wait for the transmitter to go idle before starting * an autoneg session, otherwise fet_start() may clobber * our timeout, and we don't want to allow transmission * during an autoneg session since that can screw it up. */ if (sc->fet_cdata.fet_tx_head != NULL) { sc->fet_want_auto = 1; return; } fet_autoneg_xmit(sc); ifp->if_timer = 5; sc->fet_autoneg = 1; sc->fet_want_auto = 0; return; case FET_FLAG_DELAYTIMEO: ifp->if_timer = 0; sc->fet_autoneg = 0; break; default: printf("fet%d: invalid autoneg flag: %d\n", sc->fet_unit, flag); return; } if (fet_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { if (verbose) printf("fet%d: autoneg complete, ", sc->fet_unit); phy_sts = fet_phy_readreg(sc, PHY_BMSR); } else { if (verbose) printf("fet%d: autoneg not complete, ", sc->fet_unit); } media = fet_phy_readreg(sc, PHY_BMCR); /* Link is good. Report modes and set duplex mode. */ if (fet_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { if (verbose) printf("fet%d: link status good. ", sc->fet_unit); advert = fet_phy_readreg(sc, PHY_ANAR); ability = fet_phy_readreg(sc, PHY_LPAR); if ( (sc->fet_pinfo->fet_vid == MarvellPHYID0) || (sc->fet_pinfo->fet_vid == LevelOnePHYID0) ) { ability2 = fet_phy_readreg(sc, PHY_1000SR); if (ability2 & PHY_1000SR_1000BTXFULL) { advert = 0; ability = 0; /* this version did not support 1000M, ifm->ifm_media = IFM_ETHER|IFM_1000_TX|IFM_FDX; */ ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; media &= ~PHY_BMCR_SPEEDSEL; media |= PHY_BMCR_1000; media |= PHY_BMCR_DUPLEX; printf("(full-duplex, 1000Mbps)\n"); } else if (ability2 & PHY_1000SR_1000BTXHALF) { advert = 0; ability = 0; /* this version did not support 1000M, ifm->ifm_media = IFM_ETHER|IFM_1000_TX; */ ifm->ifm_media = IFM_ETHER|IFM_100_TX; media &= ~PHY_BMCR_SPEEDSEL; media &= ~PHY_BMCR_DUPLEX; media |= PHY_BMCR_1000; printf("(half-duplex, 1000Mbps)\n"); } } if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { ifm->ifm_media = IFM_ETHER|IFM_100_T4; media |= PHY_BMCR_SPEEDSEL; media &= ~PHY_BMCR_DUPLEX; printf("(100baseT4)\n"); } else if (advert & PHY_ANAR_100BTXFULL && ability & PHY_ANAR_100BTXFULL) { ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; media |= PHY_BMCR_SPEEDSEL; media |= PHY_BMCR_DUPLEX; printf("(full-duplex, 100Mbps)\n"); } else if (advert & PHY_ANAR_100BTXHALF && ability & PHY_ANAR_100BTXHALF) { ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; media |= PHY_BMCR_SPEEDSEL; media &= ~PHY_BMCR_DUPLEX; printf("(half-duplex, 100Mbps)\n"); } else if (advert & PHY_ANAR_10BTFULL && ability & PHY_ANAR_10BTFULL) { ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; media &= ~PHY_BMCR_SPEEDSEL; media |= PHY_BMCR_DUPLEX; printf("(full-duplex, 10Mbps)\n"); } else if (advert) { ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; media &= ~PHY_BMCR_SPEEDSEL; media &= ~PHY_BMCR_DUPLEX; printf("(half-duplex, 10Mbps)\n"); } media &= ~PHY_BMCR_AUTONEGENBL; /* Set ASIC's duplex mode to match the PHY. */ fet_phy_writereg(sc, PHY_BMCR, media); fet_setcfg(sc, media); } else { if (verbose) printf("fet%d: no carrier\n", sc->fet_unit); } fet_init(sc); if (sc->fet_tx_pend) { sc->fet_autoneg = 0; sc->fet_tx_pend = 0; fet_start(ifp); } return; } /* * To get PHY ability. */ static void fet_getmode_mii(sc) struct fet_softc *sc; { u_int16_t bmsr; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; bmsr = fet_phy_readreg(sc, PHY_BMSR); if (bootverbose) printf("fet%d: PHY status word: %x\n", sc->fet_unit, bmsr); /* fallback */ sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; if (bmsr & PHY_BMSR_10BTHALF) { if (bootverbose) printf("fet%d: 10Mbps half-duplex mode supported\n", sc->fet_unit); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); } if (bmsr & PHY_BMSR_10BTFULL) { if (bootverbose) printf("fet%d: 10Mbps full-duplex mode supported\n", sc->fet_unit); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; } if (bmsr & PHY_BMSR_100BTXHALF) { if (bootverbose) printf("fet%d: 100Mbps half-duplex mode supported\n", sc->fet_unit); ifp->if_baudrate = 100000000; ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; } if (bmsr & PHY_BMSR_100BTXFULL) { if (bootverbose) printf("fet%d: 100Mbps full-duplex mode supported\n", sc->fet_unit); ifp->if_baudrate = 100000000; ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; } /* Some also support 100BaseT4. */ if (bmsr & PHY_BMSR_100BT4) { if (bootverbose) printf("fet%d: 100baseT4 mode supported\n", sc->fet_unit); ifp->if_baudrate = 100000000; ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; #ifdef FORCE_AUTONEG_TFOUR if (bootverbose) printf("fet%d: forcing on autoneg support for BT4\n", sc->fet_unit); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; #endif } /* this version did not support 1000M, if (sc->fet_pinfo->fet_vid == MarvellPHYID0) { if (bootverbose) printf("fet%d: 1000Mbps half-duplex mode supported\n", sc->fet_unit); ifp->if_baudrate = 1000000000; ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_TX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_TX|IFM_HDX, 0, NULL); if (bootverbose) printf("fet%d: 1000Mbps full-duplex mode supported\n", sc->fet_unit); ifp->if_baudrate = 1000000000; ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_TX|IFM_FDX, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER|IFM_1000_TX|IFM_FDX; } */ if (bmsr & PHY_BMSR_CANAUTONEG) { if (bootverbose) printf("fet%d: autoneg supported\n", sc->fet_unit); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; } return; } /* * Set speed and duplex mode. */ static void fet_setmode_mii(sc, media) struct fet_softc *sc; int media; { u_int16_t bmcr; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; printf("enter fet_setmode_mii()\n"); /* * If an autoneg session is in progress, stop it. */ if (sc->fet_autoneg) { printf("fet%d: canceling autoneg session\n", sc->fet_unit); ifp->if_timer = sc->fet_autoneg = sc->fet_want_auto = 0; bmcr = fet_phy_readreg(sc, PHY_BMCR); bmcr &= ~PHY_BMCR_AUTONEGENBL; fet_phy_writereg(sc, PHY_BMCR, bmcr); } printf("fet%d: selecting MII, ", sc->fet_unit); bmcr = fet_phy_readreg(sc, PHY_BMCR); bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL|PHY_BMCR_1000| PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); /* this version did not support 1000M, if (IFM_SUBTYPE(media) == IFM_1000_TX) { printf("1000Mbps/T4, half-duplex\n"); bmcr &= ~PHY_BMCR_SPEEDSEL; bmcr &= ~PHY_BMCR_DUPLEX; bmcr |= PHY_BMCR_1000; } */ if (IFM_SUBTYPE(media) == IFM_100_T4) { printf("100Mbps/T4, half-duplex\n"); bmcr |= PHY_BMCR_SPEEDSEL; bmcr &= ~PHY_BMCR_DUPLEX; } if (IFM_SUBTYPE(media) == IFM_100_TX) { printf("100Mbps, "); bmcr |= PHY_BMCR_SPEEDSEL; } if (IFM_SUBTYPE(media) == IFM_10_T) { printf("10Mbps, "); bmcr &= ~PHY_BMCR_SPEEDSEL; } if ((media & IFM_GMASK) == IFM_FDX) { printf("full duplex\n"); bmcr |= PHY_BMCR_DUPLEX; } else { printf("half duplex\n"); bmcr &= ~PHY_BMCR_DUPLEX; } fet_phy_writereg(sc, PHY_BMCR, bmcr); fet_setcfg(sc, bmcr); return; } /* * The Myson manual states that in order to fiddle with the * 'full-duplex' and '100Mbps' bits in the netconfig register, we * first have to put the transmit and/or receive logic in the idle state. */ static void fet_setcfg(sc, bmcr) struct fet_softc *sc; int bmcr; { int i, restart = 0; if (CSR_READ_4(sc, FET_TCRRCR) & (FET_TE|FET_RE)) { restart = 1; FET_CLRBIT(sc, FET_TCRRCR, (FET_TE|FET_RE)); for (i = 0; i < FET_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_4(sc, FET_TCRRCR)&(FET_TXRUN|FET_RXRUN))) break; } if (i == FET_TIMEOUT) printf("fet%d: failed to force tx and rx to idle state\n", sc->fet_unit); } FET_CLRBIT(sc, FET_TCRRCR, FET_PS1000); FET_CLRBIT(sc, FET_TCRRCR, FET_PS10); if (bmcr & PHY_BMCR_1000) FET_SETBIT(sc, FET_TCRRCR, FET_PS1000); else if (!(bmcr & PHY_BMCR_SPEEDSEL)) FET_SETBIT(sc, FET_TCRRCR, FET_PS10); if (bmcr & PHY_BMCR_DUPLEX) FET_SETBIT(sc, FET_TCRRCR, FET_FD); else FET_CLRBIT(sc, FET_TCRRCR, FET_FD); if (restart) FET_SETBIT(sc, FET_TCRRCR, FET_TE|FET_RE); return; } static void fet_reset(sc) struct fet_softc *sc; { register int i; FET_SETBIT(sc, FET_BCR, FET_SWR); for (i = 0; i < FET_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_4(sc, FET_BCR) & FET_SWR)) break; } if (i == FET_TIMEOUT) printf("m0x%d: reset never completed!\n", sc->fet_unit); /* Wait a little while for the chip to get its brains in order. */ DELAY(1000); return; } /* * Probe for a Myson chip. Check the PCI vendor and device * IDs against our list and return a device name if we find a match. */ static const char *fet_probe(config_id, device_id) pcici_t config_id; pcidi_t device_id; { struct fet_type *t; t = fet_devs; while(t->fet_name != NULL) { if ((device_id & 0xFFFF) == t->fet_vid && ((device_id >> 16) & 0xFFFF) == t->fet_did) { fet_info_tmp = t; return(t->fet_name); } t++; } return(NULL); } /* * Attach the interface. Allocate softc structures, do ifmedia * setup and ethernet/BPF attach. */ static void fet_attach(config_id, unit) pcici_t config_id; int unit; { int s, i; vm_offset_t pbase, vbase; u_char eaddr[ETHER_ADDR_LEN]; u_int32_t command, iobase; struct fet_softc *sc; struct ifnet *ifp; int media = IFM_ETHER|IFM_100_TX|IFM_FDX; unsigned int round; caddr_t roundptr; struct fet_type *p; u_int16_t phy_vid, phy_did, phy_sts; s = splimp(); sc = malloc(sizeof(struct fet_softc), M_DEVBUF, M_NOWAIT); if (sc == NULL) { printf("fet%d: no memory for softc struct!\n", unit); return; } bzero(sc, sizeof(struct fet_softc)); /* * Map control/status registers. */ command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); if (fet_info_tmp->fet_did==ID0) { iobase = pci_conf_read(config_id, FET_PCI_LOIO); if (iobase & 0x300) FET_USEIOSPACE=0; } if (FET_USEIOSPACE) { if (!(command & PCIM_CMD_PORTEN)) { printf("fet%d: failed to enable I/O ports!\n", unit); free(sc, M_DEVBUF); goto fail; } if (!pci_map_port(config_id, FET_PCI_LOIO, (u_int16_t *)&(sc->fet_bhandle))) { printf ("fet%d: couldn't map ports\n", unit); goto fail; } sc->fet_btag = I386_BUS_SPACE_IO; } else { if (!(command & PCIM_CMD_MEMEN)) { printf("fet%d: failed to enable memory mapping!\n", unit); goto fail; } if (!pci_map_mem(config_id, FET_PCI_LOMEM, &vbase, &pbase)) { printf ("fet%d: couldn't map memory\n", unit); goto fail; } /* sc->csr = (volatile caddr_t)vbase; */ sc->fet_btag = I386_BUS_SPACE_MEM; sc->fet_bhandle = vbase; } /* Allocate interrupt */ if (!pci_map_int(config_id, fet_intr, sc, &net_imask)) { printf("fet%d: couldn't map interrupt\n", unit); goto fail; } sc->fet_info = fet_info_tmp; /* Reset the adapter. */ fet_reset(sc); /* * Get station address */ for (i = 0; i < ETHER_ADDR_LEN; ++i) eaddr[i] = CSR_READ_1(sc, FET_PAR0+i); /* * A Myson chip was detected. Inform the world. */ printf("fet%d: Ethernet address: %6D\n", unit, eaddr, ":"); sc->fet_unit = unit; bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); sc->fet_ldata_ptr = malloc(sizeof(struct fet_list_data) + 8, M_DEVBUF, M_NOWAIT); if (sc->fet_ldata_ptr == NULL) { free(sc, M_DEVBUF); printf("fet%d: no memory for list buffers!\n", unit); return; } sc->fet_ldata = (struct fet_list_data *)sc->fet_ldata_ptr; round = (unsigned int)sc->fet_ldata_ptr & 0xF; roundptr = sc->fet_ldata_ptr; for (i = 0; i < 8; i++) { if (round % 8) { round++; roundptr++; } else break; } sc->fet_ldata = (struct fet_list_data *)roundptr; bzero(sc->fet_ldata, sizeof(struct fet_list_data)); ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; ifp->if_unit = unit; ifp->if_name = "fet"; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = fet_ioctl; ifp->if_output = ether_output; ifp->if_start = fet_start; ifp->if_watchdog = fet_watchdog; ifp->if_init = fet_init; ifp->if_baudrate = 10000000; if (sc->fet_info->fet_did == ID1) sc->fet_pinfo = fet_phys; else { if (bootverbose) printf("fet%d: probing for a PHY\n", sc->fet_unit); for (i = FET_PHYADDR_MIN; i < FET_PHYADDR_MAX + 1; i++) { if (bootverbose) printf("fet%d: checking address: %d\n", sc->fet_unit, i); sc->fet_phy_addr = i; phy_sts = fet_phy_readreg(sc, PHY_BMSR); if ( (phy_sts!=0)&&(phy_sts!=0xffff) ) break; else phy_sts = 0; } if (phy_sts) { phy_vid = fet_phy_readreg(sc, PHY_VENID); phy_did = fet_phy_readreg(sc, PHY_DEVID); if (bootverbose) { printf("fet%d: found PHY at address %d, ", sc->fet_unit, sc->fet_phy_addr); printf("vendor id: %x device id: %x\n", phy_vid, phy_did); } p = fet_phys; while(p->fet_vid) { if (phy_vid == p->fet_vid) { sc->fet_pinfo = p; break; } p++; } if (sc->fet_pinfo == NULL) sc->fet_pinfo = &fet_phys[PHY_UNKNOWN]; if (bootverbose) printf("fet%d: PHY type: %s\n", sc->fet_unit, sc->fet_pinfo->fet_name); } else { printf("fet%d: MII without any phy!\n", sc->fet_unit); goto fail; } } /* * Do ifmedia setup. */ ifmedia_init(&sc->ifmedia, 0, fet_ifmedia_upd, fet_ifmedia_sts); fet_getmode_mii(sc); fet_autoneg_mii(sc, FET_FLAG_FORCEDELAY, 1); media = sc->ifmedia.ifm_media; fet_stop(sc); ifmedia_set(&sc->ifmedia, media); /* * Call MI attach routines. */ if_attach(ifp); ether_ifattach(ifp); #if NBPFILTER > 0 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif at_shutdown(fet_shutdown, sc, SHUTDOWN_POST_SYNC); fail: splx(s); return; } /* * Initialize the transmit descriptors. */ static int fet_list_tx_init(sc) struct fet_softc *sc; { struct fet_chain_data *cd; struct fet_list_data *ld; int i; cd = &sc->fet_cdata; ld = sc->fet_ldata; for (i = 0; i < FET_TX_LIST_CNT; i++) { cd->fet_tx_chain[i].fet_ptr = &ld->fet_tx_list[i]; if (i == (FET_TX_LIST_CNT - 1)) cd->fet_tx_chain[i].fet_nextdesc = &cd->fet_tx_chain[0]; else cd->fet_tx_chain[i].fet_nextdesc = &cd->fet_tx_chain[i + 1]; } cd->fet_tx_free = &cd->fet_tx_chain[0]; cd->fet_tx_tail = cd->fet_tx_head = NULL; return(0); } /* * Initialize the RX descriptors and allocate mbufs for them. Note that * we arrange the descriptors in a closed ring, so that the last descriptor * points back to the first. */ static int fet_list_rx_init(sc) struct fet_softc *sc; { struct fet_chain_data *cd; struct fet_list_data *ld; int i; cd = &sc->fet_cdata; ld = sc->fet_ldata; for (i = 0; i < FET_RX_LIST_CNT; i++) { cd->fet_rx_chain[i].fet_ptr = (struct fet_desc *)&ld->fet_rx_list[i]; if (fet_newbuf(sc, &cd->fet_rx_chain[i]) == ENOBUFS) return(ENOBUFS); if (i == (FET_RX_LIST_CNT - 1)) { cd->fet_rx_chain[i].fet_nextdesc = &cd->fet_rx_chain[0]; ld->fet_rx_list[i].fet_next = vtophys(&ld->fet_rx_list[0]); } else { cd->fet_rx_chain[i].fet_nextdesc = &cd->fet_rx_chain[i + 1]; ld->fet_rx_list[i].fet_next = vtophys(&ld->fet_rx_list[i + 1]); } } cd->fet_rx_head = &cd->fet_rx_chain[0]; return(0); } /* * Initialize an RX descriptor and attach an MBUF cluster. */ static int fet_newbuf(sc, c) struct fet_softc *sc; struct fet_chain_onefrag *c; { struct mbuf *m_new = NULL; MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("fet%d: no memory for rx list -- packet dropped!\n", sc->fet_unit); return(ENOBUFS); } MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { printf("fet%d: no memory for rx list -- packet dropped!\n", sc->fet_unit); m_freem(m_new); return(ENOBUFS); } c->fet_mbuf = m_new; c->fet_ptr->fet_data = vtophys(mtod(m_new, caddr_t)); c->fet_ptr->fet_ctl = (MCLBYTES - 1)<<FET_RBSShift; c->fet_ptr->fet_status = FET_OWNByNIC; return(0); } /* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */ static void fet_rxeof(sc) struct fet_softc *sc; { struct ether_header *eh; struct mbuf *m; struct ifnet *ifp; struct fet_chain_onefrag *cur_rx; int total_len = 0; u_int32_t rxstat; ifp = &sc->arpcom.ac_if; while (!((rxstat = sc->fet_cdata.fet_rx_head->fet_ptr->fet_status)&FET_OWNByNIC)) { cur_rx = sc->fet_cdata.fet_rx_head; sc->fet_cdata.fet_rx_head = cur_rx->fet_nextdesc; if (rxstat & FET_ES) /* error summary */ { /* give up this rx pkt */ ifp->if_ierrors++; cur_rx->fet_ptr->fet_status = FET_OWNByNIC; continue; } /* No errors; receive the packet. */ total_len = (rxstat & FET_FLNGMASK) >> FET_FLNGShift; total_len -= ETHER_CRC_LEN; if (total_len < MINCLSIZE) { m = m_devget(mtod(cur_rx->fet_mbuf, char *), total_len, 0, ifp, NULL); cur_rx->fet_ptr->fet_status = FET_OWNByNIC; if (m == NULL) { ifp->if_ierrors++; continue; } } else { m = cur_rx->fet_mbuf; /* * Try to conjure up a new mbuf cluster. If that * fails, it means we have an out of memory condition and * should leave the buffer in place and continue. This will * result in a lost packet, but there's little else we * can do in this situation. */ if (fet_newbuf(sc, cur_rx) == ENOBUFS) { ifp->if_ierrors++; cur_rx->fet_ptr->fet_status = FET_OWNByNIC; continue; } m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = total_len; } ifp->if_ipackets++; eh = mtod(m, struct ether_header *); #if NBPFILTER > 0 /* * Handle BPF listeners. Let the BPF user see the packet, but * don't pass it up to the ether_input() layer unless it's * a broadcast packet, multicast packet, matches our ethernet * address or the interface is in promiscuous mode. */ if (ifp->if_bpf) { bpf_mtap(ifp, m); if (ifp->if_flags & IFF_PROMISC && (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN) && (eh->ether_dhost[0] & 1) == 0)) { m_freem(m); continue; } } #endif /* Remove header from mbuf and pass it on. */ m_adj(m, sizeof(struct ether_header)); ether_input(ifp, eh, m); } return; } /* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */ static void fet_txeof(sc) struct fet_softc *sc; { struct fet_chain *cur_tx; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; /* Clear the timeout timer. */ ifp->if_timer = 0; if (sc->fet_cdata.fet_tx_head == NULL) return; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ while (sc->fet_cdata.fet_tx_head->fet_mbuf != NULL) { u_int32_t txstat; cur_tx = sc->fet_cdata.fet_tx_head; txstat = FET_TXSTATUS(cur_tx); if ((txstat & FET_OWNByNIC) || txstat == FET_UNSENT) break; if (!(CSR_READ_4(sc, FET_TCRRCR)&FET_Enhanced)) { if (txstat & FET_TXERR) { ifp->if_oerrors++; if (txstat & FET_EC) /* excessive collision */ ifp->if_collisions++; if (txstat & FET_LC) /* late collision */ ifp->if_collisions++; } ifp->if_collisions += (txstat & FET_NCRMASK) >> FET_NCRShift; } ifp->if_opackets++; m_freem(cur_tx->fet_mbuf); cur_tx->fet_mbuf = NULL; if (sc->fet_cdata.fet_tx_head == sc->fet_cdata.fet_tx_tail) { sc->fet_cdata.fet_tx_head = NULL; sc->fet_cdata.fet_tx_tail = NULL; break; } sc->fet_cdata.fet_tx_head = cur_tx->fet_nextdesc; } if (CSR_READ_4(sc, FET_TCRRCR)&FET_Enhanced) { ifp->if_collisions += (CSR_READ_4(sc, FET_TSR)&FET_NCRMask); } return; } /* * TX 'end of channel' interrupt handler. */ static void fet_txeoc(sc) struct fet_softc *sc; { struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; if (sc->fet_cdata.fet_tx_head == NULL) { ifp->if_flags &= ~IFF_OACTIVE; sc->fet_cdata.fet_tx_tail = NULL; if (sc->fet_want_auto) fet_autoneg_mii(sc, FET_FLAG_SCHEDDELAY, 1); } else { if (FET_TXOWN(sc->fet_cdata.fet_tx_head) == FET_UNSENT) { FET_TXOWN(sc->fet_cdata.fet_tx_head) = FET_OWNByNIC; ifp->if_timer = 5; CSR_WRITE_4(sc, FET_TXPDR, 0xFFFFFFFF); } } return; } static void fet_intr(arg) void *arg; { struct fet_softc *sc; struct ifnet *ifp; u_int32_t status; sc = arg; ifp = &sc->arpcom.ac_if; if (!(ifp->if_flags & IFF_UP)) return; /* Disable interrupts. */ CSR_WRITE_4(sc, FET_IMR, 0x00000000); for (;;) { status = CSR_READ_4(sc, FET_ISR); status &= FET_INTRS; if (status) CSR_WRITE_4(sc, FET_ISR, status); else break; if (status & FET_RI) /* receive interrupt */ fet_rxeof(sc); if ((status & FET_RBU) || (status & FET_RxErr)) { /* rx buffer unavailable or rx error */ ifp->if_ierrors++; #ifdef foo fet_stop(sc); fet_reset(sc); fet_init(sc); #endif } if (status & FET_TI) /* tx interrupt */ fet_txeof(sc); if (status & FET_ETI) /* tx early interrupt */ fet_txeof(sc); if (status & FET_TBU) /* tx buffer unavailable */ fet_txeoc(sc); /* 90/1/18 delete if (status & FET_FBE) { fet_reset(sc); fet_init(sc); } */ } /* Re-enable interrupts. */ CSR_WRITE_4(sc, FET_IMR, FET_INTRS); if (ifp->if_snd.ifq_head != NULL) fet_start(ifp); return; } /* * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data * pointers to the fragment pointers. */ static int fet_encap(sc, c, m_head) struct fet_softc *sc; struct fet_chain *c; struct mbuf *m_head; { struct fet_desc *f = NULL; int total_len; struct mbuf *m, *m_new=NULL; /* calculate the total tx pkt length */ total_len = 0; for (m = m_head; m != NULL; m = m->m_next) total_len += m->m_len; /* * Start packing the mbufs in this chain into * the fragment pointers. Stop when we run out * of fragments or hit the end of the mbuf chain. */ m = m_head; MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("fet%d: no memory for tx list", sc->fet_unit); return(1); } if (m_head->m_pkthdr.len > MHLEN) { MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { m_freem(m_new); printf("fet%d: no memory for tx list", sc->fet_unit); return(1); } } m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t)); m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; m_freem(m_head); m_head = m_new; f = &c->fet_ptr->fet_frag[0]; f->fet_status = 0; f->fet_data = vtophys(mtod(m_new, caddr_t)); total_len = m_new->m_len; f->fet_ctl = FET_TXFD|FET_TXLD|FET_CRCEnable|FET_PADEnable; f->fet_ctl |= total_len<<FET_PKTShift; /* pkt size */ f->fet_ctl |= total_len; /* buffer size */ /* 89/12/29 add, for mtd891 */ if (sc->fet_info->fet_did==ID2) f->fet_ctl |= FET_ETIControl|FET_RetryTxLC; c->fet_mbuf = m_head; c->fet_lastdesc = 0; FET_TXNEXT(c) = vtophys(&c->fet_nextdesc->fet_ptr->fet_frag[0]); return(0); } /* * Main transmit routine. To avoid having to do mbuf copies, we put pointers * to the mbuf data regions directly in the transmit lists. We also save a * copy of the pointers since the transmit list fragment pointers are * physical addresses. */ static void fet_start(ifp) struct ifnet *ifp; { struct fet_softc *sc; struct mbuf *m_head = NULL; struct fet_chain *cur_tx = NULL, *start_tx; sc = ifp->if_softc; if (sc->fet_autoneg) { sc->fet_tx_pend = 1; return; } /* * Check for an available queue slot. If there are none, * punt. */ if (sc->fet_cdata.fet_tx_free->fet_mbuf != NULL) { ifp->if_flags |= IFF_OACTIVE; return; } start_tx = sc->fet_cdata.fet_tx_free; while (sc->fet_cdata.fet_tx_free->fet_mbuf == NULL) { IF_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; /* Pick a descriptor off the free list. */ cur_tx = sc->fet_cdata.fet_tx_free; sc->fet_cdata.fet_tx_free = cur_tx->fet_nextdesc; /* Pack the data into the descriptor. */ fet_encap(sc, cur_tx, m_head); if (cur_tx != start_tx) FET_TXOWN(cur_tx) = FET_OWNByNIC; #if NBPFILTER > 0 /* * If there's a BPF listener, bounce a copy of this frame * to him. */ if (ifp->if_bpf) bpf_mtap(ifp, cur_tx->fet_mbuf); #endif } /* * If there are no packets queued, bail. */ if (cur_tx == NULL) return; /* * Place the request for the upload interrupt * in the last descriptor in the chain. This way, if * we're chaining several packets at once, we'll only * get an interupt once for the whole chain rather than * once for each packet. */ FET_TXCTL(cur_tx) |= FET_TXIC; cur_tx->fet_ptr->fet_frag[0].fet_ctl |= FET_TXIC; sc->fet_cdata.fet_tx_tail = cur_tx; if (sc->fet_cdata.fet_tx_head == NULL) sc->fet_cdata.fet_tx_head = start_tx; FET_TXOWN(start_tx) = FET_OWNByNIC; CSR_WRITE_4(sc, FET_TXPDR, 0xFFFFFFFF); /* tx polling demand */ /* * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; return; } static void fet_init(xsc) void *xsc; { struct fet_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; int s, i; u_int16_t phy_bmcr = 0; if (sc->fet_autoneg) return; s = splimp(); if (sc->fet_pinfo != NULL) phy_bmcr = fet_phy_readreg(sc, PHY_BMCR); /* * Cancel pending I/O and free all RX/TX buffers. */ fet_stop(sc); fet_reset(sc); /* * Set cache alignment and burst length. */ /* 89/9/1 modify, CSR_WRITE_4(sc, FET_BCR, FET_RPBLE512); CSR_WRITE_4(sc, FET_TCRRCR, FET_TFTSF); */ CSR_WRITE_4(sc, FET_BCR, FET_PBL8); CSR_WRITE_4(sc, FET_TCRRCR, FET_TFTSF|FET_RBLEN|FET_RPBLE512); /* 89/12/29 add, for mtd891, */ if (sc->fet_info->fet_did==ID2) { FET_SETBIT(sc, FET_BCR, FET_PROG); FET_SETBIT(sc, FET_TCRRCR, FET_Enhanced); } fet_setcfg(sc, phy_bmcr); /* Init circular RX list. */ if (fet_list_rx_init(sc) == ENOBUFS) { printf("fet%d: initialization failed: no memory for rx buffers\n", sc->fet_unit); fet_stop(sc); (void)splx(s); return; } /* Init TX descriptors. */ fet_list_tx_init(sc); /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) FET_SETBIT(sc, FET_TCRRCR, FET_PROM); else FET_CLRBIT(sc, FET_TCRRCR, FET_PROM); /* * Set capture broadcast bit to capture broadcast frames. */ if (ifp->if_flags & IFF_BROADCAST) FET_SETBIT(sc, FET_TCRRCR, FET_AB); else FET_CLRBIT(sc, FET_TCRRCR, FET_AB); /* * Program the multicast filter, if necessary. */ fet_setmulti(sc); /* * Load the address of the RX list. */ FET_CLRBIT(sc, FET_TCRRCR, FET_RE); CSR_WRITE_4(sc, FET_RXLBA, vtophys(&sc->fet_ldata->fet_rx_list[0])); /* * Enable interrupts. */ CSR_WRITE_4(sc, FET_IMR, FET_INTRS); CSR_WRITE_4(sc, FET_ISR, 0xFFFFFFFF); /* Enable receiver and transmitter. */ FET_SETBIT(sc, FET_TCRRCR, FET_RE); FET_CLRBIT(sc, FET_TCRRCR, FET_TE); CSR_WRITE_4(sc, FET_TXLBA, vtophys(&sc->fet_ldata->fet_tx_list[0])); FET_SETBIT(sc, FET_TCRRCR, FET_TE); /* Restore state of BMCR */ if (sc->fet_pinfo != NULL) fet_phy_writereg(sc, PHY_BMCR, phy_bmcr); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; (void)splx(s); return; } /* * Set media options. */ static int fet_ifmedia_upd(ifp) struct ifnet *ifp; { struct fet_softc *sc; struct ifmedia *ifm; sc = ifp->if_softc; ifm = &sc->ifmedia; if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) return(EINVAL); if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) fet_autoneg_mii(sc, FET_FLAG_SCHEDDELAY, 1); else fet_setmode_mii(sc, ifm->ifm_media); return(0); } /* * Report current media status. */ static void fet_ifmedia_sts(ifp, ifmr) struct ifnet *ifp; struct ifmediareq *ifmr; { struct fet_softc *sc; u_int16_t advert = 0, ability = 0, ability2 = 0; sc = ifp->if_softc; ifmr->ifm_active = IFM_ETHER; if (!(fet_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { /* this version did not support 1000M, if (fet_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_1000) ifmr->ifm_active = IFM_ETHER|IFM_1000TX; */ if (fet_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) ifmr->ifm_active = IFM_ETHER|IFM_100_TX; else ifmr->ifm_active = IFM_ETHER|IFM_10_T; if (fet_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) ifmr->ifm_active |= IFM_FDX; else ifmr->ifm_active |= IFM_HDX; return; } ability = fet_phy_readreg(sc, PHY_LPAR); advert = fet_phy_readreg(sc, PHY_ANAR); /* this version did not support 1000M, if (sc->fet_pinfo->fet_vid = MarvellPHYID0) { ability2 = fet_phy_readreg(sc, PHY_1000SR); if (ability2 & PHY_1000SR_1000BTXFULL) { advert = 0; ability = 0; ifmr->ifm_active = IFM_ETHER|IFM_1000_TX|IFM_FDX; } else if (ability & PHY_1000SR_1000BTXHALF) { advert = 0; ability = 0; ifmr->ifm_active = IFM_ETHER|IFM_1000_TX|IFM_HDX; } } */ if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) ifmr->ifm_active = IFM_ETHER|IFM_100_T4; else if (advert & PHY_ANAR_100BTXFULL && ability & PHY_ANAR_100BTXFULL) ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; else if (advert & PHY_ANAR_100BTXHALF && ability & PHY_ANAR_100BTXHALF) ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; else if (advert & PHY_ANAR_10BTFULL && ability & PHY_ANAR_10BTFULL) ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; else if (advert & PHY_ANAR_10BTHALF && ability & PHY_ANAR_10BTHALF) ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; return; } static int fet_ioctl(ifp, command, data) struct ifnet *ifp; u_long command; caddr_t data; { struct fet_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; s = splimp(); switch(command) { case SIOCSIFADDR: case SIOCGIFADDR: case SIOCSIFMTU: error = ether_ioctl(ifp, command, data); break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) fet_init(sc); else if (ifp->if_flags & IFF_RUNNING) fet_stop(sc); error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: fet_setmulti(sc); error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); break; default: error = EINVAL; break; } (void)splx(s); return(error); } static void fet_watchdog(ifp) struct ifnet *ifp; { struct fet_softc *sc; sc = ifp->if_softc; if (sc->fet_autoneg) { fet_autoneg_mii(sc, FET_FLAG_DELAYTIMEO, 1); return; } ifp->if_oerrors++; printf("fet%d: watchdog timeout\n", sc->fet_unit); if (!(fet_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) printf("fet%d: no carrier - transceiver cable problem?\n", sc->fet_unit); fet_stop(sc); fet_reset(sc); fet_init(sc); if (ifp->if_snd.ifq_head != NULL) fet_start(ifp); return; } /* * Stop the adapter and free any mbufs allocated to the * RX and TX lists. */ static void fet_stop(sc) struct fet_softc *sc; { register int i; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; FET_CLRBIT(sc, FET_TCRRCR, (FET_RE|FET_TE)); CSR_WRITE_4(sc, FET_IMR, 0x00000000); CSR_WRITE_4(sc, FET_TXLBA, 0x00000000); CSR_WRITE_4(sc, FET_RXLBA, 0x00000000); /* * Free data in the RX lists. */ for (i = 0; i < FET_RX_LIST_CNT; i++) { if (sc->fet_cdata.fet_rx_chain[i].fet_mbuf != NULL) { m_freem(sc->fet_cdata.fet_rx_chain[i].fet_mbuf); sc->fet_cdata.fet_rx_chain[i].fet_mbuf = NULL; } } bzero((char *)&sc->fet_ldata->fet_rx_list, sizeof(sc->fet_ldata->fet_rx_list)); /* * Free the TX list buffers. */ for (i = 0; i < FET_TX_LIST_CNT; i++) { if (sc->fet_cdata.fet_tx_chain[i].fet_mbuf != NULL) { m_freem(sc->fet_cdata.fet_tx_chain[i].fet_mbuf); sc->fet_cdata.fet_tx_chain[i].fet_mbuf = NULL; } } bzero((char *)&sc->fet_ldata->fet_tx_list, sizeof(sc->fet_ldata->fet_tx_list)); ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); return; } /* * Stop all chip I/O so that the kernel's probe routines don't * get confused by errant DMAs when rebooting. */ static void fet_shutdown(howto, arg) int howto; void *arg; { struct fet_softc *sc = (struct fet_softc *)arg; fet_stop(sc); return; } static struct pci_device fet_device = { "fet", fet_probe, fet_attach, &fet_count, NULL }; DATA_SET(pcidevice_set, fet_device); -------------------------------------------------------------- if_fetreg.h -------------------------------------------------------------- /* * register definitions. */ #define FET_PAR0 0x0 /* physical address 0-3 */ #define FET_PAR1 0x04 /* physical address 4-5 */ #define FET_MAR0 0x08 /* multicast address 0-3 */ #define FET_MAR1 0x0C /* multicast address 4-7 */ #define FET_FAR0 0x10 /* flow-control address 0-3 */ #define FET_FAR1 0x14 /* flow-control address 4-5 */ #define FET_TCRRCR 0x18 /* receive & transmit configuration */ #define FET_BCR 0x1C /* bus command */ #define FET_TXPDR 0x20 /* transmit polling demand */ #define FET_RXPDR 0x24 /* receive polling demand */ #define FET_RXCWP 0x28 /* receive current word pointer */ #define FET_TXLBA 0x2C /* transmit list base address */ #define FET_RXLBA 0x30 /* receive list base address */ #define FET_ISR 0x34 /* interrupt status */ #define FET_IMR 0x38 /* interrupt mask */ #define FET_FTH 0x3C /* flow control high/low threshold */ #define FET_MANAGEMENT 0x40 /* bootrom/eeprom and mii management */ #define FET_TALLY 0x44 /* tally counters for crc and mpa */ #define FET_TSR 0x48 /* tally counter for transmit status */ #define FET_PHYBASE 0x4c /* * Receive Configuration Register */ #define FET_RXRUN 0x00008000 /* receive running status */ #define FET_EIEN 0x00004000 /* early interrupt enable */ #define FET_RFCEN 0x00002000 /* receive flow control packet enable */ #define FET_NDFA 0x00001000 /* not defined flow control address */ #define FET_RBLEN 0x00000800 /* receive burst length enable */ #define FET_RPBLE1 0x00000000 /* 1 word */ #define FET_RPBLE4 0x00000100 /* 4 words */ #define FET_RPBLE8 0x00000200 /* 8 words */ #define FET_RPBLE16 0x00000300 /* 16 words */ #define FET_RPBLE32 0x00000400 /* 32 words */ #define FET_RPBLE64 0x00000500 /* 64 words */ #define FET_RPBLE128 0x00000600 /* 128 words */ #define FET_RPBLE512 0x00000700 /* 512 words */ #define FET_PROM 0x000000080 /* promiscuous mode */ #define FET_AB 0x000000040 /* accept broadcast */ #define FET_AM 0x000000020 /* accept mutlicast */ #define FET_ARP 0x000000008 /* receive runt pkt */ #define FET_ALP 0x000000004 /* receive long pkt */ #define FET_SEP 0x000000002 /* receive error pkt */ #define FET_RE 0x000000001 /* receive enable */ /* * Transmit Configuration Register */ #define FET_TXRUN 0x04000000 /* transmit running status */ #define FET_Enhanced 0x02000000 /* transmit enhanced mode */ #define FET_TFCEN 0x01000000 /* tx flow control packet enable */ #define FET_TFT64 0x00000000 /* 64 bytes */ #define FET_TFT32 0x00200000 /* 32 bytes */ #define FET_TFT128 0x00400000 /* 128 bytes */ #define FET_TFT256 0x00600000 /* 256 bytes */ #define FET_TFT512 0x00800000 /* 512 bytes */ #define FET_TFT768 0x00A00000 /* 768 bytes */ #define FET_TFT1024 0x00C00000 /* 1024 bytes */ #define FET_TFTSF 0x00E00000 /* store and forward */ #define FET_FD 0x00100000 /* full duplex mode */ #define FET_PS10 0x00080000 /* port speed is 10M */ #define FET_TE 0x00040000 /* transmit enable */ #define FET_PS1000 0x00010000 /* port speed is 1000M */ /* * Bus Command Register */ #define FET_PROG 0x00000200 /* programming */ #define FET_RLE 0x00000100 /* read line command enable */ #define FET_RME 0x00000080 /* read multiple command enable */ #define FET_WIE 0x00000040 /* write and invalidate cmd enable */ #define FET_PBL1 0x00000000 /* 1 dword */ #define FET_PBL4 0x00000008 /* 4 dwords */ #define FET_PBL8 0x00000010 /* 8 dwords */ #define FET_PBL16 0x00000018 /* 16 dwords */ #define FET_PBL32 0x00000020 /* 32 dwords */ #define FET_PBL64 0x00000028 /* 64 dwords */ #define FET_PBL128 0x00000030 /* 128 dwords */ #define FET_PBL512 0x00000038 /* 512 dwords */ #define FET_ABR 0x00000004 /* arbitration rule */ #define FET_BLS 0x00000002 /* big/little endian select */ #define FET_SWR 0x00000001 /* software reset */ /* * Transmit Poll Demand Register */ #define FET_TxPollDemand 0x1 /* * Receive Poll Demand Register */ #define FET_RxPollDemand 0x01 /* * Interrupt Status Register */ #define FET_RFCON 0x00020000 /* receive flow control xon packet */ #define FET_RFCOFF 0x00010000 /* receive flow control xoff packet */ #define FET_LSCStatus 0x00008000 /* link status change */ #define FET_ANCStatus 0x00004000 /* autonegotiation completed */ #define FET_FBE 0x00002000 /* fatal bus error */ #define FET_FBEMask 0x00001800 #define FET_ParityErr 0x00000000 /* parity error */ #define FET_MasterErr 0x00000800 /* master error */ #define FET_TargetErr 0x00001000 /* target abort */ #define FET_TUNF 0x00000400 /* transmit underflow */ #define FET_ROVF 0x00000200 /* receive overflow */ #define FET_ETI 0x00000100 /* transmit early int */ #define FET_ERI 0x00000080 /* receive early int */ #define FET_CNTOVF 0x00000040 /* counter overflow */ #define FET_RBU 0x00000020 /* receive buffer unavailable */ #define FET_TBU 0x00000010 /* transmit buffer unavilable */ #define FET_TI 0x00000008 /* transmit interrupt */ #define FET_RI 0x00000004 /* receive interrupt */ #define FET_RxErr 0x00000002 /* receive error */ /* * Interrupt Mask Register */ #define FET_MRFCON 0x00020000 /* receive flow control xon packet */ #define FET_MRFCOFF 0x00010000 /* receive flow control xoff packet */ #define FET_MLSCStatus 0x00008000 /* link status change */ #define FET_MANCStatus 0x00004000 /* autonegotiation completed */ #define FET_MFBE 0x00002000 /* fatal bus error */ #define FET_MFBEMask 0x00001800 #define FET_MTUNF 0x00000400 /* transmit underflow */ #define FET_MROVF 0x00000200 /* receive overflow */ #define FET_METI 0x00000100 /* transmit early int */ #define FET_MERI 0x00000080 /* receive early int */ #define FET_MCNTOVF 0x00000040 /* counter overflow */ #define FET_MRBU 0x00000020 /* receive buffer unavailable */ #define FET_MTBU 0x00000010 /* transmit buffer unavilable */ #define FET_MTI 0x00000008 /* transmit interrupt */ #define FET_MRI 0x00000004 /* receive interrupt */ #define FET_MRxErr 0x00000002 /* receive error */ /* 90/1/18 delete */ /* #define FET_INTRS FET_FBE|FET_MRBU|FET_TBU|FET_MTI|FET_MRI|FET_METI */ #define FET_INTRS FET_MRBU|FET_TBU|FET_MTI|FET_MRI|FET_METI /* * Flow Control High/Low Threshold Register */ #define FET_FCHTShift 16 /* flow control high threshold */ #define FET_FCLTShift 0 /* flow control low threshold */ /* * BootROM/EEPROM/MII Management Register */ #define FET_MASK_MIIR_MII_READ 0x00000000 #define FET_MASK_MIIR_MII_WRITE 0x00000008 #define FET_MASK_MIIR_MII_MDO 0x00000004 #define FET_MASK_MIIR_MII_MDI 0x00000002 #define FET_MASK_MIIR_MII_MDC 0x00000001 /* * Tally Counter for CRC and MPA */ #define FET_TCOVF 0x80000000 /* crc tally counter overflow */ #define FET_CRCMask 0x7fff0000 /* crc number: bit 16-30 */ #define FET_CRCShift 16 #define FET_TMOVF 0x00008000 /* mpa tally counter overflow */ #define FET_MPAMask 0x00007fff /* mpa number: bit 0-14 */ #define FET_MPAShift 0 /* * Tally Counters for transmit status */ #define FET_AbortMask 0xff000000 /* transmit abort number */ #define FET_AbortShift 24 #define FET_LColMask 0x00ff0000 /* transmit late collisions */ #define FET_LColShift 16 #define FET_NCRMask 0x0000ffff /* transmit retry number */ #define FET_NCRShift 0 /* * Myson TX/RX descriptor structure. */ struct fet_desc { u_int32_t fet_status; u_int32_t fet_ctl; u_int32_t fet_data; u_int32_t fet_next; }; /* * for tx/rx descriptors */ #define FET_OWNByNIC 0x80000000 #define FET_OWNByDriver 0x0 /* * receive descriptor 0 */ #define FET_RXOWN 0x80000000 /* own bit */ #define FET_FLNGMASK 0x0fff0000 /* frame length */ #define FET_FLNGShift 16 #define FET_MARSTATUS 0x00004000 /* multicast address received */ #define FET_BARSTATUS 0x00002000 /* broadcast address received */ #define FET_PHYSTATUS 0x00001000 /* physical address received */ #define FET_RXFSD 0x00000800 /* first descriptor */ #define FET_RXLSD 0x00000400 /* last descriptor */ #define FET_ES 0x00000080 /* error summary */ #define FET_RUNT 0x00000040 /* runt packet received */ #define FET_LONG 0x00000020 /* long packet received */ #define FET_FAE 0x00000010 /* frame align error */ #define FET_CRC 0x00000008 /* crc error */ #define FET_RXER 0x00000004 /* receive error */ #define FET_RDES0CHECK 0x000078fc /* only check MAR, BAR, PHY, ES, RUNT, LONG, FAE, CRC and RXER bits */ /* * receive descriptor 1 */ #define FET_RXIC 0x00800000 /* interrupt control */ #define FET_RBSMASK 0x000007ff /* receive buffer size */ #define FET_RBSShift 0 /* * transmit descriptor 0 */ #define FET_TXERR 0x00008000 /* transmit error */ #define FET_JABTO 0x00004000 /* jabber timeout */ #define FET_CSL 0x00002000 /* carrier sense lost */ #define FET_LC 0x00001000 /* late collision */ #define FET_EC 0x00000800 /* excessive collision */ #define FET_UDF 0x00000400 /* fifo underflow */ #define FET_DFR 0x00000200 /* deferred */ #define FET_HF 0x00000100 /* heartbeat fail */ #define FET_NCRMASK 0x000000ff /* collision retry count */ #define FET_NCRShift 0 /* * tx descriptor 1 */ #define FET_TXIC 0x80000000 /* interrupt control */ #define FET_ETIControl 0x40000000 /* early transmit interrupt */ #define FET_TXLD 0x20000000 /* last descriptor */ #define FET_TXFD 0x10000000 /* first descriptor */ #define FET_CRCDisable 0x00000000 /* crc control */ #define FET_CRCEnable 0x08000000 #define FET_PADDisable 0x00000000 /* padding control */ #define FET_PADEnable 0x04000000 #define FET_RetryTxLC 0x02000000 /* retry late collision */ #define FET_PKTShift 11 /* transmit pkt size */ #define FET_TBSMASK 0x000007ff #define FET_TBSShift 0 /* transmit buffer size */ #define FET_MAXFRAGS 1 #define FET_RX_LIST_CNT 64 #define FET_TX_LIST_CNT 64 #define FET_MIN_FRAMELEN 60 /* * A transmit 'super descriptor' is actually FET_MAXFRAGS regular * descriptors clumped together. The idea here is to emulate the * multi-fragment descriptor layout found in devices such as the * Texas Instruments ThunderLAN and 3Com boomerang and cylone chips. * The advantage to using this scheme is that it avoids buffer copies. * The disadvantage is that there's a certain amount of overhead due * to the fact that each 'fragment' is 16 bytes long. In fet tests, * this limits top speed to about 10.5MB/sec. It should be more like * 11.5MB/sec. However, the upshot is that you can achieve better * results on slower machines: a Pentium 200 can pump out packets at * same speed as a PII 400. */ struct fet_txdesc { struct fet_desc fet_frag[FET_MAXFRAGS]; }; #define FET_TXSTATUS(x) x->fet_ptr->fet_frag[x->fet_lastdesc].fet_status #define FET_TXCTL(x) x->fet_ptr->fet_frag[x->fet_lastdesc].fet_ctl #define FET_TXDATA(x) x->fet_ptr->fet_frag[x->fet_lastdesc].fet_data #define FET_TXNEXT(x) x->fet_ptr->fet_frag[x->fet_lastdesc].fet_next #define FET_TXOWN(x) x->fet_ptr->fet_frag[0].fet_status #define FET_UNSENT 0x1234 struct fet_list_data { struct fet_desc fet_rx_list[FET_RX_LIST_CNT]; struct fet_txdesc fet_tx_list[FET_TX_LIST_CNT]; }; struct fet_chain { struct fet_txdesc *fet_ptr; struct mbuf *fet_mbuf; struct fet_chain *fet_nextdesc; u_int8_t fet_lastdesc; }; struct fet_chain_onefrag { struct fet_desc *fet_ptr; struct mbuf *fet_mbuf; struct fet_chain_onefrag *fet_nextdesc; u_int8_t fet_rlast; }; struct fet_chain_data { struct fet_chain_onefrag fet_rx_chain[FET_RX_LIST_CNT]; struct fet_chain fet_tx_chain[FET_TX_LIST_CNT]; struct fet_chain_onefrag *fet_rx_head; struct fet_chain *fet_tx_head; struct fet_chain *fet_tx_tail; struct fet_chain *fet_tx_free; }; struct fet_type { u_int16_t fet_vid; u_int16_t fet_did; char *fet_name; }; #define FET_FLAG_FORCEDELAY 1 #define FET_FLAG_SCHEDDELAY 2 #define FET_FLAG_DELAYTIMEO 3 struct fet_softc { struct arpcom arpcom; /* interface info */ struct ifmedia ifmedia; /* media info */ bus_space_handle_t fet_bhandle; bus_space_tag_t fet_btag; struct fet_type *fet_info; /* adapter info */ struct fet_type *fet_pinfo; /* phy info */ u_int8_t fet_unit; /* interface number */ u_int8_t fet_type; u_int8_t fet_phy_addr; /* PHY address */ u_int8_t fet_tx_pend; /* TX pending */ u_int8_t fet_want_auto; u_int8_t fet_autoneg; u_int16_t fet_txthresh; caddr_t fet_ldata_ptr; struct fet_list_data *fet_ldata; struct fet_chain_data fet_cdata; }; /* * register space access macros */ #define CSR_WRITE_4(sc, reg, val) \ bus_space_write_4(sc->fet_btag, sc->fet_bhandle, reg, val) #define CSR_WRITE_2(sc, reg, val) \ bus_space_write_2(sc->fet_btag, sc->fet_bhandle, reg, val) #define CSR_WRITE_1(sc, reg, val) \ bus_space_write_1(sc->fet_btag, sc->fet_bhandle, reg, val) #define CSR_READ_4(sc, reg) \ bus_space_read_4(sc->fet_btag, sc->fet_bhandle, reg) #define CSR_READ_2(sc, reg) \ bus_space_read_2(sc->fet_btag, sc->fet_bhandle, reg) #define CSR_READ_1(sc, reg) \ bus_space_read_1(sc->fet_btag, sc->fet_bhandle, reg) #define FET_TIMEOUT 1000 /* * General constants that are fun to know. * * PCI vendor ID */ #define FETVENDORID 0x1516 /* * FETSON device IDs. */ #define ID0 0x0800 #define ID1 0x0803 #define ID2 0x0891 /* * ST+OP+PHYAD+REGAD+TA */ #define FET_OP_READ 0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */ #define FET_OP_WRITE 0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */ /* * Constansts for Myson PHY */ #define MysonPHYID0 0x0300 /* * Constansts for Seeq 80225 PHY */ #define SeeqPHYID0 0x0016 #define SEEQ_MIIRegister18 18 #define SEEQ_SPD_DET_100 0x80 #define SEEQ_DPLX_DET_FULL 0x40 /* * Constansts for Ahdoc 101 PHY */ #define AhdocPHYID0 0x0022 #define AHDOC_DiagnosticReg 18 #define AHDOC_DPLX_FULL 0x0800 #define AHDOC_Speed_100 0x0400 /* * Constansts for Marvell 88E1000/88E1000S PHY and LevelOne PHY */ #define MarvellPHYID0 0x0141 #define LevelOnePHYID0 0x0013 #define Marvell_SpecificStatus 17 #define Marvell_Speed1000 0x8000 #define Marvell_Speed100 0x4000 #define Marvell_FullDuplex 0x2000 /* * PCI low memory base and low I/O base register, and * other PCI registers. Note: some are only available on * the 3c905B, in particular those that related to power management. */ #define FET_PCI_VENDOR_ID 0x00 #define FET_PCI_DEVICE_ID 0x02 #define FET_PCI_COMMAND 0x04 #define FET_PCI_STATUS 0x06 #define FET_PCI_CLASSCODE 0x09 #define FET_PCI_LATENCY_TIMER 0x0D #define FET_PCI_HEADER_TYPE 0x0E #define FET_PCI_LOIO 0x10 #define FET_PCI_LOMEM 0x14 #define FET_PCI_BIOSROM 0x30 #define FET_PCI_INTLINE 0x3C #define FET_PCI_INTPIN 0x3D #define FET_PCI_MINGNT 0x3E #define FET_PCI_MINLAT 0x0F #define FET_PCI_RESETOPT 0x48 #define FET_PCI_EEPROM_DATA 0x4C #define PHY_UNKNOWN 3 #define FET_PHYADDR_MIN 0x00 #define FET_PHYADDR_MAX 0x1F #define PHY_BMCR 0x00 #define PHY_BMSR 0x01 #define PHY_VENID 0x02 #define PHY_DEVID 0x03 #define PHY_ANAR 0x04 #define PHY_LPAR 0x05 #define PHY_ANEXP 0x06 #define PHY_NPTR 0x07 #define PHY_LPNPR 0x08 #define PHY_1000CR 0x09 #define PHY_1000SR 0x0a #define PHY_ANAR_NEXTPAGE 0x8000 #define PHY_ANAR_RSVD0 0x4000 #define PHY_ANAR_TLRFLT 0x2000 #define PHY_ANAR_RSVD1 0x1000 #define PHY_ANAR_RSVD2 0x0800 #define PHY_ANAR_RSVD3 0x0400 #define PHY_ANAR_100BT4 0x0200L #define PHY_ANAR_100BTXFULL 0x0100 #define PHY_ANAR_100BTXHALF 0x0080 #define PHY_ANAR_10BTFULL 0x0040 #define PHY_ANAR_10BTHALF 0x0020 #define PHY_ANAR_PROTO4 0x0010 #define PHY_ANAR_PROTO3 0x0008 #define PHY_ANAR_PROTO2 0x0004 #define PHY_ANAR_PROTO1 0x0002 #define PHY_ANAR_PROTO0 0x0001 #define PHY_1000SR_1000BTXFULL 0x0800 #define PHY_1000SR_1000BTXHALF 0x0400 /* * These are the register definitions for the PHY (physical layer * interface chip). */ /* * PHY BMCR Basic Mode Control Register */ #define PHY_BMCR_RESET 0x8000 #define PHY_BMCR_LOOPBK 0x4000 #define PHY_BMCR_SPEEDSEL 0x2000 #define PHY_BMCR_AUTONEGENBL 0x1000 #define PHY_BMCR_RSVD0 0x0800 /* write as zero */ #define PHY_BMCR_ISOLATE 0x0400 #define PHY_BMCR_AUTONEGRSTR 0x0200 #define PHY_BMCR_DUPLEX 0x0100 #define PHY_BMCR_COLLTEST 0x0080 #define PHY_BMCR_1000 0x0040 /* only used for Marvell PHY */ #define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */ #define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */ #define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */ #define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */ #define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */ #define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */ /* * RESET: 1 == software reset, 0 == normal operation * Resets status and control registers to default values. * Relatches all hardware config values. * * LOOPBK: 1 == loopback operation enabled, 0 == normal operation * * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s * Link speed is selected byt his bit or if auto-negotiation if bit * 12 (AUTONEGENBL) is set (in which case the value of this register * is ignored). * * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13 * determine speed and mode. Should be cleared and then set if PHY configured * for no autoneg on startup. * * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation * * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation * * DUPLEX: 1 == full duplex mode, 0 == half duplex mode * * COLLTEST: 1 == collision test enabled, 0 == normal operation */ /* * PHY, BMSR Basic Mode Status Register */ #define PHY_BMSR_100BT4 0x8000 #define PHY_BMSR_100BTXFULL 0x4000 #define PHY_BMSR_100BTXHALF 0x2000 #define PHY_BMSR_10BTFULL 0x1000 #define PHY_BMSR_10BTHALF 0x0800 #define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */ #define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */ #define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */ #define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */ #define PHY_BMSR_MFPRESUP 0x0040 #define PHY_BMSR_AUTONEGCOMP 0x0020 #define PHY_BMSR_REMFAULT 0x0010 #define PHY_BMSR_CANAUTONEG 0x0008 #define PHY_BMSR_LINKSTAT 0x0004 #define PHY_BMSR_JABBER 0x0002 #define PHY_BMSR_EXTENDED 0x0001
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?002301c4a23c$3222b790$1b6d18ac>