On 05.04.2024 21:16, Lukas Wunner wrote: > On Fri, Apr 05, 2024 at 07:48:08PM +0200, Lukas Wunner wrote: >> Roman, does the below patch fix the issue? > > Actually the patch in my previous e-mail was crap as the unregistering > of the LEDs happened after unbind of the pdev, i.e. after > igc_release_hw_control() and pci_disable_device(). > For r8169 the first version is sufficient because everything is device-managed. > The driver otherwise doesn't seem to be using devm_*() and with > devm_*() it's always all or nothing. A mix of devm_*() and manual > teardown is prone to ordering issues. > > Here's another attempt: > > -- >8 -- > > diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h > index 90316dc58630..f9ffe9df9a96 100644 > --- a/drivers/net/ethernet/intel/igc/igc.h > +++ b/drivers/net/ethernet/intel/igc/igc.h > @@ -298,6 +298,7 @@ struct igc_adapter { > > /* LEDs */ > struct mutex led_mutex; > + struct igc_led_classdev *leds; > }; > > void igc_up(struct igc_adapter *adapter); > @@ -723,6 +724,7 @@ void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts); > void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter); > > int igc_led_setup(struct igc_adapter *adapter); > +void igc_led_teardown(struct igc_adapter *adapter); > > #define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring)) > > diff --git a/drivers/net/ethernet/intel/igc/igc_leds.c b/drivers/net/ethernet/intel/igc/igc_leds.c > index bf240c5daf86..4c2806c0878a 100644 > --- a/drivers/net/ethernet/intel/igc/igc_leds.c > +++ b/drivers/net/ethernet/intel/igc/igc_leds.c > @@ -236,8 +236,8 @@ static void igc_led_get_name(struct igc_adapter *adapter, int index, char *buf, > pci_dev_id(adapter->pdev), index); > } > > -static void igc_setup_ldev(struct igc_led_classdev *ldev, > - struct net_device *netdev, int index) > +static int igc_setup_ldev(struct igc_led_classdev *ldev, > + struct net_device *netdev, int index) > { > struct igc_adapter *adapter = netdev_priv(netdev); > struct led_classdev *led_cdev = &ldev->led; > @@ -257,15 +257,15 @@ static void igc_setup_ldev(struct igc_led_classdev *ldev, > led_cdev->hw_control_get = igc_led_hw_control_get; > led_cdev->hw_control_get_device = igc_led_hw_control_get_device; > > - devm_led_classdev_register(&netdev->dev, led_cdev); > + return led_classdev_register(&netdev->dev, led_cdev); > } > > int igc_led_setup(struct igc_adapter *adapter) > { > struct net_device *netdev = adapter->netdev; > - struct device *dev = &netdev->dev; > + struct device *dev = &adapter->pdev->dev; > struct igc_led_classdev *leds; > - int i; > + int i, ret; > > mutex_init(&adapter->led_mutex); > > @@ -273,8 +273,27 @@ int igc_led_setup(struct igc_adapter *adapter) > if (!leds) > return -ENOMEM; > > - for (i = 0; i < IGC_NUM_LEDS; i++) > - igc_setup_ldev(leds + i, netdev, i); > + for (i = 0; i < IGC_NUM_LEDS; i++) { > + ret = igc_setup_ldev(leds + i, netdev, i); > + if (ret) > + goto err; > + } > + > + adapter->leds = leds; > > return 0; > + > +err: > + for (i--; i >= 0; i--) > + led_classdev_unregister(&((leds + i)->led)); > + return ret; > +} > + > +void igc_led_teardown(struct igc_adapter *adapter) > +{ > + struct igc_led_classdev *leds = adapter->leds; > + int i; > + > + for (i = 0; i < IGC_NUM_LEDS; i++) > + led_classdev_unregister(&((leds + i)->led)); > } > diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c > index 2e1cfbd82f4f..cd164442ab35 100644 > --- a/drivers/net/ethernet/intel/igc/igc_main.c > +++ b/drivers/net/ethernet/intel/igc/igc_main.c > @@ -7025,6 +7025,9 @@ static void igc_remove(struct pci_dev *pdev) > cancel_work_sync(&adapter->watchdog_task); > hrtimer_cancel(&adapter->hrtimer); > > + if (IS_ENABLED(CONFIG_IGC_LEDS)) > + igc_led_teardown(adapter); > + > /* Release control of h/w to f/w. If f/w is AMT enabled, this > * would have already happened in close and is redundant. > */ >