Commit f1536585 authored by Bartosz Golaszewski's avatar Bartosz Golaszewski Committed by Bjorn Helgaas

PCI: Don't rely on of_platform_depopulate() for reused OF-nodes

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: 8fb18619 ("PCI/pwrctl: Create platform devices for child OF nodes of the port node")
Signed-off-by: default avatarBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Acked-by: default avatarManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
parent 8400291e
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h>
#include "pci.h" #include "pci.h"
static void pci_free_resources(struct pci_dev *dev) static void pci_free_resources(struct pci_dev *dev)
...@@ -14,12 +17,25 @@ 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) static void pci_stop_dev(struct pci_dev *dev)
{ {
pci_pme_active(dev, false); pci_pme_active(dev, false);
if (pci_dev_is_added(dev)) { 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); device_release_driver(&dev->dev);
pci_proc_detach_device(dev); pci_proc_detach_device(dev);
pci_remove_sysfs_dev_files(dev); pci_remove_sysfs_dev_files(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment