From e1c80d2dbf2960afcc89fef482e8d30540854ddf Mon Sep 17 00:00:00 2001 From: msaitoh Date: Mon, 22 May 2023 02:12:13 +0000 Subject: [PATCH] Fix a bug when a media is changed to IFM_AUTO. Fix a bug that ifconfig ifN media auto doesn't change the setting when the previous media setting used autonego. When the mii_phy_setmedia() function is called to change the media to IFM_AUTO, the BMCR_AUTOEN bit was used to check if the previous setting was IFM_AUTO. It's not correct. IFM_1000_T also uses autonego. So if a previous setting is IFM_1000_T and the next setting is IFM_AUTO, mii_phy_auto() is not called if neither MIIF_FORCEANEG nor MIIF_DOPAUSE are set. As a result, after changing IFM_AUTO, neither 10Mbps nor 100Mbps are not advertised. Note that almost all drivers uses MIIF_DOPAUSE flags. TODO: cleanup ciphy.c and rgephy.c. Those have #ifdef foo. --- sys/dev/mii/mii_physubr.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c index 125a3aa1a96f..01d55c71ffab 100644 --- a/sys/dev/mii/mii_physubr.c +++ b/sys/dev/mii/mii_physubr.c @@ -1,4 +1,4 @@ -/* $NetBSD: mii_physubr.c,v 1.102 2023/02/22 08:09:09 msaitoh Exp $ */ +/* $NetBSD: mii_physubr.c,v 1.103 2023/05/22 02:12:13 msaitoh Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: mii_physubr.c,v 1.102 2023/02/22 08:09:09 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mii_physubr.c,v 1.103 2023/05/22 02:12:13 msaitoh Exp $"); #include #include @@ -138,22 +138,14 @@ mii_phy_setmedia(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + u_int subtype; uint16_t bmcr, anar, gtcr; KASSERT(mii_locked(mii)); - if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { - /* - * Force renegotiation if MIIF_DOPAUSE. - * - * XXX This is only necessary because many NICs don't - * XXX advertise PAUSE capabilities at boot time. Maybe - * XXX we should force this only once? - */ - PHY_READ(sc, MII_BMCR, &bmcr); - if ((bmcr & BMCR_AUTOEN) == 0 || - (sc->mii_flags & (MIIF_FORCEANEG | MIIF_DOPAUSE))) - (void) mii_phy_auto(sc); + subtype = IFM_SUBTYPE(ife->ifm_media); + if ((subtype == IFM_AUTO) || (subtype == IFM_1000_T)) { + (void) mii_phy_auto(sc); return; } @@ -169,7 +161,7 @@ mii_phy_setmedia(struct mii_softc *sc) gtcr = mii_media_table[ife->ifm_data].mm_gtcr; if (mii->mii_media.ifm_media & IFM_ETH_MASTER) { - switch (IFM_SUBTYPE(ife->ifm_media)) { + switch (subtype) { case IFM_1000_T: gtcr |= GTCR_MAN_MS | GTCR_ADV_MS; break; @@ -198,10 +190,7 @@ mii_phy_setmedia(struct mii_softc *sc) PHY_WRITE(sc, MII_ANAR, anar); if (sc->mii_flags & MIIF_HAVE_GTCR) PHY_WRITE(sc, MII_100T2CR, gtcr); - if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) - mii_phy_auto(sc); - else - PHY_WRITE(sc, MII_BMCR, bmcr); + PHY_WRITE(sc, MII_BMCR, bmcr); } /* Setup autonegotiation and start it. */