summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/man4.i386/mx.41
-rw-r--r--share/man/man4/mx.41
-rw-r--r--sys/alpha/conf/GENERIC4
-rw-r--r--sys/alpha/conf/NOTES4
-rw-r--r--sys/amd64/conf/GENERIC2
-rw-r--r--sys/dev/mii/mxphy.c487
-rw-r--r--sys/i386/conf/GENERIC2
-rw-r--r--sys/modules/mii/Makefile2
-rw-r--r--sys/modules/mx/Makefile7
-rw-r--r--sys/pci/if_mx.c924
-rw-r--r--sys/pci/if_mxreg.h140
11 files changed, 683 insertions, 891 deletions
diff --git a/share/man/man4/man4.i386/mx.4 b/share/man/man4/man4.i386/mx.4
index 6a96041..ada9d48 100644
--- a/share/man/man4/man4.i386/mx.4
+++ b/share/man/man4/man4.i386/mx.4
@@ -38,6 +38,7 @@
.Nd
Macronix 98713/98715/98725 fast ethernet device driver
.Sh SYNOPSIS
+.Cd "controller miibus0"
.Cd "device mx0"
.Sh DESCRIPTION
The
diff --git a/share/man/man4/mx.4 b/share/man/man4/mx.4
index 6a96041..ada9d48 100644
--- a/share/man/man4/mx.4
+++ b/share/man/man4/mx.4
@@ -38,6 +38,7 @@
.Nd
Macronix 98713/98715/98725 fast ethernet device driver
.Sh SYNOPSIS
+.Cd "controller miibus0"
.Cd "device mx0"
.Sh DESCRIPTION
The
diff --git a/sys/alpha/conf/GENERIC b/sys/alpha/conf/GENERIC
index 1a18c6c..cd5094b 100644
--- a/sys/alpha/conf/GENERIC
+++ b/sys/alpha/conf/GENERIC
@@ -116,13 +116,13 @@ device ax0 # ASIX AX88140A
device de0 # DEC/Intel DC21x4x (``Tulip'')
device fxp0 # Intel EtherExpress PRO/100B (82557, 82558)
device le0 # Lance
-device mx0 # Macronix 98713/98715/98725 (``PMAC'')
+device pn0 # Lite-On 82c168/82c169 (``PNIC'')
# PCI Ethernet NICs that use the common MII bus controller code.
controller miibus0 # MII bus support
device al0 # ADMtek AL981/AN985 (``Comet''/``Centaur'')
device dm0 # Davicom DM9100/DM9102
-device pn0 # Lite-On 82c168/82c169 (``PNIC'')
+device mx0 # Macronix 98713/98715/98725 (``PMAC'')
device rl0 # RealTek 8129/8139
device sf0 # Adaptec AIC-6915 (``Starfire'')
device sis0 # Silicon Integrated Systems SiS 900/SiS 7016
diff --git a/sys/alpha/conf/NOTES b/sys/alpha/conf/NOTES
index 1a18c6c..cd5094b 100644
--- a/sys/alpha/conf/NOTES
+++ b/sys/alpha/conf/NOTES
@@ -116,13 +116,13 @@ device ax0 # ASIX AX88140A
device de0 # DEC/Intel DC21x4x (``Tulip'')
device fxp0 # Intel EtherExpress PRO/100B (82557, 82558)
device le0 # Lance
-device mx0 # Macronix 98713/98715/98725 (``PMAC'')
+device pn0 # Lite-On 82c168/82c169 (``PNIC'')
# PCI Ethernet NICs that use the common MII bus controller code.
controller miibus0 # MII bus support
device al0 # ADMtek AL981/AN985 (``Comet''/``Centaur'')
device dm0 # Davicom DM9100/DM9102
-device pn0 # Lite-On 82c168/82c169 (``PNIC'')
+device mx0 # Macronix 98713/98715/98725 (``PMAC'')
device rl0 # RealTek 8129/8139
device sf0 # Adaptec AIC-6915 (``Starfire'')
device sis0 # Silicon Integrated Systems SiS 900/SiS 7016
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index ddc7905..827ace1 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -161,7 +161,6 @@ device ppi0 # Parallel port interface device
device ax0 # ASIX AX88140A
device de0 # DEC/Intel DC21x4x (``Tulip'')
device fxp0 # Intel EtherExpress PRO/100B (82557, 82558)
-device mx0 # Macronix 98713/98715/98725 (``PMAC'')
device pn0 # Lite-On 82c168/82c169 (``PNIC'')
device tx0 # SMC 9432TX (83c170 ``EPIC'')
device vx0 # 3Com 3c590, 3c595 (``Vortex'')
@@ -170,6 +169,7 @@ device vx0 # 3Com 3c590, 3c595 (``Vortex'')
controller miibus0 # MII bus support
device al0 # ADMtek AL981/AN985 (``Comet''/``Centaur'')
device dm0 # Davicom DM9100/DM9102
+device mx0 # Macronix 98713/98715/98725 (``PMAC'')
device rl0 # RealTek 8129/8139
device sf0 # Adaptec AIC-6915 (``Starfire'')
device sis0 # Silicon Integrated Systems SiS 900/SiS 7016
diff --git a/sys/dev/mii/mxphy.c b/sys/dev/mii/mxphy.c
new file mode 100644
index 0000000..532847e
--- /dev/null
+++ b/sys/dev/mii/mxphy.c
@@ -0,0 +1,487 @@
+/*
+ * 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 Macronix 98713/98715/98725
+ * PMAC controller chips. The Macronix chips use the same internal
+ * NWAY register layout as the DEC/Intel 21143. Technically we're
+ * abusing the miibus code to handle the 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/if_mxreg.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+#define MX_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) | x)
+
+#define MX_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) & ~x)
+
+struct mxphy_softc {
+ struct mii_softc mx_mii;
+ u_int32_t mx_linkstate;
+ u_int32_t mx_media;
+};
+
+static int mxphy_probe __P((device_t));
+static int mxphy_attach __P((device_t));
+static int mxphy_detach __P((device_t));
+
+static device_method_t mxphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, mxphy_probe),
+ DEVMETHOD(device_attach, mxphy_attach),
+ DEVMETHOD(device_detach, mxphy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t mxphy_devclass;
+
+static driver_t mxphy_driver = {
+ "mxphy",
+ mxphy_methods,
+ sizeof(struct mxphy_softc)
+};
+
+DRIVER_MODULE(mxphy, miibus, mxphy_driver, mxphy_devclass, 0, 0);
+
+int mxphy_service __P((struct mii_softc *, struct mii_data *, int));
+void mxphy_status __P((struct mii_softc *));
+static int mxphy_auto __P((struct mii_softc *, int));
+static void mxphy_auto_timeout __P((void *));
+static void mxphy_reset __P((struct mii_softc *));
+
+static int mxphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ /*
+ * The mx driver will report the Macronix vendor ID
+ * and the 98715 device ID to let us know that it wants
+ * us to attach. Actually, we could also be attached
+ * in the case of a 98713A chip, but there's no point
+ * in differentiating between the two since we do the
+ * same things for both.
+ */
+ if (ma->mii_id1 != MX_VENDORID ||
+ ma->mii_id2 != MX_DEVICEID_987x5)
+ return(ENXIO);
+
+ device_set_desc(dev, "Macronix NWAY media interface");
+
+ return (0);
+}
+
+static int mxphy_attach(dev)
+ device_t dev;
+{
+ struct mxphy_softc *msc;
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ msc = device_get_softc(dev);
+ sc = &msc->mx_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 = mxphy_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);
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+
+ /*mxphy_reset(sc);*/
+
+ sc->mii_capabilities =
+ BMSR_ANEG|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");
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int mxphy_detach(dev)
+ device_t dev;
+{
+ struct mxphy_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->mx_mii.mii_dev = NULL;
+ LIST_REMOVE(&sc->mx_mii, mii_list);
+
+ return(0);
+}
+
+int
+mxphy_service(xsc, mii, cmd)
+ struct mii_softc *xsc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct mx_softc *mx_sc;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+ u_int32_t mode;
+ struct mxphy_softc *msc = (struct mxphy_softc *)xsc;
+ struct mii_softc *sc = (struct mii_softc *)&msc->mx_mii;
+
+ mx_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;
+
+ mode = CSR_READ_4(mx_sc, MX_NETCFG);
+ mode &= ~(MX_NETCFG_FULLDUPLEX|MX_NETCFG_PORTSEL|
+ MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER|MX_NETCFG_SPEEDSEL);
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ mxphy_reset(sc);
+ (void) mxphy_auto(sc, 1);
+ msc->mx_linkstate = msc->mx_media = 0;
+ break;
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ case IFM_100_TX:
+ mode |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS|
+ MX_NETCFG_SCRAMBLER;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mode |= MX_NETCFG_FULLDUPLEX;
+ else
+ mode &= ~MX_NETCFG_FULLDUPLEX;
+ MX_CLRBIT(mx_sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL);
+ CSR_WRITE_4(mx_sc, MX_NETCFG, mode);
+ break;
+ case IFM_10_T:
+ mode &= ~MX_NETCFG_PORTSEL;
+ mode |= MX_NETCFG_SPEEDSEL;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mode |= MX_NETCFG_FULLDUPLEX;
+ else
+ mode &= ~MX_NETCFG_FULLDUPLEX;
+ MX_CLRBIT(mx_sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL);
+ CSR_WRITE_4(mx_sc, MX_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);
+
+ /*
+ * 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(mx_sc, MX_10BTSTAT) &
+ (MX_TSTAT_LS10|MX_TSTAT_LS100);
+ reg = CSR_READ_4(mx_sc, MX_10BTSTAT) &
+ (MX_TSTAT_LS10|MX_TSTAT_LS100);
+
+ if (reg == msc->mx_linkstate)
+ return (0);
+ if (!reg) {
+ msc->mx_linkstate = reg;
+ break;
+ }
+ msc->mx_media = 0;
+ sc->mii_ticks = 0;
+ msc->mx_linkstate = reg;
+ mxphy_reset(sc);
+ if (mxphy_auto(sc, 0) == EJUSTRETURN)
+ return (0);
+
+ break;
+ }
+
+ /* Update the media status. */
+ mxphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ DELAY(100000);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+void
+mxphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int /*bmsr, bmcr,*/ reg, anlpar;
+ struct mx_softc *mx_sc;
+ struct mxphy_softc *msc = (struct mxphy_softc *)sc;
+
+ mx_sc = mii->mii_ifp->if_softc;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ reg = CSR_READ_4(mx_sc, MX_10BTSTAT) &
+ (MX_TSTAT_LS10|MX_TSTAT_LS100);
+
+ if (!(reg & MX_TSTAT_LS10) || !(reg & MX_TSTAT_LS100))
+ mii->mii_media_status |= IFM_ACTIVE;
+
+
+ if (CSR_READ_4(mx_sc, MX_10BTCTRL) & MX_TCTL_AUTONEGENBL &&
+ CSR_READ_4(mx_sc, MX_10BTSTAT) & MX_TSTAT_ANEGSTAT) {
+ if (!(CSR_READ_4(mx_sc, MX_10BTSTAT) & 0xFFFF0000)) {
+ /* Erg, still trying, I guess... */
+ if (CSR_READ_4(mx_sc, MX_10BTSTAT) &
+ MX_TSTAT_LP_CAN_NWAY) {
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ } else
+ msc->mx_media = 0;
+ }
+
+ if (CSR_READ_4(mx_sc, MX_10BTSTAT) & MX_TSTAT_LP_CAN_NWAY) {
+ anlpar = CSR_READ_4(mx_sc, MX_10BTSTAT) >> 16;
+ 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;
+ msc->mx_media = mii->mii_media_active;
+ return;
+ }
+ }
+ if (msc->mx_media)
+ mii->mii_media_active = msc->mx_media;
+ reg = CSR_READ_4(mx_sc, MX_10BTSTAT) &
+ (MX_TSTAT_LS10|MX_TSTAT_LS100);
+
+ msc->mx_linkstate = reg;
+ if (!(reg & MX_TSTAT_LS100))
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ msc->mx_media = mii->mii_media_active;
+
+ return;
+}
+
+static int
+mxphy_auto(mii, waitfor)
+ struct mii_softc *mii;
+ int waitfor;
+{
+ int i;
+ struct mx_softc *sc;
+
+ sc = mii->mii_pdata->mii_ifp->if_softc;
+
+ if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
+ CSR_WRITE_4(sc, MX_10BTCTRL, 0x3FFFF);
+ MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
+ MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX);
+ MX_SETBIT(sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL);
+ MX_SETBIT(sc, MX_10BTCTRL, MX_ASTAT_TXDISABLE);
+ DELAY(1000000);
+ }
+
+ if (waitfor) {
+ /* Wait 500ms for it to complete. */
+ for (i = 0; i < 500; i++) {
+ if ((CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_ANEGSTAT)
+ == MX_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;
+ timeout(mxphy_auto_timeout, mii, hz >> 1);
+ }
+ return(EJUSTRETURN);
+}
+
+static void
+mxphy_auto_timeout(arg)
+ void *arg;
+{
+ struct mii_softc *mii = arg;
+ int s;
+
+ s = splnet();
+ mii->mii_flags &= ~MIIF_DOINGAUTO;
+
+ /* Update the media status. */
+ (void) (*mii->mii_service)(mii, mii->mii_pdata, MII_POLLSTAT);
+ splx(s);
+}
+
+static void
+mxphy_reset(mii)
+ struct mii_softc *mii;
+{
+ struct mx_softc *sc;
+
+ sc = mii->mii_pdata->mii_ifp->if_softc;
+
+ MX_SETBIT(sc, MX_SIARESET, MX_SIA_RESET_NWAY);
+ DELAY(1000);
+ MX_CLRBIT(sc, MX_SIARESET, MX_SIA_RESET_NWAY);
+
+ return;
+}
+
diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC
index ddc7905..827ace1 100644
--- a/sys/i386/conf/GENERIC
+++ b/sys/i386/conf/GENERIC
@@ -161,7 +161,6 @@ device ppi0 # Parallel port interface device
device ax0 # ASIX AX88140A
device de0 # DEC/Intel DC21x4x (``Tulip'')
device fxp0 # Intel EtherExpress PRO/100B (82557, 82558)
-device mx0 # Macronix 98713/98715/98725 (``PMAC'')
device pn0 # Lite-On 82c168/82c169 (``PNIC'')
device tx0 # SMC 9432TX (83c170 ``EPIC'')
device vx0 # 3Com 3c590, 3c595 (``Vortex'')
@@ -170,6 +169,7 @@ device vx0 # 3Com 3c590, 3c595 (``Vortex'')
controller miibus0 # MII bus support
device al0 # ADMtek AL981/AN985 (``Comet''/``Centaur'')
device dm0 # Davicom DM9100/DM9102
+device mx0 # Macronix 98713/98715/98725 (``PMAC'')
device rl0 # RealTek 8129/8139
device sf0 # Adaptec AIC-6915 (``Starfire'')
device sis0 # Silicon Integrated Systems SiS 900/SiS 7016
diff --git a/sys/modules/mii/Makefile b/sys/modules/mii/Makefile
index 4949f25..9c36977 100644
--- a/sys/modules/mii/Makefile
+++ b/sys/modules/mii/Makefile
@@ -5,7 +5,7 @@ S = ${.CURDIR}/../..
KMOD = miibus
SRCS = mii.c mii_physubr.c ukphy.c ukphy_subr.c bus_if.h
SRCS += miibus_if.h device_if.h miibus_if.c exphy.c nsphy.c
-SRCS += mlphy.c tlphy.c rlphy.c amphy.c
+SRCS += mlphy.c tlphy.c rlphy.c amphy.c mxphy.c
CLEANFILES += device_if.h bus_if.h miibus_if.h miibus_if.c
CFLAGS += ${DEBUG_FLAGS}
diff --git a/sys/modules/mx/Makefile b/sys/modules/mx/Makefile
index 8cbcad5..0ffb2f6 100644
--- a/sys/modules/mx/Makefile
+++ b/sys/modules/mx/Makefile
@@ -3,8 +3,8 @@
S = ${.CURDIR}/../..
.PATH: $S/pci
KMOD = if_mx
-SRCS = if_mx.c opt_bdg.h device_if.h bus_if.h pci_if.h
-CLEANFILES += opt_bdg.h device_if.h bus_if.h pci_if.h
+SRCS = if_mx.c opt_bdg.h device_if.h bus_if.h pci_if.h miibus_if.h
+CLEANFILES += opt_bdg.h device_if.h bus_if.h pci_if.h miibus_if.h
CFLAGS += ${DEBUG_FLAGS}
opt_bdg.h:
@@ -19,4 +19,7 @@ bus_if.h: $S/kern/makedevops.pl $S/kern/bus_if.m
pci_if.h: $S/kern/makedevops.pl $S/pci/pci_if.m
perl $S/kern/makedevops.pl -h $S/pci/pci_if.m
+miibus_if.h: $S/kern/makedevops.pl $S/dev/mii/miibus_if.m
+ perl $S/kern/makedevops.pl -h $S/dev/mii/miibus_if.m
+
.include <bsd.kmod.mk>
diff --git a/sys/pci/if_mx.c b/sys/pci/if_mx.c
index 95e383b..71214a2 100644
--- a/sys/pci/if_mx.c
+++ b/sys/pci/if_mx.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 1998
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ * 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
@@ -35,7 +35,7 @@
/*
* Macronix PMAC fast ethernet PCI NIC driver
*
- * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Written by Bill Paul <wpaul@ee.columbia.edu>
* Electrical Engineering Department
* Columbia University, New York City
*/
@@ -82,15 +82,19 @@
#include <sys/bus.h>
#include <sys/rman.h>
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
#include <pci/pcireg.h>
#include <pci/pcivar.h>
#define MX_USEIOSPACE
-/* #define MX_BACKGROUND_AUTONEG */
-
#include <pci/if_mxreg.h>
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
@@ -117,22 +121,6 @@ static struct mx_type mx_devs[] = {
{ 0, 0, NULL }
};
-/*
- * Various supported PHY vendors/types and their names. Note that
- * this driver will work with pretty much any MII-compliant PHY,
- * so failure to positively identify the chip is not a fatal error.
- */
-
-static struct mx_type mx_phys[] = {
- { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" },
- { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" },
- { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"},
- { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" },
- { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" },
- { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" },
- { 0, 0, "<MII-compliant physical interface>" }
-};
-
static int mx_probe __P((device_t));
static int mx_attach __P((device_t));
static int mx_detach __P((device_t));
@@ -147,6 +135,7 @@ static void mx_rxeof __P((struct mx_softc *));
static void mx_rxeoc __P((struct mx_softc *));
static void mx_txeof __P((struct mx_softc *));
static void mx_txeoc __P((struct mx_softc *));
+static void mx_tick __P((void *));
static void mx_intr __P((void *));
static void mx_start __P((struct ifnet *));
static int mx_ioctl __P((struct ifnet *, u_long, caddr_t));
@@ -170,15 +159,11 @@ static void mx_mii_sync __P((struct mx_softc *));
static void mx_mii_send __P((struct mx_softc *, u_int32_t, int));
static int mx_mii_readreg __P((struct mx_softc *, struct mx_mii_frame *));
static int mx_mii_writereg __P((struct mx_softc *, struct mx_mii_frame *));
-static u_int16_t mx_phy_readreg __P((struct mx_softc *, int));
-static void mx_phy_writereg __P((struct mx_softc *, int, int));
-
-static void mx_autoneg_xmit __P((struct mx_softc *));
-static void mx_autoneg_mii __P((struct mx_softc *, int, int));
-static void mx_autoneg __P((struct mx_softc *, int, int));
-static void mx_setmode_mii __P((struct mx_softc *, int));
-static void mx_setmode __P((struct mx_softc *, int, int));
-static void mx_getmode_mii __P((struct mx_softc *));
+
+static int mx_miibus_readreg __P((device_t, int, int));
+static int mx_miibus_writereg __P((device_t, int, int, int));
+static void mx_miibus_statchg __P((device_t));
+
static void mx_setcfg __P((struct mx_softc *, int));
static u_int32_t mx_calchash __P((struct mx_softc *, caddr_t));
static void mx_setfilt __P((struct mx_softc *));
@@ -200,6 +185,16 @@ static device_method_t mx_methods[] = {
DEVMETHOD(device_attach, mx_attach),
DEVMETHOD(device_detach, mx_detach),
DEVMETHOD(device_shutdown, mx_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, mx_miibus_readreg),
+ DEVMETHOD(miibus_writereg, mx_miibus_writereg),
+ DEVMETHOD(miibus_statchg, mx_miibus_statchg),
+
{ 0, 0 }
};
@@ -212,6 +207,7 @@ static driver_t mx_driver = {
static devclass_t mx_devclass;
DRIVER_MODULE(if_mx, pci, mx_driver, mx_devclass, 0, 0);
+DRIVER_MODULE(miibus, mx, miibus_driver, miibus_devclass, 0, 0);
#define MX_SETBIT(sc, reg, x) \
CSR_WRITE_4(sc, reg, \
@@ -553,43 +549,78 @@ static int mx_mii_writereg(sc, frame)
return(0);
}
-static u_int16_t mx_phy_readreg(sc, reg)
- struct mx_softc *sc;
- int reg;
+static int mx_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
{
+ struct mx_softc *sc;
struct mx_mii_frame frame;
- u_int32_t cfg;
+ sc = device_get_softc(dev);
bzero((char *)&frame, sizeof(frame));
- frame.mii_phyaddr = sc->mx_phy_addr;
+ if (sc->mx_type != MX_TYPE_98713) {
+ if (phy == (MII_NPHY - 1)) {
+ switch(reg) {
+ case MII_BMSR:
+ /*
+ * Fake something to make the probe
+ * code think there's a PHY here.
+ */
+ return(BMSR_MEDIAMASK);
+ break;
+ case MII_PHYIDR1:
+ return(MX_VENDORID);
+ break;
+ case MII_PHYIDR2:
+ return(MX_DEVICEID_987x5);
+ break;
+ default:
+ return(0);
+ break;
+ }
+ }
+ }
+
+ frame.mii_phyaddr = phy;
frame.mii_regaddr = reg;
- cfg = CSR_READ_4(sc, MX_NETCFG);
MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
mx_mii_readreg(sc, &frame);
- CSR_WRITE_4(sc, MX_NETCFG, cfg);
+ MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
return(frame.mii_data);
}
-static void mx_phy_writereg(sc, reg, data)
- struct mx_softc *sc;
- int reg;
- int data;
+static int mx_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
{
struct mx_mii_frame frame;
- u_int32_t cfg;
+ struct mx_softc *sc;
+ sc = device_get_softc(dev);
bzero((char *)&frame, sizeof(frame));
- frame.mii_phyaddr = sc->mx_phy_addr;
+ frame.mii_phyaddr = phy;
frame.mii_regaddr = reg;
frame.mii_data = data;
- cfg = CSR_READ_4(sc, MX_NETCFG);
MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
mx_mii_writereg(sc, &frame);
- CSR_WRITE_4(sc, MX_NETCFG, cfg);
+ MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
+
+ return(0);
+}
+
+static void mx_miibus_statchg(dev)
+ device_t dev;
+{
+ struct mx_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(sc->mx_miibus);
+ mx_setcfg(sc, mii->mii_media_active);
return;
}
@@ -620,504 +651,6 @@ static u_int32_t mx_calchash(sc, addr)
}
/*
- * Initiate an autonegotiation session.
- */
-static void mx_autoneg_xmit(sc)
- struct mx_softc *sc;
-{
- u_int16_t phy_sts;
-
- mx_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
- DELAY(500);
- while(mx_phy_readreg(sc, PHY_BMCR)
- & PHY_BMCR_RESET);
-
- phy_sts = mx_phy_readreg(sc, PHY_BMCR);
- phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR;
- mx_phy_writereg(sc, PHY_BMCR, phy_sts);
-
- return;
-}
-
-/*
- * Invoke autonegotiation on a PHY.
- */
-static void mx_autoneg_mii(sc, flag, verbose)
- struct mx_softc *sc;
- int flag;
- int verbose;
-{
- u_int16_t phy_sts = 0, media, advert, ability;
- struct ifnet *ifp;
- struct ifmedia *ifm;
-
- ifm = &sc->ifmedia;
- ifp = &sc->arpcom.ac_if;
-
- ifm->ifm_media = IFM_ETHER | IFM_AUTO;
-
- /*
- * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported'
- * bit cleared in the status register, but has the 'autoneg enabled'
- * bit set in the control register. This is a contradiction, and
- * I'm not sure how to handle it. If you want to force an attempt
- * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR
- * and see what happens.
- */
-#ifndef FORCE_AUTONEG_TFOUR
- /*
- * First, see if autoneg is supported. If not, there's
- * no point in continuing.
- */
- phy_sts = mx_phy_readreg(sc, PHY_BMSR);
- if (!(phy_sts & PHY_BMSR_CANAUTONEG)) {
- if (verbose)
- printf("mx%d: autonegotiation not supported\n",
- sc->mx_unit);
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
- return;
- }
-#endif
-
- switch (flag) {
- case MX_FLAG_FORCEDELAY:
- /*
- * XXX Never use this option anywhere but in the probe
- * routine: making the kernel stop dead in its tracks
- * for three whole seconds after we've gone multi-user
- * is really bad manners.
- */
- mx_autoneg_xmit(sc);
- DELAY(5000000);
- break;
- case MX_FLAG_SCHEDDELAY:
- /*
- * Wait for the transmitter to go idle before starting
- * an autoneg session, otherwise mx_start() may clobber
- * our timeout, and we don't want to allow transmission
- * during an autoneg session since that can screw it up.
- */
- if (sc->mx_cdata.mx_tx_head != NULL) {
- sc->mx_want_auto = 1;
- return;
- }
- mx_autoneg_xmit(sc);
- ifp->if_timer = 5;
- sc->mx_autoneg = 1;
- sc->mx_want_auto = 0;
- return;
- break;
- case MX_FLAG_DELAYTIMEO:
- ifp->if_timer = 0;
- sc->mx_autoneg = 0;
- break;
- default:
- printf("mx%d: invalid autoneg flag: %d\n", sc->mx_unit, flag);
- return;
- }
-
- if (mx_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) {
- if (verbose)
- printf("mx%d: autoneg complete, ", sc->mx_unit);
- phy_sts = mx_phy_readreg(sc, PHY_BMSR);
- } else {
- if (verbose)
- printf("mx%d: autoneg not complete, ", sc->mx_unit);
- }
-
- media = mx_phy_readreg(sc, PHY_BMCR);
-
- /* Link is good. Report modes and set duplex mode. */
- if (mx_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) {
- if (verbose)
- printf("link status good ");
- advert = mx_phy_readreg(sc, PHY_ANAR);
- ability = mx_phy_readreg(sc, PHY_LPAR);
-
- if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) {
- ifm->ifm_media = IFM_ETHER|IFM_100_T4;
- media |= PHY_BMCR_SPEEDSEL;
- media &= ~PHY_BMCR_DUPLEX;
- printf("(100baseT4)\n");
- } else if (advert & PHY_ANAR_100BTXFULL &&
- ability & PHY_ANAR_100BTXFULL) {
- ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- media |= PHY_BMCR_SPEEDSEL;
- media |= PHY_BMCR_DUPLEX;
- printf("(full-duplex, 100Mbps)\n");
- } else if (advert & PHY_ANAR_100BTXHALF &&
- ability & PHY_ANAR_100BTXHALF) {
- ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX;
- media |= PHY_BMCR_SPEEDSEL;
- media &= ~PHY_BMCR_DUPLEX;
- printf("(half-duplex, 100Mbps)\n");
- } else if (advert & PHY_ANAR_10BTFULL &&
- ability & PHY_ANAR_10BTFULL) {
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX;
- media &= ~PHY_BMCR_SPEEDSEL;
- media |= PHY_BMCR_DUPLEX;
- printf("(full-duplex, 10Mbps)\n");
- } else if (advert & PHY_ANAR_10BTHALF &&
- ability & PHY_ANAR_10BTHALF) {
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
- media &= ~PHY_BMCR_SPEEDSEL;
- media &= ~PHY_BMCR_DUPLEX;
- printf("(half-duplex, 10Mbps)\n");
- }
-
- media &= ~PHY_BMCR_AUTONEGENBL;
-
- /* Set ASIC's duplex mode to match the PHY. */
- mx_setcfg(sc, media);
- mx_phy_writereg(sc, PHY_BMCR, media);
- } else {
- if (verbose)
- printf("no carrier\n");
- }
-
- mx_init(sc);
-
- if (sc->mx_tx_pend) {
- sc->mx_autoneg = 0;
- sc->mx_tx_pend = 0;
- mx_start(ifp);
- }
-
- return;
-}
-
-/*
- * Invoke autoneg using internal NWAY.
- */
-static void mx_autoneg(sc, flag, verbose)
- struct mx_softc *sc;
- int flag;
- int verbose;
-{
- u_int32_t media, ability;
- struct ifnet *ifp;
- struct ifmedia *ifm;
-
- ifm = &sc->ifmedia;
- ifp = &sc->arpcom.ac_if;
-
- ifm->ifm_media = IFM_ETHER | IFM_AUTO;
-
- switch (flag) {
- case MX_FLAG_FORCEDELAY:
- /*
- * XXX Never use this option anywhere but in the probe
- * routine: making the kernel stop dead in its tracks
- * for three whole seconds after we've gone multi-user
- * is really bad manners.
- */
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX);
- MX_SETBIT(sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL);
- MX_SETBIT(sc, MX_10BTCTRL, MX_ASTAT_TXDISABLE);
- DELAY(5000000);
- break;
- case MX_FLAG_SCHEDDELAY:
- /*
- * Wait for the transmitter to go idle before starting
- * an autoneg session, otherwise mx_start() may clobber
- * our timeout, and we don't want to allow transmission
- * during an autoneg session since that can screw it up.
- */
- if (sc->mx_cdata.mx_tx_head != NULL) {
- sc->mx_want_auto = 1;
- return;
- }
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX);
- MX_SETBIT(sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL);
- MX_SETBIT(sc, MX_10BTCTRL, MX_ASTAT_TXDISABLE);
- ifp->if_timer = 5;
- sc->mx_autoneg = 1;
- sc->mx_want_auto = 0;
- return;
- break;
- case MX_FLAG_DELAYTIMEO:
- ifp->if_timer = 0;
- sc->mx_autoneg = 0;
- break;
- default:
- printf("mx%d: invalid autoneg flag: %d\n", sc->mx_unit, flag);
- return;
- }
-
- if ((CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_ANEGSTAT) ==
- MX_ASTAT_AUTONEGCMP) {
- if (verbose)
- printf("mx%d: autoneg complete, ", sc->mx_unit);
- } else {
- if (verbose)
- printf("mx%d: autoneg not complete, ", sc->mx_unit);
- }
-
- media = CSR_READ_4(sc, MX_NETCFG);
-
- /* Link is good. Report modes and set duplex mode. */
- if (!(CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_LS10) ||
- !(CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_LS100)) {
- if (verbose)
- printf("link status good ");
- ability = CSR_READ_4(sc, MX_NWAYSTAT);
- if (ability & MX_NWAY_100BT4) {
- ifm->ifm_media = IFM_ETHER|IFM_100_T4;
- media |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS|
- MX_NETCFG_SCRAMBLER;
- media &= ~(MX_NETCFG_FULLDUPLEX|MX_NETCFG_SPEEDSEL);
- printf("(100baseT4)\n");
- } else if (ability & MX_NWAY_100BTFULL) {
- ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- media |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS|
- MX_NETCFG_SCRAMBLER;
- media |= MX_NETCFG_FULLDUPLEX;
- media &= ~MX_NETCFG_SPEEDSEL;
- printf("(full-duplex, 100Mbps)\n");
- } else if (ability & MX_NWAY_100BTHALF) {
- ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX;
- media |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS|
- MX_NETCFG_SCRAMBLER;
- media &= ~(MX_NETCFG_FULLDUPLEX|MX_NETCFG_SPEEDSEL);
- printf("(half-duplex, 100Mbps)\n");
- } else if (ability & MX_NWAY_10BTFULL) {
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX;
- media &= ~MX_NETCFG_PORTSEL;
- media |= (MX_NETCFG_FULLDUPLEX|MX_NETCFG_SPEEDSEL);
- printf("(full-duplex, 10Mbps)\n");
- } else {
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
- media &= ~MX_NETCFG_PORTSEL;
- media &= ~MX_NETCFG_FULLDUPLEX;
- media |= MX_NETCFG_SPEEDSEL;
- printf("(half-duplex, 10Mbps)\n");
- }
-
- CSR_WRITE_4(sc, MX_NETCFG, media);
- MX_CLRBIT(sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL);
- } else {
- if (verbose)
- printf("no carrier\n");
- }
-
- mx_init(sc);
-
- if (sc->mx_tx_pend) {
- sc->mx_autoneg = 0;
- sc->mx_tx_pend = 0;
- mx_start(ifp);
- }
-
- return;
-}
-
-static void mx_getmode_mii(sc)
- struct mx_softc *sc;
-{
- u_int16_t bmsr;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- bmsr = mx_phy_readreg(sc, PHY_BMSR);
- if (bootverbose)
- printf("mx%d: PHY status word: %x\n", sc->mx_unit, bmsr);
-
- /* fallback */
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
-
- if (bmsr & PHY_BMSR_10BTHALF) {
- if (bootverbose)
- printf("mx%d: 10Mbps half-duplex mode supported\n",
- sc->mx_unit);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
- }
-
- if (bmsr & PHY_BMSR_10BTFULL) {
- if (bootverbose)
- printf("mx%d: 10Mbps full-duplex mode supported\n",
- sc->mx_unit);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX;
- }
-
- if (bmsr & PHY_BMSR_100BTXHALF) {
- if (bootverbose)
- printf("mx%d: 100Mbps half-duplex mode supported\n",
- sc->mx_unit);
- ifp->if_baudrate = 100000000;
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX;
- }
-
- if (bmsr & PHY_BMSR_100BTXFULL) {
- if (bootverbose)
- printf("mx%d: 100Mbps full-duplex mode supported\n",
- sc->mx_unit);
- ifp->if_baudrate = 100000000;
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- }
-
- /* Some also support 100BaseT4. */
- if (bmsr & PHY_BMSR_100BT4) {
- if (bootverbose)
- printf("mx%d: 100baseT4 mode supported\n", sc->mx_unit);
- ifp->if_baudrate = 100000000;
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4;
-#ifdef FORCE_AUTONEG_TFOUR
- if (bootverbose)
- printf("mx%d: forcing on autoneg support for BT4\n",
- sc->mx_unit);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL):
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO;
-#endif
- }
-
- if (bmsr & PHY_BMSR_CANAUTONEG) {
- if (bootverbose)
- printf("mx%d: autoneg supported\n", sc->mx_unit);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO;
- }
-
- return;
-}
-
-/*
- * Set speed and duplex mode.
- */
-static void mx_setmode_mii(sc, media)
- struct mx_softc *sc;
- int media;
-{
- u_int16_t bmcr;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- /*
- * If an autoneg session is in progress, stop it.
- */
- if (sc->mx_autoneg) {
- printf("mx%d: canceling autoneg session\n", sc->mx_unit);
- ifp->if_timer = sc->mx_autoneg = sc->mx_want_auto = 0;
- bmcr = mx_phy_readreg(sc, PHY_BMCR);
- bmcr &= ~PHY_BMCR_AUTONEGENBL;
- mx_phy_writereg(sc, PHY_BMCR, bmcr);
- }
-
- printf("mx%d: selecting MII, ", sc->mx_unit);
-
- bmcr = mx_phy_readreg(sc, PHY_BMCR);
-
- bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL|
- PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK);
-
- if (IFM_SUBTYPE(media) == IFM_100_T4) {
- printf("100Mbps/T4, half-duplex\n");
- bmcr |= PHY_BMCR_SPEEDSEL;
- bmcr &= ~PHY_BMCR_DUPLEX;
- }
-
- if (IFM_SUBTYPE(media) == IFM_100_TX) {
- printf("100Mbps, ");
- bmcr |= PHY_BMCR_SPEEDSEL;
- }
-
- if (IFM_SUBTYPE(media) == IFM_10_T) {
- printf("10Mbps, ");
- bmcr &= ~PHY_BMCR_SPEEDSEL;
- }
-
- if ((media & IFM_GMASK) == IFM_FDX) {
- printf("full duplex\n");
- bmcr |= PHY_BMCR_DUPLEX;
- } else {
- printf("half duplex\n");
- bmcr &= ~PHY_BMCR_DUPLEX;
- }
-
- mx_setcfg(sc, bmcr);
- mx_phy_writereg(sc, PHY_BMCR, bmcr);
-
- return;
-}
-
-/*
- * Set speed and duplex mode on internal transceiver.
- */
-static void mx_setmode(sc, media, verbose)
- struct mx_softc *sc;
- int media;
- int verbose;
-{
- struct ifnet *ifp;
- u_int32_t mode;
-
- ifp = &sc->arpcom.ac_if;
-
- /*
- * If an autoneg session is in progress, stop it.
- */
- if (sc->mx_autoneg) {
- printf("mx%d: canceling autoneg session\n", sc->mx_unit);
- ifp->if_timer = sc->mx_autoneg = sc->mx_want_auto = 0;
- MX_CLRBIT(sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL);
- }
-
- if (verbose)
- printf("mx%d: selecting NWAY, ", sc->mx_unit);
-
- mode = CSR_READ_4(sc, MX_NETCFG);
-
- mode &= ~(MX_NETCFG_FULLDUPLEX|MX_NETCFG_PORTSEL|
- MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER|MX_NETCFG_SPEEDSEL);
-
- if (IFM_SUBTYPE(media) == IFM_100_T4) {
- if (verbose)
- printf("100Mbps/T4, half-duplex\n");
- mode |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER;
- }
-
- if (IFM_SUBTYPE(media) == IFM_100_TX) {
- if (verbose)
- printf("100Mbps, ");
- mode |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER;
- }
-
- if (IFM_SUBTYPE(media) == IFM_10_T) {
- if (verbose)
- printf("10Mbps, ");
- mode &= ~MX_NETCFG_PORTSEL;
- mode |= MX_NETCFG_SPEEDSEL;
- }
-
- if ((media & IFM_GMASK) == IFM_FDX) {
- if (verbose)
- printf("full duplex\n");
- mode |= MX_NETCFG_FULLDUPLEX;
- } else {
- if (verbose)
- printf("half duplex\n");
- mode &= ~MX_NETCFG_FULLDUPLEX;
- }
-
- CSR_WRITE_4(sc, MX_NETCFG, mode);
-
- return;
-}
-
-/*
* Programming the receiver filter on the tulip/PMAC is gross. You
* have to construct a special setup frame and download it to the
* chip via the transmit DMA engine. This routine is also somewhat
@@ -1207,9 +740,9 @@ void mx_setfilt(sc)
* 'full-duplex' and '100Mbps' bits in the netconfig register, we
* first have to put the transmit and/or receive logic in the idle state.
*/
-static void mx_setcfg(sc, bmcr)
+static void mx_setcfg(sc, media)
struct mx_softc *sc;
- int bmcr;
+ int media;
{
int i, restart = 0;
@@ -1229,19 +762,39 @@ static void mx_setcfg(sc, bmcr)
}
- if (bmcr & PHY_BMCR_SPEEDSEL) {
+ if (IFM_SUBTYPE(media) == IFM_100_TX) {
MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_SPEEDSEL);
- if (sc->mx_phy_addr == 0) {
+ if (sc->mx_type == MX_TYPE_98713) {
+ MX_SETBIT(sc, MX_WATCHDOG, MX_WDOG_JABBERDIS);
+ MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
+ MX_NETCFG_PORTSEL|MX_NETCFG_SCRAMBLER));
+ MX_SETBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
+ MX_NETCFG_PORTSEL|MX_NETCFG_SCRAMBLER));
+ } else {
MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL|
MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER);
}
- } else
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_10_T) {
MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_SPEEDSEL);
+ if (sc->mx_type == MX_TYPE_98713) {
+ MX_SETBIT(sc, MX_WATCHDOG, MX_WDOG_JABBERDIS);
+ MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
+ MX_NETCFG_PORTSEL|MX_NETCFG_SCRAMBLER));
+ MX_SETBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
+ MX_NETCFG_PORTSEL|MX_NETCFG_SCRAMBLER));
+ } else {
+ MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
+ MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_PCS);
+ }
+ }
- if (bmcr & PHY_BMCR_DUPLEX)
+ if ((media & IFM_GMASK) == IFM_FDX) {
MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX);
- else
+ } else {
MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX);
+ }
if (restart)
MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON|MX_NETCFG_RX_ON);
@@ -1336,11 +889,9 @@ int mx_attach(dev)
u_int32_t command;
struct mx_softc *sc;
struct ifnet *ifp;
- int media = IFM_ETHER|IFM_100_TX|IFM_FDX;
unsigned int round;
caddr_t roundptr;
- struct mx_type *p;
- u_int16_t phy_vid, phy_did, phy_sts, mac_offset = 0;
+ u_int16_t mac_offset = 0;
u_int32_t revision, pci_id;
int unit, error = 0, rid;
@@ -1512,94 +1063,26 @@ int mx_attach(dev)
ifp->if_baudrate = 10000000;
ifp->if_snd.ifq_maxlen = MX_TX_LIST_CNT - 1;
- if (sc->mx_type == MX_TYPE_98713) {
- if (bootverbose)
- printf("mx%d: probing for a PHY\n", sc->mx_unit);
- for (i = MX_PHYADDR_MIN; i < MX_PHYADDR_MAX + 1; i++) {
- if (bootverbose)
- printf("mx%d: checking address: %d\n",
- sc->mx_unit, i);
- sc->mx_phy_addr = i;
- mx_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
- DELAY(500);
- while(mx_phy_readreg(sc, PHY_BMCR)
- & PHY_BMCR_RESET);
- if ((phy_sts = mx_phy_readreg(sc, PHY_BMSR)))
- break;
- }
- if (phy_sts) {
- phy_vid = mx_phy_readreg(sc, PHY_VENID);
- phy_did = mx_phy_readreg(sc, PHY_DEVID);
- if (bootverbose)
- printf("mx%d: found PHY at address %d, ",
- sc->mx_unit, sc->mx_phy_addr);
- if (bootverbose)
- printf("vendor id: %x device id: %x\n",
- phy_vid, phy_did);
- p = mx_phys;
- while(p->mx_vid) {
- if (phy_vid == p->mx_vid &&
- (phy_did | 0x000F) == p->mx_did) {
- sc->mx_pinfo = p;
- break;
- }
- p++;
- }
- if (sc->mx_pinfo == NULL)
- sc->mx_pinfo = &mx_phys[PHY_UNKNOWN];
- if (bootverbose)
- printf("mx%d: PHY type: %s\n",
- sc->mx_unit, sc->mx_pinfo->mx_name);
- } else {
-#ifdef DIAGNOSTIC
- printf("mx%d: MII without any phy!\n", sc->mx_unit);
-#endif
- }
- }
-
/*
* Do ifmedia setup.
*/
- ifmedia_init(&sc->ifmedia, 0, mx_ifmedia_upd, mx_ifmedia_sts);
- if (sc->mx_type == MX_TYPE_98713 && sc->mx_pinfo != NULL) {
- mx_getmode_mii(sc);
- if (cold) {
- mx_autoneg_mii(sc, MX_FLAG_FORCEDELAY, 1);
- mx_stop(sc);
- } else {
- mx_init(sc);
- mx_autoneg_mii(sc, MX_FLAG_SCHEDDELAY, 1);
- }
- } else {
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
- if (cold) {
- mx_autoneg(sc, MX_FLAG_FORCEDELAY, 1);
- mx_stop(sc);
- } else {
- mx_init(sc);
- mx_autoneg(sc, MX_FLAG_SCHEDDELAY, 1);
- }
+ if (mii_phy_probe(dev, &sc->mx_miibus,
+ mx_ifmedia_upd, mx_ifmedia_sts)) {
+ printf("mx%d: MII without any PHY!\n", sc->mx_unit);
+ bus_teardown_intr(dev, sc->mx_irq, sc->mx_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->mx_irq);
+ bus_release_resource(dev, MX_RES, MX_RID, sc->mx_res);
+ error = ENXIO;
+ goto fail;
}
- media = sc->ifmedia.ifm_media;
- ifmedia_set(&sc->ifmedia, media);
-
/*
* Call MI attach routines.
*/
if_attach(ifp);
ether_ifattach(ifp);
+ callout_handle_init(&sc->mx_stat_ch);
bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
@@ -1624,12 +1107,14 @@ static int mx_detach(dev)
mx_stop(sc);
if_detach(ifp);
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->mx_miibus);
+
bus_teardown_intr(dev, sc->mx_irq, sc->mx_intrhand);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->mx_irq);
bus_release_resource(dev, MX_RES, MX_RID, sc->mx_res);
free(sc->mx_ldata_ptr, M_DEVBUF);
- ifmedia_removeall(&sc->ifmedia);
splx(s);
@@ -1923,18 +1408,31 @@ static void mx_txeoc(sc)
if (sc->mx_cdata.mx_tx_head == NULL) {
ifp->if_flags &= ~IFF_OACTIVE;
sc->mx_cdata.mx_tx_tail = NULL;
- if (sc->mx_want_auto) {
- if (sc->mx_type == MX_TYPE_98713 &&
- sc->mx_pinfo != NULL)
- mx_autoneg_mii(sc, MX_FLAG_DELAYTIMEO, 1);
- else
- mx_autoneg(sc, MX_FLAG_DELAYTIMEO, 1);
- }
}
return;
}
+static void mx_tick(xsc)
+ void *xsc;
+{
+ struct mx_softc *sc;
+ struct mii_data *mii;
+ int s;
+
+ s = splimp();
+
+ sc = xsc;
+ mii = device_get_softc(sc->mx_miibus);
+ mii_tick(mii);
+
+ sc->mx_stat_ch = timeout(mx_tick, sc, hz);
+
+ splx(s);
+
+ return;
+}
+
static void mx_intr(arg)
void *arg;
{
@@ -2119,11 +1617,6 @@ static void mx_start(ifp)
sc = ifp->if_softc;
- if (sc->mx_autoneg) {
- sc->mx_tx_pend = 1;
- return;
- }
-
if (ifp->if_flags & IFF_OACTIVE)
return;
@@ -2188,16 +1681,13 @@ static void mx_init(xsc)
{
struct mx_softc *sc = xsc;
struct ifnet *ifp = &sc->arpcom.ac_if;
- u_int16_t phy_bmcr = 0;
+ struct mii_data *mii;
int s;
-
- if (sc->mx_autoneg)
- return;
+ u_int32_t tmp;
s = splimp();
- if (sc->mx_pinfo != NULL)
- phy_bmcr = mx_phy_readreg(sc, PHY_BMCR);
+ mii = device_get_softc(sc->mx_miibus);
/*
* Cancel pending I/O and free all RX/TX buffers.
@@ -2245,16 +1735,17 @@ static void mx_init(xsc)
else
MX_SETBIT(sc, MX_MAGICPACKET, MX_MAGIC_98715);
- if (sc->mx_pinfo != NULL) {
- MX_SETBIT(sc, MX_WATCHDOG, MX_WDOG_JABBERDIS);
- mx_setcfg(sc, mx_phy_readreg(sc, PHY_BMCR));
- } else
- mx_setmode(sc, sc->ifmedia.ifm_media, 0);
+ if (sc->mx_type == MX_TYPE_98713) {
+ MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
+ MX_NETCFG_PORTSEL|MX_NETCFG_SCRAMBLER));
+ MX_SETBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
+ MX_NETCFG_PORTSEL|MX_NETCFG_SCRAMBLER));
+ }
MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_TX_THRESH);
/*MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_SPEEDSEL);*/
- if (IFM_SUBTYPE(sc->ifmedia.ifm_media) == IFM_10_T)
+ if (IFM_SUBTYPE(mii->mii_media.ifm_media) == IFM_10_T)
MX_SETBIT(sc, MX_NETCFG, MX_TXTHRESH_160BYTES);
else
MX_SETBIT(sc, MX_NETCFG, MX_TXTHRESH_72BYTES);
@@ -2293,15 +1784,21 @@ static void mx_init(xsc)
MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON|MX_NETCFG_RX_ON);
CSR_WRITE_4(sc, MX_RXSTART, 0xFFFFFFFF);
- /* Restore state of BMCR */
- if (sc->mx_pinfo != NULL)
- mx_phy_writereg(sc, PHY_BMCR, phy_bmcr);
+ tmp = mii->mii_media.ifm_cur->ifm_media;
+ mii->mii_media.ifm_cur->ifm_media = IFM_ETHER|IFM_10_T;
+ mii_mediachg(mii);
+ mii->mii_media.ifm_cur->ifm_media = IFM_ETHER|IFM_100_TX;
+ mii_mediachg(mii);
+ mii->mii_media.ifm_cur->ifm_media = tmp;
+ mii_mediachg(mii);
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
(void)splx(s);
+ sc->mx_stat_ch = timeout(mx_tick, sc, hz);
+
return;
}
@@ -2312,25 +1809,12 @@ static int mx_ifmedia_upd(ifp)
struct ifnet *ifp;
{
struct mx_softc *sc;
- struct ifmedia *ifm;
+ struct mii_data *mii;
sc = ifp->if_softc;
- ifm = &sc->ifmedia;
+ mii = device_get_softc(sc->mx_miibus);
- if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
- return(EINVAL);
-
- if (sc->mx_type == MX_TYPE_98713 && sc->mx_pinfo != NULL) {
- if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO)
- mx_autoneg_mii(sc, MX_FLAG_SCHEDDELAY, 1);
- else
- mx_setmode_mii(sc, ifm->ifm_media);
- } else {
- if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO)
- mx_autoneg(sc, MX_FLAG_SCHEDDELAY, 1);
- else
- mx_setmode(sc, ifm->ifm_media, 1);
- }
+ mii_mediachg(mii);
return(0);
}
@@ -2343,56 +1827,13 @@ static void mx_ifmedia_sts(ifp, ifmr)
struct ifmediareq *ifmr;
{
struct mx_softc *sc;
- u_int16_t advert = 0, ability = 0;
- u_int32_t media = 0;
+ struct mii_data *mii;
sc = ifp->if_softc;
-
- ifmr->ifm_active = IFM_ETHER;
-
- if (sc->mx_type != MX_TYPE_98713 || sc->mx_pinfo == NULL) {
- media = CSR_READ_4(sc, MX_NETCFG);
- if (media & MX_NETCFG_PORTSEL)
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX;
- else
- ifmr->ifm_active = IFM_ETHER|IFM_10_T;
- if (media & MX_NETCFG_FULLDUPLEX)
- ifmr->ifm_active |= IFM_FDX;
- else
- ifmr->ifm_active |= IFM_HDX;
- return;
- }
-
- if (!(mx_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) {
- if (mx_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL)
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX;
- else
- ifmr->ifm_active = IFM_ETHER|IFM_10_T;
- if (mx_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX)
- ifmr->ifm_active |= IFM_FDX;
- else
- ifmr->ifm_active |= IFM_HDX;
- return;
- }
-
- ability = mx_phy_readreg(sc, PHY_LPAR);
- advert = mx_phy_readreg(sc, PHY_ANAR);
- if (advert & PHY_ANAR_100BT4 &&
- ability & PHY_ANAR_100BT4) {
- ifmr->ifm_active = IFM_ETHER|IFM_100_T4;
- } else if (advert & PHY_ANAR_100BTXFULL &&
- ability & PHY_ANAR_100BTXFULL) {
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX;
- } else if (advert & PHY_ANAR_100BTXHALF &&
- ability & PHY_ANAR_100BTXHALF) {
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX;
- } else if (advert & PHY_ANAR_10BTFULL &&
- ability & PHY_ANAR_10BTFULL) {
- ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX;
- } else if (advert & PHY_ANAR_10BTHALF &&
- ability & PHY_ANAR_10BTHALF) {
- ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX;
- }
+ mii = device_get_softc(sc->mx_miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
return;
}
@@ -2403,6 +1844,7 @@ static int mx_ioctl(ifp, command, data)
caddr_t data;
{
struct mx_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
struct ifreq *ifr = (struct ifreq *) data;
int s, error = 0;
@@ -2416,11 +1858,21 @@ static int mx_ioctl(ifp, command, data)
break;
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
- mx_init(sc);
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->mx_if_flags & IFF_PROMISC)) {
+ MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_RX_PROMISC);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->mx_if_flags & IFF_PROMISC) {
+ MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_RX_PROMISC);
+ } else
+ mx_init(sc);
} else {
if (ifp->if_flags & IFF_RUNNING)
mx_stop(sc);
}
+ sc->mx_if_flags = ifp->if_flags;
error = 0;
break;
case SIOCADDMULTI:
@@ -2430,7 +1882,8 @@ static int mx_ioctl(ifp, command, data)
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
- error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
+ mii = device_get_softc(sc->mx_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
break;
default:
error = EINVAL;
@@ -2449,30 +1902,9 @@ static void mx_watchdog(ifp)
sc = ifp->if_softc;
- if (sc->mx_autoneg) {
- if (sc->mx_type == MX_TYPE_98713 && sc->mx_pinfo != NULL)
- mx_autoneg_mii(sc, MX_FLAG_DELAYTIMEO, 1);
- else
- mx_autoneg(sc, MX_FLAG_DELAYTIMEO, 1);
- if (!(ifp->if_flags & IFF_UP))
- mx_stop(sc);
- return;
- }
-
ifp->if_oerrors++;
printf("mx%d: watchdog timeout\n", sc->mx_unit);
- if (sc->mx_pinfo == NULL) {
- if (!(CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_LS10) ||
- !(CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_LS100))
- printf("mx%d: no carrier - transceiver "
- "cable problem?\n", sc->mx_unit);
- } else {
- if (!(mx_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT))
- printf("mx%d: no carrier - transceiver "
- "cable problem?\n", sc->mx_unit);
- }
-
mx_stop(sc);
mx_reset(sc);
mx_init(sc);
@@ -2496,6 +1928,8 @@ static void mx_stop(sc)
ifp = &sc->arpcom.ac_if;
ifp->if_timer = 0;
+ untimeout(mx_tick, sc, sc->mx_stat_ch);
+
MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_RX_ON|MX_NETCFG_TX_ON));
CSR_WRITE_4(sc, MX_IMR, 0x00000000);
CSR_WRITE_4(sc, MX_TXADDR, 0x00000000);
diff --git a/sys/pci/if_mxreg.h b/sys/pci/if_mxreg.h
index c19e891..1c44e43 100644
--- a/sys/pci/if_mxreg.h
+++ b/sys/pci/if_mxreg.h
@@ -479,24 +479,21 @@ struct mx_mii_frame {
struct mx_softc {
struct arpcom arpcom; /* interface info */
- struct ifmedia ifmedia; /* media info */
bus_space_handle_t mx_bhandle; /* bus space handle */
bus_space_tag_t mx_btag; /* bus space tag */
void *mx_intrhand;
struct resource *mx_irq;
struct resource *mx_res;
+ device_t mx_miibus;
struct mx_type *mx_info; /* Macronix adapter info */
- struct mx_type *mx_pinfo; /* phy info */
u_int8_t mx_unit; /* interface number */
u_int8_t mx_type;
- u_int8_t mx_phy_addr; /* PHY address */
- u_int8_t mx_tx_pend; /* TX pending */
- u_int8_t mx_want_auto;
- u_int8_t mx_autoneg;
u_int8_t mx_cachesize;
+ int mx_if_flags;
caddr_t mx_ldata_ptr;
struct mx_list_data *mx_ldata;
struct mx_chain_data mx_cdata;
+ struct callout_handle mx_stat_ch;
};
/*
@@ -554,38 +551,6 @@ struct mx_softc {
#define PN_DEVICEID_PNIC_II 0xc115
/*
- * Texas Instruments PHY identifiers
- */
-#define TI_PHY_VENDORID 0x4000
-#define TI_PHY_10BT 0x501F
-#define TI_PHY_100VGPMI 0x502F
-
-/*
- * These ID values are for the NS DP83840A 10/100 PHY
- */
-#define NS_PHY_VENDORID 0x2000
-#define NS_PHY_83840A 0x5C0F
-
-/*
- * Level 1 10/100 PHY
- */
-#define LEVEL1_PHY_VENDORID 0x7810
-#define LEVEL1_PHY_LXT970 0x000F
-
-/*
- * Intel 82555 10/100 PHY
- */
-#define INTEL_PHY_VENDORID 0x0A28
-#define INTEL_PHY_82555 0x015F
-
-/*
- * SEEQ 80220 10/100 PHY
- */
-#define SEEQ_PHY_VENDORID 0x0016
-#define SEEQ_PHY_80220 0xF83F
-
-
-/*
* PCI low memory base and low I/O base register, and
* other PCI registers.
*/
@@ -623,105 +588,6 @@ struct mx_softc {
#define MX_PME_EN 0x0010
#define MX_PME_STATUS 0x8000
-#define PHY_UNKNOWN 6
-
-#define MX_PHYADDR_MIN 0x00
-#define MX_PHYADDR_MAX 0x1F
-
-#define PHY_BMCR 0x00
-#define PHY_BMSR 0x01
-#define PHY_VENID 0x02
-#define PHY_DEVID 0x03
-#define PHY_ANAR 0x04
-#define PHY_LPAR 0x05
-#define PHY_ANEXP 0x06
-
-#define PHY_ANAR_NEXTPAGE 0x8000
-#define PHY_ANAR_RSVD0 0x4000
-#define PHY_ANAR_TLRFLT 0x2000
-#define PHY_ANAR_RSVD1 0x1000
-#define PHY_ANAR_RSVD2 0x0800
-#define PHY_ANAR_RSVD3 0x0400
-#define PHY_ANAR_100BT4 0x0200
-#define PHY_ANAR_100BTXFULL 0x0100
-#define PHY_ANAR_100BTXHALF 0x0080
-#define PHY_ANAR_10BTFULL 0x0040
-#define PHY_ANAR_10BTHALF 0x0020
-#define PHY_ANAR_PROTO4 0x0010
-#define PHY_ANAR_PROTO3 0x0008
-#define PHY_ANAR_PROTO2 0x0004
-#define PHY_ANAR_PROTO1 0x0002
-#define PHY_ANAR_PROTO0 0x0001
-
-/*
- * These are the register definitions for the PHY (physical layer
- * interface chip).
- */
-/*
- * PHY BMCR Basic Mode Control Register
- */
-#define PHY_BMCR_RESET 0x8000
-#define PHY_BMCR_LOOPBK 0x4000
-#define PHY_BMCR_SPEEDSEL 0x2000
-#define PHY_BMCR_AUTONEGENBL 0x1000
-#define PHY_BMCR_RSVD0 0x0800 /* write as zero */
-#define PHY_BMCR_ISOLATE 0x0400
-#define PHY_BMCR_AUTONEGRSTR 0x0200
-#define PHY_BMCR_DUPLEX 0x0100
-#define PHY_BMCR_COLLTEST 0x0080
-#define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */
-#define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */
-#define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */
-#define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */
-#define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */
-#define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */
-#define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */
-/*
- * RESET: 1 == software reset, 0 == normal operation
- * Resets status and control registers to default values.
- * Relatches all hardware config values.
- *
- * LOOPBK: 1 == loopback operation enabled, 0 == normal operation
- *
- * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s
- * Link speed is selected byt his bit or if auto-negotiation if bit
- * 12 (AUTONEGENBL) is set (in which case the value of this register
- * is ignored).
- *
- * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled
- * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13
- * determine speed and mode. Should be cleared and then set if PHY configured
- * for no autoneg on startup.
- *
- * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation
- *
- * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation
- *
- * DUPLEX: 1 == full duplex mode, 0 == half duplex mode
- *
- * COLLTEST: 1 == collision test enabled, 0 == normal operation
- */
-
-/*
- * PHY, BMSR Basic Mode Status Register
- */
-#define PHY_BMSR_100BT4 0x8000
-#define PHY_BMSR_100BTXFULL 0x4000
-#define PHY_BMSR_100BTXHALF 0x2000
-#define PHY_BMSR_10BTFULL 0x1000
-#define PHY_BMSR_10BTHALF 0x0800
-#define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */
-#define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */
-#define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */
-#define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */
-#define PHY_BMSR_MFPRESUP 0x0040
-#define PHY_BMSR_AUTONEGCOMP 0x0020
-#define PHY_BMSR_REMFAULT 0x0010
-#define PHY_BMSR_CANAUTONEG 0x0008
-#define PHY_BMSR_LINKSTAT 0x0004
-#define PHY_BMSR_JABBER 0x0002
-#define PHY_BMSR_EXTENDED 0x0001
-
#ifdef __alpha__
#undef vtophys
#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
OpenPOWER on IntegriCloud