68 lines
2.1 KiB
Diff
68 lines
2.1 KiB
Diff
From c938ab4da0eb1620ae3243b0b24c572ddfc318fc Mon Sep 17 00:00:00 2001
|
|
From: Andrew Lunn <andrew@lunn.ch>
|
|
Date: Sat, 17 Jun 2023 17:55:00 +0200
|
|
Subject: [PATCH] net: phy: Manual remove LEDs to ensure correct ordering
|
|
|
|
If the core is left to remove the LEDs via devm_, it is performed too
|
|
late, after the PHY driver is removed from the PHY. This results in
|
|
dereferencing a NULL pointer when the LED core tries to turn the LED
|
|
off before destroying the LED.
|
|
|
|
Manually unregister the LEDs at a safe point in phy_remove.
|
|
|
|
Cc: stable@vger.kernel.org
|
|
Reported-by: Florian Fainelli <f.fainelli@gmail.com>
|
|
Suggested-by: Florian Fainelli <f.fainelli@gmail.com>
|
|
Fixes: 01e5b728e9e4 ("net: phy: Add a binding for PHY LEDs")
|
|
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
---
|
|
drivers/net/phy/phy_device.c | 15 ++++++++++++++-
|
|
1 file changed, 14 insertions(+), 1 deletion(-)
|
|
|
|
--- a/drivers/net/phy/phy_device.c
|
|
+++ b/drivers/net/phy/phy_device.c
|
|
@@ -3068,6 +3068,15 @@ static int phy_led_blink_set(struct led_
|
|
return err;
|
|
}
|
|
|
|
+static void phy_leds_unregister(struct phy_device *phydev)
|
|
+{
|
|
+ struct phy_led *phyled;
|
|
+
|
|
+ list_for_each_entry(phyled, &phydev->leds, list) {
|
|
+ led_classdev_unregister(&phyled->led_cdev);
|
|
+ }
|
|
+}
|
|
+
|
|
static int of_phy_led(struct phy_device *phydev,
|
|
struct device_node *led)
|
|
{
|
|
@@ -3101,7 +3110,7 @@ static int of_phy_led(struct phy_device
|
|
init_data.fwnode = of_fwnode_handle(led);
|
|
init_data.devname_mandatory = true;
|
|
|
|
- err = devm_led_classdev_register_ext(dev, cdev, &init_data);
|
|
+ err = led_classdev_register_ext(dev, cdev, &init_data);
|
|
if (err)
|
|
return err;
|
|
|
|
@@ -3130,6 +3139,7 @@ static int of_phy_leds(struct phy_device
|
|
err = of_phy_led(phydev, led);
|
|
if (err) {
|
|
of_node_put(led);
|
|
+ phy_leds_unregister(phydev);
|
|
return err;
|
|
}
|
|
}
|
|
@@ -3335,6 +3345,9 @@ static int phy_remove(struct device *dev
|
|
|
|
cancel_delayed_work_sync(&phydev->state_queue);
|
|
|
|
+ if (IS_ENABLED(CONFIG_PHYLIB_LEDS))
|
|
+ phy_leds_unregister(phydev);
|
|
+
|
|
phydev->state = PHY_DOWN;
|
|
|
|
sfp_bus_del_upstream(phydev->sfp_bus);
|