12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- From c938ab4da0eb1620ae3243b0b24c572ddfc318fc Mon Sep 17 00:00:00 2001
- From: Andrew Lunn <[email protected]>
- 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: [email protected]
- Reported-by: Florian Fainelli <[email protected]>
- Suggested-by: Florian Fainelli <[email protected]>
- Fixes: 01e5b728e9e4 ("net: phy: Add a binding for PHY LEDs")
- Signed-off-by: Andrew Lunn <[email protected]>
- Signed-off-by: David S. Miller <[email protected]>
- ---
- 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
- @@ -3070,6 +3070,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)
- {
- @@ -3103,7 +3112,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;
-
- @@ -3132,6 +3141,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;
- }
- }
- @@ -3337,6 +3347,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);
|