[openwrt/openwrt] generic: net: phy: realtek: work-around hang on SerDes setup

LEDE Commits lede-commits at lists.infradead.org
Fri Jan 31 12:39:47 PST 2025


hauke pushed a commit to openwrt/openwrt.git, branch openwrt-24.10:
https://git.openwrt.org/81db3077483388ec8fa7be441e34756438678f78

commit 81db3077483388ec8fa7be441e34756438678f78
Author: Daniel Golle <daniel at makrotopia.org>
AuthorDate: Thu Jan 30 05:49:43 2025 +0000

    generic: net: phy: realtek: work-around hang on SerDes setup
    
    On some but not all devices using the RTL8221B 2.5GBit/s PHY the SerDes
    setup sequence may hang under some circumstances (eg. <2500M link
    partner present during boot).
    
    RTL8221B-VB-CG 2.5Gbps PHY (C45) mdio-bus:01: rtl822xb_config_init failed: -110
    
    Work-around the issue by performing a hardware reset and subsequent
    retry of the SerDes setup, which seems to always succeed.
    
    Doing this requires moving ALDPS setup to config_init (which is anyway
    the better place for that) as it otherwise doesn't survive the reset.
    
    Also disable listening on MDIO address 0 which may be used by other PHYs
    despite being spec'ed as "broadcast address", as bus activity on address
    0 may otherwise confuse the RealTek PHY for good reasons.
    
    Tested-by: Luis Mita <luis at luismita.com>
    Signed-off-by: Daniel Golle <daniel at makrotopia.org>
    (cherry picked from commit c87a767801ef375feadb0a5c41d5a674ad3a7d2c)
    Link: https://github.com/openwrt/openwrt/pull/17790
    Signed-off-by: Hauke Mehrtens <hauke at hauke-m.de>
---
 ...phy-realtek-introduce-rtl822x_aldps_probe.patch | 104 ---------------------
 .../720-04-net-phy-realtek-setup-aldps.patch       |  42 +++++++++
 ...-realtek-detect-early-version-of-RTL8221B.patch |   2 +-
 ...phy-realtek-support-interrupt-of-RTL8221B.patch |  18 ++--
 ...phy-realtek-mark-existing-MMDs-as-present.patch |   2 +-
 ...net-phy-realtek-work-around-broken-serdes.patch |  58 ++++++++++++
 ...09-net-phy-realtek-disable-MDIO-broadcast.patch |  27 ++++++
 7 files changed, 138 insertions(+), 115 deletions(-)

diff --git a/target/linux/generic/pending-6.6/720-04-net-phy-realtek-introduce-rtl822x_aldps_probe.patch b/target/linux/generic/pending-6.6/720-04-net-phy-realtek-introduce-rtl822x_aldps_probe.patch
deleted file mode 100644
index 6610af12c3..0000000000
--- a/target/linux/generic/pending-6.6/720-04-net-phy-realtek-introduce-rtl822x_aldps_probe.patch
+++ /dev/null
@@ -1,104 +0,0 @@
-From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel at makrotopia.org>
-Date: Sat, 22 Apr 2023 03:26:01 +0100
-Subject: [PATCH] net: phy: realtek: setup ALDPS on RTL822x
-
-Setup Link Down Power Saving Mode according the DTS property
-just like for RTL821x 1GE PHYs.
-
-Signed-off-by: Daniel Golle <daniel at makrotopia.org>
----
- drivers/net/phy/realtek/realtek_main.c | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
---- a/drivers/net/phy/realtek/realtek_main.c
-+++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -82,6 +82,10 @@
- 
- #define RTL822X_VND2_GANLPAR				0xa414
- 
-+#define RTL8221B_PHYCR1				0xa430
-+#define RTL8221B_PHYCR1_ALDPS_EN		BIT(2)
-+#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN	BIT(12)
-+
- #define RTL8366RB_POWER_SAVE			0x15
- #define RTL8366RB_POWER_SAVE_ON			BIT(12)
- 
-@@ -1207,6 +1211,25 @@ static int rtl8251b_c45_match_phy_device
- 	return rtlgen_is_c45_match(phydev, RTL_8251B, true);
- }
- 
-+static int rtl822x_aldps_probe(struct phy_device *phydev)
-+{
-+	struct device *dev = &phydev->mdio.dev;
-+	int val;
-+
-+	val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1);
-+	if (val < 0)
-+		return val;
-+
-+	if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
-+		val |= RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN;
-+	else
-+		val &= ~(RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
-+
-+	phy_write_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, val);
-+
-+	return rtl822x_probe(phydev);
-+}
-+
- static int rtlgen_resume(struct phy_device *phydev)
- {
- 	int ret = genphy_resume(phydev);
-@@ -1478,6 +1501,7 @@ static struct phy_driver realtek_drvs[]
- 	}, {
- 		PHY_ID_MATCH_EXACT(0x001cc838),
- 		.name           = "RTL8226-CG 2.5Gbps PHY",
-+		.probe          = rtl822x_aldps_probe,
- 		.soft_reset     = genphy_soft_reset,
- 		.get_features   = rtl822x_get_features,
- 		.config_aneg    = rtl822x_config_aneg,
-@@ -1489,6 +1513,7 @@ static struct phy_driver realtek_drvs[]
- 	}, {
- 		PHY_ID_MATCH_EXACT(0x001cc848),
- 		.name           = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
-+		.probe          = rtl822x_aldps_probe,
- 		.soft_reset     = genphy_soft_reset,
- 		.get_features   = rtl822x_get_features,
- 		.config_aneg    = rtl822x_config_aneg,
-@@ -1503,7 +1528,7 @@ static struct phy_driver realtek_drvs[]
- 		.match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
- 		.name           = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
- 		.soft_reset     = genphy_soft_reset,
--		.probe		= rtl822x_probe,
-+		.probe          = rtl822x_aldps_probe,
- 		.get_features   = rtl822x_get_features,
- 		.config_aneg    = rtl822x_config_aneg,
- 		.config_init    = rtl822xb_config_init,
-@@ -1517,7 +1542,7 @@ static struct phy_driver realtek_drvs[]
- 		.match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
- 		.name           = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
- 		.soft_reset     = genphy_soft_reset,
--		.probe		= rtl822x_probe,
-+		.probe          = rtl822x_aldps_probe,
- 		.config_init    = rtl822xb_config_init,
- 		.get_rate_matching = rtl822xb_get_rate_matching,
- 		.get_features   = rtl822x_c45_get_features,
-@@ -1529,7 +1554,7 @@ static struct phy_driver realtek_drvs[]
- 		.match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
- 		.name           = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
- 		.soft_reset     = genphy_soft_reset,
--		.probe		= rtl822x_probe,
-+		.probe          = rtl822x_aldps_probe,
- 		.get_features   = rtl822x_get_features,
- 		.config_aneg    = rtl822x_config_aneg,
- 		.config_init    = rtl822xb_config_init,
-@@ -1543,7 +1568,7 @@ static struct phy_driver realtek_drvs[]
- 		.match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
- 		.name           = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
- 		.soft_reset     = genphy_soft_reset,
--		.probe		= rtl822x_probe,
-+		.probe          = rtl822x_aldps_probe,
- 		.config_init    = rtl822xb_config_init,
- 		.get_rate_matching = rtl822xb_get_rate_matching,
- 		.get_features   = rtl822x_c45_get_features,
diff --git a/target/linux/generic/pending-6.6/720-04-net-phy-realtek-setup-aldps.patch b/target/linux/generic/pending-6.6/720-04-net-phy-realtek-setup-aldps.patch
new file mode 100644
index 0000000000..23b3ca893a
--- /dev/null
+++ b/target/linux/generic/pending-6.6/720-04-net-phy-realtek-setup-aldps.patch
@@ -0,0 +1,42 @@
+From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Sat, 22 Apr 2023 03:26:01 +0100
+Subject: [PATCH] net: phy: realtek: setup ALDPS on RTL822x
+
+Setup Link Down Power Saving Mode according the DTS property
+just like for RTL821x 1GE PHYs.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ drivers/net/phy/realtek/realtek_main.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/drivers/net/phy/realtek/realtek_main.c
++++ b/drivers/net/phy/realtek/realtek_main.c
+@@ -82,6 +82,10 @@
+ 
+ #define RTL822X_VND2_GANLPAR				0xa414
+ 
++#define RTL8221B_PHYCR1				0xa430
++#define RTL8221B_PHYCR1_ALDPS_EN		BIT(2)
++#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN	BIT(12)
++
+ #define RTL8366RB_POWER_SAVE			0x15
+ #define RTL8366RB_POWER_SAVE_ON			BIT(12)
+ 
+@@ -889,6 +893,15 @@ static int rtl822xb_config_init(struct p
+ 	if (ret < 0)
+ 		return ret;
+ 
++	if (of_property_read_bool(phydev->mdio.dev.of_node, "realtek,aldps-enable"))
++		ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1,
++				 RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
++	else
++		ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1,
++				   RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
++	if (ret < 0)
++		return ret;
++
+ 	/* Disable SGMII AN */
+ 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2);
+ 	if (ret < 0)
diff --git a/target/linux/generic/pending-6.6/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch b/target/linux/generic/pending-6.6/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch
index 22c271c3eb..d7fbf3a2a6 100644
--- a/target/linux/generic/pending-6.6/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch
+++ b/target/linux/generic/pending-6.6/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch
@@ -14,7 +14,7 @@ Signed-off-by: Daniel Golle <daniel at makrotopia.org>
 Signed-off-by: Mieczyslaw Nalewaj <namiltd at yahoo.com>
 --- a/drivers/net/phy/realtek/realtek_main.c
 +++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1157,10 +1157,32 @@ static int rtl8226_match_phy_device(stru
+@@ -1166,10 +1166,32 @@ static int rtl8226_match_phy_device(stru
  static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
  			       bool is_c45)
  {
diff --git a/target/linux/generic/pending-6.6/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch b/target/linux/generic/pending-6.6/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch
index 3e9b34b8a5..45ca5413f3 100644
--- a/target/linux/generic/pending-6.6/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch
+++ b/target/linux/generic/pending-6.6/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch
@@ -12,7 +12,7 @@ Signed-off-by: Jianhui Zhao <zhaojh329 at gmail.com>
 
 --- a/drivers/net/phy/realtek/realtek_main.c
 +++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1387,6 +1387,51 @@ static irqreturn_t rtl9000a_handle_inter
+@@ -1377,6 +1377,51 @@ static irqreturn_t rtl9000a_handle_inter
  	return IRQ_HANDLED;
  }
  
@@ -64,39 +64,39 @@ Signed-off-by: Jianhui Zhao <zhaojh329 at gmail.com>
  static struct phy_driver realtek_drvs[] = {
  	{
  		PHY_ID_MATCH_EXACT(0x00008201),
-@@ -1549,6 +1594,8 @@ static struct phy_driver realtek_drvs[]
+@@ -1537,6 +1582,8 @@ static struct phy_driver realtek_drvs[]
  	}, {
  		.match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
  		.name           = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
 +		.config_intr	= rtl8221b_config_intr,
 +		.handle_interrupt = rtl8221b_handle_interrupt,
  		.soft_reset     = genphy_soft_reset,
- 		.probe          = rtl822x_aldps_probe,
+ 		.probe		= rtl822x_probe,
  		.get_features   = rtl822x_get_features,
-@@ -1563,6 +1610,8 @@ static struct phy_driver realtek_drvs[]
+@@ -1551,6 +1598,8 @@ static struct phy_driver realtek_drvs[]
  	}, {
  		.match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
  		.name           = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
 +		.config_intr	= rtl8221b_config_intr,
 +		.handle_interrupt = rtl8221b_handle_interrupt,
  		.soft_reset     = genphy_soft_reset,
- 		.probe          = rtl822x_aldps_probe,
+ 		.probe		= rtl822x_probe,
  		.config_init    = rtl822xb_config_init,
-@@ -1575,6 +1624,8 @@ static struct phy_driver realtek_drvs[]
+@@ -1563,6 +1612,8 @@ static struct phy_driver realtek_drvs[]
  	}, {
  		.match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
  		.name           = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
 +		.config_intr	= rtl8221b_config_intr,
 +		.handle_interrupt = rtl8221b_handle_interrupt,
  		.soft_reset     = genphy_soft_reset,
- 		.probe          = rtl822x_aldps_probe,
+ 		.probe		= rtl822x_probe,
  		.get_features   = rtl822x_get_features,
-@@ -1589,6 +1640,8 @@ static struct phy_driver realtek_drvs[]
+@@ -1577,6 +1628,8 @@ static struct phy_driver realtek_drvs[]
  	}, {
  		.match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
  		.name           = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
 +		.config_intr	= rtl8221b_config_intr,
 +		.handle_interrupt = rtl8221b_handle_interrupt,
  		.soft_reset     = genphy_soft_reset,
- 		.probe          = rtl822x_aldps_probe,
+ 		.probe		= rtl822x_probe,
  		.config_init    = rtl822xb_config_init,
diff --git a/target/linux/generic/pending-6.6/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch b/target/linux/generic/pending-6.6/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch
index 1ef42e866d..555e5905d3 100644
--- a/target/linux/generic/pending-6.6/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch
+++ b/target/linux/generic/pending-6.6/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch
@@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle <daniel at makrotopia.org>
 
 --- a/drivers/net/phy/realtek/realtek_main.c
 +++ b/drivers/net/phy/realtek/realtek_main.c
-@@ -1034,6 +1034,9 @@ static int rtl822x_c45_get_features(stru
+@@ -1043,6 +1043,9 @@ static int rtl822x_c45_get_features(stru
  	linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT,
  			 phydev->supported);
  
diff --git a/target/linux/generic/pending-6.6/720-08-net-phy-realtek-work-around-broken-serdes.patch b/target/linux/generic/pending-6.6/720-08-net-phy-realtek-work-around-broken-serdes.patch
new file mode 100644
index 0000000000..e356a0a6ee
--- /dev/null
+++ b/target/linux/generic/pending-6.6/720-08-net-phy-realtek-work-around-broken-serdes.patch
@@ -0,0 +1,58 @@
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Thu, 30 Jan 2025 05:33:12 +0000
+Subject: [PATCH] net: phy: realtek: work around broken SerDes
+
+For still unknown reasons the SerDes init sequence may sometimes
+time out because a self-clearing bit never clears, indicating the
+PHY has entered an unrecoverable error state.
+
+Work-around the issue by triggering a hardware reset and retry the
+setup sequence while warning the user that this has happened.
+This is really more of a work-around than a fix, and should be
+replaced by a better actual fix in future (hopefully).
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+--- a/drivers/net/phy/realtek/realtek_main.c
++++ b/drivers/net/phy/realtek/realtek_main.c
+@@ -923,6 +923,22 @@ static int rtl822xb_config_init(struct p
+ 	return 0;
+ }
+ 
++static int rtl822xb_config_init_war(struct phy_device *phydev)
++{
++	int ret;
++
++	ret = rtl822xb_config_init(phydev);
++
++	if (ret == -ETIMEDOUT) {
++		phydev_warn(phydev, "SerDes setup timed out, retrying\n");
++		phy_device_reset(phydev, 1);
++		phy_device_reset(phydev, 0);
++		ret = rtl822xb_config_init(phydev);
++	}
++
++	return ret;
++}
++
+ static int rtl822xb_get_rate_matching(struct phy_device *phydev,
+ 				      phy_interface_t iface)
+ {
+@@ -1605,7 +1621,7 @@ static struct phy_driver realtek_drvs[]
+ 		.handle_interrupt = rtl8221b_handle_interrupt,
+ 		.soft_reset     = genphy_soft_reset,
+ 		.probe		= rtl822x_probe,
+-		.config_init    = rtl822xb_config_init,
++		.config_init    = rtl822xb_config_init_war,
+ 		.get_rate_matching = rtl822xb_get_rate_matching,
+ 		.get_features   = rtl822x_c45_get_features,
+ 		.config_aneg    = rtl822x_c45_config_aneg,
+@@ -1635,7 +1651,7 @@ static struct phy_driver realtek_drvs[]
+ 		.handle_interrupt = rtl8221b_handle_interrupt,
+ 		.soft_reset     = genphy_soft_reset,
+ 		.probe		= rtl822x_probe,
+-		.config_init    = rtl822xb_config_init,
++		.config_init    = rtl822xb_config_init_war,
+ 		.get_rate_matching = rtl822xb_get_rate_matching,
+ 		.get_features   = rtl822x_c45_get_features,
+ 		.config_aneg    = rtl822x_c45_config_aneg,
diff --git a/target/linux/generic/pending-6.6/720-09-net-phy-realtek-disable-MDIO-broadcast.patch b/target/linux/generic/pending-6.6/720-09-net-phy-realtek-disable-MDIO-broadcast.patch
new file mode 100644
index 0000000000..b2d26a8780
--- /dev/null
+++ b/target/linux/generic/pending-6.6/720-09-net-phy-realtek-disable-MDIO-broadcast.patch
@@ -0,0 +1,27 @@
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Thu, 30 Jan 2025 05:38:31 +0000
+Subject: [PATCH] net: phy: realtek: disable MDIO broadcast
+
+RealTek's PHYs by default also listen on MDIO address 0 which is defined
+as broadcast address. This can lead to problems if there is an actual PHY
+(such as MT7981 built-in PHY) present at this address, as accessing that
+PHY may then confuse the RealTek PHY.
+
+Disabled listening on the MDIO broadcast address to avoid such problems.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+--- a/drivers/net/phy/realtek/realtek_main.c
++++ b/drivers/net/phy/realtek/realtek_main.c
+@@ -849,6 +849,11 @@ static int rtl822xb_config_init(struct p
+ 			     phydev->host_interfaces) ||
+ 		    phydev->interface == PHY_INTERFACE_MODE_SGMII;
+ 
++	/* disable listening on MDIO broadcast address (0) */
++	ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0xa430, BIT(13));
++	if (ret < 0)
++		return ret;
++
+ 	/* fill in possible interfaces */
+ 	__assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces,
+ 		     has_2500);




More information about the lede-commits mailing list