Skip to content

Commit

Permalink
Merge branch 'pci/pwrctl'
Browse files Browse the repository at this point in the history
- Use of_platform_device_create() instead of of_platform_populate() to
  create pwrctl platform devices so we can control it based on the child
  nodes (Manivannan Sadhasivam)

- Create pwrctrl platform devices only if there's a relevant power supply
  property (Manivannan Sadhasivam)

- Add device link from the pwrctl supplier to the PCI dev to ensure pwrctl
  drivers are probed before the PCI dev driver; this avoids a race where
  pwrctl could change device power state while the PCI driver was active
  (Manivannan Sadhasivam)

- Find pwrctl device for removal with of_find_device_by_node() instead of
  searching all children of the parent (Manivannan Sadhasivam)

- Rename 'pwrctl' to 'pwrctrl' to use the same 'ctrl' suffix as 'bwctrl'
  and other PCI files to reduce confusion (Bjorn Helgaas)

* pci/pwrctl:
  PCI/pwrctrl: Rename pwrctrl functions and structures
  PCI/pwrctrl: Rename pwrctl files to pwrctrl
  PCI/pwrctl: Remove pwrctl device without iterating over all children of pwrctl parent
  PCI/pwrctl: Ensure that pwrctl drivers are probed before PCI client drivers
  PCI/pwrctl: Create pwrctl device only if at least one power supply is present
  PCI/pwrctl: Use of_platform_device_create() to create pwrctl devices

# Conflicts:
#	drivers/pci/bus.c
#	drivers/pci/remove.c
  • Loading branch information
bjorn-helgaas committed Nov 25, 2024
2 parents 95e9303 + 3f925cd commit ce1deca
Show file tree
Hide file tree
Showing 14 changed files with 285 additions and 212 deletions.
4 changes: 2 additions & 2 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -17916,8 +17916,8 @@ M: Bartosz Golaszewski <[email protected]>
L: [email protected]
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git
F: drivers/pci/pwrctl/*
F: include/linux/pci-pwrctl.h
F: drivers/pci/pwrctrl/*
F: include/linux/pci-pwrctrl.h

PCI SUBSYSTEM
M: Bjorn Helgaas <[email protected]>
Expand Down
2 changes: 1 addition & 1 deletion drivers/pci/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,6 @@ source "drivers/pci/hotplug/Kconfig"
source "drivers/pci/controller/Kconfig"
source "drivers/pci/endpoint/Kconfig"
source "drivers/pci/switch/Kconfig"
source "drivers/pci/pwrctl/Kconfig"
source "drivers/pci/pwrctrl/Kconfig"

endif
2 changes: 1 addition & 1 deletion drivers/pci/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \

obj-$(CONFIG_PCI) += msi/
obj-$(CONFIG_PCI) += pcie/
obj-$(CONFIG_PCI) += pwrctl/
obj-$(CONFIG_PCI) += pwrctrl/

ifdef CONFIG_PCI
obj-$(CONFIG_PROC_FS) += proc.o
Expand Down
67 changes: 59 additions & 8 deletions drivers/pci/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>

Expand Down Expand Up @@ -330,6 +331,47 @@ void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }

void __weak pcibios_bus_add_device(struct pci_dev *pdev) { }

/*
* Create pwrctrl devices (if required) for the PCI devices to handle the power
* state.
*/
static void pci_pwrctrl_create_devices(struct pci_dev *dev)
{
struct device_node *np = dev_of_node(&dev->dev);
struct device *parent = &dev->dev;
struct platform_device *pdev;

/*
* First ensure that we are starting from a PCI bridge and it has a
* corresponding devicetree node.
*/
if (np && pci_is_bridge(dev)) {
/*
* Now look for the child PCI device nodes and create pwrctrl
* devices for them. The pwrctrl device drivers will manage the
* power state of the devices.
*/
for_each_available_child_of_node_scoped(np, child) {
/*
* First check whether the pwrctrl device really
* needs to be created or not. This is decided
* based on at least one of the power supplies
* being defined in the devicetree node of the
* device.
*/
if (!of_pci_supply_present(child)) {
pci_dbg(dev, "skipping OF node: %s\n", child->name);
return;
}

/* Now create the pwrctrl device */
pdev = of_platform_device_create(child, NULL, parent);
if (!pdev)
pci_err(dev, "failed to create OF node: %s\n", child->name);
}
}
}

/**
* pci_bus_add_device - start driver for a single device
* @dev: device to add
Expand All @@ -339,6 +381,7 @@ void __weak pcibios_bus_add_device(struct pci_dev *pdev) { }
void pci_bus_add_device(struct pci_dev *dev)
{
struct device_node *dn = dev->dev.of_node;
struct platform_device *pdev;
int retval;

/*
Expand All @@ -353,20 +396,28 @@ void pci_bus_add_device(struct pci_dev *dev)
pci_proc_attach_device(dev);
pci_bridge_d3_update(dev);

pci_pwrctrl_create_devices(dev);

/*
* If the PCI device is associated with a pwrctrl device with a
* power supply, create a device link between the PCI device and
* pwrctrl device. This ensures that pwrctrl drivers are probed
* before PCI client drivers.
*/
pdev = of_find_device_by_node(dn);
if (pdev && of_pci_supply_present(dn)) {
if (!device_link_add(&dev->dev, &pdev->dev,
DL_FLAG_AUTOREMOVE_CONSUMER))
pci_err(dev, "failed to add device link to power control device %s\n",
pdev->name);
}

dev->match_driver = !dn || of_device_is_available(dn);
retval = device_attach(&dev->dev);
if (retval < 0 && retval != -EPROBE_DEFER)
pci_warn(dev, "device attach failed (%d)\n", retval);

pci_dev_assign_added(dev);

if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL,
&dev->dev);
if (retval)
pci_err(dev, "failed to populate child OF nodes (%d)\n",
retval);
}
}
EXPORT_SYMBOL_GPL(pci_bus_add_device);

Expand Down
27 changes: 27 additions & 0 deletions drivers/pci/of.c
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,33 @@ void of_pci_make_dev_node(struct pci_dev *pdev)
}
#endif

/**
* of_pci_supply_present() - Check if the power supply is present for the PCI
* device
* @np: Device tree node
*
* Check if the power supply for the PCI device is present in the device tree
* node or not.
*
* Return: true if at least one power supply exists; false otherwise.
*/
bool of_pci_supply_present(struct device_node *np)
{
struct property *prop;
char *supply;

if (!np)
return false;

for_each_property_of_node(np, prop) {
supply = strrchr(prop->name, '-');
if (supply && !strcmp(supply, "-supply"))
return true;
}

return false;
}

#endif /* CONFIG_PCI */

/**
Expand Down
5 changes: 5 additions & 0 deletions drivers/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,7 @@ void pci_set_bus_of_node(struct pci_bus *bus);
void pci_release_bus_of_node(struct pci_bus *bus);

int devm_of_pci_bridge_init(struct device *dev, struct pci_host_bridge *bridge);
bool of_pci_supply_present(struct device_node *np);

#else
static inline int
Expand Down Expand Up @@ -844,6 +845,10 @@ static inline int devm_of_pci_bridge_init(struct device *dev, struct pci_host_br
return 0;
}

static inline bool of_pci_supply_present(struct device_node *np)
{
return false;
}
#endif /* CONFIG_OF */

struct of_changeset;
Expand Down
6 changes: 0 additions & 6 deletions drivers/pci/pwrctl/Makefile

This file was deleted.

157 changes: 0 additions & 157 deletions drivers/pci/pwrctl/core.c

This file was deleted.

File renamed without changes.
6 changes: 6 additions & 0 deletions drivers/pci/pwrctrl/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only

obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctrl-core.o
pci-pwrctrl-core-y := core.o

obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctrl-pwrseq.o
Loading

0 comments on commit ce1deca

Please sign in to comment.