public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next] net: phy: make PHY fixup support always built-in
@ 2026-01-23  6:50 Heiner Kallweit
  2026-01-23  9:22 ` Russell King (Oracle)
  0 siblings, 1 reply; 5+ messages in thread
From: Heiner Kallweit @ 2026-01-23  6:50 UTC (permalink / raw)
  To: Andrew Lunn, Russell King - ARM Linux, Paolo Abeni,
	Jakub Kicinski, David Miller, Eric Dumazet, Andrew Lunn
  Cc: netdev@vger.kernel.org

PHY fixup registration is used from platform code in init phase only.
Let's move the PHY fixup code from the modular part of phylib to the
always built-in part of phylib. This allows to annotate the fixup
registration as __init.

phy_needs_fixup() and phy_scan_fixups() wouldn't have to be moved to
the built-in part of phylib. But doing so allows to fully factor out
fixup support into its own source code file, and make struct
phy_fixup and phy_fixup_list strictly private to phy_fixup.c.

phy_scan_fixups() is used after init phase only, then phy_fixup_list
is read-only. So we don't need the mutex when accessing the list.
Also when registering PHY fixups the mutex isn't needed, because
fixup registration is done sequentially from platform init code.
Actually there is only one platform with more than one fixup.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
 drivers/net/phy/Makefile          |   2 +-
 drivers/net/phy/phy_device.c      |  90 --------------------------
 drivers/net/phy/phy_fixup.c       | 101 ++++++++++++++++++++++++++++++
 drivers/net/phy/phylib-internal.h |   1 +
 include/linux/phy.h               |   8 +--
 5 files changed, 107 insertions(+), 95 deletions(-)
 create mode 100644 drivers/net/phy/phy_fixup.c

diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 3a34917adea..52bbb441e87 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -8,7 +8,7 @@ mdio-bus-y			+= mdio_bus.o mdio_device.o
 
 ifdef CONFIG_PHYLIB
 # built-in whenever PHYLIB is built-in or module
-obj-y				+= stubs.o
+obj-y				+= stubs.o phy_fixup.o
 endif
 
 libphy-$(CONFIG_SWPHY)		+= swphy.o
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index f624218bf36..7dd73a11f86 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -49,14 +49,6 @@ MODULE_DESCRIPTION("PHY library");
 MODULE_AUTHOR("Andy Fleming");
 MODULE_LICENSE("GPL");
 
-struct phy_fixup {
-	struct list_head list;
-	char bus_id[MII_BUS_ID_SIZE + 3];
-	u32 phy_uid;
-	u32 phy_uid_mask;
-	int (*run)(struct phy_device *phydev);
-};
-
 static struct phy_driver genphy_c45_driver = {
 	.phy_id         = 0xffffffff,
 	.phy_id_mask    = 0xffffffff,
@@ -237,9 +229,6 @@ static void phy_mdio_device_remove(struct mdio_device *mdiodev)
 
 static struct phy_driver genphy_driver;
 
-static LIST_HEAD(phy_fixup_list);
-static DEFINE_MUTEX(phy_fixup_lock);
-
 static bool phy_drv_wol_enabled(struct phy_device *phydev)
 {
 	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
@@ -427,85 +416,6 @@ static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(mdio_bus_phy_pm_ops, mdio_bus_phy_suspend,
 			 mdio_bus_phy_resume);
 
-/**
- * phy_register_fixup - creates a new phy_fixup and adds it to the list
- * @bus_id: A string which matches phydev->mdio.dev.bus_id (or NULL)
- * @phy_uid: Used to match against phydev->phy_id (the UID of the PHY)
- * @phy_uid_mask: Applied to phydev->phy_id and fixup->phy_uid before
- *	comparison (or 0 to disable id-based matching)
- * @run: The actual code to be run when a matching PHY is found
- */
-static int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
-			      int (*run)(struct phy_device *))
-{
-	struct phy_fixup *fixup = kzalloc(sizeof(*fixup), GFP_KERNEL);
-
-	if (!fixup)
-		return -ENOMEM;
-
-	if (bus_id)
-		strscpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id));
-	fixup->phy_uid = phy_uid;
-	fixup->phy_uid_mask = phy_uid_mask;
-	fixup->run = run;
-
-	mutex_lock(&phy_fixup_lock);
-	list_add_tail(&fixup->list, &phy_fixup_list);
-	mutex_unlock(&phy_fixup_lock);
-
-	return 0;
-}
-
-/* Registers a fixup to be run on any PHY with the UID in phy_uid */
-int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
-			       int (*run)(struct phy_device *))
-{
-	return phy_register_fixup(NULL, phy_uid, phy_uid_mask, run);
-}
-EXPORT_SYMBOL(phy_register_fixup_for_uid);
-
-/* Registers a fixup to be run on the PHY with id string bus_id */
-int phy_register_fixup_for_id(const char *bus_id,
-			      int (*run)(struct phy_device *))
-{
-	return phy_register_fixup(bus_id, 0, 0, run);
-}
-EXPORT_SYMBOL(phy_register_fixup_for_id);
-
-static bool phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)
-{
-	if (!strcmp(fixup->bus_id, phydev_name(phydev)))
-		return true;
-
-	if (fixup->phy_uid_mask &&
-	    phy_id_compare(phydev->phy_id, fixup->phy_uid, fixup->phy_uid_mask))
-		return true;
-
-	return false;
-}
-
-/* Runs any matching fixups for this phydev */
-static int phy_scan_fixups(struct phy_device *phydev)
-{
-	struct phy_fixup *fixup;
-
-	mutex_lock(&phy_fixup_lock);
-	list_for_each_entry(fixup, &phy_fixup_list, list) {
-		if (phy_needs_fixup(phydev, fixup)) {
-			int err = fixup->run(phydev);
-
-			if (err < 0) {
-				mutex_unlock(&phy_fixup_lock);
-				return err;
-			}
-			phydev->has_fixups = true;
-		}
-	}
-	mutex_unlock(&phy_fixup_lock);
-
-	return 0;
-}
-
 /**
  * genphy_match_phy_device - match a PHY device with a PHY driver
  * @phydev: target phy_device struct
diff --git a/drivers/net/phy/phy_fixup.c b/drivers/net/phy/phy_fixup.c
new file mode 100644
index 00000000000..ace78512686
--- /dev/null
+++ b/drivers/net/phy/phy_fixup.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * PHY fixup support
+ */
+
+#include <linux/list.h>
+#include <linux/phy.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "phylib-internal.h"
+
+static struct list_head phy_fixup_list __ro_after_init =
+	LIST_HEAD_INIT(phy_fixup_list);
+
+struct phy_fixup {
+	struct list_head list;
+	char bus_id[MII_BUS_ID_SIZE + 3];
+	u32 phy_uid;
+	u32 phy_uid_mask;
+	int (*run)(struct phy_device *phydev);
+};
+
+/**
+ * phy_register_fixup - creates a new phy_fixup and adds it to the list
+ * @bus_id: A string which matches phydev->mdio.dev.bus_id (or PHY_ANY_ID)
+ * @phy_uid: Used to match against phydev->phy_id (the UID of the PHY)
+ *	It can also be PHY_ANY_UID
+ * @phy_uid_mask: Applied to phydev->phy_id and fixup->phy_uid before
+ *	comparison
+ * @run: The actual code to be run when a matching PHY is found
+ */
+static int __init phy_register_fixup(const char *bus_id, u32 phy_uid,
+				     u32 phy_uid_mask,
+				     int (*run)(struct phy_device *))
+{
+	struct phy_fixup *fixup = kzalloc(sizeof(*fixup), GFP_KERNEL);
+
+	if (!fixup)
+		return -ENOMEM;
+
+	if (bus_id)
+		strscpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id));
+	fixup->phy_uid = phy_uid;
+	fixup->phy_uid_mask = phy_uid_mask;
+	fixup->run = run;
+
+	list_add_tail(&fixup->list, &phy_fixup_list);
+
+	return 0;
+}
+
+/* Registers a fixup to be run on any PHY with the UID in phy_uid */
+int __init phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
+				      int (*run)(struct phy_device *))
+{
+	return phy_register_fixup(NULL, phy_uid, phy_uid_mask, run);
+}
+
+/* Registers a fixup to be run on the PHY with id string bus_id */
+int __init phy_register_fixup_for_id(const char *bus_id,
+				     int (*run)(struct phy_device *))
+{
+	return phy_register_fixup(bus_id, 0, 0, run);
+}
+
+static bool phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)
+{
+	if (!strcmp(fixup->bus_id, phydev_name(phydev)))
+		return true;
+
+	if (fixup->phy_uid_mask &&
+	    phy_id_compare(phydev->phy_id, fixup->phy_uid, fixup->phy_uid_mask))
+		return true;
+
+	return false;
+}
+
+/**
+ * phy_scan_fixups - runs any matching fixups for this phydev
+ * @phydev: the phydev to search and run fixups for
+ * Returns: 0 or an errno
+ */
+int phy_scan_fixups(struct phy_device *phydev)
+{
+	struct phy_fixup *fixup;
+
+	list_for_each_entry(fixup, &phy_fixup_list, list) {
+		if (phy_needs_fixup(phydev, fixup)) {
+			int err = fixup->run(phydev);
+
+			if (err < 0)
+				return err;
+
+			phydev->has_fixups = true;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(phy_scan_fixups);
diff --git a/drivers/net/phy/phylib-internal.h b/drivers/net/phy/phylib-internal.h
index dc9592c6bb8..ca3794ffe04 100644
--- a/drivers/net/phy/phylib-internal.h
+++ b/drivers/net/phy/phylib-internal.h
@@ -19,6 +19,7 @@ void of_set_phy_eee_broken(struct phy_device *phydev);
 void of_set_phy_timing_role(struct phy_device *phydev);
 int phy_speed_down_core(struct phy_device *phydev);
 void phy_check_downshift(struct phy_device *phydev);
+int phy_scan_fixups(struct phy_device *phydev);
 
 int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv);
 
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 5972f19af16..ec09159e546 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -2400,10 +2400,10 @@ int phy_get_mac_termination(struct phy_device *phydev, struct device *dev,
 void phy_resolve_pause(unsigned long *local_adv, unsigned long *partner_adv,
 		       bool *tx_pause, bool *rx_pause);
 
-int phy_register_fixup_for_id(const char *bus_id,
-			      int (*run)(struct phy_device *));
-int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
-			       int (*run)(struct phy_device *));
+int __init phy_register_fixup_for_id(const char *bus_id,
+				     int (*run)(struct phy_device *));
+int __init phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
+				      int (*run)(struct phy_device *));
 
 int phy_eee_tx_clock_stop_capable(struct phy_device *phydev);
 int phy_eee_rx_clock_stop(struct phy_device *phydev, bool clk_stop_enable);
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next] net: phy: make PHY fixup support always built-in
  2026-01-23  6:50 [PATCH net-next] net: phy: make PHY fixup support always built-in Heiner Kallweit
@ 2026-01-23  9:22 ` Russell King (Oracle)
  2026-01-23 11:39   ` Heiner Kallweit
  0 siblings, 1 reply; 5+ messages in thread
From: Russell King (Oracle) @ 2026-01-23  9:22 UTC (permalink / raw)
  To: Heiner Kallweit
  Cc: Andrew Lunn, Paolo Abeni, Jakub Kicinski, David Miller,
	Eric Dumazet, Andrew Lunn, netdev@vger.kernel.org

On Fri, Jan 23, 2026 at 07:50:20AM +0100, Heiner Kallweit wrote:
> PHY fixup registration is used from platform code in init phase only.
> Let's move the PHY fixup code from the modular part of phylib to the
> always built-in part of phylib. This allows to annotate the fixup
> registration as __init.
> 
> phy_needs_fixup() and phy_scan_fixups() wouldn't have to be moved to
> the built-in part of phylib. But doing so allows to fully factor out
> fixup support into its own source code file, and make struct
> phy_fixup and phy_fixup_list strictly private to phy_fixup.c.
> 
> phy_scan_fixups() is used after init phase only, then phy_fixup_list
> is read-only. So we don't need the mutex when accessing the list.
> Also when registering PHY fixups the mutex isn't needed, because
> fixup registration is done sequentially from platform init code.
> Actually there is only one platform with more than one fixup.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>

What is broken today that needs this change, and why haven't we had
reports of breakage?

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next] net: phy: make PHY fixup support always built-in
  2026-01-23  9:22 ` Russell King (Oracle)
@ 2026-01-23 11:39   ` Heiner Kallweit
  2026-01-25 19:57     ` Jakub Kicinski
  0 siblings, 1 reply; 5+ messages in thread
From: Heiner Kallweit @ 2026-01-23 11:39 UTC (permalink / raw)
  To: Russell King (Oracle)
  Cc: Andrew Lunn, Paolo Abeni, Jakub Kicinski, David Miller,
	Eric Dumazet, Andrew Lunn, netdev@vger.kernel.org

On 1/23/2026 10:22 AM, Russell King (Oracle) wrote:
> On Fri, Jan 23, 2026 at 07:50:20AM +0100, Heiner Kallweit wrote:
>> PHY fixup registration is used from platform code in init phase only.
>> Let's move the PHY fixup code from the modular part of phylib to the
>> always built-in part of phylib. This allows to annotate the fixup
>> registration as __init.
>>
>> phy_needs_fixup() and phy_scan_fixups() wouldn't have to be moved to
>> the built-in part of phylib. But doing so allows to fully factor out
>> fixup support into its own source code file, and make struct
>> phy_fixup and phy_fixup_list strictly private to phy_fixup.c.
>>
>> phy_scan_fixups() is used after init phase only, then phy_fixup_list
>> is read-only. So we don't need the mutex when accessing the list.
>> Also when registering PHY fixups the mutex isn't needed, because
>> fixup registration is done sequentially from platform init code.
>> Actually there is only one platform with more than one fixup.
>>
>> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
> 
> What is broken today that needs this change, and why haven't we had
> reports of breakage?
> 
Nothing is broken, otherwise patch would have been addressed to net tree.

Recent removal of the dnet driver removed last fixup user not being
platform init code. This (and considering that PHY fixups are a legacy
functionality) allows to:
- factor out this legacy functionality from phy_device.c
- discard half the related code after init phase
- simplify the code (e.g. remove mutex)
- use modular phylib on platforms where fixup just sets a flag,
  e.g. apx4devkit_phy_fixup() in arch/arm/mach-mxs/mach-mxs.c.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next] net: phy: make PHY fixup support always built-in
  2026-01-23 11:39   ` Heiner Kallweit
@ 2026-01-25 19:57     ` Jakub Kicinski
  2026-01-25 20:05       ` Heiner Kallweit
  0 siblings, 1 reply; 5+ messages in thread
From: Jakub Kicinski @ 2026-01-25 19:57 UTC (permalink / raw)
  To: Heiner Kallweit
  Cc: Russell King (Oracle), Andrew Lunn, Paolo Abeni, David Miller,
	Eric Dumazet, Andrew Lunn, netdev@vger.kernel.org

On Fri, 23 Jan 2026 12:39:22 +0100 Heiner Kallweit wrote:
> Recent removal of the dnet driver removed last fixup user not being
> platform init code.

Oh, driver removals may need to be reverted if someone speaks up.
Could you wait at least 2 releases with the dependent cleanups?
We had to revert back at least 2 drivers we removed in the past.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next] net: phy: make PHY fixup support always built-in
  2026-01-25 19:57     ` Jakub Kicinski
@ 2026-01-25 20:05       ` Heiner Kallweit
  0 siblings, 0 replies; 5+ messages in thread
From: Heiner Kallweit @ 2026-01-25 20:05 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Russell King (Oracle), Andrew Lunn, Paolo Abeni, David Miller,
	Eric Dumazet, Andrew Lunn, netdev@vger.kernel.org

On 1/25/2026 8:57 PM, Jakub Kicinski wrote:
> On Fri, 23 Jan 2026 12:39:22 +0100 Heiner Kallweit wrote:
>> Recent removal of the dnet driver removed last fixup user not being
>> platform init code.
> 
> Oh, driver removals may need to be reverted if someone speaks up.
> Could you wait at least 2 releases with the dependent cleanups?
> We had to revert back at least 2 drivers we removed in the past.

OK. I'll keep the change in my local tree until then.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-01-25 20:05 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-23  6:50 [PATCH net-next] net: phy: make PHY fixup support always built-in Heiner Kallweit
2026-01-23  9:22 ` Russell King (Oracle)
2026-01-23 11:39   ` Heiner Kallweit
2026-01-25 19:57     ` Jakub Kicinski
2026-01-25 20:05       ` Heiner Kallweit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox