Skip to content

Commit 912e97c

Browse files
lukaszluba-armrafaeljw
authored andcommitted
thermal: gov_power_allocator: Move memory allocation out of throttle()
The new thermal callback allows to react to the change of cooling instances in the thermal zone. Move the memory allocation to that new callback and save CPU cycles in the throttle() code path. Signed-off-by: Lukasz Luba <lukasz.luba@arm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 792c3dc commit 912e97c

File tree

1 file changed

+136
-71
lines changed

1 file changed

+136
-71
lines changed

drivers/thermal/gov_power_allocator.c

Lines changed: 136 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ static inline s64 div_frac(s64 x, s64 y)
4646
return div_s64(x << FRAC_BITS, y);
4747
}
4848

49+
/**
50+
* struct power_actor - internal power information for power actor
51+
* @req_power: requested power value (not weighted)
52+
* @max_power: max allocatable power for this actor
53+
* @granted_power: granted power for this actor
54+
* @extra_actor_power: extra power that this actor can receive
55+
* @weighted_req_power: weighted requested power as input to IPA
56+
*/
57+
struct power_actor {
58+
u32 req_power;
59+
u32 max_power;
60+
u32 granted_power;
61+
u32 extra_actor_power;
62+
u32 weighted_req_power;
63+
};
64+
4965
/**
5066
* struct power_allocator_params - parameters for the power allocator governor
5167
* @allocated_tzp: whether we have allocated tzp for this thermal zone and
@@ -61,6 +77,9 @@ static inline s64 div_frac(s64 x, s64 y)
6177
* @trip_switch_on should be NULL.
6278
* @trip_max: last passive trip point of the thermal zone. The
6379
* temperature we are controlling for.
80+
* @num_actors: number of cooling devices supporting IPA callbacks
81+
* @buffer_size: internal buffer size, to avoid runtime re-calculation
82+
* @power: buffer for all power actors internal power information
6483
*/
6584
struct power_allocator_params {
6685
bool allocated_tzp;
@@ -69,6 +88,9 @@ struct power_allocator_params {
6988
u32 sustainable_power;
7089
const struct thermal_trip *trip_switch_on;
7190
const struct thermal_trip *trip_max;
91+
unsigned int num_actors;
92+
unsigned int buffer_size;
93+
struct power_actor *power;
7294
};
7395

7496
/**
@@ -303,15 +325,10 @@ power_actor_set_power(struct thermal_cooling_device *cdev,
303325

304326
/**
305327
* divvy_up_power() - divvy the allocated power between the actors
306-
* @req_power: each actor's requested power
307-
* @max_power: each actor's maximum available power
308-
* @num_actors: size of the @req_power, @max_power and @granted_power's array
309-
* @total_req_power: sum of @req_power
328+
* @power: buffer for all power actors internal power information
329+
* @num_actors: number of power actors in this thermal zone
330+
* @total_req_power: sum of all weighted requested power for all actors
310331
* @power_range: total allocated power
311-
* @granted_power: output array: each actor's granted power
312-
* @extra_actor_power: an appropriately sized array to be used in the
313-
* function as temporary storage of the extra power given
314-
* to the actors
315332
*
316333
* This function divides the total allocated power (@power_range)
317334
* fairly between the actors. It first tries to give each actor a
@@ -324,13 +341,9 @@ power_actor_set_power(struct thermal_cooling_device *cdev,
324341
* If any actor received more than their maximum power, then that
325342
* surplus is re-divvied among the actors based on how far they are
326343
* from their respective maximums.
327-
*
328-
* Granted power for each actor is written to @granted_power, which
329-
* should've been allocated by the calling function.
330344
*/
331-
static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors,
332-
u32 total_req_power, u32 power_range,
333-
u32 *granted_power, u32 *extra_actor_power)
345+
static void divvy_up_power(struct power_actor *power, int num_actors,
346+
u32 total_req_power, u32 power_range)
334347
{
335348
u32 capped_extra_power = 0;
336349
u32 extra_power = 0;
@@ -343,18 +356,19 @@ static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors,
343356
total_req_power = 1;
344357

345358
for (i = 0; i < num_actors; i++) {
346-
u64 req_range = (u64)req_power[i] * power_range;
359+
struct power_actor *pa = &power[i];
360+
u64 req_range = (u64)pa->req_power * power_range;
347361

348-
granted_power[i] = DIV_ROUND_CLOSEST_ULL(req_range,
349-
total_req_power);
362+
pa->granted_power = DIV_ROUND_CLOSEST_ULL(req_range,
363+
total_req_power);
350364

351-
if (granted_power[i] > max_power[i]) {
352-
extra_power += granted_power[i] - max_power[i];
353-
granted_power[i] = max_power[i];
365+
if (pa->granted_power > pa->max_power) {
366+
extra_power += pa->granted_power - pa->max_power;
367+
pa->granted_power = pa->max_power;
354368
}
355369

356-
extra_actor_power[i] = max_power[i] - granted_power[i];
357-
capped_extra_power += extra_actor_power[i];
370+
pa->extra_actor_power = pa->max_power - pa->granted_power;
371+
capped_extra_power += pa->extra_actor_power;
358372
}
359373

360374
if (!extra_power || !capped_extra_power)
@@ -367,61 +381,44 @@ static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors,
367381
extra_power = min(extra_power, capped_extra_power);
368382

369383
for (i = 0; i < num_actors; i++) {
370-
u64 extra_range = (u64)extra_actor_power[i] * extra_power;
384+
struct power_actor *pa = &power[i];
385+
u64 extra_range = pa->extra_actor_power;
371386

372-
granted_power[i] += DIV_ROUND_CLOSEST_ULL(extra_range,
373-
capped_extra_power);
387+
extra_range *= extra_power;
388+
pa->granted_power += DIV_ROUND_CLOSEST_ULL(extra_range,
389+
capped_extra_power);
374390
}
375391
}
376392

377393
static int allocate_power(struct thermal_zone_device *tz, int control_temp)
378394
{
379-
u32 *req_power, *max_power, *granted_power, *extra_actor_power;
380395
struct power_allocator_params *params = tz->governor_data;
396+
unsigned int num_actors = params->num_actors;
397+
struct power_actor *power = params->power;
381398
struct thermal_cooling_device *cdev;
382399
struct thermal_instance *instance;
383400
u32 total_weighted_req_power = 0;
384401
u32 max_allocatable_power = 0;
385402
u32 total_granted_power = 0;
386403
u32 total_req_power = 0;
387-
u32 *weighted_req_power;
388404
u32 power_range, weight;
389405
int total_weight = 0;
390-
int num_actors = 0;
391-
int i = 0;
392-
393-
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
394-
if ((instance->trip == params->trip_max) &&
395-
cdev_is_power_actor(instance->cdev)) {
396-
num_actors++;
397-
total_weight += instance->weight;
398-
}
399-
}
406+
int i = 0, ret;
400407

401408
if (!num_actors)
402409
return -ENODEV;
403410

404-
/*
405-
* We need to allocate five arrays of the same size:
406-
* req_power, max_power, granted_power, extra_actor_power and
407-
* weighted_req_power. They are going to be needed until this
408-
* function returns. Allocate them all in one go to simplify
409-
* the allocation and deallocation logic.
410-
*/
411-
BUILD_BUG_ON(sizeof(*req_power) != sizeof(*max_power));
412-
BUILD_BUG_ON(sizeof(*req_power) != sizeof(*granted_power));
413-
BUILD_BUG_ON(sizeof(*req_power) != sizeof(*extra_actor_power));
414-
BUILD_BUG_ON(sizeof(*req_power) != sizeof(*weighted_req_power));
415-
req_power = kcalloc(num_actors * 5, sizeof(*req_power), GFP_KERNEL);
416-
if (!req_power)
417-
return -ENOMEM;
411+
list_for_each_entry(instance, &tz->thermal_instances, tz_node)
412+
if ((instance->trip == params->trip_max) &&
413+
cdev_is_power_actor(instance->cdev))
414+
total_weight += instance->weight;
418415

419-
max_power = &req_power[num_actors];
420-
granted_power = &req_power[2 * num_actors];
421-
extra_actor_power = &req_power[3 * num_actors];
422-
weighted_req_power = &req_power[4 * num_actors];
416+
/* Clean all buffers for new power estimations */
417+
memset(power, 0, params->buffer_size);
423418

424419
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
420+
struct power_actor *pa = &power[i];
421+
425422
cdev = instance->cdev;
426423

427424
if (instance->trip != params->trip_max)
@@ -430,47 +427,50 @@ static int allocate_power(struct thermal_zone_device *tz, int control_temp)
430427
if (!cdev_is_power_actor(cdev))
431428
continue;
432429

433-
if (cdev->ops->get_requested_power(cdev, &req_power[i]))
430+
ret = cdev->ops->get_requested_power(cdev, &pa->req_power);
431+
if (ret)
434432
continue;
435433

436434
if (!total_weight)
437435
weight = 1 << FRAC_BITS;
438436
else
439437
weight = instance->weight;
440438

441-
weighted_req_power[i] = frac_to_int(weight * req_power[i]);
439+
pa->weighted_req_power = frac_to_int(weight * pa->req_power);
442440

443-
if (cdev->ops->state2power(cdev, instance->lower,
444-
&max_power[i]))
441+
ret = cdev->ops->state2power(cdev, instance->lower,
442+
&pa->max_power);
443+
if (ret)
445444
continue;
446445

447-
total_req_power += req_power[i];
448-
max_allocatable_power += max_power[i];
449-
total_weighted_req_power += weighted_req_power[i];
446+
total_req_power += pa->req_power;
447+
max_allocatable_power += pa->max_power;
448+
total_weighted_req_power += pa->weighted_req_power;
450449

451450
i++;
452451
}
453452

454453
power_range = pid_controller(tz, control_temp, max_allocatable_power);
455454

456-
divvy_up_power(weighted_req_power, max_power, num_actors,
457-
total_weighted_req_power, power_range, granted_power,
458-
extra_actor_power);
455+
divvy_up_power(power, num_actors, total_weighted_req_power,
456+
power_range);
459457

460458
i = 0;
461459
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
460+
struct power_actor *pa = &power[i];
461+
462462
if (instance->trip != params->trip_max)
463463
continue;
464464

465465
if (!cdev_is_power_actor(instance->cdev))
466466
continue;
467467

468468
power_actor_set_power(instance->cdev, instance,
469-
granted_power[i]);
470-
total_granted_power += granted_power[i];
469+
pa->granted_power);
470+
total_granted_power += pa->granted_power;
471471

472-
trace_thermal_power_actor(tz, i, req_power[i],
473-
granted_power[i]);
472+
trace_thermal_power_actor(tz, i, pa->req_power,
473+
pa->granted_power);
474474
i++;
475475
}
476476

@@ -479,8 +479,6 @@ static int allocate_power(struct thermal_zone_device *tz, int control_temp)
479479
max_allocatable_power, tz->temperature,
480480
control_temp - tz->temperature);
481481

482-
kfree(req_power);
483-
484482
return 0;
485483
}
486484

@@ -607,6 +605,63 @@ static int check_power_actors(struct thermal_zone_device *tz,
607605
return ret;
608606
}
609607

608+
static int allocate_actors_buffer(struct power_allocator_params *params,
609+
int num_actors)
610+
{
611+
int ret;
612+
613+
kfree(params->power);
614+
615+
/* There might be no cooling devices yet. */
616+
if (!num_actors) {
617+
ret = -EINVAL;
618+
goto clean_state;
619+
}
620+
621+
params->power = kcalloc(num_actors, sizeof(struct power_actor),
622+
GFP_KERNEL);
623+
if (!params->power) {
624+
ret = -ENOMEM;
625+
goto clean_state;
626+
}
627+
628+
params->num_actors = num_actors;
629+
params->buffer_size = num_actors * sizeof(struct power_actor);
630+
631+
return 0;
632+
633+
clean_state:
634+
params->num_actors = 0;
635+
params->buffer_size = 0;
636+
params->power = NULL;
637+
return ret;
638+
}
639+
640+
static void power_allocator_update_tz(struct thermal_zone_device *tz,
641+
enum thermal_notify_event reason)
642+
{
643+
struct power_allocator_params *params = tz->governor_data;
644+
struct thermal_instance *instance;
645+
int num_actors = 0;
646+
647+
switch (reason) {
648+
case THERMAL_TZ_BIND_CDEV:
649+
case THERMAL_TZ_UNBIND_CDEV:
650+
list_for_each_entry(instance, &tz->thermal_instances, tz_node)
651+
if ((instance->trip == params->trip_max) &&
652+
cdev_is_power_actor(instance->cdev))
653+
num_actors++;
654+
655+
if (num_actors == params->num_actors)
656+
return;
657+
658+
allocate_actors_buffer(params, num_actors);
659+
break;
660+
default:
661+
break;
662+
}
663+
}
664+
610665
/**
611666
* power_allocator_bind() - bind the power_allocator governor to a thermal zone
612667
* @tz: thermal zone to bind it to
@@ -640,6 +695,13 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
640695
return ret;
641696
}
642697

698+
ret = allocate_actors_buffer(params, ret);
699+
if (ret) {
700+
dev_warn(&tz->device, "power_allocator: allocation failed\n");
701+
kfree(params);
702+
return ret;
703+
}
704+
643705
if (!tz->tzp) {
644706
tz->tzp = kzalloc(sizeof(*tz->tzp), GFP_KERNEL);
645707
if (!tz->tzp) {
@@ -664,6 +726,7 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
664726
return 0;
665727

666728
free_params:
729+
kfree(params->power);
667730
kfree(params);
668731

669732
return ret;
@@ -680,6 +743,7 @@ static void power_allocator_unbind(struct thermal_zone_device *tz)
680743
tz->tzp = NULL;
681744
}
682745

746+
kfree(params->power);
683747
kfree(tz->governor_data);
684748
tz->governor_data = NULL;
685749
}
@@ -718,5 +782,6 @@ static struct thermal_governor thermal_gov_power_allocator = {
718782
.bind_to_tz = power_allocator_bind,
719783
.unbind_from_tz = power_allocator_unbind,
720784
.throttle = power_allocator_throttle,
785+
.update_tz = power_allocator_update_tz,
721786
};
722787
THERMAL_GOVERNOR_DECLARE(thermal_gov_power_allocator);

0 commit comments

Comments
 (0)