diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2001-04-05 02:03:14 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2001-04-05 02:03:14 +0000 |
commit | 8454deae1b1734bf8aa6ce12f1030880c0b991e4 (patch) | |
tree | 06fa6ef29dd24a4875a23ccfc0557e7b58ce01e1 /sys | |
parent | c9712f2bde361a8244b6fdb3b8ee336285cae8df (diff) |
merge with freebsd/netbsd; mainly a conversion to mii
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/mii/tlphy.c | 76 | ||||
-rw-r--r-- | sys/dev/pci/if_tl.c | 804 | ||||
-rw-r--r-- | sys/dev/pci/if_tlreg.h | 299 |
3 files changed, 255 insertions, 924 deletions
diff --git a/sys/dev/mii/tlphy.c b/sys/dev/mii/tlphy.c index dada41b4bed..00582287665 100644 --- a/sys/dev/mii/tlphy.c +++ b/sys/dev/mii/tlphy.c @@ -1,8 +1,7 @@ -/* $OpenBSD: tlphy.c,v 1.6 2000/08/26 20:04:18 nate Exp $ */ -/* $NetBSD: tlphy.c,v 1.24 2000/02/02 17:50:46 thorpej Exp $ */ +/* $NetBSD: tlphy.c,v 1.26 2000/07/04 03:29:00 thorpej Exp $ */ /*- - * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -78,9 +77,14 @@ #include <sys/socket.h> #include <sys/errno.h> +#include <machine/bus.h> + #include <net/if.h> #include <net/if_media.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + #include <dev/mii/mii.h> #include <dev/mii/miivar.h> #include <dev/mii/miidevs.h> @@ -89,7 +93,7 @@ #include <dev/mii/tlphyvar.h> /* ThunderLAN PHY can only be on a ThunderLAN */ -#include <dev/pci/if_tlvar.h> +#include <dev/pci/if_tlreg.h> struct tlphy_softc { struct mii_softc sc_mii; /* generic PHY */ @@ -97,13 +101,13 @@ struct tlphy_softc { int sc_need_acomp; }; -int tlphymatch __P((struct device *, void *, void *)); -void tlphyattach __P((struct device *, struct device *, void *)); - struct cfdriver tlphy_cd = { NULL, "tlphy", DV_DULL }; +int tlphymatch __P((struct device *, void *, void *)); +void tlphyattach __P((struct device *, struct device *, void *)); + struct cfattach tlphy_ca = { sizeof(struct tlphy_softc), tlphymatch, tlphyattach, mii_phy_detach, mii_phy_activate @@ -112,13 +116,12 @@ struct cfattach tlphy_ca = { int tlphy_service __P((struct mii_softc *, struct mii_data *, int)); int tlphy_auto __P((struct tlphy_softc *, int)); void tlphy_acomp __P((struct tlphy_softc *)); -void tlphy_status __P((struct tlphy_softc *)); +void tlphy_status __P((struct mii_softc *)); int tlphymatch(parent, match, aux) struct device *parent; - void *match; - void *aux; + void *match, *aux; { struct mii_attach_args *ma = aux; @@ -149,7 +152,9 @@ tlphyattach(parent, self, aux) sc->sc_mii.mii_pdata = mii; sc->sc_mii.mii_flags = mii->mii_flags; + sc->sc_mii.mii_flags &= ~MIIF_NOISOLATE; mii_phy_reset(&sc->sc_mii); + sc->sc_mii.mii_flags |= MIIF_NOISOLATE; /* * Note that if we're on a device that also supports 100baseTX, @@ -165,23 +170,15 @@ tlphyattach(parent, self, aux) else sc->sc_mii.mii_capabilities = 0; - if (sc->sc_tlphycap) { - if (sc->sc_tlphycap & TLPHY_MEDIA_10_2) - ifmedia_add(&mii->mii_media, - IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, - sc->sc_mii.mii_inst), - 0, NULL); - else if (sc->sc_tlphycap & TLPHY_MEDIA_10_5) - ifmedia_add(&mii->mii_media, - IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, - sc->sc_mii.mii_inst), - 0, NULL); - } - } - if (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) { + if (sc->sc_tlphycap & TLPHY_MEDIA_10_2) + ifmedia_add(&mii->mii_media, IFM_MAKEWORD(IFM_ETHER, + IFM_10_2, 0, sc->sc_mii.mii_inst), 0, NULL); + if (sc->sc_tlphycap & TLPHY_MEDIA_10_5) + ifmedia_add(&mii->mii_media, IFM_MAKEWORD(IFM_ETHER, + IFM_10_5, 0, sc->sc_mii.mii_inst), 0, NULL); + if (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) mii_phy_add_media(&sc->sc_mii); - } } int @@ -256,6 +253,18 @@ tlphy_service(self, mii, cmd) return (0); /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?! */ @@ -277,11 +286,11 @@ tlphy_service(self, mii, cmd) } void -tlphy_status(sc) - struct tlphy_softc *sc; +tlphy_status(physc) + struct mii_softc *physc; { + struct tlphy_softc *sc = (void *) physc; struct mii_data *mii = sc->sc_mii.mii_pdata; - struct tl_softc *tlsc = (struct tl_softc *)sc->sc_mii.mii_dev.dv_parent; int bmsr, bmcr, tlctrl; mii->mii_media_status = IFM_AVALID; @@ -296,15 +305,8 @@ tlphy_status(sc) tlctrl = PHY_READ(&sc->sc_mii, MII_TLPHY_CTRL); if (tlctrl & CTRL_AUISEL) { - if (sc->sc_tlphycap & TLPHY_MEDIA_10_2) - mii->mii_media_active |= IFM_10_2; - else if (sc->sc_tlphycap & TLPHY_MEDIA_10_5) - mii->mii_media_active |= IFM_10_5; - else - printf("%s: AUI selected with no matching media !\n", - sc->sc_mii.mii_dev.dv_xname); - if (tlsc->tl_flags & TL_IFACT) - mii->mii_media_status |= IFM_ACTIVE; + mii->mii_media_status = 0; + mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media; return; } diff --git a/sys/dev/pci/if_tl.c b/sys/dev/pci/if_tl.c index 158085f40ef..eef6eae021a 100644 --- a/sys/dev/pci/if_tl.c +++ b/sys/dev/pci/if_tl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_tl.c,v 1.18 2001/03/25 06:37:27 csapuntz Exp $ */ +/* $OpenBSD: if_tl.c,v 1.19 2001/04/05 02:03:12 jason Exp $ */ /* * Copyright (c) 1997, 1998 @@ -31,7 +31,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: if_tl.c,v 1.32 1999/05/09 17:07:01 peter Exp $ + * $FreeBSD: src/sys/pci/if_tl.c,v 1.64 2001/02/06 10:11:48 phk Exp $ */ /* @@ -212,6 +212,9 @@ #include <vm/vm.h> /* for vtophys */ #include <vm/pmap.h> /* for vtophys */ +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcidevs.h> @@ -223,15 +226,25 @@ */ #define TL_USEIOSPACE -/* #define TL_BACKGROUND_AUTONEG */ - #include <dev/pci/if_tlreg.h> +#include <dev/mii/tlphyvar.h> + +const struct tl_products tl_prods[] = { + { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_N100TX, TLPHY_MEDIA_NO_10_T }, + { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_N10T, TLPHY_MEDIA_10_5 }, + { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_IntNF3P, TLPHY_MEDIA_10_2 }, + { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_IntPL100TX, TLPHY_MEDIA_10_5|TLPHY_MEDIA_NO_10_T }, + { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_DPNet100TX, TLPHY_MEDIA_10_5|TLPHY_MEDIA_NO_10_T }, + { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_DP4000, TLPHY_MEDIA_10_5 }, + { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_NF3P_BNC, TLPHY_MEDIA_10_2 }, + { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_NF3P, TLPHY_MEDIA_10_5 }, + { PCI_VENDOR_TI, PCI_PRODUCT_TI_TLAN, 0 }, + { 0, 0, 0 } +}; int tl_probe __P((struct device *, void *, void *)); void tl_attach __P((struct device *, struct device *, void *)); void tl_wait_up __P((void *)); - -int tl_attach_phy __P((struct tl_softc *)); int tl_intvec_rxeoc __P((void *, u_int32_t)); int tl_intvec_txeoc __P((void *, u_int32_t)); int tl_intvec_txeof __P((void *, u_int32_t)); @@ -264,16 +277,16 @@ void tl_mii_sync __P((struct tl_softc *)); void tl_mii_send __P((struct tl_softc *, u_int32_t, int)); int tl_mii_readreg __P((struct tl_softc *, struct tl_mii_frame *)); int tl_mii_writereg __P((struct tl_softc *, struct tl_mii_frame *)); -u_int16_t tl_phy_readreg __P((struct tl_softc *, int)); -void tl_phy_writereg __P((struct tl_softc *, int, int)); +int tl_miibus_readreg __P((struct device *, int, int)); +void tl_miibus_writereg __P((struct device *, int, int, int)); +void tl_miibus_statchg __P((struct device *)); -void tl_autoneg __P((struct tl_softc *, int, int)); void tl_setmode __P((struct tl_softc *, int)); int tl_calchash __P((caddr_t)); void tl_setmulti __P((struct tl_softc *)); void tl_setfilt __P((struct tl_softc *, caddr_t, int)); void tl_softreset __P((struct tl_softc *, int)); -void tl_hardreset __P((struct tl_softc *)); +void tl_hardreset __P((struct device *)); int tl_list_rx_init __P((struct tl_softc *)); int tl_list_tx_init __P((struct tl_softc *)); @@ -720,342 +733,69 @@ int tl_mii_writereg(sc, frame) return(0); } -u_int16_t tl_phy_readreg(sc, reg) - struct tl_softc *sc; - int reg; +int tl_miibus_readreg(dev, phy, reg) + struct device *dev; + int phy, reg; { + struct tl_softc *sc = (struct tl_softc *)dev; struct tl_mii_frame frame; bzero((char *)&frame, sizeof(frame)); - frame.mii_phyaddr = sc->tl_phy_addr; + frame.mii_phyaddr = phy; frame.mii_regaddr = reg; tl_mii_readreg(sc, &frame); - /* Reenable MII interrupts, just in case. */ - tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN); - return(frame.mii_data); } -void tl_phy_writereg(sc, reg, data) - struct tl_softc *sc; - int reg; - int data; +void tl_miibus_writereg(dev, phy, reg, data) + struct device *dev; + int phy, reg, data; { + struct tl_softc *sc = (struct tl_softc *)dev; struct tl_mii_frame frame; bzero((char *)&frame, sizeof(frame)); - frame.mii_phyaddr = sc->tl_phy_addr; + frame.mii_phyaddr = phy; frame.mii_regaddr = reg; frame.mii_data = data; tl_mii_writereg(sc, &frame); - - /* Reenable MII interrupts, just in case. */ - tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN); - - return; } -/* - * Initiate autonegotiation with a link partner. - * - * Note that the Texas Instruments ThunderLAN programmer's guide - * fails to mention one very important point about autonegotiation. - * Autonegotiation is done largely by the PHY, independent of the - * ThunderLAN chip itself: the PHY sets the flags in the BMCR - * register to indicate what modes were selected and if link status - * is good. In fact, the PHY does pretty much all of the work itself, - * except for one small detail. - * - * The PHY may negotiate a full-duplex of half-duplex link, and set - * the PHY_BMCR_DUPLEX bit accordingly, but the ThunderLAN's 'NetCommand' - * register _also_ has a half-duplex/full-duplex bit, and you MUST ALSO - * SET THIS BIT MANUALLY TO CORRESPOND TO THE MODE SELECTED FOR THE PHY! - * In other words, both the ThunderLAN chip and the PHY have to be - * programmed for full-duplex mode in order for full-duplex to actually - * work. So in order for autonegotiation to really work right, we have - * to wait for the link to come up, check the BMCR register, then set - * the ThunderLAN for full or half-duplex as needed. - * - * I struggled for two days to figure this out, so I'm making a point - * of drawing attention to this fact. I think it's very strange that - * the ThunderLAN doesn't automagically track the duplex state of the - * PHY, but there you have it. - * - * Also when, using a National Semiconductor DP83840A PHY, we have to - * allow a full three seconds for autonegotiation to complete. So what - * we do is flip the autonegotiation restart bit, then set a timeout - * to wake us up in three seconds to check the link state. - * - * Note that there are some versions of the Olicom 2326 that use a - * Micro Linear ML6692 100BaseTX PHY. This particular PHY is designed - * to provide 100BaseTX support only, but can be used with a controller - * that supports an internal 10Mbps PHY to provide a complete - * 10/100Mbps solution. However, the ML6692 does not have vendor and - * device ID registers, and hence always shows up with a vendor/device - * ID of 0. - * - * We detect this configuration by checking the phy vendor ID in the - * softc structure. If it's a zero, and we're negotiating a high-speed - * mode, then we turn off the internal PHY. If it's a zero and we've - * negotiated a high-speed mode, we turn on the internal PHY. Note - * that to make things even more fun, we have to make extra sure that - * the loopback bit in the internal PHY's control register is turned - * off. - */ -void tl_autoneg(sc, flag, verbose) - struct tl_softc *sc; - int flag; - int verbose; +void tl_miibus_statchg(dev) + struct device *dev; { - u_int16_t phy_sts = 0, media = 0, advert, ability; - struct ifnet *ifp; - struct ifmedia *ifm; - - ifm = &sc->ifmedia; - ifp = &sc->arpcom.ac_if; + struct tl_softc *sc = (struct tl_softc *)dev; - /* - * First, see if autoneg is supported. If not, there's - * no point in continuing. - */ - phy_sts = tl_phy_readreg(sc, PHY_BMSR); - if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { - if (verbose) - printf("tl%d: autonegotiation not supported\n", - sc->tl_unit); - return; - } - - switch (flag) { - case TL_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. - */ - tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - phy_sts = tl_phy_readreg(sc, PHY_BMCR); - phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; - tl_phy_writereg(sc, PHY_BMCR, phy_sts); - DELAY(5000000); - break; - case TL_FLAG_SCHEDDELAY: - /* - * Wait for the transmitter to go idle before starting - * an autoneg session, otherwise tl_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->tl_txeoc) { - sc->tl_want_auto = 1; - return; - } - tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - phy_sts = tl_phy_readreg(sc, PHY_BMCR); - phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; - tl_phy_writereg(sc, PHY_BMCR, phy_sts); - ifp->if_timer = 10; - sc->tl_autoneg = 1; - sc->tl_want_auto = 0; - return; - case TL_FLAG_DELAYTIMEO: - ifp->if_timer = 0; - sc->tl_autoneg = 0; - break; - default: - printf("tl%d: invalid autoneg flag: %d\n", sc->tl_unit, flag); - return; - } - - /* - * Read the BMSR register twice: the LINKSTAT bit is a - * latching bit. - */ - tl_phy_readreg(sc, PHY_BMSR); - phy_sts = tl_phy_readreg(sc, PHY_BMSR); - if (phy_sts & PHY_BMSR_AUTONEGCOMP) { - if (verbose) - printf("tl%d: autoneg complete, ", sc->tl_unit); - phy_sts = tl_phy_readreg(sc, PHY_BMSR); + if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX) { + tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); } else { - if (verbose) - printf("tl%d: autoneg not complete, ", sc->tl_unit); + tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); } - - /* Link is good. Report modes and set duplex mode. */ - if (phy_sts & PHY_BMSR_LINKSTAT) { - if (verbose) - printf("link status good "); - - advert = tl_phy_readreg(sc, TL_PHY_ANAR); - ability = tl_phy_readreg(sc, TL_PHY_LPAR); - media = tl_phy_readreg(sc, PHY_BMCR); - - /* - * Be sure to turn off the ISOLATE and - * LOOPBACK bits in the control register, - * otherwise we may not be able to communicate. - */ - media &= ~(PHY_BMCR_LOOPBK|PHY_BMCR_ISOLATE); - /* Set the DUPLEX bit in the NetCmd register accordingly. */ - 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; - if (verbose) - 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; - if (verbose) - 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; - if (verbose) - 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; - if (verbose) - printf("(full-duplex, 10Mbps)\n"); - } else { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - media &= ~PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - if (verbose) - printf("(half-duplex, 10Mbps)\n"); - } - - if (media & PHY_BMCR_DUPLEX) - tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); - else - tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); - - media &= ~PHY_BMCR_AUTONEGENBL; - tl_phy_writereg(sc, PHY_BMCR, media); - } else { - if (verbose) - printf("no carrier\n"); - } - - tl_init(sc); - - if (sc->tl_tx_pend) { - sc->tl_autoneg = 0; - sc->tl_tx_pend = 0; - tl_start(ifp); - } - - return; } /* - * Set speed and duplex mode. Also program autoneg advertisements - * accordingly. + * Set modes for bitrate devices. */ void tl_setmode(sc, media) struct tl_softc *sc; int media; { - u_int16_t bmcr; - - if (sc->tl_bitrate) { - if (IFM_SUBTYPE(media) == IFM_10_5) - tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_MTXD1); - if (IFM_SUBTYPE(media) == IFM_10_T) { - tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_MTXD1); - if ((media & IFM_GMASK) == IFM_FDX) { - tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_MTXD3); - tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); - } else { - tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_MTXD3); - tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); - } - } - return; - } - - bmcr = tl_phy_readreg(sc, PHY_BMCR); - - bmcr &= ~(PHY_BMCR_SPEEDSEL|PHY_BMCR_DUPLEX|PHY_BMCR_AUTONEGENBL| - PHY_BMCR_LOOPBK|PHY_BMCR_ISOLATE); - - if (IFM_SUBTYPE(media) == IFM_LOOP) - bmcr |= PHY_BMCR_LOOPBK; - - if (IFM_SUBTYPE(media) == IFM_AUTO) - bmcr |= PHY_BMCR_AUTONEGENBL; - - /* - * The ThunderLAN's internal PHY has an AUI transceiver - * that can be selected. This is usually attached to a - * 10base2/BNC port. In order to activate this port, we - * have to set the AUISEL bit in the internal PHY's - * special control register. - */ - if (IFM_SUBTYPE(media) == IFM_10_5) { - u_int16_t addr, ctl; - addr = sc->tl_phy_addr; - sc->tl_phy_addr = TL_PHYADDR_MAX; - ctl = tl_phy_readreg(sc, TL_PHY_CTL); - ctl |= PHY_CTL_AUISEL; - tl_phy_writereg(sc, TL_PHY_CTL, ctl); - tl_phy_writereg(sc, PHY_BMCR, bmcr); - sc->tl_phy_addr = addr; - bmcr |= PHY_BMCR_ISOLATE; - } else { - u_int16_t addr, ctl; - addr = sc->tl_phy_addr; - sc->tl_phy_addr = TL_PHYADDR_MAX; - ctl = tl_phy_readreg(sc, TL_PHY_CTL); - ctl &= ~PHY_CTL_AUISEL; - tl_phy_writereg(sc, TL_PHY_CTL, ctl); - tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_ISOLATE); - sc->tl_phy_addr = addr; - bmcr &= ~PHY_BMCR_ISOLATE; - } - - if (IFM_SUBTYPE(media) == IFM_100_TX) { - bmcr |= PHY_BMCR_SPEEDSEL; - if ((media & IFM_GMASK) == IFM_FDX) { - bmcr |= PHY_BMCR_DUPLEX; - tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); - } else { - bmcr &= ~PHY_BMCR_DUPLEX; - tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); - } - } - + if (IFM_SUBTYPE(media) == IFM_10_5) + tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_MTXD1); if (IFM_SUBTYPE(media) == IFM_10_T) { - bmcr &= ~PHY_BMCR_SPEEDSEL; + tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_MTXD1); if ((media & IFM_GMASK) == IFM_FDX) { - bmcr |= PHY_BMCR_DUPLEX; + tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_MTXD3); tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); } else { - bmcr &= ~PHY_BMCR_DUPLEX; + tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_MTXD3); tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); } } - - tl_phy_writereg(sc, PHY_BMCR, bmcr); - - tl_init(sc); - - return; } /* @@ -1170,39 +910,23 @@ void tl_setmulti(sc) * second pause at the end to 'wait for the clocks to start' but in my * experience this isn't necessary. */ -void tl_hardreset(sc) - struct tl_softc *sc; +void tl_hardreset(dev) + struct device *dev; { + struct tl_softc *sc = (struct tl_softc *)dev; int i; - u_int16_t old_addr, flags; - - old_addr = sc->tl_phy_addr; + u_int16_t flags; - for (i = 0; i < TL_PHYADDR_MAX + 1; i++) { - sc->tl_phy_addr = i; - tl_mii_sync(sc); - } + flags = BMCR_LOOP|BMCR_ISO|BMCR_PDOWN; - flags = PHY_BMCR_LOOPBK|PHY_BMCR_ISOLATE|PHY_BMCR_PWRDOWN; - - for (i = 0; i < TL_PHYADDR_MAX + 1; i++) { - sc->tl_phy_addr = i; - tl_phy_writereg(sc, PHY_BMCR, flags); - } - - sc->tl_phy_addr = TL_PHYADDR_MAX; - tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_ISOLATE); - - DELAY(50000); - - tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_LOOPBK|PHY_BMCR_ISOLATE); + for (i =0 ; i < MII_NPHY; i++) + tl_miibus_writereg(dev, i, MII_BMCR, flags); + tl_miibus_writereg(dev, 31, MII_BMCR, BMCR_ISO); tl_mii_sync(sc); + while(tl_miibus_readreg(dev, 31, MII_BMCR) & BMCR_RESET); - while(tl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); - - sc->tl_phy_addr = old_addr; - + DELAY(5000); return; } @@ -1240,9 +964,6 @@ void tl_softreset(sc, internal) if (sc->tl_bitrate) tl_dio_setbit16(sc, TL_NETCONFIG, TL_CFG_BITRATE); - /* Set PCI burst size */ - tl_dio_write8(sc, TL_BSIZEREG, 0x33); - /* * Load adapter irq pacing timer and tx threshold. * We make the transmit threshold 1 initially but we may @@ -1257,16 +978,6 @@ void tl_softreset(sc, internal) /* Unreset the MII */ tl_dio_setbit(sc, TL_NETSIO, TL_SIO_NMRST); - /* Clear status register */ - tl_dio_setbit16(sc, TL_NETSTS, TL_STS_MIRQ); - tl_dio_setbit16(sc, TL_NETSTS, TL_STS_HBEAT); - tl_dio_setbit16(sc, TL_NETSTS, TL_STS_TXSTOP); - tl_dio_setbit16(sc, TL_NETSTS, TL_STS_RXSTOP); - - /* Enable network status interrupts for everything. */ - tl_dio_setbit(sc, TL_NETMASK, TL_MASK_MASK7|TL_MASK_MASK6| - TL_MASK_MASK5|TL_MASK_MASK4); - /* Take the adapter out of reset */ tl_dio_setbit(sc, TL_NETCMD, TL_CMD_NRESET|TL_CMD_NWRAP); @@ -1277,108 +988,6 @@ void tl_softreset(sc, internal) } /* - * Do the interface setup and attach for a PHY on a particular - * ThunderLAN chip. Also also set up interrupt vectors. - */ -int tl_attach_phy(sc) - struct tl_softc *sc; -{ - int phy_ctl; - int media = IFM_ETHER|IFM_100_TX|IFM_FDX; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - sc->tl_phy_did = tl_phy_readreg(sc, TL_PHY_DEVID); - sc->tl_phy_vid = tl_phy_readreg(sc, TL_PHY_VENID); - sc->tl_phy_sts = tl_phy_readreg(sc, TL_PHY_GENSTS); - phy_ctl = tl_phy_readreg(sc, TL_PHY_GENCTL); - - if (sc->tl_phy_sts & PHY_BMSR_100BT4 || - sc->tl_phy_sts & PHY_BMSR_100BTXFULL || - sc->tl_phy_sts & PHY_BMSR_100BTXHALF) - ifp->if_baudrate = 100000000; - else - ifp->if_baudrate = 10000000; - - if (sc->tl_phy_sts & PHY_BMSR_100BT4 || - sc->tl_phy_sts & PHY_BMSR_100BTXHALF || - sc->tl_phy_sts & PHY_BMSR_100BTXHALF) { - } else { - media &= ~IFM_100_TX; - media |= IFM_10_T; - } - - if (sc->tl_phy_sts & PHY_BMSR_100BTXFULL || - sc->tl_phy_sts & PHY_BMSR_10BTFULL) { - } else { - media &= ~IFM_FDX; - } - - if (sc->tl_phy_sts & PHY_BMSR_CANAUTONEG) { - media = IFM_ETHER|IFM_AUTO; - } - - /* Set up ifmedia data and callbacks. */ - ifmedia_init(&sc->ifmedia, 0, tl_ifmedia_upd, tl_ifmedia_sts); - - /* - * All ThunderLANs support at least 10baseT half duplex. - * They also support AUI selection if used in 10Mb/s modes. - */ - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL); - - /* Some ThunderLAN PHYs support autonegotiation. */ - if (sc->tl_phy_sts & PHY_BMSR_CANAUTONEG) - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - - /* Some support 10baseT full duplex. */ - if (sc->tl_phy_sts & PHY_BMSR_10BTFULL) - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); - - /* Some support 100BaseTX half duplex. */ - if (sc->tl_phy_sts & PHY_BMSR_100BTXHALF) - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); - if (sc->tl_phy_sts & PHY_BMSR_100BTXHALF) - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); - - /* Some support 100BaseTX full duplex. */ - if (sc->tl_phy_sts & PHY_BMSR_100BTXFULL) - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); - - /* Some also support 100BaseT4. */ - if (sc->tl_phy_sts & PHY_BMSR_100BT4) - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); - - /* Set default media. */ - ifmedia_set(&sc->ifmedia, media); - - /* - * Kick off an autonegotiation session if this PHY supports it. - * This is necessary to make sure the chip's duplex mode matches - * the PHY's duplex mode. It may not: once enabled, the PHY may - * autonegotiate full-duplex mode with its link partner, but the - * ThunderLAN chip defaults to half-duplex and stays there unless - * told otherwise. - */ - if (sc->tl_phy_sts & PHY_BMSR_CANAUTONEG) { - tl_init(sc); -#ifdef TL_BACKGROUND_AUTONEG - tl_autoneg(sc, TL_FLAG_SCHEDDELAY, 1); -#else - tl_autoneg(sc, TL_FLAG_FORCEDELAY, 1); -#endif - } - - return(0); -} - -/* * Initialize the transmit lists. */ int tl_list_tx_init(sc) @@ -1668,23 +1277,13 @@ int tl_intvec_txeoc(xsc, type) ifp->if_flags &= ~IFF_OACTIVE; sc->tl_cdata.tl_tx_tail = NULL; sc->tl_txeoc = 1; - /* - * If we just drained the TX queue and - * there's an autoneg request waiting, set - * it in motion. This will block the transmitter - * until the autoneg session completes which will - * no doubt piss off any processes waiting to - * transmit, but that's the way the ball bounces. - */ - if (sc->tl_want_auto) - tl_autoneg(sc, TL_FLAG_SCHEDDELAY, 1); } else { sc->tl_txeoc = 0; /* First we have to ack the EOC interrupt. */ CMD_PUT(sc, TL_CMD_ACK | 0x00000001 | type); /* Then load the address of the next TX list. */ CSR_WRITE_4(sc, TL_CH_PARM, - vtophys(sc->tl_cdata.tl_tx_head->tl_ptr)); + vtophys(sc->tl_cdata.tl_tx_head->tl_ptr)); /* Restart TX channel. */ cmd = CSR_READ_4(sc, TL_HOSTCMD); cmd &= ~TL_CMD_RT; @@ -1701,7 +1300,6 @@ int tl_intvec_adchk(xsc, type) u_int32_t type; { struct tl_softc *sc; - u_int16_t bmcr, ctl; sc = xsc; @@ -1709,24 +1307,7 @@ int tl_intvec_adchk(xsc, type) printf("tl%d: adapter check: %x\n", sc->tl_unit, (unsigned int)CSR_READ_4(sc, TL_CH_PARM)); - /* - * Before resetting the adapter, try reading the PHY - * settings so we can put them back later. This is - * necessary to keep the chip operating at the same - * speed and duplex settings after the reset completes. - */ - if (!sc->tl_bitrate) { - bmcr = tl_phy_readreg(sc, PHY_BMCR); - ctl = tl_phy_readreg(sc, TL_PHY_CTL); - tl_softreset(sc, 1); - tl_phy_writereg(sc, PHY_BMCR, bmcr); - tl_phy_writereg(sc, TL_PHY_CTL, ctl); - if (bmcr & PHY_BMCR_DUPLEX) { - tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); - } else { - tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); - } - } + tl_softreset(sc, 1); tl_stop(sc); tl_init(sc); CMD_SET(sc, TL_CMD_INTSON); @@ -1827,6 +1408,9 @@ void tl_stats_update(xsc) struct ifnet *ifp; struct tl_stats tl_stats; u_int32_t *p; + int s; + + s = splimp(); bzero((char *)&tl_stats, sizeof(struct tl_stats)); @@ -1850,8 +1434,23 @@ void tl_stats_update(xsc) tl_rx_overrun(tl_stats); ifp->if_oerrors += tl_tx_underrun(tl_stats); + if (tl_tx_underrun(tl_stats)) { + u_int8_t tx_thresh; + tx_thresh = tl_dio_read8(sc, TL_ACOMMIT) & TL_AC_TXTHRESH; + if (tx_thresh != TL_AC_TXTHRESH_WHOLEPKT) { + tx_thresh >>= 4; + tx_thresh++; + tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_TXTHRESH); + tl_dio_setbit(sc, TL_ACOMMIT, tx_thresh << 4); + } + } + timeout_add(&sc->tl_stats_tmo, hz); + if (!sc->tl_bitrate) + mii_tick(&sc->sc_mii); + + splx(s); return; } @@ -1960,11 +1559,6 @@ void tl_start(ifp) sc = ifp->if_softc; - if (sc->tl_autoneg) { - sc->tl_tx_pend = 1; - return; - } - /* * Check for an available queue slot. If there are none, * punt. @@ -2051,10 +1645,6 @@ void tl_init(xsc) struct tl_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; int s; - u_int16_t phy_sts; - - if (sc->tl_autoneg) - return; s = splimp(); @@ -2065,6 +1655,13 @@ void tl_init(xsc) */ tl_stop(sc); + /* Initialize TX FIFO threshold */ + tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_TXTHRESH); + tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_TXTHRESH_16LONG); + + /* Set PCI burst size */ + tl_dio_write8(sc, TL_BSIZEREG, TL_RXBURST_16LONG|TL_TXBURST_16LONG); + /* * Set 'capture all frames' bit for promiscuous mode. */ @@ -2081,6 +1678,8 @@ void tl_init(xsc) else tl_dio_setbit(sc, TL_NETCMD, TL_CMD_NOBRX); + tl_dio_write16(sc, TL_MAXRX, MCLBYTES); + /* Init our MAC address */ tl_setfilt(sc, (caddr_t)&sc->arpcom.ac_enaddr, 0); @@ -2099,16 +1698,6 @@ void tl_init(xsc) /* Init TX pointers. */ tl_list_tx_init(sc); - /* - * Enable PHY interrupts. - */ - phy_sts = tl_phy_readreg(sc, TL_PHY_CTL); - phy_sts |= PHY_CTL_INTEN; - tl_phy_writereg(sc, TL_PHY_CTL, phy_sts); - - /* Enable MII interrupts. */ - tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN); - /* Enable PCI interrupts. */ CMD_SET(sc, TL_CMD_INTSON); @@ -2116,32 +1705,11 @@ void tl_init(xsc) CMD_SET(sc, TL_CMD_RT); CSR_WRITE_4(sc, TL_CH_PARM, vtophys(&sc->tl_ldata->tl_rx_list[0])); - /* - * XXX This is a kludge to handle adapters with the Micro Linear - * ML6692 100BaseTX PHY, which only supports 100Mbps modes and - * relies on the controller's internal 10Mbps PHY to provide - * 10Mbps modes. The ML6692 always shows up with a vendor/device ID - * of 0 (it doesn't actually have vendor/device ID registers) - * so we use that property to detect it. In theory there ought to - * be a better way to 'spot the looney' but I can't find one. - */ - if (!sc->tl_phy_vid) { - u_int8_t addr = 0; - u_int16_t bmcr; - - bmcr = tl_phy_readreg(sc, PHY_BMCR); - addr = sc->tl_phy_addr; - sc->tl_phy_addr = TL_PHYADDR_MAX; - tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - if (bmcr & PHY_BMCR_SPEEDSEL) - tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_ISOLATE); - else - tl_phy_writereg(sc, PHY_BMCR, bmcr); - sc->tl_phy_addr = addr; - } + if (!sc->tl_bitrate) + mii_mediachg(&sc->sc_mii); /* Send the RX go command */ - CMD_SET(sc, TL_CMD_GO|TL_CMD_RT); + CMD_SET(sc, TL_CMD_GO|TL_CMD_NES|TL_CMD_RT); (void)splx(s); @@ -2157,22 +1725,16 @@ void tl_init(xsc) /* * Set media options. */ -int tl_ifmedia_upd(ifp) - struct ifnet *ifp; +int +tl_ifmedia_upd(ifp) + struct ifnet *ifp; { - struct tl_softc *sc; - struct ifmedia *ifm; - - sc = ifp->if_softc; - ifm = &sc->ifmedia; - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return(EINVAL); + struct tl_softc *sc = ifp->if_softc; - if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) - tl_autoneg(sc, TL_FLAG_SCHEDDELAY, 1); + if (sc->tl_bitrate) + tl_setmode(sc, sc->ifmedia.ifm_media); else - tl_setmode(sc, ifm->ifm_media); + mii_mediachg(&sc->sc_mii); return(0); } @@ -2184,11 +1746,11 @@ void tl_ifmedia_sts(ifp, ifmr) struct ifnet *ifp; struct ifmediareq *ifmr; { - u_int16_t phy_ctl; - u_int16_t phy_sts; struct tl_softc *sc; + struct mii_data *mii; sc = ifp->if_softc; + mii = &sc->sc_mii; ifmr->ifm_active = IFM_ETHER; if (sc->tl_bitrate) { @@ -2201,28 +1763,10 @@ void tl_ifmedia_sts(ifp, ifmr) else ifmr->ifm_active |= IFM_FDX; return; - } - - phy_ctl = tl_phy_readreg(sc, PHY_BMCR); - phy_sts = tl_phy_readreg(sc, TL_PHY_CTL); - - if (phy_sts & PHY_CTL_AUISEL) - ifmr->ifm_active = IFM_ETHER|IFM_10_5; - - if (phy_ctl & PHY_BMCR_LOOPBK) - ifmr->ifm_active = IFM_ETHER|IFM_LOOP; - - if (phy_ctl & PHY_BMCR_SPEEDSEL) - ifmr->ifm_active = IFM_ETHER|IFM_100_TX; - else - ifmr->ifm_active = IFM_ETHER|IFM_10_T; - - if (phy_ctl & PHY_BMCR_DUPLEX) { - ifmr->ifm_active |= IFM_FDX; - ifmr->ifm_active &= ~IFM_HDX; } else { - ifmr->ifm_active &= ~IFM_FDX; - ifmr->ifm_active |= IFM_HDX; + mii_pollstat(mii); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; } return; @@ -2261,12 +1805,24 @@ int tl_ioctl(ifp, command, data) } case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { - tl_init(sc); + if (ifp->if_flags & IFF_RUNNING && + ifp->if_flags & IFF_PROMISC && + !(sc->tl_if_flags & IFF_PROMISC)) { + tl_dio_setbit(sc, TL_NETCMD, TL_CMD_CAF); + tl_setmulti(sc); + } else if (ifp->if_flags & IFF_RUNNING && + !(ifp->if_flags & IFF_PROMISC) && + sc->tl_if_flags & IFF_PROMISC) { + tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_CAF); + tl_setmulti(sc); + } else + tl_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) { tl_stop(sc); } } + sc->tl_if_flags = ifp->if_flags; error = 0; break; case SIOCADDMULTI: @@ -2286,7 +1842,11 @@ int tl_ioctl(ifp, command, data) break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); + if (sc->tl_bitrate) + error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); + else + error = ifmedia_ioctl(ifp, ifr, + &sc->sc_mii.mii_media, command); break; default: error = EINVAL; @@ -2302,26 +1862,14 @@ void tl_watchdog(ifp) struct ifnet *ifp; { struct tl_softc *sc; - u_int16_t bmsr; sc = ifp->if_softc; - if (sc->tl_autoneg) { - tl_autoneg(sc, TL_FLAG_DELAYTIMEO, 1); - return; - } - - /* Check that we're still connected. */ - tl_phy_readreg(sc, PHY_BMSR); - bmsr = tl_phy_readreg(sc, PHY_BMSR); - if (!(bmsr & PHY_BMSR_LINKSTAT)) { - printf("tl%d: no carrier\n", sc->tl_unit); - tl_autoneg(sc, TL_FLAG_SCHEDDELAY, 1); - } else - printf("tl%d: device timeout\n", sc->tl_unit); + printf("tl%d: device timeout\n", sc->tl_unit); ifp->if_oerrors++; + tl_softreset(sc, 1); tl_init(sc); return; @@ -2359,11 +1907,6 @@ void tl_stop(sc) CMD_SET(sc, TL_CMD_INTSOFF); /* - * Disable MII interrupts. - */ - tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MINTEN); - - /* * Clear list pointer. */ CSR_WRITE_4(sc, TL_CH_PARM, 0); @@ -2455,9 +1998,10 @@ tl_attach(parent, self, aux) bus_addr_t iobase; bus_size_t iosize; u_int32_t command; - u_int round; - u_int8_t *roundptr; - int i, phys; + int i, rseg; + bus_dma_segment_t seg; + bus_dmamap_t dmamap; + caddr_t kva; /* * Map control/status registers. @@ -2527,32 +2071,44 @@ tl_attach(parent, self, aux) } printf(": %s", intrstr); - sc->tl_ldata_ptr = malloc(sizeof(struct tl_list_data) + 8, - M_DEVBUF, M_NOWAIT); - if (sc->tl_ldata_ptr == NULL) { - printf("\n%s: no memory for list buffers\n", - sc->sc_dev.dv_xname); + sc->sc_dmat = pa->pa_dmat; + if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct tl_list_data), + PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) { + printf("%s: can't alloc list\n", sc->sc_dev.dv_xname); + return; + } + if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, sizeof(struct tl_list_data), + &kva, BUS_DMA_NOWAIT)) { + printf("%s: can't map dma buffers (%d bytes)\n", + sc->sc_dev.dv_xname, sizeof(struct tl_list_data)); + bus_dmamem_free(sc->sc_dmat, &seg, rseg); + return; + } + if (bus_dmamap_create(sc->sc_dmat, sizeof(struct tl_list_data), 1, + sizeof(struct tl_list_data), 0, BUS_DMA_NOWAIT, &dmamap)) { + printf("%s: can't create dma map\n", sc->sc_dev.dv_xname); + bus_dmamem_unmap(sc->sc_dmat, kva, sizeof(struct tl_list_data)); + bus_dmamem_free(sc->sc_dmat, &seg, rseg); return; } - bzero(sc->tl_ldata_ptr, sizeof(struct tl_list_data) + 8); + if (bus_dmamap_load(sc->sc_dmat, dmamap, kva, + sizeof(struct tl_list_data), NULL, BUS_DMA_NOWAIT)) { + printf("%s: can't load dma map\n", sc->sc_dev.dv_xname); + bus_dmamap_destroy(sc->sc_dmat, dmamap); + bus_dmamem_unmap(sc->sc_dmat, kva, sizeof(struct tl_list_data)); + bus_dmamem_free(sc->sc_dmat, &seg, rseg); + return; + } + sc->tl_ldata = (struct tl_list_data *)kva; + bzero(sc->tl_ldata, sizeof(struct tl_list_data)); - sc->tl_ldata = (struct tl_list_data *)sc->tl_ldata_ptr; -#ifdef __i386__ - round = (u_int32_t)sc->tl_ldata_ptr & 0xF; -#endif -#ifdef __alpha__ - round = (u_int64_t)sc->tl_ldata_ptr & 0xF; -#endif - roundptr = sc->tl_ldata_ptr; - for (i = 0; i < 8; i++) { - if (round % 8) { - round++; - roundptr++; - } else + for (sc->tl_product = tl_prods; sc->tl_product->tp_vend; + sc->tl_product++) { + if (sc->tl_product->tp_vend == PCI_VENDOR(pa->pa_id) && + sc->tl_product->tp_prod == PCI_PRODUCT(pa->pa_id)) break; } - sc->tl_ldata = (struct tl_list_data *)roundptr; - + sc->tl_unit = sc->sc_dev.dv_unit; if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_COMPAQ || PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TI) @@ -2564,7 +2120,7 @@ tl_attach(parent, self, aux) * Reset adapter. */ tl_softreset(sc, 1); - tl_hardreset(sc); + tl_hardreset(self); DELAY(1000000); tl_softreset(sc, 1); @@ -2598,35 +2154,30 @@ tl_attach(parent, self, aux) ifp->if_start = tl_start; ifp->if_watchdog = tl_watchdog; ifp->if_baudrate = 10000000; - ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; + ifp->if_snd.ifq_maxlen = TL_TX_LIST_CNT - 1; bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); /* * Reset adapter (again). */ tl_softreset(sc, 1); - tl_hardreset(sc); + tl_hardreset(self); DELAY(1000000); tl_softreset(sc, 1); - for (i = TL_PHYADDR_MIN; i < TL_PHYADDR_MAX + 1; i++) { - sc->tl_phy_addr = i; - tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(tl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); - sc->tl_phy_sts = tl_phy_readreg(sc, PHY_BMSR); - if (!sc->tl_phy_sts) - continue; - if (tl_attach_phy(sc)) { - printf("%s: failed to attach a phy %d\n", - sc->sc_dev.dv_xname, i); - return; - } - phys++; - if (phys && i != TL_PHYADDR_MAX) - break; - } - if (!phys) { + /* + * Do MII setup. If no PHYs are found, then this is a + * bitrate ThunderLAN chip that only supports 10baseT + * and AUI/BNC. + */ + sc->sc_mii.mii_ifp = ifp; + sc->sc_mii.mii_readreg = tl_miibus_readreg; + sc->sc_mii.mii_writereg = tl_miibus_writereg; + sc->sc_mii.mii_statchg = tl_miibus_statchg; + ifmedia_init(&sc->sc_mii.mii_media, 0, tl_ifmedia_upd, tl_ifmedia_sts); + mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, + 0); + if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { struct ifmedia *ifm; sc->tl_bitrate = 1; ifmedia_init(&sc->ifmedia, 0, tl_ifmedia_upd, tl_ifmedia_sts); @@ -2640,15 +2191,8 @@ tl_attach(parent, self, aux) ifm = &sc->ifmedia; ifm->ifm_media = ifm->ifm_cur->ifm_media; tl_ifmedia_upd(ifp); - } - - tl_intvec_adchk((void *)sc, 0); - tl_stop(sc); - - /* - * Attempt to clear stray interrupts - */ - tl_intr((void *)sc); + } else + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO); /* * Attach us everywhere. diff --git a/sys/dev/pci/if_tlreg.h b/sys/dev/pci/if_tlreg.h index 087c1e9728f..9234072af71 100644 --- a/sys/dev/pci/if_tlreg.h +++ b/sys/dev/pci/if_tlreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_tlreg.h,v 1.6 2001/02/03 05:52:27 mickey Exp $ */ +/* $OpenBSD: if_tlreg.h,v 1.7 2001/04/05 02:03:13 jason Exp $ */ /* * Copyright (c) 1997, 1998 @@ -31,7 +31,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: if_tlreg.h,v 1.7 1998/10/31 17:23:48 wpaul Exp $ + * $FreeBSD: src/sys/pci/if_tlreg.h,v 1.17 2001/02/09 06:11:21 bmilekic Exp $ */ @@ -52,8 +52,8 @@ struct tl_type { #define TL_MAXFRAGS 10 #define TL_RX_LIST_CNT 20 -#define TL_TX_LIST_CNT 20 -#define TL_MIN_FRAMELEN 64 +#define TL_TX_LIST_CNT 64 +#define TL_MIN_FRAMELEN 128 struct tl_frag { u_int32_t tlist_dcnt; @@ -110,6 +110,12 @@ struct tl_chain_data { struct tl_chain *tl_tx_free; }; +struct tl_products { + u_int16_t tp_vend; + u_int16_t tp_prod; + u_int32_t tp_tlphymedia; +}; + struct tl_softc { struct device sc_dev; /* generic device structure */ void * sc_ih; /* interrupt handler cookie */ @@ -118,23 +124,19 @@ struct tl_softc { struct timeout tl_stats_tmo, tl_wait_tmo; bus_space_handle_t tl_bhandle; bus_space_tag_t tl_btag; + bus_dma_tag_t sc_dmat; struct tl_type *tl_dinfo; /* ThunderLAN adapter info */ struct tl_type *tl_pinfo; /* PHY info struct */ + int tl_if_flags; u_int8_t tl_ctlr; /* chip number */ u_int8_t tl_unit; /* interface number */ u_int8_t tl_eeaddr; - u_int8_t tl_phy_addr; /* PHY address */ - u_int8_t tl_tx_pend; /* TX pending */ - u_int8_t tl_want_auto; /* autoneg scheduled */ - u_int8_t tl_autoneg; /* autoneg in progress */ - u_int16_t tl_phy_sts; /* PHY status */ - u_int16_t tl_phy_vid; /* PHY vendor ID */ - u_int16_t tl_phy_did; /* PHY device ID */ - caddr_t tl_ldata_ptr; struct tl_list_data *tl_ldata; /* TX/RX lists and mbufs */ struct tl_chain_data tl_cdata; u_int8_t tl_txeoc; u_int8_t tl_bitrate; + struct mii_data sc_mii; + const struct tl_products *tl_product; }; /* @@ -142,20 +144,6 @@ struct tl_softc { */ #define TX_THR 0x00000004 -#define TL_FLAG_FORCEDELAY 1 -#define TL_FLAG_SCHEDDELAY 2 -#define TL_FLAG_DELAYTIMEO 3 - -/* - * The ThunderLAN supports up to 32 PHYs. - */ -#define TL_PHYADDR_MIN 0x00 -#define TL_PHYADDR_MAX 0x1F - -#define PHY_UNKNOWN 6 - -#define TL_PHYS_IDLE -1 - /* * General constants that are fun to know. * @@ -168,65 +156,6 @@ struct tl_softc { #define TI_DEVICEID_THUNDERLAN 0x0500 /* - * Known PHY Ids. According to the Level 1 documentation (which is - * very nice, incidentally), here's how they work: - * - * The PHY identifier register #1 is composed of bits 3 through 18 - * of the OUI. (First 16-bit word.) - * The PHY identifier register #2 is composed of bits 19 through 24 - * if the OUI. - * This is followed by 6 bits containing the manufacturer's model - * number. - * Lastly, there are 4 bits for the manufacturer's revision number. - * - * Honestly, there are a lot of these that don't make any sense; the - * only way to be really sure is to look at the data sheets. - */ - -/* - * Texas Instruments PHY identifiers - * - * The ThunderLAN manual has a curious and confusing error in it. - * In chapter 7, which describes PHYs, it says that TI PHYs have - * the following ID codes, where xx denotes a revision: - * - * 0x4000501xx internal 10baseT PHY - * 0x4000502xx TNETE211 100VG-AnyLan PMI - * - * The problem here is that these are not valid 32-bit hex numbers: - * there's one digit too many. My guess is that they mean the internal - * 10baseT PHY is 0x4000501x and the TNETE211 is 0x4000502x since these - * are the only numbers that make sense. - */ -#define TI_PHY_VENDORID 0x4000 -#define TI_PHY_10BT 0x501F -#define TI_PHY_100VGPMI 0x502F - -/* - * These ID values are for the NS DP83840A 10/100 PHY - */ -#define NS_PHY_VENDORID 0x2000 -#define NS_PHY_83840A 0x5C0F - -/* - * Level 1 10/100 PHY - */ -#define LEVEL1_PHY_VENDORID 0x7810 -#define LEVEL1_PHY_LXT970 0x000F - -/* - * Intel 82555 10/100 PHY - */ -#define INTEL_PHY_VENDORID 0x0A28 -#define INTEL_PHY_82555 0x015F - -/* - * SEEQ 80220 10/100 PHY - */ -#define SEEQ_PHY_VENDORID 0x0016 -#define SEEQ_PHY_80220 0xF83F - -/* * These are the PCI vendor and device IDs for Compaq ethernet * adapters based on the ThunderLAN controller. */ @@ -539,6 +468,34 @@ struct tl_stats { #define TL_AC_MTXD2 0x04 /* loopback disable */ #define TL_AC_MTXD3 0x08 /* full duplex disable */ +#define TL_AC_TXTHRESH 0xF0 +#define TL_AC_TXTHRESH_16LONG 0x00 +#define TL_AC_TXTHRESH_32LONG 0x10 +#define TL_AC_TXTHRESH_64LONG 0x20 +#define TL_AC_TXTHRESH_128LONG 0x30 +#define TL_AC_TXTHRESH_256LONG 0x40 +#define TL_AC_TXTHRESH_WHOLEPKT 0x50 + +/* + * PCI burst size register (TL_BSIZEREG). + */ +#define TL_RXBURST 0x0F +#define TL_TXBURST 0xF0 + +#define TL_RXBURST_4LONG 0x00 +#define TL_RXBURST_8LONG 0x01 +#define TL_RXBURST_16LONG 0x02 +#define TL_RXBURST_32LONG 0x03 +#define TL_RXBURST_64LONG 0x04 +#define TL_RXBURST_128LONG 0x05 + +#define TL_TXBURST_4LONG 0x00 +#define TL_TXBURST_8LONG 0x10 +#define TL_TXBURST_16LONG 0x20 +#define TL_TXBURST_32LONG 0x30 +#define TL_TXBURST_64LONG 0x40 +#define TL_TXBURST_128LONG 0x50 + /* * register space access macros */ @@ -633,178 +590,6 @@ struct tl_stats { tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ETXEN); /* Disable xmit. */ \ tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK); /* Pull clock low again */ - -/* - * These are the register definitions for the PHY (physical layer - * interface chip). - * The ThunderLAN chip has a built-in 10Mb/sec PHY which may be used - * in some configurations. The Compaq 10/100 cards based on the ThunderLAN - * use a National Semiconductor DP83840A PHY. The generic BMCR and BMSR - * layouts for both PHYs are identical, however some of the bits are not - * used by the ThunderLAN's internal PHY (most notably those dealing with - * switching between 10 and 100Mb/sec speeds). Since Both PHYs use the - * same bits, we #define them with generic names here. - */ -/* - * PHY BMCR Basic Mode Control Register - */ -#define PHY_BMCR 0x00 -#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_PWRDOWN 0x0800 /* tlan internal PHY only */ -#define PHY_BMCR_ISOLATE 0x0400 -#define PHY_BMCR_AUTONEGRSTR 0x0200 -#define PHY_BMCR_DUPLEX 0x0100 -#define PHY_BMCR_COLLTEST 0x0080 -#define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */ -#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 0x01 -#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 - -#define PHY_CTL_IGLINK 0x8000 -#define PHY_CTL_SWAPOL 0x4000 -#define PHY_CTL_AUISEL 0x2000 -#define PHY_CTL_SQEEN 0x1000 -#define PHY_CTL_MTEST 0x0800 -#define PHY_CTL_NFEW 0x0004 -#define PHY_CTL_INTEN 0x0002 -#define PHY_CTL_TINT 0x0001 - -#define TL_PHY_GENCTL 0x00 -#define TL_PHY_GENSTS 0x01 - -/* - * PHY Generic Identifier Register, hi bits - */ -#define TL_PHY_VENID 0x02 - -/* - * PHY Generic Identifier Register, lo bits - */ -#define TL_PHY_DEVID 0x03 - -#define TL_PHY_ANAR 0x04 -#define TL_PHY_LPAR 0x05 -#define TL_PHY_ANEXP 0x06 - -#define TL_PHY_PHYID 0x10 -#define TL_PHY_CTL 0x11 -#define TL_PHY_STS 0x12 - -#define TL_LPAR_RMFLT 0x2000 -#define TL_LPAR_RSVD0 0x1000 -#define TL_LPAR_RSVD1 0x0800 -#define TL_LPAR_100BT4 0x0400 -#define TL_LPAR_100BTXFULL 0x0200 -#define TL_LPAR_100BTXHALF 0x0100 -#define TL_LPAR_10BTFULL 0x0080 -#define TL_LPAR_10BTHALF 0x0040 - -/* - * PHY Antoneg advertisement register. - */ -#define PHY_ANAR TL_PHY_ANAR -#define PHY_ANAR_NEXTPAGE 0x8000 -#define PHY_ANAR_RSVD0 0x4000 -#define PHY_ANAR_TLRFLT 0x2000 -#define PHY_ANAR_RSVD1 0x1000 -#define PHY_RSVD_RSDV2 0x0800 -#define PHY_RSVD_RSVD3 0x0400 -#define PHY_ANAR_100BT4 0x0200 -#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_AHAR_PROTO1 0x0002 -#define PHY_AHAR_PROTO0 0x0001 - -/* - * DP83840 PHY, PCS Confifguration Register - */ -#define TL_DP83840_PCS 0x17 -#define TL_DP83840_PCS_LED4_MODE 0x0002 -#define TL_DP83840_PCS_F_CONNECT 0x0020 -#define TL_DP83840_PCS_BIT8 0x0100 -#define TL_DP83840_PCS_BIT10 0x0400 - -/* - * DP83840 PHY, PAR register - */ -#define TL_DP83840_PAR 0x19 - -#define PAR_RSVD0 0x8000 -#define PAR_RSVD1 0x4000 -#define PAR_RSVD2 0x2000 -#define PAR_RSVD3 0x1000 -#define PAR_DIS_CRS_JAB 0x0800 -#define PAR_AN_EN_STAT 0x0400 -#define PAR_RSVD4 0x0200 -#define PAR_FEFI_EN 0x0100 -#define PAR_DUPLEX_STAT 0x0080 -#define PAR_SPEED_10 0x0040 -#define PAR_CIM_STATUS 0x0020 -#define PAR_PHYADDR4 0x0010 -#define PAR_PHYADDR3 0x0008 -#define PAR_PHYADDR2 0x0004 -#define PAR_PHYADDR1 0x0002 -#define PAR_PHYADDR0 0x0001 - - /* * Microchip Technology 24Cxx EEPROM control bytes */ |