Index: head/sys/dev/dc/dcphy.c =================================================================== --- head/sys/dev/dc/dcphy.c (revision 227907) +++ head/sys/dev/dc/dcphy.c (revision 227908) @@ -1,406 +1,406 @@ /*- * 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. */ #include __FBSDID("$FreeBSD$"); /* * Pseudo-driver for internal NWAY support on DEC 21143 and workalike * controllers. Technically we're abusing the miibus code to handle * media selection and NWAY support here since there is no MII * interface. However the logical operations are roughly the same, * and the alternative is to create a fake MII interface in the driver, * which is harder to do. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include #include #include #include "miibus_if.h" #define DC_SETBIT(sc, reg, x) \ CSR_WRITE_4(sc, reg, \ CSR_READ_4(sc, reg) | x) #define DC_CLRBIT(sc, reg, x) \ CSR_WRITE_4(sc, reg, \ CSR_READ_4(sc, reg) & ~x) #define MIIF_AUTOTIMEOUT 0x0004 /* * This is the subsystem ID for the built-in 21143 ethernet * in several Compaq Presario systems. Apparently these are * 10Mbps only, so we need to treat them specially. */ #define COMPAQ_PRESARIO_ID 0xb0bb0e11 static int dcphy_probe(device_t); static int dcphy_attach(device_t); static device_method_t dcphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, dcphy_probe), DEVMETHOD(device_attach, dcphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t dcphy_devclass; static driver_t dcphy_driver = { "dcphy", dcphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0); static int dcphy_service(struct mii_softc *, struct mii_data *, int); static void dcphy_status(struct mii_softc *); static void dcphy_reset(struct mii_softc *); static int dcphy_auto(struct mii_softc *); static const struct mii_phy_funcs dcphy_funcs = { dcphy_service, dcphy_status, dcphy_reset }; static int dcphy_probe(device_t dev) { struct mii_attach_args *ma; ma = device_get_ivars(dev); /* * The dc driver will report the 21143 vendor and device * ID to let us know that it wants us to attach. */ if (ma->mii_id1 != DC_VENDORID_DEC || ma->mii_id2 != DC_DEVICEID_21143) return (ENXIO); device_set_desc(dev, "Intel 21143 NWAY media interface"); return (BUS_PROBE_DEFAULT); } static int dcphy_attach(device_t dev) { struct mii_softc *sc; struct dc_softc *dc_sc; device_t brdev; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &dcphy_funcs, 0); /*PHY_RESET(sc);*/ dc_sc = sc->mii_pdata->mii_ifp->if_softc; CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0); CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0); brdev = device_get_parent(sc->mii_dev); switch (pci_get_subdevice(brdev) << 16 | pci_get_subvendor(brdev)) { case COMPAQ_PRESARIO_ID: /* Example of how to only allow 10Mbps modes. */ sc->mii_capabilities = BMSR_ANEG | BMSR_10TFDX | BMSR_10THDX; break; default: if (dc_sc->dc_pmode == DC_PMODE_SIA) sc->mii_capabilities = BMSR_ANEG | BMSR_10TFDX | BMSR_10THDX; else sc->mii_capabilities = BMSR_ANEG | BMSR_100TXFDX | BMSR_100TXHDX | BMSR_10TFDX | BMSR_10THDX; break; } sc->mii_capabilities &= sc->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int dcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct dc_softc *dc_sc; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; u_int32_t mode; dc_sc = mii->mii_ifp->if_softc; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii->mii_media_active = IFM_NONE; mode = CSR_READ_4(dc_sc, DC_NETCFG); mode &= ~(DC_NETCFG_FULLDUPLEX | DC_NETCFG_PORTSEL | DC_NETCFG_PCS | DC_NETCFG_SCRAMBLER | DC_NETCFG_SPEEDSEL); switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: /*PHY_RESET(sc);*/ (void)dcphy_auto(sc); break; case IFM_100_TX: PHY_RESET(sc); DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); mode |= DC_NETCFG_PORTSEL | DC_NETCFG_PCS | DC_NETCFG_SCRAMBLER; if ((ife->ifm_media & IFM_FDX) != 0) mode |= DC_NETCFG_FULLDUPLEX; else mode &= ~DC_NETCFG_FULLDUPLEX; CSR_WRITE_4(dc_sc, DC_NETCFG, mode); break; case IFM_10_T: DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET); DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF); if ((ife->ifm_media & IFM_FDX) != 0) DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D); else DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F); DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET); DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); mode &= ~DC_NETCFG_PORTSEL; mode |= DC_NETCFG_SPEEDSEL; if ((ife->ifm_media & IFM_FDX) != 0) mode |= DC_NETCFG_FULLDUPLEX; else mode &= ~DC_NETCFG_FULLDUPLEX; CSR_WRITE_4(dc_sc, DC_NETCFG, mode); break; default: return (EINVAL); } break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) break; reg = CSR_READ_4(dc_sc, DC_10BTSTAT); if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) break; /* * Only retry autonegotiation every 5 seconds. * * Otherwise, fall through to calling dcphy_status() * since real Intel 21143 chips don't show valid link * status until autonegotiation is switched off, and * that only happens in dcphy_status(). Without this, * successful autonegotiation is never recognised on * these chips. */ if (++sc->mii_ticks <= 50) break; sc->mii_ticks = 0; dcphy_auto(sc); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void dcphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; int anlpar, tstat; struct dc_softc *dc_sc; dc_sc = mii->mii_ifp->if_softc; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return; tstat = CSR_READ_4(dc_sc, DC_10BTSTAT); if (!(tstat & DC_TSTAT_LS10) || !(tstat & DC_TSTAT_LS100)) mii->mii_media_status |= IFM_ACTIVE; if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) { /* Erg, still trying, I guess... */ if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) { if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) && (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE) goto skip; mii->mii_media_active |= IFM_NONE; return; } if (tstat & DC_TSTAT_LP_CAN_NWAY) { anlpar = tstat >> 16; if (anlpar & ANLPAR_TX_FD && sc->mii_capabilities & BMSR_100TXFDX) mii->mii_media_active |= IFM_100_TX | IFM_FDX; else if (anlpar & ANLPAR_T4 && sc->mii_capabilities & BMSR_100T4) mii->mii_media_active |= IFM_100_T4 | IFM_HDX; else if (anlpar & ANLPAR_TX && sc->mii_capabilities & BMSR_100TXHDX) mii->mii_media_active |= IFM_100_TX | IFM_HDX; 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 | IFM_HDX; else mii->mii_media_active |= IFM_NONE; if (DC_IS_INTEL(dc_sc)) DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); return; } /* * If the other side doesn't support NWAY, then the * best we can do is determine if we have a 10Mbps or * 100Mbps link. There's no way to know if the link * is full or half duplex, so we default to half duplex * and hope that the user is clever enough to manually * change the media settings if we're wrong. */ if (!(tstat & DC_TSTAT_LS100)) mii->mii_media_active |= IFM_100_TX | IFM_HDX; else if (!(tstat & DC_TSTAT_LS10)) mii->mii_media_active |= IFM_10_T | IFM_HDX; else mii->mii_media_active |= IFM_NONE; if (DC_IS_INTEL(dc_sc)) DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); return; } skip: if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL) mii->mii_media_active |= IFM_10_T; else mii->mii_media_active |= IFM_100_TX; if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } static int dcphy_auto(struct mii_softc *mii) { struct dc_softc *sc; sc = mii->mii_pdata->mii_ifp->if_softc; DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX); DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); if (mii->mii_capabilities & BMSR_100TXHDX) CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF); else CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF); DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE); return (EJUSTRETURN); } static void dcphy_reset(struct mii_softc *mii) { struct dc_softc *sc; sc = mii->mii_pdata->mii_ifp->if_softc; DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); DELAY(1000); DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); } Index: head/sys/dev/dc/pnphy.c =================================================================== --- head/sys/dev/dc/pnphy.c (revision 227907) +++ head/sys/dev/dc/pnphy.c (revision 227908) @@ -1,226 +1,226 @@ /* * 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. */ #include __FBSDID("$FreeBSD$"); /* * Pseudo-driver for media selection on the Lite-On PNIC 82c168 * chip. The NWAY support on this chip is horribly broken, so we * only support manual mode selection. This is lame, but getting * NWAY to work right is amazingly difficult. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include #include #include "miibus_if.h" static int pnphy_probe(device_t); static int pnphy_attach(device_t); static device_method_t pnphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, pnphy_probe), DEVMETHOD(device_attach, pnphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t pnphy_devclass; static driver_t pnphy_driver = { "pnphy", pnphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(pnphy, miibus, pnphy_driver, pnphy_devclass, 0, 0); static int pnphy_service(struct mii_softc *, struct mii_data *, int); static void pnphy_status(struct mii_softc *); static void pnphy_reset(struct mii_softc *); static const struct mii_phy_funcs pnphy_funcs = { pnphy_service, pnphy_status, pnphy_reset }; static int pnphy_probe(device_t dev) { struct mii_attach_args *ma; ma = device_get_ivars(dev); /* * The dc driver will report the 82c168 vendor and device * ID to let us know that it wants us to attach. */ if (ma->mii_id1 != DC_VENDORID_LO || ma->mii_id2 != DC_DEVICEID_82C168) return (ENXIO); device_set_desc(dev, "PNIC 82c168 media interface"); return (BUS_PROBE_DEFAULT); } static int pnphy_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &pnphy_funcs, 0); sc->mii_capabilities = BMSR_100TXFDX | BMSR_100TXHDX | BMSR_10TFDX | BMSR_10THDX; sc->mii_capabilities &= sc->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int pnphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; /* * Note that auto-negotiation is broken on this chip. */ switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_100_TX: mii->mii_media_active = IFM_ETHER | IFM_100_TX; if ((ife->ifm_media & IFM_FDX) != 0) mii->mii_media_active |= IFM_FDX; MIIBUS_STATCHG(sc->mii_dev); return (0); case IFM_10_T: mii->mii_media_active = IFM_ETHER | IFM_10_T; if ((ife->ifm_media & IFM_FDX) != 0) mii->mii_media_active |= IFM_FDX; MIIBUS_STATCHG(sc->mii_dev); return (0); default: return (EINVAL); } break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void pnphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; int reg; struct dc_softc *dc_sc; dc_sc = mii->mii_ifp->if_softc; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; reg = CSR_READ_4(dc_sc, DC_ISR); if (!(reg & DC_ISR_LINKFAIL)) mii->mii_media_status |= IFM_ACTIVE; reg = CSR_READ_4(dc_sc, DC_NETCFG); if (reg & DC_NETCFG_SPEEDSEL) mii->mii_media_active |= IFM_10_T; else mii->mii_media_active |= IFM_100_TX; if (reg & DC_NETCFG_FULLDUPLEX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } static void pnphy_reset(struct mii_softc *sc __unused) { } Index: head/sys/dev/mii/acphy.c =================================================================== --- head/sys/dev/mii/acphy.c (revision 227907) +++ head/sys/dev/mii/acphy.c (revision 227908) @@ -1,258 +1,258 @@ /*- * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Driver for Altima AC101 10/100 PHY */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int acphy_probe(device_t); static int acphy_attach(device_t); static device_method_t acphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, acphy_probe), DEVMETHOD(device_attach, acphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t acphy_devclass; static driver_t acphy_driver = { "acphy", acphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(acphy, miibus, acphy_driver, acphy_devclass, 0, 0); static int acphy_service(struct mii_softc *, struct mii_data *, int); static void acphy_reset(struct mii_softc *); static void acphy_status(struct mii_softc *); static const struct mii_phydesc acphys[] = { MII_PHY_DESC(ALTIMA, AC101), MII_PHY_DESC(ALTIMA, AC101L), /* XXX This is reported to work, but it's not from any data sheet. */ MII_PHY_DESC(ALTIMA, ACXXX), MII_PHY_END }; static const struct mii_phy_funcs acphy_funcs = { acphy_service, acphy_status, acphy_reset }; static int acphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, acphys, BUS_PROBE_DEFAULT)); } static int acphy_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &acphy_funcs, 0); PHY_RESET(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; device_printf(dev, " "); #define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL) if ((PHY_READ(sc, MII_ACPHY_MCTL) & AC_MCTL_FX_SEL) != 0) { sc->mii_flags |= MIIF_HAVEFIBER; ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst), MII_MEDIA_100_TX); printf("100baseFX, "); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst), MII_MEDIA_100_TX_FDX); printf("100baseFX-FDX, "); } #undef ADD mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int acphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { int reg; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; /* Wake & deisolate up if necessary */ reg = PHY_READ(sc, MII_BMCR); if (reg & (BMCR_ISO | BMCR_PDOWN)) PHY_WRITE(sc, MII_BMCR, reg & ~(BMCR_ISO | BMCR_PDOWN)); mii_phy_setmedia(sc); break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * This PHY's autonegotiation doesn't need to be kicked. */ break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void acphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr, diag; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } diag = PHY_READ(sc, MII_ACPHY_DIAG); if (diag & AC_DIAG_SPEED) mii->mii_media_active |= IFM_100_TX; else mii->mii_media_active |= IFM_10_T; if (diag & AC_DIAG_DUPLEX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } static void acphy_reset(struct mii_softc *sc) { mii_phy_reset(sc); PHY_WRITE(sc, MII_ACPHY_INT, 0); } Index: head/sys/dev/mii/amphy.c =================================================================== --- head/sys/dev/mii/amphy.c (revision 227907) +++ head/sys/dev/mii/amphy.c (revision 227908) @@ -1,215 +1,215 @@ /*- * 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. */ #include __FBSDID("$FreeBSD$"); /* * driver for AMD AM79c873 PHYs * This driver also works for Davicom DM910{1,2} PHYs, which appear * to be AM79c873 workalikes. */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int amphy_probe(device_t); static int amphy_attach(device_t); static device_method_t amphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, amphy_probe), DEVMETHOD(device_attach, amphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t amphy_devclass; static driver_t amphy_driver = { "amphy", amphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(amphy, miibus, amphy_driver, amphy_devclass, 0, 0); static int amphy_service(struct mii_softc *, struct mii_data *, int); static void amphy_status(struct mii_softc *); static const struct mii_phydesc amphys[] = { MII_PHY_DESC(xxDAVICOM, DM9102), MII_PHY_DESC(xxDAVICOM, DM9101), MII_PHY_DESC(yyDAVICOM, DM9101), MII_PHY_END }; static const struct mii_phy_funcs amphy_funcs = { amphy_service, amphy_status, mii_phy_reset }; static int amphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, amphys, BUS_PROBE_DEFAULT)); } static int amphy_attach(device_t dev) { mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &hy_funcs, 1); return (0); } static int amphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void amphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr, par, anlpar; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { /* * The PAR status bits are only valid if autonegotiation * has completed (or it's disabled). */ if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if (PHY_READ(sc, MII_ANER) & ANER_LPAN) { anlpar = PHY_READ(sc, MII_ANAR) & PHY_READ(sc, MII_ANLPAR); if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (anlpar & ANLPAR_T4) mii->mii_media_active |= IFM_100_T4|IFM_HDX; else if (anlpar & ANLPAR_TX) mii->mii_media_active |= IFM_100_TX|IFM_HDX; 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|IFM_HDX; else mii->mii_media_active |= IFM_NONE; return; } /* * Link partner is not capable of autonegotiation. */ par = PHY_READ(sc, MII_AMPHY_DSCSR); if (par & DSCSR_100FDX) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (par & DSCSR_100HDX) mii->mii_media_active |= IFM_100_TX|IFM_HDX; else if (par & DSCSR_10FDX) mii->mii_media_active |= IFM_10_T|IFM_HDX; else if (par & DSCSR_10HDX) mii->mii_media_active |= IFM_10_T|IFM_HDX; if ((mii->mii_media_active & IFM_FDX) != 0) mii->mii_media_active |= mii_phy_flowstatus(sc); } else mii->mii_media_active = ife->ifm_media; } Index: head/sys/dev/mii/atphy.c =================================================================== --- head/sys/dev/mii/atphy.c (revision 227907) +++ head/sys/dev/mii/atphy.c (revision 227908) @@ -1,377 +1,377 @@ /*- * Copyright (c) 2008, Pyun YongHyeon * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Driver for the Attansic/Atheros F1 10/100/1000 PHY. */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int atphy_probe(device_t); static int atphy_attach(device_t); static device_method_t atphy_methods[] = { /* Device interface. */ DEVMETHOD(device_probe, atphy_probe), DEVMETHOD(device_attach, atphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { NULL, NULL } + DEVMETHOD_END }; static devclass_t atphy_devclass; static driver_t atphy_driver = { "atphy", atphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(atphy, miibus, atphy_driver, atphy_devclass, 0, 0); static int atphy_service(struct mii_softc *, struct mii_data *, int); static void atphy_status(struct mii_softc *); static void atphy_reset(struct mii_softc *); static uint16_t atphy_anar(struct ifmedia_entry *); static int atphy_setmedia(struct mii_softc *, int); static const struct mii_phydesc atphys[] = { MII_PHY_DESC(xxATHEROS, F1), MII_PHY_DESC(xxATHEROS, F1_7), MII_PHY_DESC(xxATHEROS, F2), MII_PHY_END }; static const struct mii_phy_funcs atphy_funcs = { atphy_service, atphy_status, atphy_reset }; static int atphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, atphys, BUS_PROBE_DEFAULT)); } static int atphy_attach(device_t dev) { mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &atphy_funcs, 1); return (0); } static int atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint16_t anar, bmcr, bmsr; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { atphy_setmedia(sc, ife->ifm_media); break; } bmcr = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_100_TX: bmcr = BMCR_S100; break; case IFM_10_T: bmcr = BMCR_S10; break; case IFM_NONE: bmcr = PHY_READ(sc, MII_BMCR); /* * XXX * Due to an unknown reason powering down PHY resulted * in unexpected results such as inaccessibility of * hardware of freshly rebooted system. Disable * powering down PHY until I got more information for * Attansic/Atheros PHY hardwares. */ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); goto done; default: return (EINVAL); } anar = atphy_anar(ife); if ((ife->ifm_media & IFM_FDX) != 0) { bmcr |= BMCR_FDX; if ((ife->ifm_media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= ANAR_PAUSE_TOWARDS; } if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) PHY_WRITE(sc, MII_100T2CR, 0); PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); /* * Reset the PHY so all changes take effect. */ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); done: break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * Check for link. * Read the status register twice; BMSR_LINK is latch-low. */ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) { sc->mii_ticks = 0; break; } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; if (sc->mii_ticks <= sc->mii_anegticks) return (0); sc->mii_ticks = 0; atphy_setmedia(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void atphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; uint32_t bmsr, bmcr, ssr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if ((bmsr & BMSR_LINK) != 0) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if ((bmcr & BMCR_ISO) != 0) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if ((bmcr & BMCR_LOOP) != 0) mii->mii_media_active |= IFM_LOOP; ssr = PHY_READ(sc, ATPHY_SSR); if ((ssr & ATPHY_SSR_SPD_DPLX_RESOLVED) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } switch (ssr & ATPHY_SSR_SPEED_MASK) { case ATPHY_SSR_1000MBS: mii->mii_media_active |= IFM_1000_T; /* * atphy(4) has a valid link so reset mii_ticks. * Resetting mii_ticks is needed in order to * detect link loss after auto-negotiation. */ sc->mii_ticks = 0; break; case ATPHY_SSR_100MBS: mii->mii_media_active |= IFM_100_TX; sc->mii_ticks = 0; break; case ATPHY_SSR_10MBS: mii->mii_media_active |= IFM_10_T; sc->mii_ticks = 0; break; default: mii->mii_media_active |= IFM_NONE; return; } if ((ssr & ATPHY_SSR_DUPLEX) != 0) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && (PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } static void atphy_reset(struct mii_softc *sc) { struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; uint32_t reg; int i; /* Take PHY out of power down mode. */ PHY_WRITE(sc, 29, 0x29); PHY_WRITE(sc, 30, 0); reg = PHY_READ(sc, ATPHY_SCR); /* Enable automatic crossover. */ reg |= ATPHY_SCR_AUTO_X_MODE; /* Disable power down. */ reg &= ~ATPHY_SCR_MAC_PDOWN; /* Enable CRS on Tx. */ reg |= ATPHY_SCR_ASSERT_CRS_ON_TX; /* Auto correction for reversed cable polarity. */ reg |= ATPHY_SCR_POLARITY_REVERSAL; PHY_WRITE(sc, ATPHY_SCR, reg); /* Workaround F1 bug to reset phy. */ atphy_setmedia(sc, ife == NULL ? IFM_AUTO : ife->ifm_media); for (i = 0; i < 1000; i++) { DELAY(1); if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0) break; } } static uint16_t atphy_anar(struct ifmedia_entry *ife) { uint16_t anar; anar = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10; return (anar); case IFM_1000_T: return (anar); case IFM_100_TX: anar |= ANAR_TX; break; case IFM_10_T: anar |= ANAR_10; break; default: return (0); } if ((ife->ifm_media & IFM_FDX) != 0) { if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_TX) anar |= ANAR_TX_FD; else anar |= ANAR_10_FD; } return (anar); } static int atphy_setmedia(struct mii_softc *sc, int media) { uint16_t anar; anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; if ((IFM_SUBTYPE(media) == IFM_AUTO || (media & IFM_FDX) != 0) && ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0)) anar |= ANAR_PAUSE_TOWARDS; PHY_WRITE(sc, MII_ANAR, anar); if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) PHY_WRITE(sc, MII_100T2CR, GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX); else if (sc->mii_mpd_model == MII_MODEL_xxATHEROS_F1) { /* * AR8132 has 10/100 PHY and the PHY uses the same * model number of F1 gigabit PHY. The PHY has no * ability to establish gigabit link so explicitly * disable 1000baseT configuration for the PHY. * Otherwise, there is a case that atphy(4) could * not establish a link against gigabit link partner * unless the link partner supports down-shifting. */ PHY_WRITE(sc, MII_100T2CR, 0); } PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); return (EJUSTRETURN); } Index: head/sys/dev/mii/axphy.c =================================================================== --- head/sys/dev/mii/axphy.c (revision 227907) +++ head/sys/dev/mii/axphy.c (revision 227908) @@ -1,183 +1,183 @@ /*- * Copyright (c) 2009, M. Warner Losh * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * driver for internal phy in the AX88x9x chips. */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include "miibus_if.h" static int axphy_probe(device_t dev); static int axphy_attach(device_t dev); static device_method_t axphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, axphy_probe), DEVMETHOD(device_attach, axphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t axphy_devclass; static driver_t axphy_driver = { "axphy", axphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(axphy, miibus, axphy_driver, axphy_devclass, 0, 0); static int axphy_service(struct mii_softc *, struct mii_data *, int); static void axphy_status(struct mii_softc *); static const struct mii_phydesc axphys[] = { MII_PHY_DESC(xxASIX, AX88X9X), MII_PHY_END }; static const struct mii_phy_funcs axphy_funcs = { axphy_service, axphy_status, mii_phy_reset }; static int axphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, axphys, BUS_PROBE_DEFAULT)); } static int axphy_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &axphy_funcs, 1); mii_phy_setmedia(sc); return (0); } static int axphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void axphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { if ((bmsr & BMSR_ACOMP) == 0) { mii->mii_media_active |= IFM_NONE; return; } #if 0 scr = PHY_READ(sc, MII_AXPHY_SCR); if (scr & SCR_S100) mii->mii_media_active |= IFM_100_TX; else mii->mii_media_active |= IFM_10_T; if (scr & SCR_FDX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; #endif } else mii->mii_media_active = ife->ifm_media; } Index: head/sys/dev/mii/bmtphy.c =================================================================== --- head/sys/dev/mii/bmtphy.c (revision 227907) +++ head/sys/dev/mii/bmtphy.c (revision 227908) @@ -1,263 +1,262 @@ /*- * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp * */ #include __FBSDID("$FreeBSD$"); /* * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs. This also * drives the PHY on the 3Com 3c905C. The 3c905C's PHY is described in * the 3c905C data sheet. */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int bmtphy_probe(device_t); static int bmtphy_attach(device_t); static device_method_t bmtphy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bmtphy_probe), DEVMETHOD(device_attach, bmtphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - - { 0, 0 } + DEVMETHOD_END }; static devclass_t bmtphy_devclass; static driver_t bmtphy_driver = { "bmtphy", bmtphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0); static int bmtphy_service(struct mii_softc *, struct mii_data *, int); static void bmtphy_status(struct mii_softc *); static void bmtphy_reset(struct mii_softc *); static const struct mii_phydesc bmtphys_dp[] = { MII_PHY_DESC(xxBROADCOM, BCM4401), MII_PHY_DESC(xxBROADCOM, BCM5201), MII_PHY_DESC(xxBROADCOM, BCM5214), MII_PHY_DESC(xxBROADCOM, BCM5221), MII_PHY_DESC(xxBROADCOM, BCM5222), MII_PHY_END }; static const struct mii_phydesc bmtphys_lp[] = { MII_PHY_DESC(xxBROADCOM, 3C905B), MII_PHY_DESC(xxBROADCOM, 3C905C), MII_PHY_END }; static const struct mii_phy_funcs bmtphy_funcs = { bmtphy_service, bmtphy_status, bmtphy_reset }; static int bmtphy_probe(device_t dev) { int rval; /* Let exphy(4) take precedence for these. */ rval = mii_phy_dev_probe(dev, bmtphys_lp, BUS_PROBE_LOW_PRIORITY); if (rval <= 0) return (rval); return (mii_phy_dev_probe(dev, bmtphys_dp, BUS_PROBE_DEFAULT)); } static int bmtphy_attach(device_t dev) { mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &bmtphy_funcs, 1); return (0); } static int bmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void bmtphy_status(struct mii_softc *sc) { struct mii_data *mii; struct ifmedia_entry *ife; int bmsr, bmcr, aux_csr; mii = sc->mii_pdata; ife = mii->mii_media.ifm_cur; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { /* * The media status bits are only valid if autonegotiation * has completed (or it's disabled). */ if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); if (aux_csr & AUX_CSR_SPEED) mii->mii_media_active |= IFM_100_TX; else mii->mii_media_active |= IFM_10_T; if (aux_csr & AUX_CSR_FDX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } static void bmtphy_reset(struct mii_softc *sc) { u_int16_t data; mii_phy_reset(sc); if (sc->mii_mpd_model == MII_MODEL_xxBROADCOM_BCM5221) { /* Enable shadow register mode. */ data = PHY_READ(sc, 0x1f); PHY_WRITE(sc, 0x1f, data | 0x0080); /* Enable APD (Auto PowerDetect). */ data = PHY_READ(sc, MII_BMTPHY_AUX2); PHY_WRITE(sc, MII_BMTPHY_AUX2, data | 0x0020); /* Enable clocks across APD for Auto-MDIX functionality. */ data = PHY_READ(sc, MII_BMTPHY_INTR); PHY_WRITE(sc, MII_BMTPHY_INTR, data | 0x0004); /* Disable shadow register mode. */ data = PHY_READ(sc, 0x1f); PHY_WRITE(sc, 0x1f, data & ~0x0080); } } Index: head/sys/dev/mii/brgphy.c =================================================================== --- head/sys/dev/mii/brgphy.c (revision 227907) +++ head/sys/dev/mii/brgphy.c (revision 227908) @@ -1,1062 +1,1062 @@ /*- * Copyright (c) 2000 * 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. */ #include __FBSDID("$FreeBSD$"); /* * Driver for the Broadcom BCM54xx/57xx 1000baseTX PHY. */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include #include #include #include #include #include #include "miibus_if.h" static int brgphy_probe(device_t); static int brgphy_attach(device_t); struct brgphy_softc { struct mii_softc mii_sc; int serdes_flags; /* Keeps track of the serdes type used */ #define BRGPHY_5706S 0x0001 #define BRGPHY_5708S 0x0002 #define BRGPHY_NOANWAIT 0x0004 #define BRGPHY_5709S 0x0008 int bce_phy_flags; /* PHY flags transferred from the MAC driver */ }; static device_method_t brgphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, brgphy_probe), DEVMETHOD(device_attach, brgphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t brgphy_devclass; static driver_t brgphy_driver = { "brgphy", brgphy_methods, sizeof(struct brgphy_softc) }; DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0); static int brgphy_service(struct mii_softc *, struct mii_data *, int); static void brgphy_setmedia(struct mii_softc *, int); static void brgphy_status(struct mii_softc *); static void brgphy_mii_phy_auto(struct mii_softc *, int); static void brgphy_reset(struct mii_softc *); static void brgphy_enable_loopback(struct mii_softc *); static void bcm5401_load_dspcode(struct mii_softc *); static void bcm5411_load_dspcode(struct mii_softc *); static void bcm54k2_load_dspcode(struct mii_softc *); static void brgphy_fixup_5704_a0_bug(struct mii_softc *); static void brgphy_fixup_adc_bug(struct mii_softc *); static void brgphy_fixup_adjust_trim(struct mii_softc *); static void brgphy_fixup_ber_bug(struct mii_softc *); static void brgphy_fixup_crc_bug(struct mii_softc *); static void brgphy_fixup_jitter_bug(struct mii_softc *); static void brgphy_ethernet_wirespeed(struct mii_softc *); static void brgphy_jumbo_settings(struct mii_softc *, u_long); static const struct mii_phydesc brgphys[] = { MII_PHY_DESC(BROADCOM, BCM5400), MII_PHY_DESC(BROADCOM, BCM5401), MII_PHY_DESC(BROADCOM, BCM5411), MII_PHY_DESC(BROADCOM, BCM54K2), MII_PHY_DESC(BROADCOM, BCM5701), MII_PHY_DESC(BROADCOM, BCM5703), MII_PHY_DESC(BROADCOM, BCM5704), MII_PHY_DESC(BROADCOM, BCM5705), MII_PHY_DESC(BROADCOM, BCM5706), MII_PHY_DESC(BROADCOM, BCM5714), MII_PHY_DESC(BROADCOM, BCM5421), MII_PHY_DESC(BROADCOM, BCM5750), MII_PHY_DESC(BROADCOM, BCM5752), MII_PHY_DESC(BROADCOM, BCM5780), MII_PHY_DESC(BROADCOM, BCM5708C), MII_PHY_DESC(BROADCOM2, BCM5482), MII_PHY_DESC(BROADCOM2, BCM5708S), MII_PHY_DESC(BROADCOM2, BCM5709C), MII_PHY_DESC(BROADCOM2, BCM5709S), MII_PHY_DESC(BROADCOM2, BCM5709CAX), MII_PHY_DESC(BROADCOM2, BCM5722), MII_PHY_DESC(BROADCOM2, BCM5755), MII_PHY_DESC(BROADCOM2, BCM5754), MII_PHY_DESC(BROADCOM2, BCM5761), MII_PHY_DESC(BROADCOM2, BCM5784), MII_PHY_DESC(BROADCOM2, BCM5785), MII_PHY_DESC(BROADCOM3, BCM5717C), MII_PHY_DESC(BROADCOM3, BCM5719C), MII_PHY_DESC(BROADCOM3, BCM5720C), MII_PHY_DESC(BROADCOM3, BCM57765), MII_PHY_DESC(xxBROADCOM_ALT1, BCM5906), MII_PHY_END }; static const struct mii_phy_funcs brgphy_funcs = { brgphy_service, brgphy_status, brgphy_reset }; #define HS21_PRODUCT_ID "IBM eServer BladeCenter HS21" #define HS21_BCM_CHIPID 0x57081021 static int detect_hs21(struct bce_softc *bce_sc) { char *sysenv; int found; found = 0; if (bce_sc->bce_chipid == HS21_BCM_CHIPID) { sysenv = getenv("smbios.system.product"); if (sysenv != NULL) { if (strncmp(sysenv, HS21_PRODUCT_ID, strlen(HS21_PRODUCT_ID)) == 0) found = 1; freeenv(sysenv); } } return (found); } /* Search for our PHY in the list of known PHYs */ static int brgphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, brgphys, BUS_PROBE_DEFAULT)); } /* Attach the PHY to the MII bus */ static int brgphy_attach(device_t dev) { struct brgphy_softc *bsc; struct bge_softc *bge_sc = NULL; struct bce_softc *bce_sc = NULL; struct mii_softc *sc; struct ifnet *ifp; bsc = device_get_softc(dev); sc = &bsc->mii_sc; mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &brgphy_funcs, 0); bsc->serdes_flags = 0; /* Handle any special cases based on the PHY ID */ switch (sc->mii_mpd_oui) { case MII_OUI_BROADCOM: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM_BCM5706: case MII_MODEL_BROADCOM_BCM5714: /* * The 5464 PHY used in the 5706 supports both copper * and fiber interfaces over GMII. Need to check the * shadow registers to see which mode is actually * in effect, and therefore whether we have 5706C or * 5706S. */ PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_MODE_CTRL); if (PHY_READ(sc, BRGPHY_MII_SHADOW_1C) & BRGPHY_SHADOW_1C_ENA_1000X) { bsc->serdes_flags |= BRGPHY_5706S; sc->mii_flags |= MIIF_HAVEFIBER; } break; } break; case MII_OUI_BROADCOM2: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM2_BCM5708S: bsc->serdes_flags |= BRGPHY_5708S; sc->mii_flags |= MIIF_HAVEFIBER; break; case MII_MODEL_BROADCOM2_BCM5709S: bsc->serdes_flags |= BRGPHY_5709S; sc->mii_flags |= MIIF_HAVEFIBER; break; } break; } ifp = sc->mii_pdata->mii_ifp; /* Find the MAC driver associated with this PHY. */ if (strcmp(ifp->if_dname, "bge") == 0) { bge_sc = ifp->if_softc; } else if (strcmp(ifp->if_dname, "bce") == 0) { bce_sc = ifp->if_softc; } PHY_RESET(sc); /* Read the PHY's capabilities. */ sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); device_printf(dev, " "); #define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL) /* Add the supported media types */ if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { mii_phy_add_media(sc); printf("\n"); } else { sc->mii_anegticks = MII_ANEGTICKS_GIGE; ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), BRGPHY_S1000 | BRGPHY_BMCR_FDX); printf("1000baseSX-FDX, "); /* 2.5G support is a software enabled feature on the 5708S and 5709S. */ if (bce_sc && (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)) { ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, sc->mii_inst), 0); printf("2500baseSX-FDX, "); } else if ((bsc->serdes_flags & BRGPHY_5708S) && bce_sc && (detect_hs21(bce_sc) != 0)) { /* * There appears to be certain silicon revision * in IBM HS21 blades that is having issues with * this driver wating for the auto-negotiation to * complete. This happens with a specific chip id * only and when the 1000baseSX-FDX is the only * mode. Workaround this issue since it's unlikely * to be ever addressed. */ printf("auto-neg workaround, "); bsc->serdes_flags |= BRGPHY_NOANWAIT; } ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); printf("auto\n"); } #undef ADD MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int val; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; /* Todo: Why is this here? Is it really needed? */ PHY_RESET(sc); /* XXX hardware bug work-around */ switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: brgphy_mii_phy_auto(sc, ife->ifm_media); break; case IFM_2500_SX: case IFM_1000_SX: case IFM_1000_T: case IFM_100_TX: case IFM_10_T: brgphy_setmedia(sc, ife->ifm_media); break; default: return (EINVAL); } break; case MII_TICK: /* Bail if the interface isn't up. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* Bail if autoneg isn't in process. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. */ val = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (val & BMSR_LINK) { sc->mii_ticks = 0; /* Reset autoneg timer. */ break; } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; /* Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) break; /* Retry autonegotiation */ sc->mii_ticks = 0; brgphy_mii_phy_auto(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* * Callback if something changed. Note that we need to poke * the DSP on the Broadcom PHYs if the media changes. */ if (sc->mii_media_active != mii->mii_media_active || sc->mii_media_status != mii->mii_media_status || cmd == MII_MEDIACHG) { switch (sc->mii_mpd_oui) { case MII_OUI_BROADCOM: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM_BCM5400: bcm5401_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM5401: if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) bcm5401_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM5411: bcm5411_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM54K2: bcm54k2_load_dspcode(sc); break; } break; } } mii_phy_update(sc, cmd); return (0); } /****************************************************************************/ /* Sets the PHY link speed. */ /* */ /* Returns: */ /* None */ /****************************************************************************/ static void brgphy_setmedia(struct mii_softc *sc, int media) { int bmcr = 0, gig; switch (IFM_SUBTYPE(media)) { case IFM_2500_SX: break; case IFM_1000_SX: case IFM_1000_T: bmcr = BRGPHY_S1000; break; case IFM_100_TX: bmcr = BRGPHY_S100; break; case IFM_10_T: default: bmcr = BRGPHY_S10; break; } if ((media & IFM_FDX) != 0) { bmcr |= BRGPHY_BMCR_FDX; gig = BRGPHY_1000CTL_AFD; } else { gig = BRGPHY_1000CTL_AHD; } /* Force loopback to disconnect PHY from Ethernet medium. */ brgphy_enable_loopback(sc); PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); if (IFM_SUBTYPE(media) != IFM_1000_T && IFM_SUBTYPE(media) != IFM_1000_SX) { PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr); return; } if (IFM_SUBTYPE(media) == IFM_1000_T) { gig |= BRGPHY_1000CTL_MSE; if ((media & IFM_ETH_MASTER) != 0) gig |= BRGPHY_1000CTL_MSC; } PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr | BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); } /****************************************************************************/ /* Set the media status based on the PHY settings. */ /* */ /* Returns: */ /* None */ /****************************************************************************/ static void brgphy_status(struct mii_softc *sc) { struct brgphy_softc *bsc = (struct brgphy_softc *)sc; struct mii_data *mii = sc->mii_pdata; int aux, bmcr, bmsr, val, xstat; u_int flowstat; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); if (bmcr & BRGPHY_BMCR_LOOP) { mii->mii_media_active |= IFM_LOOP; } if ((bmcr & BRGPHY_BMCR_AUTOEN) && (bmsr & BRGPHY_BMSR_ACOMP) == 0 && (bsc->serdes_flags & BRGPHY_NOANWAIT) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { /* * NB: reading the ANAR, ANLPAR or 1000STS after the AUXSTS * wedges at least the PHY of BCM5704 (but not others). */ flowstat = mii_phy_flowstatus(sc); xstat = PHY_READ(sc, BRGPHY_MII_1000STS); aux = PHY_READ(sc, BRGPHY_MII_AUXSTS); /* If copper link is up, get the negotiated speed/duplex. */ if (aux & BRGPHY_AUXSTS_LINK) { mii->mii_media_status |= IFM_ACTIVE; switch (aux & BRGPHY_AUXSTS_AN_RES) { case BRGPHY_RES_1000FD: mii->mii_media_active |= IFM_1000_T | IFM_FDX; break; case BRGPHY_RES_1000HD: mii->mii_media_active |= IFM_1000_T | IFM_HDX; break; case BRGPHY_RES_100FD: mii->mii_media_active |= IFM_100_TX | IFM_FDX; break; case BRGPHY_RES_100T4: mii->mii_media_active |= IFM_100_T4; break; case BRGPHY_RES_100HD: mii->mii_media_active |= IFM_100_TX | IFM_HDX; break; case BRGPHY_RES_10FD: mii->mii_media_active |= IFM_10_T | IFM_FDX; break; case BRGPHY_RES_10HD: mii->mii_media_active |= IFM_10_T | IFM_HDX; break; default: mii->mii_media_active |= IFM_NONE; break; } if ((mii->mii_media_active & IFM_FDX) != 0) mii->mii_media_active |= flowstat; if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T && (xstat & BRGPHY_1000STS_MSR) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } } else { /* Todo: Add support for flow control. */ /* If serdes link is up, get the negotiated speed/duplex. */ if (bmsr & BRGPHY_BMSR_LINK) { mii->mii_media_status |= IFM_ACTIVE; } /* Check the link speed/duplex based on the PHY type. */ if (bsc->serdes_flags & BRGPHY_5706S) { mii->mii_media_active |= IFM_1000_SX; /* If autoneg enabled, read negotiated duplex settings */ if (bmcr & BRGPHY_BMCR_AUTOEN) { val = PHY_READ(sc, BRGPHY_SERDES_ANAR) & PHY_READ(sc, BRGPHY_SERDES_ANLPAR); if (val & BRGPHY_SERDES_ANAR_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } } else if (bsc->serdes_flags & BRGPHY_5708S) { PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); /* Check for MRBE auto-negotiated speed results. */ switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: mii->mii_media_active |= IFM_10_FL; break; case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: mii->mii_media_active |= IFM_100_FX; break; case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: mii->mii_media_active |= IFM_1000_SX; break; case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: mii->mii_media_active |= IFM_2500_SX; break; } /* Check for MRBE auto-negotiated duplex results. */ if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } else if (bsc->serdes_flags & BRGPHY_5709S) { /* Select GP Status Block of the AN MMD, get autoneg results. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_GP_STATUS); xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); /* Restore IEEE0 block (assumed in all brgphy(4) code). */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); /* Check for MRBE auto-negotiated speed results. */ switch (xstat & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: mii->mii_media_active |= IFM_10_FL; break; case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: mii->mii_media_active |= IFM_100_FX; break; case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: mii->mii_media_active |= IFM_1000_SX; break; case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: mii->mii_media_active |= IFM_2500_SX; break; } /* Check for MRBE auto-negotiated duplex results. */ if (xstat & BRGPHY_GP_STATUS_TOP_ANEG_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } } } static void brgphy_mii_phy_auto(struct mii_softc *sc, int media) { int anar, ktcr = 0; PHY_RESET(sc); if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= BRGPHY_ANAR_PC | BRGPHY_ANAR_ASP; PHY_WRITE(sc, BRGPHY_MII_ANAR, anar); } else { anar = BRGPHY_SERDES_ANAR_FDX | BRGPHY_SERDES_ANAR_HDX; if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE; PHY_WRITE(sc, BRGPHY_SERDES_ANAR, anar); } ktcr = BRGPHY_1000CTL_AFD | BRGPHY_1000CTL_AHD; if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701) ktcr |= BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC; PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr); ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL); PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); } /* Enable loopback to force the link down. */ static void brgphy_enable_loopback(struct mii_softc *sc) { int i; PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP); for (i = 0; i < 15000; i++) { if (!(PHY_READ(sc, BRGPHY_MII_BMSR) & BRGPHY_BMSR_LINK)) break; DELAY(10); } } /* Turn off tap power management on 5401. */ static void bcm5401_load_dspcode(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c20 }, { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); DELAY(40); } static void bcm5411_load_dspcode(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { 0x1c, 0x8c23 }, { 0x1c, 0x8ca3 }, { 0x1c, 0x8c23 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } void bcm54k2_load_dspcode(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { 4, 0x01e1 }, { 9, 0x0300 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_5704_a0_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { 0x1c, 0x8d68 }, { 0x1c, 0x8d68 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_adc_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_adjust_trim(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, { BRGPHY_MII_DSP_RW_PORT, 0x110b }, { BRGPHY_MII_TEST1, 0x0014 }, { BRGPHY_MII_AUXCTL, 0x0400 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_ber_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, { BRGPHY_MII_DSP_RW_PORT, 0x310b }, { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, { BRGPHY_MII_AUXCTL, 0x0400 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_crc_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_DSP_RW_PORT, 0x0a75 }, { 0x1c, 0x8c68 }, { 0x1c, 0x8d68 }, { 0x1c, 0x8c68 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_jitter_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, { BRGPHY_MII_DSP_RW_PORT, 0x010b }, { BRGPHY_MII_AUXCTL, 0x0400 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_disable_early_dac(struct mii_softc *sc) { uint32_t val; PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08); val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); val &= ~(1 << 8); PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val); } static void brgphy_ethernet_wirespeed(struct mii_softc *sc) { uint32_t val; /* Enable Ethernet@WireSpeed. */ PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); val = PHY_READ(sc, BRGPHY_MII_AUXCTL); PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4)); } static void brgphy_jumbo_settings(struct mii_softc *sc, u_long mtu) { uint32_t val; /* Set or clear jumbo frame settings in the PHY. */ if (mtu > ETHER_MAX_LEN) { if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5401) { /* BCM5401 PHY cannot read-modify-write. */ PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); } else { PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); val = PHY_READ(sc, BRGPHY_MII_AUXCTL); PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | BRGPHY_AUXCTL_LONG_PKT); } val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, val | BRGPHY_PHY_EXTCTL_HIGH_LA); } else { PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); val = PHY_READ(sc, BRGPHY_MII_AUXCTL); PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7)); val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, val & ~BRGPHY_PHY_EXTCTL_HIGH_LA); } } static void brgphy_reset(struct mii_softc *sc) { struct bge_softc *bge_sc = NULL; struct bce_softc *bce_sc = NULL; struct ifnet *ifp; int i, val; /* * Perform a reset. Note that at least some Broadcom PHYs default to * being powered down as well as isolated after a reset but don't work * if one or both of these bits are cleared. However, they just work * fine if both bits remain set, so we don't use mii_phy_reset() here. */ PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_RESET); /* Wait 100ms for it to complete. */ for (i = 0; i < 100; i++) { if ((PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_RESET) == 0) break; DELAY(1000); } /* Handle any PHY specific procedures following the reset. */ switch (sc->mii_mpd_oui) { case MII_OUI_BROADCOM: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM_BCM5400: bcm5401_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM5401: if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) bcm5401_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM5411: bcm5411_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM54K2: bcm54k2_load_dspcode(sc); break; } break; } ifp = sc->mii_pdata->mii_ifp; /* Find the driver associated with this PHY. */ if (strcmp(ifp->if_dname, "bge") == 0) { bge_sc = ifp->if_softc; } else if (strcmp(ifp->if_dname, "bce") == 0) { bce_sc = ifp->if_softc; } if (bge_sc) { /* Fix up various bugs */ if (bge_sc->bge_phy_flags & BGE_PHY_5704_A0_BUG) brgphy_fixup_5704_a0_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_ADC_BUG) brgphy_fixup_adc_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_ADJUST_TRIM) brgphy_fixup_adjust_trim(sc); if (bge_sc->bge_phy_flags & BGE_PHY_BER_BUG) brgphy_fixup_ber_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_CRC_BUG) brgphy_fixup_crc_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_JITTER_BUG) brgphy_fixup_jitter_bug(sc); brgphy_jumbo_settings(sc, ifp->if_mtu); if ((bge_sc->bge_phy_flags & BGE_PHY_NO_WIRESPEED) == 0) brgphy_ethernet_wirespeed(sc); /* Enable Link LED on Dell boxes */ if (bge_sc->bge_phy_flags & BGE_PHY_NO_3LED) { PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) & ~BRGPHY_PHY_EXTCTL_3_LED); } /* Adjust output voltage (From Linux driver) */ if (bge_sc->bge_asicrev == BGE_ASICREV_BCM5906) PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); } else if (bce_sc) { if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5708 && (bce_sc->bce_phy_flags & BCE_PHY_SERDES_FLAG)) { /* Store autoneg capabilities/results in digital block (Page 0) */ PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); /* Enable fiber mode and autodetection */ PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); /* Enable parallel detection */ PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); /* Advertise 2.5G support through next page during autoneg */ if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); /* Increase TX signal amplitude */ if ((BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_A0) || (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B0) || (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B1)) { PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_TX_MISC_PG5); PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & ~0x30); PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); } /* Backplanes use special driver/pre-driver/pre-emphasis values. */ if ((bce_sc->bce_shared_hw_cfg & BCE_SHARED_HW_CFG_PHY_BACKPLANE) && (bce_sc->bce_port_hw_cfg & BCE_PORT_HW_CFG_CFG_TXCTL3_MASK)) { PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_TX_MISC_PG5); PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, bce_sc->bce_port_hw_cfg & BCE_PORT_HW_CFG_CFG_TXCTL3_MASK); PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); } } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709 && (bce_sc->bce_phy_flags & BCE_PHY_SERDES_FLAG)) { /* Select the SerDes Digital block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_SERDES_DIG); val = PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1); val &= ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET; val |= BRGPHY_SD_DIG_1000X_CTL1_FIBER; PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, val); /* Select the Over 1G block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_OVER_1G); /* Enable autoneg "Next Page" to advertise 2.5G support. */ val = PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1); if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) val |= BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G; else val &= ~BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G; PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, val); /* Select the Multi-Rate Backplane Ethernet block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_MRBE); /* Enable MRBE speed autoneg. */ val = PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP); val |= BRGPHY_MRBE_MSG_PG5_NP_MBRE | BRGPHY_MRBE_MSG_PG5_NP_T2; PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, val); /* Select the Clause 73 User B0 block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_CL73_USER_B0); /* Enable MRBE speed autoneg. */ PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1, BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP | BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR | BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG); /* Restore IEEE0 block (assumed in all brgphy(4) code). */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709) { if ((BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Ax) || (BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Bx)) brgphy_fixup_disable_early_dac(sc); brgphy_jumbo_settings(sc, ifp->if_mtu); brgphy_ethernet_wirespeed(sc); } else { brgphy_fixup_ber_bug(sc); brgphy_jumbo_settings(sc, ifp->if_mtu); brgphy_ethernet_wirespeed(sc); } } } Index: head/sys/dev/mii/ciphy.c =================================================================== --- head/sys/dev/mii/ciphy.c (revision 227907) +++ head/sys/dev/mii/ciphy.c (revision 227908) @@ -1,379 +1,379 @@ /*- * Copyright (c) 2004 * 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. */ #include __FBSDID("$FreeBSD$"); /* * Driver for the Cicada/Vitesse CS/VSC8xxx 10/100/1000 copper PHY. */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" #include static int ciphy_probe(device_t); static int ciphy_attach(device_t); static device_method_t ciphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, ciphy_probe), DEVMETHOD(device_attach, ciphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t ciphy_devclass; static driver_t ciphy_driver = { "ciphy", ciphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(ciphy, miibus, ciphy_driver, ciphy_devclass, 0, 0); static int ciphy_service(struct mii_softc *, struct mii_data *, int); static void ciphy_status(struct mii_softc *); static void ciphy_reset(struct mii_softc *); static void ciphy_fixup(struct mii_softc *); static const struct mii_phydesc ciphys[] = { MII_PHY_DESC(xxCICADA, CS8201), MII_PHY_DESC(xxCICADA, CS8201A), MII_PHY_DESC(xxCICADA, CS8201B), MII_PHY_DESC(xxCICADA, CS8204), MII_PHY_DESC(xxCICADA, VSC8211), MII_PHY_DESC(xxCICADA, CS8244), MII_PHY_DESC(xxVITESSE, VSC8601), MII_PHY_END }; static const struct mii_phy_funcs ciphy_funcs = { ciphy_service, ciphy_status, ciphy_reset }; static int ciphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, ciphys, BUS_PROBE_DEFAULT)); } static int ciphy_attach(device_t dev) { mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &ciphy_funcs, 1); return (0); } static int ciphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg, speed, gig; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; ciphy_fixup(sc); /* XXX hardware bug work-around */ switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: #ifdef foo /* * If we're already in auto mode, just return. */ if (PHY_READ(sc, CIPHY_MII_BMCR) & CIPHY_BMCR_AUTOEN) return (0); #endif (void)mii_phy_auto(sc); break; case IFM_1000_T: speed = CIPHY_S1000; goto setit; case IFM_100_TX: speed = CIPHY_S100; goto setit; case IFM_10_T: speed = CIPHY_S10; setit: if ((ife->ifm_media & IFM_FDX) != 0) { speed |= CIPHY_BMCR_FDX; gig = CIPHY_1000CTL_AFD; } else gig = CIPHY_1000CTL_AHD; if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { gig |= CIPHY_1000CTL_MSE; if ((ife->ifm_media & IFM_ETH_MASTER) != 0) gig |= CIPHY_1000CTL_MSC; speed |= CIPHY_BMCR_AUTOEN | CIPHY_BMCR_STARTNEG; } else gig = 0; PHY_WRITE(sc, CIPHY_MII_1000CTL, gig); PHY_WRITE(sc, CIPHY_MII_BMCR, speed); PHY_WRITE(sc, CIPHY_MII_ANAR, CIPHY_SEL_TYPE); break; case IFM_NONE: PHY_WRITE(sc, MII_BMCR, BMCR_ISO | BMCR_PDOWN); break; default: return (EINVAL); } break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) break; /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. Read * the BMSR twice in case it's latched. */ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) break; /* Announce link loss right after it happens. */ if (++sc->mii_ticks == 0) break; /* * Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; mii_phy_auto(sc); break; } /* Update the media status. */ PHY_STATUS(sc); /* * Callback if something changed. Note that we need to poke * apply fixups for certain PHY revs. */ if (sc->mii_media_active != mii->mii_media_active || sc->mii_media_status != mii->mii_media_status || cmd == MII_MEDIACHG) { ciphy_fixup(sc); } mii_phy_update(sc, cmd); return (0); } static void ciphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; int bmsr, bmcr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, CIPHY_MII_BMCR); if (bmcr & CIPHY_BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & CIPHY_BMCR_AUTOEN) { if ((bmsr & CIPHY_BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } } bmsr = PHY_READ(sc, CIPHY_MII_AUXCSR); switch (bmsr & CIPHY_AUXCSR_SPEED) { case CIPHY_SPEED10: mii->mii_media_active |= IFM_10_T; break; case CIPHY_SPEED100: mii->mii_media_active |= IFM_100_TX; break; case CIPHY_SPEED1000: mii->mii_media_active |= IFM_1000_T; break; default: device_printf(sc->mii_dev, "unknown PHY speed %x\n", bmsr & CIPHY_AUXCSR_SPEED); break; } if (bmsr & CIPHY_AUXCSR_FDX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && (PHY_READ(sc, CIPHY_MII_1000STS) & CIPHY_1000STS_MSR) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } static void ciphy_reset(struct mii_softc *sc) { mii_phy_reset(sc); DELAY(1000); } #define PHY_SETBIT(x, y, z) \ PHY_WRITE(x, y, (PHY_READ(x, y) | (z))) #define PHY_CLRBIT(x, y, z) \ PHY_WRITE(x, y, (PHY_READ(x, y) & ~(z))) static void ciphy_fixup(struct mii_softc *sc) { uint16_t model; uint16_t status, speed; uint16_t val; model = MII_MODEL(PHY_READ(sc, CIPHY_MII_PHYIDR2)); status = PHY_READ(sc, CIPHY_MII_AUXCSR); speed = status & CIPHY_AUXCSR_SPEED; if (strcmp(device_get_name(device_get_parent(sc->mii_dev)), "nfe") == 0) { /* need to set for 2.5V RGMII for NVIDIA adapters */ val = PHY_READ(sc, CIPHY_MII_ECTL1); val &= ~(CIPHY_ECTL1_IOVOL | CIPHY_ECTL1_INTSEL); val |= (CIPHY_IOVOL_2500MV | CIPHY_INTSEL_RGMII); PHY_WRITE(sc, CIPHY_MII_ECTL1, val); /* From Linux. */ val = PHY_READ(sc, CIPHY_MII_AUXCSR); val |= CIPHY_AUXCSR_MDPPS; PHY_WRITE(sc, CIPHY_MII_AUXCSR, val); val = PHY_READ(sc, CIPHY_MII_10BTCSR); val |= CIPHY_10BTCSR_ECHO; PHY_WRITE(sc, CIPHY_MII_10BTCSR, val); } switch (model) { case MII_MODEL_xxCICADA_CS8204: case MII_MODEL_xxCICADA_CS8201: /* Turn off "aux mode" (whatever that means) */ PHY_SETBIT(sc, CIPHY_MII_AUXCSR, CIPHY_AUXCSR_MDPPS); /* * Work around speed polling bug in VT3119/VT3216 * when using MII in full duplex mode. */ if ((speed == CIPHY_SPEED10 || speed == CIPHY_SPEED100) && (status & CIPHY_AUXCSR_FDX)) { PHY_SETBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO); } else { PHY_CLRBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO); } /* Enable link/activity LED blink. */ PHY_SETBIT(sc, CIPHY_MII_LED, CIPHY_LED_LINKACTBLINK); break; case MII_MODEL_xxCICADA_CS8201A: case MII_MODEL_xxCICADA_CS8201B: /* * Work around speed polling bug in VT3119/VT3216 * when using MII in full duplex mode. */ if ((speed == CIPHY_SPEED10 || speed == CIPHY_SPEED100) && (status & CIPHY_AUXCSR_FDX)) { PHY_SETBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO); } else { PHY_CLRBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO); } break; case MII_MODEL_xxCICADA_VSC8211: case MII_MODEL_xxCICADA_CS8244: case MII_MODEL_xxVITESSE_VSC8601: break; default: device_printf(sc->mii_dev, "unknown CICADA PHY model %x\n", model); break; } } Index: head/sys/dev/mii/e1000phy.c =================================================================== --- head/sys/dev/mii/e1000phy.c (revision 227907) +++ head/sys/dev/mii/e1000phy.c (revision 227908) @@ -1,501 +1,501 @@ /*- * Principal Author: Parag Patel * Copyright (c) 2001 * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Additional Copyright (c) 2001 by Traakan Software under same licence. * Secondary Author: Matthew Jacob */ #include __FBSDID("$FreeBSD$"); /* * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY. */ /* * Support added for the Marvell 88E1011 (Alaska) 1000/100/10baseTX and * 1000baseSX PHY. * Nathan Binkert * Jung-uk Kim */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int e1000phy_probe(device_t); static int e1000phy_attach(device_t); static device_method_t e1000phy_methods[] = { /* device interface */ DEVMETHOD(device_probe, e1000phy_probe), DEVMETHOD(device_attach, e1000phy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t e1000phy_devclass; static driver_t e1000phy_driver = { "e1000phy", e1000phy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(e1000phy, miibus, e1000phy_driver, e1000phy_devclass, 0, 0); static int e1000phy_service(struct mii_softc *, struct mii_data *, int); static void e1000phy_status(struct mii_softc *); static void e1000phy_reset(struct mii_softc *); static int e1000phy_mii_phy_auto(struct mii_softc *, int); static const struct mii_phydesc e1000phys[] = { MII_PHY_DESC(MARVELL, E1000), MII_PHY_DESC(MARVELL, E1011), MII_PHY_DESC(MARVELL, E1000_3), MII_PHY_DESC(MARVELL, E1000_5), MII_PHY_DESC(MARVELL, E1111), MII_PHY_DESC(xxMARVELL, E1000), MII_PHY_DESC(xxMARVELL, E1011), MII_PHY_DESC(xxMARVELL, E1000_3), MII_PHY_DESC(xxMARVELL, E1000S), MII_PHY_DESC(xxMARVELL, E1000_5), MII_PHY_DESC(xxMARVELL, E1101), MII_PHY_DESC(xxMARVELL, E3082), MII_PHY_DESC(xxMARVELL, E1112), MII_PHY_DESC(xxMARVELL, E1149), MII_PHY_DESC(xxMARVELL, E1111), MII_PHY_DESC(xxMARVELL, E1116), MII_PHY_DESC(xxMARVELL, E1116R), MII_PHY_DESC(xxMARVELL, E1118), MII_PHY_DESC(xxMARVELL, E1149R), MII_PHY_DESC(xxMARVELL, E3016), MII_PHY_DESC(xxMARVELL, PHYG65G), MII_PHY_END }; static const struct mii_phy_funcs e1000phy_funcs = { e1000phy_service, e1000phy_status, e1000phy_reset }; static int e1000phy_probe(device_t dev) { return (mii_phy_dev_probe(dev, e1000phys, BUS_PROBE_DEFAULT)); } static int e1000phy_attach(device_t dev) { struct mii_softc *sc; struct ifnet *ifp; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &e1000phy_funcs, 0); ifp = sc->mii_pdata->mii_ifp; if (strcmp(ifp->if_dname, "msk") == 0 && (sc->mii_flags & MIIF_MACPRIV0) != 0) sc->mii_flags |= MIIF_PHYPRIV0; switch (sc->mii_mpd_model) { case MII_MODEL_xxMARVELL_E1011: case MII_MODEL_xxMARVELL_E1112: if (PHY_READ(sc, E1000_ESSR) & E1000_ESSR_FIBER_LINK) sc->mii_flags |= MIIF_HAVEFIBER; break; case MII_MODEL_xxMARVELL_E1149: case MII_MODEL_xxMARVELL_E1149R: /* * Some 88E1149 PHY's page select is initialized to * point to other bank instead of copper/fiber bank * which in turn resulted in wrong registers were * accessed during PHY operation. It is believed that * page 0 should be used for copper PHY so reinitialize * E1000_EADR to select default copper PHY. If parent * device know the type of PHY(either copper or fiber), * that information should be used to select default * type of PHY. */ PHY_WRITE(sc, E1000_EADR, 0); break; } PHY_RESET(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static void e1000phy_reset(struct mii_softc *sc) { uint16_t reg, page; reg = PHY_READ(sc, E1000_SCR); if ((sc->mii_flags & MIIF_HAVEFIBER) != 0) { reg &= ~E1000_SCR_AUTO_X_MODE; PHY_WRITE(sc, E1000_SCR, reg); if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1112) { /* Select 1000BASE-X only mode. */ page = PHY_READ(sc, E1000_EADR); PHY_WRITE(sc, E1000_EADR, 2); reg = PHY_READ(sc, E1000_SCR); reg &= ~E1000_SCR_MODE_MASK; reg |= E1000_SCR_MODE_1000BX; PHY_WRITE(sc, E1000_SCR, reg); if ((sc->mii_flags & MIIF_PHYPRIV0) != 0) { /* Set SIGDET polarity low for SFP module. */ PHY_WRITE(sc, E1000_EADR, 1); reg = PHY_READ(sc, E1000_SCR); reg |= E1000_SCR_FIB_SIGDET_POLARITY; PHY_WRITE(sc, E1000_SCR, reg); } PHY_WRITE(sc, E1000_EADR, page); } } else { switch (sc->mii_mpd_model) { case MII_MODEL_xxMARVELL_E1111: case MII_MODEL_xxMARVELL_E1112: case MII_MODEL_xxMARVELL_E1116: case MII_MODEL_xxMARVELL_E1118: case MII_MODEL_xxMARVELL_E1149: case MII_MODEL_xxMARVELL_E1149R: case MII_MODEL_xxMARVELL_PHYG65G: /* Disable energy detect mode. */ reg &= ~E1000_SCR_EN_DETECT_MASK; reg |= E1000_SCR_AUTO_X_MODE; if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1116) reg &= ~E1000_SCR_POWER_DOWN; reg |= E1000_SCR_ASSERT_CRS_ON_TX; break; case MII_MODEL_xxMARVELL_E3082: reg |= (E1000_SCR_AUTO_X_MODE >> 1); reg |= E1000_SCR_ASSERT_CRS_ON_TX; break; case MII_MODEL_xxMARVELL_E3016: reg |= E1000_SCR_AUTO_MDIX; reg &= ~(E1000_SCR_EN_DETECT | E1000_SCR_SCRAMBLER_DISABLE); reg |= E1000_SCR_LPNP; /* XXX Enable class A driver for Yukon FE+ A0. */ PHY_WRITE(sc, 0x1C, PHY_READ(sc, 0x1C) | 0x0001); break; default: reg &= ~E1000_SCR_AUTO_X_MODE; reg |= E1000_SCR_ASSERT_CRS_ON_TX; break; } if (sc->mii_mpd_model != MII_MODEL_xxMARVELL_E3016) { /* Auto correction for reversed cable polarity. */ reg &= ~E1000_SCR_POLARITY_REVERSAL; } PHY_WRITE(sc, E1000_SCR, reg); if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1116 || sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1149 || sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1149R) { PHY_WRITE(sc, E1000_EADR, 2); reg = PHY_READ(sc, E1000_SCR); reg |= E1000_SCR_RGMII_POWER_UP; PHY_WRITE(sc, E1000_SCR, reg); PHY_WRITE(sc, E1000_EADR, 0); } } switch (sc->mii_mpd_model) { case MII_MODEL_xxMARVELL_E3082: case MII_MODEL_xxMARVELL_E1112: case MII_MODEL_xxMARVELL_E1118: break; case MII_MODEL_xxMARVELL_E1116: page = PHY_READ(sc, E1000_EADR); /* Select page 3, LED control register. */ PHY_WRITE(sc, E1000_EADR, 3); PHY_WRITE(sc, E1000_SCR, E1000_SCR_LED_LOS(1) | /* Link/Act */ E1000_SCR_LED_INIT(8) | /* 10Mbps */ E1000_SCR_LED_STAT1(7) | /* 100Mbps */ E1000_SCR_LED_STAT0(7)); /* 1000Mbps */ /* Set blink rate. */ PHY_WRITE(sc, E1000_IER, E1000_PULSE_DUR(E1000_PULSE_170MS) | E1000_BLINK_RATE(E1000_BLINK_84MS)); PHY_WRITE(sc, E1000_EADR, page); break; case MII_MODEL_xxMARVELL_E3016: /* LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED. */ PHY_WRITE(sc, 0x16, 0x0B << 8 | 0x05 << 4 | 0x04); /* Integrated register calibration workaround. */ PHY_WRITE(sc, 0x1D, 17); PHY_WRITE(sc, 0x1E, 0x3F60); break; default: /* Force TX_CLK to 25MHz clock. */ reg = PHY_READ(sc, E1000_ESCR); reg |= E1000_ESCR_TX_CLK_25; PHY_WRITE(sc, E1000_ESCR, reg); break; } /* Reset the PHY so all changes take effect. */ reg = PHY_READ(sc, E1000_CR); reg |= E1000_CR_RESET; PHY_WRITE(sc, E1000_CR, reg); } static int e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint16_t speed, gig; int reg; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { e1000phy_mii_phy_auto(sc, ife->ifm_media); break; } speed = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_1000_T: if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) == 0) return (EINVAL); speed = E1000_CR_SPEED_1000; break; case IFM_1000_SX: if ((sc->mii_extcapabilities & (EXTSR_1000XFDX | EXTSR_1000XHDX)) == 0) return (EINVAL); speed = E1000_CR_SPEED_1000; break; case IFM_100_TX: speed = E1000_CR_SPEED_100; break; case IFM_10_T: speed = E1000_CR_SPEED_10; break; case IFM_NONE: reg = PHY_READ(sc, E1000_CR); PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE | E1000_CR_POWER_DOWN); goto done; default: return (EINVAL); } if ((ife->ifm_media & IFM_FDX) != 0) { speed |= E1000_CR_FULL_DUPLEX; gig = E1000_1GCR_1000T_FD; } else gig = E1000_1GCR_1000T; reg = PHY_READ(sc, E1000_CR); reg &= ~E1000_CR_AUTO_NEG_ENABLE; PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET); if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { gig |= E1000_1GCR_MS_ENABLE; if ((ife->ifm_media & IFM_ETH_MASTER) != 0) gig |= E1000_1GCR_MS_VALUE; } else if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) gig = 0; PHY_WRITE(sc, E1000_1GCR, gig); PHY_WRITE(sc, E1000_AR, E1000_AR_SELECTOR_FIELD); PHY_WRITE(sc, E1000_CR, speed | E1000_CR_RESET); done: break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * check for link. * Read the status register twice; BMSR_LINK is latch-low. */ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) { sc->mii_ticks = 0; break; } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; if (sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; PHY_RESET(sc); e1000phy_mii_phy_auto(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void e1000phy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; int bmcr, bmsr, ssr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); bmcr = PHY_READ(sc, E1000_CR); ssr = PHY_READ(sc, E1000_SSR); if (bmsr & E1000_SR_LINK_STATUS) mii->mii_media_status |= IFM_ACTIVE; if (bmcr & E1000_CR_LOOPBACK) mii->mii_media_active |= IFM_LOOP; if ((bmcr & E1000_CR_AUTO_NEG_ENABLE) != 0 && (ssr & E1000_SSR_SPD_DPLX_RESOLVED) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { switch (ssr & E1000_SSR_SPEED) { case E1000_SSR_1000MBS: mii->mii_media_active |= IFM_1000_T; break; case E1000_SSR_100MBS: mii->mii_media_active |= IFM_100_TX; break; case E1000_SSR_10MBS: mii->mii_media_active |= IFM_10_T; break; default: mii->mii_media_active |= IFM_NONE; return; } } else { /* * Some fiber PHY(88E1112) does not seem to set resolved * speed so always assume we've got IFM_1000_SX. */ mii->mii_media_active |= IFM_1000_SX; } if (ssr & E1000_SSR_DUPLEX) { mii->mii_media_active |= IFM_FDX; if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) mii->mii_media_active |= mii_phy_flowstatus(sc); } else mii->mii_media_active |= IFM_HDX; if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { if (((PHY_READ(sc, E1000_1GSR) | PHY_READ(sc, E1000_1GSR)) & E1000_1GSR_MS_CONFIG_RES) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } } static int e1000phy_mii_phy_auto(struct mii_softc *sc, int media) { uint16_t reg; if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { reg = PHY_READ(sc, E1000_AR); reg &= ~(E1000_AR_PAUSE | E1000_AR_ASM_DIR); reg |= E1000_AR_10T | E1000_AR_10T_FD | E1000_AR_100TX | E1000_AR_100TX_FD; if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) reg |= E1000_AR_PAUSE | E1000_AR_ASM_DIR; PHY_WRITE(sc, E1000_AR, reg | E1000_AR_SELECTOR_FIELD); } else PHY_WRITE(sc, E1000_AR, E1000_FA_1000X_FD | E1000_FA_1000X); if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) PHY_WRITE(sc, E1000_1GCR, E1000_1GCR_1000T_FD | E1000_1GCR_1000T); PHY_WRITE(sc, E1000_CR, E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG); return (EJUSTRETURN); } Index: head/sys/dev/mii/gentbi.c =================================================================== --- head/sys/dev/mii/gentbi.c (revision 227907) +++ head/sys/dev/mii/gentbi.c (revision 227908) @@ -1,267 +1,267 @@ /* $NetBSD: gentbi.c,v 1.15 2006/03/29 07:05:24 thorpej Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Driver for generic ten-bit (1000BASE-SX) interfaces, built into * many Gigabit Ethernet chips. * * All we have to do here is correctly report speed and duplex. */ #include __FBSDID("$FreeBSD$"); /* * Driver for generic unknown ten-bit interfaces(1000BASE-{LX,SX} * fiber interfaces). */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include "miibus_if.h" static int gentbi_probe(device_t); static int gentbi_attach(device_t); static device_method_t gentbi_methods[] = { /* device interface */ DEVMETHOD(device_probe, gentbi_probe), DEVMETHOD(device_attach, gentbi_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - {0, 0} + DEVMETHOD_END }; static devclass_t gentbi_devclass; static driver_t gentbi_driver = { "gentbi", gentbi_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(gentbi, miibus, gentbi_driver, gentbi_devclass, 0, 0); static int gentbi_service(struct mii_softc *, struct mii_data *, int); static void gentbi_status(struct mii_softc *); static const struct mii_phy_funcs gentbi_funcs = { gentbi_service, gentbi_status, mii_phy_reset }; static int gentbi_probe(device_t dev) { device_t parent; struct mii_attach_args *ma; int bmsr, extsr; parent = device_get_parent(dev); ma = device_get_ivars(dev); /* * We match as a generic TBI if: * * - There is no media in the BMSR. * - EXTSR has only 1000X. */ bmsr = MIIBUS_READREG(parent, ma->mii_phyno, MII_BMSR); if ((bmsr & BMSR_EXTSTAT) == 0 || (bmsr & BMSR_MEDIAMASK) != 0) return (ENXIO); extsr = MIIBUS_READREG(parent, ma->mii_phyno, MII_EXTSR); if (extsr & (EXTSR_1000TFDX|EXTSR_1000THDX)) return (ENXIO); if (extsr & (EXTSR_1000XFDX|EXTSR_1000XHDX)) { /* * We think this is a generic TBI. Return a match * priority higher than ukphy, but lower than what * specific drivers will return. */ device_set_desc(dev, "Generic ten-bit interface"); return (BUS_PROBE_LOW_PRIORITY); } return (ENXIO); } static int gentbi_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &gentbi_funcs, 0); PHY_RESET(sc); /* * Mask out all media in the BMSR. We only are really interested * in "auto". */ sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask & ~BMSR_MEDIAMASK; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int gentbi_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void gentbi_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr, anlpar; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { /* * The media status bits are only valid if autonegotiation * has completed (or it's disabled). */ if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } /* * The media is always 1000baseSX. Check the ANLPAR to * see if we're doing full-duplex. */ mii->mii_media_active |= IFM_1000_SX; anlpar = PHY_READ(sc, MII_ANLPAR); if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0 && (anlpar & ANLPAR_X_FD) != 0) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } Index: head/sys/dev/mii/icsphy.c =================================================================== --- head/sys/dev/mii/icsphy.c (revision 227907) +++ head/sys/dev/mii/icsphy.c (revision 227908) @@ -1,245 +1,245 @@ /* $NetBSD: icsphy.c,v 1.41 2006/11/16 21:24:07 christos Exp $ */ /*- * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * driver for Integrated Circuit Systems' ICS1889-1893 ethernet 10/100 PHY * datasheet from www.icst.com */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int icsphy_probe(device_t dev); static int icsphy_attach(device_t dev); static device_method_t icsphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, icsphy_probe), DEVMETHOD(device_attach, icsphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t icsphy_devclass; static driver_t icsphy_driver = { "icsphy", icsphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(icsphy, miibus, icsphy_driver, icsphy_devclass, 0, 0); static int icsphy_service(struct mii_softc *, struct mii_data *, int); static void icsphy_status(struct mii_softc *); static void icsphy_reset(struct mii_softc *); static const struct mii_phydesc icsphys[] = { MII_PHY_DESC(ICS, 1889), MII_PHY_DESC(ICS, 1890), MII_PHY_DESC(ICS, 1892), MII_PHY_DESC(ICS, 1893), MII_PHY_END }; static const struct mii_phy_funcs icsphy_funcs = { icsphy_service, icsphy_status, icsphy_reset }; static int icsphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, icsphys, BUS_PROBE_DEFAULT)); } static int icsphy_attach(device_t dev) { mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &icsphy_funcs, 1); return (0); } static int icsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void icsphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmcr, qpr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; /* * Don't get link from the BMSR. It's available in the QPR, * and we have to read it twice to unlatch it anyhow. This * gives us fewer register reads. */ qpr = PHY_READ(sc, MII_ICSPHY_QPR); /* unlatch */ qpr = PHY_READ(sc, MII_ICSPHY_QPR); /* real value */ if (qpr & QPR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { if ((qpr & QPR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if (qpr & QPR_SPEED) mii->mii_media_active |= IFM_100_TX; else mii->mii_media_active |= IFM_10_T; if (qpr & QPR_FDX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } static void icsphy_reset(struct mii_softc *sc) { mii_phy_reset(sc); /* set powerdown feature */ switch (sc->mii_mpd_model) { case MII_MODEL_ICS_1890: case MII_MODEL_ICS_1893: PHY_WRITE(sc, MII_ICSPHY_ECR2, ECR2_100AUTOPWRDN); break; case MII_MODEL_ICS_1892: PHY_WRITE(sc, MII_ICSPHY_ECR2, ECR2_10AUTOPWRDN|ECR2_100AUTOPWRDN); break; default: /* 1889 have no ECR2 */ break; } /* * There is no description that the reset do auto-negotiation in the * data sheet. */ PHY_WRITE(sc, MII_BMCR, BMCR_S100|BMCR_STARTNEG|BMCR_FDX); } Index: head/sys/dev/mii/ip1000phy.c =================================================================== --- head/sys/dev/mii/ip1000phy.c (revision 227907) +++ head/sys/dev/mii/ip1000phy.c (revision 227908) @@ -1,365 +1,365 @@ /*- * Copyright (c) 2006, Pyun YongHyeon * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); /* * Driver for the IC Plus IP1000A/IP1001 10/100/1000 PHY. */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" #include #include static int ip1000phy_probe(device_t); static int ip1000phy_attach(device_t); static device_method_t ip1000phy_methods[] = { /* device interface */ DEVMETHOD(device_probe, ip1000phy_probe), DEVMETHOD(device_attach, ip1000phy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t ip1000phy_devclass; static driver_t ip1000phy_driver = { "ip1000phy", ip1000phy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(ip1000phy, miibus, ip1000phy_driver, ip1000phy_devclass, 0, 0); static int ip1000phy_service(struct mii_softc *, struct mii_data *, int); static void ip1000phy_status(struct mii_softc *); static void ip1000phy_reset(struct mii_softc *); static int ip1000phy_mii_phy_auto(struct mii_softc *, int); static const struct mii_phydesc ip1000phys[] = { MII_PHY_DESC(xxICPLUS, IP1000A), MII_PHY_DESC(xxICPLUS, IP1001), MII_PHY_END }; static const struct mii_phy_funcs ip1000phy_funcs = { ip1000phy_service, ip1000phy_status, ip1000phy_reset }; static int ip1000phy_probe(device_t dev) { return (mii_phy_dev_probe(dev, ip1000phys, BUS_PROBE_DEFAULT)); } static int ip1000phy_attach(device_t dev) { struct mii_attach_args *ma; u_int flags; ma = device_get_ivars(dev); flags = MIIF_NOISOLATE | MIIF_NOMANPAUSE; if (MII_MODEL(ma->mii_id2) == MII_MODEL_xxICPLUS_IP1000A && strcmp(ma->mii_data->mii_ifp->if_dname, "stge") == 0 && (miibus_get_flags(dev) & MIIF_MACPRIV0) != 0) flags |= MIIF_PHYPRIV0; mii_phy_dev_attach(dev, flags, &ip1000phy_funcs, 1); return (0); } static int ip1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint32_t gig, reg, speed; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { break; } PHY_RESET(sc); switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: (void)ip1000phy_mii_phy_auto(sc, ife->ifm_media); goto done; case IFM_1000_T: /* * XXX * Manual 1000baseT setting doesn't seem to work. */ speed = IP1000PHY_BMCR_1000; break; case IFM_100_TX: speed = IP1000PHY_BMCR_100; break; case IFM_10_T: speed = IP1000PHY_BMCR_10; break; default: return (EINVAL); } if ((ife->ifm_media & IFM_FDX) != 0) { speed |= IP1000PHY_BMCR_FDX; gig = IP1000PHY_1000CR_1000T_FDX; } else gig = IP1000PHY_1000CR_1000T; if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { gig |= IP1000PHY_1000CR_MASTER | IP1000PHY_1000CR_MANUAL; if ((ife->ifm_media & IFM_ETH_MASTER) != 0) gig |= IP1000PHY_1000CR_MMASTER; } else gig = 0; PHY_WRITE(sc, IP1000PHY_MII_1000CR, gig); PHY_WRITE(sc, IP1000PHY_MII_BMCR, speed); done: break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * check for link. */ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) { sc->mii_ticks = 0; break; } /* Announce link loss right after it happens */ if (sc->mii_ticks++ == 0) break; /* * Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; ip1000phy_mii_phy_auto(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void ip1000phy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; uint32_t bmsr, bmcr, stat; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, IP1000PHY_MII_BMSR) | PHY_READ(sc, IP1000PHY_MII_BMSR); if ((bmsr & IP1000PHY_BMSR_LINK) != 0) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, IP1000PHY_MII_BMCR); if ((bmcr & IP1000PHY_BMCR_LOOP) != 0) mii->mii_media_active |= IFM_LOOP; if ((bmcr & IP1000PHY_BMCR_AUTOEN) != 0) { if ((bmsr & IP1000PHY_BMSR_ANEGCOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } } if (sc->mii_mpd_model == MII_MODEL_xxICPLUS_IP1001) { stat = PHY_READ(sc, IP1000PHY_LSR); switch (stat & IP1000PHY_LSR_SPEED_MASK) { case IP1000PHY_LSR_SPEED_10: mii->mii_media_active |= IFM_10_T; break; case IP1000PHY_LSR_SPEED_100: mii->mii_media_active |= IFM_100_TX; break; case IP1000PHY_LSR_SPEED_1000: mii->mii_media_active |= IFM_1000_T; break; default: mii->mii_media_active |= IFM_NONE; return; } if ((stat & IP1000PHY_LSR_FULL_DUPLEX) != 0) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } else { stat = PHY_READ(sc, STGE_PhyCtrl); switch (PC_LinkSpeed(stat)) { case PC_LinkSpeed_Down: mii->mii_media_active |= IFM_NONE; return; case PC_LinkSpeed_10: mii->mii_media_active |= IFM_10_T; break; case PC_LinkSpeed_100: mii->mii_media_active |= IFM_100_TX; break; case PC_LinkSpeed_1000: mii->mii_media_active |= IFM_1000_T; break; default: mii->mii_media_active |= IFM_NONE; return; } if ((stat & PC_PhyDuplexStatus) != 0) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } if ((mii->mii_media_active & IFM_FDX) != 0) mii->mii_media_active |= mii_phy_flowstatus(sc); if ((mii->mii_media_active & IFM_1000_T) != 0) { stat = PHY_READ(sc, IP1000PHY_MII_1000SR); if ((stat & IP1000PHY_1000SR_MASTER) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } } static int ip1000phy_mii_phy_auto(struct mii_softc *sc, int media) { uint32_t reg; reg = 0; if (sc->mii_mpd_model == MII_MODEL_xxICPLUS_IP1001) { reg = PHY_READ(sc, IP1000PHY_MII_ANAR); reg &= ~(IP1000PHY_ANAR_PAUSE | IP1000PHY_ANAR_APAUSE); reg |= IP1000PHY_ANAR_NP; } reg |= IP1000PHY_ANAR_10T | IP1000PHY_ANAR_10T_FDX | IP1000PHY_ANAR_100TX | IP1000PHY_ANAR_100TX_FDX; if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) reg |= IP1000PHY_ANAR_PAUSE | IP1000PHY_ANAR_APAUSE; PHY_WRITE(sc, IP1000PHY_MII_ANAR, reg | IP1000PHY_ANAR_CSMA); reg = IP1000PHY_1000CR_1000T | IP1000PHY_1000CR_1000T_FDX; if (sc->mii_mpd_model != MII_MODEL_xxICPLUS_IP1001) reg |= IP1000PHY_1000CR_MASTER; PHY_WRITE(sc, IP1000PHY_MII_1000CR, reg); PHY_WRITE(sc, IP1000PHY_MII_BMCR, (IP1000PHY_BMCR_FDX | IP1000PHY_BMCR_AUTOEN | IP1000PHY_BMCR_STARTNEG)); return (EJUSTRETURN); } static void ip1000phy_load_dspcode(struct mii_softc *sc) { PHY_WRITE(sc, 31, 0x0001); PHY_WRITE(sc, 27, 0x01e0); PHY_WRITE(sc, 31, 0x0002); PHY_WRITE(sc, 27, 0xeb8e); PHY_WRITE(sc, 31, 0x0000); PHY_WRITE(sc, 30, 0x005e); PHY_WRITE(sc, 9, 0x0700); DELAY(50); } static void ip1000phy_reset(struct mii_softc *sc) { uint32_t reg; mii_phy_reset(sc); /* clear autoneg/full-duplex as we don't want it after reset */ reg = PHY_READ(sc, IP1000PHY_MII_BMCR); reg &= ~(IP1000PHY_BMCR_AUTOEN | IP1000PHY_BMCR_FDX); PHY_WRITE(sc, MII_BMCR, reg); if ((sc->mii_flags & MIIF_PHYPRIV0) != 0) ip1000phy_load_dspcode(sc); } Index: head/sys/dev/mii/jmphy.c =================================================================== --- head/sys/dev/mii/jmphy.c (revision 227907) +++ head/sys/dev/mii/jmphy.c (revision 227908) @@ -1,356 +1,356 @@ /*- * Copyright (c) 2008, Pyun YongHyeon * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Driver for the JMicron JMP211 10/100/1000, JMP202 10/100 PHY. */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int jmphy_probe(device_t); static int jmphy_attach(device_t); static void jmphy_reset(struct mii_softc *); static uint16_t jmphy_anar(struct ifmedia_entry *); static int jmphy_setmedia(struct mii_softc *, struct ifmedia_entry *); static device_method_t jmphy_methods[] = { /* Device interface. */ DEVMETHOD(device_probe, jmphy_probe), DEVMETHOD(device_attach, jmphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { NULL, NULL } + DEVMETHOD_END }; static devclass_t jmphy_devclass; static driver_t jmphy_driver = { "jmphy", jmphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(jmphy, miibus, jmphy_driver, jmphy_devclass, 0, 0); static int jmphy_service(struct mii_softc *, struct mii_data *, int); static void jmphy_status(struct mii_softc *); static const struct mii_phydesc jmphys[] = { MII_PHY_DESC(JMICRON, JMP202), MII_PHY_DESC(JMICRON, JMP211), MII_PHY_END }; static const struct mii_phy_funcs jmphy_funcs = { jmphy_service, jmphy_status, jmphy_reset }; static int jmphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, jmphys, BUS_PROBE_DEFAULT)); } static int jmphy_attach(device_t dev) { struct mii_attach_args *ma; u_int flags; ma = device_get_ivars(dev); flags = 0; if (strcmp(ma->mii_data->mii_ifp->if_dname, "jme") == 0 && (miibus_get_flags(dev) & MIIF_MACPRIV0) != 0) flags |= MIIF_PHYPRIV0; mii_phy_dev_attach(dev, flags, &jmphy_funcs, 1); return (0); } static int jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; if (jmphy_setmedia(sc, ife) != EJUSTRETURN) return (EINVAL); break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* Check for link. */ if ((PHY_READ(sc, JMPHY_SSR) & JMPHY_SSR_LINK_UP) != 0) { sc->mii_ticks = 0; break; } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; if (sc->mii_ticks <= sc->mii_anegticks) return (0); sc->mii_ticks = 0; (void)jmphy_setmedia(sc, ife); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void jmphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; int bmcr, ssr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; ssr = PHY_READ(sc, JMPHY_SSR); if ((ssr & JMPHY_SSR_LINK_UP) != 0) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if ((bmcr & BMCR_ISO) != 0) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if ((bmcr & BMCR_LOOP) != 0) mii->mii_media_active |= IFM_LOOP; if ((ssr & JMPHY_SSR_SPD_DPLX_RESOLVED) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } switch ((ssr & JMPHY_SSR_SPEED_MASK)) { case JMPHY_SSR_SPEED_1000: mii->mii_media_active |= IFM_1000_T; /* * jmphy(4) got a valid link so reset mii_ticks. * Resetting mii_ticks is needed in order to * detect link loss after auto-negotiation. */ sc->mii_ticks = 0; break; case JMPHY_SSR_SPEED_100: mii->mii_media_active |= IFM_100_TX; sc->mii_ticks = 0; break; case JMPHY_SSR_SPEED_10: mii->mii_media_active |= IFM_10_T; sc->mii_ticks = 0; break; default: mii->mii_media_active |= IFM_NONE; return; } if ((ssr & JMPHY_SSR_DUPLEX) != 0) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { if ((PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } } static void jmphy_reset(struct mii_softc *sc) { uint16_t t2cr, val; int i; /* Disable sleep mode. */ PHY_WRITE(sc, JMPHY_TMCTL, PHY_READ(sc, JMPHY_TMCTL) & ~JMPHY_TMCTL_SLEEP_ENB); PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN); for (i = 0; i < 1000; i++) { DELAY(1); if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0) break; } /* Perform vendor recommended PHY calibration. */ if ((sc->mii_flags & MIIF_PHYPRIV0) != 0) { /* Select PHY test mode 1. */ t2cr = PHY_READ(sc, MII_100T2CR); t2cr &= ~GTCR_TEST_MASK; t2cr |= 0x2000; PHY_WRITE(sc, MII_100T2CR, t2cr); /* Apply calibration patch. */ PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_READ | JMPHY_EXT_COMM_2); val = PHY_READ(sc, JMPHY_SPEC_DATA); val &= ~0x0002; val |= 0x0010 | 0x0001; PHY_WRITE(sc, JMPHY_SPEC_DATA, val); PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_WRITE | JMPHY_EXT_COMM_2); /* XXX 20ms to complete recalibration. */ DELAY(20 * 1000); PHY_READ(sc, MII_100T2CR); PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_READ | JMPHY_EXT_COMM_2); val = PHY_READ(sc, JMPHY_SPEC_DATA); val &= ~(0x0001 | 0x0002 | 0x0010); PHY_WRITE(sc, JMPHY_SPEC_DATA, val); PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_WRITE | JMPHY_EXT_COMM_2); /* Disable PHY test mode. */ PHY_READ(sc, MII_100T2CR); t2cr &= ~GTCR_TEST_MASK; PHY_WRITE(sc, MII_100T2CR, t2cr); } } static uint16_t jmphy_anar(struct ifmedia_entry *ife) { uint16_t anar; anar = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10; break; case IFM_1000_T: break; case IFM_100_TX: anar |= ANAR_TX | ANAR_TX_FD; break; case IFM_10_T: anar |= ANAR_10 | ANAR_10_FD; break; default: break; } return (anar); } static int jmphy_setmedia(struct mii_softc *sc, struct ifmedia_entry *ife) { uint16_t anar, bmcr, gig; gig = 0; bmcr = PHY_READ(sc, MII_BMCR); switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; break; case IFM_1000_T: gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; break; case IFM_100_TX: case IFM_10_T: break; case IFM_NONE: PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO | BMCR_PDOWN); return (EJUSTRETURN); default: return (EINVAL); } anar = jmphy_anar(ife); if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || (ife->ifm_media & IFM_FDX) != 0) && ((ife->ifm_media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0)) anar |= ANAR_PAUSE_TOWARDS; if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) { if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { gig |= GTCR_MAN_MS; if ((ife->ifm_media & IFM_ETH_MASTER) != 0) gig |= GTCR_ADV_MS; } PHY_WRITE(sc, MII_100T2CR, gig); } PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_AUTOEN | BMCR_STARTNEG); return (EJUSTRETURN); } Index: head/sys/dev/mii/lxtphy.c =================================================================== --- head/sys/dev/mii/lxtphy.c (revision 227907) +++ head/sys/dev/mii/lxtphy.c (revision 227908) @@ -1,275 +1,275 @@ /* OpenBSD: lxtphy.c,v 1.5 2000/08/26 20:04:17 nate Exp */ /* NetBSD: lxtphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp */ /*- * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * driver for Level One's LXT-970 ethernet 10/100 PHY * datasheet from www.level1.com */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int lxtphy_probe(device_t); static int lxtphy_attach(device_t); static device_method_t lxtphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, lxtphy_probe), DEVMETHOD(device_attach, lxtphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t lxtphy_devclass; static driver_t lxtphy_driver = { "lxtphy", lxtphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(lxtphy, miibus, lxtphy_driver, lxtphy_devclass, 0, 0); static int lxtphy_service(struct mii_softc *, struct mii_data *, int); static void lxtphy_status(struct mii_softc *); static void lxtphy_reset(struct mii_softc *); static void lxtphy_set_tp(struct mii_softc *); static void lxtphy_set_fx(struct mii_softc *); static const struct mii_phydesc lxtphys[] = { MII_PHY_DESC(xxLEVEL1, LXT970), MII_PHY_END }; static const struct mii_phy_funcs lxtphy_funcs = { lxtphy_service, lxtphy_status, lxtphy_reset }; static int lxtphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, lxtphys, BUS_PROBE_DEFAULT)); } static int lxtphy_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &lxtphy_funcs, 0); PHY_RESET(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; device_printf(dev, " "); #define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL) ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst), MII_MEDIA_100_TX); printf("100baseFX, "); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst), MII_MEDIA_100_TX_FDX); printf("100baseFX-FDX, "); #undef ADD mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int lxtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_FX) lxtphy_set_fx(sc); else lxtphy_set_tp(sc); mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void lxtphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmcr, bmsr, csr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; /* * Get link status from the CSR; we need to read the CSR * for media type anyhow, and the link status in the CSR * doens't latch, so fewer register reads are required. */ csr = PHY_READ(sc, MII_LXTPHY_CSR); if (csr & CSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if (csr & CSR_SPEED) mii->mii_media_active |= IFM_100_TX; else mii->mii_media_active |= IFM_10_T; if (csr & CSR_DUPLEX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } static void lxtphy_reset(struct mii_softc *sc) { mii_phy_reset(sc); PHY_WRITE(sc, MII_LXTPHY_IER, PHY_READ(sc, MII_LXTPHY_IER) & ~IER_INTEN); } static void lxtphy_set_tp(struct mii_softc *sc) { int cfg; cfg = PHY_READ(sc, MII_LXTPHY_CONFIG); cfg &= ~CONFIG_100BASEFX; PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg); } static void lxtphy_set_fx(struct mii_softc *sc) { int cfg; cfg = PHY_READ(sc, MII_LXTPHY_CONFIG); cfg |= CONFIG_100BASEFX; PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg); } Index: head/sys/dev/mii/mlphy.c =================================================================== --- head/sys/dev/mii/mlphy.c (revision 227907) +++ head/sys/dev/mii/mlphy.c (revision 227908) @@ -1,390 +1,390 @@ /*- * 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. * */ #include __FBSDID("$FreeBSD$"); /* * driver for Micro Linear 6692 PHYs * * The Micro Linear 6692 is a strange beast, and dealing with it using * this code framework is tricky. The 6692 is actually a 100Mbps-only * device, which means that a second PHY is required to support 10Mbps * modes. However, even though the 6692 does not support 10Mbps modes, * it can still advertise them when performing autonegotiation. If a * 10Mbps mode is negotiated, we must program the registers of the * companion PHY accordingly in addition to programming the registers * of the 6692. * * This device also does not have vendor/device ID registers. */ #include #include #include #include #include #include #include #include #include #include #include #include "miibus_if.h" #define ML_STATE_AUTO_SELF 1 #define ML_STATE_AUTO_OTHER 2 struct mlphy_softc { struct mii_softc ml_mii; device_t ml_dev; int ml_state; int ml_linked; }; static int mlphy_probe(device_t); static int mlphy_attach(device_t); static device_method_t mlphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, mlphy_probe), DEVMETHOD(device_attach, mlphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t mlphy_devclass; static driver_t mlphy_driver = { "mlphy", mlphy_methods, sizeof(struct mlphy_softc) }; DRIVER_MODULE(mlphy, miibus, mlphy_driver, mlphy_devclass, 0, 0); static struct mii_softc *mlphy_find_other(struct mlphy_softc *); static int mlphy_service(struct mii_softc *, struct mii_data *, int); static void mlphy_reset(struct mii_softc *); static void mlphy_status(struct mii_softc *); static const struct mii_phy_funcs mlphy_funcs = { mlphy_service, mlphy_status, mlphy_reset }; static int mlphy_probe(dev) device_t dev; { struct mii_attach_args *ma; ma = device_get_ivars(dev); /* * Micro Linear PHY reports oui == 0 model == 0 */ if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || MII_MODEL(ma->mii_id2) != 0) return (ENXIO); /* * Make sure the parent is a `tl'. So far, I have only * encountered the 6692 on an Olicom card with a ThunderLAN * controller chip. */ if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), "tl") != 0) return (ENXIO); device_set_desc(dev, "Micro Linear 6692 media interface"); return (BUS_PROBE_DEFAULT); } static int mlphy_attach(dev) device_t dev; { struct mlphy_softc *msc; struct mii_softc *sc; msc = device_get_softc(dev); sc = &msc->ml_mii; msc->ml_dev = dev; mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &mlphy_funcs, 0); PHY_RESET(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; /* Let the companion PHY (if any) only handle the media we don't. */ sc->mii_capmask = ~sc->mii_capabilities; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static struct mii_softc * mlphy_find_other(struct mlphy_softc *msc) { device_t *devlist; struct mii_softc *retval; int i, devs; retval = NULL; if (device_get_children(msc->ml_mii.mii_dev, &devlist, &devs) != 0) return (NULL); for (i = 0; i < devs; i++) { if (devlist[i] != msc->ml_dev) { retval = device_get_softc(devlist[i]); break; } } free(devlist, M_TEMP); return (retval); } static int mlphy_service(xsc, mii, cmd) struct mii_softc *xsc; struct mii_data *mii; int cmd; { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; struct mii_softc *other = NULL; struct mlphy_softc *msc = (struct mlphy_softc *)xsc; struct mii_softc *sc = (struct mii_softc *)&msc->ml_mii; int other_inst, reg; /* * See if there's another PHY on this bus with us. * If so, we may need it for 10Mbps modes. */ other = mlphy_find_other(msc); switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: /* * For autonegotiation, reset and isolate the * companion PHY (if any) and then do NWAY * autonegotiation ourselves. */ msc->ml_state = ML_STATE_AUTO_SELF; if (other != NULL) { PHY_RESET(other); PHY_WRITE(other, MII_BMCR, BMCR_ISO); } (void)mii_phy_auto(sc); msc->ml_linked = 0; return (0); case IFM_10_T: /* * For 10baseT modes, reset and program the * companion PHY (of any), then program ourselves * to match. This will put us in pass-through * mode and let the companion PHY do all the * work. * * BMCR data is stored in the ifmedia entry. */ if (other != NULL) { PHY_RESET(other); PHY_WRITE(other, MII_BMCR, ife->ifm_data); } mii_phy_setmedia(sc); msc->ml_state = 0; break; case IFM_100_TX: /* * For 100baseTX modes, reset and isolate the * companion PHY (if any), then program ourselves * accordingly. * * BMCR data is stored in the ifmedia entry. */ if (other != NULL) { PHY_RESET(other); PHY_WRITE(other, MII_BMCR, BMCR_ISO); } mii_phy_setmedia(sc); msc->ml_state = 0; break; default: return (EINVAL); } break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) break; /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. Read * the BMSR twice in case it's latched. * If we're in a 10Mbps mode, check the link of the * 10Mbps PHY. Sometimes the Micro Linear PHY's * linkstat bit will clear while the linkstat bit of * the companion PHY will remain set. */ if (msc->ml_state == ML_STATE_AUTO_OTHER) { reg = PHY_READ(other, MII_BMSR) | PHY_READ(other, MII_BMSR); } else { reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); } if (reg & BMSR_LINK) { if (!msc->ml_linked) { msc->ml_linked = 1; PHY_STATUS(sc); } break; } /* * Only retry autonegotiation every 5 seconds. */ if (++sc->mii_ticks <= MII_ANEGTICKS) break; sc->mii_ticks = 0; msc->ml_linked = 0; mii->mii_media_active = IFM_NONE; PHY_RESET(sc); msc->ml_state = ML_STATE_AUTO_SELF; if (other != NULL) { PHY_RESET(other); PHY_WRITE(other, MII_BMCR, BMCR_ISO); } mii_phy_auto(sc); return (0); } /* Update the media status. */ if (msc->ml_state == ML_STATE_AUTO_OTHER) { other_inst = other->mii_inst; other->mii_inst = sc->mii_inst; if (IFM_INST(ife->ifm_media) == other->mii_inst) (void)PHY_SERVICE(other, mii, MII_POLLSTAT); other->mii_inst = other_inst; sc->mii_media_active = other->mii_media_active; sc->mii_media_status = other->mii_media_status; } else ukphy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } /* * The Micro Linear PHY comes out of reset with the 'autoneg * enable' bit set, which we don't want. */ static void mlphy_reset(sc) struct mii_softc *sc; { int reg; mii_phy_reset(sc); reg = PHY_READ(sc, MII_BMCR); reg &= ~BMCR_AUTOEN; PHY_WRITE(sc, MII_BMCR, reg); } /* * If we negotiate a 10Mbps mode, we need to check for an alternate * PHY and make sure it's enabled and set correctly. */ static void mlphy_status(sc) struct mii_softc *sc; { struct mlphy_softc *msc = (struct mlphy_softc *)sc; struct mii_data *mii = msc->ml_mii.mii_pdata; struct mii_softc *other = NULL; /* See if there's another PHY on the bus with us. */ other = mlphy_find_other(msc); if (other == NULL) return; ukphy_status(sc); if (IFM_SUBTYPE(mii->mii_media_active) != IFM_10_T) { msc->ml_state = ML_STATE_AUTO_SELF; PHY_RESET(other); PHY_WRITE(other, MII_BMCR, BMCR_ISO); } if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) { msc->ml_state = ML_STATE_AUTO_OTHER; PHY_RESET(&msc->ml_mii); PHY_WRITE(&msc->ml_mii, MII_BMCR, BMCR_ISO); PHY_RESET(other); mii_phy_auto(other); } } Index: head/sys/dev/mii/nsgphy.c =================================================================== --- head/sys/dev/mii/nsgphy.c (revision 227907) +++ head/sys/dev/mii/nsgphy.c (revision 227908) @@ -1,252 +1,252 @@ /*- * Copyright (c) 2001 Wind River Systems * Copyright (c) 2001 * Bill Paul . All rights reserved. * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Driver for the National Semiconductor DP83861, DP83865 and DP83891 * 10/100/1000 PHYs. * Datasheet available at: http://www.national.com/ds/DP/DP83861.pdf * and at: http://www.national.com/ds/DP/DP83865.pdf * * The DP83891 is the older NS GigE PHY which isn't being sold * anymore. The DP83861 is its replacement, which is an 'enhanced' * firmware driven component. The major difference between the * two is that the DP83891 can't generate interrupts, while the * 83861 can (probably it wasn't originally designed to do this, but * it can now thanks to firmware updates). The DP83861 also allows * access to its internal RAM via indirect register access. The * DP83865 is an ultra low power version of the DP83861 and DP83891. */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int nsgphy_probe(device_t); static int nsgphy_attach(device_t); static device_method_t nsgphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, nsgphy_probe), DEVMETHOD(device_attach, nsgphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t nsgphy_devclass; static driver_t nsgphy_driver = { "nsgphy", nsgphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(nsgphy, miibus, nsgphy_driver, nsgphy_devclass, 0, 0); static int nsgphy_service(struct mii_softc *, struct mii_data *,int); static void nsgphy_status(struct mii_softc *); static const struct mii_phydesc nsgphys[] = { MII_PHY_DESC(xxNATSEMI, DP83861), MII_PHY_DESC(xxNATSEMI, DP83865), MII_PHY_DESC(xxNATSEMI, DP83891), MII_PHY_END }; static const struct mii_phy_funcs nsgphy_funcs = { nsgphy_service, nsgphy_status, mii_phy_reset }; static int nsgphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, nsgphys, BUS_PROBE_DEFAULT)); } static int nsgphy_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &nsgphy_funcs, 0); PHY_RESET(sc); /* * NB: the PHY has the 10BASE-T BMSR bits hard-wired to 0, * even though it supports 10BASE-T. */ sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) | BMSR_10TFDX | BMSR_10THDX) & sc->mii_capmask; /* * Note that as documented manual 1000BASE-T modes of DP83865 only * work together with other National Semiconductor PHYs. */ if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int nsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void nsgphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr, physup, gtsr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); physup = PHY_READ(sc, NSGPHY_MII_PHYSUP); if (physup & PHY_SUP_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { /* * The media status bits are only valid if autonegotiation * has completed (or it's disabled). */ if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } switch (physup & (PHY_SUP_SPEED1 | PHY_SUP_SPEED0)) { case PHY_SUP_SPEED1: mii->mii_media_active |= IFM_1000_T; gtsr = PHY_READ(sc, MII_100T2SR); if (gtsr & GTSR_MS_RES) mii->mii_media_active |= IFM_ETH_MASTER; break; case PHY_SUP_SPEED0: mii->mii_media_active |= IFM_100_TX; break; case 0: mii->mii_media_active |= IFM_10_T; break; default: mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (physup & PHY_SUP_DUPLEX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } Index: head/sys/dev/mii/nsphy.c =================================================================== --- head/sys/dev/mii/nsphy.c (revision 227907) +++ head/sys/dev/mii/nsphy.c (revision 227908) @@ -1,332 +1,332 @@ /* $NetBSD: nsphy.c,v 1.18 1999/07/14 23:57:36 thorpej Exp $ */ /*- * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * driver for National Semiconductor's DP83840A ethernet 10/100 PHY * Data Sheet available from www.national.com */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int nsphy_probe(device_t); static int nsphy_attach(device_t); static device_method_t nsphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, nsphy_probe), DEVMETHOD(device_attach, nsphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t nsphy_devclass; static driver_t nsphy_driver = { "nsphy", nsphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(nsphy, miibus, nsphy_driver, nsphy_devclass, 0, 0); static int nsphy_service(struct mii_softc *, struct mii_data *, int); static void nsphy_status(struct mii_softc *); static void nsphy_reset(struct mii_softc *); static const struct mii_phydesc nsphys[] = { MII_PHY_DESC(xxNATSEMI, DP83840), MII_PHY_END }; static const struct mii_phy_funcs nsphy_funcs = { nsphy_service, nsphy_status, nsphy_reset }; static int nsphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, nsphys, BUS_PROBE_DEFAULT)); } static int nsphy_attach(device_t dev) { const char *nic; u_int flags; nic = device_get_name(device_get_parent(device_get_parent(dev))); flags = MIIF_NOMANPAUSE; /* * Am79C971 wedge when isolating all of their external PHYs. */ if (strcmp(nic, "pcn") == 0) flags |= MIIF_NOISOLATE; mii_phy_dev_attach(dev, flags, &nsphy_funcs, 1); return (0); } static int nsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { int reg; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; reg = PHY_READ(sc, MII_NSPHY_PCR); /* * Set up the PCR to use LED4 to indicate full-duplex * in both 10baseT and 100baseTX modes. */ reg |= PCR_LED4MODE; /* * Make sure Carrier Integrity Monitor function is * disabled (normal for Node operation, but sometimes * it's not set?!) */ reg |= PCR_CIMDIS; /* * Make sure "force link good" is set to normal mode. * It's only intended for debugging. */ reg |= PCR_FLINK100; /* * Mystery bits which are supposedly `reserved', * but we seem to need to set them when the PHY * is connected to some interfaces: * * 0x0400 is needed for fxp * (Intel EtherExpress Pro 10+/100B, 82557 chip) * (nsphy with a DP83840 chip) * 0x0100 may be needed for some other card */ reg |= 0x0100 | 0x0400; if (strcmp(mii->mii_ifp->if_dname, "fxp") == 0) PHY_WRITE(sc, MII_NSPHY_PCR, reg); mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void nsphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr, par, anlpar; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { /* * The PAR status bits are only valid if autonegotiation * has completed (or it's disabled). */ if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } /* * Argh. The PAR doesn't seem to indicate duplex mode * properly! Determine media based on link partner's * advertised capabilities. */ if (PHY_READ(sc, MII_ANER) & ANER_LPAN) { anlpar = PHY_READ(sc, MII_ANAR) & PHY_READ(sc, MII_ANLPAR); if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (anlpar & ANLPAR_T4) mii->mii_media_active |= IFM_100_T4|IFM_HDX; else if (anlpar & ANLPAR_TX) mii->mii_media_active |= IFM_100_TX|IFM_HDX; 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|IFM_HDX; else mii->mii_media_active |= IFM_NONE; if ((mii->mii_media_active & IFM_FDX) != 0) mii->mii_media_active |= mii_phy_flowstatus(sc); return; } /* * Link partner is not capable of autonegotiation. * We will never be in full-duplex mode if this is * the case, so reading the PAR is OK. */ par = PHY_READ(sc, MII_NSPHY_PAR); if (par & PAR_10) mii->mii_media_active |= IFM_10_T; else mii->mii_media_active |= IFM_100_TX; mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } static void nsphy_reset(struct mii_softc *sc) { struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; int reg, i; if (sc->mii_flags & MIIF_NOISOLATE) reg = BMCR_RESET; else reg = BMCR_RESET | BMCR_ISO; PHY_WRITE(sc, MII_BMCR, reg); /* * It is best to allow a little time for the reset to settle * in before we start polling the BMCR again. Notably, the * DP83840A manuals state that there should be a 500us delay * between asserting software reset and attempting MII serial * operations. Be conservative. */ DELAY(1000); /* * Wait another 2s for it to complete. * This is only a little overkill as under normal circumstances * the PHY can take up to 1s to complete reset. * This is also a bit odd because after a reset, the BMCR will * clear the reset bit and simply reports 0 even though the reset * is not yet complete. */ for (i = 0; i < 1000; i++) { reg = PHY_READ(sc, MII_BMCR); if (reg != 0 && (reg & BMCR_RESET) == 0) break; DELAY(2000); } if ((sc->mii_flags & MIIF_NOISOLATE) == 0) { if ((ife == NULL && sc->mii_inst != 0) || (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst)) PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); } } Index: head/sys/dev/mii/nsphyter.c =================================================================== --- head/sys/dev/mii/nsphyter.c (revision 227907) +++ head/sys/dev/mii/nsphyter.c (revision 227908) @@ -1,266 +1,266 @@ /* $NetBSD: nsphyter.c,v 1.28 2008/01/20 07:58:19 msaitoh Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * driver for National Semiconductor's DP83843 `PHYTER' ethernet 10/100 PHY * Data Sheet available from www.national.com * * We also support the DP83815 `MacPHYTER' internal PHY since, for our * purposes, they are compatible. */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static device_probe_t nsphyter_probe; static device_attach_t nsphyter_attach; static device_method_t nsphyter_methods[] = { /* device interface */ DEVMETHOD(device_probe, nsphyter_probe), DEVMETHOD(device_attach, nsphyter_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t nsphyter_devclass; static driver_t nsphyter_driver = { "nsphyter", nsphyter_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(nsphyter, miibus, nsphyter_driver, nsphyter_devclass, 0, 0); static int nsphyter_service(struct mii_softc *, struct mii_data *, int); static void nsphyter_status(struct mii_softc *); static void nsphyter_reset(struct mii_softc *); static const struct mii_phydesc nsphyters[] = { MII_PHY_DESC(xxNATSEMI, DP83815), MII_PHY_DESC(xxNATSEMI, DP83843), MII_PHY_DESC(xxNATSEMI, DP83847), MII_PHY_END }; static const struct mii_phy_funcs nsphyter_funcs = { nsphyter_service, nsphyter_status, nsphyter_reset }; static int nsphyter_probe(device_t dev) { return (mii_phy_dev_probe(dev, nsphyters, BUS_PROBE_DEFAULT)); } static int nsphyter_attach(device_t dev) { mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &nsphyter_funcs, 1); return (0); } static int nsphyter_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void nsphyter_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr, physts; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); physts = PHY_READ(sc, MII_NSPHYTER_PHYSTS); if ((physts & PHYSTS_LINK) != 0) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if ((bmcr & BMCR_ISO) != 0) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if ((bmcr & BMCR_LOOP) != 0) mii->mii_media_active |= IFM_LOOP; if ((bmcr & BMCR_AUTOEN) != 0) { /* * The media status bits are only valid if autonegotiation * has completed (or it's disabled). */ if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if ((physts & PHYSTS_SPEED10) != 0) mii->mii_media_active |= IFM_10_T; else mii->mii_media_active |= IFM_100_TX; if ((physts & PHYSTS_DUPLEX) != 0) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } static void nsphyter_reset(struct mii_softc *sc) { struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; int reg, i; if ((sc->mii_flags & MIIF_NOISOLATE) != 0) reg = BMCR_RESET; else reg = BMCR_RESET | BMCR_ISO; PHY_WRITE(sc, MII_BMCR, reg); /* * It is best to allow a little time for the reset to settle * in before we start polling the BMCR again. Notably, the * DP8384{3,7} manuals state that there should be a 500us delay * between asserting software reset and attempting MII serial * operations. Be conservative. Also, a DP83815 can get into * a bad state on cable removal and reinsertion if we do not * delay here. */ DELAY(1000); /* * Wait another 2s for it to complete. * This is only a little overkill as under normal circumstances * the PHY can take up to 1s to complete reset. * This is also a bit odd because after a reset, the BMCR will * clear the reset bit and simply reports 0 even though the reset * is not yet complete. */ for (i = 0; i < 1000; i++) { reg = PHY_READ(sc, MII_BMCR); if (reg != 0 && (reg & BMCR_RESET) == 0) break; DELAY(2000); } if ((sc->mii_flags & MIIF_NOISOLATE) == 0) { if ((ife == NULL && sc->mii_inst != 0) || (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst)) PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); } } Index: head/sys/dev/mii/pnaphy.c =================================================================== --- head/sys/dev/mii/pnaphy.c (revision 227907) +++ head/sys/dev/mii/pnaphy.c (revision 227908) @@ -1,153 +1,153 @@ /*- * Copyright (c) 2000 Berkeley Software Design, Inc. * Copyright (c) 1997, 1998, 1999, 2000 * 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. */ #include __FBSDID("$FreeBSD$"); /* * driver for homePNA PHYs * This is really just a stub that allows us to identify homePNA-based * transceicers and display the link status. MII-based homePNA PHYs * only support one media type and no autonegotiation. If we were * really clever, we could tweak some of the vendor-specific registers * to optimize the link. */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include "miibus_if.h" static int pnaphy_probe(device_t); static int pnaphy_attach(device_t); static device_method_t pnaphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, pnaphy_probe), DEVMETHOD(device_attach, pnaphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t pnaphy_devclass; static driver_t pnaphy_driver = { "pnaphy", pnaphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(pnaphy, miibus, pnaphy_driver, pnaphy_devclass, 0, 0); static int pnaphy_service(struct mii_softc *, struct mii_data *,int); static const struct mii_phydesc pnaphys[] = { MII_PHY_DESC(yyAMD, 79c901home), MII_PHY_END }; static const struct mii_phy_funcs pnaphy_funcs = { pnaphy_service, ukphy_status, mii_phy_reset }; static int pnaphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, pnaphys, BUS_PROBE_DEFAULT)); } static int pnaphy_attach(device_t dev) { mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_IS_HPNA | MIIF_NOMANPAUSE, &pnaphy_funcs, 1); return (0); } static int pnaphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_HPNA_1: mii_phy_setmedia(sc); break; default: return (EINVAL); } break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) mii->mii_media_active = IFM_ETHER | IFM_HPNA_1; /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } Index: head/sys/dev/mii/qsphy.c =================================================================== --- head/sys/dev/mii/qsphy.c (revision 227907) +++ head/sys/dev/mii/qsphy.c (revision 227908) @@ -1,235 +1,235 @@ /* OpenBSD: qsphy.c,v 1.6 2000/08/26 20:04:18 nate Exp */ /* NetBSD: qsphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp */ /*- * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * driver for Quality Semiconductor's QS6612 ethernet 10/100 PHY * datasheet from www.qualitysemi.com */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int qsphy_probe(device_t); static int qsphy_attach(device_t); static device_method_t qsphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, qsphy_probe), DEVMETHOD(device_attach, qsphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t qsphy_devclass; static driver_t qsphy_driver = { "qsphy", qsphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(qsphy, miibus, qsphy_driver, qsphy_devclass, 0, 0); static int qsphy_service(struct mii_softc *, struct mii_data *, int); static void qsphy_reset(struct mii_softc *); static void qsphy_status(struct mii_softc *); static const struct mii_phydesc qsphys[] = { MII_PHY_DESC(xxQUALSEMI, QS6612), MII_PHY_END }; static const struct mii_phy_funcs qsphy_funcs = { qsphy_service, qsphy_status, qsphy_reset }; static int qsphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, qsphys, BUS_PROBE_DEFAULT)); } static int qsphy_attach(device_t dev) { mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &qsphy_funcs, 1); return (0); } static int qsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * This PHY's autonegotiation doesn't need to be kicked. */ break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void qsphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; int bmsr, bmcr, pctl; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(sc, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; pctl = PHY_READ(sc, MII_QSPHY_PCTL); switch (pctl & PCTL_OPMASK) { case PCTL_10_T: mii->mii_media_active |= IFM_10_T|IFM_HDX; break; case PCTL_10_T_FDX: mii->mii_media_active |= IFM_10_T|IFM_FDX; break; case PCTL_100_TX: mii->mii_media_active |= IFM_100_TX|IFM_HDX; break; case PCTL_100_TX_FDX: mii->mii_media_active |= IFM_100_TX|IFM_FDX; break; case PCTL_100_T4: mii->mii_media_active |= IFM_100_T4|IFM_HDX; break; case PCTL_AN: mii->mii_media_active |= IFM_NONE; break; default: /* Erg... this shouldn't happen. */ mii->mii_media_active |= IFM_NONE; break; } if ((mii->mii_media_active & IFM_FDX) != 0) mii->mii_media_active |= mii_phy_flowstatus(sc); } static void qsphy_reset(struct mii_softc *sc) { mii_phy_reset(sc); PHY_WRITE(sc, MII_QSPHY_IMASK, 0); } Index: head/sys/dev/mii/rgephy.c =================================================================== --- head/sys/dev/mii/rgephy.c (revision 227907) +++ head/sys/dev/mii/rgephy.c (revision 227908) @@ -1,499 +1,499 @@ /*- * Copyright (c) 2003 * 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. */ #include __FBSDID("$FreeBSD$"); /* * Driver for the RealTek 8169S/8110S/8211B/8211C internal 10/100/1000 PHY. */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" #include #include static int rgephy_probe(device_t); static int rgephy_attach(device_t); static device_method_t rgephy_methods[] = { /* device interface */ DEVMETHOD(device_probe, rgephy_probe), DEVMETHOD(device_attach, rgephy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t rgephy_devclass; static driver_t rgephy_driver = { "rgephy", rgephy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, 0, 0); static int rgephy_service(struct mii_softc *, struct mii_data *, int); static void rgephy_status(struct mii_softc *); static int rgephy_mii_phy_auto(struct mii_softc *, int); static void rgephy_reset(struct mii_softc *); static void rgephy_loop(struct mii_softc *); static void rgephy_load_dspcode(struct mii_softc *); static const struct mii_phydesc rgephys[] = { MII_PHY_DESC(REALTEK, RTL8169S), MII_PHY_END }; static const struct mii_phy_funcs rgephy_funcs = { rgephy_service, rgephy_status, rgephy_reset }; static int rgephy_probe(device_t dev) { return (mii_phy_dev_probe(dev, rgephys, BUS_PROBE_DEFAULT)); } static int rgephy_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, 0, &rgephy_funcs, 0); /* RTL8169S do not report auto-sense; add manually. */ sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) | BMSR_ANEG) & sc->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); /* * Allow IFM_FLAG0 to be set indicating that auto-negotiation with * manual configuration, which is used to work around issues with * certain setups by default, should not be triggered as it may in * turn cause harm in some edge cases. */ sc->mii_pdata->mii_media.ifm_mask |= IFM_FLAG0; PHY_RESET(sc); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg, speed, gig, anar; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; PHY_RESET(sc); /* XXX hardware bug work-around */ anar = PHY_READ(sc, RGEPHY_MII_ANAR); anar &= ~(RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP | RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX | RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10); switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: #ifdef foo /* * If we're already in auto mode, just return. */ if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN) return (0); #endif (void)rgephy_mii_phy_auto(sc, ife->ifm_media); break; case IFM_1000_T: speed = RGEPHY_S1000; goto setit; case IFM_100_TX: speed = RGEPHY_S100; anar |= RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX; goto setit; case IFM_10_T: speed = RGEPHY_S10; anar |= RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10; setit: if ((ife->ifm_media & IFM_FLOW) != 0 && (mii->mii_media.ifm_media & IFM_FLAG0) != 0) return (EINVAL); if ((ife->ifm_media & IFM_FDX) != 0) { speed |= RGEPHY_BMCR_FDX; gig = RGEPHY_1000CTL_AFD; anar &= ~(RGEPHY_ANAR_TX | RGEPHY_ANAR_10); if ((ife->ifm_media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP; } else { gig = RGEPHY_1000CTL_AHD; anar &= ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_10_FD); } if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { gig |= RGEPHY_1000CTL_MSE; if ((ife->ifm_media & IFM_ETH_MASTER) != 0) gig |= RGEPHY_1000CTL_MSC; } else { gig = 0; anar &= ~RGEPHY_ANAR_ASP; } if ((mii->mii_media.ifm_media & IFM_FLAG0) == 0) speed |= RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG; rgephy_loop(sc); PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig); PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); PHY_WRITE(sc, RGEPHY_MII_BMCR, speed); break; case IFM_NONE: PHY_WRITE(sc, MII_BMCR, BMCR_ISO | BMCR_PDOWN); break; default: return (EINVAL); } break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. */ if (sc->mii_mpd_rev >= 2) { /* RTL8211B(L) */ reg = PHY_READ(sc, RGEPHY_MII_SSR); if (reg & RGEPHY_SSR_LINK) { sc->mii_ticks = 0; break; } } else { reg = PHY_READ(sc, RL_GMEDIASTAT); if (reg & RL_GMEDIASTAT_LINK) { sc->mii_ticks = 0; break; } } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; /* Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) return (0); sc->mii_ticks = 0; rgephy_mii_phy_auto(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* * Callback if something changed. Note that we need to poke * the DSP on the RealTek PHYs if the media changes. * */ if (sc->mii_media_active != mii->mii_media_active || sc->mii_media_status != mii->mii_media_status || cmd == MII_MEDIACHG) { rgephy_load_dspcode(sc); } mii_phy_update(sc, cmd); return (0); } static void rgephy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; int bmsr, bmcr; uint16_t ssr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; if (sc->mii_mpd_rev >= 2) { ssr = PHY_READ(sc, RGEPHY_MII_SSR); if (ssr & RGEPHY_SSR_LINK) mii->mii_media_status |= IFM_ACTIVE; } else { bmsr = PHY_READ(sc, RL_GMEDIASTAT); if (bmsr & RL_GMEDIASTAT_LINK) mii->mii_media_status |= IFM_ACTIVE; } bmsr = PHY_READ(sc, RGEPHY_MII_BMSR); bmcr = PHY_READ(sc, RGEPHY_MII_BMCR); if (bmcr & RGEPHY_BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & RGEPHY_BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & RGEPHY_BMCR_AUTOEN) { if ((bmsr & RGEPHY_BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } } if (sc->mii_mpd_rev >= 2) { ssr = PHY_READ(sc, RGEPHY_MII_SSR); switch (ssr & RGEPHY_SSR_SPD_MASK) { case RGEPHY_SSR_S1000: mii->mii_media_active |= IFM_1000_T; break; case RGEPHY_SSR_S100: mii->mii_media_active |= IFM_100_TX; break; case RGEPHY_SSR_S10: mii->mii_media_active |= IFM_10_T; break; default: mii->mii_media_active |= IFM_NONE; break; } if (ssr & RGEPHY_SSR_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } else { bmsr = PHY_READ(sc, RL_GMEDIASTAT); if (bmsr & RL_GMEDIASTAT_1000MBPS) mii->mii_media_active |= IFM_1000_T; else if (bmsr & RL_GMEDIASTAT_100MBPS) mii->mii_media_active |= IFM_100_TX; else if (bmsr & RL_GMEDIASTAT_10MBPS) mii->mii_media_active |= IFM_10_T; else mii->mii_media_active |= IFM_NONE; if (bmsr & RL_GMEDIASTAT_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } if ((mii->mii_media_active & IFM_FDX) != 0) mii->mii_media_active |= mii_phy_flowstatus(sc); if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && (PHY_READ(sc, RGEPHY_MII_1000STS) & RGEPHY_1000STS_MSR) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } static int rgephy_mii_phy_auto(struct mii_softc *sc, int media) { int anar; rgephy_loop(sc); PHY_RESET(sc); anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP; PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); DELAY(1000); PHY_WRITE(sc, RGEPHY_MII_1000CTL, RGEPHY_1000CTL_AHD | RGEPHY_1000CTL_AFD); DELAY(1000); PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); DELAY(100); return (EJUSTRETURN); } static void rgephy_loop(struct mii_softc *sc) { int i; if (sc->mii_mpd_rev < 2) { PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN); DELAY(1000); } for (i = 0; i < 15000; i++) { if (!(PHY_READ(sc, RGEPHY_MII_BMSR) & RGEPHY_BMSR_LINK)) { #if 0 device_printf(sc->mii_dev, "looped %d\n", i); #endif break; } DELAY(10); } } #define PHY_SETBIT(x, y, z) \ PHY_WRITE(x, y, (PHY_READ(x, y) | (z))) #define PHY_CLRBIT(x, y, z) \ PHY_WRITE(x, y, (PHY_READ(x, y) & ~(z))) /* * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of * existing revisions of the 8169S/8110S chips need to be tuned in * order to reliably negotiate a 1000Mbps link. This is only needed * for rev 0 and rev 1 of the PHY. Later versions work without * any fixups. */ static void rgephy_load_dspcode(struct mii_softc *sc) { int val; if (sc->mii_mpd_rev >= 2) return; PHY_WRITE(sc, 31, 0x0001); PHY_WRITE(sc, 21, 0x1000); PHY_WRITE(sc, 24, 0x65C7); PHY_CLRBIT(sc, 4, 0x0800); val = PHY_READ(sc, 4) & 0xFFF; PHY_WRITE(sc, 4, val); PHY_WRITE(sc, 3, 0x00A1); PHY_WRITE(sc, 2, 0x0008); PHY_WRITE(sc, 1, 0x1020); PHY_WRITE(sc, 0, 0x1000); PHY_SETBIT(sc, 4, 0x0800); PHY_CLRBIT(sc, 4, 0x0800); val = (PHY_READ(sc, 4) & 0xFFF) | 0x7000; PHY_WRITE(sc, 4, val); PHY_WRITE(sc, 3, 0xFF41); PHY_WRITE(sc, 2, 0xDE60); PHY_WRITE(sc, 1, 0x0140); PHY_WRITE(sc, 0, 0x0077); val = (PHY_READ(sc, 4) & 0xFFF) | 0xA000; PHY_WRITE(sc, 4, val); PHY_WRITE(sc, 3, 0xDF01); PHY_WRITE(sc, 2, 0xDF20); PHY_WRITE(sc, 1, 0xFF95); PHY_WRITE(sc, 0, 0xFA00); val = (PHY_READ(sc, 4) & 0xFFF) | 0xB000; PHY_WRITE(sc, 4, val); PHY_WRITE(sc, 3, 0xFF41); PHY_WRITE(sc, 2, 0xDE20); PHY_WRITE(sc, 1, 0x0140); PHY_WRITE(sc, 0, 0x00BB); val = (PHY_READ(sc, 4) & 0xFFF) | 0xF000; PHY_WRITE(sc, 4, val); PHY_WRITE(sc, 3, 0xDF01); PHY_WRITE(sc, 2, 0xDF20); PHY_WRITE(sc, 1, 0xFF95); PHY_WRITE(sc, 0, 0xBF00); PHY_SETBIT(sc, 4, 0x0800); PHY_CLRBIT(sc, 4, 0x0800); PHY_WRITE(sc, 31, 0x0000); DELAY(40); } static void rgephy_reset(struct mii_softc *sc) { uint16_t ssr; if (sc->mii_mpd_rev == 3) { /* RTL8211C(L) */ ssr = PHY_READ(sc, RGEPHY_MII_SSR); if ((ssr & RGEPHY_SSR_ALDPS) != 0) { ssr &= ~RGEPHY_SSR_ALDPS; PHY_WRITE(sc, RGEPHY_MII_SSR, ssr); } } mii_phy_reset(sc); DELAY(1000); rgephy_load_dspcode(sc); } Index: head/sys/dev/mii/rlphy.c =================================================================== --- head/sys/dev/mii/rlphy.c (revision 227907) +++ head/sys/dev/mii/rlphy.c (revision 227908) @@ -1,272 +1,272 @@ /*- * 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. */ #include __FBSDID("$FreeBSD$"); /* * driver for RealTek 8139 internal PHYs */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include #include "miibus_if.h" static int rlphy_probe(device_t); static int rlphy_attach(device_t); static device_method_t rlphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, rlphy_probe), DEVMETHOD(device_attach, rlphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t rlphy_devclass; static driver_t rlphy_driver = { "rlphy", rlphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(rlphy, miibus, rlphy_driver, rlphy_devclass, 0, 0); static int rlphy_service(struct mii_softc *, struct mii_data *, int); static void rlphy_status(struct mii_softc *); /* * RealTek internal PHYs don't have vendor/device ID registers; * re(4) and rl(4) fake up a return value of all zeros. */ static const struct mii_phydesc rlintphys[] = { { 0, 0, "RealTek internal media interface" }, MII_PHY_END }; static const struct mii_phydesc rlphys[] = { MII_PHY_DESC(yyREALTEK, RTL8201L), MII_PHY_DESC(REALTEK, RTL8201E), MII_PHY_DESC(xxICPLUS, IP101), MII_PHY_END }; static const struct mii_phy_funcs rlphy_funcs = { rlphy_service, rlphy_status, mii_phy_reset }; static int rlphy_probe(device_t dev) { const char *nic; int rv; rv = mii_phy_dev_probe(dev, rlphys, BUS_PROBE_DEFAULT); if (rv <= 0) return (rv); nic = device_get_name(device_get_parent(device_get_parent(dev))); if (strcmp(nic, "rl") == 0 || strcmp(nic, "re") == 0) return (mii_phy_dev_probe(dev, rlintphys, BUS_PROBE_DEFAULT)); return (ENXIO); } static int rlphy_attach(device_t dev) { /* * The RealTek PHY can never be isolated. */ mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &rlphy_funcs, 1); return (0); } static int rlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * The RealTek PHY's autonegotiation doesn't need to be * kicked; it continues in the background. */ break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void rlphy_status(struct mii_softc *phy) { struct mii_data *mii = phy->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr, anlpar; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(phy, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { /* * NWay autonegotiation takes the highest-order common * bit of the ANAR and ANLPAR (i.e. best media advertised * both by us and our link partner). */ if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if ((anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR))) { if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (anlpar & ANLPAR_T4) mii->mii_media_active |= IFM_100_T4|IFM_HDX; else if (anlpar & ANLPAR_TX) mii->mii_media_active |= IFM_100_TX|IFM_HDX; 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|IFM_HDX; else mii->mii_media_active |= IFM_NONE; if ((mii->mii_media_active & IFM_FDX) != 0) mii->mii_media_active |= mii_phy_flowstatus(phy); return; } /* * If the other side doesn't support NWAY, then the * best we can do is determine if we have a 10Mbps or * 100Mbps link. There's no way to know if the link * is full or half duplex, so we default to half duplex * and hope that the user is clever enough to manually * change the media settings if we're wrong. */ /* * The RealTek PHY supports non-NWAY link speed * detection, however it does not report the link * detection results via the ANLPAR or BMSR registers. * (What? RealTek doesn't do things the way everyone * else does? I'm just shocked, shocked I tell you.) * To determine the link speed, we have to do one * of two things: * * - If this is a standalone RealTek RTL8201(L) or * workalike PHY, we can determine the link speed by * testing bit 0 in the magic, vendor-specific register * at offset 0x19. * * - If this is a RealTek MAC with integrated PHY, we * can test the 'SPEED10' bit of the MAC's media status * register. */ if (!(phy->mii_mpd_model == 0 && phy->mii_mpd_rev == 0)) { if (PHY_READ(phy, 0x0019) & 0x01) mii->mii_media_active |= IFM_100_TX; else mii->mii_media_active |= IFM_10_T; } else { if (PHY_READ(phy, RL_MEDIASTAT) & RL_MEDIASTAT_SPEED10) mii->mii_media_active |= IFM_10_T; else mii->mii_media_active |= IFM_100_TX; } mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } Index: head/sys/dev/mii/rlswitch.c =================================================================== --- head/sys/dev/mii/rlswitch.c (revision 227907) +++ head/sys/dev/mii/rlswitch.c (revision 227908) @@ -1,401 +1,401 @@ /*- * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * Copyright (c) 2006 Bernd Walter. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * driver for RealTek 8305 pseudo PHYs */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include #include "miibus_if.h" //#define RL_DEBUG #define RL_VLAN static int rlswitch_probe(device_t); static int rlswitch_attach(device_t); static device_method_t rlswitch_methods[] = { /* device interface */ DEVMETHOD(device_probe, rlswitch_probe), DEVMETHOD(device_attach, rlswitch_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t rlswitch_devclass; static driver_t rlswitch_driver = { "rlswitch", rlswitch_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(rlswitch, miibus, rlswitch_driver, rlswitch_devclass, 0, 0); static int rlswitch_service(struct mii_softc *, struct mii_data *, int); static void rlswitch_status(struct mii_softc *); #ifdef RL_DEBUG static void rlswitch_phydump(device_t dev); #endif static const struct mii_phydesc rlswitches[] = { MII_PHY_DESC(REALTEK, RTL8305SC), MII_PHY_END }; static const struct mii_phy_funcs rlswitch_funcs = { rlswitch_service, rlswitch_status, mii_phy_reset }; static int rlswitch_probe(device_t dev) { int rv; rv = mii_phy_dev_probe(dev, rlswitches, BUS_PROBE_DEFAULT); if (rv <= 0) return (rv); return (ENXIO); } static int rlswitch_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); /* * We handle all pseudo PHYs in a single instance. */ mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &rlswitch_funcs, 0); sc->mii_capabilities = BMSR_100TXFDX & sc->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); #ifdef RL_DEBUG rlswitch_phydump(dev); #endif #ifdef RL_VLAN int val; /* Global Control 0 */ val = 0; val |= 0 << 10; /* enable 802.1q VLAN Tag support */ val |= 0 << 9; /* enable VLAN ingress filtering */ val |= 1 << 8; /* disable VLAN tag admit control */ val |= 1 << 6; /* internal use */ val |= 1 << 5; /* internal use */ val |= 1 << 4; /* internal use */ val |= 1 << 3; /* internal use */ val |= 1 << 1; /* reserved */ MIIBUS_WRITEREG(sc->mii_dev, 0, 16, val); /* Global Control 2 */ val = 0; val |= 1 << 15; /* reserved */ val |= 0 << 14; /* enable 1552 Bytes support */ val |= 1 << 13; /* enable broadcast input drop */ val |= 1 << 12; /* forward reserved control frames */ val |= 1 << 11; /* disable forwarding unicast frames to other VLAN's */ val |= 1 << 10; /* disable forwarding ARP broadcasts to other VLAN's */ val |= 1 << 9; /* enable 48 pass 1 */ val |= 0 << 8; /* enable VLAN */ val |= 1 << 7; /* reserved */ val |= 1 << 6; /* enable defer */ val |= 1 << 5; /* 43ms LED blink time */ val |= 3 << 3; /* 16:1 queue weight */ val |= 1 << 2; /* disable broadcast storm control */ val |= 1 << 1; /* enable power-on LED blinking */ val |= 1 << 0; /* reserved */ MIIBUS_WRITEREG(sc->mii_dev, 0, 18, val); /* Port 0 Control Register 0 */ val = 0; val |= 1 << 15; /* reserved */ val |= 1 << 11; /* drop received packets with wrong VLAN tag */ val |= 1 << 10; /* disable 802.1p priority classification */ val |= 1 << 9; /* disable diffserv priority classification */ val |= 1 << 6; /* internal use */ val |= 3 << 4; /* internal use */ val |= 1 << 3; /* internal use */ val |= 1 << 2; /* internal use */ val |= 1 << 0; /* remove VLAN tags on output */ MIIBUS_WRITEREG(sc->mii_dev, 0, 22, val); /* Port 1 Control Register 0 */ val = 0; val |= 1 << 15; /* reserved */ val |= 1 << 11; /* drop received packets with wrong VLAN tag */ val |= 1 << 10; /* disable 802.1p priority classification */ val |= 1 << 9; /* disable diffserv priority classification */ val |= 1 << 6; /* internal use */ val |= 3 << 4; /* internal use */ val |= 1 << 3; /* internal use */ val |= 1 << 2; /* internal use */ val |= 1 << 0; /* remove VLAN tags on output */ MIIBUS_WRITEREG(sc->mii_dev, 1, 22, val); /* Port 2 Control Register 0 */ val = 0; val |= 1 << 15; /* reserved */ val |= 1 << 11; /* drop received packets with wrong VLAN tag */ val |= 1 << 10; /* disable 802.1p priority classification */ val |= 1 << 9; /* disable diffserv priority classification */ val |= 1 << 6; /* internal use */ val |= 3 << 4; /* internal use */ val |= 1 << 3; /* internal use */ val |= 1 << 2; /* internal use */ val |= 1 << 0; /* remove VLAN tags on output */ MIIBUS_WRITEREG(sc->mii_dev, 2, 22, val); /* Port 3 Control Register 0 */ val = 0; val |= 1 << 15; /* reserved */ val |= 1 << 11; /* drop received packets with wrong VLAN tag */ val |= 1 << 10; /* disable 802.1p priority classification */ val |= 1 << 9; /* disable diffserv priority classification */ val |= 1 << 6; /* internal use */ val |= 3 << 4; /* internal use */ val |= 1 << 3; /* internal use */ val |= 1 << 2; /* internal use */ val |= 1 << 0; /* remove VLAN tags on output */ MIIBUS_WRITEREG(sc->mii_dev, 3, 22, val); /* Port 4 (system port) Control Register 0 */ val = 0; val |= 1 << 15; /* reserved */ val |= 0 << 11; /* don't drop received packets with wrong VLAN tag */ val |= 1 << 10; /* disable 802.1p priority classification */ val |= 1 << 9; /* disable diffserv priority classification */ val |= 1 << 6; /* internal use */ val |= 3 << 4; /* internal use */ val |= 1 << 3; /* internal use */ val |= 1 << 2; /* internal use */ val |= 2 << 0; /* add VLAN tags for untagged packets on output */ MIIBUS_WRITEREG(sc->mii_dev, 4, 22, val); /* Port 0 Control Register 1 and VLAN A */ val = 0; val |= 0x0 << 12; /* Port 0 VLAN Index */ val |= 1 << 11; /* internal use */ val |= 1 << 10; /* internal use */ val |= 1 << 9; /* internal use */ val |= 1 << 7; /* internal use */ val |= 1 << 6; /* internal use */ val |= 0x11 << 0; /* VLAN A membership */ MIIBUS_WRITEREG(sc->mii_dev, 0, 24, val); /* Port 0 Control Register 2 and VLAN A */ val = 0; val |= 1 << 15; /* internal use */ val |= 1 << 14; /* internal use */ val |= 1 << 13; /* internal use */ val |= 1 << 12; /* internal use */ val |= 0x100 << 0; /* VLAN A ID */ MIIBUS_WRITEREG(sc->mii_dev, 0, 25, val); /* Port 1 Control Register 1 and VLAN B */ val = 0; val |= 0x1 << 12; /* Port 1 VLAN Index */ val |= 1 << 11; /* internal use */ val |= 1 << 10; /* internal use */ val |= 1 << 9; /* internal use */ val |= 1 << 7; /* internal use */ val |= 1 << 6; /* internal use */ val |= 0x12 << 0; /* VLAN B membership */ MIIBUS_WRITEREG(sc->mii_dev, 1, 24, val); /* Port 1 Control Register 2 and VLAN B */ val = 0; val |= 1 << 15; /* internal use */ val |= 1 << 14; /* internal use */ val |= 1 << 13; /* internal use */ val |= 1 << 12; /* internal use */ val |= 0x101 << 0; /* VLAN B ID */ MIIBUS_WRITEREG(sc->mii_dev, 1, 25, val); /* Port 2 Control Register 1 and VLAN C */ val = 0; val |= 0x2 << 12; /* Port 2 VLAN Index */ val |= 1 << 11; /* internal use */ val |= 1 << 10; /* internal use */ val |= 1 << 9; /* internal use */ val |= 1 << 7; /* internal use */ val |= 1 << 6; /* internal use */ val |= 0x14 << 0; /* VLAN C membership */ MIIBUS_WRITEREG(sc->mii_dev, 2, 24, val); /* Port 2 Control Register 2 and VLAN C */ val = 0; val |= 1 << 15; /* internal use */ val |= 1 << 14; /* internal use */ val |= 1 << 13; /* internal use */ val |= 1 << 12; /* internal use */ val |= 0x102 << 0; /* VLAN C ID */ MIIBUS_WRITEREG(sc->mii_dev, 2, 25, val); /* Port 3 Control Register 1 and VLAN D */ val = 0; val |= 0x3 << 12; /* Port 3 VLAN Index */ val |= 1 << 11; /* internal use */ val |= 1 << 10; /* internal use */ val |= 1 << 9; /* internal use */ val |= 1 << 7; /* internal use */ val |= 1 << 6; /* internal use */ val |= 0x18 << 0; /* VLAN D membership */ MIIBUS_WRITEREG(sc->mii_dev, 3, 24, val); /* Port 3 Control Register 2 and VLAN D */ val = 0; val |= 1 << 15; /* internal use */ val |= 1 << 14; /* internal use */ val |= 1 << 13; /* internal use */ val |= 1 << 12; /* internal use */ val |= 0x103 << 0; /* VLAN D ID */ MIIBUS_WRITEREG(sc->mii_dev, 3, 25, val); /* Port 4 Control Register 1 and VLAN E */ val = 0; val |= 0x0 << 12; /* Port 4 VLAN Index */ val |= 1 << 11; /* internal use */ val |= 1 << 10; /* internal use */ val |= 1 << 9; /* internal use */ val |= 1 << 7; /* internal use */ val |= 1 << 6; /* internal use */ val |= 0 << 0; /* VLAN E membership */ MIIBUS_WRITEREG(sc->mii_dev, 4, 24, val); /* Port 4 Control Register 2 and VLAN E */ val = 0; val |= 1 << 15; /* internal use */ val |= 1 << 14; /* internal use */ val |= 1 << 13; /* internal use */ val |= 1 << 12; /* internal use */ val |= 0x104 << 0; /* VLAN E ID */ MIIBUS_WRITEREG(sc->mii_dev, 4, 25, val); #endif #ifdef RL_DEBUG rlswitch_phydump(dev); #endif MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int rlswitch_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ // mii_phy_update(sc, cmd); return (0); } static void rlswitch_status(struct mii_softc *phy) { struct mii_data *mii = phy->mii_pdata; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; mii->mii_media_status |= IFM_ACTIVE; mii->mii_media_active |= IFM_100_TX | IFM_FDX | mii_phy_flowstatus(phy); } #ifdef RL_DEBUG static void rlswitch_phydump(device_t dev) { int phy, reg, val; struct mii_softc *sc; sc = device_get_softc(dev); device_printf(dev, "rlswitchphydump\n"); for (phy = 0; phy <= 5; phy++) { printf("PHY%i:", phy); for (reg = 0; reg <= 31; reg++) { val = MIIBUS_READREG(sc->mii_dev, phy, reg); printf(" 0x%x", val); } printf("\n"); } } #endif Index: head/sys/dev/mii/smcphy.c =================================================================== --- head/sys/dev/mii/smcphy.c (revision 227907) +++ head/sys/dev/mii/smcphy.c (revision 227908) @@ -1,218 +1,216 @@ /*- * Copyright (c) 2006 Benno Rice. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Driver for the internal PHY on the SMSC LAN91C111. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include "miibus_if.h" static int smcphy_probe(device_t); static int smcphy_attach(device_t); static int smcphy_service(struct mii_softc *, struct mii_data *, int); static void smcphy_reset(struct mii_softc *); static void smcphy_auto(struct mii_softc *, int); static device_method_t smcphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, smcphy_probe), DEVMETHOD(device_attach, smcphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - - { 0, 0 } + DEVMETHOD_END }; static devclass_t smcphy_devclass; static driver_t smcphy_driver = { "smcphy", smcphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(smcphy, miibus, smcphy_driver, smcphy_devclass, 0, 0); static const struct mii_phydesc smcphys[] = { MII_PHY_DESC(SEEQ, 84220), MII_PHY_END }; static const struct mii_phy_funcs smcphy_funcs = { smcphy_service, ukphy_status, smcphy_reset }; static int smcphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, smcphys, BUS_PROBE_DEFAULT)); } static int smcphy_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &smcphy_funcs, 1); mii_phy_setmedia(sc); return (0); } static int smcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife; int reg; ife = mii->mii_media.ifm_cur; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: smcphy_auto(sc, ife->ifm_media); break; default: mii_phy_setmedia(sc); break; } break; case MII_TICK: if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { return (0); } if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { break; } /* I have no idea why BMCR_ISO gets set. */ reg = PHY_READ(sc, MII_BMCR); if (reg & BMCR_ISO) { PHY_WRITE(sc, MII_BMCR, reg & ~BMCR_ISO); } reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) { sc->mii_ticks = 0; break; } if (++sc->mii_ticks <= MII_ANEGTICKS) { break; } sc->mii_ticks = 0; PHY_RESET(sc); smcphy_auto(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void smcphy_reset(struct mii_softc *sc) { u_int bmcr; int timeout; PHY_WRITE(sc, MII_BMCR, BMCR_RESET); for (timeout = 2; timeout > 0; timeout--) { DELAY(50000); bmcr = PHY_READ(sc, MII_BMCR); if ((bmcr & BMCR_RESET) == 0) break; } if (bmcr & BMCR_RESET) device_printf(sc->mii_dev, "reset failed\n"); PHY_WRITE(sc, MII_BMCR, 0x3000); /* Mask interrupts, we poll instead. */ PHY_WRITE(sc, 0x1e, 0xffc0); } static void smcphy_auto(struct mii_softc *sc, int media) { uint16_t anar; - anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | - ANAR_CSMA; + anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= ANAR_FC; PHY_WRITE(sc, MII_ANAR, anar); /* Apparently this helps. */ anar = PHY_READ(sc, MII_ANAR); PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); } Index: head/sys/dev/mii/tdkphy.c =================================================================== --- head/sys/dev/mii/tdkphy.c (revision 227907) +++ head/sys/dev/mii/tdkphy.c (revision 227908) @@ -1,229 +1,229 @@ /*- * Copyright (c) 2000,2001 Jonathan Chen. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Driver for the TDK 78Q2120 MII * * References: * Datasheet for the 78Q2120 - http://www.tsc.tdk.com/lan/78q2120.pdf * Most of this code stolen from ukphy.c */ /* * The TDK 78Q2120 is found on some Xircom X3201 based CardBus cards, * also spotted on some 3C575 cards. It's just like any other normal * phy, except it does auto negotiation in a different way. */ #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int tdkphy_probe(device_t); static int tdkphy_attach(device_t); static device_method_t tdkphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, tdkphy_probe), DEVMETHOD(device_attach, tdkphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t tdkphy_devclass; static driver_t tdkphy_driver = { "tdkphy", tdkphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(tdkphy, miibus, tdkphy_driver, tdkphy_devclass, 0, 0); static int tdkphy_service(struct mii_softc *, struct mii_data *, int); static void tdkphy_status(struct mii_softc *); static const struct mii_phydesc tdkphys[] = { MII_PHY_DESC(xxTSC, 78Q2120), MII_PHY_END }; static const struct mii_phy_funcs tdkphy_funcs = { tdkphy_service, tdkphy_status, mii_phy_reset }; static int tdkphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, tdkphys, BUS_PROBE_DEFAULT)); } static int tdkphy_attach(device_t dev) { mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &tdkphy_funcs, 1); return (0); } static int tdkphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); if (sc->mii_pdata->mii_media_active & IFM_FDX) PHY_WRITE(sc, MII_BMCR, PHY_READ(sc, MII_BMCR) | BMCR_FDX); else PHY_WRITE(sc, MII_BMCR, PHY_READ(sc, MII_BMCR) & ~BMCR_FDX); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void tdkphy_status(struct mii_softc *phy) { struct mii_data *mii = phy->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr, anlpar, diag; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(phy, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & BMCR_AUTOEN) { /* * NWay autonegotiation takes the highest-order common * bit of the ANAR and ANLPAR (i.e. best media advertised * both by us and our link partner). */ if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR); /* * ANLPAR doesn't get set on my card, but we check it anyway, * since it is mentioned in the 78Q2120 specs. */ if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (anlpar & ANLPAR_T4) mii->mii_media_active |= IFM_100_T4|IFM_HDX; else if (anlpar & ANLPAR_TX) mii->mii_media_active |= IFM_100_TX|IFM_HDX; 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|IFM_HDX; else { /* * ANLPAR isn't set, which leaves two possibilities: * 1) Auto negotiation failed * 2) Auto negotiation completed, but the card forgot * to set ANLPAR. * So we check the MII_DIAG(18) register... */ diag = PHY_READ(phy, MII_DIAG); if (diag & DIAG_NEGFAIL) /* assume 10baseT if no neg */ mii->mii_media_active |= IFM_10_T|IFM_HDX; else { if (diag & DIAG_DUPLEX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; if (diag & DIAG_RATE_100) mii->mii_media_active |= IFM_100_TX; else mii->mii_media_active |= IFM_10_T; } } if ((mii->mii_media_active & IFM_FDX) != 0) mii->mii_media_active |= mii_phy_flowstatus(phy); } else mii->mii_media_active = ife->ifm_media; } Index: head/sys/dev/mii/tlphy.c =================================================================== --- head/sys/dev/mii/tlphy.c (revision 227907) +++ head/sys/dev/mii/tlphy.c (revision 227908) @@ -1,387 +1,387 @@ /* $NetBSD: tlphy.c,v 1.18 1999/05/14 11:40:28 drochner Exp $ */ /*- * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Driver for Texas Instruments's ThunderLAN PHYs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" struct tlphy_softc { struct mii_softc sc_mii; /* generic PHY */ int sc_need_acomp; }; static int tlphy_probe(device_t); static int tlphy_attach(device_t); static device_method_t tlphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, tlphy_probe), DEVMETHOD(device_attach, tlphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t tlphy_devclass; static driver_t tlphy_driver = { "tlphy", tlphy_methods, sizeof(struct tlphy_softc) }; DRIVER_MODULE(tlphy, miibus, tlphy_driver, tlphy_devclass, 0, 0); static int tlphy_service(struct mii_softc *, struct mii_data *, int); static int tlphy_auto(struct tlphy_softc *); static void tlphy_acomp(struct tlphy_softc *); static void tlphy_status(struct mii_softc *); static const struct mii_phydesc tlphys[] = { MII_PHY_DESC(TI, TLAN10T), MII_PHY_END }; static const struct mii_phy_funcs tlphy_funcs = { tlphy_service, tlphy_status, mii_phy_reset }; static int tlphy_probe(device_t dev) { if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), "tl") != 0) return (ENXIO); return (mii_phy_dev_probe(dev, tlphys, BUS_PROBE_DEFAULT)); } static int tlphy_attach(device_t dev) { device_t *devlist; struct mii_softc *other, *sc_mii; const char *sep = ""; int capmask, devs, i; sc_mii = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &tlphy_funcs, 0); /* * Note that if we're on a device that also supports 100baseTX, * we are not going to want to use the built-in 10baseT port, * since there will be another PHY on the MII wired up to the * UTP connector. */ capmask = BMSR_DEFCAPMASK; if (sc_mii->mii_inst && device_get_children(sc_mii->mii_dev, &devlist, &devs) == 0) { for (i = 0; i < devs; i++) { if (devlist[i] != dev) { other = device_get_softc(devlist[i]); capmask &= ~other->mii_capabilities; break; } } free(devlist, M_TEMP); } PHY_RESET(sc_mii); sc_mii->mii_capabilities = PHY_READ(sc_mii, MII_BMSR) & capmask; #define ADD(m, c) \ ifmedia_add(&sc_mii->mii_pdata->mii_media, (m), (c), NULL) #define PRINT(s) printf("%s%s", sep, s); sep = ", " if ((sc_mii->mii_flags & (MIIF_MACPRIV0 | MIIF_MACPRIV1)) != 0 && (sc_mii->mii_capabilities & BMSR_MEDIAMASK) != 0) device_printf(dev, " "); if ((sc_mii->mii_flags & MIIF_MACPRIV0) != 0) { ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc_mii->mii_inst), 0); PRINT("10base2/BNC"); } if ((sc_mii->mii_flags & MIIF_MACPRIV1) != 0) { ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, sc_mii->mii_inst), 0); PRINT("10base5/AUI"); } if ((sc_mii->mii_capabilities & BMSR_MEDIAMASK) != 0) { printf("%s", sep); mii_phy_add_media(sc_mii); } if ((sc_mii->mii_flags & (MIIF_MACPRIV0 | MIIF_MACPRIV1)) != 0 && (sc_mii->mii_capabilities & BMSR_MEDIAMASK) != 0) printf("\n"); #undef ADD #undef PRINT MIIBUS_MEDIAINIT(sc_mii->mii_dev); return (0); } static int tlphy_service(struct mii_softc *self, struct mii_data *mii, int cmd) { struct tlphy_softc *sc = (struct tlphy_softc *)self; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; if (sc->sc_need_acomp) tlphy_acomp(sc); switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: /* * The ThunderLAN PHY doesn't self-configure after * an autonegotiation cycle, so there's no such * thing as "already in auto mode". */ (void)tlphy_auto(sc); break; case IFM_10_2: case IFM_10_5: PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL); DELAY(100000); break; default: PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0); DELAY(100000); mii_phy_setmedia(&sc->sc_mii); } break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) break; /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. Read * the BMSR twice in case it's latched. * * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?! */ reg = PHY_READ(&sc->sc_mii, MII_BMSR) | PHY_READ(&sc->sc_mii, MII_BMSR); if (reg & BMSR_LINK) break; /* * Only retry autonegotiation every 5 seconds. */ if (++sc->sc_mii.mii_ticks <= MII_ANEGTICKS) break; sc->sc_mii.mii_ticks = 0; PHY_RESET(&sc->sc_mii); (void)tlphy_auto(sc); return (0); } /* Update the media status. */ PHY_STATUS(self); /* Callback if something changed. */ mii_phy_update(&sc->sc_mii, cmd); return (0); } static void tlphy_status(struct mii_softc *self) { struct tlphy_softc *sc = (struct tlphy_softc *)self; struct mii_data *mii = sc->sc_mii.mii_pdata; int bmsr, bmcr, tlctrl; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmcr = PHY_READ(&sc->sc_mii, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } tlctrl = PHY_READ(&sc->sc_mii, MII_TLPHY_CTRL); if (tlctrl & CTRL_AUISEL) { mii->mii_media_status = 0; mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media; return; } bmsr = PHY_READ(&sc->sc_mii, MII_BMSR) | PHY_READ(&sc->sc_mii, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; if (bmcr & BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; /* * Grr, braindead ThunderLAN PHY doesn't have any way to * tell which media is actually active. (Note it also * doesn't self-configure after autonegotiation.) We * just have to report what's in the BMCR. */ if (bmcr & BMCR_FDX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(self); else mii->mii_media_active |= IFM_HDX; mii->mii_media_active |= IFM_10_T; } static int tlphy_auto(struct tlphy_softc *sc) { int error; switch ((error = mii_phy_auto(&sc->sc_mii))) { case EIO: /* * Just assume we're not in full-duplex mode. * XXX Check link and try AUI/BNC? */ PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); break; case EJUSTRETURN: /* Flag that we need to program when it completes. */ sc->sc_need_acomp = 1; break; default: tlphy_acomp(sc); } return (error); } static void tlphy_acomp(struct tlphy_softc *sc) { int aner, anlpar; sc->sc_need_acomp = 0; /* * Grr, braindead ThunderLAN PHY doesn't self-configure * after autonegotiation. We have to do it ourselves * based on the link partner status. */ aner = PHY_READ(&sc->sc_mii, MII_ANER); if (aner & ANER_LPAN) { anlpar = PHY_READ(&sc->sc_mii, MII_ANLPAR) & PHY_READ(&sc->sc_mii, MII_ANAR); if (anlpar & ANAR_10_FD) { PHY_WRITE(&sc->sc_mii, MII_BMCR, BMCR_FDX); return; } } PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); } Index: head/sys/dev/mii/truephy.c =================================================================== --- head/sys/dev/mii/truephy.c (revision 227907) +++ head/sys/dev/mii/truephy.c (revision 227908) @@ -1,327 +1,327 @@ /*- * Copyright (c) 2007 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Sepherosa Ziehau * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name of The DragonFly Project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific, prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $DragonFly: src/sys/dev/netif/mii_layer/truephy.c,v 1.3 2008/02/10 07:29:27 sephe Exp $ * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" #define TRUEPHY_FRAMELEN(mtu) \ (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + (mtu) + ETHER_CRC_LEN) static int truephy_service(struct mii_softc *, struct mii_data *, int); static int truephy_attach(device_t); static int truephy_probe(device_t); static void truephy_reset(struct mii_softc *); static void truephy_status(struct mii_softc *); static device_method_t truephy_methods[] = { /* device interface */ DEVMETHOD(device_probe, truephy_probe), DEVMETHOD(device_attach, truephy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static const struct mii_phydesc truephys[] = { MII_PHY_DESC(AGERE, ET1011), MII_PHY_DESC(AGERE, ET1011C), MII_PHY_END }; static devclass_t truephy_devclass; static driver_t truephy_driver = { "truephy", truephy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(truephy, miibus, truephy_driver, truephy_devclass, 0, 0); static const struct mii_phy_funcs truephy_funcs = { truephy_service, truephy_status, truephy_reset }; static const struct truephy_dsp { uint16_t index; uint16_t data; } truephy_dspcode[] = { { 0x880b, 0x0926 }, /* AfeIfCreg4B1000Msbs */ { 0x880c, 0x0926 }, /* AfeIfCreg4B100Msbs */ { 0x880d, 0x0926 }, /* AfeIfCreg4B10Msbs */ { 0x880e, 0xb4d3 }, /* AfeIfCreg4B1000Lsbs */ { 0x880f, 0xb4d3 }, /* AfeIfCreg4B100Lsbs */ { 0x8810, 0xb4d3 }, /* AfeIfCreg4B10Lsbs */ { 0x8805, 0xb03e }, /* AfeIfCreg3B1000Msbs */ { 0x8806, 0xb03e }, /* AfeIfCreg3B100Msbs */ { 0x8807, 0xff00 }, /* AfeIfCreg3B10Msbs */ { 0x8808, 0xe090 }, /* AfeIfCreg3B1000Lsbs */ { 0x8809, 0xe110 }, /* AfeIfCreg3B100Lsbs */ { 0x880a, 0x0000 }, /* AfeIfCreg3B10Lsbs */ { 0x300d, 1 }, /* DisableNorm */ { 0x280c, 0x0180 }, /* LinkHoldEnd */ { 0x1c21, 0x0002 }, /* AlphaM */ { 0x3821, 6 }, /* FfeLkgTx0 */ { 0x381d, 1 }, /* FfeLkg1g4 */ { 0x381e, 1 }, /* FfeLkg1g5 */ { 0x381f, 1 }, /* FfeLkg1g6 */ { 0x3820, 1 }, /* FfeLkg1g7 */ { 0x8402, 0x01f0 }, /* Btinact */ { 0x800e, 20 }, /* LftrainTime */ { 0x800f, 24 }, /* DvguardTime */ { 0x8010, 46 } /* IdlguardTime */ }; static int truephy_probe(device_t dev) { return (mii_phy_dev_probe(dev, truephys, BUS_PROBE_DEFAULT)); } static int truephy_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &truephy_funcs, 0); PHY_RESET(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) { sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); /* No 1000baseT half-duplex support */ sc->mii_extcapabilities &= ~EXTSR_1000THDX; } device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int truephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmcr; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { bmcr = PHY_READ(sc, MII_BMCR) & ~BMCR_AUTOEN; PHY_WRITE(sc, MII_BMCR, bmcr); PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_PDOWN); } mii_phy_setmedia(sc); if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { bmcr = PHY_READ(sc, MII_BMCR) & ~BMCR_PDOWN; PHY_WRITE(sc, MII_BMCR, bmcr); if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_AUTOEN | BMCR_STARTNEG); } } break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void truephy_reset(struct mii_softc *sc) { int i; if (sc->mii_mpd_model == MII_MODEL_AGERE_ET1011) { mii_phy_reset(sc); return; } for (i = 0; i < 2; ++i) { PHY_READ(sc, MII_PHYIDR1); PHY_READ(sc, MII_PHYIDR2); PHY_READ(sc, TRUEPHY_CTRL); PHY_WRITE(sc, TRUEPHY_CTRL, TRUEPHY_CTRL_DIAG | TRUEPHY_CTRL_RSV1); PHY_WRITE(sc, TRUEPHY_INDEX, TRUEPHY_INDEX_MAGIC); PHY_READ(sc, TRUEPHY_DATA); PHY_WRITE(sc, TRUEPHY_CTRL, TRUEPHY_CTRL_RSV1); } PHY_READ(sc, MII_BMCR); PHY_READ(sc, TRUEPHY_CTRL); PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_PDOWN | BMCR_S1000); PHY_WRITE(sc, TRUEPHY_CTRL, TRUEPHY_CTRL_DIAG | TRUEPHY_CTRL_RSV1 | TRUEPHY_CTRL_RSV0); #define N(arr) (int)(sizeof(arr) / sizeof(arr[0])) for (i = 0; i < N(truephy_dspcode); ++i) { const struct truephy_dsp *dsp = &truephy_dspcode[i]; PHY_WRITE(sc, TRUEPHY_INDEX, dsp->index); PHY_WRITE(sc, TRUEPHY_DATA, dsp->data); PHY_WRITE(sc, TRUEPHY_INDEX, dsp->index); PHY_READ(sc, TRUEPHY_DATA); } #undef N PHY_READ(sc, MII_BMCR); PHY_READ(sc, TRUEPHY_CTRL); PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_S1000); PHY_WRITE(sc, TRUEPHY_CTRL, TRUEPHY_CTRL_RSV1); mii_phy_reset(sc); if (TRUEPHY_FRAMELEN(sc->mii_pdata->mii_ifp->if_mtu) > 2048) { int conf; conf = PHY_READ(sc, TRUEPHY_CONF); conf &= ~TRUEPHY_CONF_TXFIFO_MASK; conf |= TRUEPHY_CONF_TXFIFO_24; PHY_WRITE(sc, TRUEPHY_CONF, conf); } } static void truephy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; int bmsr, bmcr, sr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; sr = PHY_READ(sc, TRUEPHY_SR); bmcr = PHY_READ(sc, MII_BMCR); bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; if (bmcr & BMCR_AUTOEN) { if ((bmsr & BMSR_ACOMP) == 0) { mii->mii_media_active |= IFM_NONE; return; } } switch (sr & TRUEPHY_SR_SPD_MASK) { case TRUEPHY_SR_SPD_1000T: mii->mii_media_active |= IFM_1000_T; break; case TRUEPHY_SR_SPD_100TX: mii->mii_media_active |= IFM_100_TX; break; case TRUEPHY_SR_SPD_10T: mii->mii_media_active |= IFM_10_T; break; default: /* XXX will this ever happen? */ printf("invalid media SR %#x\n", sr); mii->mii_media_active |= IFM_NONE; return; } if (sr & TRUEPHY_SR_FDX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } Index: head/sys/dev/mii/ukphy.c =================================================================== --- head/sys/dev/mii/ukphy.c (revision 227907) +++ head/sys/dev/mii/ukphy.c (revision 227908) @@ -1,164 +1,164 @@ /* $NetBSD: ukphy.c,v 1.2 1999/04/23 04:24:32 thorpej Exp $ */ /*- * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center, and by Frank van der Linden. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * driver for generic unknown PHYs */ #include #include #include #include #include #include #include #include #include #include #include #include "miibus_if.h" static int ukphy_probe(device_t); static int ukphy_attach(device_t); static device_method_t ukphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, ukphy_probe), DEVMETHOD(device_attach, ukphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t ukphy_devclass; static driver_t ukphy_driver = { "ukphy", ukphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(ukphy, miibus, ukphy_driver, ukphy_devclass, 0, 0); static int ukphy_service(struct mii_softc *, struct mii_data *, int); static const struct mii_phy_funcs ukphy_funcs = { ukphy_service, ukphy_status, mii_phy_reset }; static int ukphy_probe(device_t dev) { /* * We know something is here, so always match at a low priority. */ device_set_desc(dev, "Generic IEEE 802.3u media interface"); return (BUS_PROBE_GENERIC); } static int ukphy_attach(device_t dev) { struct mii_softc *sc; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &ukphy_funcs, 1); mii_phy_setmedia(sc); return (0); } static int ukphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } Index: head/sys/dev/mii/xmphy.c =================================================================== --- head/sys/dev/mii/xmphy.c (revision 227907) +++ head/sys/dev/mii/xmphy.c (revision 227908) @@ -1,287 +1,287 @@ /*- * Copyright (c) 2000 * 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. */ #include __FBSDID("$FreeBSD$"); /* * driver for the XaQti XMAC II's internal PHY. This is sort of * like a 10/100 PHY, except the only thing we're really autoselecting * here is full/half duplex. Speed is always 1000mbps. */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int xmphy_probe(device_t); static int xmphy_attach(device_t); static device_method_t xmphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, xmphy_probe), DEVMETHOD(device_attach, xmphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t xmphy_devclass; static driver_t xmphy_driver = { "xmphy", xmphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(xmphy, miibus, xmphy_driver, xmphy_devclass, 0, 0); static int xmphy_service(struct mii_softc *, struct mii_data *, int); static void xmphy_status(struct mii_softc *); static int xmphy_mii_phy_auto(struct mii_softc *); static const struct mii_phydesc xmphys[] = { MII_PHY_DESC(xxJATO, BASEX), MII_PHY_DESC(xxXAQTI, XMACII), MII_PHY_END }; static const struct mii_phy_funcs xmphy_funcs = { xmphy_service, xmphy_status, mii_phy_reset }; static int xmphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, xmphys, BUS_PROBE_DEFAULT)); } static int xmphy_attach(device_t dev) { struct mii_softc *sc; const char *sep = ""; sc = device_get_softc(dev); mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &xmphy_funcs, 0); sc->mii_anegticks = MII_ANEGTICKS; PHY_RESET(sc); #define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL) #define PRINT(s) printf("%s%s", sep, s); sep = ", " device_printf(dev, " "); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst), XMPHY_BMCR_FDX); PRINT("1000baseSX"); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 0); PRINT("1000baseSX-FDX"); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); PRINT("auto"); printf("\n"); #undef ADD #undef PRINT MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int xmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: #ifdef foo /* * If we're already in auto mode, just return. */ if (PHY_READ(sc, XMPHY_MII_BMCR) & XMPHY_BMCR_AUTOEN) return (0); #endif (void)xmphy_mii_phy_auto(sc); break; case IFM_1000_SX: PHY_RESET(sc); if ((ife->ifm_media & IFM_FDX) != 0) { PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_FDX); PHY_WRITE(sc, XMPHY_MII_BMCR, XMPHY_BMCR_FDX); } else { PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_HDX); PHY_WRITE(sc, XMPHY_MII_BMCR, 0); } break; default: return (EINVAL); } break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) break; /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. Read * the BMSR twice in case it's latched. */ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) break; /* Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; PHY_RESET(sc); xmphy_mii_phy_auto(sc); return (0); } /* Update the media status. */ xmphy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void xmphy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; int bmsr, bmcr, anlpar; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, XMPHY_MII_BMSR) | PHY_READ(sc, XMPHY_MII_BMSR); if (bmsr & XMPHY_BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; /* Do dummy read of extended status register. */ bmcr = PHY_READ(sc, XMPHY_MII_EXTSTS); bmcr = PHY_READ(sc, XMPHY_MII_BMCR); if (bmcr & XMPHY_BMCR_LOOP) mii->mii_media_active |= IFM_LOOP; if (bmcr & XMPHY_BMCR_AUTOEN) { if ((bmsr & XMPHY_BMSR_ACOMP) == 0) { if (bmsr & XMPHY_BMSR_LINK) { mii->mii_media_active |= IFM_1000_SX|IFM_HDX; return; } /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } mii->mii_media_active |= IFM_1000_SX; anlpar = PHY_READ(sc, XMPHY_MII_ANAR) & PHY_READ(sc, XMPHY_MII_ANLPAR); if (anlpar & XMPHY_ANLPAR_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; return; } mii->mii_media_active |= IFM_1000_SX; if (bmcr & XMPHY_BMCR_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } static int xmphy_mii_phy_auto(struct mii_softc *mii) { int anar = 0; anar = PHY_READ(mii, XMPHY_MII_ANAR); anar |= XMPHY_ANAR_FDX|XMPHY_ANAR_HDX; PHY_WRITE(mii, XMPHY_MII_ANAR, anar); DELAY(1000); PHY_WRITE(mii, XMPHY_MII_BMCR, XMPHY_BMCR_AUTOEN | XMPHY_BMCR_STARTNEG); return (EJUSTRETURN); } Index: head/sys/dev/usb/net/ruephy.c =================================================================== --- head/sys/dev/usb/net/ruephy.c (revision 227907) +++ head/sys/dev/usb/net/ruephy.c (revision 227908) @@ -1,232 +1,232 @@ /*- * Copyright (c) 2001-2003, Shunsuke Akiyama . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); /* * driver for RealTek RTL8150 internal PHY */ #include #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" static int ruephy_probe(device_t); static int ruephy_attach(device_t); static device_method_t ruephy_methods[] = { /* device interface */ DEVMETHOD(device_probe, ruephy_probe), DEVMETHOD(device_attach, ruephy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t ruephy_devclass; static driver_t ruephy_driver = { "ruephy", ruephy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(ruephy, miibus, ruephy_driver, ruephy_devclass, 0, 0); static int ruephy_service(struct mii_softc *, struct mii_data *, int); static void ruephy_reset(struct mii_softc *); static void ruephy_status(struct mii_softc *); /* * The RealTek RTL8150 internal PHY doesn't have vendor/device ID * registers; rue(4) fakes up a return value of all zeros. */ static const struct mii_phydesc ruephys[] = { { 0, 0, "RealTek RTL8150 internal media interface" }, MII_PHY_END }; static const struct mii_phy_funcs ruephy_funcs = { ruephy_service, ruephy_status, ruephy_reset }; static int ruephy_probe(device_t dev) { if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), "rue") == 0) return (mii_phy_dev_probe(dev, ruephys, BUS_PROBE_DEFAULT)); return (ENXIO); } static int ruephy_attach(device_t dev) { mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &ruephy_funcs, 1); return (0); } static int ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) break; /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. Read * the MSR twice in case it's latched. */ reg = PHY_READ(sc, RUEPHY_MII_MSR) | PHY_READ(sc, RUEPHY_MII_MSR); if (reg & RUEPHY_MSR_LINK) break; /* Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; PHY_RESET(sc); if (mii_phy_auto(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void ruephy_reset(struct mii_softc *sc) { mii_phy_reset(sc); /* * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after * XXX reset, which breaks autonegotiation. */ PHY_WRITE(sc, MII_BMCR, (BMCR_S100 | BMCR_AUTOEN | BMCR_FDX)); } static void ruephy_status(struct mii_softc *phy) { struct mii_data *mii = phy->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int bmsr, bmcr, msr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; msr = PHY_READ(phy, RUEPHY_MII_MSR) | PHY_READ(phy, RUEPHY_MII_MSR); if (msr & RUEPHY_MSR_LINK) mii->mii_media_status |= IFM_ACTIVE; bmcr = PHY_READ(phy, MII_BMCR); if (bmcr & BMCR_ISO) { mii->mii_media_active |= IFM_NONE; mii->mii_media_status = 0; return; } bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); if (bmcr & BMCR_AUTOEN) { if ((bmsr & BMSR_ACOMP) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if (msr & RUEPHY_MSR_SPEED100) mii->mii_media_active |= IFM_100_TX; else mii->mii_media_active |= IFM_10_T; if (msr & RUEPHY_MSR_DUPLEX) mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(phy); else mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } Index: head/sys/dev/xl/xlphy.c =================================================================== --- head/sys/dev/xl/xlphy.c (revision 227907) +++ head/sys/dev/xl/xlphy.c (revision 227908) @@ -1,197 +1,197 @@ /* $NetBSD: exphy.c,v 1.16 1999/04/23 04:24:32 thorpej Exp $ */ /*- * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center, and by Frank van der Linden. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * driver for 3Com internal PHYs */ #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include "miibus_if.h" static int xlphy_probe(device_t); static int xlphy_attach(device_t); static device_method_t xlphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, xlphy_probe), DEVMETHOD(device_attach, xlphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - { 0, 0 } + DEVMETHOD_END }; static devclass_t xlphy_devclass; static driver_t xlphy_driver = { "xlphy", xlphy_methods, sizeof(struct mii_softc) }; DRIVER_MODULE(xlphy, miibus, xlphy_driver, xlphy_devclass, 0, 0); static int xlphy_service(struct mii_softc *, struct mii_data *, int); static void xlphy_reset(struct mii_softc *); /* * Some 3Com internal PHYs report zero for OUI and model, others use * actual values. * Note that the 3Com internal PHYs having OUI 0x105a and model 0 are * handled fine by ukphy(4); they can be isolated and don't require * special treatment after reset. */ static const struct mii_phydesc xlphys[] = { { 0, 0, "3Com internal media interface" }, MII_PHY_DESC(xxBROADCOM, 3C905C), MII_PHY_END }; static const struct mii_phy_funcs xlphy_funcs = { xlphy_service, ukphy_status, xlphy_reset }; static int xlphy_probe(device_t dev) { if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), "xl") == 0) return (mii_phy_dev_probe(dev, xlphys, BUS_PROBE_DEFAULT)); return (ENXIO); } static int xlphy_attach(device_t dev) { /* * The 3Com PHY can never be isolated. */ mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &xlphy_funcs, 1); return (0); } static int xlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * The 3Com PHY's autonegotiation doesn't need to be * kicked; it continues in the background. */ break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); } static void xlphy_reset(struct mii_softc *sc) { mii_phy_reset(sc); /* * XXX 3Com PHY doesn't set the BMCR properly after * XXX reset, which breaks autonegotiation. */ PHY_WRITE(sc, MII_BMCR, BMCR_S100|BMCR_AUTOEN|BMCR_FDX); }