]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - drivers/net/ethernet/realtek/r8169_leds.c
r8169: fix LED-related deadlock on module removal
[thirdparty/kernel/stable.git] / drivers / net / ethernet / realtek / r8169_leds.c
index 7c5dc9d0df855ef57592b7a25d4357232279a60f..e10bee706bc691b8c32ec2410baa8d4279de69a0 100644 (file)
@@ -146,22 +146,22 @@ static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev,
        led_cdev->hw_control_get_device = r8169_led_hw_control_get_device;
 
        /* ignore errors */
-       devm_led_classdev_register(&ndev->dev, led_cdev);
+       led_classdev_register(&ndev->dev, led_cdev);
 }
 
-void rtl8168_init_leds(struct net_device *ndev)
+struct r8169_led_classdev *rtl8168_init_leds(struct net_device *ndev)
 {
-       /* bind resource mgmt to netdev */
-       struct device *dev = &ndev->dev;
        struct r8169_led_classdev *leds;
        int i;
 
-       leds = devm_kcalloc(dev, RTL8168_NUM_LEDS, sizeof(*leds), GFP_KERNEL);
+       leds = kcalloc(RTL8168_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL);
        if (!leds)
-               return;
+               return NULL;
 
        for (i = 0; i < RTL8168_NUM_LEDS; i++)
                rtl8168_setup_ldev(leds + i, ndev, i);
+
+       return leds;
 }
 
 static int rtl8125_led_hw_control_is_supported(struct led_classdev *led_cdev,
@@ -245,20 +245,31 @@ static void rtl8125_setup_led_ldev(struct r8169_led_classdev *ldev,
        led_cdev->hw_control_get_device = r8169_led_hw_control_get_device;
 
        /* ignore errors */
-       devm_led_classdev_register(&ndev->dev, led_cdev);
+       led_classdev_register(&ndev->dev, led_cdev);
 }
 
-void rtl8125_init_leds(struct net_device *ndev)
+struct r8169_led_classdev *rtl8125_init_leds(struct net_device *ndev)
 {
-       /* bind resource mgmt to netdev */
-       struct device *dev = &ndev->dev;
        struct r8169_led_classdev *leds;
        int i;
 
-       leds = devm_kcalloc(dev, RTL8125_NUM_LEDS, sizeof(*leds), GFP_KERNEL);
+       leds = kcalloc(RTL8125_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL);
        if (!leds)
-               return;
+               return NULL;
 
        for (i = 0; i < RTL8125_NUM_LEDS; i++)
                rtl8125_setup_led_ldev(leds + i, ndev, i);
+
+       return leds;
+}
+
+void r8169_remove_leds(struct r8169_led_classdev *leds)
+{
+       if (!leds)
+               return;
+
+       for (struct r8169_led_classdev *l = leds; l->ndev; l++)
+               led_classdev_unregister(&l->led);
+
+       kfree(leds);
 }