summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2001-04-05 02:03:14 +0000
committerJason Wright <jason@cvs.openbsd.org>2001-04-05 02:03:14 +0000
commit8454deae1b1734bf8aa6ce12f1030880c0b991e4 (patch)
tree06fa6ef29dd24a4875a23ccfc0557e7b58ce01e1 /sys
parentc9712f2bde361a8244b6fdb3b8ee336285cae8df (diff)
merge with freebsd/netbsd; mainly a conversion to mii
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/mii/tlphy.c76
-rw-r--r--sys/dev/pci/if_tl.c804
-rw-r--r--sys/dev/pci/if_tlreg.h299
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
*/