.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * POWERNV cpufreq driver for the IBM POWER processors |
---|
3 | 4 | * |
---|
4 | 5 | * (C) Copyright IBM 2014 |
---|
5 | 6 | * |
---|
6 | 7 | * Author: Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com> |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License as published by |
---|
10 | | - * the Free Software Foundation; either version 2, or (at your option) |
---|
11 | | - * any later version. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, |
---|
14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
16 | | - * GNU General Public License for more details. |
---|
17 | | - * |
---|
18 | 8 | */ |
---|
19 | 9 | |
---|
20 | 10 | #define pr_fmt(fmt) "powernv-cpufreq: " fmt |
---|
.. | .. |
---|
75 | 65 | * highest_lpstate_idx |
---|
76 | 66 | * @last_sampled_time: Time from boot in ms when global pstates were |
---|
77 | 67 | * last set |
---|
78 | | - * @last_lpstate_idx, Last set value of local pstate and global |
---|
79 | | - * last_gpstate_idx pstate in terms of cpufreq table index |
---|
| 68 | + * @last_lpstate_idx: Last set value of local pstate and global |
---|
| 69 | + * @last_gpstate_idx: pstate in terms of cpufreq table index |
---|
80 | 70 | * @timer: Is used for ramping down if cpu goes idle for |
---|
81 | 71 | * a long time with global pstate held high |
---|
82 | 72 | * @gpstate_lock: A spinlock to maintain synchronization between |
---|
83 | 73 | * routines called by the timer handler and |
---|
84 | 74 | * governer's target_index calls |
---|
| 75 | + * @policy: Associated CPUFreq policy |
---|
85 | 76 | */ |
---|
86 | 77 | struct global_pstate_info { |
---|
87 | 78 | int highest_lpstate_idx; |
---|
.. | .. |
---|
96 | 87 | |
---|
97 | 88 | static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; |
---|
98 | 89 | |
---|
99 | | -DEFINE_HASHTABLE(pstate_revmap, POWERNV_MAX_PSTATES_ORDER); |
---|
| 90 | +static DEFINE_HASHTABLE(pstate_revmap, POWERNV_MAX_PSTATES_ORDER); |
---|
100 | 91 | /** |
---|
101 | 92 | * struct pstate_idx_revmap_data: Entry in the hashmap pstate_revmap |
---|
102 | 93 | * indexed by a function of pstate id. |
---|
.. | .. |
---|
181 | 172 | |
---|
182 | 173 | /* Use following functions for conversions between pstate_id and index */ |
---|
183 | 174 | |
---|
184 | | -/** |
---|
| 175 | +/* |
---|
185 | 176 | * idx_to_pstate : Returns the pstate id corresponding to the |
---|
186 | 177 | * frequency in the cpufreq frequency table |
---|
187 | 178 | * powernv_freqs indexed by @i. |
---|
.. | .. |
---|
199 | 190 | return powernv_freqs[i].driver_data; |
---|
200 | 191 | } |
---|
201 | 192 | |
---|
202 | | -/** |
---|
| 193 | +/* |
---|
203 | 194 | * pstate_to_idx : Returns the index in the cpufreq frequencytable |
---|
204 | 195 | * powernv_freqs for the frequency whose corresponding |
---|
205 | 196 | * pstate id is @pstate. |
---|
.. | .. |
---|
245 | 236 | u32 len_ids, len_freqs; |
---|
246 | 237 | u32 pstate_min, pstate_max, pstate_nominal; |
---|
247 | 238 | u32 pstate_turbo, pstate_ultra_turbo; |
---|
| 239 | + int rc = -ENODEV; |
---|
248 | 240 | |
---|
249 | 241 | power_mgt = of_find_node_by_path("/ibm,opal/power-mgt"); |
---|
250 | 242 | if (!power_mgt) { |
---|
.. | .. |
---|
254 | 246 | |
---|
255 | 247 | if (of_property_read_u32(power_mgt, "ibm,pstate-min", &pstate_min)) { |
---|
256 | 248 | pr_warn("ibm,pstate-min node not found\n"); |
---|
257 | | - return -ENODEV; |
---|
| 249 | + goto out; |
---|
258 | 250 | } |
---|
259 | 251 | |
---|
260 | 252 | if (of_property_read_u32(power_mgt, "ibm,pstate-max", &pstate_max)) { |
---|
261 | 253 | pr_warn("ibm,pstate-max node not found\n"); |
---|
262 | | - return -ENODEV; |
---|
| 254 | + goto out; |
---|
263 | 255 | } |
---|
264 | 256 | |
---|
265 | 257 | if (of_property_read_u32(power_mgt, "ibm,pstate-nominal", |
---|
266 | 258 | &pstate_nominal)) { |
---|
267 | 259 | pr_warn("ibm,pstate-nominal not found\n"); |
---|
268 | | - return -ENODEV; |
---|
| 260 | + goto out; |
---|
269 | 261 | } |
---|
270 | 262 | |
---|
271 | 263 | if (of_property_read_u32(power_mgt, "ibm,pstate-ultra-turbo", |
---|
.. | .. |
---|
294 | 286 | pstate_ids = of_get_property(power_mgt, "ibm,pstate-ids", &len_ids); |
---|
295 | 287 | if (!pstate_ids) { |
---|
296 | 288 | pr_warn("ibm,pstate-ids not found\n"); |
---|
297 | | - return -ENODEV; |
---|
| 289 | + goto out; |
---|
298 | 290 | } |
---|
299 | 291 | |
---|
300 | 292 | pstate_freqs = of_get_property(power_mgt, "ibm,pstate-frequencies-mhz", |
---|
301 | 293 | &len_freqs); |
---|
302 | 294 | if (!pstate_freqs) { |
---|
303 | 295 | pr_warn("ibm,pstate-frequencies-mhz not found\n"); |
---|
304 | | - return -ENODEV; |
---|
| 296 | + goto out; |
---|
305 | 297 | } |
---|
306 | 298 | |
---|
307 | 299 | if (len_ids != len_freqs) { |
---|
.. | .. |
---|
312 | 304 | nr_pstates = min(len_ids, len_freqs) / sizeof(u32); |
---|
313 | 305 | if (!nr_pstates) { |
---|
314 | 306 | pr_warn("No PStates found\n"); |
---|
315 | | - return -ENODEV; |
---|
| 307 | + goto out; |
---|
316 | 308 | } |
---|
317 | 309 | |
---|
318 | 310 | powernv_pstate_info.nr_pstates = nr_pstates; |
---|
.. | .. |
---|
328 | 320 | powernv_freqs[i].frequency = freq * 1000; /* kHz */ |
---|
329 | 321 | powernv_freqs[i].driver_data = id & 0xFF; |
---|
330 | 322 | |
---|
331 | | - revmap_data = (struct pstate_idx_revmap_data *) |
---|
332 | | - kmalloc(sizeof(*revmap_data), GFP_KERNEL); |
---|
| 323 | + revmap_data = kmalloc(sizeof(*revmap_data), GFP_KERNEL); |
---|
| 324 | + if (!revmap_data) { |
---|
| 325 | + rc = -ENOMEM; |
---|
| 326 | + goto out; |
---|
| 327 | + } |
---|
333 | 328 | |
---|
334 | 329 | revmap_data->pstate_id = id & 0xFF; |
---|
335 | 330 | revmap_data->cpufreq_table_idx = i; |
---|
.. | .. |
---|
353 | 348 | |
---|
354 | 349 | /* End of list marker entry */ |
---|
355 | 350 | powernv_freqs[i].frequency = CPUFREQ_TABLE_END; |
---|
| 351 | + |
---|
| 352 | + of_node_put(power_mgt); |
---|
356 | 353 | return 0; |
---|
| 354 | +out: |
---|
| 355 | + of_node_put(power_mgt); |
---|
| 356 | + return rc; |
---|
357 | 357 | } |
---|
358 | 358 | |
---|
359 | 359 | /* Returns the CPU frequency corresponding to the pstate_id. */ |
---|
.. | .. |
---|
382 | 382 | powernv_freqs[powernv_pstate_info.nominal].frequency); |
---|
383 | 383 | } |
---|
384 | 384 | |
---|
385 | | -struct freq_attr cpufreq_freq_attr_cpuinfo_nominal_freq = |
---|
| 385 | +static struct freq_attr cpufreq_freq_attr_cpuinfo_nominal_freq = |
---|
386 | 386 | __ATTR_RO(cpuinfo_nominal_freq); |
---|
387 | 387 | |
---|
388 | 388 | #define SCALING_BOOST_FREQS_ATTR_INDEX 2 |
---|
.. | .. |
---|
662 | 662 | /** |
---|
663 | 663 | * gpstate_timer_handler |
---|
664 | 664 | * |
---|
665 | | - * @data: pointer to cpufreq_policy on which timer was queued |
---|
| 665 | + * @t: Timer context used to fetch global pstate info struct |
---|
666 | 666 | * |
---|
667 | 667 | * This handler brings down the global pstate closer to the local pstate |
---|
668 | 668 | * according quadratic equation. Queues a new timer if it is still not equal |
---|
669 | 669 | * to local pstate |
---|
670 | 670 | */ |
---|
671 | | -void gpstate_timer_handler(struct timer_list *t) |
---|
| 671 | +static void gpstate_timer_handler(struct timer_list *t) |
---|
672 | 672 | { |
---|
673 | 673 | struct global_pstate_info *gpstates = from_timer(gpstates, t, timer); |
---|
674 | 674 | struct cpufreq_policy *policy = gpstates->policy; |
---|
.. | .. |
---|
904 | 904 | .notifier_call = powernv_cpufreq_reboot_notifier, |
---|
905 | 905 | }; |
---|
906 | 906 | |
---|
907 | | -void powernv_cpufreq_work_fn(struct work_struct *work) |
---|
| 907 | +static void powernv_cpufreq_work_fn(struct work_struct *work) |
---|
908 | 908 | { |
---|
909 | 909 | struct chip *chip = container_of(work, struct chip, throttle); |
---|
910 | 910 | struct cpufreq_policy *policy; |
---|
.. | .. |
---|
1133 | 1133 | if (rc) |
---|
1134 | 1134 | goto out; |
---|
1135 | 1135 | |
---|
1136 | | - register_reboot_notifier(&powernv_cpufreq_reboot_nb); |
---|
1137 | | - opal_message_notifier_register(OPAL_MSG_OCC, &powernv_cpufreq_opal_nb); |
---|
1138 | | - |
---|
1139 | 1136 | if (powernv_pstate_info.wof_enabled) |
---|
1140 | 1137 | powernv_cpufreq_driver.boost_enabled = true; |
---|
1141 | 1138 | else |
---|
.. | .. |
---|
1144 | 1141 | rc = cpufreq_register_driver(&powernv_cpufreq_driver); |
---|
1145 | 1142 | if (rc) { |
---|
1146 | 1143 | pr_info("Failed to register the cpufreq driver (%d)\n", rc); |
---|
1147 | | - goto cleanup_notifiers; |
---|
| 1144 | + goto cleanup; |
---|
1148 | 1145 | } |
---|
1149 | 1146 | |
---|
1150 | 1147 | if (powernv_pstate_info.wof_enabled) |
---|
1151 | 1148 | cpufreq_enable_boost_support(); |
---|
1152 | 1149 | |
---|
| 1150 | + register_reboot_notifier(&powernv_cpufreq_reboot_nb); |
---|
| 1151 | + opal_message_notifier_register(OPAL_MSG_OCC, &powernv_cpufreq_opal_nb); |
---|
| 1152 | + |
---|
1153 | 1153 | return 0; |
---|
1154 | | -cleanup_notifiers: |
---|
1155 | | - unregister_all_notifiers(); |
---|
| 1154 | +cleanup: |
---|
1156 | 1155 | clean_chip_info(); |
---|
1157 | 1156 | out: |
---|
1158 | 1157 | pr_info("Platform driver disabled. System does not support PState control\n"); |
---|