Skip to content

Commit a47ccc7

Browse files
authored
PCI/pwrctrl: Do not try to power on/off devices that don't need pwrctrl (#480)
PCI/pwrctrl: Do not try to power on/off devices that don't need pwrctrl
2 parents 796722c + d549eaf commit a47ccc7

2 files changed

Lines changed: 50 additions & 1 deletion

File tree

drivers/pci/pwrctrl/core.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/export.h>
1010
#include <linux/kernel.h>
1111
#include <linux/of.h>
12+
#include <linux/of_graph.h>
1213
#include <linux/of_platform.h>
1314
#include <linux/pci.h>
1415
#include <linux/pci-pwrctrl.h>
@@ -138,6 +139,48 @@ int devm_pci_pwrctrl_device_set_ready(struct device *dev,
138139
}
139140
EXPORT_SYMBOL_GPL(devm_pci_pwrctrl_device_set_ready);
140141

142+
/*
143+
* Check whether the pwrctrl device really needs to be created or not. The
144+
* pwrctrl device will only be created if the node satisfies below requirements:
145+
*
146+
* 1. Presence of compatible property with "pci" prefix to match against the
147+
* pwrctrl driver (AND)
148+
* 2. At least one of the power supplies defined in the devicetree node of the
149+
* device (OR) in the remote endpoint parent node to indicate pwrctrl
150+
* requirement.
151+
*/
152+
static bool pci_pwrctrl_is_required(struct device_node *np)
153+
{
154+
struct device_node *endpoint;
155+
const char *compat;
156+
int ret;
157+
158+
ret = of_property_read_string(np, "compatible", &compat);
159+
if (ret < 0)
160+
return false;
161+
162+
if (!strstarts(compat, "pci"))
163+
return false;
164+
165+
if (of_pci_supply_present(np))
166+
return true;
167+
168+
if (of_graph_is_present(np)) {
169+
for_each_endpoint_of_node(np, endpoint) {
170+
struct device_node *remote __free(device_node) =
171+
of_graph_get_remote_port_parent(endpoint);
172+
if (remote) {
173+
if (of_pci_supply_present(remote)) {
174+
of_node_put(endpoint);
175+
return true;
176+
}
177+
}
178+
}
179+
}
180+
181+
return false;
182+
}
183+
141184
static int __pci_pwrctrl_power_off_device(struct device *dev)
142185
{
143186
struct pci_pwrctrl *pwrctrl = dev_get_drvdata(dev);
@@ -156,6 +199,9 @@ static void pci_pwrctrl_power_off_device(struct device_node *np)
156199
for_each_available_child_of_node_scoped(np, child)
157200
pci_pwrctrl_power_off_device(child);
158201

202+
if (!pci_pwrctrl_is_required(np))
203+
return;
204+
159205
pdev = of_find_device_by_node(np);
160206
if (!pdev)
161207
return;
@@ -212,6 +258,9 @@ static int pci_pwrctrl_power_on_device(struct device_node *np)
212258
return ret;
213259
}
214260

261+
if (!pci_pwrctrl_is_required(np))
262+
return 0;
263+
215264
pdev = of_find_device_by_node(np);
216265
if (!pdev)
217266
return 0;

include/linux/pci-pwrctrl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwrctrl);
5454
void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl);
5555
int devm_pci_pwrctrl_device_set_ready(struct device *dev,
5656
struct pci_pwrctrl *pwrctrl);
57-
#if IS_ENABLED(CONFIG_PCI_PWRCTRL)
57+
#if IS_REACHABLE(CONFIG_PCI_PWRCTRL)
5858
int pci_pwrctrl_create_devices(struct device *parent);
5959
void pci_pwrctrl_destroy_devices(struct device *parent);
6060
int pci_pwrctrl_power_on_devices(struct device *parent);

0 commit comments

Comments
 (0)