]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
PCI: Don't rely on of_platform_depopulate() for reused OF-nodes
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Fri, 23 Aug 2024 09:33:22 +0000 (11:33 +0200)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 3 Sep 2024 22:10:57 +0000 (17:10 -0500)
of_platform_depopulate() doesn't play nicely with reused OF nodes - it
ignores the ones that are not marked explicitly as populated and it may
happen that the PCI device goes away before the platform device in which
case the PCI core clears the OF_POPULATED bit.

Unconditionally unregister the platform devices for child nodes when
stopping the PCI device.

Link: https://lore.kernel.org/r/20240823093323.33450-2-brgl@bgdev.pl
Fixes: 8fb18619d910 ("PCI/pwrctl: Create platform devices for child OF nodes of the port node")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
drivers/pci/remove.c

index 910387e5bdbf985a3f1fa3184348e7d0bc8cb524..4770cb87e3f0a1acd32a835c2c5fc0bc7aba208c 100644 (file)
@@ -1,7 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
 #include "pci.h"
 
 static void pci_free_resources(struct pci_dev *dev)
@@ -14,12 +17,25 @@ static void pci_free_resources(struct pci_dev *dev)
        }
 }
 
+static int pci_pwrctl_unregister(struct device *dev, void *data)
+{
+       struct device_node *pci_node = data, *plat_node = dev_of_node(dev);
+
+       if (dev_is_platform(dev) && plat_node && plat_node == pci_node) {
+               of_device_unregister(to_platform_device(dev));
+               of_node_clear_flag(plat_node, OF_POPULATED);
+       }
+
+       return 0;
+}
+
 static void pci_stop_dev(struct pci_dev *dev)
 {
        pci_pme_active(dev, false);
 
        if (pci_dev_is_added(dev)) {
-               of_platform_depopulate(&dev->dev);
+               device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev),
+                                     pci_pwrctl_unregister);
                device_release_driver(&dev->dev);
                pci_proc_detach_device(dev);
                pci_remove_sysfs_dev_files(dev);