Skip to content

Commit 9784239

Browse files
committed
Merge back earlier power capping changes for v6.6.
2 parents 16e95a6 + 2fa0076 commit 9784239

File tree

2 files changed

+93
-68
lines changed

2 files changed

+93
-68
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;

0 commit comments

Comments
 (0)