From: Markus Stockhausen <markus.stockhausen@gmx.de>
To: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, netdev@vger.kernel.org,
chris.packham@alliedtelesis.co.nz, daniel@makrotopia.org,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
devicetree@vger.kernel.org
Cc: Markus Stockhausen <markus.stockhausen@gmx.de>
Subject: [PATCH net-next v3 4/8] net: mdio: realtek-rtl9300: Configure hardware polling during probing
Date: Sun, 5 Jul 2026 18:35:28 +0200 [thread overview]
Message-ID: <20260705163532.2853959-5-markus.stockhausen@gmx.de> (raw)
In-Reply-To: <20260705163532.2853959-1-markus.stockhausen@gmx.de>
During PHY probing and configuration complex configuration sequences
might be issued and firmware might be loaded. Hardware polling can
interfere badly with that. E.g. a hardware polling MMD c45 over c22
request might break an ongoing firmware loading sequence.
To avoid such issues the polling of the Realtek Otto switches can be
(de)activated with one or two 32 bit mask registers. Each bit enables
(=1) or disables (=0) the polling of the corresponding port. Make use
of this as follows:
- Disable polling for all ports when the MDIO driver starts.
- Reenable polling just after the PHY has been attached.
- Disable polling just before the PHY is being detached.
This synchronizes the kernel and hardware polling to some extent. It
gracefully handles deferred probing of PHYs in case the driver is
loaded asynchronously during boot. Additionally it brings the hardware
polling into a consistent operation mode for devices where U-Boot does
not take care.
[1] https://github.com/openwrt/openwrt/blob/main/target/linux/realtek/files-6.18/drivers/net/mdio/mdio-realtek-otto.c#L818
[2] https://lore.kernel.org/netdev/680696024a8648535ce6dee771fe4de67802e0e8.1769053496.git.daniel@makrotopia.org/
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
---
drivers/net/mdio/mdio-realtek-rtl9300.c | 77 +++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c
index 562f9c7f2895..c36244cd9a66 100644
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
@@ -139,6 +139,7 @@
#define RTL9300_PHY_CTRL_INDATA GENMASK(31, 16)
#define RTL9300_PHY_CTRL_DATA GENMASK(15, 0)
#define RTL9300_SMI_ACCESS_PHY_CTRL_3 0xcb7c
+#define RTL9300_SMI_POLL_CTRL 0xca90
#define RTL9300_SMI_PORT0_5_ADDR_CTRL 0xcb80
#define RTL9310_NUM_BUSES 4
@@ -164,6 +165,7 @@
#define RTL9310_PHY_CTRL_INDATA GENMASK(15, 0)
#define RTL9310_SMI_INDRT_ACCESS_MMD_CTRL 0x0c18
#define RTL9310_SMI_PORT_ADDR_CTRL 0x0c74
+#define RTL9310_SMI_PORT_POLLING_CTRL 0x0ccc
#define RTL9310_SMI_PORT_POLLING_SEL 0x0c9c
#define PHY_CTRL_CMD BIT(0)
@@ -194,6 +196,7 @@ struct otto_emdio_priv {
const struct otto_emdio_info *info;
struct regmap *regmap;
struct mutex lock; /* protect HW access */
+ DECLARE_BITMAP(phy_poll, MAX_PORTS);
DECLARE_BITMAP(valid_ports, MAX_PORTS);
u8 smi_bus[MAX_PORTS];
u8 smi_addr[MAX_PORTS];
@@ -211,6 +214,7 @@ struct otto_emdio_info {
u8 num_buses;
u8 num_ports;
u16 num_pages;
+ u32 poll_ctrl;
int (*setup_controller)(struct otto_emdio_priv *priv);
int (*read_c22)(struct mii_bus *bus, int port, int regnum, u32 *value);
int (*read_c45)(struct mii_bus *bus, int port, int dev_addr, int regnum, u32 *value);
@@ -246,6 +250,14 @@ static struct otto_emdio_priv *otto_emdio_bus_to_priv(struct mii_bus *bus)
return chan->priv;
}
+static int otto_emdio_set_port_polling(struct otto_emdio_priv *priv, int port, bool active)
+{
+ lockdep_assert_held(&priv->lock);
+
+ return regmap_assign_bits(priv->regmap, priv->info->poll_ctrl + (port / 32) * 4,
+ BIT(port % 32), active);
+}
+
static int otto_emdio_run_cmd(struct mii_bus *bus, u32 cmd,
struct otto_emdio_cmd_regs *cmd_data)
{
@@ -576,6 +588,47 @@ static int otto_emdio_9310_setup_controller(struct otto_emdio_priv *priv)
return 0;
}
+static int otto_emdio_notify_phy_attach(struct phy_device *phydev)
+{
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(phydev->mdio.bus);
+ int port = otto_emdio_phy_to_port(phydev->mdio.bus, phydev->mdio.addr);
+ int ret;
+
+ if (port < 0)
+ return port;
+
+ if (test_bit(port, priv->phy_poll))
+ return 0;
+
+ scoped_guard(mutex, &priv->lock) {
+ ret = otto_emdio_set_port_polling(priv, port, true);
+ if (!ret)
+ __set_bit(port, priv->phy_poll);
+ }
+
+ return ret;
+}
+
+static void otto_emdio_notify_phy_detach(struct phy_device *phydev)
+{
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(phydev->mdio.bus);
+ int port = otto_emdio_phy_to_port(phydev->mdio.bus, phydev->mdio.addr);
+ struct mii_bus *bus = phydev->mdio.bus;
+ int ret;
+
+ if (port < 0)
+ return;
+
+ scoped_guard(mutex, &priv->lock) {
+ ret = otto_emdio_set_port_polling(priv, port, false);
+ if (!ret)
+ __clear_bit(port, priv->phy_poll);
+ }
+
+ if (ret)
+ dev_err(bus->parent, "failed to disable polling for port %d\n", port);
+}
+
static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv,
struct fwnode_handle *node)
{
@@ -605,6 +658,9 @@ static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv
bus->write = otto_emdio_write_c22;
}
bus->parent = dev;
+ bus->notify_phy_attach = otto_emdio_notify_phy_attach;
+ bus->notify_phy_detach = otto_emdio_notify_phy_detach;
+
chan = bus->priv;
chan->mdio_bus = mdio_bus;
chan->priv = priv;
@@ -721,6 +777,21 @@ static int otto_emdio_map_ports(struct device *dev)
return err;
}
+static int otto_emdio_init_polling(struct otto_emdio_priv *priv)
+{
+ int err;
+
+ for (int port = 0; port < priv->info->num_ports; port++) {
+ scoped_guard(mutex, &priv->lock) {
+ err = otto_emdio_set_port_polling(priv, port, false);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
static int otto_emdio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -740,6 +811,10 @@ static int otto_emdio_probe(struct platform_device *pdev)
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
+ err = otto_emdio_init_polling(priv);
+ if (err)
+ return err;
+
platform_set_drvdata(pdev, priv);
err = otto_emdio_map_ports(dev);
@@ -780,6 +855,7 @@ static const struct otto_emdio_info otto_emdio_9300_info = {
.num_buses = RTL9300_NUM_BUSES,
.num_ports = RTL9300_NUM_PORTS,
.num_pages = RTL9300_NUM_PAGES,
+ .poll_ctrl = RTL9300_SMI_POLL_CTRL,
.setup_controller = otto_emdio_9300_setup_controller,
.read_c22 = otto_emdio_9300_read_c22,
.read_c45 = otto_emdio_9300_read_c45,
@@ -805,6 +881,7 @@ static const struct otto_emdio_info otto_emdio_9310_info = {
.num_buses = RTL9310_NUM_BUSES,
.num_pages = RTL9310_NUM_PAGES,
.num_ports = RTL9310_NUM_PORTS,
+ .poll_ctrl = RTL9310_SMI_PORT_POLLING_CTRL,
.setup_controller = otto_emdio_9310_setup_controller,
.read_c22 = otto_emdio_9310_read_c22,
.read_c45 = otto_emdio_9310_read_c45,
--
2.54.0
next prev parent reply other threads:[~2026-07-05 16:35 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-05 16:35 [PATCH net-next v3 0/8] net: mdio: realtek-rtl9300: Add RTL83xx support Markus Stockhausen
2026-07-05 16:35 ` [PATCH net-next v3 1/8] dt-bindings: net: realtek,rtl9301-mdio: Add RTL83xx series Markus Stockhausen
2026-07-06 17:08 ` Conor Dooley
2026-07-05 16:35 ` [PATCH net-next v3 2/8] net: mdio: realtek-rtl9300: Add polling documentation Markus Stockhausen
2026-07-05 16:35 ` [PATCH net-next v3 3/8] net: phy: add (*notify_phy_attach/detach)() hooks to struct mii_bus Markus Stockhausen
[not found] ` <20260706163627.A22DC1F000E9@smtp.kernel.org>
2026-07-06 17:36 ` AW: " Markus Stockhausen
2026-07-05 16:35 ` Markus Stockhausen [this message]
2026-07-05 16:35 ` [PATCH net-next v3 5/8] net: mdio: realtek-rtl9300: Add page tracking Markus Stockhausen
2026-07-05 16:35 ` [PATCH net-next v3 6/8] net: mdio: realtek-rtl9300: Increase MDIO timeout Markus Stockhausen
2026-07-05 16:35 ` [PATCH net-next v3 7/8] net: mdio: realtek-rtl9300: Add support for RTL838x Markus Stockhausen
2026-07-05 16:35 ` [PATCH net-next v3 8/8] net: mdio: realtek-rtl9300: Add support for RTL839x Markus Stockhausen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260705163532.2853959-5-markus.stockhausen@gmx.de \
--to=markus.stockhausen@gmx.de \
--cc=andrew@lunn.ch \
--cc=chris.packham@alliedtelesis.co.nz \
--cc=conor+dt@kernel.org \
--cc=daniel@makrotopia.org \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=edumazet@google.com \
--cc=hkallweit1@gmail.com \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=linux@armlinux.org.uk \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox