Merge tag 'pci-v6.11-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci

Pull pci fixes from Bjorn Helgaas:

- Unregister platform devices for child nodes when stopping a PCI
device, even if the PCI core has already cleared the OF_POPULATED bit
and of_platform_depopulate() doesn't do anything (Bartosz
Golaszewski)

- Rescan the bus from a separate thread so we don't deadlock when
triggering rescan from sysfs (Bartosz Golaszewski)

* tag 'pci-v6.11-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci:
PCI/pwrctl: Rescan bus on a separate thread
PCI: Don't rely on of_platform_depopulate() for reused OF-nodes

+44 -5
+23 -3
drivers/pci/pwrctl/core.c
··· 48 48 return NOTIFY_DONE; 49 49 } 50 50 51 + static void rescan_work_func(struct work_struct *work) 52 + { 53 + struct pci_pwrctl *pwrctl = container_of(work, struct pci_pwrctl, work); 54 + 55 + pci_lock_rescan_remove(); 56 + pci_rescan_bus(to_pci_dev(pwrctl->dev->parent)->bus); 57 + pci_unlock_rescan_remove(); 58 + } 59 + 60 + /** 61 + * pci_pwrctl_init() - Initialize the PCI power control context struct 62 + * 63 + * @pwrctl: PCI power control data 64 + * @dev: Parent device 65 + */ 66 + void pci_pwrctl_init(struct pci_pwrctl *pwrctl, struct device *dev) 67 + { 68 + pwrctl->dev = dev; 69 + INIT_WORK(&pwrctl->work, rescan_work_func); 70 + } 71 + EXPORT_SYMBOL_GPL(pci_pwrctl_init); 72 + 51 73 /** 52 74 * pci_pwrctl_device_set_ready() - Notify the pwrctl subsystem that the PCI 53 75 * device is powered-up and ready to be detected. ··· 96 74 if (ret) 97 75 return ret; 98 76 99 - pci_lock_rescan_remove(); 100 - pci_rescan_bus(to_pci_dev(pwrctl->dev->parent)->bus); 101 - pci_unlock_rescan_remove(); 77 + schedule_work(&pwrctl->work); 102 78 103 79 return 0; 104 80 }
+1 -1
drivers/pci/pwrctl/pci-pwrctl-pwrseq.c
··· 50 50 if (ret) 51 51 return ret; 52 52 53 - data->ctx.dev = dev; 53 + pci_pwrctl_init(&data->ctx, dev); 54 54 55 55 ret = devm_pci_pwrctl_device_set_ready(dev, &data->ctx); 56 56 if (ret)
+17 -1
drivers/pci/remove.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 #include <linux/pci.h> 3 3 #include <linux/module.h> 4 + #include <linux/of.h> 4 5 #include <linux/of_platform.h> 6 + #include <linux/platform_device.h> 7 + 5 8 #include "pci.h" 6 9 7 10 static void pci_free_resources(struct pci_dev *dev) ··· 17 14 } 18 15 } 19 16 17 + static int pci_pwrctl_unregister(struct device *dev, void *data) 18 + { 19 + struct device_node *pci_node = data, *plat_node = dev_of_node(dev); 20 + 21 + if (dev_is_platform(dev) && plat_node && plat_node == pci_node) { 22 + of_device_unregister(to_platform_device(dev)); 23 + of_node_clear_flag(plat_node, OF_POPULATED); 24 + } 25 + 26 + return 0; 27 + } 28 + 20 29 static void pci_stop_dev(struct pci_dev *dev) 21 30 { 22 31 pci_pme_active(dev, false); 23 32 24 33 if (pci_dev_is_added(dev)) { 25 - of_platform_depopulate(&dev->dev); 34 + device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev), 35 + pci_pwrctl_unregister); 26 36 device_release_driver(&dev->dev); 27 37 pci_proc_detach_device(dev); 28 38 pci_remove_sysfs_dev_files(dev);
+3
include/linux/pci-pwrctl.h
··· 7 7 #define __PCI_PWRCTL_H__ 8 8 9 9 #include <linux/notifier.h> 10 + #include <linux/workqueue.h> 10 11 11 12 struct device; 12 13 struct device_link; ··· 42 41 /* Private: don't use. */ 43 42 struct notifier_block nb; 44 43 struct device_link *link; 44 + struct work_struct work; 45 45 }; 46 46 47 + void pci_pwrctl_init(struct pci_pwrctl *pwrctl, struct device *dev); 47 48 int pci_pwrctl_device_set_ready(struct pci_pwrctl *pwrctl); 48 49 void pci_pwrctl_device_unset_ready(struct pci_pwrctl *pwrctl); 49 50 int devm_pci_pwrctl_device_set_ready(struct device *dev,