lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240701-b4-dp83869-sfp-v1-6-a71d6d0ad5f8@bootlin.com>
Date: Mon, 01 Jul 2024 10:51:08 +0200
From: Romain Gantois <romain.gantois@...tlin.com>
To: Andrew Lunn <andrew@...n.ch>, Heiner Kallweit <hkallweit1@...il.com>, 
 Russell King <linux@...linux.org.uk>, 
 "David S. Miller" <davem@...emloft.net>, Eric Dumazet <edumazet@...gle.com>, 
 Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>
Cc: Thomas Petazzoni <thomas.petazzoni@...tlin.com>, netdev@...r.kernel.org, 
 linux-kernel@...r.kernel.org, Romain Gantois <romain.gantois@...tlin.com>
Subject: [PATCH net-next 6/6] net: phy: dp83869: Fix link up reporting in
 SGMII bridge mode

In RGMII-SGMII bridge mode, the DP83869HM PHY can perform an SGMII
autonegotiation with a downstream link partner. In this operational mode,
the standard link and autonegotiation status bits do not report correct
values, the extended fiber status register must be checked.

Link parameters should theoretically be obtainable from the DP83869
registers after SGMII autonegotiation has completed. However, for unknown
reasons, this is not the case, and the link partner fiber capabilities
register will incorrectly report a remote fault even if the SGMII
autonegotiation was successful.

Modify the read_status() callback of the DP83869 driver to check the fiber
status register in RGMII-SGMII bridge mode. On link up, obtain the link
parameters from the downstream SFP PHY driver if possible. If not, set
speed and duplex to "unknown".

Signed-off-by: Romain Gantois <romain.gantois@...tlin.com>
---
 drivers/net/phy/dp83869.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c
index a07ec1be84baf..843af90667d41 100644
--- a/drivers/net/phy/dp83869.c
+++ b/drivers/net/phy/dp83869.c
@@ -43,6 +43,7 @@
 #define DP83869_IO_MUX_CFG	0x0170
 #define DP83869_OP_MODE		0x01df
 #define DP83869_FX_CTRL		0x0c00
+#define DP83869_FX_STS		0x0c01
 
 #define DP83869_SW_RESET	BIT(15)
 #define DP83869_SW_RESTART	BIT(14)
@@ -72,6 +73,10 @@
 /* This is the same bit mask as the BMCR so re-use the BMCR default */
 #define DP83869_FX_CTRL_DEFAULT	MII_DP83869_BMCR_DEFAULT
 
+/* FX_STS bits */
+#define DP83869_FX_LSTATUS         BIT(2)
+#define DP83869_FX_ANEGCOMPLETE    BIT(5)
+
 /* CFG1 bits */
 #define DP83869_CFG1_DEFAULT	(ADVERTISE_1000HALF | \
 				 ADVERTISE_1000FULL | \
@@ -160,7 +165,8 @@ struct dp83869_private {
 static int dp83869_read_status(struct phy_device *phydev)
 {
 	struct dp83869_private *dp83869 = phydev->priv;
-	int ret;
+	int ret, old_link = phydev->link;
+	u32 status;
 
 	ret = genphy_read_status(phydev);
 	if (ret)
@@ -176,6 +182,38 @@ static int dp83869_read_status(struct phy_device *phydev)
 		}
 	}
 
+	if (dp83869->mode == DP83869_RGMII_SGMII_BRIDGE) {
+		/* check if SGMII link is up */
+		status = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_FX_STS);
+
+		phydev->link = status & DP83869_FX_LSTATUS ? 1 : 0;
+		phydev->autoneg_complete = status & DP83869_FX_ANEGCOMPLETE ? 1 : 0;
+
+		if (!phydev->autoneg_complete) {
+			phydev->link = 0;
+		} else if (phydev->link && !old_link) {
+			/* It seems like link status and duplex resolved from
+			 * SGMII autonegotiation are incorrectly reported in
+			 * the fiber link partner capabilities register and in
+			 * the PHY status register. If there is a handle to the
+			 * downstream PHY, read link parameters from it. If
+			 * not, fallback to unknown.
+			 */
+
+			if (dp83869->mod_phy) {
+				ret = phy_read_status(dp83869->mod_phy);
+				if (ret)
+					return ret;
+
+				phydev->speed = dp83869->mod_phy->speed;
+				phydev->duplex = dp83869->mod_phy->duplex;
+			} else {
+				phydev->speed = SPEED_UNKNOWN;
+				phydev->duplex = DUPLEX_UNKNOWN;
+			}
+		}
+	}
+
 	return 0;
 }
 

-- 
2.45.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ