Skip to content

Commit 6a900f8

Browse files
committed
Merge branches 'pm-domains' and 'pm-tools'
Additional updates of the generic power domains (genpd) framework (support for devices attached to multiple domains) and the cpupower utility (minor fixes) for 4.18-rc1. * pm-domains: PM / Domains: Add dev_pm_domain_attach_by_id() to manage multi PM domains PM / Domains: Add support for multi PM domains per device to genpd PM / Domains: Split genpd_dev_pm_attach() PM / Domains: Don't attach devices in genpd with multi PM domains PM / Domains: dt: Allow power-domain property to be a list of specifiers * pm-tools: cpupower : Fix header name to read idle state name cpupower: fix spelling mistake: "logilename" -> "logfilename"
3 parents 2652df3 + 82e12d9 + 5202e32 commit 6a900f8

File tree

8 files changed

+228
-44
lines changed

8 files changed

+228
-44
lines changed

Documentation/devicetree/bindings/power/power_domain.txt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ Example 3:
111111
==PM domain consumers==
112112

113113
Required properties:
114-
- power-domains : A phandle and PM domain specifier as defined by bindings of
115-
the power controller specified by phandle.
114+
- power-domains : A list of PM domain specifiers, as defined by bindings of
115+
the power controller that is the PM domain provider.
116116

117117
Example:
118118

@@ -122,9 +122,18 @@ Example:
122122
power-domains = <&power 0>;
123123
};
124124

125-
The node above defines a typical PM domain consumer device, which is located
126-
inside a PM domain with index 0 of a power controller represented by a node
127-
with the label "power".
125+
leaky-device@12351000 {
126+
compatible = "foo,i-leak-current";
127+
reg = <0x12351000 0x1000>;
128+
power-domains = <&power 0>, <&power 1> ;
129+
};
130+
131+
The first example above defines a typical PM domain consumer device, which is
132+
located inside a PM domain with index 0 of a power controller represented by a
133+
node with the label "power".
134+
In the second example the consumer device are partitioned across two PM domains,
135+
the first with index 0 and the second with index 1, of a power controller that
136+
is represented by a node with the label "power.
128137

129138
Optional properties:
130139
- required-opps: This contains phandle to an OPP node in another device's OPP

drivers/base/power/common.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,51 @@ int dev_pm_domain_attach(struct device *dev, bool power_on)
116116
}
117117
EXPORT_SYMBOL_GPL(dev_pm_domain_attach);
118118

119+
/**
120+
* dev_pm_domain_attach_by_id - Associate a device with one of its PM domains.
121+
* @dev: The device used to lookup the PM domain.
122+
* @index: The index of the PM domain.
123+
*
124+
* As @dev may only be attached to a single PM domain, the backend PM domain
125+
* provider creates a virtual device to attach instead. If attachment succeeds,
126+
* the ->detach() callback in the struct dev_pm_domain are assigned by the
127+
* corresponding backend attach function, as to deal with detaching of the
128+
* created virtual device.
129+
*
130+
* This function should typically be invoked by a driver during the probe phase,
131+
* in case its device requires power management through multiple PM domains. The
132+
* driver may benefit from using the received device, to configure device-links
133+
* towards its original device. Depending on the use-case and if needed, the
134+
* links may be dynamically changed by the driver, which allows it to control
135+
* the power to the PM domains independently from each other.
136+
*
137+
* Callers must ensure proper synchronization of this function with power
138+
* management callbacks.
139+
*
140+
* Returns the virtual created device when successfully attached to its PM
141+
* domain, NULL in case @dev don't need a PM domain, else an ERR_PTR().
142+
* Note that, to detach the returned virtual device, the driver shall call
143+
* dev_pm_domain_detach() on it, typically during the remove phase.
144+
*/
145+
struct device *dev_pm_domain_attach_by_id(struct device *dev,
146+
unsigned int index)
147+
{
148+
if (dev->pm_domain)
149+
return ERR_PTR(-EEXIST);
150+
151+
return genpd_dev_pm_attach_by_id(dev, index);
152+
}
153+
EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_id);
154+
119155
/**
120156
* dev_pm_domain_detach - Detach a device from its PM domain.
121157
* @dev: Device to detach.
122158
* @power_off: Used to indicate whether we should power off the device.
123159
*
124-
* This functions will reverse the actions from dev_pm_domain_attach() and thus
125-
* try to detach the @dev from its PM domain. Typically it should be invoked
126-
* from subsystem level code during the remove phase.
160+
* This functions will reverse the actions from dev_pm_domain_attach() and
161+
* dev_pm_domain_attach_by_id(), thus it detaches @dev from its PM domain.
162+
* Typically it should be invoked during the remove phase, either from
163+
* subsystem level code or from drivers.
127164
*
128165
* Callers must ensure proper synchronization of this function with power
129166
* management callbacks.

drivers/base/power/domain.c

Lines changed: 114 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2171,6 +2171,15 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
21712171
}
21722172
EXPORT_SYMBOL_GPL(of_genpd_remove_last);
21732173

2174+
static void genpd_release_dev(struct device *dev)
2175+
{
2176+
kfree(dev);
2177+
}
2178+
2179+
static struct bus_type genpd_bus_type = {
2180+
.name = "genpd",
2181+
};
2182+
21742183
/**
21752184
* genpd_dev_pm_detach - Detach a device from its PM domain.
21762185
* @dev: Device to detach.
@@ -2208,6 +2217,10 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
22082217

22092218
/* Check if PM domain can be powered off after removing this device. */
22102219
genpd_queue_power_off_work(pd);
2220+
2221+
/* Unregister the device if it was created by genpd. */
2222+
if (dev->bus == &genpd_bus_type)
2223+
device_unregister(dev);
22112224
}
22122225

22132226
static void genpd_dev_pm_sync(struct device *dev)
@@ -2221,32 +2234,17 @@ static void genpd_dev_pm_sync(struct device *dev)
22212234
genpd_queue_power_off_work(pd);
22222235
}
22232236

2224-
/**
2225-
* genpd_dev_pm_attach - Attach a device to its PM domain using DT.
2226-
* @dev: Device to attach.
2227-
*
2228-
* Parse device's OF node to find a PM domain specifier. If such is found,
2229-
* attaches the device to retrieved pm_domain ops.
2230-
*
2231-
* Returns 1 on successfully attached PM domain, 0 when the device don't need a
2232-
* PM domain or a negative error code in case of failures. Note that if a
2233-
* power-domain exists for the device, but it cannot be found or turned on,
2234-
* then return -EPROBE_DEFER to ensure that the device is not probed and to
2235-
* re-try again later.
2236-
*/
2237-
int genpd_dev_pm_attach(struct device *dev)
2237+
static int __genpd_dev_pm_attach(struct device *dev, struct device_node *np,
2238+
unsigned int index)
22382239
{
22392240
struct of_phandle_args pd_args;
22402241
struct generic_pm_domain *pd;
22412242
int ret;
22422243

2243-
if (!dev->of_node)
2244-
return 0;
2245-
2246-
ret = of_parse_phandle_with_args(dev->of_node, "power-domains",
2247-
"#power-domain-cells", 0, &pd_args);
2244+
ret = of_parse_phandle_with_args(np, "power-domains",
2245+
"#power-domain-cells", index, &pd_args);
22482246
if (ret < 0)
2249-
return 0;
2247+
return ret;
22502248

22512249
mutex_lock(&gpd_list_lock);
22522250
pd = genpd_get_from_provider(&pd_args);
@@ -2282,8 +2280,98 @@ int genpd_dev_pm_attach(struct device *dev)
22822280

22832281
return ret ? -EPROBE_DEFER : 1;
22842282
}
2283+
2284+
/**
2285+
* genpd_dev_pm_attach - Attach a device to its PM domain using DT.
2286+
* @dev: Device to attach.
2287+
*
2288+
* Parse device's OF node to find a PM domain specifier. If such is found,
2289+
* attaches the device to retrieved pm_domain ops.
2290+
*
2291+
* Returns 1 on successfully attached PM domain, 0 when the device don't need a
2292+
* PM domain or when multiple power-domains exists for it, else a negative error
2293+
* code. Note that if a power-domain exists for the device, but it cannot be
2294+
* found or turned on, then return -EPROBE_DEFER to ensure that the device is
2295+
* not probed and to re-try again later.
2296+
*/
2297+
int genpd_dev_pm_attach(struct device *dev)
2298+
{
2299+
if (!dev->of_node)
2300+
return 0;
2301+
2302+
/*
2303+
* Devices with multiple PM domains must be attached separately, as we
2304+
* can only attach one PM domain per device.
2305+
*/
2306+
if (of_count_phandle_with_args(dev->of_node, "power-domains",
2307+
"#power-domain-cells") != 1)
2308+
return 0;
2309+
2310+
return __genpd_dev_pm_attach(dev, dev->of_node, 0);
2311+
}
22852312
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
22862313

2314+
/**
2315+
* genpd_dev_pm_attach_by_id - Associate a device with one of its PM domains.
2316+
* @dev: The device used to lookup the PM domain.
2317+
* @index: The index of the PM domain.
2318+
*
2319+
* Parse device's OF node to find a PM domain specifier at the provided @index.
2320+
* If such is found, creates a virtual device and attaches it to the retrieved
2321+
* pm_domain ops. To deal with detaching of the virtual device, the ->detach()
2322+
* callback in the struct dev_pm_domain are assigned to genpd_dev_pm_detach().
2323+
*
2324+
* Returns the created virtual device if successfully attached PM domain, NULL
2325+
* when the device don't need a PM domain, else an ERR_PTR() in case of
2326+
* failures. If a power-domain exists for the device, but cannot be found or
2327+
* turned on, then ERR_PTR(-EPROBE_DEFER) is returned to ensure that the device
2328+
* is not probed and to re-try again later.
2329+
*/
2330+
struct device *genpd_dev_pm_attach_by_id(struct device *dev,
2331+
unsigned int index)
2332+
{
2333+
struct device *genpd_dev;
2334+
int num_domains;
2335+
int ret;
2336+
2337+
if (!dev->of_node)
2338+
return NULL;
2339+
2340+
/* Deal only with devices using multiple PM domains. */
2341+
num_domains = of_count_phandle_with_args(dev->of_node, "power-domains",
2342+
"#power-domain-cells");
2343+
if (num_domains < 2 || index >= num_domains)
2344+
return NULL;
2345+
2346+
/* Allocate and register device on the genpd bus. */
2347+
genpd_dev = kzalloc(sizeof(*genpd_dev), GFP_KERNEL);
2348+
if (!genpd_dev)
2349+
return ERR_PTR(-ENOMEM);
2350+
2351+
dev_set_name(genpd_dev, "genpd:%u:%s", index, dev_name(dev));
2352+
genpd_dev->bus = &genpd_bus_type;
2353+
genpd_dev->release = genpd_release_dev;
2354+
2355+
ret = device_register(genpd_dev);
2356+
if (ret) {
2357+
kfree(genpd_dev);
2358+
return ERR_PTR(ret);
2359+
}
2360+
2361+
/* Try to attach the device to the PM domain at the specified index. */
2362+
ret = __genpd_dev_pm_attach(genpd_dev, dev->of_node, index);
2363+
if (ret < 1) {
2364+
device_unregister(genpd_dev);
2365+
return ret ? ERR_PTR(ret) : NULL;
2366+
}
2367+
2368+
pm_runtime_set_active(genpd_dev);
2369+
pm_runtime_enable(genpd_dev);
2370+
2371+
return genpd_dev;
2372+
}
2373+
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach_by_id);
2374+
22872375
static const struct of_device_id idle_state_match[] = {
22882376
{ .compatible = "domain-idle-state", },
22892377
{ }
@@ -2443,6 +2531,12 @@ unsigned int of_genpd_opp_to_performance_state(struct device *dev,
24432531
}
24442532
EXPORT_SYMBOL_GPL(of_genpd_opp_to_performance_state);
24452533

2534+
static int __init genpd_bus_init(void)
2535+
{
2536+
return bus_register(&genpd_bus_type);
2537+
}
2538+
core_initcall(genpd_bus_init);
2539+
24462540
#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
24472541

24482542

include/linux/pm_domain.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ unsigned int of_genpd_opp_to_performance_state(struct device *dev,
237237
struct device_node *opp_node);
238238

239239
int genpd_dev_pm_attach(struct device *dev);
240+
struct device *genpd_dev_pm_attach_by_id(struct device *dev,
241+
unsigned int index);
240242
#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
241243
static inline int of_genpd_add_provider_simple(struct device_node *np,
242244
struct generic_pm_domain *genpd)
@@ -282,6 +284,12 @@ static inline int genpd_dev_pm_attach(struct device *dev)
282284
return 0;
283285
}
284286

287+
static inline struct device *genpd_dev_pm_attach_by_id(struct device *dev,
288+
unsigned int index)
289+
{
290+
return NULL;
291+
}
292+
285293
static inline
286294
struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
287295
{
@@ -291,13 +299,20 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
291299

292300
#ifdef CONFIG_PM
293301
int dev_pm_domain_attach(struct device *dev, bool power_on);
302+
struct device *dev_pm_domain_attach_by_id(struct device *dev,
303+
unsigned int index);
294304
void dev_pm_domain_detach(struct device *dev, bool power_off);
295305
void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd);
296306
#else
297307
static inline int dev_pm_domain_attach(struct device *dev, bool power_on)
298308
{
299309
return 0;
300310
}
311+
static inline struct device *dev_pm_domain_attach_by_id(struct device *dev,
312+
unsigned int index)
313+
{
314+
return NULL;
315+
}
301316
static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {}
302317
static inline void dev_pm_domain_set(struct device *dev,
303318
struct dev_pm_domain *pd) {}

tools/power/cpupower/bench/parse.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ FILE *prepare_output(const char *dirname)
104104
dirname, time(NULL));
105105
}
106106

107-
dprintf("logilename: %s\n", filename);
107+
dprintf("logfilename: %s\n", filename);
108108

109109
output = fopen(filename, "w+");
110110
if (output == NULL) {

tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,20 @@ void fix_up_intel_idle_driver_name(char *tmp, int num)
126126
}
127127
}
128128

129+
#ifdef __powerpc__
130+
void map_power_idle_state_name(char *tmp)
131+
{
132+
if (!strncmp(tmp, "stop0_lite", CSTATE_NAME_LEN))
133+
strcpy(tmp, "stop0L");
134+
else if (!strncmp(tmp, "stop1_lite", CSTATE_NAME_LEN))
135+
strcpy(tmp, "stop1L");
136+
else if (!strncmp(tmp, "stop2_lite", CSTATE_NAME_LEN))
137+
strcpy(tmp, "stop2L");
138+
}
139+
#else
140+
void map_power_idle_state_name(char *tmp) { }
141+
#endif
142+
129143
static struct cpuidle_monitor *cpuidle_register(void)
130144
{
131145
int num;
@@ -145,6 +159,7 @@ static struct cpuidle_monitor *cpuidle_register(void)
145159
if (tmp == NULL)
146160
continue;
147161

162+
map_power_idle_state_name(tmp);
148163
fix_up_intel_idle_driver_name(tmp, num);
149164
strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
150165
free(tmp);

0 commit comments

Comments
 (0)