summaryrefslogtreecommitdiffstats
path: root/sys/dev/mii
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mii')
-rw-r--r--sys/dev/mii/acphy.c313
-rw-r--r--sys/dev/mii/acphyreg.h77
-rw-r--r--sys/dev/mii/amphy.c298
-rw-r--r--sys/dev/mii/amphyreg.h84
-rw-r--r--sys/dev/mii/bmtphy.c301
-rw-r--r--sys/dev/mii/bmtphyreg.h182
-rw-r--r--sys/dev/mii/brgphy.c633
-rw-r--r--sys/dev/mii/brgphyreg.h267
-rw-r--r--sys/dev/mii/dcphy.c464
-rw-r--r--sys/dev/mii/e1000phy.c428
-rw-r--r--sys/dev/mii/e1000phyreg.h314
-rw-r--r--sys/dev/mii/exphy.c274
-rw-r--r--sys/dev/mii/inphy.c236
-rw-r--r--sys/dev/mii/inphyreg.h35
-rw-r--r--sys/dev/mii/lxtphy.c343
-rw-r--r--sys/dev/mii/lxtphyreg.h90
-rw-r--r--sys/dev/mii/mii.c386
-rw-r--r--sys/dev/mii/mii.h206
-rw-r--r--sys/dev/mii/mii_physubr.c545
-rw-r--r--sys/dev/mii/miibus_if.m45
-rw-r--r--sys/dev/mii/miidevs176
-rw-r--r--sys/dev/mii/miivar.h225
-rw-r--r--sys/dev/mii/mlphy.c436
-rw-r--r--sys/dev/mii/nsgphy.c285
-rw-r--r--sys/dev/mii/nsgphyreg.h72
-rw-r--r--sys/dev/mii/nsphy.c384
-rw-r--r--sys/dev/mii/nsphyreg.h115
-rw-r--r--sys/dev/mii/pnaphy.c230
-rw-r--r--sys/dev/mii/pnphy.c279
-rw-r--r--sys/dev/mii/qsphy.c317
-rw-r--r--sys/dev/mii/qsphyreg.h88
-rw-r--r--sys/dev/mii/rgephy.c476
-rw-r--r--sys/dev/mii/rgephyreg.h142
-rw-r--r--sys/dev/mii/rlphy.c352
-rw-r--r--sys/dev/mii/ruephy.c299
-rw-r--r--sys/dev/mii/ruephyreg.h38
-rw-r--r--sys/dev/mii/tdkphy.c316
-rw-r--r--sys/dev/mii/tdkphyreg.h82
-rw-r--r--sys/dev/mii/tlphy.c439
-rw-r--r--sys/dev/mii/tlphyreg.h59
-rw-r--r--sys/dev/mii/ukphy.c229
-rw-r--r--sys/dev/mii/ukphy_subr.c119
-rw-r--r--sys/dev/mii/xmphy.c345
-rw-r--r--sys/dev/mii/xmphyreg.h117
44 files changed, 11141 insertions, 0 deletions
diff --git a/sys/dev/mii/acphy.c b/sys/dev/mii/acphy.c
new file mode 100644
index 0000000..47105ff
--- /dev/null
+++ b/sys/dev/mii/acphy.c
@@ -0,0 +1,313 @@
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Driver for Altima AC101 10/100 PHY
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/acphyreg.h>
+
+#include "miibus_if.h"
+
+static int acphy_probe(device_t);
+static int acphy_attach(device_t);
+
+static device_method_t acphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, acphy_probe),
+ DEVMETHOD(device_attach, acphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t acphy_devclass;
+
+static driver_t acphy_driver = {
+ "acphy",
+ acphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(acphy, miibus, acphy_driver, acphy_devclass, 0, 0);
+
+static int acphy_service(struct mii_softc *, struct mii_data *, int);
+static void acphy_reset(struct mii_softc *);
+static void acphy_status(struct mii_softc *);
+
+static int
+acphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxALTIMA &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxALTIMA_AC101) {
+ device_set_desc(dev, MII_STR_xxALTIMA_AC101);
+ } else if(MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxALTIMA &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxALTIMA_AC101L) {
+ device_set_desc(dev, MII_STR_xxALTIMA_AC101L);
+ } else
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+acphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = acphy_service;
+ sc->mii_pdata = mii;
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+ acphy_reset(sc);
+
+ mii->mii_instance++;
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_add_media(sc);
+ printf("\n");
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return (0);
+}
+
+static int
+acphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ /*
+ * If we're not selected, then do nothing, just isolate and power
+ * down, if changing media.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ if (cmd == MII_MEDIACHG) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO | BMCR_PDOWN);
+ }
+
+ return (0);
+ }
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ /* Wake & deisolate up if necessary */
+ reg = PHY_READ(sc, MII_BMCR);
+ if (reg & (BMCR_ISO | BMCR_PDOWN))
+ PHY_WRITE(sc, MII_BMCR, reg & ~(BMCR_ISO | BMCR_PDOWN));
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
+ return (0);
+
+ (void) mii_phy_auto(sc);
+ break;
+
+ default:
+ /*
+ * BMCR data is stored in the ifmedia entry.
+ */
+ PHY_WRITE(sc, MII_ANAR,
+ mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * This PHY's autonegotiation doesn't need to be kicked.
+ */
+ break;
+ }
+
+ /* Update the media status. */
+ acphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+acphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int bmsr, bmcr, diag;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, MII_BMSR) |
+ PHY_READ(sc, MII_BMSR);
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(sc, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BMCR_AUTOEN) {
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+ diag = PHY_READ(sc, MII_ACPHY_DIAG);
+ if (diag & AC_DIAG_SPEED)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+
+ if (diag & AC_DIAG_DUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+ } else
+ mii->mii_media_active = ife->ifm_media;
+}
+
+static void
+acphy_reset(sc)
+ struct mii_softc *sc;
+{
+
+ mii_phy_reset(sc);
+ PHY_WRITE(sc, MII_ACPHY_INT, 0);
+}
diff --git a/sys/dev/mii/acphyreg.h b/sys/dev/mii/acphyreg.h
new file mode 100644
index 0000000..827aba6
--- /dev/null
+++ b/sys/dev/mii/acphyreg.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2001 Semen Ustimenko (semenu@FreeBSD.org)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_ACPHYREG_H_
+#define _DEV_MII_ACPHYREG_H_
+
+/*
+ * Register definitions for the Altima Communications AC101
+ */
+
+#define MII_ACPHY_POL 0x10 /* Polarity int level */
+
+/* High byte is interrupt mask register */
+#define MII_ACPHY_INT 0x11 /* Interrupt control/status */
+#define AC_INT_ACOMP 0x0001 /* Autoneg complete */
+#define AC_INT_REM_FLT 0x0002 /* Remote fault */
+#define AC_INT_LINK_DOWN 0x0004 /* Link not OK */
+#define AC_INT_LP_ACK 0x0008 /* FLP ack recved */
+#define AC_INT_PD_FLT 0x0010 /* Parallel detect fault */
+#define AC_INT_PAGE_RECV 0x0020 /* New page recved */
+#define AC_INT_RX_ER 0x0040 /* RX_ER transitions high */
+#define AC_INT_JAB 0x0080 /* Jabber detected */
+
+#define MII_ACPHY_DIAG 0x12 /* Diagnostic */
+#define AC_DIAG_RX_LOCK 0x0100
+#define AC_DIAG_RX_PASS 0x0200
+#define AC_DIAG_SPEED 0x0400 /* Aneg speed result */
+#define AC_DIAG_DUPLEX 0x0800 /* Aneg duplex result */
+
+#define MII_ACPHY_PWRLOOP 0x13 /* Power/Loopback */
+#define MII_ACPHY_CBLMEAS 0x14 /* Cable meas. */
+
+#define MII_ACPHY_MCTL 0x15 /* Mode control */
+#define AC_MCTL_FX_SEL 0x0001 /* FX mode */
+#define AC_MCTL_BYP_PCS 0x0001 /* Bypass PCS */
+#define AC_MCTL_SCRMBL 0x0004 /* Data scrambling */
+#define AC_MCTL_REM_LOOP 0x0008 /* Remote loopback */
+#define AC_MCTL_DIS_WDT 0x0010 /* Disable watchdog timer */
+#define AC_MCTL_DIS_REC 0x0020 /* Disable recv error counter */
+#define AC_MCTL_REC_FULL 0x0040 /* Recv error counter full */
+#define AC_MCTL_FRC_FEF 0x0080 /* Force Far End Fault Insert. */
+#define AC_MCTL_DIS_FEF 0x0100 /* Disable FEF Insertion */
+#define AC_MCTL_LED_SEL 0x0200 /* Compat LED config */
+#define AC_MCTL_ALED_SEL 0x0400 /* ActLED RX&TX - RX only */
+#define AC_MCTL_10BT_SEL 0x0800 /* Enable 7-wire interface */
+#define AC_MCTL_DIS_JAB 0x1000 /* Disable jabber */
+#define AC_MCTL_FRC_LINK 0x2000 /* Force TX link up */
+#define AC_MCTL_DIS_NLP 0x4000 /* Disable NLP check */
+
+#define MII_ACPHY_REC 0x18 /* Recv error counter */
+
+#endif /* _DEV_MII_ACPHYREG_H_ */
diff --git a/sys/dev/mii/amphy.c b/sys/dev/mii/amphy.c
new file mode 100644
index 0000000..e63d050
--- /dev/null
+++ b/sys/dev/mii/amphy.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * driver for AMD AM79c873 PHYs
+ * This driver also works for the Davicom DM9101 PHY, which appears to
+ * be an AM79c873 workalike.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/amphyreg.h>
+
+#include "miibus_if.h"
+
+static int amphy_probe(device_t);
+static int amphy_attach(device_t);
+
+static device_method_t amphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, amphy_probe),
+ DEVMETHOD(device_attach, amphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t amphy_devclass;
+
+static driver_t amphy_driver = {
+ "amphy",
+ amphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(amphy, miibus, amphy_driver, amphy_devclass, 0, 0);
+
+static int amphy_service(struct mii_softc *, struct mii_data *, int);
+static void amphy_status(struct mii_softc *);
+
+static int
+amphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ if ((MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_xxAMD ||
+ MII_MODEL(ma->mii_id2) != MII_MODEL_xxAMD_79C873) &&
+ (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_xxDAVICOM ||
+ MII_MODEL(ma->mii_id2) != MII_MODEL_xxDAVICOM_DM9101))
+ return(ENXIO);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxAMD)
+ device_set_desc(dev, MII_STR_xxAMD_79C873);
+ else if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxDAVICOM)
+ device_set_desc(dev, MII_STR_xxDAVICOM_DM9101);
+
+ return(0);
+}
+
+static int
+amphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = amphy_service;
+ sc->mii_pdata = mii;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+#if 0
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+#endif
+
+ mii_phy_reset(sc);
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_add_media(sc);
+ printf("\n");
+#undef ADD
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+amphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
+ return (0);
+ (void) mii_phy_auto(sc);
+ break;
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ default:
+ /*
+ * BMCR data is stored in the ifmedia entry.
+ */
+ PHY_WRITE(sc, MII_ANAR,
+ mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ if (mii_phy_tick(sc) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ amphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+amphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int bmsr, bmcr, par, anlpar;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, MII_BMSR) |
+ PHY_READ(sc, MII_BMSR);
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(sc, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BMCR_AUTOEN) {
+ /*
+ * The PAR status bits are only valid of autonegotiation
+ * has completed (or it's disabled).
+ */
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if (PHY_READ(sc, MII_ANER) & ANER_LPAN) {
+ anlpar = PHY_READ(sc, MII_ANAR) &
+ PHY_READ(sc, MII_ANLPAR);
+ if (anlpar & ANLPAR_T4)
+ mii->mii_media_active |= IFM_100_T4;
+ else if (anlpar & ANLPAR_TX_FD)
+ mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+ else if (anlpar & ANLPAR_TX)
+ mii->mii_media_active |= IFM_100_TX;
+ else if (anlpar & ANLPAR_10_FD)
+ mii->mii_media_active |= IFM_10_T|IFM_FDX;
+ else if (anlpar & ANLPAR_10)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ /*
+ * Link partner is not capable of autonegotiation.
+ */
+ par = PHY_READ(sc, MII_AMPHY_DSCSR);
+ if (par & DSCSR_100FDX)
+ mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+ else if (par & DSCSR_100HDX)
+ mii->mii_media_active |= IFM_100_TX;
+ else if (par & DSCSR_10FDX)
+ mii->mii_media_active |= IFM_10_T|IFM_HDX;
+ else if (par & DSCSR_10HDX)
+ mii->mii_media_active |= IFM_10_T;
+ } else
+ mii->mii_media_active = mii_media_from_bmcr(bmcr);
+}
diff --git a/sys/dev/mii/amphyreg.h b/sys/dev/mii/amphyreg.h
new file mode 100644
index 0000000..ffc362a
--- /dev/null
+++ b/sys/dev/mii/amphyreg.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_AMTPHYREG_H_
+#define _DEV_MII_AMTPHYREG_H_
+
+/*
+ * AMD Am79C873 registers.
+ */
+
+
+#define MII_AMPHY_DSCR 0x10 /* Specified configuration register */a
+#define DSCR_BP4B5B 0x8000 /* Bypass 4B5B encoding */
+#define DSCR_BPSCR 0x4000 /* Bypass scrambler */
+#define DSCR_BPALIGN 0x2000 /* Bypass symbol alignment */
+#define DSCR_REPEATER 0x0800 /* Repeater mode */
+#define DSCR_TX 0x0400 /* TX/FX mode control */
+#define DSCR_UTP 0x0200 /* UTP/STP mode control */
+#define DSCR_CLK25MDIS 0x0100 /* CLK25M disable */
+#define DSCR_FGLNKTX 0x0080 /* Force good link at 100baseTX */
+#define DSCR_LINKLEDCTL 0x0020 /* Link LED control */
+#define DSCR_FDXLEDCTL 0x0010 /* FDX LED control */
+#define DSCR_SMRTS 0x0008 /* Reset state machine */
+#define DSCR_MFPSC 0x0004 /* Preamble surpression control */
+#define DSCR_SLEEP 0x0002 /* Sleep mode */
+#define DSCR_RLOUT 0x0001 /* Remote loopout control */
+
+#define MII_AMPHY_DSCSR 0x11 /* Specified configuration and status */
+#define DSCSR_100FDX 0x8000 /* 100MBps full duplex */
+#define DSCSR_100HDX 0x4000 /* 100Mbps half duplex */
+#define DSCSR_10FDX 0x2000 /* 10Mbps full duplex */
+#define DSCSR_10HDX 0x1000 /* 10Mbps half duplex */
+#define DSCSR_PADDR 0x01F0 /* PHY address */
+#define DSCSR_ASTAT 0x000F /* Autonegotiation status */
+
+#define ASTAT_COMPLETE 0x8
+#define ASTAT_PDLINK_READY_FAIL 0x7
+#define ASTAT_PDLINK_READY 0x6
+#define ASTAT_CONSTMATCH_FAIL 0x5
+#define ASTAT_CONSTMATCH 0x4
+#define ASTAT_ACKMATCH_FAIL 0x3
+#define ASTAT_ACKMATCH 0x2
+#define ASTAT_ABILITYMATCH 0x1
+#define ASTAT_IDLE 0x0
+
+#define MII_AMPHY_T10CSRSCR 0x12 /* 10baseT configuration/status */
+#define T10CSRSCR_LPEN 0x4000 /* Link pulse enable */
+#define T10CSRSCR_HBE 0x2000 /* Heartbeat enable */
+#define T10CSRSCR_JABEN 0x0800 /* Jabber enable */
+#define T10CSRSCR_SER 0x0400 /* Serial mode enable */
+#define T10CSRSCR_POLR 0x0001 /* Polarity reversed */
+
+#endif /* _DEV_MII_AMTPHYREG_H_ */
diff --git a/sys/dev/mii/bmtphy.c b/sys/dev/mii/bmtphy.c
new file mode 100644
index 0000000..df5bdc5
--- /dev/null
+++ b/sys/dev/mii/bmtphy.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp
+ *
+ */
+
+/*
+ * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs. This also
+ * drives the PHY on the 3Com 3c905C. The 3c905C's PHY is described in
+ * the 3c905C data sheet.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/bmtphyreg.h>
+
+#include "miibus_if.h"
+
+static int bmtphy_probe(device_t);
+static int bmtphy_attach(device_t);
+
+static device_method_t bmtphy_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, bmtphy_probe),
+ DEVMETHOD(device_attach, bmtphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ { 0, 0 }
+};
+
+static devclass_t bmtphy_devclass;
+
+static driver_t bmtphy_driver = {
+ "bmtphy",
+ bmtphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0);
+
+static int bmtphy_service(struct mii_softc *, struct mii_data *, int);
+static void bmtphy_status(struct mii_softc *);
+
+static int
+bmtphy_probe(device_t dev)
+{
+ struct mii_attach_args *ma;
+ int rval;
+
+ ma = device_get_ivars(dev);
+ rval = 0;
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM)
+ return (ENXIO);
+
+ switch (MII_MODEL(ma->mii_id2)) {
+ case MII_MODEL_BROADCOM_3C905B:
+ device_set_desc(dev, MII_STR_BROADCOM_3C905B);
+ rval = -10; /* Let exphy take precedence. */
+ break;
+ case MII_MODEL_BROADCOM_3C905C:
+ device_set_desc(dev, MII_STR_BROADCOM_3C905C);
+ rval = -10; /* Let exphy take precedence. */
+ break;
+ case MII_MODEL_BROADCOM_BCM5201:
+ device_set_desc(dev, MII_STR_BROADCOM_BCM5201);
+ break;
+ case MII_MODEL_BROADCOM_BCM5221:
+ device_set_desc(dev, MII_STR_BROADCOM_BCM5221);
+ break;
+ case MII_MODEL_BROADCOM_BCM4401:
+ device_set_desc(dev, MII_STR_BROADCOM_BCM4401);
+ break;
+ default:
+ return (ENXIO);
+ }
+
+ return (rval);
+}
+
+static int
+bmtphy_attach(device_t dev)
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = bmtphy_service;
+ sc->mii_pdata = mii;
+
+ mii_phy_reset(sc);
+
+ mii->mii_instance++;
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_phy_add_media(sc);
+
+ printf("\n");
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+
+ return (0);
+}
+
+static int
+bmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
+{
+ struct ifmedia_entry *ife;
+ int reg;
+
+ ife = mii->mii_media.ifm_cur;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ mii_phy_setmedia(sc);
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ if (mii_phy_tick(sc) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ bmtphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+
+ return (0);
+}
+
+static void
+bmtphy_status(struct mii_softc *sc)
+{
+ struct mii_data *mii;
+ struct ifmedia_entry *ife;
+ int bmsr, bmcr, aux_csr;
+
+ mii = sc->mii_pdata;
+ ife = mii->mii_media.ifm_cur;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
+ aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR);
+
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(sc, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BMCR_AUTOEN) {
+ /*
+ * The media status bits are only valid if autonegotiation
+ * has completed (or it's disabled).
+ */
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if (aux_csr & AUX_CSR_SPEED)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ if (aux_csr & AUX_CSR_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ } else
+ mii->mii_media_active = ife->ifm_media;
+}
diff --git a/sys/dev/mii/bmtphyreg.h b/sys/dev/mii/bmtphyreg.h
new file mode 100644
index 0000000..7f2956a
--- /dev/null
+++ b/sys/dev/mii/bmtphyreg.h
@@ -0,0 +1,182 @@
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * from NetBSD: bmtphyreg.h,v 1.1 2001/06/02 21:42:10 thorpej Exp
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_BMTPHYREG_H_
+#define _DEV_MII_BMTPHYREG_H_
+
+/*
+ * BCM5201/BCM5202 registers.
+ */
+
+#define MII_BMTPHY_AUX_CTL 0x10 /* auxiliary control */
+#define AUX_CTL_TXDIS 0x2000 /* transmitter disable */
+#define AUX_CTL_4B5B_BYPASS 0x0400 /* bypass 4b5b encoder */
+#define AUX_CTL_SCR_BYPASS 0x0200 /* bypass scrambler */
+#define AUX_CTL_NRZI_BYPASS 0x0100 /* bypass NRZI encoder */
+#define AUX_CTL_RXALIGN_BYPASS 0x0080 /* bypass rx symbol alignment */
+#define AUX_CTL_BASEWANDER_DIS 0x0040 /* disable baseline wander correction */
+#define AUX_CTL_FEF_EN 0x0020 /* far-end fault enable */
+
+
+#define MII_BMTPHY_AUX_STS 0x11 /* auxiliary status */
+#define AUX_STS_FX_MODE 0x0400 /* 100base-FX mode (strap pin) */
+#define AUX_STS_LOCKED 0x0200 /* descrambler locked */
+#define AUX_STS_100BASE_LINK 0x0100 /* 1 = 100base link */
+#define AUX_STS_REMFAULT 0x0080 /* remote fault */
+#define AUX_STS_DISCON_STATE 0x0040 /* disconnect state */
+#define AUX_STS_FCARDET 0x0020 /* false carrier detected */
+#define AUX_STS_BAD_ESD 0x0010 /* bad ESD detected */
+#define AUX_STS_RXERROR 0x0008 /* Rx error detected */
+#define AUX_STS_TXERROR 0x0004 /* Tx error detected */
+#define AUX_STS_LOCKERROR 0x0002 /* lock error detected */
+#define AUX_STS_MLT3ERROR 0x0001 /* MLT3 code error detected */
+
+
+#define MII_BMTPHY_RXERROR_CTR 0x12 /* 100base-X Rx error counter */
+#define RXERROR_CTR_MASK 0x00ff
+
+
+#define MII_BMTPHY_FCS_CTR 0x13 /* 100base-X false carrier counter */
+#define FCS_CTR_MASK 0x00ff
+
+
+#define MII_BMTPHY_DIS_CTR 0x14 /* 100base-X disconnect counter */
+#define DIS_CTR_MASK 0x00ff
+
+
+#define MII_BMTPHY_PTEST 0x17 /* PTEST */
+
+
+#define MII_BMTPHY_AUX_CSR 0x18 /* auxiliary control/status */
+#define AUX_CSR_JABBER_DIS 0x8000 /* jabber disable */
+#define AUX_CSR_FLINK 0x4000 /* force 10baseT link pass */
+#define AUX_CSR_HSQ 0x0080 /* SQ high */
+#define AUX_CSR_LSQ 0x0040 /* SQ low */
+#define AUX_CSR_ER1 0x0020 /* edge rate 1 */
+#define AUX_CSR_ER0 0x0010 /* edge rate 0 */
+#define AUX_CSR_ANEG 0x0008 /* auto-negotiation activated */
+#define AUX_CSR_F100 0x0004 /* force 100base */
+#define AUX_CSR_SPEED 0x0002 /* 1 = 100, 0 = 10 */
+#define AUX_CSR_FDX 0x0001 /* full-duplex */
+
+
+#define MII_BMTPHY_AUX_SS 0x19 /* auxiliary status summary */
+#define AUX_SS_ACOMP 0x8000 /* auto-negotiation complete */
+#define AUX_SS_ACOMP_ACK 0x4000 /* auto-negotiation compl. ack */
+#define AUX_SS_AACK_DET 0x2000 /* auto-neg. ack detected */
+#define AUX_SS_ANLPAD 0x1000 /* auto-neg. link part. ability det */
+#define AUX_SS_ANEG_PAUSE 0x0800 /* pause operation bit */
+#define AUX_SS_HCD 0x0700 /* highest common denominator */
+#define AUX_SS_HCD_NONE 0x0000 /* none */
+#define AUX_SS_HCD_10T 0x0100 /* 10baseT */
+#define AUX_SS_HCD_10T_FDX 0x0200 /* 10baseT-FDX */
+#define AUX_SS_HCD_100TX 0x0300 /* 100baseTX-FDX */
+#define AUX_SS_HCD_100T4 0x0400 /* 100baseT4 */
+#define AUX_SS_HCD_100TX_FDX 0x0500 /* 100baseTX-FDX */
+#define AUX_SS_PDF 0x0080 /* parallel detection fault */
+#define AUX_SS_LPRF 0x0040 /* link partner remote fault */
+#define AUX_SS_LPPR 0x0020 /* link partner page received */
+#define AUX_SS_LPANA 0x0010 /* link partner auto-neg able */
+#define AUX_SS_SPEED 0x0008 /* 1 = 100, 0 = 10 */
+#define AUX_SS_LINK 0x0004 /* link pass */
+#define AUX_SS_ANEN 0x0002 /* auto-neg. enabled */
+#define AUX_SS_JABBER 0x0001 /* jabber detected */
+
+
+#define MII_BMTPHY_INTR 0x1a /* interrupt register */
+#define INTR_FDX_LED 0x8000 /* full-duplex led enable */
+#define INTR_INTR_EN 0x4000 /* interrupt enable */
+#define INTR_FDX_MASK 0x0800 /* full-dupled intr mask */
+#define INTR_SPD_MASK 0x0400 /* speed intr mask */
+#define INTR_LINK_MASK 0x0200 /* link intr mask */
+#define INTR_INTR_MASK 0x0100 /* master interrupt mask */
+#define INTR_FDX_CHANGE 0x0008 /* full-duplex change */
+#define INTR_SPD_CHANGE 0x0004 /* speed change */
+#define INTR_LINK_CHANGE 0x0002 /* link change */
+#define INTR_INTR_STATUS 0x0001 /* interrupt status */
+
+
+#define MII_BMTPHY_AUX2 0x1b /* auliliary mode 2 */
+#define AUX2_BLOCK_RXDV 0x0200 /* block RXDV mode enabled */
+#define AUX2_ANPDQ 0x0100 /* auto-neg parallel detection Q mode */
+#define AUX2_TRAFFIC_LED 0x0040 /* traffic meter led enable */
+#define AUX2_FXMTRCV_LED 0x0020 /* force Tx and Rx LEDs */
+#define AUX2_HS_TOKEN 0x0010 /* high-speed token ring mode */
+#define AUX2_AUTO_LP 0x0008 /* auto low-power mode */
+#define AUX2_TWOLINK_LED 0x0004 /* two link LEDs */
+#define AUX2_SQE_DIS 0x0002 /* disable SQE pulse */
+
+
+#define MII_BMTPHY_AUXERR 0x1c /* auxiliary error */
+#define AUXERR_MANCHESTER 0x0400 /* Manchester code error */
+#define AUXERR_EOF 0x0200 /* EOF detection error */
+#define AUXERR_POLARITY 0x0100 /* polarity inversion */
+#define AUXERR_ANEG 0x0008 /* autonegotiation enabled */
+#define AUXERR_F100 0x0004 /* force 100base */
+#define AUXERR_SPEED 0x0002 /* 1 = 100, 0 = 10 */
+#define AUXERR_FDX 0x0001 /* full-duplex */
+
+
+#define MII_BMTPHY_AUXMODE 0x1d /* auxiliary mode */
+#define AUXMODE_ACT_LED_DIS 0x0010 /* activity LED disable */
+#define AUXMODE_LINK_LED_DIS 0x0008 /* link LED disable */
+#define AUXMODE_BLOCK_TXEN 0x0002 /* enable block TXEN */
+
+
+#define MII_BMTPHY_AUXMPHY 0x1e /* auxiliary multiple phy register */
+#define AUXMPHY_HCD_TX_FDX 0x8000 /* res. is 100baseTX-FDX */
+#define AUXMPHY_HCD_T4 0x4000 /* res. is 100baseT4 */
+#define AUXMPHY_HCD_TX 0x2000 /* res. is 100baseTX */
+#define AUXMPHY_HCD_10T_FDX 0x1000 /* res. is 10baseT-FDX */
+#define AUXMPHY_HCD_10T 0x0800 /* res. is 10baseT */
+#define AUXMPHY_RES_ANEG 0x0100 /* restart auto-negotiation */
+#define AUXMPHY_ANEG_COMP 0x0080 /* auto-negotiation complete */
+#define AUXMPHY_ACK_COMP 0x0040 /* acknowledge complete */
+#define AUXMPHY_ACK_DET 0x0020 /* acknowledge detected */
+#define AUXMPHY_ABILITY_DET 0x0010 /* waiting for LP ability */
+#define AUXMPHY_SUPER_ISO 0x0008 /* super-isolate mode */
+#define AUXMPHY_10T_SERIAL 0x0002 /* 10baseT serial mode */
+
+
+#define MII_BMTPHY_TEST 0x1d /* Broadcom test register */
+
+
+#endif /* _DEV_MII_BMTPHYREG_H_ */
diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c
new file mode 100644
index 0000000..6b4d38f
--- /dev/null
+++ b/sys/dev/mii/brgphy.c
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 2000
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Driver for the Broadcom BCR5400 1000baseTX PHY. Speed is always
+ * 1000mbps; all we need to negotiate here is full or half duplex.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+
+#include <machine/clock.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/brgphyreg.h>
+#include <net/if_arp.h>
+#include <machine/bus.h>
+#include <dev/bge/if_bgereg.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include "miibus_if.h"
+
+static int brgphy_probe(device_t);
+static int brgphy_attach(device_t);
+
+static device_method_t brgphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, brgphy_probe),
+ DEVMETHOD(device_attach, brgphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t brgphy_devclass;
+
+static driver_t brgphy_driver = {
+ "brgphy",
+ brgphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0);
+
+static int brgphy_service(struct mii_softc *, struct mii_data *, int);
+static void brgphy_status(struct mii_softc *);
+static int brgphy_mii_phy_auto(struct mii_softc *);
+static void brgphy_reset(struct mii_softc *);
+static void brgphy_loop(struct mii_softc *);
+static void bcm5401_load_dspcode(struct mii_softc *);
+static void bcm5411_load_dspcode(struct mii_softc *);
+static void bcm5703_load_dspcode(struct mii_softc *);
+static int brgphy_mii_model;
+
+static int
+brgphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5400) {
+ device_set_desc(dev, MII_STR_xxBROADCOM_BCM5400);
+ return(0);
+ }
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5401) {
+ device_set_desc(dev, MII_STR_xxBROADCOM_BCM5401);
+ return(0);
+ }
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5411) {
+ device_set_desc(dev, MII_STR_xxBROADCOM_BCM5411);
+ return(0);
+ }
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5701) {
+ device_set_desc(dev, MII_STR_xxBROADCOM_BCM5701);
+ return(0);
+ }
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5703) {
+ device_set_desc(dev, MII_STR_xxBROADCOM_BCM5703);
+ return(0);
+ }
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5704) {
+ device_set_desc(dev, MII_STR_xxBROADCOM_BCM5704);
+ return(0);
+ }
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5705) {
+ device_set_desc(dev, MII_STR_xxBROADCOM_BCM5705);
+ return(0);
+ }
+
+ return(ENXIO);
+}
+
+static int
+brgphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+ const char *sep = "";
+ struct bge_softc *bge_sc;
+ int fast_ether_only = FALSE;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = brgphy_service;
+ sc->mii_pdata = mii;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+#define PRINT(s) printf("%s%s", sep, s); sep = ", "
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+#if 0
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+#endif
+
+ brgphy_mii_model = MII_MODEL(ma->mii_id2);
+ brgphy_reset(sc);
+
+
+ sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ sc->mii_capabilities &= ~BMSR_ANEG;
+ device_printf(dev, " ");
+ mii_add_media(sc);
+
+ /* The 590x chips are 10/100 only. */
+
+ bge_sc = mii->mii_ifp->if_softc;
+
+ if (strcmp(mii->mii_ifp->if_dname, "bge") == 0 &&
+ pci_get_vendor(bge_sc->bge_dev) == BCOM_VENDORID &&
+ (pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901 ||
+ pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901A2))
+ fast_ether_only = TRUE;
+
+ if (fast_ether_only == FALSE) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
+ sc->mii_inst), BRGPHY_BMCR_FDX);
+ PRINT(", 1000baseTX");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
+ IFM_FDX, sc->mii_inst), 0);
+ PRINT("1000baseTX-FDX");
+ }
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
+ PRINT("auto");
+
+ printf("\n");
+#undef ADD
+#undef PRINT
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+brgphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg, speed, gig;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ brgphy_reset(sc); /* XXX hardware bug work-around */
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+#ifdef foo
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_AUTOEN)
+ return (0);
+#endif
+ (void) brgphy_mii_phy_auto(sc);
+ break;
+ case IFM_1000_T:
+ speed = BRGPHY_S1000;
+ goto setit;
+ case IFM_100_TX:
+ speed = BRGPHY_S100;
+ goto setit;
+ case IFM_10_T:
+ speed = BRGPHY_S10;
+setit:
+ brgphy_loop(sc);
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
+ speed |= BRGPHY_BMCR_FDX;
+ gig = BRGPHY_1000CTL_AFD;
+ } else {
+ gig = BRGPHY_1000CTL_AHD;
+ }
+
+ PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0);
+ PHY_WRITE(sc, BRGPHY_MII_BMCR, speed);
+ PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE);
+
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
+ break;
+
+ PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig);
+ PHY_WRITE(sc, BRGPHY_MII_BMCR,
+ speed|BRGPHY_BMCR_AUTOEN|BRGPHY_BMCR_STARTNEG);
+
+ if (brgphy_mii_model != MII_MODEL_xxBROADCOM_BCM5701)
+ break;
+
+ /*
+ * When settning the link manually, one side must
+ * be the master and the other the slave. However
+ * ifmedia doesn't give us a good way to specify
+ * this, so we fake it by using one of the LINK
+ * flags. If LINK0 is set, we program the PHY to
+ * be a master, otherwise it's a slave.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_LINK0)) {
+ PHY_WRITE(sc, BRGPHY_MII_1000CTL,
+ gig|BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC);
+ } else {
+ PHY_WRITE(sc, BRGPHY_MII_1000CTL,
+ gig|BRGPHY_1000CTL_MSE);
+ }
+ break;
+#ifdef foo
+ case IFM_NONE:
+ PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
+ break;
+#endif
+ case IFM_100_T4:
+ default:
+ return (EINVAL);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * Check to see if we have link. If we do, we don't
+ * need to restart the autonegotiation process. Read
+ * the BMSR twice in case it's latched.
+ */
+ reg = PHY_READ(sc, BRGPHY_MII_AUXSTS);
+ if (reg & BRGPHY_AUXSTS_LINK)
+ break;
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (0);
+
+ sc->mii_ticks = 0;
+ brgphy_mii_phy_auto(sc);
+ return (0);
+ }
+
+ /* Update the media status. */
+ brgphy_status(sc);
+
+ /*
+ * Callback if something changed. Note that we need to poke
+ * the DSP on the Broadcom PHYs if the media changes.
+ *
+ */
+ if (sc->mii_media_active != mii->mii_media_active ||
+ sc->mii_media_status != mii->mii_media_status ||
+ cmd == MII_MEDIACHG) {
+ mii_phy_update(sc, cmd);
+ switch (brgphy_mii_model) {
+ case MII_MODEL_xxBROADCOM_BCM5401:
+ bcm5401_load_dspcode(sc);
+ break;
+ case MII_MODEL_xxBROADCOM_BCM5411:
+ bcm5411_load_dspcode(sc);
+ break;
+ }
+ }
+ return (0);
+}
+
+static void
+brgphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int bmsr, bmcr;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, BRGPHY_MII_BMSR);
+ if (PHY_READ(sc, BRGPHY_MII_AUXSTS) & BRGPHY_AUXSTS_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(sc, BRGPHY_MII_BMCR);
+
+ if (bmcr & BRGPHY_BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BRGPHY_BMCR_AUTOEN) {
+ if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ switch (PHY_READ(sc, BRGPHY_MII_AUXSTS) &
+ BRGPHY_AUXSTS_AN_RES) {
+ case BRGPHY_RES_1000FD:
+ mii->mii_media_active |= IFM_1000_T | IFM_FDX;
+ break;
+ case BRGPHY_RES_1000HD:
+ mii->mii_media_active |= IFM_1000_T | IFM_HDX;
+ break;
+ case BRGPHY_RES_100FD:
+ mii->mii_media_active |= IFM_100_TX | IFM_FDX;
+ break;
+ case BRGPHY_RES_100T4:
+ mii->mii_media_active |= IFM_100_T4;
+ break;
+ case BRGPHY_RES_100HD:
+ mii->mii_media_active |= IFM_100_TX | IFM_HDX;
+ break;
+ case BRGPHY_RES_10FD:
+ mii->mii_media_active |= IFM_10_T | IFM_FDX;
+ break;
+ case BRGPHY_RES_10HD:
+ mii->mii_media_active |= IFM_10_T | IFM_HDX;
+ break;
+ default:
+ mii->mii_media_active |= IFM_NONE;
+ break;
+ }
+ return;
+ }
+
+ mii->mii_media_active = ife->ifm_media;
+
+ return;
+}
+
+
+static int
+brgphy_mii_phy_auto(mii)
+ struct mii_softc *mii;
+{
+ int ktcr = 0;
+
+ brgphy_loop(mii);
+ brgphy_reset(mii);
+ ktcr = BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD;
+ if (brgphy_mii_model == MII_MODEL_xxBROADCOM_BCM5701)
+ ktcr |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC;
+ PHY_WRITE(mii, BRGPHY_MII_1000CTL, ktcr);
+ ktcr = PHY_READ(mii, BRGPHY_MII_1000CTL);
+ DELAY(1000);
+ PHY_WRITE(mii, BRGPHY_MII_ANAR,
+ BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
+ DELAY(1000);
+ PHY_WRITE(mii, BRGPHY_MII_BMCR,
+ BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG);
+ PHY_WRITE(mii, BRGPHY_MII_IMR, 0xFF00);
+ return (EJUSTRETURN);
+}
+
+static void
+brgphy_loop(struct mii_softc *sc)
+{
+ u_int32_t bmsr;
+ int i;
+
+ PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP);
+ for (i = 0; i < 15000; i++) {
+ bmsr = PHY_READ(sc, BRGPHY_MII_BMSR);
+ if (!(bmsr & BRGPHY_BMSR_LINK)) {
+#if 0
+ device_printf(sc->mii_dev, "looped %d\n", i);
+#endif
+ break;
+ }
+ DELAY(10);
+ }
+}
+
+/* Turn off tap power management on 5401. */
+static void
+bcm5401_load_dspcode(struct mii_softc *sc)
+{
+ static const struct {
+ int reg;
+ uint16_t val;
+ } dspcode[] = {
+ { BRGPHY_MII_AUXCTL, 0x0c20 },
+ { BRGPHY_MII_DSP_ADDR_REG, 0x0012 },
+ { BRGPHY_MII_DSP_RW_PORT, 0x1804 },
+ { BRGPHY_MII_DSP_ADDR_REG, 0x0013 },
+ { BRGPHY_MII_DSP_RW_PORT, 0x1204 },
+ { BRGPHY_MII_DSP_ADDR_REG, 0x8006 },
+ { BRGPHY_MII_DSP_RW_PORT, 0x0132 },
+ { BRGPHY_MII_DSP_ADDR_REG, 0x8006 },
+ { BRGPHY_MII_DSP_RW_PORT, 0x0232 },
+ { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
+ { BRGPHY_MII_DSP_RW_PORT, 0x0a20 },
+ { 0, 0 },
+ };
+ int i;
+
+ for (i = 0; dspcode[i].reg != 0; i++)
+ PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
+ DELAY(40);
+}
+
+static void
+bcm5411_load_dspcode(struct mii_softc *sc)
+{
+ static const struct {
+ int reg;
+ uint16_t val;
+ } dspcode[] = {
+ { 0x1c, 0x8c23 },
+ { 0x1c, 0x8ca3 },
+ { 0x1c, 0x8c23 },
+ { 0, 0 },
+ };
+ int i;
+
+ for (i = 0; dspcode[i].reg != 0; i++)
+ PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
+}
+
+static void
+bcm5703_load_dspcode(struct mii_softc *sc)
+{
+ static const struct {
+ int reg;
+ uint16_t val;
+ } dspcode[] = {
+ { BRGPHY_MII_AUXCTL, 0x0c00 },
+ { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
+ { BRGPHY_MII_DSP_RW_PORT, 0x2aaa },
+ { 0, 0 },
+ };
+ int i;
+
+ for (i = 0; dspcode[i].reg != 0; i++)
+ PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
+}
+
+static void
+bcm5704_load_dspcode(struct mii_softc *sc)
+{
+ static const struct {
+ int reg;
+ u_int16_t val;
+ } dspcode[] = {
+ { 0x1c, 0x8d68 },
+ { 0x1c, 0x8d68 },
+ { 0, 0 },
+ };
+ int i;
+
+ for (i = 0; dspcode[i].reg != 0; i++)
+ PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
+}
+
+static void
+brgphy_reset(struct mii_softc *sc)
+{
+ u_int32_t val;
+ struct ifnet *ifp;
+ struct bge_softc *bge_sc;
+
+ mii_phy_reset(sc);
+
+ switch (brgphy_mii_model) {
+ case MII_MODEL_xxBROADCOM_BCM5401:
+ bcm5401_load_dspcode(sc);
+ break;
+ case MII_MODEL_xxBROADCOM_BCM5411:
+ bcm5411_load_dspcode(sc);
+ break;
+ case MII_MODEL_xxBROADCOM_BCM5703:
+ bcm5703_load_dspcode(sc);
+ break;
+ case MII_MODEL_xxBROADCOM_BCM5704:
+ bcm5704_load_dspcode(sc);
+ break;
+ }
+
+ ifp = sc->mii_pdata->mii_ifp;
+ bge_sc = ifp->if_softc;
+
+ /*
+ * Don't enable Ethernet@WireSpeed for the 5700 or the
+ * 5705 A1 and A2 chips. Make sure we only do this test
+ * on "bge" NICs, since other drivers may use this same
+ * PHY subdriver.
+ */
+ if (strcmp(ifp->if_dname, "bge") == 0 &&
+ (bge_sc->bge_asicrev == BGE_ASICREV_BCM5700 ||
+ bge_sc->bge_chipid == BGE_CHIPID_BCM5705_A1 ||
+ bge_sc->bge_chipid == BGE_CHIPID_BCM5705_A2))
+ return;
+
+ /* Enable Ethernet@WireSpeed. */
+ PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007);
+ val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
+ PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4));
+
+ /* Enable Link LED on Dell boxes */
+ if (bge_sc->bge_no_3_led) {
+ PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
+ PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL)
+ & ~BRGPHY_PHY_EXTCTL_3_LED);
+ }
+}
diff --git a/sys/dev/mii/brgphyreg.h b/sys/dev/mii/brgphyreg.h
new file mode 100644
index 0000000..786f49d
--- /dev/null
+++ b/sys/dev/mii/brgphyreg.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2000
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_BRGPHYREG_H_
+#define _DEV_MII_BRGPHYREG_H_
+
+/*
+ * Broadcom BCM5400 registers
+ */
+
+#define BRGPHY_MII_BMCR 0x00
+#define BRGPHY_BMCR_RESET 0x8000
+#define BRGPHY_BMCR_LOOP 0x4000
+#define BRGPHY_BMCR_SPD0 0x2000 /* speed select, lower bit */
+#define BRGPHY_BMCR_AUTOEN 0x1000 /* Autoneg enabled */
+#define BRGPHY_BMCR_PDOWN 0x0800 /* Power down */
+#define BRGPHY_BMCR_ISO 0x0400 /* Isolate */
+#define BRGPHY_BMCR_STARTNEG 0x0200 /* Restart autoneg */
+#define BRGPHY_BMCR_FDX 0x0100 /* Duplex mode */
+#define BRGPHY_BMCR_CTEST 0x0080 /* Collision test enable */
+#define BRGPHY_BMCR_SPD1 0x0040 /* Speed select, upper bit */
+
+#define BRGPHY_S1000 BRGPHY_BMCR_SPD1 /* 1000mbps */
+#define BRGPHY_S100 BRGPHY_BMCR_SPD0 /* 100mpbs */
+#define BRGPHY_S10 0 /* 10mbps */
+
+#define BRGPHY_MII_BMSR 0x01
+#define BRGPHY_BMSR_EXTSTS 0x0100 /* Extended status present */
+#define BRGPHY_BMSR_PRESUB 0x0040 /* Preamble surpression */
+#define BRGPHY_BMSR_ACOMP 0x0020 /* Autoneg complete */
+#define BRGPHY_BMSR_RFAULT 0x0010 /* Remote fault condition occured */
+#define BRGPHY_BMSR_ANEG 0x0008 /* Autoneg capable */
+#define BRGPHY_BMSR_LINK 0x0004 /* Link status */
+#define BRGPHY_BMSR_JABBER 0x0002 /* Jabber detected */
+#define BRGPHY_BMSR_EXT 0x0001 /* Extended capability */
+
+#define BRGPHY_MII_ANAR 0x04
+#define BRGPHY_ANAR_NP 0x8000 /* Next page */
+#define BRGPHY_ANAR_RF 0x2000 /* Remote fault */
+#define BRGPHY_ANAR_ASP 0x0800 /* Asymmetric Pause */
+#define BRGPHY_ANAR_PC 0x0400 /* Pause capable */
+#define BRGPHY_ANAR_SEL 0x001F /* selector field, 00001=Ethernet */
+
+#define BRGPHY_MII_ANLPAR 0x05
+#define BRGPHY_ANLPAR_NP 0x8000 /* Next page */
+#define BRGPHY_ANLPAR_RF 0x2000 /* Remote fault */
+#define BRGPHY_ANLPAR_ASP 0x0800 /* Asymmetric Pause */
+#define BRGPHY_ANLPAR_PC 0x0400 /* Pause capable */
+#define BRGPHY_ANLPAR_SEL 0x001F /* selector field, 00001=Ethernet */
+
+#define BRGPHY_SEL_TYPE 0x0001 /* ethernet */
+
+#define BRGPHY_MII_ANER 0x06
+#define BRGPHY_ANER_PDF 0x0010 /* Parallel detection fault */
+#define BRGPHY_ANER_LPNP 0x0008 /* Link partner can next page */
+#define BRGPHY_ANER_NP 0x0004 /* Local PHY can next page */
+#define BRGPHY_ANER_RX 0x0002 /* Next page received */
+#define BRGPHY_ANER_LPAN 0x0001 /* Link partner autoneg capable */
+
+#define BRGPHY_MII_NEXTP 0x07 /* Next page */
+
+#define BRGPHY_MII_NEXTP_LP 0x08 /* Next page of link partner */
+
+#define BRGPHY_MII_1000CTL 0x09 /* 1000baseT control */
+#define BRGPHY_1000CTL_TST 0xE000 /* test modes */
+#define BRGPHY_1000CTL_MSE 0x1000 /* Master/Slave enable */
+#define BRGPHY_1000CTL_MSC 0x0800 /* Master/Slave configuration */
+#define BRGPHY_1000CTL_RD 0x0400 /* Repeater/DTE */
+#define BRGPHY_1000CTL_AFD 0x0200 /* Advertise full duplex */
+#define BRGPHY_1000CTL_AHD 0x0100 /* Advertise half duplex */
+
+#define BRGPHY_MII_1000STS 0x0A /* 1000baseT status */
+#define BRGPHY_1000STS_MSF 0x8000 /* Master/slave fault */
+#define BRGPHY_1000STS_MSR 0x4000 /* Master/slave result */
+#define BRGPHY_1000STS_LRS 0x2000 /* Local receiver status */
+#define BRGPHY_1000STS_RRS 0x1000 /* Remote receiver status */
+#define BRGPHY_1000STS_LPFD 0x0800 /* Link partner can FD */
+#define BRGPHY_1000STS_LPHD 0x0400 /* Link partner can HD */
+#define BRGPHY_1000STS_IEC 0x00FF /* Idle error count */
+
+#define BRGPHY_MII_EXTSTS 0x0F /* Extended status */
+#define BRGPHY_EXTSTS_X_FD_CAP 0x8000 /* 1000base-X FD capable */
+#define BRGPHY_EXTSTS_X_HD_CAP 0x4000 /* 1000base-X HD capable */
+#define BRGPHY_EXTSTS_T_FD_CAP 0x2000 /* 1000base-T FD capable */
+#define BRGPHY_EXTSTS_T_HD_CAP 0x1000 /* 1000base-T HD capable */
+
+#define BRGPHY_MII_PHY_EXTCTL 0x10 /* PHY extended control */
+#define BRGPHY_PHY_EXTCTL_MAC_PHY 0x8000 /* 10BIT/GMI-interface */
+#define BRGPHY_PHY_EXTCTL_DIS_CROSS 0x4000 /* Disable MDI crossover */
+#define BRGPHY_PHY_EXTCTL_TX_DIS 0x2000 /* Tx output disable d*/
+#define BRGPHY_PHY_EXTCTL_INT_DIS 0x1000 /* Interrupts disabled */
+#define BRGPHY_PHY_EXTCTL_F_INT 0x0800 /* Force interrupt */
+#define BRGPHY_PHY_EXTCTL_BY_45 0x0400 /* Bypass 4B5B-Decoder */
+#define BRGPHY_PHY_EXTCTL_BY_SCR 0x0200 /* Bypass scrambler */
+#define BRGPHY_PHY_EXTCTL_BY_MLT3 0x0100 /* Bypass MLT3 encoder */
+#define BRGPHY_PHY_EXTCTL_BY_RXA 0x0080 /* Bypass RX alignment */
+#define BRGPHY_PHY_EXTCTL_RES_SCR 0x0040 /* Reset scrambler */
+#define BRGPHY_PHY_EXTCTL_EN_LTR 0x0020 /* Enable LED traffic mode */
+#define BRGPHY_PHY_EXTCTL_LED_ON 0x0010 /* Force LEDs on */
+#define BRGPHY_PHY_EXTCTL_LED_OFF 0x0008 /* Force LEDs off */
+#define BRGPHY_PHY_EXTCTL_EX_IPG 0x0004 /* Extended TX IPG mode */
+#define BRGPHY_PHY_EXTCTL_3_LED 0x0002 /* Three link LED mode */
+#define BRGPHY_PHY_EXTCTL_HIGH_LA 0x0001 /* GMII Fifo Elasticy (?) */
+
+#define BRGPHY_MII_PHY_EXTSTS 0x11 /* PHY extended status */
+#define BRGPHY_PHY_EXTSTS_CROSS_STAT 0x2000 /* MDI crossover status */
+#define BRGPHY_PHY_EXTSTS_INT_STAT 0x1000 /* Interrupt status */
+#define BRGPHY_PHY_EXTSTS_RRS 0x0800 /* Remote receiver status */
+#define BRGPHY_PHY_EXTSTS_LRS 0x0400 /* Local receiver status */
+#define BRGPHY_PHY_EXTSTS_LOCKED 0x0200 /* Locked */
+#define BRGPHY_PHY_EXTSTS_LS 0x0100 /* Link status */
+#define BRGPHY_PHY_EXTSTS_RF 0x0080 /* Remove fault */
+#define BRGPHY_PHY_EXTSTS_CE_ER 0x0040 /* Carrier ext error */
+#define BRGPHY_PHY_EXTSTS_BAD_SSD 0x0020 /* Bad SSD */
+#define BRGPHY_PHY_EXTSTS_BAD_ESD 0x0010 /* Bad ESS */
+#define BRGPHY_PHY_EXTSTS_RX_ER 0x0008 /* RX error */
+#define BRGPHY_PHY_EXTSTS_TX_ER 0x0004 /* TX error */
+#define BRGPHY_PHY_EXTSTS_LOCK_ER 0x0002 /* Lock error */
+#define BRGPHY_PHY_EXTSTS_MLT3_ER 0x0001 /* MLT3 code error */
+
+#define BRGPHY_MII_RXERRCNT 0x12 /* RX error counter */
+
+#define BRGPHY_MII_FCERRCNT 0x13 /* false carrier sense counter */
+#define BGRPHY_FCERRCNT 0x00FF /* False carrier counter */
+
+#define BRGPHY_MII_RXNOCNT 0x14 /* RX not OK counter */
+#define BRGPHY_RXNOCNT_LOCAL 0xFF00 /* Local RX not OK counter */
+#define BRGPHY_RXNOCNT_REMOTE 0x00FF /* Local RX not OK counter */
+
+#define BRGPHY_MII_DSP_RW_PORT 0x15 /* DSP coefficient r/w port */
+
+#define BRGPHY_MII_DSP_ADDR_REG 0x17 /* DSP coefficient addr register */
+
+#define BRGPHY_DSP_TAP_NUMBER_MASK 0x00
+#define BRGPHY_DSP_AGC_A 0x00
+#define BRGPHY_DSP_AGC_B 0x01
+#define BRGPHY_DSP_MSE_PAIR_STATUS 0x02
+#define BRGPHY_DSP_SOFT_DECISION 0x03
+#define BRGPHY_DSP_PHASE_REG 0x04
+#define BRGPHY_DSP_SKEW 0x05
+#define BRGPHY_DSP_POWER_SAVER_UPPER_BOUND 0x06
+#define BRGPHY_DSP_POWER_SAVER_LOWER_BOUND 0x07
+#define BRGPHY_DSP_LAST_ECHO 0x08
+#define BRGPHY_DSP_FREQUENCY 0x09
+#define BRGPHY_DSP_PLL_BANDWIDTH 0x0A
+#define BRGPHY_DSP_PLL_PHASE_OFFSET 0x0B
+
+#define BRGPHYDSP_FILTER_DCOFFSET 0x0C00
+#define BRGPHY_DSP_FILTER_FEXT3 0x0B00
+#define BRGPHY_DSP_FILTER_FEXT2 0x0A00
+#define BRGPHY_DSP_FILTER_FEXT1 0x0900
+#define BRGPHY_DSP_FILTER_FEXT0 0x0800
+#define BRGPHY_DSP_FILTER_NEXT3 0x0700
+#define BRGPHY_DSP_FILTER_NEXT2 0x0600
+#define BRGPHY_DSP_FILTER_NEXT1 0x0500
+#define BRGPHY_DSP_FILTER_NEXT0 0x0400
+#define BRGPHY_DSP_FILTER_ECHO 0x0300
+#define BRGPHY_DSP_FILTER_DFE 0x0200
+#define BRGPHY_DSP_FILTER_FFE 0x0100
+
+#define BRGPHY_DSP_CONTROL_ALL_FILTERS 0x1000
+
+#define BRGPHY_DSP_SEL_CH_0 0x0000
+#define BRGPHY_DSP_SEL_CH_1 0x2000
+#define BRGPHY_DSP_SEL_CH_2 0x4000
+#define BRGPHY_DSP_SEL_CH_3 0x6000
+
+#define BRGPHY_MII_AUXCTL 0x18 /* AUX control */
+#define BRGPHY_AUXCTL_LOW_SQ 0x8000 /* Low squelch */
+#define BRGPHY_AUXCTL_LONG_PKT 0x4000 /* RX long packets */
+#define BRGPHY_AUXCTL_ER_CTL 0x3000 /* Edgerate control */
+#define BRGPHY_AUXCTL_TX_TST 0x0400 /* TX test, always 1 */
+#define BRGPHY_AUXCTL_DIS_PRF 0x0080 /* dis part resp filter */
+#define BRGPHY_AUXCTL_DIAG_MODE 0x0004 /* Diagnostic mode */
+
+#define BRGPHY_MII_AUXSTS 0x19 /* AUX status */
+#define BRGPHY_AUXSTS_ACOMP 0x8000 /* autoneg complete */
+#define BRGPHY_AUXSTS_AN_ACK 0x4000 /* autoneg complete ack */
+#define BRGPHY_AUXSTS_AN_ACK_D 0x2000 /* autoneg complete ack detect */
+#define BRGPHY_AUXSTS_AN_NPW 0x1000 /* autoneg next page wait */
+#define BRGPHY_AUXSTS_AN_RES 0x0700 /* AN HDC */
+#define BRGPHY_AUXSTS_PDF 0x0080 /* Parallel detect. fault */
+#define BRGPHY_AUXSTS_RF 0x0040 /* remote fault */
+#define BRGPHY_AUXSTS_ANP_R 0x0020 /* AN page received */
+#define BRGPHY_AUXSTS_LP_ANAB 0x0010 /* LP AN ability */
+#define BRGPHY_AUXSTS_LP_NPAB 0x0008 /* LP Next page ability */
+#define BRGPHY_AUXSTS_LINK 0x0004 /* Link status */
+#define BRGPHY_AUXSTS_PRR 0x0002 /* Pause resolution-RX */
+#define BRGPHY_AUXSTS_PRT 0x0001 /* Pause resolution-TX */
+
+#define BRGPHY_RES_1000FD 0x0700 /* 1000baseT full duplex */
+#define BRGPHY_RES_1000HD 0x0600 /* 1000baseT half duplex */
+#define BRGPHY_RES_100FD 0x0500 /* 100baseT full duplex */
+#define BRGPHY_RES_100T4 0x0400 /* 100baseT4 */
+#define BRGPHY_RES_100HD 0x0300 /* 100baseT half duplex */
+#define BRGPHY_RES_10FD 0x0200 /* 10baseT full duplex */
+#define BRGPHY_RES_10HD 0x0100 /* 10baseT half duplex */
+
+#define BRGPHY_MII_ISR 0x1A /* interrupt status */
+#define BRGPHY_ISR_PSERR 0x4000 /* Pair swap error */
+#define BRGPHY_ISR_MDXI_SC 0x2000 /* MDIX Status Change */
+#define BRGPHY_ISR_HCT 0x1000 /* counter above 32K */
+#define BRGPHY_ISR_LCT 0x0800 /* all counter below 128 */
+#define BRGPHY_ISR_AN_PR 0x0400 /* Autoneg page received */
+#define BRGPHY_ISR_NO_HDCL 0x0200 /* No HCD Link */
+#define BRGPHY_ISR_NO_HDC 0x0100 /* No HCD */
+#define BRGPHY_ISR_USHDC 0x0080 /* Negotiated Unsupported HCD */
+#define BRGPHY_ISR_SCR_S_ERR 0x0040 /* Scrambler sync error */
+#define BRGPHY_ISR_RRS_CHG 0x0020 /* Remote RX status change */
+#define BRGPHY_ISR_LRS_CHG 0x0010 /* Local RX status change */
+#define BRGPHY_ISR_DUP_CHG 0x0008 /* Duplex mode change */
+#define BRGPHY_ISR_LSP_CHG 0x0004 /* Link speed changed */
+#define BRGPHY_ISR_LNK_CHG 0x0002 /* Link status change */
+#define BRGPHY_ISR_CRCERR 0x0001 /* CEC error */
+
+#define BRGPHY_MII_IMR 0x1B /* interrupt mask */
+#define BRGPHY_IMR_PSERR 0x4000 /* Pair swap error */
+#define BRGPHY_IMR_MDXI_SC 0x2000 /* MDIX Status Change */
+#define BRGPHY_IMR_HCT 0x1000 /* counter above 32K */
+#define BRGPHY_IMR_LCT 0x0800 /* all counter below 128 */
+#define BRGPHY_IMR_AN_PR 0x0400 /* Autoneg page received */
+#define BRGPHY_IMR_NO_HDCL 0x0200 /* No HCD Link */
+#define BRGPHY_IMR_NO_HDC 0x0100 /* No HCD */
+#define BRGPHY_IMR_USHDC 0x0080 /* Negotiated Unsupported HCD */
+#define BRGPHY_IMR_SCR_S_ERR 0x0040 /* Scrambler sync error */
+#define BRGPHY_IMR_RRS_CHG 0x0020 /* Remote RX status change */
+#define BRGPHY_IMR_LRS_CHG 0x0010 /* Local RX status change */
+#define BRGPHY_IMR_DUP_CHG 0x0008 /* Duplex mode change */
+#define BRGPHY_IMR_LSP_CHG 0x0004 /* Link speed changed */
+#define BRGPHY_IMR_LNK_CHG 0x0002 /* Link status change */
+#define BRGPHY_IMR_CRCERR 0x0001 /* CEC error */
+
+#define BRGPHY_INTRS \
+ ~(BRGPHY_IMR_LNK_CHG|BRGPHY_IMR_LSP_CHG|BRGPHY_IMR_DUP_CHG)
+
+#endif /* _DEV_BRGPHY_MIIREG_H_ */
diff --git a/sys/dev/mii/dcphy.c b/sys/dev/mii/dcphy.c
new file mode 100644
index 0000000..4c930e5
--- /dev/null
+++ b/sys/dev/mii/dcphy.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Pseudo-driver for internal NWAY support on DEC 21143 and workalike
+ * controllers. Technically we're abusing the miibus code to handle
+ * media selection and NWAY support here since there is no MII
+ * interface. However the logical operations are roughly the same,
+ * and the alternative is to create a fake MII interface in the driver,
+ * which is harder to do.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <pci/if_dcreg.h>
+
+#include "miibus_if.h"
+
+#define DC_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) | x)
+
+#define DC_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) & ~x)
+
+#define MIIF_AUTOTIMEOUT 0x0004
+
+/*
+ * This is the subsystem ID for the built-in 21143 ethernet
+ * in several Compaq Presario systems. Apparently these are
+ * 10Mbps only, so we need to treat them specially.
+ */
+#define COMPAQ_PRESARIO_ID 0xb0bb0e11
+
+static int dcphy_probe(device_t);
+static int dcphy_attach(device_t);
+
+static device_method_t dcphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, dcphy_probe),
+ DEVMETHOD(device_attach, dcphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t dcphy_devclass;
+
+static driver_t dcphy_driver = {
+ "dcphy",
+ dcphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0);
+
+static int dcphy_service(struct mii_softc *, struct mii_data *, int);
+static void dcphy_status(struct mii_softc *);
+static void dcphy_reset(struct mii_softc *);
+static int dcphy_auto(struct mii_softc *);
+
+static int
+dcphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ /*
+ * The dc driver will report the 21143 vendor and device
+ * ID to let us know that it wants us to attach.
+ */
+ if (ma->mii_id1 != DC_VENDORID_DEC ||
+ ma->mii_id2 != DC_DEVICEID_21143)
+ return(ENXIO);
+
+ device_set_desc(dev, "Intel 21143 NWAY media interface");
+
+ return (0);
+}
+
+static int
+dcphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+ struct dc_softc *dc_sc;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = dcphy_service;
+ sc->mii_pdata = mii;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+
+ /*dcphy_reset(sc);*/
+ dc_sc = mii->mii_ifp->if_softc;
+ CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0);
+ CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0);
+
+ switch(pci_read_config(device_get_parent(sc->mii_dev),
+ DC_PCI_CSID, 4)) {
+ case COMPAQ_PRESARIO_ID:
+ /* Example of how to only allow 10Mbps modes. */
+ sc->mii_capabilities = BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
+ break;
+ default:
+ if (dc_sc->dc_pmode == DC_PMODE_SIA) {
+ sc->mii_capabilities =
+ BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
+ } else {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP,
+ sc->mii_inst), BMCR_LOOP|BMCR_S100);
+
+ sc->mii_capabilities =
+ BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX|
+ BMSR_10TFDX|BMSR_10THDX;
+ }
+ break;
+ }
+
+ sc->mii_capabilities &= ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_add_media(sc);
+ printf("\n");
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+dcphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct dc_softc *dc_sc;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+ u_int32_t mode;
+
+ dc_sc = mii->mii_ifp->if_softc;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ return (0);
+ }
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ sc->mii_flags = 0;
+ mii->mii_media_active = IFM_NONE;
+ mode = CSR_READ_4(dc_sc, DC_NETCFG);
+ mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL|
+ DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL);
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*dcphy_reset(sc);*/
+ (void) dcphy_auto(sc);
+ break;
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ case IFM_100_TX:
+ dcphy_reset(sc);
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS|
+ DC_NETCFG_SCRAMBLER;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mode |= DC_NETCFG_FULLDUPLEX;
+ else
+ mode &= ~DC_NETCFG_FULLDUPLEX;
+ CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
+ break;
+ case IFM_10_T:
+ DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF);
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D);
+ else
+ DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F);
+ DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ mode &= ~DC_NETCFG_PORTSEL;
+ mode |= DC_NETCFG_SPEEDSEL;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mode |= DC_NETCFG_FULLDUPLEX;
+ else
+ mode &= ~DC_NETCFG_FULLDUPLEX;
+ CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
+ break;
+ default:
+ return(EINVAL);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
+ if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
+ break;
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ *
+ * Otherwise, fall through to calling dcphy_status()
+ * since real Intel 21143 chips don't show valid link
+ * status until autonegotiation is switched off, and
+ * that only happens in dcphy_status(). Without this,
+ * successful autonegotation is never recognised on
+ * these chips.
+ */
+ if (++sc->mii_ticks != 50)
+ break;
+
+ sc->mii_ticks = 0;
+ dcphy_auto(sc);
+
+ break;
+ }
+
+ /* Update the media status. */
+ dcphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+dcphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int reg, anlpar, tstat = 0;
+ struct dc_softc *dc_sc;
+
+ dc_sc = mii->mii_ifp->if_softc;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return;
+
+ reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
+ if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) {
+ /* Erg, still trying, I guess... */
+ tstat = CSR_READ_4(dc_sc, DC_10BTSTAT);
+ if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) {
+ if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) &&
+ (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE)
+ goto skip;
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if (tstat & DC_TSTAT_LP_CAN_NWAY) {
+ anlpar = tstat >> 16;
+ if (anlpar & ANLPAR_T4 &&
+ sc->mii_capabilities & BMSR_100TXHDX)
+ mii->mii_media_active |= IFM_100_T4;
+ else if (anlpar & ANLPAR_TX_FD &&
+ sc->mii_capabilities & BMSR_100TXFDX)
+ mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+ else if (anlpar & ANLPAR_TX &&
+ sc->mii_capabilities & BMSR_100TXHDX)
+ mii->mii_media_active |= IFM_100_TX;
+ else if (anlpar & ANLPAR_10_FD)
+ mii->mii_media_active |= IFM_10_T|IFM_FDX;
+ else if (anlpar & ANLPAR_10)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ if (DC_IS_INTEL(dc_sc))
+ DC_CLRBIT(dc_sc, DC_10BTCTRL,
+ DC_TCTL_AUTONEGENBL);
+ return;
+ }
+ /*
+ * If the other side doesn't support NWAY, then the
+ * best we can do is determine if we have a 10Mbps or
+ * 100Mbps link. There's no way to know if the link
+ * is full or half duplex, so we default to half duplex
+ * and hope that the user is clever enough to manually
+ * change the media settings if we're wrong.
+ */
+ if (!(reg & DC_TSTAT_LS100))
+ mii->mii_media_active |= IFM_100_TX;
+ else if (!(reg & DC_TSTAT_LS10))
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ if (DC_IS_INTEL(dc_sc))
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ return;
+ }
+
+skip:
+
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_100_TX;
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+
+ return;
+}
+
+static int
+dcphy_auto(mii)
+ struct mii_softc *mii;
+{
+ struct dc_softc *sc;
+
+ sc = mii->mii_pdata->mii_ifp->if_softc;
+
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
+ DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ if (mii->mii_capabilities & BMSR_100TXHDX)
+ CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF);
+ else
+ CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF);
+ DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE);
+
+ return(EJUSTRETURN);
+}
+
+static void
+dcphy_reset(mii)
+ struct mii_softc *mii;
+{
+ struct dc_softc *sc;
+
+ sc = mii->mii_pdata->mii_ifp->if_softc;
+
+ DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ DELAY(1000);
+ DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
+
+ return;
+}
+
diff --git a/sys/dev/mii/e1000phy.c b/sys/dev/mii/e1000phy.c
new file mode 100644
index 0000000..6f9f458
--- /dev/null
+++ b/sys/dev/mii/e1000phy.c
@@ -0,0 +1,428 @@
+/*
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+ * Principal Author: Parag Patel
+ * Copyright (c) 2001
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Additonal Copyright (c) 2001 by Traakan Software under same licence.
+ * Secondary Author: Matthew Jacob
+ */
+
+/*
+ * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY.
+ */
+
+/*
+ * Support added for the Marvell 88E1011 (Alaska) 1000/100/10baseTX and
+ * 1000baseSX PHY.
+ * Nathan Binkert <nate@openbsd.org>
+ * Jung-uk Kim <jkim@niksun.com>
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+
+#include <machine/clock.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/e1000phyreg.h>
+
+#include "miibus_if.h"
+
+static int e1000phy_probe(device_t);
+static int e1000phy_attach(device_t);
+
+static device_method_t e1000phy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, e1000phy_probe),
+ DEVMETHOD(device_attach, e1000phy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t e1000phy_devclass;
+static driver_t e1000phy_driver = {
+ "e1000phy", e1000phy_methods, sizeof (struct mii_softc)
+};
+DRIVER_MODULE(e1000phy, miibus, e1000phy_driver, e1000phy_devclass, 0, 0);
+
+static int e1000phy_service(struct mii_softc *, struct mii_data *, int);
+static void e1000phy_status(struct mii_softc *);
+static void e1000phy_reset(struct mii_softc *);
+static int e1000phy_mii_phy_auto(struct mii_softc *);
+
+static int e1000phy_debug = 0;
+
+static int
+e1000phy_probe(device_t dev)
+{
+ struct mii_attach_args *ma;
+ u_int32_t id;
+
+ ma = device_get_ivars(dev);
+ id = ((ma->mii_id1 << 16) | ma->mii_id2) & E1000_ID_MASK;
+ if (id != E1000_ID_88E1000
+ && id != E1000_ID_88E1000S
+ && id != E1000_ID_88E1011) {
+ return ENXIO;
+ }
+
+ device_set_desc(dev, MII_STR_MARVELL_E1000);
+ return 0;
+}
+
+static int
+e1000phy_attach(device_t dev)
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+ u_int32_t id;
+
+ getenv_int("e1000phy_debug", &e1000phy_debug);
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = e1000phy_service;
+ sc->mii_pdata = mii;
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+ id = ((ma->mii_id1 << 16) | ma->mii_id2) & E1000_ID_MASK;
+ if (id == E1000_ID_88E1011
+ && (PHY_READ(sc, E1000_ESSR) & E1000_ESSR_FIBER_LINK))
+ sc->mii_flags |= MIIF_HAVEFIBER;
+ mii->mii_instance++;
+ e1000phy_reset(sc);
+
+ device_printf(dev, " ");
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+ if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
+#if 0
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ E1000_CR_ISOLATE);
+#endif
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
+ E1000_CR_SPEED_10);
+ printf("10baseT, ");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
+ E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX);
+ printf("10baseT-FDX, ");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
+ E1000_CR_SPEED_100);
+ printf("100baseTX, ");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
+ E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX);
+ printf("100baseTX-FDX, ");
+ /*
+ * 1000BT-simplex not supported; driver must ignore this entry,
+ * but it must be present in order to manually set full-duplex.
+ */
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst),
+ E1000_CR_SPEED_1000);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst),
+ E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX);
+ printf("1000baseTX-FDX, ");
+ } else {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst),
+ E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX);
+ printf("1000baseSX-FDX, ");
+ }
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
+ printf("auto\n");
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static void
+e1000phy_reset(struct mii_softc *sc)
+{
+ u_int32_t reg;
+ int i;
+
+ /* initialize custom E1000 registers to magic values */
+ reg = PHY_READ(sc, E1000_SCR);
+ reg &= ~E1000_SCR_AUTO_X_MODE;
+ PHY_WRITE(sc, E1000_SCR, reg);
+
+ /* normal PHY reset */
+ /*mii_phy_reset(sc);*/
+ reg = PHY_READ(sc, E1000_CR);
+ reg |= E1000_CR_RESET;
+ PHY_WRITE(sc, E1000_CR, reg);
+
+ for (i = 0; i < 500; i++) {
+ DELAY(1);
+ reg = PHY_READ(sc, E1000_CR);
+ if (!(reg & E1000_CR_RESET))
+ break;
+ }
+
+ /* set more custom E1000 registers to magic values */
+ reg = PHY_READ(sc, E1000_SCR);
+ reg |= E1000_SCR_ASSERT_CRS_ON_TX;
+ PHY_WRITE(sc, E1000_SCR, reg);
+
+ reg = PHY_READ(sc, E1000_ESCR);
+ reg |= E1000_ESCR_TX_CLK_25;
+ PHY_WRITE(sc, E1000_ESCR, reg);
+
+ /* even more magic to reset DSP? */
+ PHY_WRITE(sc, 29, 0x1d);
+ PHY_WRITE(sc, 30, 0xc1);
+ PHY_WRITE(sc, 30, 0x00);
+}
+
+static int
+e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, E1000_CR);
+ PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) {
+ break;
+ }
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ e1000phy_reset(sc);
+ (void)e1000phy_mii_phy_auto(sc);
+ break;
+
+ case IFM_1000_T:
+ e1000phy_reset(sc);
+
+ /* TODO - any other way to force 1000BT? */
+ (void)e1000phy_mii_phy_auto(sc);
+ break;
+
+ case IFM_1000_SX:
+ e1000phy_reset(sc);
+
+ PHY_WRITE(sc, E1000_CR,
+ E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_1000);
+ PHY_WRITE(sc, E1000_AR, E1000_FA_1000X_FD);
+ break;
+
+ case IFM_100_TX:
+ e1000phy_reset(sc);
+
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
+ PHY_WRITE(sc, E1000_CR,
+ E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_100);
+ PHY_WRITE(sc, E1000_AR, E1000_AR_100TX_FD);
+ } else {
+ PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_100);
+ PHY_WRITE(sc, E1000_AR, E1000_AR_100TX);
+ }
+ break;
+
+ case IFM_10_T:
+ e1000phy_reset(sc);
+
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
+ PHY_WRITE(sc, E1000_CR,
+ E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_10);
+ PHY_WRITE(sc, E1000_AR, E1000_AR_10T_FD);
+ } else {
+ PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_10);
+ PHY_WRITE(sc, E1000_AR, E1000_AR_10T);
+ }
+
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ return (0);
+ }
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * check for link.
+ * Read the status register twice; BMSR_LINK is latch-low.
+ */
+ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
+ if (reg & BMSR_LINK)
+ break;
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (0);
+
+ sc->mii_ticks = 0;
+ e1000phy_reset(sc);
+ e1000phy_mii_phy_auto(sc);
+ return (0);
+ }
+
+ /* Update the media status. */
+ e1000phy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+e1000phy_status(struct mii_softc *sc)
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int bmsr, bmcr, esr, ssr, isr, ar, lpar;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR);
+ esr = PHY_READ(sc, E1000_ESR);
+ bmcr = PHY_READ(sc, E1000_CR);
+ ssr = PHY_READ(sc, E1000_SSR);
+ isr = PHY_READ(sc, E1000_ISR);
+ ar = PHY_READ(sc, E1000_AR);
+ lpar = PHY_READ(sc, E1000_LPAR);
+
+ if (bmsr & E1000_SR_LINK_STATUS)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ if (bmcr & E1000_CR_LOOPBACK)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if ((!(bmsr & E1000_SR_AUTO_NEG_COMPLETE) || !(ssr & E1000_SSR_LINK) ||
+ !(ssr & E1000_SSR_SPD_DPLX_RESOLVED))) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
+ if (ssr & E1000_SSR_1000MBS)
+ mii->mii_media_active |= IFM_1000_T;
+ else if (ssr & E1000_SSR_100MBS)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ } else {
+ if (ssr & E1000_SSR_1000MBS)
+ mii->mii_media_active |= IFM_1000_SX;
+ }
+
+ if (ssr & E1000_SSR_DUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+ else
+ mii->mii_media_active |= IFM_HDX;
+
+ if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
+ /* FLAG0==rx-flow-control FLAG1==tx-flow-control */
+ if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) {
+ mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1;
+ } else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) &&
+ (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) {
+ mii->mii_media_active |= IFM_FLAG1;
+ } else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) &&
+ !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) {
+ mii->mii_media_active |= IFM_FLAG0;
+ }
+ }
+}
+
+static int
+e1000phy_mii_phy_auto(struct mii_softc *mii)
+{
+
+ if ((mii->mii_flags & MIIF_HAVEFIBER) == 0) {
+ PHY_WRITE(mii, E1000_AR, E1000_AR_10T | E1000_AR_10T_FD |
+ E1000_AR_100TX | E1000_AR_100TX_FD |
+ E1000_AR_PAUSE | E1000_AR_ASM_DIR);
+ PHY_WRITE(mii, E1000_1GCR, E1000_1GCR_1000T_FD);
+ PHY_WRITE(mii, E1000_CR,
+ E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG);
+ }
+
+ return (EJUSTRETURN);
+}
diff --git a/sys/dev/mii/e1000phyreg.h b/sys/dev/mii/e1000phyreg.h
new file mode 100644
index 0000000..bdfc665
--- /dev/null
+++ b/sys/dev/mii/e1000phyreg.h
@@ -0,0 +1,314 @@
+/* $FreeBSD$ */
+/*
+ * Principal Author: Parag Patel
+ * Copyright (c) 2001
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Additonal Copyright (c) 2001 by Traakan Software under same licence.
+ * Secondary Author: Matthew Jacob
+ */
+
+/*
+ * Derived by information released by Intel under the following license:
+ *
+ * Copyright (c) 1999 - 2001, Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Marvell E1000 PHY registers
+ */
+
+#define E1000_MAX_REG_ADDRESS 0x1F
+
+#define E1000_CR 0x00 /* control register */
+#define E1000_CR_SPEED_SELECT_MSB 0x0040
+#define E1000_CR_COLL_TEST_ENABLE 0x0080
+#define E1000_CR_FULL_DUPLEX 0x0100
+#define E1000_CR_RESTART_AUTO_NEG 0x0200
+#define E1000_CR_ISOLATE 0x0400
+#define E1000_CR_POWER_DOWN 0x0800
+#define E1000_CR_AUTO_NEG_ENABLE 0x1000
+#define E1000_CR_SPEED_SELECT_LSB 0x2000
+#define E1000_CR_LOOPBACK 0x4000
+#define E1000_CR_RESET 0x8000
+
+#define E1000_CR_SPEED_1000 0x0040
+#define E1000_CR_SPEED_100 0x2000
+#define E1000_CR_SPEED_10 0x0000
+
+#define E1000_SR 0x01 /* status register */
+#define E1000_SR_EXTENDED 0x0001
+#define E1000_SR_JABBER_DETECT 0x0002
+#define E1000_SR_LINK_STATUS 0x0004
+#define E1000_SR_AUTO_NEG 0x0008
+#define E1000_SR_REMOTE_FAULT 0x0010
+#define E1000_SR_AUTO_NEG_COMPLETE 0x0020
+#define E1000_SR_PREAMBLE_SUPPRESS 0x0040
+#define E1000_SR_EXTENDED_STATUS 0x0100
+#define E1000_SR_100T2 0x0200
+#define E1000_SR_100T2_FD 0x0400
+#define E1000_SR_10T 0x0800
+#define E1000_SR_10T_FD 0x1000
+#define E1000_SR_100TX 0x2000
+#define E1000_SR_100TX_FD 0x4000
+#define E1000_SR_100T4 0x8000
+
+#define E1000_ID1 0x02 /* ID register 1 */
+#define E1000_ID2 0x03 /* ID register 2 */
+#define E1000_ID_88E1000 0x01410C50
+#define E1000_ID_88E1000S 0x01410C40
+#define E1000_ID_88E1011 0x01410C20
+#define E1000_ID_MASK 0xFFFFFFF0
+
+#define E1000_AR 0x04 /* autonegotiation advertise reg */
+#define E1000_AR_SELECTOR_FIELD 0x0001
+#define E1000_AR_10T 0x0020
+#define E1000_AR_10T_FD 0x0040
+#define E1000_AR_100TX 0x0080
+#define E1000_AR_100TX_FD 0x0100
+#define E1000_AR_100T4 0x0200
+#define E1000_AR_PAUSE 0x0400
+#define E1000_AR_ASM_DIR 0x0800
+#define E1000_AR_REMOTE_FAULT 0x2000
+#define E1000_AR_NEXT_PAGE 0x8000
+#define E1000_AR_SPEED_MASK 0x01E0
+
+/* Autonegotiation register bits for fiber cards (Alaska Only!) */
+#define E1000_FA_1000X_FD 0x0020
+#define E1000_FA_1000X 0x0040
+#define E1000_FA_SYM_PAUSE 0x0080
+#define E1000_FA_ASYM_PAUSE 0x0100
+#define E1000_FA_FAULT1 0x1000
+#define E1000_FA_FAULT2 0x2000
+#define E1000_FA_NEXT_PAGE 0x8000
+
+#define E1000_LPAR 0x05 /* autoneg link partner abilities reg */
+#define E1000_LPAR_SELECTOR_FIELD 0x0001
+#define E1000_LPAR_10T 0x0020
+#define E1000_LPAR_10T_FD 0x0040
+#define E1000_LPAR_100TX 0x0080
+#define E1000_LPAR_100TX_FD 0x0100
+#define E1000_LPAR_100T4 0x0200
+#define E1000_LPAR_PAUSE 0x0400
+#define E1000_LPAR_ASM_DIR 0x0800
+#define E1000_LPAR_REMOTE_FAULT 0x2000
+#define E1000_LPAR_ACKNOWLEDGE 0x4000
+#define E1000_LPAR_NEXT_PAGE 0x8000
+
+/* autoneg link partner ability register bits for fiber cards (Alaska Only!) */
+#define E1000_FPAR_1000X_FD 0x0020
+#define E1000_FPAR_1000X 0x0040
+#define E1000_FPAR_SYM_PAUSE 0x0080
+#define E1000_FPAR_ASYM_PAUSE 0x0100
+#define E1000_FPAR_FAULT1 0x1000
+#define E1000_FPAR_FAULT2 0x2000
+#define E1000_FPAR_ACK 0x4000
+#define E1000_FPAR_NEXT_PAGE 0x8000
+
+#define E1000_ER 0x06 /* autoneg expansion reg */
+#define E1000_ER_LP_NWAY 0x0001
+#define E1000_ER_PAGE_RXD 0x0002
+#define E1000_ER_NEXT_PAGE 0x0004
+#define E1000_ER_LP_NEXT_PAGE 0x0008
+#define E1000_ER_PAR_DETECT_FAULT 0x0100
+
+#define E1000_NPTX 0x07 /* autoneg next page TX */
+#define E1000_NPTX_MSG_CODE_FIELD 0x0001
+#define E1000_NPTX_TOGGLE 0x0800
+#define E1000_NPTX_ACKNOWLDGE2 0x1000
+#define E1000_NPTX_MSG_PAGE 0x2000
+#define E1000_NPTX_NEXT_PAGE 0x8000
+
+#define E1000_RNPR 0x08 /* autoneg link-partner (?) next page */
+#define E1000_RNPR_MSG_CODE_FIELD 0x0001
+#define E1000_RNPR_TOGGLE 0x0800
+#define E1000_RNPR_ACKNOWLDGE2 0x1000
+#define E1000_RNPR_MSG_PAGE 0x2000
+#define E1000_RNPR_ACKNOWLDGE 0x4000
+#define E1000_RNPR_NEXT_PAGE 0x8000
+
+#define E1000_1GCR 0x09 /* 1000T (1G) control reg */
+#define E1000_1GCR_ASYM_PAUSE 0x0080
+#define E1000_1GCR_1000T 0x0100
+#define E1000_1GCR_1000T_FD 0x0200
+#define E1000_1GCR_REPEATER_DTE 0x0400
+#define E1000_1GCR_MS_VALUE 0x0800
+#define E1000_1GCR_MS_ENABLE 0x1000
+#define E1000_1GCR_TEST_MODE_NORMAL 0x0000
+#define E1000_1GCR_TEST_MODE_1 0x2000
+#define E1000_1GCR_TEST_MODE_2 0x4000
+#define E1000_1GCR_TEST_MODE_3 0x6000
+#define E1000_1GCR_TEST_MODE_4 0x8000
+#define E1000_1GCR_SPEED_MASK 0x0300
+
+#define E1000_1GSR 0x0A /* 1000T (1G) status reg */
+#define E1000_1GSR_IDLE_ERROR_CNT 0x0000
+#define E1000_1GSR_ASYM_PAUSE_DIR 0x0100
+#define E1000_1GSR_LP 0x0400
+#define E1000_1GSR_LP_FD 0x0800
+#define E1000_1GSR_REMOTE_RX_STATUS 0x1000
+#define E1000_1GSR_LOCAL_RX_STATUS 0x2000
+#define E1000_1GSR_MS_CONFIG_RES 0x4000
+#define E1000_1GSR_MS_CONFIG_FAULT 0x8000
+
+#define E1000_ESR 0x0F /* IEEE extended status reg */
+#define E1000_ESR_1000T 0x1000
+#define E1000_ESR_1000T_FD 0x2000
+#define E1000_ESR_1000X 0x4000
+#define E1000_ESR_1000X_FD 0x8000
+
+#define E1000_TX_POLARITY_MASK 0x0100
+#define E1000_TX_NORMAL_POLARITY 0
+
+#define E1000_AUTO_POLARITY_DISABLE 0x0010
+
+#define E1000_SCR 0x10 /* special control register */
+#define E1000_SCR_JABBER_DISABLE 0x0001
+#define E1000_SCR_POLARITY_REVERSAL 0x0002
+#define E1000_SCR_SQE_TEST 0x0004
+#define E1000_SCR_INT_FIFO_DISABLE 0x0008
+#define E1000_SCR_CLK125_DISABLE 0x0010
+#define E1000_SCR_MDI_MANUAL_MODE 0x0000
+#define E1000_SCR_MDIX_MANUAL_MODE 0x0020
+#define E1000_SCR_AUTO_X_1000T 0x0040
+#define E1000_SCR_AUTO_X_MODE 0x0060
+#define E1000_SCR_10BT_EXT_ENABLE 0x0080
+#define E1000_SCR_MII_5BIT_ENABLE 0x0100
+#define E1000_SCR_SCRAMBLER_DISABLE 0x0200
+#define E1000_SCR_FORCE_LINK_GOOD 0x0400
+#define E1000_SCR_ASSERT_CRS_ON_TX 0x0800
+#define E1000_SCR_RX_FIFO_DEPTH_6 0x0000
+#define E1000_SCR_RX_FIFO_DEPTH_8 0x1000
+#define E1000_SCR_RX_FIFO_DEPTH_10 0x2000
+#define E1000_SCR_RX_FIFO_DEPTH_12 0x3000
+#define E1000_SCR_TX_FIFO_DEPTH_6 0x0000
+#define E1000_SCR_TX_FIFO_DEPTH_8 0x4000
+#define E1000_SCR_TX_FIFO_DEPTH_10 0x8000
+#define E1000_SCR_TX_FIFO_DEPTH_12 0xC000
+
+#define E1000_SSR 0x11 /* special status register */
+#define E1000_SSR_JABBER 0x0001
+#define E1000_SSR_REV_POLARITY 0x0002
+#define E1000_SSR_MDIX 0x0020
+#define E1000_SSR_LINK 0x0400
+#define E1000_SSR_SPD_DPLX_RESOLVED 0x0800
+#define E1000_SSR_PAGE_RCVD 0x1000
+#define E1000_SSR_DUPLEX 0x2000
+#define E1000_SSR_SPEED 0xC000
+#define E1000_SSR_10MBS 0x0000
+#define E1000_SSR_100MBS 0x4000
+#define E1000_SSR_1000MBS 0x8000
+
+#define E1000_IER 0x12 /* interrupt enable reg */
+#define E1000_IER_JABBER 0x0001
+#define E1000_IER_POLARITY_CHANGE 0x0002
+#define E1000_IER_MDIX_CHANGE 0x0040
+#define E1000_IER_FIFO_OVER_UNDERUN 0x0080
+#define E1000_IER_FALSE_CARRIER 0x0100
+#define E1000_IER_SYMBOL_ERROR 0x0200
+#define E1000_IER_LINK_STAT_CHANGE 0x0400
+#define E1000_IER_AUTO_NEG_COMPLETE 0x0800
+#define E1000_IER_PAGE_RECEIVED 0x1000
+#define E1000_IER_DUPLEX_CHANGED 0x2000
+#define E1000_IER_SPEED_CHANGED 0x4000
+#define E1000_IER_AUTO_NEG_ERR 0x8000
+
+#define E1000_ISR 0x13 /* interrupt status reg */
+#define E1000_ISR_JABBER 0x0001
+#define E1000_ISR_POLARITY_CHANGE 0x0002
+#define E1000_ISR_MDIX_CHANGE 0x0040
+#define E1000_ISR_FIFO_OVER_UNDERUN 0x0080
+#define E1000_ISR_FALSE_CARRIER 0x0100
+#define E1000_ISR_SYMBOL_ERROR 0x0200
+#define E1000_ISR_LINK_STAT_CHANGE 0x0400
+#define E1000_ISR_AUTO_NEG_COMPLETE 0x0800
+#define E1000_ISR_PAGE_RECEIVED 0x1000
+#define E1000_ISR_DUPLEX_CHANGED 0x2000
+#define E1000_ISR_SPEED_CHANGED 0x4000
+#define E1000_ISR_AUTO_NEG_ERR 0x8000
+
+#define E1000_ESCR 0x14 /* extended special control reg */
+#define E1000_ESCR_FIBER_LOOPBACK 0x4000
+#define E1000_ESCR_DOWN_NO_IDLE 0x8000
+#define E1000_ESCR_TX_CLK_2_5 0x0060
+#define E1000_ESCR_TX_CLK_25 0x0070
+#define E1000_ESCR_TX_CLK_0 0x0000
+
+#define E1000_RECR 0x15 /* RX error counter reg */
+
+#define E1000_LCR 0x18 /* LED control reg */
+#define E1000_LCR_LED_TX 0x0001
+#define E1000_LCR_LED_RX 0x0002
+#define E1000_LCR_LED_DUPLEX 0x0004
+#define E1000_LCR_LINK 0x0008
+#define E1000_LCR_BLINK_42MS 0x0000
+#define E1000_LCR_BLINK_84MS 0x0100
+#define E1000_LCR_BLINK_170MS 0x0200
+#define E1000_LCR_BLINK_340MS 0x0300
+#define E1000_LCR_BLINK_670MS 0x0400
+#define E1000_LCR_PULSE_OFF 0x0000
+#define E1000_LCR_PULSE_21_42MS 0x1000
+#define E1000_LCR_PULSE_42_84MS 0x2000
+#define E1000_LCR_PULSE_84_170MS 0x3000
+#define E1000_LCR_PULSE_170_340MS 0x4000
+#define E1000_LCR_PULSE_340_670MS 0x5000
+#define E1000_LCR_PULSE_670_13S 0x6000
+#define E1000_LCR_PULSE_13_26S 0x7000
+
+/* The following register is found only on the 88E1011 Alaska PHY */
+#define E1000_ESSR 0x1B /* Extended PHY specific sts */
+#define E1000_ESSR_FIBER_LINK 0x2000
+#define E1000_ESSR_GMII_COPPER 0x000f
+#define E1000_ESSR_GMII_FIBER 0x0007
+#define E1000_ESSR_TBI_COPPER 0x000d
+#define E1000_ESSR_TBI_FIBER 0x0005
diff --git a/sys/dev/mii/exphy.c b/sys/dev/mii/exphy.c
new file mode 100644
index 0000000..97c97cd
--- /dev/null
+++ b/sys/dev/mii/exphy.c
@@ -0,0 +1,274 @@
+/* $NetBSD: exphy.c,v 1.16 1999/04/23 04:24:32 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center, and by Frank van der Linden.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * driver for 3Com internal PHYs
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include "miibus_if.h"
+
+static int exphy_probe(device_t);
+static int exphy_attach(device_t);
+
+static device_method_t exphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, exphy_probe),
+ DEVMETHOD(device_attach, exphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t exphy_devclass;
+
+static driver_t exphy_driver = {
+ "xlphy",
+ exphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(xlphy, miibus, exphy_driver, exphy_devclass, 0, 0);
+
+static int exphy_service(struct mii_softc *, struct mii_data *, int);
+static void exphy_reset(struct mii_softc *);
+
+static int
+exphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+ device_t parent;
+
+ ma = device_get_ivars(dev);
+ parent = device_get_parent(device_get_parent(dev));
+
+ /*
+ * Argh, 3Com PHY reports oui == 0 model == 0!
+ */
+ if ((MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
+ MII_MODEL(ma->mii_id2) != 0) &&
+ (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM ||
+ MII_MODEL(ma->mii_id2) != MII_MODEL_BROADCOM_3C905C))
+ return (ENXIO);
+
+ /*
+ * Make sure the parent is an `ex'.
+ */
+ if (strcmp(device_get_name(parent), "xl") != 0)
+ return (ENXIO);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == 0)
+ device_set_desc(dev, "3Com internal media interface");
+ else
+ device_set_desc(dev, MII_STR_BROADCOM_3C905C);
+
+ return (0);
+}
+
+static int
+exphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+
+ /*
+ * The 3Com PHY can never be isolated, so never allow non-zero
+ * instances!
+ */
+ if (mii->mii_instance != 0) {
+ device_printf(dev, "ignoring this PHY, non-zero instance\n");
+ return(ENXIO);
+ }
+
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = exphy_service;
+ sc->mii_pdata = mii;
+ mii->mii_instance++;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+#if 0 /* See above. */
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+#endif
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+
+ exphy_reset(sc);
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_phy_add_media(sc);
+ printf("\n");
+#undef ADD
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+exphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+
+ /*
+ * We can't isolate the 3Com PHY, so it has to be the only one!
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ panic("exphy_service: can't isolate 3Com PHY");
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ mii_phy_setmedia(sc);
+ break;
+
+ case MII_TICK:
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * The 3Com PHY's autonegotiation doesn't need to be
+ * kicked; it continues in the background.
+ */
+ break;
+ }
+
+ /* Update the media status. */
+ ukphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+exphy_reset(struct mii_softc *sc)
+{
+
+ mii_phy_reset(sc);
+
+ /*
+ * XXX 3Com PHY doesn't set the BMCR properly after
+ * XXX reset, which breaks autonegotiation.
+ */
+ PHY_WRITE(sc, MII_BMCR, BMCR_S100|BMCR_AUTOEN|BMCR_FDX);
+}
diff --git a/sys/dev/mii/inphy.c b/sys/dev/mii/inphy.c
new file mode 100644
index 0000000..3aa6f16
--- /dev/null
+++ b/sys/dev/mii/inphy.c
@@ -0,0 +1,236 @@
+/*-
+ * Copyright (c) 2001 Jonathan Lemon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * driver for Intel 82553 and 82555 PHYs
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/inphyreg.h>
+
+#include "miibus_if.h"
+
+static int inphy_probe(device_t dev);
+static int inphy_attach(device_t dev);
+
+static device_method_t inphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, inphy_probe),
+ DEVMETHOD(device_attach, inphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t inphy_devclass;
+
+static driver_t inphy_driver = {
+ "inphy",
+ inphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(inphy, miibus, inphy_driver, inphy_devclass, 0, 0);
+
+static int inphy_service(struct mii_softc *, struct mii_data *, int);
+static void inphy_status(struct mii_softc *);
+
+static int
+inphy_probe(device_t dev)
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ /* Intel 82553 A/B steppings */
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxINTEL &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxINTEL_I82553AB) {
+ device_set_desc(dev, MII_STR_xxINTEL_I82553AB);
+ return (0);
+ }
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_INTEL) {
+ switch (MII_MODEL(ma->mii_id2)) {
+ case MII_MODEL_INTEL_I82555:
+ device_set_desc(dev, MII_STR_INTEL_I82555);
+ return (0);
+ case MII_MODEL_INTEL_I82553C:
+ device_set_desc(dev, MII_STR_INTEL_I82553C);
+ return (0);
+ case MII_MODEL_INTEL_I82562EM:
+ device_set_desc(dev, MII_STR_INTEL_I82562EM);
+ return (0);
+ case MII_MODEL_INTEL_I82562ET:
+ device_set_desc(dev, MII_STR_INTEL_I82562ET);
+ return (0);
+ }
+ }
+
+ return (ENXIO);
+}
+
+static int
+inphy_attach(device_t dev)
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = inphy_service;
+ sc->mii_pdata = mii;
+ mii->mii_instance++;
+
+#if 0
+ sc->mii_flags |= MIIF_NOISOLATE;
+#endif
+
+ ifmedia_add(&mii->mii_media,
+ IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100, NULL);
+
+ mii_phy_reset(sc);
+
+ sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_phy_add_media(sc);
+ printf("\n");
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+
+ return (0);
+}
+
+static int
+inphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ mii_phy_setmedia(sc);
+ break;
+
+ case MII_TICK:
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ if (mii_phy_tick(sc) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ inphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+inphy_status(struct mii_softc *sc)
+{
+ struct mii_data *mii = sc->mii_pdata;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int bmsr, bmcr, scr;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(sc, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BMCR_AUTOEN) {
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ scr = PHY_READ(sc, MII_INPHY_SCR);
+ if (scr & SCR_S100)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ if (scr & SCR_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ } else
+ mii->mii_media_active = ife->ifm_media;
+}
diff --git a/sys/dev/mii/inphyreg.h b/sys/dev/mii/inphyreg.h
new file mode 100644
index 0000000..4b7d1f1
--- /dev/null
+++ b/sys/dev/mii/inphyreg.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2001 Jonathan Lemon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#define MII_INPHY_SCR 0x10 /* status and control register */
+#define SCR_FLOWCTL 0x8000
+#define SCR_S100 0x0002 /* autonegotiated speed */
+#define SCR_FDX 0x0001 /* autonegotiated duplex */
diff --git a/sys/dev/mii/lxtphy.c b/sys/dev/mii/lxtphy.c
new file mode 100644
index 0000000..57fbe16
--- /dev/null
+++ b/sys/dev/mii/lxtphy.c
@@ -0,0 +1,343 @@
+/* OpenBSD: lxtphy.c,v 1.5 2000/08/26 20:04:17 nate Exp */
+/* NetBSD: lxtphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp */
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * driver for Level One's LXT-970 ethernet 10/100 PHY
+ * datasheet from www.level1.com
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/lxtphyreg.h>
+
+#include "miibus_if.h"
+
+static int lxtphy_probe(device_t);
+static int lxtphy_attach(device_t);
+
+static device_method_t lxtphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, lxtphy_probe),
+ DEVMETHOD(device_attach, lxtphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t lxtphy_devclass;
+
+static driver_t lxtphy_driver = {
+ "lxtphy",
+ lxtphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(lxtphy, miibus, lxtphy_driver, lxtphy_devclass, 0, 0);
+
+static int lxtphy_service(struct mii_softc *, struct mii_data *, int);
+static void lxtphy_status(struct mii_softc *);
+static void lxtphy_set_tp(struct mii_softc *);
+static void lxtphy_set_fx(struct mii_softc *);
+
+static int
+lxtphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxLEVEL1 &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxLEVEL1_LXT970) {
+ device_set_desc(dev, MII_STR_xxLEVEL1_LXT970);
+ } else
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+lxtphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = lxtphy_service;
+ sc->mii_pdata = mii;
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+ mii_phy_reset(sc);
+
+ mii->mii_instance++;
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst),
+ BMCR_S100);
+ printf("100baseFX, ");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst),
+ BMCR_S100|BMCR_FDX);
+ printf("100baseFX-FDX, ");
+#undef ADD
+
+ mii_add_media(sc);
+ printf("\n");
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+lxtphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
+ return (0);
+
+ lxtphy_set_tp(sc);
+
+ (void) mii_phy_auto(sc);
+ break;
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+
+ case IFM_100_FX:
+ lxtphy_set_fx(sc);
+ /* XXX: fall though intentional ?? */
+ default:
+ /*
+ * BMCR data is stored in the ifmedia entry.
+ */
+ PHY_WRITE(sc, MII_ANAR,
+ mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ if (mii_phy_tick(sc) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ lxtphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+lxtphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int bmcr, bmsr, csr;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ /*
+ * Get link status from the CSR; we need to read the CSR
+ * for media type anyhow, and the link status in the CSR
+ * doens't latch, so fewer register reads are required.
+ */
+ csr = PHY_READ(sc, MII_LXTPHY_CSR);
+ if (csr & CSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(sc, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BMCR_AUTOEN) {
+ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+ if (csr & CSR_SPEED)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ if (csr & CSR_DUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+ } else
+ mii->mii_media_active = ife->ifm_media;
+}
+
+static void
+lxtphy_set_tp(sc)
+ struct mii_softc *sc;
+{
+ int cfg;
+
+ cfg = PHY_READ(sc, MII_LXTPHY_CONFIG);
+ cfg &= ~CONFIG_100BASEFX;
+ PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg);
+}
+
+static void
+lxtphy_set_fx(sc)
+ struct mii_softc *sc;
+{
+ int cfg;
+
+ cfg = PHY_READ(sc, MII_LXTPHY_CONFIG);
+ cfg |= CONFIG_100BASEFX;
+ PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg);
+}
+
diff --git a/sys/dev/mii/lxtphyreg.h b/sys/dev/mii/lxtphyreg.h
new file mode 100644
index 0000000..662bd34
--- /dev/null
+++ b/sys/dev/mii/lxtphyreg.h
@@ -0,0 +1,90 @@
+/* OpenBSD: lxtphyreg.h,v 1.1 1998/11/11 19:34:47 jason Exp */
+/* NetBSD: lxtphyreg.h,v 1.1 1998/10/24 00:33:17 thorpej Exp */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_MII_LXTPHYREG_H_
+#define _DEV_MII_LXTPHYREG_H_
+
+/*
+ * LXT970 registers.
+ */
+
+#define MII_LXTPHY_MIRROR 0x10 /* Mirror register */
+ /* All bits user-defined */
+
+#define MII_LXTPHY_IER 0x11 /* Interrupt Enable Register */
+#define IER_MIIDRVLVL 0x0008 /* Rediced MII driver levels */
+#define IER_LNK_CRITERIA 0x0004 /* Enhanced Link Loss Criteria */
+#define IER_INTEN 0x0002 /* Interrupt Enable */
+#define IER_TINT 0x0001 /* Force Interrupt */
+
+#define MII_LXTPHY_ISR 0x12 /* Interrupt Status Register */
+#define ISR_MINT 0x8000 /* MII Interrupt Pending */
+#define ISR_XTALOK 0x4000 /* Clocks OK */
+
+#define MII_LXTPHY_CONFIG 0x13 /* Configuration Register */
+#define CONFIG_TXMIT_TEST 0x4000 /* 100base-T Transmit Test */
+#define CONFIG_REPEATER 0x2000 /* Repeater Mode */
+#define CONFIG_MDIO_INT 0x1000 /* Enable intr signalling on MDIO */
+#define CONFIG_TPLOOP 0x0800 /* Disable 10base-T Loopback */
+#define CONFIG_SQE 0x0400 /* Enable SQE */
+#define CONFIG_DISJABBER 0x0200 /* Disable Jabber */
+#define CONFIG_DISLINKTEST 0x0100 /* Disable Link Test */
+#define CONFIG_LEDC1 0x0080 /* LEDC configuration */
+#define CONFIG_LEDC0 0x0040 /* ... */
+ /* 0 0 LEDC indicates collision */
+ /* 0 1 LEDC is off */
+ /* 1 0 LEDC indicates activity */
+ /* 1 1 LEDC is on */
+#define CONFIG_ADVTXCLK 0x0020 /* Advance TX clock */
+#define CONFIG_5BSYMBOL 0x0010 /* 5-bit Symbol mode */
+#define CONFIG_SCRAMBLER 0x0008 /* Bypass scrambler */
+#define CONFIG_100BASEFX 0x0004 /* 100base-FX */
+#define CONFIG_TXDISCON 0x0001 /* Disconnect TP transmitter */
+
+#define MII_LXTPHY_CSR 0x14 /* Chip Status Register */
+#define CSR_LINK 0x2000 /* Link is up */
+#define CSR_DUPLEX 0x1000 /* Full-duplex */
+#define CSR_SPEED 0x0800 /* 100Mbps */
+#define CSR_ACOMP 0x0400 /* Autonegotiation complete */
+#define CSR_PAGERCVD 0x0200 /* Link page received */
+#define CSR_LOWVCC 0x0004 /* Low Voltage Fault */
+
+#endif /* _DEV_MII_LXTPHYREG_H_ */
diff --git a/sys/dev/mii/mii.c b/sys/dev/mii/mii.c
new file mode 100644
index 0000000..4771cc5
--- /dev/null
+++ b/sys/dev/mii/mii.c
@@ -0,0 +1,386 @@
+/* $NetBSD: mii.c,v 1.12 1999/08/03 19:41:49 drochner Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * MII bus layer, glues MII-capable network interface drivers to sharable
+ * PHY drivers. This exports an interface compatible with BSD/OS 3.0's,
+ * plus some NetBSD extensions.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+MODULE_VERSION(miibus, 1);
+
+#include "miibus_if.h"
+
+static int miibus_readreg(device_t, int, int);
+static int miibus_writereg(device_t, int, int, int);
+static void miibus_statchg(device_t);
+static void miibus_linkchg(device_t);
+static void miibus_mediainit(device_t);
+
+static device_method_t miibus_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, miibus_probe),
+ DEVMETHOD(device_attach, miibus_attach),
+ DEVMETHOD(device_detach, miibus_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, miibus_readreg),
+ DEVMETHOD(miibus_writereg, miibus_writereg),
+ DEVMETHOD(miibus_statchg, miibus_statchg),
+ DEVMETHOD(miibus_linkchg, miibus_linkchg),
+ DEVMETHOD(miibus_mediainit, miibus_mediainit),
+
+ { 0, 0 }
+};
+
+devclass_t miibus_devclass;
+
+driver_t miibus_driver = {
+ "miibus",
+ miibus_methods,
+ sizeof(struct mii_data)
+};
+
+/*
+ * Helper function used by network interface drivers, attaches PHYs
+ * to the network interface driver parent.
+ */
+
+int
+miibus_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args ma, *args;
+ struct mii_data *mii;
+ device_t child = NULL, parent;
+ int bmsr, capmask = 0xFFFFFFFF;
+
+ mii = device_get_softc(dev);
+ parent = device_get_parent(dev);
+ LIST_INIT(&mii->mii_phys);
+
+ for (ma.mii_phyno = 0; ma.mii_phyno < MII_NPHY; ma.mii_phyno++) {
+ /*
+ * Check to see if there is a PHY at this address. Note,
+ * many braindead PHYs report 0/0 in their ID registers,
+ * so we test for media in the BMSR.
+ */
+ bmsr = MIIBUS_READREG(parent, ma.mii_phyno, MII_BMSR);
+ if (bmsr == 0 || bmsr == 0xffff ||
+ (bmsr & BMSR_MEDIAMASK) == 0) {
+ /* Assume no PHY at this address. */
+ continue;
+ }
+
+ /*
+ * Extract the IDs. Braindead PHYs will be handled by
+ * the `ukphy' driver, as we have no ID information to
+ * match on.
+ */
+ ma.mii_id1 = MIIBUS_READREG(parent, ma.mii_phyno,
+ MII_PHYIDR1);
+ ma.mii_id2 = MIIBUS_READREG(parent, ma.mii_phyno,
+ MII_PHYIDR2);
+
+ ma.mii_data = mii;
+ ma.mii_capmask = capmask;
+
+ args = malloc(sizeof(struct mii_attach_args),
+ M_DEVBUF, M_NOWAIT);
+ bcopy((char *)&ma, (char *)args, sizeof(ma));
+ child = device_add_child(dev, NULL, -1);
+ device_set_ivars(child, args);
+ }
+
+ if (child == NULL)
+ return(ENXIO);
+
+ device_set_desc(dev, "MII bus");
+
+ return(0);
+}
+
+int
+miibus_attach(dev)
+ device_t dev;
+{
+ void **v;
+ ifm_change_cb_t ifmedia_upd;
+ ifm_stat_cb_t ifmedia_sts;
+ struct mii_data *mii;
+
+ mii = device_get_softc(dev);
+ /*
+ * Note that each NIC's softc must start with an ifnet structure.
+ */
+ mii->mii_ifp = device_get_softc(device_get_parent(dev));
+ v = device_get_ivars(dev);
+ ifmedia_upd = v[0];
+ ifmedia_sts = v[1];
+ ifmedia_init(&mii->mii_media, IFM_IMASK, ifmedia_upd, ifmedia_sts);
+ bus_generic_attach(dev);
+
+ return(0);
+}
+
+int
+miibus_detach(dev)
+ device_t dev;
+{
+ struct mii_data *mii;
+
+ bus_generic_detach(dev);
+ mii = device_get_softc(dev);
+ ifmedia_removeall(&mii->mii_media);
+ mii->mii_ifp = NULL;
+
+ return(0);
+}
+
+static int
+miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ device_t parent;
+
+ parent = device_get_parent(dev);
+ return(MIIBUS_READREG(parent, phy, reg));
+}
+
+static int
+miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ device_t parent;
+
+ parent = device_get_parent(dev);
+ return(MIIBUS_WRITEREG(parent, phy, reg, data));
+}
+
+static void
+miibus_statchg(dev)
+ device_t dev;
+{
+ device_t parent;
+
+ parent = device_get_parent(dev);
+ MIIBUS_STATCHG(parent);
+ return;
+}
+
+static void
+miibus_linkchg(dev)
+ device_t dev;
+{
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ device_t parent;
+ int link;
+
+ parent = device_get_parent(dev);
+ MIIBUS_LINKCHG(parent);
+
+ mii = device_get_softc(dev);
+ /*
+ * Note that each NIC's softc must start with an ifnet structure.
+ */
+ ifp = device_get_softc(parent);
+
+ if (mii->mii_media_status & IFM_AVALID) {
+ if (mii->mii_media_status & IFM_ACTIVE)
+ link = NOTE_LINKUP;
+ else
+ link = NOTE_LINKDOWN;
+ } else {
+ link = NOTE_LINKINV;
+ }
+
+ KNOTE(&ifp->if_klist, link);
+}
+
+static void
+miibus_mediainit(dev)
+ device_t dev;
+{
+ struct mii_data *mii;
+ struct ifmedia_entry *m;
+ int media = 0;
+
+ /* Poke the parent in case it has any media of its own to add. */
+ MIIBUS_MEDIAINIT(device_get_parent(dev));
+
+ mii = device_get_softc(dev);
+ LIST_FOREACH(m, &mii->mii_media.ifm_list, ifm_list) {
+ media = m->ifm_media;
+ if (media == (IFM_ETHER|IFM_AUTO))
+ break;
+ }
+
+ ifmedia_set(&mii->mii_media, media);
+
+ return;
+}
+
+int
+mii_phy_probe(dev, child, ifmedia_upd, ifmedia_sts)
+ device_t dev;
+ device_t *child;
+ ifm_change_cb_t ifmedia_upd;
+ ifm_stat_cb_t ifmedia_sts;
+{
+ void **v;
+ int bmsr, i;
+
+ v = malloc(sizeof(vm_offset_t) * 2, M_DEVBUF, M_NOWAIT);
+ if (v == 0) {
+ return (ENOMEM);
+ }
+ v[0] = ifmedia_upd;
+ v[1] = ifmedia_sts;
+ *child = device_add_child(dev, "miibus", -1);
+ device_set_ivars(*child, v);
+
+ for (i = 0; i < MII_NPHY; i++) {
+ bmsr = MIIBUS_READREG(dev, i, MII_BMSR);
+ if (bmsr == 0 || bmsr == 0xffff ||
+ (bmsr & BMSR_MEDIAMASK) == 0) {
+ /* Assume no PHY at this address. */
+ continue;
+ } else
+ break;
+ }
+
+ if (i == MII_NPHY) {
+ device_delete_child(dev, *child);
+ *child = NULL;
+ return(ENXIO);
+ }
+
+ bus_generic_attach(dev);
+
+ return(0);
+}
+
+/*
+ * Media changed; notify all PHYs.
+ */
+int
+mii_mediachg(mii)
+ struct mii_data *mii;
+{
+ struct mii_softc *child;
+ int rv;
+
+ mii->mii_media_status = 0;
+ mii->mii_media_active = IFM_NONE;
+
+ LIST_FOREACH(child, &mii->mii_phys, mii_list) {
+ rv = (*child->mii_service)(child, mii, MII_MEDIACHG);
+ if (rv)
+ return (rv);
+ }
+ return (0);
+}
+
+/*
+ * Call the PHY tick routines, used during autonegotiation.
+ */
+void
+mii_tick(mii)
+ struct mii_data *mii;
+{
+ struct mii_softc *child;
+
+ LIST_FOREACH(child, &mii->mii_phys, mii_list)
+ (void) (*child->mii_service)(child, mii, MII_TICK);
+}
+
+/*
+ * Get media status from PHYs.
+ */
+void
+mii_pollstat(mii)
+ struct mii_data *mii;
+{
+ struct mii_softc *child;
+
+ mii->mii_media_status = 0;
+ mii->mii_media_active = IFM_NONE;
+
+ LIST_FOREACH(child, &mii->mii_phys, mii_list)
+ (void) (*child->mii_service)(child, mii, MII_POLLSTAT);
+}
+
+/*
+ * Inform the PHYs that the interface is down.
+ */
+void
+mii_down(struct mii_data *mii)
+{
+ struct mii_softc *child;
+
+ LIST_FOREACH(child, &mii->mii_phys, mii_list)
+ mii_phy_down(child);
+}
diff --git a/sys/dev/mii/mii.h b/sys/dev/mii/mii.h
new file mode 100644
index 0000000..963c226
--- /dev/null
+++ b/sys/dev/mii/mii.h
@@ -0,0 +1,206 @@
+/* $NetBSD: mii.h,v 1.9 2001/05/31 03:07:14 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Modification to match BSD/OS 3.0 MII interface by Jason R. Thorpe,
+ * Numerical Aerospace Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_MII_H_
+#define _DEV_MII_MII_H_
+
+/*
+ * Registers common to all PHYs.
+ */
+
+#define MII_NPHY 32 /* max # of PHYs per MII */
+
+/*
+ * MII commands, used if a device must drive the MII lines
+ * manually.
+ */
+#define MII_COMMAND_START 0x01
+#define MII_COMMAND_READ 0x02
+#define MII_COMMAND_WRITE 0x01
+#define MII_COMMAND_ACK 0x02
+
+#define MII_BMCR 0x00 /* Basic mode control register (rw) */
+#define BMCR_RESET 0x8000 /* reset */
+#define BMCR_LOOP 0x4000 /* loopback */
+#define BMCR_SPEED0 0x2000 /* speed selection (LSB) */
+#define BMCR_AUTOEN 0x1000 /* autonegotiation enable */
+#define BMCR_PDOWN 0x0800 /* power down */
+#define BMCR_ISO 0x0400 /* isolate */
+#define BMCR_STARTNEG 0x0200 /* restart autonegotiation */
+#define BMCR_FDX 0x0100 /* Set duplex mode */
+#define BMCR_CTEST 0x0080 /* collision test */
+#define BMCR_SPEED1 0x0040 /* speed selection (MSB) */
+
+#define BMCR_S10 0x0000 /* 10 Mb/s */
+#define BMCR_S100 BMCR_SPEED0 /* 100 Mb/s */
+#define BMCR_S1000 BMCR_SPEED1 /* 1000 Mb/s */
+
+#define BMCR_SPEED(x) ((x) & (BMCR_SPEED0|BMCR_SPEED1))
+
+#define MII_BMSR 0x01 /* Basic mode status register (ro) */
+#define BMSR_100T4 0x8000 /* 100 base T4 capable */
+#define BMSR_100TXFDX 0x4000 /* 100 base Tx full duplex capable */
+#define BMSR_100TXHDX 0x2000 /* 100 base Tx half duplex capable */
+#define BMSR_10TFDX 0x1000 /* 10 base T full duplex capable */
+#define BMSR_10THDX 0x0800 /* 10 base T half duplex capable */
+#define BMSR_100T2FDX 0x0400 /* 100 base T2 full duplex capable */
+#define BMSR_100T2HDX 0x0200 /* 100 base T2 half duplex capable */
+#define BMSR_EXTSTAT 0x0100 /* Extended status in register 15 */
+#define BMSR_MFPS 0x0040 /* MII Frame Preamble Suppression */
+#define BMSR_ACOMP 0x0020 /* Autonegotiation complete */
+#define BMSR_RFAULT 0x0010 /* Link partner fault */
+#define BMSR_ANEG 0x0008 /* Autonegotiation capable */
+#define BMSR_LINK 0x0004 /* Link status */
+#define BMSR_JABBER 0x0002 /* Jabber detected */
+#define BMSR_EXTCAP 0x0001 /* Extended capability */
+
+/*
+ * Note that the EXTSTAT bit indicates that there is extended status
+ * info available in register 15, but 802.3 section 22.2.4.3 also
+ * states that that all 1000 Mb/s capable PHYs will set this bit to 1.
+ */
+#if 0
+#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX| \
+ BMSR_10THDX|BMSR_ANEG)
+
+#else
+/* NetBSD uses: */
+#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX| \
+ BMSR_10TFDX|BMSR_10THDX|BMSR_100T2FDX|BMSR_100T2HDX)
+#endif
+
+/*
+ * Convert BMSR media capabilities to ANAR bits for autonegotiation.
+ * Note the shift chopps off the BMSR_ANEG bit.
+ */
+#define BMSR_MEDIA_TO_ANAR(x) (((x) & BMSR_MEDIAMASK) >> 6)
+
+#define MII_PHYIDR1 0x02 /* ID register 1 (ro) */
+
+#define MII_PHYIDR2 0x03 /* ID register 2 (ro) */
+#define IDR2_OUILSB 0xfc00 /* OUI LSB */
+#define IDR2_MODEL 0x03f0 /* vendor model */
+#define IDR2_REV 0x000f /* vendor revision */
+
+#define MII_OUI(id1, id2) (((id1) << 6) | ((id2) >> 10))
+#define MII_MODEL(id2) (((id2) & IDR2_MODEL) >> 4)
+#define MII_REV(id2) ((id2) & IDR2_REV)
+
+#define MII_ANAR 0x04 /* Autonegotiation advertisement (rw) */
+ /* section 28.2.4.1 and 37.2.6.1 */
+#define ANAR_NP 0x8000 /* Next page (ro) */
+#define ANAR_ACK 0x4000 /* link partner abilities acknowledged (ro) */
+#define ANAR_RF 0x2000 /* remote fault (ro) */
+#define ANAR_FC 0x0400 /* local device supports PAUSE */
+#define ANAR_T4 0x0200 /* local device supports 100bT4 */
+#define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */
+#define ANAR_TX 0x0080 /* local device supports 100bTx */
+#define ANAR_10_FD 0x0040 /* local device supports 10bT FD */
+#define ANAR_10 0x0020 /* local device supports 10bT */
+#define ANAR_CSMA 0x0001 /* protocol selector CSMA/CD */
+
+#define ANAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */
+#define ANAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */
+#define ANAR_X_PAUSE_NONE (0 << 7)
+#define ANAR_X_PAUSE_SYM (1 << 7)
+#define ANAR_X_PAUSE_ASYM (2 << 7)
+#define ANAR_X_PAUSE_TOWARDS (3 << 7)
+
+#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
+ /* section 28.2.4.1 and 37.2.6.1 */
+#define ANLPAR_NP 0x8000 /* Next page (ro) */
+#define ANLPAR_ACK 0x4000 /* link partner accepted ACK (ro) */
+#define ANLPAR_RF 0x2000 /* remote fault (ro) */
+#define ANLPAR_FC 0x0400 /* link partner supports PAUSE */
+#define ANLPAR_T4 0x0200 /* link partner supports 100bT4 */
+#define ANLPAR_TX_FD 0x0100 /* link partner supports 100bTx FD */
+#define ANLPAR_TX 0x0080 /* link partner supports 100bTx */
+#define ANLPAR_10_FD 0x0040 /* link partner supports 10bT FD */
+#define ANLPAR_10 0x0020 /* link partner supports 10bT */
+#define ANLPAR_CSMA 0x0001 /* protocol selector CSMA/CD */
+
+#define ANLPAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */
+#define ANLPAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */
+#define ANLPAR_X_PAUSE_MASK (3 << 7)
+#define ANLPAR_X_PAUSE_NONE (0 << 7)
+#define ANLPAR_X_PAUSE_SYM (1 << 7)
+#define ANLPAR_X_PAUSE_ASYM (2 << 7)
+#define ANLPAR_X_PAUSE_TOWARDS (3 << 7)
+
+#define MII_ANER 0x06 /* Autonegotiation expansion (ro) */
+ /* section 28.2.4.1 and 37.2.6.1 */
+#define ANER_MLF 0x0010 /* multiple link detection fault */
+#define ANER_LPNP 0x0008 /* link parter next page-able */
+#define ANER_NP 0x0004 /* next page-able */
+#define ANER_PAGE_RX 0x0002 /* Page received */
+#define ANER_LPAN 0x0001 /* link parter autoneg-able */
+
+#define MII_ANNP 0x07 /* Autonegotiation next page */
+ /* section 28.2.4.1 and 37.2.6.1 */
+
+#define MII_ANLPRNP 0x08 /* Autonegotiation link partner rx next page */
+ /* section 32.5.1 and 37.2.6.1 */
+
+ /* This is also the 1000baseT control register */
+#define MII_100T2CR 0x09 /* 100base-T2 control register */
+#define GTCR_TEST_MASK 0xe000 /* see 802.3ab ss. 40.6.1.1.2 */
+#define GTCR_MAN_MS 0x1000 /* enable manual master/slave control */
+#define GTCR_ADV_MS 0x0800 /* 1 = adv. master, 0 = adv. slave */
+#define GTCR_PORT_TYPE 0x0400 /* 1 = DCE, 0 = DTE (NIC) */
+#define GTCR_ADV_1000TFDX 0x0200 /* adv. 1000baseT FDX */
+#define GTCR_ADV_1000THDX 0x0100 /* adv. 1000baseT HDX */
+
+ /* This is also the 1000baseT status register */
+#define MII_100T2SR 0x0a /* 100base-T2 status register */
+#define GTSR_MAN_MS_FLT 0x8000 /* master/slave config fault */
+#define GTSR_MS_RES 0x4000 /* result: 1 = master, 0 = slave */
+#define GTSR_LRS 0x2000 /* local rx status, 1 = ok */
+#define GTSR_RRS 0x1000 /* remove rx status, 1 = ok */
+#define GTSR_LP_1000TFDX 0x0800 /* link partner 1000baseT FDX capable */
+#define GTSR_LP_1000THDX 0x0400 /* link partner 1000baseT HDX capable */
+#define GTSR_LP_ASM_DIR 0x0200 /* link partner asym. pause dir. capable */
+#define GTSR_IDLE_ERR 0x00ff /* IDLE error count */
+
+#define MII_EXTSR 0x0f /* Extended status register */
+#define EXTSR_1000XFDX 0x8000 /* 1000X full-duplex capable */
+#define EXTSR_1000XHDX 0x4000 /* 1000X half-duplex capable */
+#define EXTSR_1000TFDX 0x2000 /* 1000T full-duplex capable */
+#define EXTSR_1000THDX 0x1000 /* 1000T half-duplex capable */
+
+#define EXTSR_MEDIAMASK (EXTSR_1000XFDX|EXTSR_1000XHDX| \
+ EXTSR_1000TFDX|EXTSR_1000THDX)
+
+#endif /* _DEV_MII_MII_H_ */
diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c
new file mode 100644
index 0000000..96e481c
--- /dev/null
+++ b/sys/dev/mii/mii_physubr.c
@@ -0,0 +1,545 @@
+/* $NetBSD: mii_physubr.c,v 1.5 1999/08/03 19:41:49 drochner Exp $ */
+
+/*-
+ * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Subroutines common to all PHYs.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include "miibus_if.h"
+
+/*
+ * Media to register setting conversion table. Order matters.
+ */
+const struct mii_media mii_media_table[MII_NMEDIA] = {
+ /* None */
+ { BMCR_ISO, ANAR_CSMA,
+ 0, },
+
+ /* 10baseT */
+ { BMCR_S10, ANAR_CSMA|ANAR_10,
+ 0, },
+
+ /* 10baseT-FDX */
+ { BMCR_S10|BMCR_FDX, ANAR_CSMA|ANAR_10_FD,
+ 0, },
+
+ /* 100baseT4 */
+ { BMCR_S100, ANAR_CSMA|ANAR_T4,
+ 0, },
+
+ /* 100baseTX */
+ { BMCR_S100, ANAR_CSMA|ANAR_TX,
+ 0, },
+
+ /* 100baseTX-FDX */
+ { BMCR_S100|BMCR_FDX, ANAR_CSMA|ANAR_TX_FD,
+ 0, },
+
+ /* 1000baseX */
+ { BMCR_S1000, ANAR_CSMA,
+ 0, },
+
+ /* 1000baseX-FDX */
+ { BMCR_S1000|BMCR_FDX, ANAR_CSMA,
+ 0, },
+
+ /* 1000baseT */
+ { BMCR_S1000, ANAR_CSMA,
+ GTCR_ADV_1000THDX },
+
+ /* 1000baseT-FDX */
+ { BMCR_S1000, ANAR_CSMA,
+ GTCR_ADV_1000TFDX },
+};
+
+void
+mii_phy_setmedia(struct mii_softc *sc)
+{
+ struct mii_data *mii = sc->mii_pdata;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int bmcr, anar, gtcr;
+
+ if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
+ if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
+ (void) mii_phy_auto(sc);
+ return;
+ }
+
+ /*
+ * Table index is stored in the media entry.
+ */
+
+ KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA,
+ ("invalid ife->ifm_data (0x%x) in mii_phy_setmedia",
+ ife->ifm_data));
+
+ anar = mii_media_table[ife->ifm_data].mm_anar;
+ bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
+ gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
+
+ if (mii->mii_media.ifm_media & IFM_ETH_MASTER) {
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_1000_T:
+ gtcr |= GTCR_MAN_MS|GTCR_ADV_MS;
+ break;
+
+ default:
+ panic("mii_phy_setmedia: MASTER on wrong media");
+ }
+ }
+
+ if (ife->ifm_media & IFM_LOOP)
+ bmcr |= BMCR_LOOP;
+
+ PHY_WRITE(sc, MII_ANAR, anar);
+ PHY_WRITE(sc, MII_BMCR, bmcr);
+ if (sc->mii_flags & MIIF_HAVE_GTCR)
+ PHY_WRITE(sc, MII_100T2CR, gtcr);
+}
+
+int
+mii_phy_auto(struct mii_softc *sc)
+{
+
+ /*
+ * Check for 1000BASE-X. Autonegotiation is a bit
+ * different on such devices.
+ */
+ if (sc->mii_flags & MIIF_IS_1000X) {
+ uint16_t anar = 0;
+
+ if (sc->mii_extcapabilities & EXTSR_1000XFDX)
+ anar |= ANAR_X_FD;
+ if (sc->mii_extcapabilities & EXTSR_1000XHDX)
+ anar |= ANAR_X_HD;
+
+ if (sc->mii_flags & MIIF_DOPAUSE) {
+ /* XXX Asymmetric vs. symmetric? */
+ anar |= ANLPAR_X_PAUSE_TOWARDS;
+ }
+
+ PHY_WRITE(sc, MII_ANAR, anar);
+ } else {
+ uint16_t anar;
+
+ anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) |
+ ANAR_CSMA;
+ if (sc->mii_flags & MIIF_DOPAUSE)
+ anar |= ANAR_FC;
+ PHY_WRITE(sc, MII_ANAR, anar);
+ if (sc->mii_flags & MIIF_HAVE_GTCR) {
+ uint16_t gtcr = 0;
+
+ if (sc->mii_extcapabilities & EXTSR_1000TFDX)
+ gtcr |= GTCR_ADV_1000TFDX;
+ if (sc->mii_extcapabilities & EXTSR_1000THDX)
+ gtcr |= GTCR_ADV_1000THDX;
+
+ PHY_WRITE(sc, MII_100T2CR, gtcr);
+ }
+ }
+ PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
+ return (EJUSTRETURN);
+}
+
+int
+mii_phy_tick(struct mii_softc *sc)
+{
+ struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
+ struct ifnet *ifp = sc->mii_pdata->mii_ifp;
+ int reg;
+
+ /* Just bail now if the interface is down. */
+ if ((ifp->if_flags & IFF_UP) == 0)
+ return (EJUSTRETURN);
+
+ /*
+ * If we're not doing autonegotiation, we don't need to do
+ * any extra work here. However, we need to check the link
+ * status so we can generate an announcement if the status
+ * changes.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /* Read the status register twice; BMSR_LINK is latch-low. */
+ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
+ if (reg & BMSR_LINK) {
+ /*
+ * See above.
+ */
+ return (0);
+ }
+
+ /*
+ * Only retry autonegotiation every N seconds.
+ */
+ if (sc->mii_anegticks == 0)
+ sc->mii_anegticks = 17;
+ if (++sc->mii_ticks != sc->mii_anegticks)
+ return (EJUSTRETURN);
+
+ sc->mii_ticks = 0;
+ mii_phy_reset(sc);
+ mii_phy_auto(sc);
+ return (0);
+}
+
+void
+mii_phy_reset(struct mii_softc *sc)
+{
+ int reg, i;
+
+ if (sc->mii_flags & MIIF_NOISOLATE)
+ reg = BMCR_RESET;
+ else
+ reg = BMCR_RESET | BMCR_ISO;
+ PHY_WRITE(sc, MII_BMCR, reg);
+
+ /* Wait 100ms for it to complete. */
+ for (i = 0; i < 100; i++) {
+ reg = PHY_READ(sc, MII_BMCR);
+ if ((reg & BMCR_RESET) == 0)
+ break;
+ DELAY(1000);
+ }
+
+ if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE) == 0))
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+}
+
+void
+mii_phy_down(struct mii_softc *sc)
+{
+
+}
+
+void
+mii_phy_update(struct mii_softc *sc, int cmd)
+{
+ struct mii_data *mii = sc->mii_pdata;
+
+ if (sc->mii_media_active != mii->mii_media_active ||
+ cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_media_active = mii->mii_media_active;
+ }
+ if (sc->mii_media_status != mii->mii_media_status) {
+ MIIBUS_LINKCHG(sc->mii_dev);
+ sc->mii_media_status = mii->mii_media_status;
+ }
+}
+
+/*
+ * Given an ifmedia word, return the corresponding ANAR value.
+ */
+int
+mii_anar(media)
+ int media;
+{
+ int rv;
+
+ switch (media & (IFM_TMASK|IFM_NMASK|IFM_FDX)) {
+ case IFM_ETHER|IFM_10_T:
+ rv = ANAR_10|ANAR_CSMA;
+ break;
+ case IFM_ETHER|IFM_10_T|IFM_FDX:
+ rv = ANAR_10_FD|ANAR_CSMA;
+ break;
+ case IFM_ETHER|IFM_100_TX:
+ rv = ANAR_TX|ANAR_CSMA;
+ break;
+ case IFM_ETHER|IFM_100_TX|IFM_FDX:
+ rv = ANAR_TX_FD|ANAR_CSMA;
+ break;
+ case IFM_ETHER|IFM_100_T4:
+ rv = ANAR_T4|ANAR_CSMA;
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+ return (rv);
+}
+
+/*
+ * Given a BMCR value, return the corresponding ifmedia word.
+ */
+int
+mii_media_from_bmcr(bmcr)
+ int bmcr;
+{
+ int rv = IFM_ETHER;
+
+ if (bmcr & BMCR_S100)
+ rv |= IFM_100_TX;
+ else
+ rv |= IFM_10_T;
+ if (bmcr & BMCR_FDX)
+ rv |= IFM_FDX;
+
+ return (rv);
+}
+
+/*
+ * Initialize generic PHY media based on BMSR, called when a PHY is
+ * attached. We expect to be set up to print a comma-separated list
+ * of media names. Does not print a newline.
+ */
+void
+mii_add_media(struct mii_softc *sc)
+{
+ const char *sep = "";
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->mii_dev);
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) {
+ printf("no media present");
+ return;
+ }
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+#define PRINT(s) printf("%s%s", sep, s); sep = ", "
+
+ if (sc->mii_capabilities & BMSR_10THDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 0);
+ PRINT("10baseT");
+ }
+ if (sc->mii_capabilities & BMSR_10TFDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
+ BMCR_FDX);
+ PRINT("10baseT-FDX");
+ }
+ if (sc->mii_capabilities & BMSR_100TXHDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
+ BMCR_S100);
+ PRINT("100baseTX");
+ }
+ if (sc->mii_capabilities & BMSR_100TXFDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
+ BMCR_S100|BMCR_FDX);
+ PRINT("100baseTX-FDX");
+ }
+ if (sc->mii_capabilities & BMSR_100T4) {
+ /*
+ * XXX How do you enable 100baseT4? I assume we set
+ * XXX BMCR_S100 and then assume the PHYs will take
+ * XXX watever action is necessary to switch themselves
+ * XXX into T4 mode.
+ */
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
+ BMCR_S100);
+ PRINT("100baseT4");
+ }
+ if (sc->mii_capabilities & BMSR_ANEG) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
+ BMCR_AUTOEN);
+ PRINT("auto");
+ }
+
+
+
+#undef ADD
+#undef PRINT
+}
+
+/*
+ * Initialize generic PHY media based on BMSR, called when a PHY is
+ * attached. We expect to be set up to print a comma-separated list
+ * of media names. Does not print a newline.
+ */
+void
+mii_phy_add_media(struct mii_softc *sc)
+{
+ struct mii_data *mii = sc->mii_pdata;
+ const char *sep = "";
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+#define PRINT(s) printf("%s%s", sep, s); sep = ", "
+
+ if ((sc->mii_flags & MIIF_NOISOLATE) == 0)
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ MII_MEDIA_NONE);
+
+ /*
+ * There are different interpretations for the bits in
+ * HomePNA PHYs. And there is really only one media type
+ * that is supported.
+ */
+ if (sc->mii_flags & MIIF_IS_HPNA) {
+ if (sc->mii_capabilities & BMSR_10THDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0,
+ sc->mii_inst),
+ MII_MEDIA_10_T);
+ PRINT("HomePNA1");
+ }
+ return;
+ }
+
+ if (sc->mii_capabilities & BMSR_10THDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
+ MII_MEDIA_10_T);
+ PRINT("10baseT");
+ }
+ if (sc->mii_capabilities & BMSR_10TFDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
+ MII_MEDIA_10_T_FDX);
+ PRINT("10baseT-FDX");
+ }
+ if (sc->mii_capabilities & BMSR_100TXHDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
+ MII_MEDIA_100_TX);
+ PRINT("100baseTX");
+ }
+ if (sc->mii_capabilities & BMSR_100TXFDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
+ MII_MEDIA_100_TX_FDX);
+ PRINT("100baseTX-FDX");
+ }
+ if (sc->mii_capabilities & BMSR_100T4) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
+ MII_MEDIA_100_T4);
+ PRINT("100baseT4");
+ }
+
+ if (sc->mii_extcapabilities & EXTSR_MEDIAMASK) {
+ /*
+ * XXX Right now only handle 1000SX and 1000TX. Need
+ * XXX to handle 1000LX and 1000CX some how.
+ *
+ * Note since it can take 5 seconds to auto-negotiate
+ * a gigabit link, we make anegticks 10 seconds for
+ * all the gigabit media types.
+ */
+ if (sc->mii_extcapabilities & EXTSR_1000XHDX) {
+ sc->mii_anegticks = 17;
+ sc->mii_flags |= MIIF_IS_1000X;
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
+ sc->mii_inst), MII_MEDIA_1000_X);
+ PRINT("1000baseSX");
+ }
+ if (sc->mii_extcapabilities & EXTSR_1000XFDX) {
+ sc->mii_anegticks = 17;
+ sc->mii_flags |= MIIF_IS_1000X;
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
+ sc->mii_inst), MII_MEDIA_1000_X_FDX);
+ PRINT("1000baseSX-FDX");
+ }
+
+ /*
+ * 1000baseT media needs to be able to manipulate
+ * master/slave mode. We set IFM_ETH_MASTER in
+ * the "don't care mask" and filter it out when
+ * the media is set.
+ *
+ * All 1000baseT PHYs have a 1000baseT control register.
+ */
+ if (sc->mii_extcapabilities & EXTSR_1000THDX) {
+ sc->mii_anegticks = 17;
+ sc->mii_flags |= MIIF_HAVE_GTCR;
+ mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
+ sc->mii_inst), MII_MEDIA_1000_T);
+ PRINT("1000baseT");
+ }
+ if (sc->mii_extcapabilities & EXTSR_1000TFDX) {
+ sc->mii_anegticks = 17;
+ sc->mii_flags |= MIIF_HAVE_GTCR;
+ mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
+ sc->mii_inst), MII_MEDIA_1000_T_FDX);
+ PRINT("1000baseT-FDX");
+ }
+ }
+
+ if (sc->mii_capabilities & BMSR_ANEG) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
+ MII_NMEDIA); /* intentionally invalid index */
+ PRINT("auto");
+ }
+#undef ADD
+#undef PRINT
+}
+
+int
+mii_phy_detach(device_t dev)
+{
+ struct mii_softc *sc;
+
+ sc = device_get_softc(dev);
+ mii_phy_down(sc);
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+
+const struct mii_phydesc *
+mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd)
+{
+
+ for (; mpd->mpd_name != NULL; mpd++) {
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui &&
+ MII_MODEL(ma->mii_id2) == mpd->mpd_model)
+ return (mpd);
+ }
+ return (NULL);
+}
diff --git a/sys/dev/mii/miibus_if.m b/sys/dev/mii/miibus_if.m
new file mode 100644
index 0000000..017812f
--- /dev/null
+++ b/sys/dev/mii/miibus_if.m
@@ -0,0 +1,45 @@
+# $FreeBSD$
+
+#include <sys/bus.h>
+
+INTERFACE miibus;
+
+#
+# Read register from device on MII bus
+#
+METHOD int readreg {
+ device_t dev;
+ int phy;
+ int reg;
+};
+
+#
+# Write register to device on MII bus
+#
+METHOD int writereg {
+ device_t dev;
+ int phy;
+ int reg;
+ int val;
+};
+
+#
+# Notify bus about PHY status change.
+#
+METHOD void statchg {
+ device_t dev;
+};
+
+#
+# Notify bus about PHY link change.
+#
+METHOD void linkchg {
+ device_t dev;
+};
+
+#
+# Notify bus that media has been set.
+#
+METHOD void mediainit {
+ device_t dev;
+};
diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs
new file mode 100644
index 0000000..1f58417
--- /dev/null
+++ b/sys/dev/mii/miidevs
@@ -0,0 +1,176 @@
+$FreeBSD$
+/*$NetBSD: miidevs,v 1.6 1999/05/14 11:37:30 drochner Exp $*/
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * List of known MII OUIs.
+ * For a complete list see http://standards.ieee.org/regauth/oui/
+ *
+ * XXX Vendors do obviously not agree how OUIs (18 bit) are mapped
+ * to the 16 bits available in the id registers. The MII_OUI() macro
+ * in "mii.h" reflects the most obvious way. If a vendor uses a
+ * different mapping, an "xx" prefixed OUI is defined here which is
+ * mangled accordingly to compensate.
+ */
+
+oui ALTIMA 0x0010a9 Altima Communications
+oui AMD 0x00001a Advanced Micro Devices
+oui BROADCOM 0x001018 Broadcom Corporation
+oui DAVICOM 0x00606e Davicom Semiconductor
+oui ICS 0x00a0be Integrated Circuit Systems
+oui INTEL 0x00aa00 Intel
+oui JATO 0x00e083 Jato Technologies
+oui LEVEL1 0x00207b Level 1
+oui NATSEMI 0x080017 National Semiconductor
+oui QUALSEMI 0x006051 Quality Semiconductor
+oui REALTEK 0x000020 RealTek Semicondctor
+oui SEEQ 0x00a07d Seeq
+oui SIS 0x00e006 Silicon Integrated Systems
+oui TDK 0x00c039 TDK
+oui TI 0x080028 Texas Instruments
+oui XAQTI 0x00e0ae XaQti Corp.
+oui MARVELL 0x005043 Marvell Semiconductor
+oui xxMARVELL 0x000ac2 Marvell Semiconductor
+
+/* in the 79c873, AMD uses another OUI (which matches Davicom!) */
+oui xxAMD 0x00606e Advanced Micro Devices
+
+/* Intel 82553 A/B steppings */
+oui xxINTEL 0x00f800 Intel
+
+/* some vendors have the bits swapped within bytes
+ (ie, ordered as on the wire) */
+oui xxALTIMA 0x000895 Altima Communications
+oui xxBROADCOM 0x000818 Broadcom Corporation
+oui xxICS 0x00057d Integrated Circuit Systems
+oui xxSEEQ 0x0005be Seeq
+oui xxSIS 0x000760 Silicon Integrated Systems
+oui xxTI 0x100014 Texas Instruments
+oui xxXAQTI 0x350700 XaQti Corp.
+
+/* Level 1 is completely different - from right to left.
+ (Two bits get lost in the third OUI byte.) */
+oui xxLEVEL1 0x1e0400 Level 1
+
+/* Don't know what's going on here. */
+oui xxDAVICOM 0x006040 Davicom Semiconductor
+
+/* This is the OUI of the gigE PHY in the RealTek 8169S/8110S chips */
+oui xxREALTEK 0x000732
+
+/*
+ * List of known models. Grouped by oui.
+ */
+
+/* Altima Communications PHYs */
+model xxALTIMA AC101 0x0021 AC101 10/100 media interface
+model xxALTIMA AC101L 0x0012 AC101L 10/100 media interface
+
+/* Advanced Micro Devices PHYs */
+model xxAMD 79C873 0x0000 Am79C873 10/100 media interface
+model AMD 79c973phy 0x0036 Am79c973 internal PHY
+model AMD 79c978 0x0039 Am79c978 HomePNA PHY
+
+/* Broadcom Corp. PHYs. */
+model BROADCOM 3C905B 0x0012 3c905B 10/100 internal PHY
+model BROADCOM 3C905C 0x0017 3c905C 10/100 internal PHY
+model BROADCOM BCM5201 0x0021 BCM5201 10/100baseTX PHY
+model BROADCOM BCM5221 0x001e BCM5221 10/100baseTX PHY
+model BROADCOM BCM4401 0x0036 BCM4401 10/100baseTX PHY
+model xxBROADCOM BCM5400 0x0004 Broadcom 1000baseTX PHY
+model xxBROADCOM BCM5401 0x0005 BCM5401 10/100/1000baseTX PHY
+model xxBROADCOM BCM5411 0x0007 BCM5411 10/100/1000baseTX PHY
+model xxBROADCOM BCM5701 0x0011 BCM5701 10/100/1000baseTX PHY
+model xxBROADCOM BCM5703 0x0016 BCM5703 10/100/1000baseTX PHY
+model xxBROADCOM BCM5704 0x0019 BCM5704 10/100/1000baseTX PHY
+model xxBROADCOM BCM5705 0x001a BCM5705 10/100/1000baseTX PHY
+
+/* Davicom Semiconductor PHYs */
+model xxDAVICOM DM9101 0x0000 DM9101 10/100 media interface
+
+/* Integrated Circuit Systems PHYs */
+model xxICS 1890 0x0002 ICS1890 10/100 media interface
+
+/* Intel PHYs */
+model xxINTEL I82553AB 0x0000 i83553 10/100 media interface
+model INTEL I82555 0x0015 i82555 10/100 media interface
+model INTEL I82562EM 0x0032 i82562EM 10/100 media interface
+model INTEL I82562ET 0x0033 i82562ET 10/100 media interface
+model INTEL I82553C 0x0035 i82553 10/100 media interface
+
+/* Jato Technologies PHYs */
+model JATO BASEX 0x0000 Jato 1000baseX media interface
+
+/* Level 1 PHYs */
+model xxLEVEL1 LXT970 0x0000 LXT970 10/100 media interface
+
+/* National Semiconductor PHYs */
+model NATSEMI DP83840 0x0000 DP83840 10/100 media interface
+model NATSEMI DP83843 0x0001 DP83843 10/100 media interface
+model NATSEMI DP83891 0x0005 DP83891 10/100/1000 media interface
+model NATSEMI DP83861 0x0006 DP83861 10/100/1000 media interface
+
+/* Quality Semiconductor PHYs */
+model QUALSEMI QS6612 0x0000 QS6612 10/100 media interface
+
+/* RealTek Semiconductor PHYs */
+model REALTEK RTL8201L 0x0020 RTL8201L 10/100 media interface
+model xxREALTEK RTL8169S 0x0011 RTL8169S/8110S media interface
+
+/* Seeq PHYs */
+model xxSEEQ 80220 0x0003 Seeq 80220 10/100 media interface
+model xxSEEQ 84220 0x0004 Seeq 84220 10/100 media interface
+
+/* Silicon Integrated Systems PHYs */
+model xxSIS 900 0x0000 SiS 900 10/100 media interface
+
+/* TDK */
+model TDK 78Q2120 0x0014 TDK 78Q2120 media interface
+
+/* Texas Instruments PHYs */
+model xxTI TLAN10T 0x0001 ThunderLAN 10baseT media interface
+model xxTI 100VGPMI 0x0002 ThunderLAN 100VG-AnyLan media interface
+
+/* XaQti Corp. PHYs. */
+model XAQTI XMACII 0x0000 XaQti Corp. XMAC II gigabit interface
+
+/* Marvell Semiconductor PHYs */
+model MARVELL E1000 0x0000 Marvell 88E1000 Gigabit PHY
+model MARVELL E1011 0x0002 Marvell 88E1011 Gigabit PHY
+model xxMARVELL E1000 0x0005 Marvell 88E1000 Gigabit PHY
diff --git a/sys/dev/mii/miivar.h b/sys/dev/mii/miivar.h
new file mode 100644
index 0000000..f6c759c
--- /dev/null
+++ b/sys/dev/mii/miivar.h
@@ -0,0 +1,225 @@
+/* $NetBSD: miivar.h,v 1.8 1999/04/23 04:24:32 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_MIIVAR_H_
+#define _DEV_MII_MIIVAR_H_
+
+#include <sys/queue.h>
+
+/*
+ * Media Independent Interface configuration defintions.
+ */
+
+struct mii_softc;
+
+/*
+ * Callbacks from MII layer into network interface device driver.
+ */
+typedef int (*mii_readreg_t)(struct device *, int, int);
+typedef void (*mii_writereg_t)(struct device *, int, int, int);
+typedef void (*mii_statchg_t)(struct device *);
+
+/*
+ * A network interface driver has one of these structures in its softc.
+ * It is the interface from the network interface driver to the MII
+ * layer.
+ */
+struct mii_data {
+ struct ifmedia mii_media; /* media information */
+ struct ifnet *mii_ifp; /* pointer back to network interface */
+
+ /*
+ * For network interfaces with multiple PHYs, a list of all
+ * PHYs is required so they can all be notified when a media
+ * request is made.
+ */
+ LIST_HEAD(mii_listhead, mii_softc) mii_phys;
+ int mii_instance;
+
+ /*
+ * PHY driver fills this in with active media status.
+ */
+ int mii_media_status;
+ int mii_media_active;
+
+ /*
+ * Calls from MII layer into network interface driver.
+ */
+ mii_readreg_t mii_readreg;
+ mii_writereg_t mii_writereg;
+ mii_statchg_t mii_statchg;
+};
+typedef struct mii_data mii_data_t;
+
+/*
+ * This call is used by the MII layer to call into the PHY driver
+ * to perform a `service request'.
+ */
+typedef int (*mii_downcall_t)(struct mii_softc *, struct mii_data *, int);
+
+/*
+ * Requests that can be made to the downcall.
+ */
+#define MII_TICK 1 /* once-per-second tick */
+#define MII_MEDIACHG 2 /* user changed media; perform the switch */
+#define MII_POLLSTAT 3 /* user requested media status; fill it in */
+
+/*
+ * Each PHY driver's softc has one of these as the first member.
+ * XXX This would be better named "phy_softc", but this is the name
+ * XXX BSDI used, and we would like to have the same interface.
+ */
+struct mii_softc {
+ device_t mii_dev; /* generic device glue */
+
+ LIST_ENTRY(mii_softc) mii_list; /* entry on parent's PHY list */
+
+ int mii_phy; /* our MII address */
+ int mii_inst; /* instance for ifmedia */
+
+ mii_downcall_t mii_service; /* our downcall */
+ struct mii_data *mii_pdata; /* pointer to parent's mii_data */
+
+ int mii_flags; /* misc. flags; see below */
+ int mii_capabilities; /* capabilities from BMSR */
+ int mii_extcapabilities; /* extended capabilities */
+ int mii_ticks; /* MII_TICK counter */
+ int mii_anegticks; /* ticks before retrying aneg */
+ int mii_media_active; /* last active media */
+ int mii_media_status; /* last active status */
+};
+typedef struct mii_softc mii_softc_t;
+
+/* mii_flags */
+#define MIIF_INITDONE 0x0001 /* has been initialized (mii_data) */
+#define MIIF_NOISOLATE 0x0002 /* do not isolate the PHY */
+#define MIIF_NOLOOP 0x0004 /* no loopback capability */
+#define MIIF_AUTOTSLEEP 0x0010 /* use tsleep(), not callout() */
+#define MIIF_HAVEFIBER 0x0020 /* from parent: has fiber interface */
+#define MIIF_HAVE_GTCR 0x0040 /* has 100base-T2/1000base-T CR */
+#define MIIF_IS_1000X 0x0080 /* is a 1000BASE-X device */
+#define MIIF_DOPAUSE 0x0100 /* advertise PAUSE capability */
+#define MIIF_IS_HPNA 0x0200 /* is a HomePNA device */
+
+#define MIIF_INHERIT_MASK (MIIF_NOISOLATE|MIIF_NOLOOP|MIIF_AUTOTSLEEP)
+
+/*
+ * Used to attach a PHY to a parent.
+ */
+struct mii_attach_args {
+ struct mii_data *mii_data; /* pointer to parent data */
+ int mii_phyno; /* MII address */
+ int mii_id1; /* PHY ID register 1 */
+ int mii_id2; /* PHY ID register 2 */
+ int mii_capmask; /* capability mask from BMSR */
+};
+typedef struct mii_attach_args mii_attach_args_t;
+
+/*
+ * Used to match a PHY.
+ */
+struct mii_phydesc {
+ u_int32_t mpd_oui; /* the PHY's OUI */
+ u_int32_t mpd_model; /* the PHY's model */
+ const char *mpd_name; /* the PHY's name */
+};
+
+/*
+ * An array of these structures map MII media types to BMCR/ANAR settings.
+ */
+struct mii_media {
+ int mm_bmcr; /* BMCR settings for this media */
+ int mm_anar; /* ANAR settings for this media */
+ int mm_gtcr; /* 100base-T2 or 1000base-T CR */
+};
+
+#define MII_MEDIA_NONE 0
+#define MII_MEDIA_10_T 1
+#define MII_MEDIA_10_T_FDX 2
+#define MII_MEDIA_100_T4 3
+#define MII_MEDIA_100_TX 4
+#define MII_MEDIA_100_TX_FDX 5
+#define MII_MEDIA_1000_X 6
+#define MII_MEDIA_1000_X_FDX 7
+#define MII_MEDIA_1000_T 8
+#define MII_MEDIA_1000_T_FDX 9
+#define MII_NMEDIA 10
+
+#ifdef _KERNEL
+
+#define PHY_READ(p, r) \
+ MIIBUS_READREG((p)->mii_dev, (p)->mii_phy, (r))
+
+#define PHY_WRITE(p, r, v) \
+ MIIBUS_WRITEREG((p)->mii_dev, (p)->mii_phy, (r), (v))
+
+extern devclass_t miibus_devclass;
+extern driver_t miibus_driver;
+
+int miibus_probe(device_t);
+int miibus_attach(device_t);
+int miibus_detach(device_t);
+
+int mii_anar(int);
+void mii_down(struct mii_data *);
+int mii_mediachg(struct mii_data *);
+void mii_tick(struct mii_data *);
+void mii_pollstat(struct mii_data *);
+int mii_phy_probe(device_t, device_t *, ifm_change_cb_t, ifm_stat_cb_t);
+void mii_add_media(struct mii_softc *);
+void mii_phy_add_media(struct mii_softc *);
+
+int mii_media_from_bmcr(int);
+
+int mii_phy_auto(struct mii_softc *);
+int mii_phy_detach(device_t dev);
+void mii_phy_down(struct mii_softc *);
+void mii_phy_reset(struct mii_softc *);
+void mii_phy_setmedia(struct mii_softc *sc);
+void mii_phy_update(struct mii_softc *, int);
+int mii_phy_tick(struct mii_softc *);
+
+const struct mii_phydesc * mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd);
+
+void ukphy_status(struct mii_softc *);
+#endif /* _KERNEL */
+
+#endif /* _DEV_MII_MIIVAR_H_ */
diff --git a/sys/dev/mii/mlphy.c b/sys/dev/mii/mlphy.c
new file mode 100644
index 0000000..744d3c3
--- /dev/null
+++ b/sys/dev/mii/mlphy.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * driver for Micro Linear 6692 PHYs
+ *
+ * The Micro Linear 6692 is a strange beast, and dealing with it using
+ * this code framework is tricky. The 6692 is actually a 100Mbps-only
+ * device, which means that a second PHY is required to support 10Mbps
+ * modes. However, even though the 6692 does not support 10Mbps modes,
+ * it can still advertise them when performing autonegotiation. If a
+ * 10Mbps mode is negotiated, we must program the registers of the
+ * companion PHY accordingly in addition to programming the registers
+ * of the 6692.
+ *
+ * This device also does not have vendor/device ID registers.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include "miibus_if.h"
+
+#define ML_STATE_AUTO_SELF 1
+#define ML_STATE_AUTO_OTHER 2
+
+struct mlphy_softc {
+ struct mii_softc ml_mii;
+ int ml_state;
+ int ml_linked;
+};
+
+static int mlphy_probe(device_t);
+static int mlphy_attach(device_t);
+
+static device_method_t mlphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, mlphy_probe),
+ DEVMETHOD(device_attach, mlphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t mlphy_devclass;
+
+static driver_t mlphy_driver = {
+ "mlphy",
+ mlphy_methods,
+ sizeof(struct mlphy_softc)
+};
+
+DRIVER_MODULE(mlphy, miibus, mlphy_driver, mlphy_devclass, 0, 0);
+
+static int mlphy_service(struct mii_softc *, struct mii_data *, int);
+static void mlphy_reset(struct mii_softc *);
+static void mlphy_status(struct mii_softc *);
+
+static int
+mlphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+ device_t parent;
+
+ ma = device_get_ivars(dev);
+ parent = device_get_parent(device_get_parent(dev));
+
+ /*
+ * Micro Linear PHY reports oui == 0 model == 0
+ */
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
+ MII_MODEL(ma->mii_id2) != 0)
+ return (ENXIO);
+
+ /*
+ * Make sure the parent is a `tl'. So far, I have only
+ * encountered the 6692 on an Olicom card with a ThunderLAN
+ * controller chip.
+ */
+ if (strcmp(device_get_name(parent), "tl") != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Micro Linear 6692 media interface");
+
+ return (0);
+}
+
+static int
+mlphy_attach(dev)
+ device_t dev;
+{
+ struct mlphy_softc *msc;
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ msc = device_get_softc(dev);
+ sc = &msc->ml_mii;
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = mlphy_service;
+ sc->mii_pdata = mii;
+
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+#if 0 /* See above. */
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+#endif
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+
+ sc->mii_flags &= ~MIIF_NOISOLATE;
+ mii_phy_reset(sc);
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ ma->mii_capmask = ~sc->mii_capabilities;
+ device_printf(dev, " ");
+ mii_add_media(sc);
+ printf("\n");
+#undef ADD
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+mlphy_service(xsc, mii, cmd)
+ struct mii_softc *xsc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+ struct mii_softc *other = NULL;
+ struct mlphy_softc *msc = (struct mlphy_softc *)xsc;
+ struct mii_softc *sc = (struct mii_softc *)&msc->ml_mii;
+ device_t *devlist;
+ int devs, i;
+
+ /*
+ * See if there's another PHY on this bus with us.
+ * If so, we may need it for 10Mbps modes.
+ */
+ device_get_children(msc->ml_mii.mii_dev, &devlist, &devs);
+ for (i = 0; i < devs; i++) {
+ if (strcmp(device_get_name(devlist[i]), "mlphy")) {
+ other = device_get_softc(devlist[i]);
+ break;
+ }
+ }
+ free(devlist, M_TEMP);
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * For autonegotiation, reset and isolate the
+ * companion PHY (if any) and then do NWAY
+ * autonegotiation ourselves.
+ */
+ msc->ml_state = ML_STATE_AUTO_SELF;
+ if (other != NULL) {
+ mii_phy_reset(other);
+ PHY_WRITE(other, MII_BMCR, BMCR_ISO);
+ }
+ (void) mii_phy_auto(sc);
+ msc->ml_linked = 0;
+ return(0);
+ case IFM_10_T:
+ /*
+ * For 10baseT modes, reset and program the
+ * companion PHY (of any), then program ourselves
+ * to match. This will put us in pass-through
+ * mode and let the companion PHY do all the
+ * work.
+ *
+ * BMCR data is stored in the ifmedia entry.
+ */
+ if (other != NULL) {
+ mii_phy_reset(other);
+ PHY_WRITE(other, MII_BMCR, ife->ifm_data);
+ }
+ PHY_WRITE(sc, MII_ANAR, mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ msc->ml_state = 0;
+ break;
+ case IFM_100_TX:
+ /*
+ * For 100baseTX modes, reset and isolate the
+ * companion PHY (if any), then program ourselves
+ * accordingly.
+ *
+ * BMCR data is stored in the ifmedia entry.
+ */
+ if (other != NULL) {
+ mii_phy_reset(other);
+ PHY_WRITE(other, MII_BMCR, BMCR_ISO);
+ }
+ PHY_WRITE(sc, MII_ANAR, mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ msc->ml_state = 0;
+ break;
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ default:
+ break;
+
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * Check to see if we have link. If we do, we don't
+ * need to restart the autonegotiation process. Read
+ * the BMSR twice in case it's latched.
+ * If we're in a 10Mbps mode, check the link of the
+ * 10Mbps PHY. Sometimes the Micro Linear PHY's
+ * linkstat bit will clear while the linkstat bit of
+ * the companion PHY will remain set.
+ */
+ if (msc->ml_state == ML_STATE_AUTO_OTHER) {
+ reg = PHY_READ(other, MII_BMSR) |
+ PHY_READ(other, MII_BMSR);
+ } else {
+ reg = PHY_READ(sc, MII_BMSR) |
+ PHY_READ(sc, MII_BMSR);
+ }
+
+ if (reg & BMSR_LINK) {
+ if (!msc->ml_linked) {
+ msc->ml_linked = 1;
+ mlphy_status(sc);
+ }
+ break;
+ }
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (0);
+
+ sc->mii_ticks = 0;
+ msc->ml_linked = 0;
+ mii->mii_media_active = IFM_NONE;
+ mii_phy_reset(sc);
+ msc->ml_state = ML_STATE_AUTO_SELF;
+ if (other != NULL) {
+ mii_phy_reset(other);
+ PHY_WRITE(other, MII_BMCR, BMCR_ISO);
+ }
+ mii_phy_auto(sc);
+ return(0);
+ }
+
+ /* Update the media status. */
+
+ if (msc->ml_state == ML_STATE_AUTO_OTHER) {
+ int other_inst;
+ other_inst = other->mii_inst;
+ other->mii_inst = sc->mii_inst;
+ (void) (*other->mii_service)(other, mii, MII_POLLSTAT);
+ other->mii_inst = other_inst;
+ sc->mii_media_active = other->mii_media_active;
+ sc->mii_media_status = other->mii_media_status;
+ } else
+ ukphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+/*
+ * The Micro Linear PHY comes out of reset with the 'autoneg
+ * enable' bit set, which we don't want.
+ */
+static void
+mlphy_reset(sc)
+ struct mii_softc *sc;
+{
+ int reg;
+
+ mii_phy_reset(sc);
+ reg = PHY_READ(sc, MII_BMCR);
+ reg &= ~BMCR_AUTOEN;
+ PHY_WRITE(sc, MII_BMCR, reg);
+
+ return;
+}
+
+/*
+ * If we negotiate a 10Mbps mode, we need to check for an alternate
+ * PHY and make sure it's enabled and set correctly.
+ */
+static void
+mlphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mlphy_softc *msc = (struct mlphy_softc *)sc;
+ struct mii_data *mii = msc->ml_mii.mii_pdata;
+ struct mii_softc *other = NULL;
+ device_t *devlist;
+ int devs, i;
+
+ /* See if there's another PHY on the bus with us. */
+ device_get_children(msc->ml_mii.mii_dev, &devlist, &devs);
+ for (i = 0; i < devs; i++) {
+ if (strcmp(device_get_name(devlist[i]), "mlphy")) {
+ other = device_get_softc(devlist[i]);
+ break;
+ }
+ }
+ free(devlist, M_TEMP);
+
+ if (other == NULL)
+ return;
+
+ ukphy_status(sc);
+
+ if (IFM_SUBTYPE(mii->mii_media_active) != IFM_10_T) {
+ msc->ml_state = ML_STATE_AUTO_SELF;
+ mii_phy_reset(other);
+ PHY_WRITE(other, MII_BMCR, BMCR_ISO);
+ }
+
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) {
+ msc->ml_state = ML_STATE_AUTO_OTHER;
+ mlphy_reset(&msc->ml_mii);
+ PHY_WRITE(&msc->ml_mii, MII_BMCR, BMCR_ISO);
+ mii_phy_reset(other);
+ mii_phy_auto(other);
+ }
+
+ return;
+}
diff --git a/sys/dev/mii/nsgphy.c b/sys/dev/mii/nsgphy.c
new file mode 100644
index 0000000..0cd6133
--- /dev/null
+++ b/sys/dev/mii/nsgphy.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2001 Wind River Systems
+ * Copyright (c) 2001
+ * Bill Paul <wpaul@bsdi.com>. All rights reserved.
+ * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Driver for the National Semiconductor DP83891 and DP83861
+ * 10/100/1000 PHYs.
+ * Datasheet available at: http://www.national.com/ds/DP/DP83861.pdf
+ *
+ * The DP83891 is the older NatSemi gigE PHY which isn't being sold
+ * anymore. The DP83861 is its replacement, which is an 'enhanced'
+ * firmware driven component. The major difference between the
+ * two is that the 83891 can't generate interrupts, while the
+ * 83861 can. (I think it wasn't originally designed to do this, but
+ * it can now thanks to firmware updates.) The 83861 also allows
+ * access to its internal RAM via indirect register access.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+
+#include <machine/clock.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/nsgphyreg.h>
+
+#include "miibus_if.h"
+
+static int nsgphy_probe(device_t);
+static int nsgphy_attach(device_t);
+
+static device_method_t nsgphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, nsgphy_probe),
+ DEVMETHOD(device_attach, nsgphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t nsgphy_devclass;
+
+static driver_t nsgphy_driver = {
+ "nsgphy",
+ nsgphy_methods,
+ sizeof(struct mii_softc)
+};
+
+
+DRIVER_MODULE(nsgphy, miibus, nsgphy_driver, nsgphy_devclass, 0, 0);
+
+static int nsgphy_service(struct mii_softc *, struct mii_data *,int);
+static void nsgphy_status(struct mii_softc *);
+
+const struct mii_phydesc gphyters[] = {
+ { MII_OUI_NATSEMI, MII_MODEL_NATSEMI_DP83861,
+ MII_STR_NATSEMI_DP83861 },
+
+ { MII_OUI_NATSEMI, MII_MODEL_NATSEMI_DP83891,
+ MII_STR_NATSEMI_DP83891 },
+
+ { 0, 0,
+ NULL },
+};
+
+static int
+nsgphy_probe(device_t dev)
+{
+ struct mii_attach_args *ma;
+ const struct mii_phydesc *mpd;
+
+ ma = device_get_ivars(dev);
+ mpd = mii_phy_match(ma, gphyters);
+ if (mpd != NULL) {
+ device_set_desc(dev, mpd->mpd_name);
+ return(0);
+ }
+
+ return(ENXIO);
+}
+
+static int
+nsgphy_attach(device_t dev)
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ if (bootverbose)
+ device_printf(dev, "<rev. %d>\n", MII_REV(ma->mii_id2));
+ device_printf(dev, " ");
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = nsgphy_service;
+ sc->mii_pdata = mii;
+ sc->mii_anegticks = 5;
+
+ mii->mii_instance++;
+
+ sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) |
+ (BMSR_10TFDX|BMSR_10THDX)) & ma->mii_capmask;
+ if (sc->mii_capabilities & BMSR_EXTSTAT)
+ sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
+
+ mii_phy_add_media(sc);
+ printf("\n");
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+nsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ mii_phy_setmedia(sc);
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ if (mii_phy_tick(sc) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ nsgphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+nsgphy_status(struct mii_softc *sc)
+{
+ struct mii_data *mii = sc->mii_pdata;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int bmsr, bmcr, physup, gtsr;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
+
+ physup = PHY_READ(sc, NSGPHY_MII_PHYSUP);
+
+ if (physup & PHY_SUP_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(sc, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BMCR_AUTOEN) {
+ /*
+ * The media status bits are only valid if autonegotiation
+ * has completed (or it's disabled).
+ */
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ switch (physup & (PHY_SUP_SPEED1|PHY_SUP_SPEED0)) {
+ case PHY_SUP_SPEED1:
+ mii->mii_media_active |= IFM_1000_T;
+ gtsr = PHY_READ(sc, MII_100T2SR);
+ if (gtsr & GTSR_MS_RES)
+ mii->mii_media_active |= IFM_ETH_MASTER;
+ break;
+
+ case PHY_SUP_SPEED0:
+ mii->mii_media_active |= IFM_100_TX;
+ break;
+
+ case 0:
+ mii->mii_media_active |= IFM_10_T;
+ break;
+
+ default:
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ }
+ if (physup & PHY_SUP_DUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+ } else
+ mii->mii_media_active = ife->ifm_media;
+}
diff --git a/sys/dev/mii/nsgphyreg.h b/sys/dev/mii/nsgphyreg.h
new file mode 100644
index 0000000..c7680f1
--- /dev/null
+++ b/sys/dev/mii/nsgphyreg.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2001 Wind River Systems
+ * Copyright (c) 2001
+ * Bill Paul <wpaul@bsdi.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_NSGPHYREG_H_
+#define _DEV_MII_NSGPHYREG_H_
+
+/*
+ * NatSemi DP83891 registers
+ */
+
+#define NSGPHY_MII_STRAPOPT 0x10 /* Strap options */
+#define NSGPHY_STRAPOPT_PHYADDR 0xF800 /* PHY address */
+#define NSGPHY_STRAPOPT_COMPAT 0x0400 /* Broadcom compat mode */
+#define NSGPHY_STRAPOPT_MMSE 0x0200 /* Manual master/slave enable */
+#define NSGPHY_STRAPOPT_ANEG 0x0100 /* Autoneg enable */
+#define NSGPHY_STRAPOPT_MMSV 0x0080 /* Manual master/slave setting */
+#define NSGPHY_STRAPOPT_1000HDX 0x0010 /* Advertise 1000 half-duplex */
+#define NSGPHY_STRAPOPT_1000FDX 0x0008 /* Advertise 1000 full-duplex */
+#define NSGPHY_STRAPOPT_100_ADV 0x0004 /* Advertise 100 full/half-duplex */
+#define NSGPHY_STRAPOPT_SPEED1 0x0002 /* speed selection */
+#define NSGPHY_STRAPOPT_SPEED0 0x0001 /* speed selection */
+#define NSGPHY_STRAPOPT_SPDSEL (NSGPHY_STRAPOPT_SPEED1|NSGPHY_STRAPOPT_SPEED0)
+
+#define NSGPHY_MII_PHYSUP 0x11 /* PHY support/current status */
+#define PHY_SUP_SPEED1 0x0010 /* speed bit 1 */
+#define PHY_SUP_SPEED0 0x0008 /* speed bit 1 */
+#define NSGPHY_PHYSUP_SPEED1 0x0010 /* speed status */
+#define NSGPHY_PHYSUP_SPEED0 0x0008 /* speed status */
+#define NSGPHY_PHYSUP_SPDSTS (NSGPHY_PHYSUP_SPEED1|NSGPHY_PHYSUP_SPEED0)
+#define NSGPHY_PHYSUP_LNKSTS 0x0004 /* link status */
+#define PHY_SUP_LINK 0x0004 /* link status */
+#define PHY_SUP_DUPLEX 0x0002 /* 1 == full-duplex */
+#define NSGPHY_PHYSUP_DUPSTS 0x0002 /* duplex status 1 == full */
+#define NSGPHY_PHYSUP_10BT 0x0001 /* 10baseT resolved */
+
+#define NSGPHY_SPDSTS_1000 0x0010
+#define NSGPHY_SPDSTS_100 0x0008
+#define NSGPHY_SPDSTS_10 0x0000
+
+#endif /* _DEV_NSGPHY_MIIREG_H_ */
diff --git a/sys/dev/mii/nsphy.c b/sys/dev/mii/nsphy.c
new file mode 100644
index 0000000..85a1d8f
--- /dev/null
+++ b/sys/dev/mii/nsphy.c
@@ -0,0 +1,384 @@
+/* $NetBSD: nsphy.c,v 1.18 1999/07/14 23:57:36 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * driver for National Semiconductor's DP83840A ethernet 10/100 PHY
+ * Data Sheet available from www.national.com
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/nsphyreg.h>
+
+#include "miibus_if.h"
+
+static int nsphy_probe(device_t);
+static int nsphy_attach(device_t);
+
+static device_method_t nsphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, nsphy_probe),
+ DEVMETHOD(device_attach, nsphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t nsphy_devclass;
+
+static driver_t nsphy_driver = {
+ "nsphy",
+ nsphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(nsphy, miibus, nsphy_driver, nsphy_devclass, 0, 0);
+
+static int nsphy_service(struct mii_softc *, struct mii_data *, int);
+static void nsphy_status(struct mii_softc *);
+
+static int
+nsphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_NATSEMI &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_NATSEMI_DP83840) {
+ device_set_desc(dev, MII_STR_NATSEMI_DP83840);
+ } else
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+nsphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = nsphy_service;
+ sc->mii_pdata = mii;
+
+#ifdef foo
+ /*
+ * i82557 wedges if all of its PHYs are isolated!
+ */
+ if (strcmp(device_get_name(device_get_parent(sc->mii_dev)),
+ "fxp") == 0 && mii->mii_instance == 0)
+#endif
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+#if 0
+ /* Can't do this on the i82557! */
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+#endif
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+
+ mii_phy_reset(sc);
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_add_media(sc);
+ printf("\n");
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+nsphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ reg = PHY_READ(sc, MII_NSPHY_PCR);
+
+ /*
+ * Set up the PCR to use LED4 to indicate full-duplex
+ * in both 10baseT and 100baseTX modes.
+ */
+ reg |= PCR_LED4MODE;
+
+ /*
+ * Make sure Carrier Intgrity Monitor function is
+ * disabled (normal for Node operation, but sometimes
+ * it's not set?!)
+ */
+ reg |= PCR_CIMDIS;
+
+ /*
+ * Make sure "force link good" is set to normal mode.
+ * It's only intended for debugging.
+ */
+ reg |= PCR_FLINK100;
+
+ /*
+ * Mystery bits which are supposedly `reserved',
+ * but we seem to need to set them when the PHY
+ * is connected to some interfaces:
+ *
+ * 0x0400 is needed for fxp
+ * (Intel EtherExpress Pro 10+/100B, 82557 chip)
+ * (nsphy with a DP83840 chip)
+ * 0x0100 may be needed for some other card
+ */
+ reg |= 0x0100 | 0x0400;
+
+ if (strcmp(device_get_name(device_get_parent(sc->mii_dev)),
+ "fxp") == 0)
+ PHY_WRITE(sc, MII_NSPHY_PCR, reg);
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
+ return (0);
+ (void) mii_phy_auto(sc);
+ break;
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ default:
+ /*
+ * BMCR data is stored in the ifmedia entry.
+ */
+ PHY_WRITE(sc, MII_ANAR,
+ mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ if (mii_phy_tick(sc) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ nsphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+nsphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int bmsr, bmcr, par, anlpar;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, MII_BMSR) |
+ PHY_READ(sc, MII_BMSR);
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(sc, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BMCR_AUTOEN) {
+ /*
+ * The PAR status bits are only valid of autonegotiation
+ * has completed (or it's disabled).
+ */
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ /*
+ * Argh. The PAR doesn't seem to indicate duplex mode
+ * properly! Determine media based on link partner's
+ * advertised capabilities.
+ */
+ if (PHY_READ(sc, MII_ANER) & ANER_LPAN) {
+ anlpar = PHY_READ(sc, MII_ANAR) &
+ PHY_READ(sc, MII_ANLPAR);
+ if (anlpar & ANLPAR_T4)
+ mii->mii_media_active |= IFM_100_T4;
+ else if (anlpar & ANLPAR_TX_FD)
+ mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+ else if (anlpar & ANLPAR_TX)
+ mii->mii_media_active |= IFM_100_TX;
+ else if (anlpar & ANLPAR_10_FD)
+ mii->mii_media_active |= IFM_10_T|IFM_FDX;
+ else if (anlpar & ANLPAR_10)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ /*
+ * Link partner is not capable of autonegotiation.
+ * We will never be in full-duplex mode if this is
+ * the case, so reading the PAR is OK.
+ */
+ par = PHY_READ(sc, MII_NSPHY_PAR);
+ if (par & PAR_10)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_100_TX;
+#if 0
+ if (par & PAR_FDX)
+ mii->mii_media_active |= IFM_FDX;
+#endif
+ } else
+ mii->mii_media_active |= mii_media_from_bmcr(bmcr);
+}
diff --git a/sys/dev/mii/nsphyreg.h b/sys/dev/mii/nsphyreg.h
new file mode 100644
index 0000000..5ff0490
--- /dev/null
+++ b/sys/dev/mii/nsphyreg.h
@@ -0,0 +1,115 @@
+/* $NetBSD: nsphyreg.h,v 1.1 1998/08/10 23:58:39 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_NSPHYREG_H_
+#define _DEV_MII_NSPHYREG_H_
+
+/*
+ * DP83840 registers.
+ */
+
+#define MII_NSPHY_DCR 0x12 /* Disconnect counter */
+
+#define MII_NSPHY_FCSCR 0x13 /* False carrier sense counter */
+
+#define MII_NSPHY_RECR 0x15 /* Receive error counter */
+
+#define MII_NSPHY_SRR 0x16 /* Silicon revision */
+
+#define MII_NSPHY_PCR 0x17 /* PCS sub-layer configuration */
+#define PCR_NRZI 0x8000 /* NRZI encoding enabled for 100TX */
+#define PCR_DESCRTOSEL 0x4000 /* descrambler t/o select (2ms) */
+#define PCR_DESCRTODIS 0x2000 /* descrambler t/o disable */
+#define PCR_REPEATER 0x1000 /* repeater mode */
+#define PCR_ENCSEL 0x0800 /* encoder mode select */
+#define PCR_CLK25MDIS 0x0080 /* CLK25M disable */
+#define PCR_FLINK100 0x0040 /* force good link in 100mbps */
+#define PCR_CIMDIS 0x0020 /* carrier integrity monitor disable */
+#define PCR_TXOFF 0x0010 /* force transmit off */
+#define PCR_LED1MODE 0x0004 /* LED1 mode: see below */
+#define PCR_LED4MODE 0x0002 /* LED4 mode: see below */
+
+/*
+ * LED1 Mode:
+ *
+ * 1 LED1 output configured to PAR's CON_STATUS, useful for
+ * network management in 100baseTX mode.
+ *
+ * 0 Normal LED1 operation - 10baseTX and 100baseTX transmission
+ * activity.
+ *
+ * LED4 Mode:
+ *
+ * 1 LED4 output configured to indicate full-duplex in both
+ * 10baseT and 100baseTX modes.
+ *
+ * 0 LED4 output configured to indicate polarity in 10baseT
+ * mode and full-duplex in 100baseTX mode.
+ */
+
+#define MII_NSPHY_LBREMR 0x18 /* Loopback, bypass, error mask */
+#define LBREMR_BADSSDEN 0x8000 /* enable bad SSD detection */
+#define LBREMR_BP4B5B 0x4000 /* bypass 4b/5b encoding */
+#define LBREMR_BPSCR 0x2000 /* bypass scrambler */
+#define LBREMR_BPALIGN 0x1000 /* bypass alignment function */
+#define LBREMR_10LOOP 0x0800 /* 10baseT loopback */
+#define LBREMR_LB1 0x0200 /* loopback ctl 1 */
+#define LBREMR_LB0 0x0100 /* loopback ctl 0 */
+#define LBREMR_ALTCRS 0x0040 /* alt crs operation */
+#define LBREMR_LOOPXMTDIS 0x0020 /* disable transmit in 100TX loopbk */
+#define LBREMR_CODEERR 0x0010 /* code errors */
+#define LBREMR_PEERR 0x0008 /* premature end errors */
+#define LBREMR_LINKERR 0x0004 /* link errors */
+#define LBREMR_PKTERR 0x0002 /* packet errors */
+
+#define MII_NSPHY_PAR 0x19 /* Physical address and status */
+#define PAR_DISCRSJAB 0x0800 /* disable car sense during jab */
+#define PAR_ANENSTAT 0x0400 /* autoneg mode status */
+#define PAR_FEFIEN 0x0100 /* far end fault enable */
+#define PAR_FDX 0x0080 /* full duplex status */
+#define PAR_10 0x0040 /* 10mbps mode */
+#define PAR_CON 0x0020 /* connect status */
+#define PAR_AMASK 0x001f /* PHY address bits */
+
+#define MII_NSPHY_10BTSR 0x1b /* 10baseT status */
+#define MII_NSPHY_10BTCR 0x1c /* 10baseT configuration */
+
+#endif /* _DEV_MII_NSPHYREG_H_ */
diff --git a/sys/dev/mii/pnaphy.c b/sys/dev/mii/pnaphy.c
new file mode 100644
index 0000000..f952574
--- /dev/null
+++ b/sys/dev/mii/pnaphy.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2000 Berkeley Software Design, Inc.
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Bill Paul <wpaul@osd.bsdi.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * driver for homePNA PHYs
+ * This is really just a stub that allows us to identify homePNA-based
+ * transceicers and display the link status. MII-based homePNA PHYs
+ * only support one media type and no autonegotiation. If we were
+ * really clever, we could tweak some of the vendor-specific registers
+ * to optimize the link.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include "miibus_if.h"
+
+static int pnaphy_probe(device_t);
+static int pnaphy_attach(device_t);
+
+static device_method_t pnaphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, pnaphy_probe),
+ DEVMETHOD(device_attach, pnaphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t pnaphy_devclass;
+
+static driver_t pnaphy_driver = {
+ "pnaphy",
+ pnaphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(pnaphy, miibus, pnaphy_driver, pnaphy_devclass, 0, 0);
+
+static int pnaphy_service(struct mii_softc *, struct mii_data *,int);
+
+static int
+pnaphy_probe(dev)
+ device_t dev;
+{
+
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_AMD &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_AMD_79c978) {
+ device_set_desc(dev, MII_STR_AMD_79c978);
+ return(0);
+ }
+
+ return(ENXIO);
+}
+
+static int
+pnaphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+ const char *sep = "";
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = pnaphy_service;
+ sc->mii_pdata = mii;
+
+ mii->mii_instance++;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+#define PRINT(s) printf("%s%s", sep, s); sep = ", "
+
+ mii_phy_reset(sc);
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, sc->mii_inst), 0);
+ PRINT("HomePNA");
+ }
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+
+ printf("\n");
+
+#undef ADD
+#undef PRINT
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+
+ return(0);
+}
+
+static int
+pnaphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ case IFM_10_T:
+ case IFM_100_TX:
+ case IFM_100_T4:
+ return (EINVAL);
+ default:
+ /*
+ * BMCR data is stored in the ifmedia entry.
+ */
+ PHY_WRITE(sc, MII_ANAR,
+ mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ if (mii_phy_tick(sc) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ ukphy_status(sc);
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
+ mii->mii_media_active = IFM_ETHER|IFM_HPNA_1;
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
diff --git a/sys/dev/mii/pnphy.c b/sys/dev/mii/pnphy.c
new file mode 100644
index 0000000..4cfed03
--- /dev/null
+++ b/sys/dev/mii/pnphy.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Pseudo-driver for media selection on the Lite-On PNIC 82c168
+ * chip. The NWAY support on this chip is horribly broken, so we
+ * only support manual mode selection. This is lame, but getting
+ * NWAY to work right is amazingly difficult.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <pci/if_dcreg.h>
+
+#include "miibus_if.h"
+
+#define DC_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) | x)
+
+#define DC_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) & ~x)
+
+static int pnphy_probe(device_t);
+static int pnphy_attach(device_t);
+
+static device_method_t pnphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, pnphy_probe),
+ DEVMETHOD(device_attach, pnphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t pnphy_devclass;
+
+static driver_t pnphy_driver = {
+ "pnphy",
+ pnphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(pnphy, miibus, pnphy_driver, pnphy_devclass, 0, 0);
+
+static int pnphy_service(struct mii_softc *, struct mii_data *, int);
+static void pnphy_status(struct mii_softc *);
+
+static int
+pnphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ /*
+ * The dc driver will report the 82c168 vendor and device
+ * ID to let us know that it wants us to attach.
+ */
+ if (ma->mii_id1 != DC_VENDORID_LO ||
+ ma->mii_id2 != DC_DEVICEID_82C168)
+ return(ENXIO);
+
+ device_set_desc(dev, "PNIC 82c168 media interface");
+
+ return (0);
+}
+
+static int
+pnphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = pnphy_service;
+ sc->mii_pdata = mii;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+ sc->mii_capabilities =
+ BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX|BMSR_10THDX;
+ sc->mii_capabilities &= ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_add_media(sc);
+ printf("\n");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+pnphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ return (0);
+ }
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ sc->mii_flags = 0;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /* NWAY is busted on this chip */
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ case IFM_100_TX:
+ mii->mii_media_active = IFM_ETHER|IFM_100_TX;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ MIIBUS_STATCHG(sc->mii_dev);
+ return(0);
+ case IFM_10_T:
+ mii->mii_media_active = IFM_ETHER|IFM_10_T;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ MIIBUS_STATCHG(sc->mii_dev);
+ return(0);
+ default:
+ return(EINVAL);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ break;
+ }
+
+ /* Update the media status. */
+ pnphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+pnphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int reg;
+ struct dc_softc *dc_sc;
+
+ dc_sc = mii->mii_ifp->if_softc;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ reg = CSR_READ_4(dc_sc, DC_ISR);
+
+ if (!(reg & DC_ISR_LINKFAIL))
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_100_TX;
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+
+ return;
+}
diff --git a/sys/dev/mii/qsphy.c b/sys/dev/mii/qsphy.c
new file mode 100644
index 0000000..2c2bd6a
--- /dev/null
+++ b/sys/dev/mii/qsphy.c
@@ -0,0 +1,317 @@
+/* OpenBSD: qsphy.c,v 1.6 2000/08/26 20:04:18 nate Exp */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+/* NetBSD: qsphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp */
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * driver for Quality Semiconductor's QS6612 ethernet 10/100 PHY
+ * datasheet from www.qualitysemi.com
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/qsphyreg.h>
+
+#include "miibus_if.h"
+
+static int qsphy_probe(device_t);
+static int qsphy_attach(device_t);
+
+static device_method_t qsphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, qsphy_probe),
+ DEVMETHOD(device_attach, qsphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t qsphy_devclass;
+
+static driver_t qsphy_driver = {
+ "qsphy",
+ qsphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(qsphy, miibus, qsphy_driver, qsphy_devclass, 0, 0);
+
+static int qsphy_service(struct mii_softc *, struct mii_data *, int);
+static void qsphy_reset(struct mii_softc *);
+static void qsphy_status(struct mii_softc *);
+
+static int
+qsphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_QUALSEMI &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_QUALSEMI_QS6612) {
+ device_set_desc(dev, MII_STR_QUALSEMI_QS6612);
+ } else
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+qsphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = qsphy_service;
+ sc->mii_pdata = mii;
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+ qsphy_reset(sc);
+
+ mii->mii_instance++;
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_add_media(sc);
+ printf("\n");
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return (0);
+}
+
+static int
+qsphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ /*
+ * If we're not selected, then do nothing, just isolate, if
+ * changing media.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ if (cmd == MII_MEDIACHG) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ }
+
+ return (0);
+ }
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
+ return (0);
+
+ (void) mii_phy_auto(sc);
+ break;
+
+ default:
+ /*
+ * BMCR data is stored in the ifmedia entry.
+ */
+ PHY_WRITE(sc, MII_ANAR,
+ mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * This PHY's autonegotiation doesn't need to be kicked.
+ */
+ break;
+ }
+
+ /* Update the media status. */
+ qsphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+qsphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int bmsr, bmcr, pctl;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, MII_BMSR) |
+ PHY_READ(sc, MII_BMSR);
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(sc, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ pctl = PHY_READ(sc, MII_QSPHY_PCTL);
+ switch (pctl & PCTL_OPMASK) {
+ case PCTL_10_T:
+ mii->mii_media_active |= IFM_10_T;
+ break;
+ case PCTL_10_T_FDX:
+ mii->mii_media_active |= IFM_10_T|IFM_FDX;
+ break;
+ case PCTL_100_TX:
+ mii->mii_media_active |= IFM_100_TX;
+ break;
+ case PCTL_100_TX_FDX:
+ mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+ break;
+ case PCTL_100_T4:
+ mii->mii_media_active |= IFM_100_T4;
+ break;
+ case PCTL_AN:
+ mii->mii_media_active |= IFM_NONE;
+ break;
+ default:
+ /* Erg... this shouldn't happen. */
+ mii->mii_media_active |= IFM_NONE;
+ break;
+ }
+}
+
+static void
+qsphy_reset(sc)
+ struct mii_softc *sc;
+{
+
+ mii_phy_reset(sc);
+ PHY_WRITE(sc, MII_QSPHY_IMASK, 0);
+}
diff --git a/sys/dev/mii/qsphyreg.h b/sys/dev/mii/qsphyreg.h
new file mode 100644
index 0000000..a697865
--- /dev/null
+++ b/sys/dev/mii/qsphyreg.h
@@ -0,0 +1,88 @@
+/* OpenBSD: qsphyreg.h,v 1.2 1999/03/09 00:02:45 jason Exp */
+/* NetBSD: qsphyreg.h,v 1.1 1998/08/11 00:01:03 thorpej Exp */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_MII_QSPHYREG_H_
+#define _DEV_MII_QSPHYREG_H_
+
+/*
+ * Register definitions for the Quality Semiconductor QS6612
+ * Further documentation can be found at:
+ * http://www.qualitysemi.com/products/network.html
+ */
+
+#define MII_QSPHY_MCTL 0x11 /* Mode control */
+#define MCTL_T4PRE 0x1000 /* 100baseT4 interface present */
+#define MCTL_BTEXT 0x0800 /* reduce 10baseT squelch level */
+#define MCTL_FACTTEST 0x0100 /* factory test mode */
+#define MCTL_PHYADDRMASK 0x00f8 /* PHY address */
+#define MCTL_FACTTEST2 0x0004 /* another factory test mode */
+#define MCTL_NLPDIS 0x0002 /* disable link pulse tx */
+#define MCTL_SQEDIS 0x0001 /* disable SQE */
+
+#define MII_QSPHY_ISRC 0x1d /* Interrupt source */
+#define MII_QSPHY_IMASK 0x1e /* Interrupt mask */
+#define IMASK_TLINTR 0x8000 /* ThunderLAN interrupt mode */
+#define IMASK_ANCPL 0x0040 /* autonegotiation complete */
+#define IMASK_RFD 0x0020 /* remote fault detected */
+#define IMASK_LD 0x0010 /* link down */
+#define IMASK_ANLPA 0x0008 /* autonegotiation LP ACK */
+#define IMASK_PDT 0x0004 /* parallel detection fault */
+#define IMASK_ANPR 0x0002 /* autonegotiation page received */
+#define IMASK_REF 0x0001 /* receive error counter full */
+
+#define MII_QSPHY_PCTL 0x1f /* PHY control */
+#define PCTL_RXERDIS 0x2000 /* receive error counter disable */
+#define PCTL_ANC 0x1000 /* autonegotiation complete */
+#define PCTL_RLBEN 0x0200 /* remote coopback enable */
+#define PCTL_DCREN 0x0100 /* DC restoration enable */
+#define PCTL_4B5BEN 0x0040 /* 4b/5b encoding */
+#define PCTL_PHYISO 0x0020 /* isolate PHY */
+#define PCTL_OPMASK 0x001c /* operation mode mask */
+#define PCTL_AN 0x0000 /* autonegotiation in-progress */
+#define PCTL_10_T 0x0004 /* 10baseT */
+#define PCTL_100_TX 0x0008 /* 100baseTX */
+#define PCTL_100_T4 0x0010 /* 100baseT4 */
+#define PCTL_10_T_FDX 0x0014 /* 10baseT-FDX */
+#define PCTL_100_TX_FDX 0x0018 /* 100baseTX-FDX */
+#define PCTL_MLT3DIS 0x0002 /* disable MLT3 */
+#define PCTL_SRCDIS 0x0001 /* disable scrambling */
+
+#endif /* _DEV_MII_QSPHYREG_H_ */
diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c
new file mode 100644
index 0000000..5c0f13d
--- /dev/null
+++ b/sys/dev/mii/rgephy.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2003
+ * Bill Paul <wpaul@windriver.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Driver for the RealTek 8169S/8110S internal 10/100/1000 PHY.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+
+#include <machine/clock.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/rgephyreg.h>
+
+#include "miibus_if.h"
+
+#include <machine/bus.h>
+#include <pci/if_rlreg.h>
+
+static int rgephy_probe(device_t);
+static int rgephy_attach(device_t);
+
+static device_method_t rgephy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, rgephy_probe),
+ DEVMETHOD(device_attach, rgephy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t rgephy_devclass;
+
+static driver_t rgephy_driver = {
+ "rgephy",
+ rgephy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, 0, 0);
+
+static int rgephy_service(struct mii_softc *, struct mii_data *, int);
+static void rgephy_status(struct mii_softc *);
+static int rgephy_mii_phy_auto(struct mii_softc *);
+static void rgephy_reset(struct mii_softc *);
+static void rgephy_loop(struct mii_softc *);
+static void rgephy_load_dspcode(struct mii_softc *);
+static int rgephy_mii_model;
+
+static int
+rgephy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxREALTEK &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_xxREALTEK_RTL8169S) {
+ device_set_desc(dev, MII_STR_xxREALTEK_RTL8169S);
+ return(0);
+ }
+
+ return(ENXIO);
+}
+
+static int
+rgephy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+ const char *sep = "";
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = rgephy_service;
+ sc->mii_pdata = mii;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+#define PRINT(s) printf("%s%s", sep, s); sep = ", "
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+#if 0
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+#endif
+
+ rgephy_mii_model = MII_MODEL(ma->mii_id2);
+ rgephy_reset(sc);
+
+ sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ sc->mii_capabilities &= ~BMSR_ANEG;
+
+ device_printf(dev, " ");
+ mii_add_media(sc);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst),
+ RGEPHY_BMCR_FDX);
+ PRINT(", 1000baseTX");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), 0);
+ PRINT("1000baseTX-FDX");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
+ PRINT("auto");
+
+ printf("\n");
+#undef ADD
+#undef PRINT
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+rgephy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg, speed, gig;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ rgephy_reset(sc); /* XXX hardware bug work-around */
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+#ifdef foo
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN)
+ return (0);
+#endif
+ (void) rgephy_mii_phy_auto(sc);
+ break;
+ case IFM_1000_T:
+ speed = RGEPHY_S1000;
+ goto setit;
+ case IFM_100_TX:
+ speed = RGEPHY_S100;
+ goto setit;
+ case IFM_10_T:
+ speed = RGEPHY_S10;
+setit:
+ rgephy_loop(sc);
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
+ speed |= RGEPHY_BMCR_FDX;
+ gig = RGEPHY_1000CTL_AFD;
+ } else {
+ gig = RGEPHY_1000CTL_AHD;
+ }
+
+ PHY_WRITE(sc, RGEPHY_MII_1000CTL, 0);
+ PHY_WRITE(sc, RGEPHY_MII_BMCR, speed);
+ PHY_WRITE(sc, RGEPHY_MII_ANAR, RGEPHY_SEL_TYPE);
+
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
+ break;
+
+ PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig);
+ PHY_WRITE(sc, RGEPHY_MII_BMCR,
+ speed|RGEPHY_BMCR_AUTOEN|RGEPHY_BMCR_STARTNEG);
+
+ /*
+ * When settning the link manually, one side must
+ * be the master and the other the slave. However
+ * ifmedia doesn't give us a good way to specify
+ * this, so we fake it by using one of the LINK
+ * flags. If LINK0 is set, we program the PHY to
+ * be a master, otherwise it's a slave.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_LINK0)) {
+ PHY_WRITE(sc, RGEPHY_MII_1000CTL,
+ gig|RGEPHY_1000CTL_MSE|RGEPHY_1000CTL_MSC);
+ } else {
+ PHY_WRITE(sc, RGEPHY_MII_1000CTL,
+ gig|RGEPHY_1000CTL_MSE);
+ }
+ break;
+#ifdef foo
+ case IFM_NONE:
+ PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
+ break;
+#endif
+ case IFM_100_T4:
+ default:
+ return (EINVAL);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * Check to see if we have link. If we do, we don't
+ * need to restart the autonegotiation process. Read
+ * the BMSR twice in case it's latched.
+ */
+ reg = PHY_READ(sc, RL_GMEDIASTAT);
+ if (reg & RL_GMEDIASTAT_LINK)
+ break;
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5/*10*/)
+ return (0);
+
+ sc->mii_ticks = 0;
+ rgephy_mii_phy_auto(sc);
+ return (0);
+ }
+
+ /* Update the media status. */
+ rgephy_status(sc);
+
+ /*
+ * Callback if something changed. Note that we need to poke
+ * the DSP on the RealTek PHYs if the media changes.
+ *
+ */
+ if (sc->mii_media_active != mii->mii_media_active ||
+ sc->mii_media_status != mii->mii_media_status ||
+ cmd == MII_MEDIACHG) {
+ mii_phy_update(sc, cmd);
+ rgephy_load_dspcode(sc);
+ }
+ return (0);
+}
+
+static void
+rgephy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int bmsr, bmcr;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, RL_GMEDIASTAT);
+
+ if (bmsr & RL_GMEDIASTAT_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+ bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
+
+ bmcr = PHY_READ(sc, RGEPHY_MII_BMCR);
+
+ if (bmcr & RGEPHY_BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & RGEPHY_BMCR_AUTOEN) {
+ if ((bmsr & RGEPHY_BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+ }
+
+ bmsr = PHY_READ(sc, RL_GMEDIASTAT);
+ if (bmsr & RL_GMEDIASTAT_10MBPS)
+ mii->mii_media_active |= IFM_10_T;
+ if (bmsr & RL_GMEDIASTAT_100MBPS)
+ mii->mii_media_active |= IFM_100_TX;
+ if (bmsr & RL_GMEDIASTAT_1000MBPS)
+ mii->mii_media_active |= IFM_1000_T;
+ if (bmsr & RL_GMEDIASTAT_FDX)
+ mii->mii_media_active |= IFM_FDX;
+
+ return;
+}
+
+
+static int
+rgephy_mii_phy_auto(mii)
+ struct mii_softc *mii;
+{
+ rgephy_loop(mii);
+ rgephy_reset(mii);
+
+ PHY_WRITE(mii, RGEPHY_MII_ANAR,
+ BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
+ DELAY(1000);
+ PHY_WRITE(mii, RGEPHY_MII_1000CTL, RGEPHY_1000CTL_AFD);
+ DELAY(1000);
+ PHY_WRITE(mii, RGEPHY_MII_BMCR,
+ RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
+ DELAY(100);
+
+ return (EJUSTRETURN);
+}
+
+static void
+rgephy_loop(struct mii_softc *sc)
+{
+ u_int32_t bmsr;
+ int i;
+
+ PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN);
+ DELAY(1000);
+
+ for (i = 0; i < 15000; i++) {
+ bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
+ if (!(bmsr & RGEPHY_BMSR_LINK)) {
+#if 0
+ device_printf(sc->mii_dev, "looped %d\n", i);
+#endif
+ break;
+ }
+ DELAY(10);
+ }
+}
+
+#define PHY_SETBIT(x, y, z) \
+ PHY_WRITE(x, y, (PHY_READ(x, y) | (z)))
+#define PHY_CLRBIT(x, y, z) \
+ PHY_WRITE(x, y, (PHY_READ(x, y) & ~(z)))
+
+/*
+ * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of
+ * existing revisions of the 8169S/8110S chips need to be tuned in
+ * order to reliably negotiate a 1000Mbps link. Later revs of the
+ * chips may not require this software tuning.
+ */
+static void
+rgephy_load_dspcode(struct mii_softc *sc)
+{
+ int val;
+
+ PHY_WRITE(sc, 31, 0x0001);
+ PHY_WRITE(sc, 21, 0x1000);
+ PHY_WRITE(sc, 24, 0x65C7);
+ PHY_CLRBIT(sc, 4, 0x0800);
+ val = PHY_READ(sc, 4) & 0xFFF;
+ PHY_WRITE(sc, 4, val);
+ PHY_WRITE(sc, 3, 0x00A1);
+ PHY_WRITE(sc, 2, 0x0008);
+ PHY_WRITE(sc, 1, 0x1020);
+ PHY_WRITE(sc, 0, 0x1000);
+ PHY_SETBIT(sc, 4, 0x0800);
+ PHY_CLRBIT(sc, 4, 0x0800);
+ val = (PHY_READ(sc, 4) & 0xFFF) | 0x7000;
+ PHY_WRITE(sc, 4, val);
+ PHY_WRITE(sc, 3, 0xFF41);
+ PHY_WRITE(sc, 2, 0xDE60);
+ PHY_WRITE(sc, 1, 0x0140);
+ PHY_WRITE(sc, 0, 0x0077);
+ val = (PHY_READ(sc, 4) & 0xFFF) | 0xA000;
+ PHY_WRITE(sc, 4, val);
+ PHY_WRITE(sc, 3, 0xDF01);
+ PHY_WRITE(sc, 2, 0xDF20);
+ PHY_WRITE(sc, 1, 0xFF95);
+ PHY_WRITE(sc, 0, 0xFA00);
+ val = (PHY_READ(sc, 4) & 0xFFF) | 0xB000;
+ PHY_WRITE(sc, 4, val);
+ PHY_WRITE(sc, 3, 0xFF41);
+ PHY_WRITE(sc, 2, 0xDE20);
+ PHY_WRITE(sc, 1, 0x0140);
+ PHY_WRITE(sc, 0, 0x00BB);
+ val = (PHY_READ(sc, 4) & 0xFFF) | 0xF000;
+ PHY_WRITE(sc, 4, val);
+ PHY_WRITE(sc, 3, 0xDF01);
+ PHY_WRITE(sc, 2, 0xDF20);
+ PHY_WRITE(sc, 1, 0xFF95);
+ PHY_WRITE(sc, 0, 0xBF00);
+ PHY_SETBIT(sc, 4, 0x0800);
+ PHY_CLRBIT(sc, 4, 0x0800);
+ PHY_WRITE(sc, 31, 0x0000);
+
+ DELAY(40);
+}
+
+static void
+rgephy_reset(struct mii_softc *sc)
+{
+ mii_phy_reset(sc);
+ DELAY(1000);
+ rgephy_load_dspcode(sc);
+
+ return;
+}
diff --git a/sys/dev/mii/rgephyreg.h b/sys/dev/mii/rgephyreg.h
new file mode 100644
index 0000000..1adecf4
--- /dev/null
+++ b/sys/dev/mii/rgephyreg.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2003
+ * Bill Paul <wpaul@windriver.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_RGEPHYREG_H_
+#define _DEV_MII_RGEPHYREG_H_
+
+/*
+ * RealTek 8169S/8110S gigE PHY registers
+ */
+
+#define RGEPHY_MII_BMCR 0x00
+#define RGEPHY_BMCR_RESET 0x8000
+#define RGEPHY_BMCR_LOOP 0x4000
+#define RGEPHY_BMCR_SPD0 0x2000 /* speed select, lower bit */
+#define RGEPHY_BMCR_AUTOEN 0x1000 /* Autoneg enabled */
+#define RGEPHY_BMCR_PDOWN 0x0800 /* Power down */
+#define RGEPHY_BMCR_ISO 0x0400 /* Isolate */
+#define RGEPHY_BMCR_STARTNEG 0x0200 /* Restart autoneg */
+#define RGEPHY_BMCR_FDX 0x0100 /* Duplex mode */
+#define RGEPHY_BMCR_CTEST 0x0080 /* Collision test enable */
+#define RGEPHY_BMCR_SPD1 0x0040 /* Speed select, upper bit */
+
+#define RGEPHY_S1000 RGEPHY_BMCR_SPD1 /* 1000mbps */
+#define RGEPHY_S100 RGEPHY_BMCR_SPD0 /* 100mpbs */
+#define RGEPHY_S10 0 /* 10mbps */
+
+#define RGEPHY_MII_BMSR 0x01
+#define RGEPHY_BMSR_100T4 0x8000 /* 100 base T4 capable */
+#define RGEPHY_BMSR_100TXFDX 0x4000 /* 100 base Tx full duplex capable */
+#define RGEPHY_BMSR_100TXHDX 0x2000 /* 100 base Tx half duplex capable */
+#define RGEPHY_BMSR_10TFDX 0x1000 /* 10 base T full duplex capable */
+#define RGEPHY_BMSR_10THDX 0x0800 /* 10 base T half duplex capable */
+#define RGEPHY_BMSR_100T2FDX 0x0400 /* 100 base T2 full duplex capable */
+#define RGEPHY_BMSR_100T2HDX 0x0200 /* 100 base T2 half duplex capable */
+#define RGEPHY_BMSR_EXTSTS 0x0100 /* Extended status present */
+#define RGEPHY_BMSR_PRESUB 0x0040 /* Preamble surpression */
+#define RGEPHY_BMSR_ACOMP 0x0020 /* Autoneg complete */
+#define RGEPHY_BMSR_RFAULT 0x0010 /* Remote fault condition occured */
+#define RGEPHY_BMSR_ANEG 0x0008 /* Autoneg capable */
+#define RGEPHY_BMSR_LINK 0x0004 /* Link status */
+#define RGEPHY_BMSR_JABBER 0x0002 /* Jabber detected */
+#define RGEPHY_BMSR_EXT 0x0001 /* Extended capability */
+
+#define RGEPHY_MII_ANAR 0x04
+#define RGEPHY_ANAR_NP 0x8000 /* Next page */
+#define RGEPHY_ANAR_RF 0x2000 /* Remote fault */
+#define RGEPHY_ANAR_ASP 0x0800 /* Asymmetric Pause */
+#define RGEPHY_ANAR_PC 0x0400 /* Pause capable */
+#define RGEPHY_ANAR_T4 0x0200 /* local device supports 100bT4 */
+#define RGEPHY_ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */
+#define RGEPHY_ANAR_TX 0x0080 /* local device supports 100bTx */
+#define RGEPHY_ANAR_10_FD 0x0040 /* local device supports 10bT FD */
+#define RGEPHY_ANAR_10 0x0020 /* local device supports 10bT */
+#define RGEPHY_ANAR_SEL 0x001F /* selector field, 00001=Ethernet */
+
+#define RGEPHY_MII_ANLPAR 0x05
+#define RGEPHY_ANLPAR_NP 0x8000 /* Next page */
+#define RGEPHY_ANLPAR_RF 0x2000 /* Remote fault */
+#define RGEPHY_ANLPAR_ASP 0x0800 /* Asymmetric Pause */
+#define RGEPHY_ANLPAR_PC 0x0400 /* Pause capable */
+#define RGEPHY_ANLPAR_T4 0x0200 /* link partner supports 100bT4 */
+#define RGEPHY_ANLPAR_TX_FD 0x0100 /* link partner supports 100bTx FD */
+#define RGEPHY_ANLPAR_TX 0x0080 /* link partner supports 100bTx */
+#define RGEPHY_ANLPAR_10_FD 0x0040 /* link partner supports 10bT FD */
+#define RGEPHY_ANLPAR_10 0x0020 /* link partner supports 10bT */
+#define RGEPHY_ANLPAR_SEL 0x001F /* selector field, 00001=Ethernet */
+
+#define RGEPHY_SEL_TYPE 0x0001 /* ethernet */
+
+#define RGEPHY_MII_ANER 0x06
+#define RGEPHY_ANER_PDF 0x0010 /* Parallel detection fault */
+#define RGEPHY_ANER_LPNP 0x0008 /* Link partner can next page */
+#define RGEPHY_ANER_NP 0x0004 /* Local PHY can next page */
+#define RGEPHY_ANER_RX 0x0002 /* Next page received */
+#define RGEPHY_ANER_LPAN 0x0001 /* Link partner autoneg capable */
+
+#define RGEPHY_MII_NEXTP 0x07 /* Next page */
+
+#define RGEPHY_MII_NEXTP_LP 0x08 /* Next page of link partner */
+
+#define RGEPHY_MII_1000CTL 0x09 /* 1000baseT control */
+#define RGEPHY_1000CTL_TST 0xE000 /* test modes */
+#define RGEPHY_1000CTL_MSE 0x1000 /* Master/Slave manual enable */
+#define RGEPHY_1000CTL_MSC 0x0800 /* Master/Slave select */
+#define RGEPHY_1000CTL_RD 0x0400 /* Repeater/DTE */
+#define RGEPHY_1000CTL_AFD 0x0200 /* Advertise full duplex */
+#define RGEPHY_1000CTL_AHD 0x0100 /* Advertise half duplex */
+
+#define RGEPHY_TEST_TX_JITTER 0x2000
+#define RGEPHY_TEST_TX_JITTER_MASTER_MODE 0x4000
+#define RGEPHY_TEST_TX_JITTER_SLAVE_MODE 0x6000
+#define RGEPHY_TEST_TX_DISTORTION 0x8000
+
+#define RGEPHY_MII_1000STS 0x0A /* 1000baseT status */
+#define RGEPHY_1000STS_MSF 0x8000 /* Master/slave fault */
+#define RGEPHY_1000STS_MSR 0x4000 /* Master/slave result */
+#define RGEPHY_1000STS_LRS 0x2000 /* Local receiver status */
+#define RGEPHY_1000STS_RRS 0x1000 /* Remote receiver status */
+#define RGEPHY_1000STS_LPFD 0x0800 /* Link partner can FD */
+#define RGEPHY_1000STS_LPHD 0x0400 /* Link partner can HD */
+#define RGEPHY_1000STS_IEC 0x00FF /* Idle error count */
+
+#define RGEPHY_MII_EXTSTS 0x0F /* Extended status */
+#define RGEPHY_EXTSTS_X_FD_CAP 0x8000 /* 1000base-X FD capable */
+#define RGEPHY_EXTSTS_X_HD_CAP 0x4000 /* 1000base-X HD capable */
+#define RGEPHY_EXTSTS_T_FD_CAP 0x2000 /* 1000base-T FD capable */
+#define RGEPHY_EXTSTS_T_HD_CAP 0x1000 /* 1000base-T HD capable */
+
+
+
+#endif /* _DEV_RGEPHY_MIIREG_H_ */
diff --git a/sys/dev/mii/rlphy.c b/sys/dev/mii/rlphy.c
new file mode 100644
index 0000000..1847586
--- /dev/null
+++ b/sys/dev/mii/rlphy.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * driver for RealTek 8139 internal PHYs
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <machine/bus.h>
+#include <pci/if_rlreg.h>
+
+#include "miibus_if.h"
+
+static int rlphy_probe(device_t);
+static int rlphy_attach(device_t);
+
+static device_method_t rlphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, rlphy_probe),
+ DEVMETHOD(device_attach, rlphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t rlphy_devclass;
+
+static driver_t rlphy_driver = {
+ "rlphy",
+ rlphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(rlphy, miibus, rlphy_driver, rlphy_devclass, 0, 0);
+
+static int rlphy_service(struct mii_softc *, struct mii_data *, int);
+static void rlphy_status(struct mii_softc *);
+
+static int
+rlphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+ device_t parent;
+
+ ma = device_get_ivars(dev);
+ parent = device_get_parent(device_get_parent(dev));
+
+ /* Test for RealTek 8201L PHY */
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_REALTEK &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_REALTEK_RTL8201L) {
+ device_set_desc(dev, MII_STR_REALTEK_RTL8201L);
+ return(0);
+ }
+
+ /*
+ * RealTek PHY doesn't have vendor/device ID registers:
+ * the rl driver fakes up a return value of all zeros.
+ */
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
+ MII_MODEL(ma->mii_id2) != 0)
+ return (ENXIO);
+
+ /*
+ * Make sure the parent is an `rl' or an `re'.
+ */
+ if (strcmp(device_get_name(parent), "rl") != 0 &&
+ strcmp(device_get_name(parent), "re") != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "RealTek internal media interface");
+
+ return (0);
+}
+
+static int
+rlphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+
+ /*
+ * The RealTek PHY can never be isolated, so never allow non-zero
+ * instances!
+ */
+ if (mii->mii_instance != 0) {
+ device_printf(dev, "ignoring this PHY, non-zero instance\n");
+ return(ENXIO);
+ }
+
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = rlphy_service;
+ sc->mii_pdata = mii;
+ mii->mii_instance++;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+#if 0 /* See above. */
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+#endif
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+
+ mii_phy_reset(sc);
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_add_media(sc);
+ printf("\n");
+#undef ADD
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+rlphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+
+ /*
+ * We can't isolate the RealTek PHY, so it has to be the only one!
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ panic("rlphy_service: can't isolate RealTek PHY");
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
+ return (0);
+ (void) mii_phy_auto(sc);
+ break;
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ default:
+ /*
+ * BMCR data is stored in the ifmedia entry.
+ */
+ PHY_WRITE(sc, MII_ANAR,
+ mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * The RealTek PHY's autonegotiation doesn't need to be
+ * kicked; it continues in the background.
+ */
+ break;
+ }
+
+ /* Update the media status. */
+ rlphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+rlphy_status(phy)
+ struct mii_softc *phy;
+{
+ struct mii_data *mii = phy->mii_pdata;
+ int bmsr, bmcr, anlpar;
+ device_t parent;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR);
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(phy, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BMCR_AUTOEN) {
+ /*
+ * NWay autonegotiation takes the highest-order common
+ * bit of the ANAR and ANLPAR (i.e. best media advertised
+ * both by us and our link partner).
+ */
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if ((anlpar = PHY_READ(phy, MII_ANAR) &
+ PHY_READ(phy, MII_ANLPAR))) {
+ if (anlpar & ANLPAR_T4)
+ mii->mii_media_active |= IFM_100_T4;
+ else if (anlpar & ANLPAR_TX_FD)
+ mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+ else if (anlpar & ANLPAR_TX)
+ mii->mii_media_active |= IFM_100_TX;
+ else if (anlpar & ANLPAR_10_FD)
+ mii->mii_media_active |= IFM_10_T|IFM_FDX;
+ else if (anlpar & ANLPAR_10)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+ /*
+ * If the other side doesn't support NWAY, then the
+ * best we can do is determine if we have a 10Mbps or
+ * 100Mbps link. There's no way to know if the link
+ * is full or half duplex, so we default to half duplex
+ * and hope that the user is clever enough to manually
+ * change the media settings if we're wrong.
+ */
+
+
+ /*
+ * The RealTek PHY supports non-NWAY link speed
+ * detection, however it does not report the link
+ * detection results via the ANLPAR or BMSR registers.
+ * (What? RealTek doesn't do things the way everyone
+ * else does? I'm just shocked, shocked I tell you.)
+ * To determine the link speed, we have to do one
+ * of two things:
+ *
+ * - If this is a standalone RealTek RTL8201(L) PHY,
+ * we can determine the link speed by testing bit 0
+ * in the magic, vendor-specific register at offset
+ * 0x19.
+ *
+ * - If this is a RealTek MAC with integrated PHY, we
+ * can test the 'SPEED10' bit of the MAC's media status
+ * register.
+ */
+ parent = device_get_parent(phy->mii_dev);
+ if (strcmp(device_get_name(parent), "rl") != 0) {
+ if (PHY_READ(phy, 0x0019) & 0x01)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ } else {
+ if (PHY_READ(phy, RL_MEDIASTAT) &
+ RL_MEDIASTAT_SPEED10)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_100_TX;
+ }
+
+ } else
+ mii->mii_media_active = mii_media_from_bmcr(bmcr);
+}
diff --git a/sys/dev/mii/ruephy.c b/sys/dev/mii/ruephy.c
new file mode 100644
index 0000000..f2dbc16
--- /dev/null
+++ b/sys/dev/mii/ruephy.c
@@ -0,0 +1,299 @@
+/*-
+ * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * driver for RealTek RTL8150 internal PHY
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <machine/bus.h>
+#include <dev/mii/ruephyreg.h>
+
+#include "miibus_if.h"
+
+static int ruephy_probe(device_t);
+static int ruephy_attach(device_t);
+
+static device_method_t ruephy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ruephy_probe),
+ DEVMETHOD(device_attach, ruephy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t ruephy_devclass;
+
+static driver_t ruephy_driver = {
+ "ruephy",
+ ruephy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(ruephy, miibus, ruephy_driver, ruephy_devclass, 0, 0);
+
+static int ruephy_service(struct mii_softc *, struct mii_data *, int);
+static void ruephy_reset(struct mii_softc *);
+static void ruephy_status(struct mii_softc *);
+
+static int
+ruephy_probe(device_t dev)
+{
+ struct mii_attach_args *ma;
+ device_t parent;
+
+ ma = device_get_ivars(dev);
+ parent = device_get_parent(device_get_parent(dev));
+
+ /*
+ * RealTek RTL8150 PHY doesn't have vendor/device ID registers:
+ * the rue driver fakes up a return value of all zeros.
+ */
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
+ MII_MODEL(ma->mii_id2) != 0)
+ return (ENXIO);
+
+ /*
+ * Make sure the parent is an 'rue'.
+ */
+ if (strcmp(device_get_name(parent), "rue") != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "RealTek RTL8150 internal media interface");
+
+ return (0);
+}
+
+static int
+ruephy_attach(device_t dev)
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+
+ /*
+ * The RealTek PHY can never be isolated, so never allow non-zero
+ * instances!
+ */
+ if (mii->mii_instance != 0) {
+ device_printf(dev, "ignoring this PHY, non-zero instance\n");
+ return (ENXIO);
+ }
+
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = ruephy_service;
+ sc->mii_pdata = mii;
+ mii->mii_instance++;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+ ruephy_reset(sc);
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_phy_add_media(sc);
+ printf("\n");
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return (0);
+}
+
+static int
+ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ /*
+ * We can't isolate the RealTek RTL8150 PHY,
+ * so it has to be the only one!
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ panic("ruephy_service: can't isolate RealTek RTL8150 PHY");
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
+ return (0);
+ (void) mii_phy_auto(sc);
+ break;
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ default:
+ /*
+ * BMCR data is stored in the ifmedia entry.
+ */
+ PHY_WRITE(sc, MII_ANAR,
+ mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * Check to see if we have link. If we do, we don't
+ * need to restart the autonegotiation process. Read
+ * the MSR twice in case it's latched.
+ */
+ reg = PHY_READ(sc, RUEPHY_MII_MSR) |
+ PHY_READ(sc, RUEPHY_MII_MSR);
+ if (reg & RUEPHY_MSR_LINK)
+ break;
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (0);
+
+ sc->mii_ticks = 0;
+ ruephy_reset(sc);
+ if (mii_phy_auto(sc) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ ruephy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+
+ return (0);
+}
+
+static void
+ruephy_reset(struct mii_softc *sc)
+{
+
+ mii_phy_reset(sc);
+
+ /*
+ * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after
+ * XXX reset, which breaks autonegotiation.
+ */
+ PHY_WRITE(sc, MII_BMCR, (BMCR_S100 | BMCR_AUTOEN | BMCR_FDX));
+}
+
+static void
+ruephy_status(struct mii_softc *phy)
+{
+ struct mii_data *mii = phy->mii_pdata;
+ int bmsr, bmcr, msr;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ msr = PHY_READ(phy, RUEPHY_MII_MSR) | PHY_READ(phy, RUEPHY_MII_MSR);
+ if (msr & RUEPHY_MSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(phy, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR);
+
+ if (bmcr & BMCR_AUTOEN) {
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if (msr & RUEPHY_MSR_SPEED100)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+
+ if (msr & RUEPHY_MSR_DUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+ } else
+ mii->mii_media_active = mii_media_from_bmcr(bmcr);
+}
diff --git a/sys/dev/mii/ruephyreg.h b/sys/dev/mii/ruephyreg.h
new file mode 100644
index 0000000..5f3911b
--- /dev/null
+++ b/sys/dev/mii/ruephyreg.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _RUEPHYREG_H_
+#define _RUEPHYREG_H_
+
+#define RUEPHY_MII_MSR 0x0137 /* B, R/W */
+#define RUEPHY_MSR_RXFCE 0x40
+#define RUEPHY_MSR_DUPLEX 0x10
+#define RUEPHY_MSR_SPEED100 0x08
+#define RUEPHY_MSR_LINK 0x04
+
+#endif /* _RUEPHYREG_H_ */
diff --git a/sys/dev/mii/tdkphy.c b/sys/dev/mii/tdkphy.c
new file mode 100644
index 0000000..b21311f
--- /dev/null
+++ b/sys/dev/mii/tdkphy.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2000,2001 Jonathan Chen.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Driver for the TDK 78Q2120 MII
+ *
+ * References:
+ * Datasheet for the 78Q2120 - http://www.tsc.tdk.com/lan/78q2120.pdf
+ * Most of this code stolen from ukphy.c
+ */
+
+/*
+ * The TDK 78Q2120 is found on some Xircom X3201 based cardbus cards. It's just
+ * like any other normal phy, except it does auto negotiation in a different
+ * way.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <machine/clock.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/tdkphyreg.h>
+
+#include "miibus_if.h"
+
+#if 0
+#if !defined(lint)
+static const char rcsid[] =
+ "$Id: tdkphy.c,v 1.3 2000/10/14 06:20:56 jon Exp $";
+#endif
+#endif
+
+static int tdkphy_probe(device_t);
+static int tdkphy_attach(device_t);
+
+static device_method_t tdkphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, tdkphy_probe),
+ DEVMETHOD(device_attach, tdkphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t tdkphy_devclass;
+
+static driver_t tdkphy_driver = {
+ "tdkphy",
+ tdkphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(tdkphy, miibus, tdkphy_driver, tdkphy_devclass, 0, 0);
+
+static int tdkphy_service(struct mii_softc *, struct mii_data *, int);
+static void tdkphy_status(struct mii_softc *);
+
+static int
+tdkphy_probe(device_t dev)
+{
+ struct mii_attach_args *ma;
+ ma = device_get_ivars(dev);
+ if ((MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_TDK ||
+ MII_MODEL(ma->mii_id2) != MII_MODEL_TDK_78Q2120))
+ return (ENXIO);
+
+ device_set_desc(dev, MII_STR_TDK_78Q2120);
+ return (0);
+}
+
+static int
+tdkphy_attach(device_t dev)
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ if (bootverbose)
+ device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n",
+ MII_OUI(ma->mii_id1, ma->mii_id2),
+ MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2));
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = tdkphy_service;
+ sc->mii_pdata = mii;
+
+ mii->mii_instance++;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+#if 0
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+#endif
+
+ mii_phy_reset(sc);
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ device_printf(dev, " ");
+ mii_add_media(sc);
+ printf("\n");
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+
+ return(0);
+}
+
+static int
+tdkphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
+ return (0);
+ (void) mii_phy_auto(sc);
+ break;
+ case IFM_100_T4:
+ /*
+ * Not supported on MII
+ */
+ return (EINVAL);
+ default:
+ /*
+ * BMCR data is stored in the ifmedia entry.
+ */
+ PHY_WRITE(sc, MII_ANAR,
+ mii_anar(ife->ifm_media));
+ PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ if (mii_phy_tick(sc) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ tdkphy_status(sc);
+ if (sc->mii_pdata->mii_media_active & IFM_FDX)
+ PHY_WRITE(sc, MII_BMCR, PHY_READ(sc, MII_BMCR) | BMCR_FDX);
+ else
+ PHY_WRITE(sc, MII_BMCR, PHY_READ(sc, MII_BMCR) & ~BMCR_FDX);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+tdkphy_status(struct mii_softc *phy)
+{
+ struct mii_data *mii = phy->mii_pdata;
+ int bmsr, bmcr, anlpar, diag;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR);
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(phy, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BMCR_AUTOEN) {
+ /*
+ * NWay autonegotiation takes the highest-order common
+ * bit of the ANAR and ANLPAR (i.e. best media advertised
+ * both by us and our link partner).
+ */
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR);
+ /*
+ * ANLPAR doesn't get set on my card, but we check it anyway,
+ * since it is mentioned in the 78Q2120 specs.
+ */
+ if (anlpar & ANLPAR_T4)
+ mii->mii_media_active |= IFM_100_T4;
+ else if (anlpar & ANLPAR_TX_FD)
+ mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+ else if (anlpar & ANLPAR_TX)
+ mii->mii_media_active |= IFM_100_TX;
+ else if (anlpar & ANLPAR_10_FD)
+ mii->mii_media_active |= IFM_10_T|IFM_FDX;
+ else if (anlpar & ANLPAR_10)
+ mii->mii_media_active |= IFM_10_T;
+ else {
+ /*
+ * ANLPAR isn't set, which leaves two possibilities:
+ * 1) Auto negotiation failed
+ * 2) Auto negotiation completed, but the card forgot
+ * to set ANLPAR.
+ * So we check the MII_DIAG(18) register...
+ */
+ diag = PHY_READ(phy, MII_DIAG);
+ if (diag & DIAG_NEGFAIL) /* assume 10baseT if no neg */
+ mii->mii_media_active |= IFM_10_T;
+ else {
+ if (diag & DIAG_DUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+ if (diag & DIAG_RATE_100)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ }
+ }
+ } else {
+ mii->mii_media_active = mii_media_from_bmcr(bmcr);
+ }
+}
diff --git a/sys/dev/mii/tdkphyreg.h b/sys/dev/mii/tdkphyreg.h
new file mode 100644
index 0000000..1f10625
--- /dev/null
+++ b/sys/dev/mii/tdkphyreg.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2000,2001 Jonathan Chen.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Register definitions for TDK 78Q2120
+ */
+
+#ifndef _DEV_MII_TDKPHYREG_H_
+#define _DEV_MII_TDKPHYREG_H_
+
+#define MII_VENDOR 16
+#define VENDOR_RXCC 0x0001
+#define VENDOR_PCSBP 0x0002
+#define VENDOR_RVSPOL 0x0010
+#define VENDOR_NOAPOL 0x0020
+#define VENDOR_GPIO0DIR 0x0040
+#define VENDOR_GPIO0DAT 0x0080
+#define VENDOR_GPIO1DIR 0x0100
+#define VENDOR_GPIO1DAT 0x0200
+#define VENDOR_10BTLOOP 0x0400
+#define VENDOR_NOSQE 0x0800
+#define VENDOR_TXHIM 0x1000
+#define VENDOR_INTLVL 0x4000
+#define VENDOR_RPTR 0x8000
+
+#define MII_INT 17
+#define INT_STAT_MASK 0x00ff
+#define INT_STAT_ACOMP 0x0001
+#define INT_STAT_RFAULT 0x0002
+#define INT_STAT_LSCHG 0x0004
+#define INT_STAT_LPACK 0x0008
+#define INT_STAT_PDF 0x0010
+#define INT_STAT_PRX 0x0020
+#define INT_STAT_RXERR 0x0040
+#define INT_STAT_JABBER 0x0080
+#define INT_CTRL_MASK 0xff00
+#define INT_CTRL_ACOMP 0x0100
+#define INT_CTRL_RFAULT 0x0200
+#define INT_CTRL_LSCHG 0x0400
+#define INT_CTRL_LPACK 0x0800
+#define INT_CTRL_PDF 0x1000
+#define INT_CTRL_PRX 0x2000
+#define INT_CTRL_RXERR 0x4000
+#define INT_CTRL_JABBER 0x8000
+
+
+#define MII_DIAG 18
+#define DIAG_RLOCK 0x0100
+#define DIAG_RPASS 0x0200
+#define DIAG_RATE_100 0x0400
+#define DIAG_DUPLEX 0x0800
+#define DIAG_NEGFAIL 0x1000
+
+
+#endif
diff --git a/sys/dev/mii/tlphy.c b/sys/dev/mii/tlphy.c
new file mode 100644
index 0000000..ca9f854
--- /dev/null
+++ b/sys/dev/mii/tlphy.c
@@ -0,0 +1,439 @@
+/* $NetBSD: tlphy.c,v 1.18 1999/05/14 11:40:28 drochner Exp $ */
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Driver for Texas Instruments's ThunderLAN PHYs
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/tlphyreg.h>
+
+#include "miibus_if.h"
+
+struct tlphy_softc {
+ struct mii_softc sc_mii; /* generic PHY */
+ int sc_need_acomp;
+};
+
+static int tlphy_probe(device_t);
+static int tlphy_attach(device_t);
+
+static device_method_t tlphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, tlphy_probe),
+ DEVMETHOD(device_attach, tlphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t tlphy_devclass;
+
+static driver_t tlphy_driver = {
+ "tlphy",
+ tlphy_methods,
+ sizeof(struct tlphy_softc)
+};
+
+DRIVER_MODULE(tlphy, miibus, tlphy_driver, tlphy_devclass, 0, 0);
+
+static int tlphy_service(struct mii_softc *, struct mii_data *, int);
+static int tlphy_auto(struct tlphy_softc *);
+static void tlphy_acomp(struct tlphy_softc *);
+static void tlphy_status(struct tlphy_softc *);
+
+static int
+tlphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_xxTI ||
+ MII_MODEL(ma->mii_id2) != MII_MODEL_xxTI_TLAN10T)
+ return (ENXIO);
+
+ device_set_desc(dev, MII_STR_xxTI_TLAN10T);
+
+ return (0);
+}
+
+static int
+tlphy_attach(dev)
+ device_t dev;
+{
+ struct tlphy_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+ const char *sep = "";
+ int capmask = 0xFFFFFFFF;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->sc_mii.mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->sc_mii.mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, &sc->sc_mii, mii_list);
+
+ sc->sc_mii.mii_inst = mii->mii_instance;
+ sc->sc_mii.mii_phy = ma->mii_phyno;
+ sc->sc_mii.mii_service = tlphy_service;
+ sc->sc_mii.mii_pdata = mii;
+
+ if (mii->mii_instance) {
+ struct mii_softc *other;
+ device_t *devlist;
+ int devs, i;
+
+ device_get_children(sc->sc_mii.mii_dev, &devlist, &devs);
+ for (i = 0; i < devs; i++) {
+ if (strcmp(device_get_name(devlist[i]), "tlphy")) {
+ other = device_get_softc(devlist[i]);
+ capmask &= ~other->mii_capabilities;
+ break;
+ }
+ }
+ free(devlist, M_TEMP);
+ }
+
+ mii->mii_instance++;
+
+ 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,
+ * we are not going to want to use the built-in 10baseT port,
+ * since there will be another PHY on the MII wired up to the
+ * UTP connector. The parent indicates this to us by specifying
+ * the TLPHY_MEDIA_NO_10_T bit.
+ */
+ sc->sc_mii.mii_capabilities =
+ PHY_READ(&sc->sc_mii, MII_BMSR) & capmask /*ma->mii_capmask*/;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->sc_mii.mii_inst),
+ BMCR_ISO);
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_LOOP,
+ sc->sc_mii.mii_inst), BMCR_LOOP);
+
+#define PRINT(s) printf("%s%s", sep, s); sep = ", "
+
+ device_printf(dev, " ");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc->sc_mii.mii_inst), 0);
+ PRINT("10base2/BNC");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, sc->sc_mii.mii_inst), 0);
+ PRINT("10base5/AUI");
+
+ if (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) {
+ printf("%s", sep);
+ mii_add_media(&sc->sc_mii);
+ }
+
+ printf("\n");
+#undef ADD
+#undef PRINT
+ MIIBUS_MEDIAINIT(sc->sc_mii.mii_dev);
+ return(0);
+}
+
+static int
+tlphy_service(self, mii, cmd)
+ struct mii_softc *self;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct tlphy_softc *sc = (struct tlphy_softc *)self;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ if (sc->sc_need_acomp)
+ tlphy_acomp(sc);
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) {
+ reg = PHY_READ(&sc->sc_mii, MII_BMCR);
+ PHY_WRITE(&sc->sc_mii, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*
+ * The ThunderLAN PHY doesn't self-configure after
+ * an autonegotiation cycle, so there's no such
+ * thing as "already in auto mode".
+ */
+ (void) tlphy_auto(sc);
+ break;
+ case IFM_10_2:
+ case IFM_10_5:
+ PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
+ PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL);
+ DELAY(100000);
+ break;
+ default:
+ PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0);
+ DELAY(100000);
+ PHY_WRITE(&sc->sc_mii, MII_ANAR,
+ mii_anar(ife->ifm_media));
+ PHY_WRITE(&sc->sc_mii, MII_BMCR, ife->ifm_data);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * Check to see if we have link. If we do, we don't
+ * need to restart the autonegotiation process. Read
+ * the BMSR twice in case it's latched.
+ *
+ * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?!
+ */
+ reg = PHY_READ(&sc->sc_mii, MII_BMSR) |
+ PHY_READ(&sc->sc_mii, MII_BMSR);
+ if (reg & BMSR_LINK)
+ break;
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->sc_mii.mii_ticks != 5)
+ return (0);
+
+ sc->sc_mii.mii_ticks = 0;
+ mii_phy_reset(&sc->sc_mii);
+ tlphy_auto(sc);
+ return (0);
+ }
+
+ /* Update the media status. */
+ tlphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(&sc->sc_mii, cmd);
+ return (0);
+}
+
+static void
+tlphy_status(sc)
+ struct tlphy_softc *sc;
+{
+ struct mii_data *mii = sc->sc_mii.mii_pdata;
+ int bmsr, bmcr, tlctrl;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmcr = PHY_READ(&sc->sc_mii, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ tlctrl = PHY_READ(&sc->sc_mii, MII_TLPHY_CTRL);
+ if (tlctrl & CTRL_AUISEL) {
+ mii->mii_media_status = 0;
+ mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media;
+ return;
+ }
+
+ bmsr = PHY_READ(&sc->sc_mii, MII_BMSR) |
+ PHY_READ(&sc->sc_mii, MII_BMSR);
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ /*
+ * Grr, braindead ThunderLAN PHY doesn't have any way to
+ * tell which media is actually active. (Note it also
+ * doesn't self-configure after autonegotiation.) We
+ * just have to report what's in the BMCR.
+ */
+ if (bmcr & BMCR_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ mii->mii_media_active |= IFM_10_T;
+}
+
+static int
+tlphy_auto(sc)
+ struct tlphy_softc *sc;
+{
+ int error;
+
+ switch ((error = mii_phy_auto(&sc->sc_mii))) {
+ case EIO:
+ /*
+ * Just assume we're not in full-duplex mode.
+ * XXX Check link and try AUI/BNC?
+ */
+ PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
+ break;
+
+ case EJUSTRETURN:
+ /* Flag that we need to program when it completes. */
+ sc->sc_need_acomp = 1;
+ break;
+
+ default:
+ tlphy_acomp(sc);
+ }
+
+ return (error);
+}
+
+static void
+tlphy_acomp(sc)
+ struct tlphy_softc *sc;
+{
+ int aner, anlpar;
+
+ sc->sc_need_acomp = 0;
+
+ /*
+ * Grr, braindead ThunderLAN PHY doesn't self-configure
+ * after autonegotiation. We have to do it ourselves
+ * based on the link partner status.
+ */
+
+ aner = PHY_READ(&sc->sc_mii, MII_ANER);
+ if (aner & ANER_LPAN) {
+ anlpar = PHY_READ(&sc->sc_mii, MII_ANLPAR) &
+ PHY_READ(&sc->sc_mii, MII_ANAR);
+ if (anlpar & ANAR_10_FD) {
+ PHY_WRITE(&sc->sc_mii, MII_BMCR, BMCR_FDX);
+ return;
+ }
+ }
+ PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
+}
diff --git a/sys/dev/mii/tlphyreg.h b/sys/dev/mii/tlphyreg.h
new file mode 100644
index 0000000..77e4a45
--- /dev/null
+++ b/sys/dev/mii/tlphyreg.h
@@ -0,0 +1,59 @@
+/* $NetBSD: tlphyreg.h,v 1.1 1998/08/10 23:59:58 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_TLPHYREG_H_
+#define _DEV_MII_TLPHYREG_H_
+
+/*
+ * Registers for the TI ThunderLAN internal PHY.
+ */
+
+#define MII_TLPHY_ID 0x10 /* ThunderLAN PHY ID */
+#define ID_10BASETAUI 0x0001 /* 10baseT/AUI PHY */
+
+#define MII_TLPHY_CTRL 0x11 /* Control regiseter */
+#define CTRL_ILINK 0x8000 /* Ignore link */
+#define CTRL_SWPOL 0x4000 /* swap polarity */
+#define CTRL_AUISEL 0x2000 /* Select AUI */
+#define CTRL_SQEEN 0x1000 /* Enable SQE */
+#define CTRL_NFEW 0x0004 /* Not far end wrap */
+#define CTRL_INTEN 0x0002 /* Interrupts enable */
+#define CTRL_TINT 0x0001 /* Test Interrupts */
+
+#define MII_TLPHY_ST 0x12 /* Status register */
+#define ST_MII_INT 0x8000 /* MII interrupt */
+#define ST_PHOK 0x4000 /* Power high OK */
+#define ST_POLOK 0x2000 /* Polarity OK */
+#define ST_TPE 0x1000 /* Twisted pair energy */
+
+#endif /* _DEV_MII_TLPHYREG_H_ */
diff --git a/sys/dev/mii/ukphy.c b/sys/dev/mii/ukphy.c
new file mode 100644
index 0000000..68403ee
--- /dev/null
+++ b/sys/dev/mii/ukphy.c
@@ -0,0 +1,229 @@
+/* $NetBSD: ukphy.c,v 1.2 1999/04/23 04:24:32 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center, and by Frank van der Linden.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * driver for generic unknown PHYs
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include "miibus_if.h"
+
+static int ukphy_probe(device_t);
+static int ukphy_attach(device_t);
+
+static device_method_t ukphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ukphy_probe),
+ DEVMETHOD(device_attach, ukphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t ukphy_devclass;
+
+static driver_t ukphy_driver = {
+ "ukphy",
+ ukphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(ukphy, miibus, ukphy_driver, ukphy_devclass, 0, 0);
+
+static int ukphy_service(struct mii_softc *, struct mii_data *, int);
+
+static int
+ukphy_probe(dev)
+ device_t dev;
+{
+
+ /*
+ * We know something is here, so always match at a low priority.
+ */
+ device_set_desc(dev, "Generic IEEE 802.3u media interface");
+ return (-100);
+}
+
+static int
+ukphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ if (bootverbose)
+ device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n",
+ MII_OUI(ma->mii_id1, ma->mii_id2),
+ MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2));
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = ukphy_service;
+ sc->mii_pdata = mii;
+
+ mii->mii_instance++;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+
+ mii_phy_reset(sc);
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ if (sc->mii_capabilities & BMSR_EXTSTAT)
+ sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
+ device_printf(dev, " ");
+ mii_phy_add_media(sc);
+ printf("\n");
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+
+ return(0);
+}
+
+static int
+ukphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ mii_phy_setmedia(sc);
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ if (mii_phy_tick(sc) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ ukphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
diff --git a/sys/dev/mii/ukphy_subr.c b/sys/dev/mii/ukphy_subr.c
new file mode 100644
index 0000000..ca26b95
--- /dev/null
+++ b/sys/dev/mii/ukphy_subr.c
@@ -0,0 +1,119 @@
+/* $NetBSD: ukphy_subr.c,v 1.2 1998/11/05 04:08:02 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center, and by Frank van der Linden.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Subroutines shared by the ukphy driver and other PHY drivers.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include "miibus_if.h"
+
+/*
+ * Media status subroutine. If a PHY driver does media detection simply
+ * by decoding the NWay autonegotiation, use this routine.
+ */
+void
+ukphy_status(struct mii_softc *phy)
+{
+ struct mii_data *mii = phy->mii_pdata;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int bmsr, bmcr, anlpar;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR);
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(phy, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if (bmcr & BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if (bmcr & BMCR_AUTOEN) {
+ /*
+ * NWay autonegotiation takes the highest-order common
+ * bit of the ANAR and ANLPAR (i.e. best media advertised
+ * both by us and our link partner).
+ */
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR);
+ if (anlpar & ANLPAR_T4)
+ mii->mii_media_active |= IFM_100_T4;
+ else if (anlpar & ANLPAR_TX_FD)
+ mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+ else if (anlpar & ANLPAR_TX)
+ mii->mii_media_active |= IFM_100_TX;
+ else if (anlpar & ANLPAR_10_FD)
+ mii->mii_media_active |= IFM_10_T|IFM_FDX;
+ else if (anlpar & ANLPAR_10)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ } else
+ mii->mii_media_active = ife->ifm_media;
+}
diff --git a/sys/dev/mii/xmphy.c b/sys/dev/mii/xmphy.c
new file mode 100644
index 0000000..2a1ee80
--- /dev/null
+++ b/sys/dev/mii/xmphy.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2000
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * driver for the XaQti XMAC II's internal PHY. This is sort of
+ * like a 10/100 PHY, except the only thing we're really autoselecting
+ * here is full/half duplex. Speed is always 1000mbps.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+
+#include <dev/mii/xmphyreg.h>
+
+#include "miibus_if.h"
+
+static int xmphy_probe(device_t);
+static int xmphy_attach(device_t);
+
+static device_method_t xmphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, xmphy_probe),
+ DEVMETHOD(device_attach, xmphy_attach),
+ DEVMETHOD(device_detach, mii_phy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t xmphy_devclass;
+
+static driver_t xmphy_driver = {
+ "xmphy",
+ xmphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(xmphy, miibus, xmphy_driver, xmphy_devclass, 0, 0);
+
+static int xmphy_service(struct mii_softc *, struct mii_data *, int);
+static void xmphy_status(struct mii_softc *);
+static int xmphy_mii_phy_auto(struct mii_softc *);
+
+static int
+xmphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxXAQTI &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_XAQTI_XMACII) {
+ device_set_desc(dev, MII_STR_XAQTI_XMACII);
+ return(0);
+ }
+
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_JATO &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_JATO_BASEX) {
+ device_set_desc(dev, MII_STR_JATO_BASEX);
+ return(0);
+ }
+
+ return(ENXIO);
+}
+
+static int
+xmphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+ const char *sep = "";
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = xmphy_service;
+ sc->mii_pdata = mii;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+#define PRINT(s) printf("%s%s", sep, s); sep = ", "
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+#if 0
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+#endif
+
+ mii_phy_reset(sc);
+
+ device_printf(dev, " ");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst),
+ XMPHY_BMCR_FDX);
+ PRINT("1000baseSX");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 0);
+ PRINT("1000baseSX-FDX");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
+ PRINT("auto");
+
+ printf("\n");
+#undef ADD
+#undef PRINT
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int
+xmphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+#ifdef foo
+ /*
+ * If we're already in auto mode, just return.
+ */
+ if (PHY_READ(sc, XMPHY_MII_BMCR) & XMPHY_BMCR_AUTOEN)
+ return (0);
+#endif
+ (void) xmphy_mii_phy_auto(sc);
+ break;
+ case IFM_1000_SX:
+ mii_phy_reset(sc);
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
+ PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_FDX);
+ PHY_WRITE(sc, XMPHY_MII_BMCR, XMPHY_BMCR_FDX);
+ } else {
+ PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_HDX);
+ PHY_WRITE(sc, XMPHY_MII_BMCR, 0);
+ }
+ break;
+ case IFM_100_T4:
+ case IFM_100_TX:
+ case IFM_10_T:
+ default:
+ return (EINVAL);
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ break;
+
+ /*
+ * Check to see if we have link. If we do, we don't
+ * need to restart the autonegotiation process. Read
+ * the BMSR twice in case it's latched.
+ */
+ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
+ if (reg & BMSR_LINK)
+ break;
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (0);
+
+ sc->mii_ticks = 0;
+
+ mii_phy_reset(sc);
+ xmphy_mii_phy_auto(sc);
+ return(0);
+ }
+
+ /* Update the media status. */
+ xmphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+static void
+xmphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int bmsr, bmcr, anlpar;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(sc, XMPHY_MII_BMSR) |
+ PHY_READ(sc, XMPHY_MII_BMSR);
+ if (bmsr & XMPHY_BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ /* Do dummy read of extended status register. */
+ bmcr = PHY_READ(sc, XMPHY_MII_EXTSTS);
+
+ bmcr = PHY_READ(sc, XMPHY_MII_BMCR);
+
+ if (bmcr & XMPHY_BMCR_LOOP)
+ mii->mii_media_active |= IFM_LOOP;
+
+
+ if (bmcr & XMPHY_BMCR_AUTOEN) {
+ if ((bmsr & XMPHY_BMSR_ACOMP) == 0) {
+ if (bmsr & XMPHY_BMSR_LINK) {
+ mii->mii_media_active |= IFM_1000_SX|IFM_HDX;
+ return;
+ }
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ mii->mii_media_active |= IFM_1000_SX;
+ anlpar = PHY_READ(sc, XMPHY_MII_ANAR) &
+ PHY_READ(sc, XMPHY_MII_ANLPAR);
+ if (anlpar & XMPHY_ANLPAR_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ else
+ mii->mii_media_active |= IFM_HDX;
+ return;
+ }
+
+ mii->mii_media_active |= IFM_1000_SX;
+ if (bmcr & XMPHY_BMCR_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ else
+ mii->mii_media_active |= IFM_HDX;
+
+ return;
+}
+
+
+static int
+xmphy_mii_phy_auto(mii)
+ struct mii_softc *mii;
+{
+ int anar = 0;
+
+ anar = PHY_READ(mii, XMPHY_MII_ANAR);
+ anar |= XMPHY_ANAR_FDX|XMPHY_ANAR_HDX;
+ PHY_WRITE(mii, XMPHY_MII_ANAR, anar);
+ DELAY(1000);
+ PHY_WRITE(mii, XMPHY_MII_BMCR,
+ XMPHY_BMCR_AUTOEN | XMPHY_BMCR_STARTNEG);
+
+ return (EJUSTRETURN);
+}
diff --git a/sys/dev/mii/xmphyreg.h b/sys/dev/mii/xmphyreg.h
new file mode 100644
index 0000000..e06b197
--- /dev/null
+++ b/sys/dev/mii/xmphyreg.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2000
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_XMPHYREG_H_
+#define _DEV_MII_XMPHYREG_H_
+
+/*
+ * XaQti XMAC II PHY registers
+ */
+
+#define XMPHY_MII_BMCR 0x00
+#define XMPHY_BMCR_RESET 0x8000
+#define XMPHY_BMCR_LOOP 0x4000
+#define XMPHY_BMCR_AUTOEN 0x1000 /* Autoneg enabled */
+#define XMPHY_BMCR_PDOWN 0x0800 /* Power down */
+#define XMPHY_BMCR_ISO 0x0400 /* Isolate */
+#define XMPHY_BMCR_STARTNEG 0x0200 /* Restart autoneg */
+#define XMPHY_BMCR_FDX 0x0100 /* Duplex mode */
+
+#define XMPHY_MII_BMSR 0x01
+#define XMPHY_BMSR_EXTSTS 0x0100 /* Extended status present */
+#define XMPHY_BMSR_ACOMP 0x0020 /* Autoneg complete */
+#define XMPHY_BMSR_RFAULT 0x0010 /* Remote fault condition occured */
+#define XMPHY_BMSR_ANEG 0x0008 /* Autoneg capable */
+#define XMPHY_BMSR_LINK 0x0004 /* Link status */
+#define XMPHY_BMSR_EXT 0x0001 /* Extended capability */
+
+#define XMPHY_MII_ANAR 0x04
+#define XMPHY_ANAR_NP 0x8000 /* Next page */
+#define XMPHY_ANAR_ACK 0x4000 /* Next page or base received */
+#define XMPHY_ANAR_RFBITS 0x3000 /* Remote fault bits */
+#define XMPHY_ANAR_PAUSEBITS 0x0180 /* Pause bits */
+#define XMPHY_ANAR_HDX 0x0040 /* Select half duplex */
+#define XMPHY_ANAR_FDX 0x0020 /* Select full duplex */
+
+#define XMPHY_MII_ANLPAR 0x05
+#define XMPHY_ANLPAR_NP 0x8000 /* Next page */
+#define XMPHY_ANLPAR_ACK 0x4000 /* Next page or base received */
+#define XMPHY_ANLPAR_RFBITS 0x3000 /* Remote fault bits */
+#define XMPHY_ANLPAR_PAUSEBITS 0x0180 /* Pause bits */
+#define XMPHY_ANLPAR_HDX 0x0040 /* Select half duplex */
+#define XMPHY_ANLPAR_FDX 0x0020 /* Select full duplex */
+
+#define XMPHY_RF_OK 0x0000 /* No error -- link is good */
+#define XMPHY_RF_LINKFAIL 0x1000 /* Link failure */
+#define XMPHY_RF_OFFLINE 0x2000 /* Offline */
+#define XMPHY_RF_ANEGFAIL 0x3000 /* Autonegotiation error */
+
+#define XMPHY_PAUSE_NOPAUSE 0x0000 /* No pause possible */
+#define XMPHY_PAUSE_ASYMETRIC 0x0080 /* Asymetric pause toward LP */
+#define XMPHY_PAUSE_SYMETRIC 0x0100 /* Symetric pause */
+#define XMPHY_PAUSE_BOTH 0x0180 /* Both sym and asym pause */
+
+#define XMPHY_MII_ANER 0x06
+#define XMPHY_ANER_LPNP 0x0008 /* Link partner can next page */
+#define XMPHY_ANER_NP 0x0004 /* Local PHY can next page */
+#define XMPHY_ANER_RX 0x0002 /* Next page received */
+
+#define XMPHY_MII_NEXTP 0x07 /* Next page */
+#define XMPHY_NEXTP_MORE 0x8000 /* More next pages to follow */
+#define XMPHY_NEXTP_ACK1 0x4000 /* Ack bit received OK */
+#define XMPHY_NEXTP_MP 0x2000 /* Page is message page */
+#define XMPHY_NEXTP_ACK2 0x1000 /* can comply with message (r/o) */
+#define XMPHY_NEXTP_TOGGLE 0x0800 /* sync with LP */
+#define XMPHY_NEXTP_MESSAGE 0x07FF /* message */
+
+#define XMPHY_MII_NEXTPLP 0x08 /* Next page of link partner */
+#define XMPHY_NEXTPLP_MORE 0x8000 /* More next pages to follow */
+#define XMPHY_NEXTPLP_ACK1 0x4000 /* Ack bit received OK */
+#define XMPHY_NEXTPLP_MP 0x2000 /* Page is message page */
+#define XMPHY_NEXTPLP_ACK2 0x1000 /* can comply with message (r/o) */
+#define XMPHY_NEXTPLP_TOGGLE 0x0800 /* sync with LP */
+#define XMPHY_NEXTPLP_MESSAGE 0x07FF /* message */
+
+#define XMPHY_MII_EXTSTS 0x0F /* Extended status */
+#define XMPHY_EXTSTS_FDX 0x8000 /* 1000base-X FD capable */
+#define XMPHY_EXTSTS_HDX 0x4000 /* 1000base-X HD capable */
+
+#define XMPHY_MII_RESAB 0x10 /* Resolved ability */
+#define XMPHY_RESAB_PAUSEBITS 0x0180 /* Pause bits */
+#define XMPHY_RESAB_HDX 0x0040 /* Half duplex selected */
+#define XMPHY_RESAB_FDX 0x0020 /* Full duplex selected */
+#define XMPHY_RESAB_ABLMIS 0x0010 /* Ability mismatch */
+#define XMPHY_RESAB_PAUSEMIS 0x0008 /* Pause mismatch */
+
+#endif /* _DEV_MII_XMPHYREG_H_ */
OpenPOWER on IntegriCloud