summaryrefslogtreecommitdiffstats
path: root/sys/dev/mii
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mii')
-rw-r--r--sys/dev/mii/Makefile.miidevs8
-rw-r--r--sys/dev/mii/amphy.c351
-rw-r--r--sys/dev/mii/amphyreg.h84
-rw-r--r--sys/dev/mii/dcphy.c541
-rw-r--r--sys/dev/mii/devlist2h.awk147
-rw-r--r--sys/dev/mii/exphy.c316
-rw-r--r--sys/dev/mii/mii.c329
-rw-r--r--sys/dev/mii/mii.h128
-rw-r--r--sys/dev/mii/mii_physubr.c264
-rw-r--r--sys/dev/mii/miibus_if.m36
-rw-r--r--sys/dev/mii/miidevs122
-rw-r--r--sys/dev/mii/miidevs.h144
-rw-r--r--sys/dev/mii/miivar.h178
-rw-r--r--sys/dev/mii/mlphy.c456
-rw-r--r--sys/dev/mii/nsphy.c430
-rw-r--r--sys/dev/mii/nsphyreg.h115
-rw-r--r--sys/dev/mii/pnphy.c311
-rw-r--r--sys/dev/mii/rlphy.c284
-rw-r--r--sys/dev/mii/tlphy.c457
-rw-r--r--sys/dev/mii/tlphyreg.h59
-rw-r--r--sys/dev/mii/ukphy.c313
-rw-r--r--sys/dev/mii/ukphy_subr.c120
22 files changed, 5193 insertions, 0 deletions
diff --git a/sys/dev/mii/Makefile.miidevs b/sys/dev/mii/Makefile.miidevs
new file mode 100644
index 0000000..964ecf3
--- /dev/null
+++ b/sys/dev/mii/Makefile.miidevs
@@ -0,0 +1,8 @@
+# $NetBSD: Makefile.miidevs,v 1.1 1998/08/10 23:55:17 thorpej Exp $
+# $FreeBSD$
+
+AWK= awk
+
+miidevs.h: miidevs devlist2h.awk
+ /bin/rm -f miidevs.h
+ ${AWK} -f devlist2h.awk miidevs
diff --git a/sys/dev/mii/amphy.c b/sys/dev/mii/amphy.c
new file mode 100644
index 0000000..91eb707
--- /dev/null
+++ b/sys/dev/mii/amphy.c
@@ -0,0 +1,351 @@
+/*
+ * 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$
+ */
+
+/*
+ * driver for AMD AM79c873 PHYs
+ * This driver also works for the Davicom DM9101 PHY, which appears to
+ * be an AM79c873 workalike.
+ */
+
+#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_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/miidevs.h>
+
+#include <dev/mii/amphyreg.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+static int amphy_probe __P((device_t));
+static int amphy_attach __P((device_t));
+static int amphy_detach __P((device_t));
+
+static device_method_t amphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, amphy_probe),
+ DEVMETHOD(device_attach, amphy_attach),
+ DEVMETHOD(device_detach, amphy_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);
+
+int amphy_service __P((struct mii_softc *, struct mii_data *, int));
+void amphy_status __P((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, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_add_media(mii, sc->mii_capabilities,
+ sc->mii_inst);
+ printf("\n");
+#undef ADD
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int amphy_detach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+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, 1);
+ 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);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (0);
+
+ sc->mii_ticks = 0;
+
+ /*
+ * 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;
+
+ mii_phy_reset(sc);
+ if (mii_phy_auto(sc, 0) == EJUSTRETURN)
+ return(0);
+ break;
+ }
+
+ /* Update the media status. */
+ amphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+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/dcphy.c b/sys/dev/mii/dcphy.c
new file mode 100644
index 0000000..8576d84
--- /dev/null
+++ b/sys/dev/mii/dcphy.c
@@ -0,0 +1,541 @@
+/*
+ * 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$
+ */
+
+/*
+ * 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/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.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 <dev/mii/miidevs.h>
+
+#include <machine/clock.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/pcivar.h>
+
+#include <pci/if_dcreg.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+#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 __P((device_t));
+static int dcphy_attach __P((device_t));
+static int dcphy_detach __P((device_t));
+
+static device_method_t dcphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, dcphy_probe),
+ DEVMETHOD(device_attach, dcphy_attach),
+ DEVMETHOD(device_detach, dcphy_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);
+
+int dcphy_service __P((struct mii_softc *, struct mii_data *, int));
+void dcphy_status __P((struct mii_softc *));
+static int dcphy_auto __P((struct mii_softc *, int));
+static void dcphy_reset __P((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:
+ 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, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_add_media(mii, sc->mii_capabilities, sc->mii_inst);
+ printf("\n");
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int dcphy_detach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+
+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, 0);
+ 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;
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ if (sc->mii_flags & MIIF_DOINGAUTO) {
+ if (++sc->mii_ticks != 5)
+ return(0);
+ else {
+ sc->mii_ticks = 0;
+ sc->mii_flags &= ~MIIF_DOINGAUTO;
+ sc->mii_flags |= MIIF_AUTOTIMEOUT;
+ }
+ }
+
+ sc->mii_flags &= ~MIIF_DOINGAUTO;
+
+ /*
+ * 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 = CSR_READ_4(dc_sc, DC_10BTSTAT) &
+ (DC_TSTAT_LS10|DC_TSTAT_LS100);
+
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX &&
+ !(reg & DC_TSTAT_LS100)) {
+ if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
+ sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
+ break;
+ } else
+ return(0);
+ } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T &&
+ !(reg & DC_TSTAT_LS10)) {
+ if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
+ sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
+ break;
+ } else
+ return(0);
+ } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE &&
+ (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))) {
+ if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
+ sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
+ break;
+ } else
+ return(0);
+ } else if (CSR_READ_4(dc_sc, DC_ISR) & DC_ISR_LINKGOOD) {
+ if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
+ sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
+ break;
+ } else
+ return(0);
+ }
+
+ sc->mii_ticks = 0;
+ /*dcphy_reset(sc);*/
+ dcphy_auto(sc, 0);
+
+ break;
+ }
+
+ /* Update the media status. */
+ dcphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+void
+dcphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int reg, anlpar;
+ 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_10BTSTAT) &
+ (DC_TSTAT_LS10|DC_TSTAT_LS100);
+
+ if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ if (sc->mii_flags & MIIF_DOINGAUTO) {
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL &&
+ CSR_READ_4(dc_sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT) {
+ /* Erg, still trying, I guess... */
+ if ((CSR_READ_4(dc_sc, DC_10BTSTAT) &
+ DC_ASTAT_AUTONEGCMP) != DC_ASTAT_AUTONEGCMP) {
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if (CSR_READ_4(dc_sc, DC_10BTSTAT) & DC_TSTAT_LP_CAN_NWAY) {
+ anlpar = CSR_READ_4(dc_sc, DC_10BTSTAT) >> 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_100TXHDX)
+ 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;
+ }
+
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SCRAMBLER)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+
+ return;
+}
+
+static int
+dcphy_auto(mii, waitfor)
+ struct mii_softc *mii;
+ int waitfor;
+{
+ int i;
+ struct dc_softc *sc;
+
+ sc = mii->mii_pdata->mii_ifp->if_softc;
+
+ if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
+ 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);
+ }
+
+ if (waitfor) {
+ /* Wait 500ms for it to complete. */
+ for (i = 0; i < 500; i++) {
+ if ((CSR_READ_4(sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT)
+ == DC_ASTAT_AUTONEGCMP)
+ return(0);
+ DELAY(1000);
+ }
+ /*
+ * Don't need to worry about clearing MIIF_DOINGAUTO.
+ * If that's set, a timeout is pending, and it will
+ * clear the flag.
+ */
+ return(EIO);
+ }
+
+ /*
+ * Just let it finish asynchronously. This is for the benefit of
+ * the tick handler driving autonegotiation. Don't want 500ms
+ * delays all the time while the system is running!
+ */
+ if ((mii->mii_flags & MIIF_DOINGAUTO) == 0)
+ mii->mii_flags |= MIIF_DOINGAUTO;
+
+ 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/devlist2h.awk b/sys/dev/mii/devlist2h.awk
new file mode 100644
index 0000000..6c76b17
--- /dev/null
+++ b/sys/dev/mii/devlist2h.awk
@@ -0,0 +1,147 @@
+#! /usr/bin/awk -f
+# $NetBSD: devlist2h.awk,v 1.2 1998/09/05 14:42:06 christos Exp $
+#
+# Copyright (c) 1998 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Christos Zoulas.
+#
+# 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) 1995, 1996 Christopher G. Demetriou
+# 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 model includes software developed by Christopher G. Demetriou.
+# This model includes software developed by Christos Zoulas
+# 4. The name of the author(s) may not be used to endorse or promote models
+# 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$
+#
+function collectline(f, line) {
+ oparen = 0
+ line = ""
+ while (f <= NF) {
+ if ($f == "#") {
+ line = line "("
+ oparen = 1
+ f++
+ continue
+ }
+ if (oparen) {
+ line = line $f
+ if (f < NF)
+ line = line " "
+ f++
+ continue
+ }
+ line = line $f
+ if (f < NF)
+ line = line " "
+ f++
+ }
+ if (oparen)
+ line = line ")"
+ return line
+}
+BEGIN {
+ nmodels = nouis = 0
+ hfile="miidevs.h"
+}
+NR == 1 {
+ VERSION = $0
+ gsub("\\$", "", VERSION)
+
+ printf("/*\t\$FreeBSD\$\t*/\n\n") > hfile
+ printf("/*\n") > hfile
+ printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \
+ > hfile
+ printf(" *\n") > hfile
+ printf(" * generated from:\n") > hfile
+ printf(" *\t%s\n", VERSION) > hfile
+ printf(" */\n") > hfile
+
+ next
+}
+$1 == "oui" {
+ nuios++
+
+ ouiindex[$2] = nouis; # record index for this name, for later.
+
+ ouis[nouis, 1] = $2; # name
+ ouis[nouis, 2] = $3; # id
+ printf("#define\tMII_OUI_%s\t%s\t", ouis[nouis, 1],
+ ouis[nouis, 2]) > hfile
+ ouis[nouis, 3] = collectline(4, line)
+ printf("/* %s */\n", ouis[nouis, 3]) > hfile
+ next
+}
+$1 == "model" {
+ nmodels++
+
+ models[nmodels, 1] = $2; # oui name
+ models[nmodels, 2] = $3; # model id
+ models[nmodels, 3] = $4; # id
+
+ printf("#define\tMII_MODEL_%s_%s\t%s\n", models[nmodels, 1],
+ models[nmodels, 2], models[nmodels, 3]) > hfile
+
+ models[nmodels, 4] = collectline(5, line)
+
+ printf("#define\tMII_STR_%s_%s\t\"%s\"\n",
+ models[nmodels, 1], models[nmodels, 2],
+ models[nmodels, 4]) > hfile
+
+ next
+}
+{
+ print $0 > hfile
+}
diff --git a/sys/dev/mii/exphy.c b/sys/dev/mii/exphy.c
new file mode 100644
index 0000000..30b6b63
--- /dev/null
+++ b/sys/dev/mii/exphy.c
@@ -0,0 +1,316 @@
+/* $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.
+ */
+
+/*
+ * 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/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.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 <dev/mii/miidevs.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+static int exphy_probe __P((device_t));
+static int exphy_attach __P((device_t));
+static int exphy_detach __P((device_t));
+
+static device_method_t exphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, exphy_probe),
+ DEVMETHOD(device_attach, exphy_attach),
+ DEVMETHOD(device_detach, exphy_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);
+
+int exphy_service __P((struct mii_softc *, struct mii_data *, int));
+void exphy_reset __P((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_3c905Cphy))
+ 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_3c905Cphy);
+
+ 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, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_add_media(mii, sc->mii_capabilities,
+ sc->mii_inst);
+ printf("\n");
+#undef ADD
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int exphy_detach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+
+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;
+
+ 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, 1);
+ 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:
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * 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. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+void
+exphy_reset(sc)
+ 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/mii.c b/sys/dev/mii/mii.c
new file mode 100644
index 0000000..b3f40e2
--- /dev/null
+++ b/sys/dev/mii/mii.c
@@ -0,0 +1,329 @@
+/* $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.
+ */
+
+/*
+ * 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/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>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+static int miibus_readreg __P((device_t, int, int));
+static int miibus_writereg __P((device_t, int, int, int));
+static void miibus_statchg __P((device_t));
+static void miibus_mediainit __P((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_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);
+ 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_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);
+ for (m = LIST_FIRST(&mii->mii_media.ifm_list); m != NULL;
+ m = LIST_NEXT(m, 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);
+ 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;
+
+ for (child = LIST_FIRST(&mii->mii_phys); child != NULL;
+ child = LIST_NEXT(child, 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;
+
+ for (child = LIST_FIRST(&mii->mii_phys); child != NULL;
+ child = LIST_NEXT(child, 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;
+
+ for (child = LIST_FIRST(&mii->mii_phys); child != NULL;
+ child = LIST_NEXT(child, mii_list))
+ (void) (*child->mii_service)(child, mii, MII_POLLSTAT);
+}
diff --git a/sys/dev/mii/mii.h b/sys/dev/mii/mii.h
new file mode 100644
index 0000000..c21fe03
--- /dev/null
+++ b/sys/dev/mii/mii.h
@@ -0,0 +1,128 @@
+/* $NetBSD: mii.h,v 1.1 1998/08/10 23:55:17 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_S100 0x2000 /* speed (10/100) select */
+#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 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_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_EXT 0x0001 /* Extended capability */
+
+#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX| \
+ BMSR_10THDX|BMSR_ANEG)
+
+/*
+ * 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) */
+#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_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 MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
+#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_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 MII_ANER 0x06 /* Autonegotiation expansion (ro) */
+#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 */
+
+#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..ff47190
--- /dev/null
+++ b/sys/dev/mii/mii_physubr.c
@@ -0,0 +1,264 @@
+/* $NetBSD: mii_physubr.c,v 1.5 1999/08/03 19:41:49 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.
+ */
+
+/*
+ * Subroutines common to all PHYs.
+ */
+
+#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 <machine/clock.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+void mii_phy_auto_timeout __P((void *));
+
+int
+mii_phy_auto(mii, waitfor)
+ struct mii_softc *mii;
+ int waitfor;
+{
+ int bmsr, i;
+
+ if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
+ PHY_WRITE(mii, MII_ANAR,
+ BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
+ PHY_WRITE(mii, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
+ }
+
+ if (waitfor) {
+ /* Wait 500ms for it to complete. */
+ for (i = 0; i < 500; i++) {
+ if ((bmsr = PHY_READ(mii, MII_BMSR)) & BMSR_ACOMP)
+ return (0);
+ DELAY(1000);
+#if 0
+ if ((bmsr & BMSR_ACOMP) == 0)
+ printf("%s: autonegotiation failed to complete\n",
+ mii->mii_dev.dv_xname);
+#endif
+ }
+
+ /*
+ * Don't need to worry about clearing MIIF_DOINGAUTO.
+ * If that's set, a timeout is pending, and it will
+ * clear the flag.
+ */
+ return (EIO);
+ }
+
+ /*
+ * Just let it finish asynchronously. This is for the benefit of
+ * the tick handler driving autonegotiation. Don't want 500ms
+ * delays all the time while the system is running!
+ */
+ if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
+ mii->mii_flags |= MIIF_DOINGAUTO;
+ timeout(mii_phy_auto_timeout, mii, hz >> 1);
+ }
+ return (EJUSTRETURN);
+}
+
+void
+mii_phy_auto_timeout(arg)
+ void *arg;
+{
+ struct mii_softc *mii = arg;
+ int s, bmsr;
+
+ s = splnet();
+ mii->mii_flags &= ~MIIF_DOINGAUTO;
+ bmsr = PHY_READ(mii, MII_BMSR);
+#if 0
+ if ((bmsr & BMSR_ACOMP) == 0)
+ printf("%s: autonegotiation failed to complete\n",
+ sc->sc_dev.dv_xname);
+#endif
+
+ /* Update the media status. */
+ (void) (*mii->mii_service)(mii, mii->mii_pdata, MII_POLLSTAT);
+ splx(s);
+}
+
+void
+mii_phy_reset(mii)
+ struct mii_softc *mii;
+{
+ int reg, i;
+
+ if (mii->mii_flags & MIIF_NOISOLATE)
+ reg = BMCR_RESET;
+ else
+ reg = BMCR_RESET | BMCR_ISO;
+ PHY_WRITE(mii, MII_BMCR, reg);
+
+ /* Wait 100ms for it to complete. */
+ for (i = 0; i < 100; i++) {
+ reg = PHY_READ(mii, MII_BMCR);
+ if ((reg & BMCR_RESET) == 0)
+ break;
+ DELAY(1000);
+ }
+
+ if (mii->mii_inst != 0 && ((mii->mii_flags & MIIF_NOISOLATE) == 0))
+ PHY_WRITE(mii, MII_BMCR, reg | BMCR_ISO);
+}
+
+/*
+ * 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(mii, bmsr, instance)
+ struct mii_data *mii;
+ int bmsr, instance;
+{
+ 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 (bmsr & BMSR_10THDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, instance), 0);
+ PRINT("10baseT");
+ }
+ if (bmsr & BMSR_10TFDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, instance),
+ BMCR_FDX);
+ PRINT("10baseT-FDX");
+ }
+ if (bmsr & BMSR_100TXHDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, instance),
+ BMCR_S100);
+ PRINT("100baseTX");
+ }
+ if (bmsr & BMSR_100TXFDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, instance),
+ BMCR_S100|BMCR_FDX);
+ PRINT("100baseTX-FDX");
+ }
+ if (bmsr & 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, instance),
+ BMCR_S100);
+ PRINT("100baseT4");
+ }
+ if (bmsr & BMSR_ANEG) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, instance),
+ BMCR_AUTOEN);
+ PRINT("auto");
+ }
+#undef ADD
+#undef PRINT
+}
diff --git a/sys/dev/mii/miibus_if.m b/sys/dev/mii/miibus_if.m
new file mode 100644
index 0000000..d540964
--- /dev/null
+++ b/sys/dev/mii/miibus_if.m
@@ -0,0 +1,36 @@
+# $FreeBSD$
+
+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 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..8d24ce1
--- /dev/null
+++ b/sys/dev/mii/miidevs
@@ -0,0 +1,122 @@
+$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 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 LEVEL1 0x00207b Level 1
+oui NATSEMI 0x080017 National Semiconductor
+oui QUALSEMI 0x006051 Quality Semiconductor
+oui SEEQ 0x00a07d Seeq
+oui SIS 0x00e006 Silicon Integrated Systems
+oui TI 0x080028 Texas Instruments
+
+
+/* in the 79c873, AMD uses another OUI (which matches Davicom!) */
+oui xxAMD 0x00606e Advanced Micro Devices
+
+/* some vendors have the bits swapped within bytes
+ (ie, ordered as on the wire) */
+oui xxICS 0x00057d Integrated Circuit Systems
+oui xxSEEQ 0x0005be Seeq
+oui xxSIS 0x000760 Silicon Integrated Systems
+oui xxTI 0x100014 Texas Instruments
+
+/* 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
+
+
+/*
+ * List of known models. Grouped by oui.
+ */
+
+/* Advanced Micro Devices PHYs */
+model xxAMD 79C873 0x0000 Am79C873 10/100 media interface
+model AMD 79c973phy 0x0036 Am79c973 internal PHY
+
+/* Broadcom Corp. PHYs. */
+model BROADCOM 3c905Cphy 0x0017 3c905C 10/100 internal 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 INTEL I82555 0x0015 i82555 10/100 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
+
+/* Quality Semiconductor PHYs */
+model QUALSEMI QS6612 0x0000 QS6612 10/100 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
+
+/* Texas Instruments PHYs */
+model xxTI TLAN10T 0x0001 ThunderLAN 10baseT media interface
+model xxTI 100VGPMI 0x0002 ThunderLAN 100VG-AnyLan media interface
diff --git a/sys/dev/mii/miidevs.h b/sys/dev/mii/miidevs.h
new file mode 100644
index 0000000..d9108e8
--- /dev/null
+++ b/sys/dev/mii/miidevs.h
@@ -0,0 +1,144 @@
+/* $FreeBSD$ */
+
+/*
+ * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ * generated from:
+ * Id: miidevs,v 1.3 1999/08/29 15:42:04 wpaul Exp
+ */
+/*$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.
+ */
+
+#define MII_OUI_AMD 0x00001a /* Advanced Micro Devices */
+#define MII_OUI_BROADCOM 0x001018 /* Broadcom Corporation */
+#define MII_OUI_DAVICOM 0x00606e /* Davicom Semiconductor */
+#define MII_OUI_ICS 0x00a0be /* Integrated Circuit Systems */
+#define MII_OUI_INTEL 0x00aa00 /* Intel */
+#define MII_OUI_LEVEL1 0x00207b /* Level 1 */
+#define MII_OUI_NATSEMI 0x080017 /* National Semiconductor */
+#define MII_OUI_QUALSEMI 0x006051 /* Quality Semiconductor */
+#define MII_OUI_SEEQ 0x00a07d /* Seeq */
+#define MII_OUI_SIS 0x00e006 /* Silicon Integrated Systems */
+#define MII_OUI_TI 0x080028 /* Texas Instruments */
+
+
+/* in the 79c873, AMD uses another OUI (which matches Davicom!) */
+#define MII_OUI_xxAMD 0x00606e /* Advanced Micro Devices */
+
+/* some vendors have the bits swapped within bytes
+ (ie, ordered as on the wire) */
+#define MII_OUI_xxICS 0x00057d /* Integrated Circuit Systems */
+#define MII_OUI_xxSEEQ 0x0005be /* Seeq */
+#define MII_OUI_xxSIS 0x000760 /* Silicon Integrated Systems */
+#define MII_OUI_xxTI 0x100014 /* Texas Instruments */
+
+/* Level 1 is completely different - from right to left.
+ (Two bits get lost in the third OUI byte.) */
+#define MII_OUI_xxLEVEL1 0x1e0400 /* Level 1 */
+
+/* Don't know what's going on here. */
+#define MII_OUI_xxDAVICOM 0x006040 /* Davicom Semiconductor */
+
+
+/*
+ * List of known models. Grouped by oui.
+ */
+
+/* Advanced Micro Devices PHYs */
+#define MII_MODEL_xxAMD_79C873 0x0000
+#define MII_STR_xxAMD_79C873 "Am79C873 10/100 media interface"
+#define MII_MODEL_AMD_79c973phy 0x0036
+#define MII_STR_AMD_79c973phy "Am79c973 internal PHY"
+
+/* Broadcom Corp. PHYs. */
+#define MII_MODEL_BROADCOM_3c905Cphy 0x0017
+#define MII_STR_BROADCOM_3c905Cphy "3c905C 10/100 internal PHY"
+
+/* Davicom Semiconductor PHYs */
+#define MII_MODEL_xxDAVICOM_DM9101 0x0000
+#define MII_STR_xxDAVICOM_DM9101 "DM9101 10/100 media interface"
+
+/* Integrated Circuit Systems PHYs */
+#define MII_MODEL_xxICS_1890 0x0002
+#define MII_STR_xxICS_1890 "ICS1890 10/100 media interface"
+
+/* Intel PHYs */
+#define MII_MODEL_INTEL_I82555 0x0015
+#define MII_STR_INTEL_I82555 "i82555 10/100 media interface"
+
+/* Level 1 PHYs */
+#define MII_MODEL_xxLEVEL1_LXT970 0x0000
+#define MII_STR_xxLEVEL1_LXT970 "LXT970 10/100 media interface"
+
+/* National Semiconductor PHYs */
+#define MII_MODEL_NATSEMI_DP83840 0x0000
+#define MII_STR_NATSEMI_DP83840 "DP83840 10/100 media interface"
+#define MII_MODEL_NATSEMI_DP83843 0x0001
+#define MII_STR_NATSEMI_DP83843 "DP83843 10/100 media interface"
+
+/* Quality Semiconductor PHYs */
+#define MII_MODEL_QUALSEMI_QS6612 0x0000
+#define MII_STR_QUALSEMI_QS6612 "QS6612 10/100 media interface"
+
+/* Seeq PHYs */
+#define MII_MODEL_xxSEEQ_80220 0x0003
+#define MII_STR_xxSEEQ_80220 "Seeq 80220 10/100 media interface"
+#define MII_MODEL_xxSEEQ_84220 0x0004
+#define MII_STR_xxSEEQ_84220 "Seeq 84220 10/100 media interface"
+
+/* Silicon Integrated Systems PHYs */
+#define MII_MODEL_xxSIS_900 0x0000
+#define MII_STR_xxSIS_900 "SiS 900 10/100 media interface"
+
+/* Texas Instruments PHYs */
+#define MII_MODEL_xxTI_TLAN10T 0x0001
+#define MII_STR_xxTI_TLAN10T "ThunderLAN 10baseT media interface"
+#define MII_MODEL_xxTI_100VGPMI 0x0002
+#define MII_STR_xxTI_100VGPMI "ThunderLAN 100VG-AnyLan media interface"
diff --git a/sys/dev/mii/miivar.h b/sys/dev/mii/miivar.h
new file mode 100644
index 0000000..52380fa
--- /dev/null
+++ b/sys/dev/mii/miivar.h
@@ -0,0 +1,178 @@
+/* $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 autoconfiguration defintions.
+ *
+ * This file exports an interface which attempts to be compatible
+ * with the BSD/OS 3.0 interface.
+ */
+
+struct mii_softc;
+
+/*
+ * Callbacks from MII layer into network interface device driver.
+ */
+typedef int (*mii_readreg_t) __P((struct device *, int, int));
+typedef void (*mii_writereg_t) __P((struct device *, int, int, int));
+typedef void (*mii_statchg_t) __P((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) __P((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_ticks; /* MII_TICK counter */
+ int mii_active; /* last active media */
+};
+typedef struct mii_softc mii_softc_t;
+
+/* mii_flags */
+#define MIIF_NOISOLATE 0x0001 /* do not isolate the PHY */
+#define MIIF_DOINGAUTO 0x0002 /* doing autonegotiation */
+
+/*
+ * 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;
+
+#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 __P((device_t));
+int miibus_attach __P((device_t));
+int miibus_detach __P((device_t));
+
+int mii_anar __P((int));
+int mii_mediachg __P((struct mii_data *));
+void mii_tick __P((struct mii_data *));
+void mii_pollstat __P((struct mii_data *));
+int mii_phy_probe __P((device_t, device_t *,
+ ifm_change_cb_t, ifm_stat_cb_t));
+void mii_add_media __P((struct mii_data *, int, int));
+
+int mii_media_from_bmcr __P((int));
+
+int mii_phy_auto __P((struct mii_softc *, int));
+void mii_phy_reset __P((struct mii_softc *));
+
+void ukphy_status __P((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..2bf1767
--- /dev/null
+++ b/sys/dev/mii/mlphy.c
@@ -0,0 +1,456 @@
+/*
+ * 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.
+ *
+ * $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/malloc.h>
+#include <sys/socket.h>
+#include <sys/module.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 "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 __P((device_t));
+static int mlphy_attach __P((device_t));
+static int mlphy_detach __P((device_t));
+
+static device_method_t mlphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, mlphy_probe),
+ DEVMETHOD(device_attach, mlphy_attach),
+ DEVMETHOD(device_detach, mlphy_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 __P((struct mii_softc *, struct mii_data *, int));
+static void mlphy_reset __P((struct mii_softc *));
+static void mlphy_status __P((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, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_add_media(mii, sc->mii_capabilities,
+ sc->mii_inst);
+ printf("\n");
+#undef ADD
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int mlphy_detach(dev)
+ device_t dev;
+{
+ struct mlphy_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->ml_mii.mii_dev = NULL;
+ LIST_REMOVE(&sc->ml_mii, mii_list);
+
+ 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;
+ }
+ }
+
+ 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, 1);
+ msc->ml_linked = 0;
+ return(0);
+ break;
+ 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);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (0);
+
+ sc->mii_ticks = 0;
+
+ /*
+ * 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;
+ }
+ return(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);
+ }
+ if (mii_phy_auto(sc, 0) == EJUSTRETURN)
+ return(0);
+ break;
+ }
+
+ /* 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_active = other->mii_active;
+ } else
+ ukphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+
+ 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;
+ }
+ }
+
+ 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, 1);
+ }
+
+ return;
+}
diff --git a/sys/dev/mii/nsphy.c b/sys/dev/mii/nsphy.c
new file mode 100644
index 0000000..4c58a4e
--- /dev/null
+++ b/sys/dev/mii/nsphy.c
@@ -0,0 +1,430 @@
+/* $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.
+ */
+
+/*
+ * 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/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.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 <dev/mii/miidevs.h>
+
+#include <dev/mii/nsphyreg.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+static int nsphy_probe __P((device_t));
+static int nsphy_attach __P((device_t));
+static int nsphy_detach __P((device_t));
+
+static device_method_t nsphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, nsphy_probe),
+ DEVMETHOD(device_attach, nsphy_attach),
+ DEVMETHOD(device_detach, nsphy_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);
+
+int nsphy_service __P((struct mii_softc *, struct mii_data *, int));
+void nsphy_status __P((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)
+ return (ENXIO);
+
+ device_set_desc(dev, MII_STR_NATSEMI_DP83840);
+
+ 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, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_add_media(mii, sc->mii_capabilities,
+ sc->mii_inst);
+ printf("\n");
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int nsphy_detach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+
+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;
+
+#if 0
+ /*
+ * Mystery bits which are supposedly `reserved',
+ * but we seem to need to set them when the PHY
+ * is connected to some interfaces!
+ */
+ reg |= 0x0100 | 0x0400;
+#endif
+/*
+ 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, 1);
+ 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);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * 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)
+ return (0);
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (0);
+
+ sc->mii_ticks = 0;
+ mii_phy_reset(sc);
+ if (mii_phy_auto(sc, 0) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ nsphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+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/pnphy.c b/sys/dev/mii/pnphy.c
new file mode 100644
index 0000000..0f8498e
--- /dev/null
+++ b/sys/dev/mii/pnphy.c
@@ -0,0 +1,311 @@
+/*
+ * 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$
+ */
+
+/*
+ * 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/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.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 <dev/mii/miidevs.h>
+
+#include <machine/clock.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"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+#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 __P((device_t));
+static int pnphy_attach __P((device_t));
+static int pnphy_detach __P((device_t));
+
+static device_method_t pnphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, pnphy_probe),
+ DEVMETHOD(device_attach, pnphy_attach),
+ DEVMETHOD(device_detach, pnphy_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);
+
+int pnphy_service __P((struct mii_softc *, struct mii_data *, int));
+void pnphy_status __P((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, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_add_media(mii, sc->mii_capabilities, sc->mii_inst);
+ 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_detach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+
+int
+pnphy_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;
+
+ 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;
+
+ 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);
+ break;
+ 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);
+ break;
+ default:
+ return(EINVAL);
+ break;
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ return(0);
+ }
+
+ /* Update the media status. */
+ pnphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+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/rlphy.c b/sys/dev/mii/rlphy.c
new file mode 100644
index 0000000..956160d
--- /dev/null
+++ b/sys/dev/mii/rlphy.c
@@ -0,0 +1,284 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * driver for RealTek 8139 internal PHYs
+ */
+
+#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_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+static int rlphy_probe __P((device_t));
+static int rlphy_attach __P((device_t));
+static int rlphy_detach __P((device_t));
+
+static device_method_t rlphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, rlphy_probe),
+ DEVMETHOD(device_attach, rlphy_attach),
+ DEVMETHOD(device_detach, rlphy_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);
+
+int rlphy_service __P((struct mii_softc *, struct mii_data *, int));
+void rlphy_reset __P((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));
+
+ /*
+ * 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'.
+ */
+ if (strcmp(device_get_name(parent), "rl") != 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);
+
+ rlphy_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
+ mii_add_media(mii, sc->mii_capabilities,
+ sc->mii_inst);
+ printf("\n");
+#undef ADD
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int rlphy_detach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_softc(dev));
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+
+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, 0);
+ 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:
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (0);
+
+ sc->mii_ticks = 0;
+
+ /*
+ * The RealTek 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. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+void
+rlphy_reset(sc)
+ struct mii_softc *sc;
+{
+
+ mii_phy_reset(sc);
+
+ /*
+ * XXX RealTek 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/tlphy.c b/sys/dev/mii/tlphy.c
new file mode 100644
index 0000000..f4e3ba8
--- /dev/null
+++ b/sys/dev/mii/tlphy.c
@@ -0,0 +1,457 @@
+/* $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.
+ */
+
+/*
+ * 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/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 <machine/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 <dev/mii/miidevs.h>
+
+#include <dev/mii/tlphyreg.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+struct tlphy_softc {
+ struct mii_softc sc_mii; /* generic PHY */
+ int sc_need_acomp;
+};
+
+static int tlphy_probe __P((device_t));
+static int tlphy_attach __P((device_t));
+static int tlphy_detach __P((device_t));
+
+static device_method_t tlphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, tlphy_probe),
+ DEVMETHOD(device_attach, tlphy_attach),
+ DEVMETHOD(device_detach, tlphy_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);
+
+int tlphy_service __P((struct mii_softc *, struct mii_data *, int));
+int tlphy_auto __P((struct tlphy_softc *, int));
+void tlphy_acomp __P((struct tlphy_softc *));
+void tlphy_status __P((struct tlphy_softc *));
+
+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;
+ }
+ }
+ }
+
+ 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(sep);
+ mii_add_media(mii, sc->sc_mii.mii_capabilities,
+ sc->sc_mii.mii_inst);
+ }
+
+ printf("\n");
+#undef ADD
+#undef PRINT
+ MIIBUS_MEDIAINIT(sc->sc_mii.mii_dev);
+ return(0);
+}
+
+static int tlphy_detach(dev)
+ device_t dev;
+{
+ struct tlphy_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->sc_mii.mii_dev = NULL;
+ LIST_REMOVE(&sc->sc_mii, mii_list);
+
+ return(0);
+}
+
+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_mii.mii_flags & MIIF_DOINGAUTO) == 0 && 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, 1);
+ 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);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * 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)
+ return (0);
+
+ /*
+ * 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);
+ if (tlphy_auto(sc, 0) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ tlphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->sc_mii.mii_active != mii->mii_media_active ||
+ cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->sc_mii.mii_dev);
+ sc->sc_mii.mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+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;
+}
+
+int
+tlphy_auto(sc, waitfor)
+ struct tlphy_softc *sc;
+ int waitfor;
+{
+ int error;
+
+ switch ((error = mii_phy_auto(&sc->sc_mii, waitfor))) {
+ 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);
+}
+
+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..cb22eab
--- /dev/null
+++ b/sys/dev/mii/ukphy.c
@@ -0,0 +1,313 @@
+/* $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.
+ */
+
+/*
+ * 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/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.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 "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+static int ukphy_probe __P((device_t));
+static int ukphy_attach __P((device_t));
+static int ukphy_detach __P((device_t));
+
+static device_method_t ukphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ukphy_probe),
+ DEVMETHOD(device_attach, ukphy_attach),
+ DEVMETHOD(device_detach, ukphy_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);
+
+int ukphy_service __P((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;
+
+#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, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_add_media(mii, sc->mii_capabilities,
+ sc->mii_inst);
+ printf("\n");
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+
+ return(0);
+}
+
+static int ukphy_detach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+
+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;
+
+ 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, 1);
+ 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);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ /*
+ * 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)
+ return (0);
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (0);
+
+ sc->mii_ticks = 0;
+ mii_phy_reset(sc);
+ if (mii_phy_auto(sc, 0) == EJUSTRETURN)
+ return (0);
+ break;
+ }
+
+ /* Update the media status. */
+ ukphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
diff --git a/sys/dev/mii/ukphy_subr.c b/sys/dev/mii/ukphy_subr.c
new file mode 100644
index 0000000..d39ef46
--- /dev/null
+++ b/sys/dev/mii/ukphy_subr.c
@@ -0,0 +1,120 @@
+/* $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.
+ */
+
+/*
+ * Subroutines shared by the ukphy driver and other PHY drivers.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.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"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Media status subroutine. If a PHY driver does media detection simply
+ * by decoding the NWay autonegotiation, use this routine.
+ */
+void
+ukphy_status(phy)
+ struct mii_softc *phy;
+{
+ struct mii_data *mii = phy->mii_pdata;
+ 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 = mii_media_from_bmcr(bmcr);
+}
OpenPOWER on IntegriCloud