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: <680696024a8648535ce6dee771fe4de67802e0e8.1769053496.git.daniel@makrotopia.org>
Date: Thu, 22 Jan 2026 04:00:56 +0000
From: Daniel Golle <daniel@...rotopia.org>
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>,
	netdev@...r.kernel.org, linux-kernel@...r.kernel.org
Cc: Jonas Jelonek <jelonek.jonas@...il.com>,
	Markus Stockhausen <markus.stockhausen@....de>
Subject: [RFC PATCH v2 2/2] net: mdio: rtl9300: setup PHY polling registers

The mdio-realtek-rtl9300 driver currently relies on the bootloader to
correctly setup polling registers depending on the PHY type. On quite a
lot of switches the bootloader only does this in case the user
interrupts the boot process and loads firmware via TFTP, otherwise
Ethernet remains uninitialized. On some devices the U-Boot environment
can be customized so they always initialize the switch and MDIO
controller before launching Linux, and rarely vendors decide to just
always do it.

Setup the polling registers based on the PHYs detected on the bus, and
setup registers for non-standard Clause-45 registers used in polling in
case the PHY vendor is known and commonly used in those switches.

Signed-off-by: Daniel Golle <daniel@...rotopia.org>
---
 drivers/net/mdio/mdio-realtek-rtl9300.c | 82 +++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c
index 405a07075dd11..9e030be497ab3 100644
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
@@ -24,6 +24,9 @@
 
 #define SMI_GLB_CTRL			0xca00
 #define   GLB_CTRL_INTF_SEL(intf)	BIT(16 + (intf))
+#define SMI_MAC_TYPE_CTRL		0xca04
+#define   SMI_MAC_TYPE_CTRL_1G		3
+#define   SMI_MAC_TYPE_CTRL_2G_PLUS	1
 #define SMI_PORT0_15_POLLING_SEL	0xca08
 #define SMI_ACCESS_PHY_CTRL_0		0xcb70
 #define SMI_ACCESS_PHY_CTRL_1		0xcb74
@@ -43,6 +46,13 @@
 #define   PHY_CTRL_MMD_DEVAD		GENMASK(20, 16)
 #define   PHY_CTRL_MMD_REG		GENMASK(15, 0)
 #define SMI_PORT0_5_ADDR_CTRL		0xcb80
+#define SMI_PRVTE_POLLING_CTRL		0xca10
+#define SMI_10G_POLLING_REG0_CFG	0xcbb4
+#define SMI_10G_POLLING_REG9_CFG	0xcbb8
+#define SMI_10G_POLLING_REG10_CFG	0xcbbc
+
+#define RTMDIO_PHY_POLL_MMD(dev, reg, bit) \
+	(((bit) << 21) | ((dev) << 16) | (reg))
 
 #define MAX_PORTS       28
 #define MAX_SMI_BUSSES  4
@@ -56,6 +66,7 @@ struct rtl9300_mdio_priv {
 	u8 smi_addr[MAX_PORTS];
 	bool smi_bus_is_c45[MAX_SMI_BUSSES];
 	struct mii_bus *bus[MAX_SMI_BUSSES];
+	bool c45_polling_is_setup;
 };
 
 struct rtl9300_mdio_chan {
@@ -350,6 +361,74 @@ static int rtl9300_mdiobus_init(struct rtl9300_mdio_priv *priv)
 	return 0;
 }
 
+static int rtl9300_register_phy(struct phy_device *phydev)
+{
+	u32 mask, val, poll_duplex, poll_adv_1000, poll_lpa_1000;
+	struct mii_bus *bus = phydev->mdio.bus;
+	struct rtl9300_mdio_chan *chan;
+	struct rtl9300_mdio_priv *priv;
+	struct regmap *regmap;
+	int port, ret;
+	u8 mac_type;
+
+	chan = bus->priv;
+	priv = chan->priv;
+	regmap = priv->regmap;
+	port = rtl9300_mdio_phy_to_port(bus, phydev->mdio.addr);
+
+	/* Detect if PHY has 2.5G/5G/10G capabilities */
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported) ||
+	    linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, phydev->supported) ||
+	    linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, phydev->supported))
+		mac_type = SMI_MAC_TYPE_CTRL_2G_PLUS;
+	else
+		mac_type = SMI_MAC_TYPE_CTRL_1G;
+
+	mask = port > 23 ? 0x7 << ((port - 24) * 3 + 12) : 0x3 << ((port / 4) * 2);
+	val = mac_type << (ffs(mask) - 1);
+	ret = regmap_update_bits(regmap, SMI_MAC_TYPE_CTRL, mask, val);
+	if (ret < 0)
+		return ret;
+
+	/* Setup Clause-45 registers to be polled for the first >1G PHY.
+	 * All >1G PHYs connected to the switch SoC have to be of the same type.
+	 */
+	if (mac_type == SMI_MAC_TYPE_CTRL_1G || priv->c45_polling_is_setup)
+		return 0;
+
+	priv->c45_polling_is_setup = true;
+
+	switch (phydev->phy_id & PHY_ID_MATCH_VENDOR_MASK) {
+	case 0x001cc800: /* RealTek */
+		poll_duplex = RTMDIO_PHY_POLL_MMD(MDIO_MMD_VEND2, 0xa400, 8);
+		poll_adv_1000 = RTMDIO_PHY_POLL_MMD(MDIO_MMD_VEND2, 0xa412, 9);
+		poll_lpa_1000 = RTMDIO_PHY_POLL_MMD(MDIO_MMD_VEND2, 0xa414, 11);
+		break;
+	case 0x03a1b400: /* Aquantia */
+	case 0x31c31c00:
+		poll_duplex = RTMDIO_PHY_POLL_MMD(MDIO_MMD_PMAPMD, MDIO_CTRL1, 8);
+		poll_adv_1000 = RTMDIO_PHY_POLL_MMD(MDIO_MMD_AN, 0xc400, 15);
+		poll_lpa_1000 = RTMDIO_PHY_POLL_MMD(MDIO_MMD_AN, 0xe820, 15);
+		break;
+	default:
+		dev_warn(&phydev->mdio.dev,
+			 "Unknown register layout, relying on bootloader network setup.\n");
+		return 0;
+	};
+
+	ret = regmap_write(regmap, SMI_10G_POLLING_REG0_CFG, poll_duplex);
+	if (ret < 0)
+		return ret;
+	ret = regmap_write(regmap, SMI_10G_POLLING_REG9_CFG, poll_adv_1000);
+	if (ret < 0)
+		return ret;
+	ret = regmap_write(regmap, SMI_10G_POLLING_REG10_CFG, poll_lpa_1000);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_priv *priv,
 				     struct fwnode_handle *node)
 {
@@ -387,6 +466,7 @@ static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_pri
 		bus->write = rtl9300_mdio_write_c22;
 	}
 	bus->parent = dev;
+	bus->register_phy = rtl9300_register_phy;
 	chan = bus->priv;
 	chan->mdio_bus = mdio_bus;
 	chan->priv = priv;
@@ -481,6 +561,8 @@ static int rtl9300_mdiobus_probe(struct platform_device *pdev)
 	if (IS_ERR(priv->regmap))
 		return PTR_ERR(priv->regmap);
 
+	priv->c45_polling_is_setup = false;
+
 	platform_set_drvdata(pdev, priv);
 
 	err = rtl9300_mdiobus_map_ports(dev);
-- 
2.52.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ