Skip to content

Commit 4570ddd

Browse files
committed
powercap/drivers/dtpm: Encapsulate even more the code
In order to increase the self-encapsulation of the dtpm generic code, the following changes are adding a power update ops to the dtpm ops. That allows the generic code to call directly the dtpm backend function to update the power values. The power update function does compute the power characteristics when the function is invoked. In the case of the CPUs, the power consumption depends on the number of online CPUs. The online CPUs mask is not up to date at CPUHP_AP_ONLINE_DYN state in the tear down callback. That is the reason why the online / offline are at separate state. As there is already an existing state for DTPM, this one is only moved to the DEAD state, so there is no addition of new state with these changes. The dtpm node is not removed when the cpu is unplugged. That simplifies the code for the next changes and results in a more self-encapsulated code. Signed-off-by: Daniel Lezcano <[email protected]> Reviewed-by: Lukasz Luba <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 6880fa6 commit 4570ddd

File tree

4 files changed

+97
-110
lines changed

4 files changed

+97
-110
lines changed

drivers/powercap/dtpm.c

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ static void __dtpm_sub_power(struct dtpm *dtpm)
116116
parent->power_limit -= dtpm->power_limit;
117117
parent = parent->parent;
118118
}
119-
120-
__dtpm_rebalance_weight(root);
121119
}
122120

123121
static void __dtpm_add_power(struct dtpm *dtpm)
@@ -130,45 +128,45 @@ static void __dtpm_add_power(struct dtpm *dtpm)
130128
parent->power_limit += dtpm->power_limit;
131129
parent = parent->parent;
132130
}
131+
}
132+
133+
static int __dtpm_update_power(struct dtpm *dtpm)
134+
{
135+
int ret;
136+
137+
__dtpm_sub_power(dtpm);
133138

134-
__dtpm_rebalance_weight(root);
139+
ret = dtpm->ops->update_power_uw(dtpm);
140+
if (ret)
141+
pr_err("Failed to update power for '%s': %d\n",
142+
dtpm->zone.name, ret);
143+
144+
if (!test_bit(DTPM_POWER_LIMIT_FLAG, &dtpm->flags))
145+
dtpm->power_limit = dtpm->power_max;
146+
147+
__dtpm_add_power(dtpm);
148+
149+
if (root)
150+
__dtpm_rebalance_weight(root);
151+
152+
return ret;
135153
}
136154

137155
/**
138156
* dtpm_update_power - Update the power on the dtpm
139157
* @dtpm: a pointer to a dtpm structure to update
140-
* @power_min: a u64 representing the new power_min value
141-
* @power_max: a u64 representing the new power_max value
142158
*
143159
* Function to update the power values of the dtpm node specified in
144160
* parameter. These new values will be propagated to the tree.
145161
*
146162
* Return: zero on success, -EINVAL if the values are inconsistent
147163
*/
148-
int dtpm_update_power(struct dtpm *dtpm, u64 power_min, u64 power_max)
164+
int dtpm_update_power(struct dtpm *dtpm)
149165
{
150-
int ret = 0;
166+
int ret;
151167

152168
mutex_lock(&dtpm_lock);
153-
154-
if (power_min == dtpm->power_min && power_max == dtpm->power_max)
155-
goto unlock;
156-
157-
if (power_max < power_min) {
158-
ret = -EINVAL;
159-
goto unlock;
160-
}
161-
162-
__dtpm_sub_power(dtpm);
163-
164-
dtpm->power_min = power_min;
165-
dtpm->power_max = power_max;
166-
if (!test_bit(DTPM_POWER_LIMIT_FLAG, &dtpm->flags))
167-
dtpm->power_limit = power_max;
168-
169-
__dtpm_add_power(dtpm);
170-
171-
unlock:
169+
ret = __dtpm_update_power(dtpm);
172170
mutex_unlock(&dtpm_lock);
173171

174172
return ret;
@@ -436,6 +434,7 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent)
436434

437435
if (dtpm->ops && !(dtpm->ops->set_power_uw &&
438436
dtpm->ops->get_power_uw &&
437+
dtpm->ops->update_power_uw &&
439438
dtpm->ops->release))
440439
return -EINVAL;
441440

@@ -455,7 +454,8 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent)
455454
root = dtpm;
456455
}
457456

458-
__dtpm_add_power(dtpm);
457+
if (dtpm->ops && !dtpm->ops->update_power_uw(dtpm))
458+
__dtpm_add_power(dtpm);
459459

460460
pr_info("Registered dtpm node '%s' / %llu-%llu uW, \n",
461461
dtpm->zone.name, dtpm->power_min, dtpm->power_max);

drivers/powercap/dtpm_cpu.c

Lines changed: 67 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* The CPU hotplug is supported and the power numbers will be updated
1515
* if a CPU is hot plugged / unplugged.
1616
*/
17+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18+
1719
#include <linux/cpumask.h>
1820
#include <linux/cpufreq.h>
1921
#include <linux/cpuhotplug.h>
@@ -23,66 +25,23 @@
2325
#include <linux/slab.h>
2426
#include <linux/units.h>
2527

26-
static struct dtpm *__parent;
27-
2828
static DEFINE_PER_CPU(struct dtpm *, dtpm_per_cpu);
2929

3030
struct dtpm_cpu {
3131
struct freq_qos_request qos_req;
3232
int cpu;
3333
};
3434

35-
/*
36-
* When a new CPU is inserted at hotplug or boot time, add the power
37-
* contribution and update the dtpm tree.
38-
*/
39-
static int power_add(struct dtpm *dtpm, struct em_perf_domain *em)
40-
{
41-
u64 power_min, power_max;
42-
43-
power_min = em->table[0].power;
44-
power_min *= MICROWATT_PER_MILLIWATT;
45-
power_min += dtpm->power_min;
46-
47-
power_max = em->table[em->nr_perf_states - 1].power;
48-
power_max *= MICROWATT_PER_MILLIWATT;
49-
power_max += dtpm->power_max;
50-
51-
return dtpm_update_power(dtpm, power_min, power_max);
52-
}
53-
54-
/*
55-
* When a CPU is unplugged, remove its power contribution from the
56-
* dtpm tree.
57-
*/
58-
static int power_sub(struct dtpm *dtpm, struct em_perf_domain *em)
59-
{
60-
u64 power_min, power_max;
61-
62-
power_min = em->table[0].power;
63-
power_min *= MICROWATT_PER_MILLIWATT;
64-
power_min = dtpm->power_min - power_min;
65-
66-
power_max = em->table[em->nr_perf_states - 1].power;
67-
power_max *= MICROWATT_PER_MILLIWATT;
68-
power_max = dtpm->power_max - power_max;
69-
70-
return dtpm_update_power(dtpm, power_min, power_max);
71-
}
72-
7335
static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit)
7436
{
7537
struct dtpm_cpu *dtpm_cpu = dtpm->private;
76-
struct em_perf_domain *pd;
38+
struct em_perf_domain *pd = em_cpu_get(dtpm_cpu->cpu);
7739
struct cpumask cpus;
7840
unsigned long freq;
7941
u64 power;
8042
int i, nr_cpus;
8143

82-
pd = em_cpu_get(dtpm_cpu->cpu);
83-
8444
cpumask_and(&cpus, cpu_online_mask, to_cpumask(pd->cpus));
85-
8645
nr_cpus = cpumask_weight(&cpus);
8746

8847
for (i = 0; i < pd->nr_perf_states; i++) {
@@ -113,6 +72,7 @@ static u64 get_pd_power_uw(struct dtpm *dtpm)
11372

11473
pd = em_cpu_get(dtpm_cpu->cpu);
11574
freq = cpufreq_quick_get(dtpm_cpu->cpu);
75+
11676
cpumask_and(&cpus, cpu_online_mask, to_cpumask(pd->cpus));
11777
nr_cpus = cpumask_weight(&cpus);
11878

@@ -128,6 +88,27 @@ static u64 get_pd_power_uw(struct dtpm *dtpm)
12888
return 0;
12989
}
13090

91+
static int update_pd_power_uw(struct dtpm *dtpm)
92+
{
93+
struct dtpm_cpu *dtpm_cpu = dtpm->private;
94+
struct em_perf_domain *em = em_cpu_get(dtpm_cpu->cpu);
95+
struct cpumask cpus;
96+
int nr_cpus;
97+
98+
cpumask_and(&cpus, cpu_online_mask, to_cpumask(em->cpus));
99+
nr_cpus = cpumask_weight(&cpus);
100+
101+
dtpm->power_min = em->table[0].power;
102+
dtpm->power_min *= MICROWATT_PER_MILLIWATT;
103+
dtpm->power_min *= nr_cpus;
104+
105+
dtpm->power_max = em->table[em->nr_perf_states - 1].power;
106+
dtpm->power_max *= MICROWATT_PER_MILLIWATT;
107+
dtpm->power_max *= nr_cpus;
108+
109+
return 0;
110+
}
111+
131112
static void pd_release(struct dtpm *dtpm)
132113
{
133114
struct dtpm_cpu *dtpm_cpu = dtpm->private;
@@ -139,39 +120,24 @@ static void pd_release(struct dtpm *dtpm)
139120
}
140121

141122
static struct dtpm_ops dtpm_ops = {
142-
.set_power_uw = set_pd_power_limit,
143-
.get_power_uw = get_pd_power_uw,
144-
.release = pd_release,
123+
.set_power_uw = set_pd_power_limit,
124+
.get_power_uw = get_pd_power_uw,
125+
.update_power_uw = update_pd_power_uw,
126+
.release = pd_release,
145127
};
146128

147129
static int cpuhp_dtpm_cpu_offline(unsigned int cpu)
148130
{
149-
struct cpufreq_policy *policy;
150131
struct em_perf_domain *pd;
151132
struct dtpm *dtpm;
152133

153-
policy = cpufreq_cpu_get(cpu);
154-
155-
if (!policy)
156-
return 0;
157-
158134
pd = em_cpu_get(cpu);
159135
if (!pd)
160136
return -EINVAL;
161137

162138
dtpm = per_cpu(dtpm_per_cpu, cpu);
163139

164-
power_sub(dtpm, pd);
165-
166-
if (cpumask_weight(policy->cpus) != 1)
167-
return 0;
168-
169-
for_each_cpu(cpu, policy->related_cpus)
170-
per_cpu(dtpm_per_cpu, cpu) = NULL;
171-
172-
dtpm_unregister(dtpm);
173-
174-
return 0;
140+
return dtpm_update_power(dtpm);
175141
}
176142

177143
static int cpuhp_dtpm_cpu_online(unsigned int cpu)
@@ -184,7 +150,6 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu)
184150
int ret = -ENOMEM;
185151

186152
policy = cpufreq_cpu_get(cpu);
187-
188153
if (!policy)
189154
return 0;
190155

@@ -194,7 +159,7 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu)
194159

195160
dtpm = per_cpu(dtpm_per_cpu, cpu);
196161
if (dtpm)
197-
return power_add(dtpm, pd);
162+
return dtpm_update_power(dtpm);
198163

199164
dtpm = dtpm_alloc(&dtpm_ops);
200165
if (!dtpm)
@@ -210,27 +175,20 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu)
210175
for_each_cpu(cpu, policy->related_cpus)
211176
per_cpu(dtpm_per_cpu, cpu) = dtpm;
212177

213-
sprintf(name, "cpu%d", dtpm_cpu->cpu);
178+
snprintf(name, sizeof(name), "cpu%d-cpufreq", dtpm_cpu->cpu);
214179

215-
ret = dtpm_register(name, dtpm, __parent);
180+
ret = dtpm_register(name, dtpm, NULL);
216181
if (ret)
217182
goto out_kfree_dtpm_cpu;
218183

219-
ret = power_add(dtpm, pd);
220-
if (ret)
221-
goto out_dtpm_unregister;
222-
223184
ret = freq_qos_add_request(&policy->constraints,
224185
&dtpm_cpu->qos_req, FREQ_QOS_MAX,
225186
pd->table[pd->nr_perf_states - 1].frequency);
226187
if (ret)
227-
goto out_power_sub;
188+
goto out_dtpm_unregister;
228189

229190
return 0;
230191

231-
out_power_sub:
232-
power_sub(dtpm, pd);
233-
234192
out_dtpm_unregister:
235193
dtpm_unregister(dtpm);
236194
dtpm_cpu = NULL;
@@ -248,10 +206,38 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu)
248206

249207
int dtpm_register_cpu(struct dtpm *parent)
250208
{
251-
__parent = parent;
209+
int ret;
210+
211+
/*
212+
* The callbacks at CPU hotplug time are calling
213+
* dtpm_update_power() which in turns calls update_pd_power().
214+
*
215+
* The function update_pd_power() uses the online mask to
216+
* figure out the power consumption limits.
217+
*
218+
* At CPUHP_AP_ONLINE_DYN, the CPU is present in the CPU
219+
* online mask when the cpuhp_dtpm_cpu_online function is
220+
* called, but the CPU is still in the online mask for the
221+
* tear down callback. So the power can not be updated when
222+
* the CPU is unplugged.
223+
*
224+
* At CPUHP_AP_DTPM_CPU_DEAD, the situation is the opposite as
225+
* above. The CPU online mask is not up to date when the CPU
226+
* is plugged in.
227+
*
228+
* For this reason, we need to call the online and offline
229+
* callbacks at different moments when the CPU online mask is
230+
* consistent with the power numbers we want to update.
231+
*/
232+
ret = cpuhp_setup_state(CPUHP_AP_DTPM_CPU_DEAD, "dtpm_cpu:offline",
233+
NULL, cpuhp_dtpm_cpu_offline);
234+
if (ret < 0)
235+
return ret;
236+
237+
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "dtpm_cpu:online",
238+
cpuhp_dtpm_cpu_online, NULL);
239+
if (ret < 0)
240+
return ret;
252241

253-
return cpuhp_setup_state(CPUHP_AP_DTPM_CPU_ONLINE,
254-
"dtpm_cpu:online",
255-
cpuhp_dtpm_cpu_online,
256-
cpuhp_dtpm_cpu_offline);
242+
return 0;
257243
}

include/linux/cpuhotplug.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ enum cpuhp_state {
9797
CPUHP_LUSTRE_CFS_DEAD,
9898
CPUHP_AP_ARM_CACHE_B15_RAC_DEAD,
9999
CPUHP_PADATA_DEAD,
100+
CPUHP_AP_DTPM_CPU_DEAD,
100101
CPUHP_WORKQUEUE_PREP,
101102
CPUHP_POWER_NUMA_PREPARE,
102103
CPUHP_HRTIMERS_PREPARE,
@@ -242,7 +243,6 @@ enum cpuhp_state {
242243
CPUHP_AP_ONLINE_DYN_END = CPUHP_AP_ONLINE_DYN + 30,
243244
CPUHP_AP_X86_HPET_ONLINE,
244245
CPUHP_AP_X86_KVM_CLK_ONLINE,
245-
CPUHP_AP_DTPM_CPU_ONLINE,
246246
CPUHP_AP_ACTIVE,
247247
CPUHP_ONLINE,
248248
};

include/linux/dtpm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ struct dtpm {
2929
struct dtpm_ops {
3030
u64 (*set_power_uw)(struct dtpm *, u64);
3131
u64 (*get_power_uw)(struct dtpm *);
32+
int (*update_power_uw)(struct dtpm *);
3233
void (*release)(struct dtpm *);
3334
};
3435

@@ -62,7 +63,7 @@ static inline struct dtpm *to_dtpm(struct powercap_zone *zone)
6263
return container_of(zone, struct dtpm, zone);
6364
}
6465

65-
int dtpm_update_power(struct dtpm *dtpm, u64 power_min, u64 power_max);
66+
int dtpm_update_power(struct dtpm *dtpm);
6667

6768
int dtpm_release_zone(struct powercap_zone *pcz);
6869

0 commit comments

Comments
 (0)