Skip to content

Commit c938ab4

Browse files
lunndavem330
authored andcommitted
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: 01e5b72 ("net: phy: Add a binding for PHY LEDs") Signed-off-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent eb09fc2 commit c938ab4

File tree

1 file changed

+14
-1
lines changed

1 file changed

+14
-1
lines changed

drivers/net/phy/phy_device.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3021,6 +3021,15 @@ static int phy_led_blink_set(struct led_classdev *led_cdev,
30213021
return err;
30223022
}
30233023

3024+
static void phy_leds_unregister(struct phy_device *phydev)
3025+
{
3026+
struct phy_led *phyled;
3027+
3028+
list_for_each_entry(phyled, &phydev->leds, list) {
3029+
led_classdev_unregister(&phyled->led_cdev);
3030+
}
3031+
}
3032+
30243033
static int of_phy_led(struct phy_device *phydev,
30253034
struct device_node *led)
30263035
{
@@ -3054,7 +3063,7 @@ static int of_phy_led(struct phy_device *phydev,
30543063
init_data.fwnode = of_fwnode_handle(led);
30553064
init_data.devname_mandatory = true;
30563065

3057-
err = devm_led_classdev_register_ext(dev, cdev, &init_data);
3066+
err = led_classdev_register_ext(dev, cdev, &init_data);
30583067
if (err)
30593068
return err;
30603069

@@ -3083,6 +3092,7 @@ static int of_phy_leds(struct phy_device *phydev)
30833092
err = of_phy_led(phydev, led);
30843093
if (err) {
30853094
of_node_put(led);
3095+
phy_leds_unregister(phydev);
30863096
return err;
30873097
}
30883098
}
@@ -3305,6 +3315,9 @@ static int phy_remove(struct device *dev)
33053315

33063316
cancel_delayed_work_sync(&phydev->state_queue);
33073317

3318+
if (IS_ENABLED(CONFIG_PHYLIB_LEDS))
3319+
phy_leds_unregister(phydev);
3320+
33083321
phydev->state = PHY_DOWN;
33093322

33103323
sfp_bus_del_upstream(phydev->sfp_bus);

0 commit comments

Comments
 (0)