diff --git a/share/man/man4/man4.i386/mx.4 b/share/man/man4/man4.i386/mx.4 index 6a960416b76..ada9d487ec3 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 6a960416b76..ada9d487ec3 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 1a18c6ce53e..cd5094b70c1 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 1a18c6ce53e..cd5094b70c1 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 ddc79054e77..827ace1a5c2 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 00000000000..532847e9119 --- /dev/null +++ b/sys/dev/mii/mxphy.c @@ -0,0 +1,487 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul . 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#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 ddc79054e77..827ace1a5c2 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 4949f2540d3..9c36977a093 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 8cbcad59dd2..0ffb2f6416c 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 diff --git a/sys/pci/if_mx.c b/sys/pci/if_mx.c index 95e383b85b4..71214a29b6e 100644 --- a/sys/pci/if_mx.c +++ b/sys/pci/if_mx.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 1998 - * Bill Paul . All rights reserved. + * Copyright (c) 1997, 1998, 1999 + * Bill Paul . 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 + * Written by Bill Paul * Electrical Engineering Department * Columbia University, New York City */ @@ -82,15 +82,19 @@ #include #include +#include +#include + #include #include #define MX_USEIOSPACE -/* #define MX_BACKGROUND_AUTONEG */ - #include +/* "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_PHY_VENDORID, TI_PHY_100VGPMI, "" }, - { NS_PHY_VENDORID, NS_PHY_83840A, ""}, - { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "" }, - { INTEL_PHY_VENDORID, INTEL_PHY_82555, "" }, - { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "" }, - { 0, 0, "" } -}; - 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; } @@ -619,504 +650,6 @@ static u_int32_t mx_calchash(sc, addr) return (crc & ((1 << MX_BITS) - 1)); } -/* - * 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 @@ -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 - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_SPEEDSEL); + } - if (bmcr & PHY_BMCR_DUPLEX) + 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 ((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 c19e8911f36..1c44e431068 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; }; /* @@ -553,38 +550,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)