14
14
* The CPU hotplug is supported and the power numbers will be updated
15
15
* if a CPU is hot plugged / unplugged.
16
16
*/
17
+ #define pr_fmt (fmt ) KBUILD_MODNAME ": " fmt
18
+
17
19
#include <linux/cpumask.h>
18
20
#include <linux/cpufreq.h>
19
21
#include <linux/cpuhotplug.h>
23
25
#include <linux/slab.h>
24
26
#include <linux/units.h>
25
27
26
- static struct dtpm * __parent ;
27
-
28
28
static DEFINE_PER_CPU (struct dtpm * , dtpm_per_cpu ) ;
29
29
30
30
struct dtpm_cpu {
31
31
struct freq_qos_request qos_req ;
32
32
int cpu ;
33
33
};
34
34
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
-
73
35
static u64 set_pd_power_limit (struct dtpm * dtpm , u64 power_limit )
74
36
{
75
37
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 ) ;
77
39
struct cpumask cpus ;
78
40
unsigned long freq ;
79
41
u64 power ;
80
42
int i , nr_cpus ;
81
43
82
- pd = em_cpu_get (dtpm_cpu -> cpu );
83
-
84
44
cpumask_and (& cpus , cpu_online_mask , to_cpumask (pd -> cpus ));
85
-
86
45
nr_cpus = cpumask_weight (& cpus );
87
46
88
47
for (i = 0 ; i < pd -> nr_perf_states ; i ++ ) {
@@ -113,6 +72,7 @@ static u64 get_pd_power_uw(struct dtpm *dtpm)
113
72
114
73
pd = em_cpu_get (dtpm_cpu -> cpu );
115
74
freq = cpufreq_quick_get (dtpm_cpu -> cpu );
75
+
116
76
cpumask_and (& cpus , cpu_online_mask , to_cpumask (pd -> cpus ));
117
77
nr_cpus = cpumask_weight (& cpus );
118
78
@@ -128,6 +88,27 @@ static u64 get_pd_power_uw(struct dtpm *dtpm)
128
88
return 0 ;
129
89
}
130
90
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
+
131
112
static void pd_release (struct dtpm * dtpm )
132
113
{
133
114
struct dtpm_cpu * dtpm_cpu = dtpm -> private ;
@@ -139,39 +120,24 @@ static void pd_release(struct dtpm *dtpm)
139
120
}
140
121
141
122
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 ,
145
127
};
146
128
147
129
static int cpuhp_dtpm_cpu_offline (unsigned int cpu )
148
130
{
149
- struct cpufreq_policy * policy ;
150
131
struct em_perf_domain * pd ;
151
132
struct dtpm * dtpm ;
152
133
153
- policy = cpufreq_cpu_get (cpu );
154
-
155
- if (!policy )
156
- return 0 ;
157
-
158
134
pd = em_cpu_get (cpu );
159
135
if (!pd )
160
136
return - EINVAL ;
161
137
162
138
dtpm = per_cpu (dtpm_per_cpu , cpu );
163
139
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 );
175
141
}
176
142
177
143
static int cpuhp_dtpm_cpu_online (unsigned int cpu )
@@ -184,7 +150,6 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu)
184
150
int ret = - ENOMEM ;
185
151
186
152
policy = cpufreq_cpu_get (cpu );
187
-
188
153
if (!policy )
189
154
return 0 ;
190
155
@@ -194,7 +159,7 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu)
194
159
195
160
dtpm = per_cpu (dtpm_per_cpu , cpu );
196
161
if (dtpm )
197
- return power_add (dtpm , pd );
162
+ return dtpm_update_power (dtpm );
198
163
199
164
dtpm = dtpm_alloc (& dtpm_ops );
200
165
if (!dtpm )
@@ -210,27 +175,20 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu)
210
175
for_each_cpu (cpu , policy -> related_cpus )
211
176
per_cpu (dtpm_per_cpu , cpu ) = dtpm ;
212
177
213
- sprintf (name , "cpu%d" , dtpm_cpu -> cpu );
178
+ snprintf (name , sizeof ( name ), "cpu%d-cpufreq " , dtpm_cpu -> cpu );
214
179
215
- ret = dtpm_register (name , dtpm , __parent );
180
+ ret = dtpm_register (name , dtpm , NULL );
216
181
if (ret )
217
182
goto out_kfree_dtpm_cpu ;
218
183
219
- ret = power_add (dtpm , pd );
220
- if (ret )
221
- goto out_dtpm_unregister ;
222
-
223
184
ret = freq_qos_add_request (& policy -> constraints ,
224
185
& dtpm_cpu -> qos_req , FREQ_QOS_MAX ,
225
186
pd -> table [pd -> nr_perf_states - 1 ].frequency );
226
187
if (ret )
227
- goto out_power_sub ;
188
+ goto out_dtpm_unregister ;
228
189
229
190
return 0 ;
230
191
231
- out_power_sub :
232
- power_sub (dtpm , pd );
233
-
234
192
out_dtpm_unregister :
235
193
dtpm_unregister (dtpm );
236
194
dtpm_cpu = NULL ;
@@ -248,10 +206,38 @@ static int cpuhp_dtpm_cpu_online(unsigned int cpu)
248
206
249
207
int dtpm_register_cpu (struct dtpm * parent )
250
208
{
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 ;
252
241
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 ;
257
243
}
0 commit comments