From fed3ed710d31106da7f18384946d5a2ad42a2f77 Mon Sep 17 00:00:00 2001
From: Pyun YongHyeon <yongari@FreeBSD.org>
Date: Tue, 28 Feb 2012 05:23:29 +0000
Subject: [PATCH] Prefer RL_GMEDIASTAT register to RGEPHY_MII_SSR register to
 extract a link status of PHY when parent driver is re(4). RGEPHY_MII_SSR
 register does not seem to report correct PHY status on some integrated PHYs
 used with re(4). Unfortunately, RealTek PHYs have no additional information
 to differentiate integrated PHYs from external ones so relying on PHY model
 number is not enough to know that.  However, it seems RGEPHY_MII_SSR register
 exists for external RealTek PHYs so checking parent driver would be good
 indication to know which PHY was used. In other words, for non-re(4)
 controllers, the PHY is external one and its revision number is greater than
 or equal to 2. This change fixes intermittent link UP/DOWN messages reported
 on RTL8169 controller.

Also, mii_attach(9) is tried after setting interface name since
rgephy(4) have to know parent driver name.

PR:	kern/165509
---
 sys/dev/mii/rgephy.c | 18 ++++++++++++------
 sys/dev/re/if_re.c   | 26 +++++++++++++-------------
 2 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c
index d5dbbc82f6bc..aadc6fd9676a 100644
--- a/sys/dev/mii/rgephy.c
+++ b/sys/dev/mii/rgephy.c
@@ -110,10 +110,15 @@ static int
 rgephy_attach(device_t dev)
 {
 	struct mii_softc *sc;
+	struct mii_attach_args *ma;
+	u_int flags;
 
 	sc = device_get_softc(dev);
-
-	mii_phy_dev_attach(dev, 0, &rgephy_funcs, 0);
+	ma = device_get_ivars(dev);
+	flags = 0;
+	if (strcmp(ma->mii_data->mii_ifp->if_dname, "re") == 0)
+		flags |= MIIF_PHYPRIV0;
+	mii_phy_dev_attach(dev, flags, &rgephy_funcs, 0);
 
 	/* RTL8169S do not report auto-sense; add manually. */
 	sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) | BMSR_ANEG) &
@@ -243,7 +248,8 @@ rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
 		 * 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) {
+		if ((sc->mii_flags & MIIF_PHYPRIV0) == 0 &&
+		    sc->mii_mpd_rev >= 2) {
 			/* RTL8211B(L) */
 			reg = PHY_READ(sc, RGEPHY_MII_SSR);
 			if (reg & RGEPHY_SSR_LINK) {
@@ -298,7 +304,7 @@ rgephy_status(struct mii_softc *sc)
 	mii->mii_media_status = IFM_AVALID;
 	mii->mii_media_active = IFM_ETHER;
 
-	if (sc->mii_mpd_rev >= 2) {
+	if ((sc->mii_flags & MIIF_PHYPRIV0) == 0 && sc->mii_mpd_rev >= 2) {
 		ssr = PHY_READ(sc, RGEPHY_MII_SSR);
 		if (ssr & RGEPHY_SSR_LINK)
 			mii->mii_media_status |= IFM_ACTIVE;
@@ -328,7 +334,7 @@ rgephy_status(struct mii_softc *sc)
 		}
 	}
 
-	if (sc->mii_mpd_rev >= 2) {
+	if ((sc->mii_flags & MIIF_PHYPRIV0) == 0 && sc->mii_mpd_rev >= 2) {
 		ssr = PHY_READ(sc, RGEPHY_MII_SSR);
 		switch (ssr & RGEPHY_SSR_SPD_MASK) {
 		case RGEPHY_SSR_S1000:
@@ -484,7 +490,7 @@ rgephy_reset(struct mii_softc *sc)
 {
 	uint16_t ssr;
 
-	if (sc->mii_mpd_rev == 3) {
+	if ((sc->mii_flags & MIIF_PHYPRIV0) == 0 && sc->mii_mpd_rev == 3) {
 		/* RTL8211C(L) */
 		ssr = PHY_READ(sc, RGEPHY_MII_SSR);
 		if ((ssr & RGEPHY_SSR_ALDPS) != 0) {
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index d11661cbe318..672fced2edc3 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -1577,19 +1577,6 @@ re_attach(device_t dev)
 		re_gmii_writereg(dev, 1, 0x0e, 0);
 	}
 
-#define	RE_PHYAD_INTERNAL	 0
-
-	/* Do MII setup. */
-	phy = RE_PHYAD_INTERNAL;
-	if (sc->rl_type == RL_8169)
-		phy = 1;
-	error = mii_attach(dev, &sc->rl_miibus, ifp, re_ifmedia_upd,
-	    re_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, MIIF_DOPAUSE);
-	if (error != 0) {
-		device_printf(dev, "attaching PHYs failed\n");
-		goto fail;
-	}
-
 	ifp->if_softc = sc;
 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
@@ -1614,6 +1601,19 @@ re_attach(device_t dev)
 
 	TASK_INIT(&sc->rl_inttask, 0, re_int_task, sc);
 
+#define	RE_PHYAD_INTERNAL	 0
+
+	/* Do MII setup. */
+	phy = RE_PHYAD_INTERNAL;
+	if (sc->rl_type == RL_8169)
+		phy = 1;
+	error = mii_attach(dev, &sc->rl_miibus, ifp, re_ifmedia_upd,
+	    re_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, MIIF_DOPAUSE);
+	if (error != 0) {
+		device_printf(dev, "attaching PHYs failed\n");
+		goto fail;
+	}
+
 	/*
 	 * Call MI attach routine.
 	 */