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>] [day] [month] [year] [list]
Message-ID: <5701a9faafd1769b650b79c2d0c72cc10b5bdbc8.1764337894.git.buday.csaba@prolan.hu>
Date: Fri, 28 Nov 2025 14:53:32 +0100
From: Buday Csaba <buday.csaba@...lan.hu>
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: Buday Csaba <buday.csaba@...lan.hu>
Subject: [PATCH net-next v2 1/1] net: mdio: reset PHY before attempting to access ID register

When the ID of an Ethernet PHY is not provided by the 'compatible'
string in the device tree, its actual ID is read via the MDIO bus.
For some PHYs this could be unsafe, since a hard reset may be
necessary to safely access the MDIO registers.

Add a fallback mechanism for such devices: when reading the ID
fails, the reset will be asserted, and the ID read is retried.

This allows such devices to be used with an autodetected ID.

The fallback mechanism is activated in the error handling path, and
the return code of fwnode_mdiobus_register_phy() is unaltered, except
when the reset fails with -EPROBE_DEFER, which is propagated to the
caller.

Signed-off-by: Buday Csaba <buday.csaba@...lan.hu>
---
Patch split from a larger series:
https://lore.kernel.org/all/cover.1761732347.git.buday.csaba@prolan.hu/

The refactoring parts of the previous patchset were already merged,
leaving this one. Functionally identical to:
https://lore.kernel.org/all/5f8d93021a7aa6eeb4fb67ab27ddc7de9101c59f.1761732347.git.buday.csaba@prolan.hu/

Comments were added for clarity.
V1 -> V2: added missing EXPORT_SYMBOL_NS_GPL for
          mdio_device_register/unregister_reset functions
---
 drivers/net/mdio/fwnode_mdio.c | 42 +++++++++++++++++++++++++++++++++-
 drivers/net/phy/mdio_device.c  |  2 ++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c
index ba7091518..28daabe63 100644
--- a/drivers/net/mdio/fwnode_mdio.c
+++ b/drivers/net/mdio/fwnode_mdio.c
@@ -13,9 +13,12 @@
 #include <linux/phy.h>
 #include <linux/pse-pd/pse.h>
 
+#include "../phy/mdio-private.h"
+
 MODULE_AUTHOR("Calvin Johnson <calvin.johnson@....nxp.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("FWNODE MDIO bus (Ethernet PHY) accessors");
+MODULE_IMPORT_NS("NET_PHY_CORE_ONLY");
 
 static struct pse_control *
 fwnode_find_pse_control(struct fwnode_handle *fwnode,
@@ -67,6 +70,34 @@ fwnode_find_mii_timestamper(struct fwnode_handle *fwnode)
 	return mii_ts;
 }
 
+/* Hard-reset a PHY before registration */
+static int fwnode_reset_phy(struct mii_bus *bus, u32 addr,
+			    struct fwnode_handle *phy_node)
+{
+	struct mdio_device *tmpdev;
+	int rc;
+
+	/* Create a temporary MDIO device to allocate reset resources */
+	tmpdev = mdio_device_create(bus, addr);
+	if (IS_ERR(tmpdev))
+		return PTR_ERR(tmpdev);
+
+	device_set_node(&tmpdev->dev, fwnode_handle_get(phy_node));
+	rc = mdio_device_register_reset(tmpdev);
+	if (rc) {
+		mdio_device_free(tmpdev);
+		return rc;
+	}
+
+	mdio_device_reset(tmpdev, 1);
+	mdio_device_reset(tmpdev, 0);
+
+	mdio_device_unregister_reset(tmpdev);
+	mdio_device_free(tmpdev);
+
+	return 0;
+}
+
 int fwnode_mdiobus_phy_device_register(struct mii_bus *mdio,
 				       struct phy_device *phy,
 				       struct fwnode_handle *child, u32 addr)
@@ -129,8 +160,17 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,
 		return PTR_ERR(mii_ts);
 
 	is_c45 = fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45");
-	if (is_c45 || fwnode_get_phy_id(child, &phy_id))
+	if (is_c45 || fwnode_get_phy_id(child, &phy_id)) {
 		phy = get_phy_device(bus, addr, is_c45);
+		if (IS_ERR(phy)) {
+			/* get_phy_device() failed, retry after a reset */
+			rc = fwnode_reset_phy(bus, addr, child);
+			if (rc == -EPROBE_DEFER)
+				goto clean_mii_ts;
+			else if (!rc)
+				phy = get_phy_device(bus, addr, is_c45);
+		}
+	}
 	else
 		phy = phy_device_create(bus, addr, phy_id, 0, NULL);
 	if (IS_ERR(phy)) {
diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c
index fd0e16dbc..1125c89e4 100644
--- a/drivers/net/phy/mdio_device.c
+++ b/drivers/net/phy/mdio_device.c
@@ -156,6 +156,7 @@ int mdio_device_register_reset(struct mdio_device *mdiodev)
 
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(mdio_device_register_reset, "NET_PHY_CORE_ONLY");
 
 /**
  * mdio_device_unregister_reset - uninitialize the reset properties of
@@ -171,6 +172,7 @@ void mdio_device_unregister_reset(struct mdio_device *mdiodev)
 	mdiodev->reset_assert_delay = 0;
 	mdiodev->reset_deassert_delay = 0;
 }
+EXPORT_SYMBOL_NS_GPL(mdio_device_unregister_reset, "NET_PHY_CORE_ONLY");
 
 void mdio_device_reset(struct mdio_device *mdiodev, int value)
 {

base-commit: e2c20036a8879476c88002730d8a27f4e3c32d4b
-- 
2.39.5



Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ