[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230617155500.4005881-1-andrew@lunn.ch>
Date: Sat, 17 Jun 2023 17:55:00 +0200
From: Andrew Lunn <andrew@...n.ch>
To: netdev <netdev@...r.kernel.org>
Cc: Heiner Kallweit <hkallweit1@...il.com>,
ansuelsmth@...il.com,
Russell King <rmk+kernel@...linux.org.uk>,
Andrew Lunn <andrew@...n.ch>,
stable@...r.kernel.org,
Florian Fainelli <f.fainelli@...il.com>
Subject: [PATCH net] 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@...r.kernel.org
Reported-by: Florian Fainelli <f.fainelli@...il.com>
Suggested-by: Florian Fainelli <f.fainelli@...il.com>
Fixes: 01e5b728e9e4 ("net: phy: Add a binding for PHY LEDs")
Signed-off-by: Andrew Lunn <andrew@...n.ch>
---
drivers/net/phy/phy_device.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 17d0d0555a79..53598210be6c 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3021,6 +3021,15 @@ static int phy_led_blink_set(struct led_classdev *led_cdev,
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)
{
@@ -3054,7 +3063,7 @@ static int of_phy_led(struct phy_device *phydev,
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;
@@ -3083,6 +3092,7 @@ static int of_phy_leds(struct phy_device *phydev)
err = of_phy_led(phydev, led);
if (err) {
of_node_put(led);
+ phy_leds_unregister(phydev);
return err;
}
}
@@ -3305,6 +3315,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);
--
2.40.1
Powered by blists - more mailing lists