Skip to content

Commit 6a0b211

Browse files
committed
Merge branches 'pm-sleep', 'pm-qos' and 'powercap'
Merge system-wide power management changes and power capping updates for 6.6-rc1: - Add device PM helpers to allow a device to remain powered-on during system-wide transitions (Ulf Hansson). - Rework hibernation memory snapshotting to avoid storing pages filled with zeros in hibernation image files (Brian Geffon). - Add check to make sure that CPU latency QoS constraints do not use negative values (Clive Lin). - Optimize rp->domains memory allocation in the Intel RAPL power capping driver (xiongxin). - Remove recursion while parsing zones in the arm_scmi power capping driver (Cristian Marussi). * pm-sleep: PM: sleep: Add helpers to allow a device to remain powered-on PM: hibernate: don't store zero pages in the image file * pm-qos: PM: QoS: Add check to make sure CPU latency is non-negative * powercap: powercap: intel_rapl: Optimize rp->domains memory allocation powercap: arm_scmi: Remove recursion while parsing zones
4 parents 1201c50 + 10bb4e4 + 5f55836 + 9784239 commit 6a0b211

File tree

5 files changed

+259
-108
lines changed

5 files changed

+259
-108
lines changed

drivers/powercap/arm_scmi_powercap.c

Lines changed: 92 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212
#include <linux/module.h>
1313
#include <linux/powercap.h>
1414
#include <linux/scmi_protocol.h>
15+
#include <linux/slab.h>
1516

1617
#define to_scmi_powercap_zone(z) \
1718
container_of(z, struct scmi_powercap_zone, zone)
1819

1920
static const struct scmi_powercap_proto_ops *powercap_ops;
2021

2122
struct scmi_powercap_zone {
23+
bool registered;
24+
bool invalid;
2225
unsigned int height;
2326
struct device *dev;
2427
struct scmi_protocol_handle *ph;
@@ -32,6 +35,7 @@ struct scmi_powercap_root {
3235
unsigned int num_zones;
3336
struct scmi_powercap_zone *spzones;
3437
struct list_head *registered_zones;
38+
struct list_head scmi_zones;
3539
};
3640

3741
static struct powercap_control_type *scmi_top_pcntrl;
@@ -271,12 +275,6 @@ static void scmi_powercap_unregister_all_zones(struct scmi_powercap_root *pr)
271275
}
272276
}
273277

274-
static inline bool
275-
scmi_powercap_is_zone_registered(struct scmi_powercap_zone *spz)
276-
{
277-
return !list_empty(&spz->node);
278-
}
279-
280278
static inline unsigned int
281279
scmi_powercap_get_zone_height(struct scmi_powercap_zone *spz)
282280
{
@@ -295,11 +293,46 @@ scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz)
295293
return &spz->spzones[spz->info->parent_id];
296294
}
297295

296+
static int scmi_powercap_register_zone(struct scmi_powercap_root *pr,
297+
struct scmi_powercap_zone *spz,
298+
struct scmi_powercap_zone *parent)
299+
{
300+
int ret = 0;
301+
struct powercap_zone *z;
302+
303+
if (spz->invalid) {
304+
list_del(&spz->node);
305+
return -EINVAL;
306+
}
307+
308+
z = powercap_register_zone(&spz->zone, scmi_top_pcntrl, spz->info->name,
309+
parent ? &parent->zone : NULL,
310+
&zone_ops, 1, &constraint_ops);
311+
if (!IS_ERR(z)) {
312+
spz->height = scmi_powercap_get_zone_height(spz);
313+
spz->registered = true;
314+
list_move(&spz->node, &pr->registered_zones[spz->height]);
315+
dev_dbg(spz->dev, "Registered node %s - parent %s - height:%d\n",
316+
spz->info->name, parent ? parent->info->name : "ROOT",
317+
spz->height);
318+
} else {
319+
list_del(&spz->node);
320+
ret = PTR_ERR(z);
321+
dev_err(spz->dev,
322+
"Error registering node:%s - parent:%s - h:%d - ret:%d\n",
323+
spz->info->name,
324+
parent ? parent->info->name : "ROOT",
325+
spz->height, ret);
326+
}
327+
328+
return ret;
329+
}
330+
298331
/**
299-
* scmi_powercap_register_zone - Register an SCMI powercap zone recursively
332+
* scmi_zones_register- Register SCMI powercap zones starting from parent zones
300333
*
334+
* @dev: A reference to the SCMI device
301335
* @pr: A reference to the root powercap zones descriptors
302-
* @spz: A reference to the SCMI powercap zone to register
303336
*
304337
* When registering SCMI powercap zones with the powercap framework we should
305338
* take care to always register zones starting from the root ones and to
@@ -309,10 +342,10 @@ scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz)
309342
* zones provided by the SCMI platform firmware is built to comply with such
310343
* requirement.
311344
*
312-
* This function, given an SCMI powercap zone to register, takes care to walk
313-
* the SCMI powercap zones tree up to the root looking recursively for
314-
* unregistered parent zones before registering the provided zone; at the same
315-
* time each registered zone height in such a tree is accounted for and each
345+
* This function, given the set of SCMI powercap zones to register, takes care
346+
* to walk the SCMI powercap zones trees up to the root registering any
347+
* unregistered parent zone before registering the child zones; at the same
348+
* time each registered-zone height in such a tree is accounted for and each
316349
* zone, once registered, is stored in the @registered_zones array that is
317350
* indexed by zone height: this way will be trivial, at unregister time, to walk
318351
* the @registered_zones array backward and unregister all the zones starting
@@ -330,57 +363,55 @@ scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz)
330363
*
331364
* Return: 0 on Success
332365
*/
333-
static int scmi_powercap_register_zone(struct scmi_powercap_root *pr,
334-
struct scmi_powercap_zone *spz)
366+
static int scmi_zones_register(struct device *dev,
367+
struct scmi_powercap_root *pr)
335368
{
336369
int ret = 0;
337-
struct scmi_powercap_zone *parent;
338-
339-
if (!spz->info)
340-
return ret;
370+
unsigned int sp = 0, reg_zones = 0;
371+
struct scmi_powercap_zone *spz, **zones_stack;
341372

342-
parent = scmi_powercap_get_parent_zone(spz);
343-
if (parent && !scmi_powercap_is_zone_registered(parent)) {
344-
/*
345-
* Bail out if a parent domain was marked as unsupported:
346-
* only domains participating as leaves can be skipped.
347-
*/
348-
if (!parent->info)
349-
return -ENODEV;
373+
zones_stack = kcalloc(pr->num_zones, sizeof(spz), GFP_KERNEL);
374+
if (!zones_stack)
375+
return -ENOMEM;
350376

351-
ret = scmi_powercap_register_zone(pr, parent);
352-
if (ret)
353-
return ret;
354-
}
377+
spz = list_first_entry_or_null(&pr->scmi_zones,
378+
struct scmi_powercap_zone, node);
379+
while (spz) {
380+
struct scmi_powercap_zone *parent;
355381

356-
if (!scmi_powercap_is_zone_registered(spz)) {
357-
struct powercap_zone *z;
358-
359-
z = powercap_register_zone(&spz->zone,
360-
scmi_top_pcntrl,
361-
spz->info->name,
362-
parent ? &parent->zone : NULL,
363-
&zone_ops, 1, &constraint_ops);
364-
if (!IS_ERR(z)) {
365-
spz->height = scmi_powercap_get_zone_height(spz);
366-
list_add(&spz->node,
367-
&pr->registered_zones[spz->height]);
368-
dev_dbg(spz->dev,
369-
"Registered node %s - parent %s - height:%d\n",
370-
spz->info->name,
371-
parent ? parent->info->name : "ROOT",
372-
spz->height);
373-
ret = 0;
382+
parent = scmi_powercap_get_parent_zone(spz);
383+
if (parent && !parent->registered) {
384+
zones_stack[sp++] = spz;
385+
spz = parent;
374386
} else {
375-
ret = PTR_ERR(z);
376-
dev_err(spz->dev,
377-
"Error registering node:%s - parent:%s - h:%d - ret:%d\n",
378-
spz->info->name,
379-
parent ? parent->info->name : "ROOT",
380-
spz->height, ret);
387+
ret = scmi_powercap_register_zone(pr, spz, parent);
388+
if (!ret) {
389+
reg_zones++;
390+
} else if (sp) {
391+
/* Failed to register a non-leaf zone.
392+
* Bail-out.
393+
*/
394+
dev_err(dev,
395+
"Failed to register non-leaf zone - ret:%d\n",
396+
ret);
397+
scmi_powercap_unregister_all_zones(pr);
398+
reg_zones = 0;
399+
goto out;
400+
}
401+
/* Pick next zone to process */
402+
if (sp)
403+
spz = zones_stack[--sp];
404+
else
405+
spz = list_first_entry_or_null(&pr->scmi_zones,
406+
struct scmi_powercap_zone,
407+
node);
381408
}
382409
}
383410

411+
out:
412+
kfree(zones_stack);
413+
dev_info(dev, "Registered %d SCMI Powercap domains !\n", reg_zones);
414+
384415
return ret;
385416
}
386417

@@ -424,6 +455,8 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
424455
if (!pr->registered_zones)
425456
return -ENOMEM;
426457

458+
INIT_LIST_HEAD(&pr->scmi_zones);
459+
427460
for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) {
428461
/*
429462
* Powercap domains are validate by the protocol layer, i.e.
@@ -438,6 +471,7 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
438471
INIT_LIST_HEAD(&spz->node);
439472
INIT_LIST_HEAD(&pr->registered_zones[i]);
440473

474+
list_add_tail(&spz->node, &pr->scmi_zones);
441475
/*
442476
* Forcibly skip powercap domains using an abstract scale.
443477
* Note that only leaves domains can be skipped, so this could
@@ -448,7 +482,7 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
448482
dev_warn(dev,
449483
"Abstract power scale not supported. Skip %s.\n",
450484
spz->info->name);
451-
spz->info = NULL;
485+
spz->invalid = true;
452486
continue;
453487
}
454488
}
@@ -457,21 +491,12 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
457491
* Scan array of retrieved SCMI powercap domains and register them
458492
* recursively starting from the root domains.
459493
*/
460-
for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) {
461-
ret = scmi_powercap_register_zone(pr, spz);
462-
if (ret) {
463-
dev_err(dev,
464-
"Failed to register powercap zone %s - ret:%d\n",
465-
spz->info->name, ret);
466-
scmi_powercap_unregister_all_zones(pr);
467-
return ret;
468-
}
469-
}
494+
ret = scmi_zones_register(dev, pr);
495+
if (ret)
496+
return ret;
470497

471498
dev_set_drvdata(dev, pr);
472499

473-
dev_info(dev, "Registered %d SCMI Powercap domains !\n", pr->num_zones);
474-
475500
return ret;
476501
}
477502

drivers/powercap/intel_rapl_common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1485,7 +1485,7 @@ static int rapl_detect_domains(struct rapl_package *rp)
14851485
}
14861486
pr_debug("found %d domains on %s\n", rp->nr_domains, rp->name);
14871487

1488-
rp->domains = kcalloc(rp->nr_domains + 1, sizeof(struct rapl_domain),
1488+
rp->domains = kcalloc(rp->nr_domains, sizeof(struct rapl_domain),
14891489
GFP_KERNEL);
14901490
if (!rp->domains)
14911491
return -ENOMEM;

include/linux/pm_wakeup.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,16 @@ static inline void pm_wakeup_dev_event(struct device *dev, unsigned int msec,
194194

195195
#endif /* !CONFIG_PM_SLEEP */
196196

197+
static inline bool device_awake_path(struct device *dev)
198+
{
199+
return device_wakeup_path(dev);
200+
}
201+
202+
static inline void device_set_awake_path(struct device *dev)
203+
{
204+
device_set_wakeup_path(dev);
205+
}
206+
197207
static inline void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
198208
{
199209
return pm_wakeup_ws_event(ws, msec, false);

kernel/power/qos.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,11 @@ static struct pm_qos_constraints cpu_latency_constraints = {
220220
.type = PM_QOS_MIN,
221221
};
222222

223+
static inline bool cpu_latency_qos_value_invalid(s32 value)
224+
{
225+
return value < 0 && value != PM_QOS_DEFAULT_VALUE;
226+
}
227+
223228
/**
224229
* cpu_latency_qos_limit - Return current system-wide CPU latency QoS limit.
225230
*/
@@ -263,7 +268,7 @@ static void cpu_latency_qos_apply(struct pm_qos_request *req,
263268
*/
264269
void cpu_latency_qos_add_request(struct pm_qos_request *req, s32 value)
265270
{
266-
if (!req)
271+
if (!req || cpu_latency_qos_value_invalid(value))
267272
return;
268273

269274
if (cpu_latency_qos_request_active(req)) {
@@ -289,7 +294,7 @@ EXPORT_SYMBOL_GPL(cpu_latency_qos_add_request);
289294
*/
290295
void cpu_latency_qos_update_request(struct pm_qos_request *req, s32 new_value)
291296
{
292-
if (!req)
297+
if (!req || cpu_latency_qos_value_invalid(new_value))
293298
return;
294299

295300
if (!cpu_latency_qos_request_active(req)) {

0 commit comments

Comments
 (0)