blob: a634199052b6cd2f84ed2021d263ab3baef85c0f [file] [log] [blame]
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +05301/*
2 * POWERNV cpufreq driver for the IBM POWER processors
3 *
4 * (C) Copyright IBM 2014
5 *
6 * 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 */
19
20#define pr_fmt(fmt) "powernv-cpufreq: " fmt
21
22#include <linux/kernel.h>
23#include <linux/sysfs.h>
24#include <linux/cpumask.h>
25#include <linux/module.h>
26#include <linux/cpufreq.h>
27#include <linux/smp.h>
28#include <linux/of.h>
Shilpasri G Bhatcf30af762014-09-29 15:49:11 +020029#include <linux/reboot.h>
Shilpasri G Bhat053819e2015-07-16 13:34:18 +053030#include <linux/slab.h>
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +053031
32#include <asm/cputhreads.h>
Vaidyanathan Srinivasan6174bac2014-08-03 14:54:05 +053033#include <asm/firmware.h>
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +053034#include <asm/reg.h>
Srivatsa S. Bhatf3cae352014-04-16 11:35:38 +053035#include <asm/smp.h> /* Required for cpu_sibling_mask() in UP configs */
Shilpasri G Bhatcb166fa2015-07-16 13:34:20 +053036#include <asm/opal.h>
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +053037
38#define POWERNV_MAX_PSTATES 256
Shilpasri G Bhat09a972d2015-04-01 15:16:34 +053039#define PMSR_PSAFE_ENABLE (1UL << 30)
40#define PMSR_SPR_EM_DISABLE (1UL << 31)
41#define PMSR_MAX(x) ((x >> 32) & 0xFF)
42#define PMSR_LP(x) ((x >> 48) & 0xFF)
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +053043
44static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
Shilpasri G Bhatcb166fa2015-07-16 13:34:20 +053045static bool rebooting, throttled, occ_reset;
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +053046
Shilpasri G Bhat053819e2015-07-16 13:34:18 +053047static struct chip {
48 unsigned int id;
49 bool throttled;
50} *chips;
51
52static int nr_chips;
53
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +053054/*
55 * Note: The set of pstates consists of contiguous integers, the
56 * smallest of which is indicated by powernv_pstate_info.min, the
57 * largest of which is indicated by powernv_pstate_info.max.
58 *
59 * The nominal pstate is the highest non-turbo pstate in this
60 * platform. This is indicated by powernv_pstate_info.nominal.
61 */
62static struct powernv_pstate_info {
63 int min;
64 int max;
65 int nominal;
66 int nr_pstates;
67} powernv_pstate_info;
68
69/*
70 * Initialize the freq table based on data obtained
71 * from the firmware passed via device-tree
72 */
73static int init_powernv_pstates(void)
74{
75 struct device_node *power_mgt;
76 int i, pstate_min, pstate_max, pstate_nominal, nr_pstates = 0;
77 const __be32 *pstate_ids, *pstate_freqs;
78 u32 len_ids, len_freqs;
79
80 power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
81 if (!power_mgt) {
82 pr_warn("power-mgt node not found\n");
83 return -ENODEV;
84 }
85
86 if (of_property_read_u32(power_mgt, "ibm,pstate-min", &pstate_min)) {
87 pr_warn("ibm,pstate-min node not found\n");
88 return -ENODEV;
89 }
90
91 if (of_property_read_u32(power_mgt, "ibm,pstate-max", &pstate_max)) {
92 pr_warn("ibm,pstate-max node not found\n");
93 return -ENODEV;
94 }
95
96 if (of_property_read_u32(power_mgt, "ibm,pstate-nominal",
97 &pstate_nominal)) {
98 pr_warn("ibm,pstate-nominal not found\n");
99 return -ENODEV;
100 }
101 pr_info("cpufreq pstate min %d nominal %d max %d\n", pstate_min,
102 pstate_nominal, pstate_max);
103
104 pstate_ids = of_get_property(power_mgt, "ibm,pstate-ids", &len_ids);
105 if (!pstate_ids) {
106 pr_warn("ibm,pstate-ids not found\n");
107 return -ENODEV;
108 }
109
110 pstate_freqs = of_get_property(power_mgt, "ibm,pstate-frequencies-mhz",
111 &len_freqs);
112 if (!pstate_freqs) {
113 pr_warn("ibm,pstate-frequencies-mhz not found\n");
114 return -ENODEV;
115 }
116
Vaidyanathan Srinivasan6174bac2014-08-03 14:54:05 +0530117 if (len_ids != len_freqs) {
118 pr_warn("Entries in ibm,pstate-ids and "
119 "ibm,pstate-frequencies-mhz does not match\n");
120 }
121
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530122 nr_pstates = min(len_ids, len_freqs) / sizeof(u32);
123 if (!nr_pstates) {
124 pr_warn("No PStates found\n");
125 return -ENODEV;
126 }
127
128 pr_debug("NR PStates %d\n", nr_pstates);
129 for (i = 0; i < nr_pstates; i++) {
130 u32 id = be32_to_cpu(pstate_ids[i]);
131 u32 freq = be32_to_cpu(pstate_freqs[i]);
132
133 pr_debug("PState id %d freq %d MHz\n", id, freq);
134 powernv_freqs[i].frequency = freq * 1000; /* kHz */
Gautham R. Shenoy0692c692014-04-01 12:43:27 +0530135 powernv_freqs[i].driver_data = id;
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530136 }
137 /* End of list marker entry */
138 powernv_freqs[i].frequency = CPUFREQ_TABLE_END;
139
140 powernv_pstate_info.min = pstate_min;
141 powernv_pstate_info.max = pstate_max;
142 powernv_pstate_info.nominal = pstate_nominal;
143 powernv_pstate_info.nr_pstates = nr_pstates;
144
145 return 0;
146}
147
148/* Returns the CPU frequency corresponding to the pstate_id. */
149static unsigned int pstate_id_to_freq(int pstate_id)
150{
151 int i;
152
153 i = powernv_pstate_info.max - pstate_id;
Vaidyanathan Srinivasan6174bac2014-08-03 14:54:05 +0530154 if (i >= powernv_pstate_info.nr_pstates || i < 0) {
155 pr_warn("PState id %d outside of PState table, "
156 "reporting nominal id %d instead\n",
157 pstate_id, powernv_pstate_info.nominal);
158 i = powernv_pstate_info.max - powernv_pstate_info.nominal;
159 }
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530160
161 return powernv_freqs[i].frequency;
162}
163
164/*
165 * cpuinfo_nominal_freq_show - Show the nominal CPU frequency as indicated by
166 * the firmware
167 */
168static ssize_t cpuinfo_nominal_freq_show(struct cpufreq_policy *policy,
169 char *buf)
170{
171 return sprintf(buf, "%u\n",
172 pstate_id_to_freq(powernv_pstate_info.nominal));
173}
174
175struct freq_attr cpufreq_freq_attr_cpuinfo_nominal_freq =
176 __ATTR_RO(cpuinfo_nominal_freq);
177
178static struct freq_attr *powernv_cpu_freq_attr[] = {
179 &cpufreq_freq_attr_scaling_available_freqs,
180 &cpufreq_freq_attr_cpuinfo_nominal_freq,
181 NULL,
182};
183
184/* Helper routines */
185
186/* Access helpers to power mgt SPR */
187
188static inline unsigned long get_pmspr(unsigned long sprn)
189{
190 switch (sprn) {
191 case SPRN_PMCR:
192 return mfspr(SPRN_PMCR);
193
194 case SPRN_PMICR:
195 return mfspr(SPRN_PMICR);
196
197 case SPRN_PMSR:
198 return mfspr(SPRN_PMSR);
199 }
200 BUG();
201}
202
203static inline void set_pmspr(unsigned long sprn, unsigned long val)
204{
205 switch (sprn) {
206 case SPRN_PMCR:
207 mtspr(SPRN_PMCR, val);
208 return;
209
210 case SPRN_PMICR:
211 mtspr(SPRN_PMICR, val);
212 return;
213 }
214 BUG();
215}
216
217/*
218 * Use objects of this type to query/update
219 * pstates on a remote CPU via smp_call_function.
220 */
221struct powernv_smp_call_data {
222 unsigned int freq;
223 int pstate_id;
224};
225
226/*
227 * powernv_read_cpu_freq: Reads the current frequency on this CPU.
228 *
229 * Called via smp_call_function.
230 *
231 * Note: The caller of the smp_call_function should pass an argument of
232 * the type 'struct powernv_smp_call_data *' along with this function.
233 *
234 * The current frequency on this CPU will be returned via
235 * ((struct powernv_smp_call_data *)arg)->freq;
236 */
237static void powernv_read_cpu_freq(void *arg)
238{
239 unsigned long pmspr_val;
240 s8 local_pstate_id;
241 struct powernv_smp_call_data *freq_data = arg;
242
243 pmspr_val = get_pmspr(SPRN_PMSR);
244
245 /*
246 * The local pstate id corresponds bits 48..55 in the PMSR.
247 * Note: Watch out for the sign!
248 */
249 local_pstate_id = (pmspr_val >> 48) & 0xFF;
250 freq_data->pstate_id = local_pstate_id;
251 freq_data->freq = pstate_id_to_freq(freq_data->pstate_id);
252
253 pr_debug("cpu %d pmsr %016lX pstate_id %d frequency %d kHz\n",
254 raw_smp_processor_id(), pmspr_val, freq_data->pstate_id,
255 freq_data->freq);
256}
257
258/*
259 * powernv_cpufreq_get: Returns the CPU frequency as reported by the
260 * firmware for CPU 'cpu'. This value is reported through the sysfs
261 * file cpuinfo_cur_freq.
262 */
Brian Norris60d1ea42014-05-11 00:51:20 -0700263static unsigned int powernv_cpufreq_get(unsigned int cpu)
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530264{
265 struct powernv_smp_call_data freq_data;
266
267 smp_call_function_any(cpu_sibling_mask(cpu), powernv_read_cpu_freq,
268 &freq_data, 1);
269
270 return freq_data.freq;
271}
272
273/*
274 * set_pstate: Sets the pstate on this CPU.
275 *
276 * This is called via an smp_call_function.
277 *
278 * The caller must ensure that freq_data is of the type
279 * (struct powernv_smp_call_data *) and the pstate_id which needs to be set
280 * on this CPU should be present in freq_data->pstate_id.
281 */
282static void set_pstate(void *freq_data)
283{
284 unsigned long val;
285 unsigned long pstate_ul =
286 ((struct powernv_smp_call_data *) freq_data)->pstate_id;
287
288 val = get_pmspr(SPRN_PMCR);
289 val = val & 0x0000FFFFFFFFFFFFULL;
290
291 pstate_ul = pstate_ul & 0xFF;
292
293 /* Set both global(bits 56..63) and local(bits 48..55) PStates */
294 val = val | (pstate_ul << 56) | (pstate_ul << 48);
295
296 pr_debug("Setting cpu %d pmcr to %016lX\n",
297 raw_smp_processor_id(), val);
298 set_pmspr(SPRN_PMCR, val);
299}
300
301/*
Shilpasri G Bhatcf30af762014-09-29 15:49:11 +0200302 * get_nominal_index: Returns the index corresponding to the nominal
303 * pstate in the cpufreq table
304 */
305static inline unsigned int get_nominal_index(void)
306{
307 return powernv_pstate_info.max - powernv_pstate_info.nominal;
308}
309
Shilpasri G Bhat09a972d2015-04-01 15:16:34 +0530310static void powernv_cpufreq_throttle_check(unsigned int cpu)
311{
312 unsigned long pmsr;
Shilpasri G Bhat053819e2015-07-16 13:34:18 +0530313 int pmsr_pmax, pmsr_lp, i;
Shilpasri G Bhat09a972d2015-04-01 15:16:34 +0530314
315 pmsr = get_pmspr(SPRN_PMSR);
316
Shilpasri G Bhat053819e2015-07-16 13:34:18 +0530317 for (i = 0; i < nr_chips; i++)
318 if (chips[i].id == cpu_to_chip_id(cpu))
319 break;
320
Shilpasri G Bhat09a972d2015-04-01 15:16:34 +0530321 /* Check for Pmax Capping */
322 pmsr_pmax = (s8)PMSR_MAX(pmsr);
323 if (pmsr_pmax != powernv_pstate_info.max) {
Shilpasri G Bhat053819e2015-07-16 13:34:18 +0530324 if (chips[i].throttled)
325 goto next;
326 chips[i].throttled = true;
327 pr_info("CPU %d on Chip %u has Pmax reduced to %d\n", cpu,
328 chips[i].id, pmsr_pmax);
329 } else if (chips[i].throttled) {
330 chips[i].throttled = false;
331 pr_info("CPU %d on Chip %u has Pmax restored to %d\n", cpu,
332 chips[i].id, pmsr_pmax);
Shilpasri G Bhat09a972d2015-04-01 15:16:34 +0530333 }
334
335 /*
336 * Check for Psafe by reading LocalPstate
337 * or check if Psafe_mode_active is set in PMSR.
338 */
Shilpasri G Bhat053819e2015-07-16 13:34:18 +0530339next:
Shilpasri G Bhat09a972d2015-04-01 15:16:34 +0530340 pmsr_lp = (s8)PMSR_LP(pmsr);
341 if ((pmsr_lp < powernv_pstate_info.min) ||
342 (pmsr & PMSR_PSAFE_ENABLE)) {
343 throttled = true;
344 pr_info("Pstate set to safe frequency\n");
345 }
346
347 /* Check if SPR_EM_DISABLE is set in PMSR */
348 if (pmsr & PMSR_SPR_EM_DISABLE) {
349 throttled = true;
350 pr_info("Frequency Control disabled from OS\n");
351 }
352
353 if (throttled) {
354 pr_info("PMSR = %16lx\n", pmsr);
355 pr_crit("CPU Frequency could be throttled\n");
356 }
357}
358
Shilpasri G Bhatcf30af762014-09-29 15:49:11 +0200359/*
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530360 * powernv_cpufreq_target_index: Sets the frequency corresponding to
361 * the cpufreq table entry indexed by new_index on the cpus in the
362 * mask policy->cpus
363 */
364static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
365 unsigned int new_index)
366{
367 struct powernv_smp_call_data freq_data;
368
Shilpasri G Bhatcf30af762014-09-29 15:49:11 +0200369 if (unlikely(rebooting) && new_index != get_nominal_index())
370 return 0;
371
Shilpasri G Bhat09a972d2015-04-01 15:16:34 +0530372 if (!throttled)
373 powernv_cpufreq_throttle_check(smp_processor_id());
374
Gautham R. Shenoy0692c692014-04-01 12:43:27 +0530375 freq_data.pstate_id = powernv_freqs[new_index].driver_data;
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530376
377 /*
378 * Use smp_call_function to send IPI and execute the
379 * mtspr on target CPU. We could do that without IPI
380 * if current CPU is within policy->cpus (core)
381 */
382 smp_call_function_any(policy->cpus, set_pstate, &freq_data, 1);
383
384 return 0;
385}
386
387static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
388{
389 int base, i;
390
391 base = cpu_first_thread_sibling(policy->cpu);
392
393 for (i = 0; i < threads_per_core; i++)
394 cpumask_set_cpu(base + i, policy->cpus);
395
396 return cpufreq_table_validate_and_show(policy, powernv_freqs);
397}
398
Shilpasri G Bhatcf30af762014-09-29 15:49:11 +0200399static int powernv_cpufreq_reboot_notifier(struct notifier_block *nb,
400 unsigned long action, void *unused)
401{
402 int cpu;
403 struct cpufreq_policy cpu_policy;
404
405 rebooting = true;
406 for_each_online_cpu(cpu) {
407 cpufreq_get_policy(&cpu_policy, cpu);
408 powernv_cpufreq_target_index(&cpu_policy, get_nominal_index());
409 }
410
411 return NOTIFY_DONE;
412}
413
414static struct notifier_block powernv_cpufreq_reboot_nb = {
415 .notifier_call = powernv_cpufreq_reboot_notifier,
416};
417
Shilpasri G Bhatcb166fa2015-07-16 13:34:20 +0530418static char throttle_reason[][30] = {
419 "No throttling",
420 "Power Cap",
421 "Processor Over Temperature",
422 "Power Supply Failure",
423 "Over Current",
424 "OCC Reset"
425 };
426
427static int powernv_cpufreq_occ_msg(struct notifier_block *nb,
428 unsigned long msg_type, void *_msg)
429{
430 struct opal_msg *msg = _msg;
431 struct opal_occ_msg omsg;
432
433 if (msg_type != OPAL_MSG_OCC)
434 return 0;
435
436 omsg.type = be64_to_cpu(msg->params[0]);
437
438 switch (omsg.type) {
439 case OCC_RESET:
440 occ_reset = true;
441 /*
442 * powernv_cpufreq_throttle_check() is called in
443 * target() callback which can detect the throttle state
444 * for governors like ondemand.
445 * But static governors will not call target() often thus
446 * report throttling here.
447 */
448 if (!throttled) {
449 throttled = true;
450 pr_crit("CPU Frequency is throttled\n");
451 }
452 pr_info("OCC: Reset\n");
453 break;
454 case OCC_LOAD:
455 pr_info("OCC: Loaded\n");
456 break;
457 case OCC_THROTTLE:
458 omsg.chip = be64_to_cpu(msg->params[1]);
459 omsg.throttle_status = be64_to_cpu(msg->params[2]);
460
461 if (occ_reset) {
462 occ_reset = false;
463 throttled = false;
464 pr_info("OCC: Active\n");
465 return 0;
466 }
467
468 if (omsg.throttle_status &&
469 omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS)
470 pr_info("OCC: Chip %u Pmax reduced due to %s\n",
471 (unsigned int)omsg.chip,
472 throttle_reason[omsg.throttle_status]);
473 else if (!omsg.throttle_status)
474 pr_info("OCC: Chip %u %s\n", (unsigned int)omsg.chip,
475 throttle_reason[omsg.throttle_status]);
476 }
477 return 0;
478}
479
480static struct notifier_block powernv_cpufreq_opal_nb = {
481 .notifier_call = powernv_cpufreq_occ_msg,
482 .next = NULL,
483 .priority = 0,
484};
485
Preeti U Murthyb1203392014-09-29 15:47:53 +0200486static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy)
487{
488 struct powernv_smp_call_data freq_data;
489
490 freq_data.pstate_id = powernv_pstate_info.min;
491 smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1);
492}
493
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530494static struct cpufreq_driver powernv_cpufreq_driver = {
495 .name = "powernv-cpufreq",
496 .flags = CPUFREQ_CONST_LOOPS,
497 .init = powernv_cpufreq_cpu_init,
498 .verify = cpufreq_generic_frequency_table_verify,
499 .target_index = powernv_cpufreq_target_index,
500 .get = powernv_cpufreq_get,
Preeti U Murthyb1203392014-09-29 15:47:53 +0200501 .stop_cpu = powernv_cpufreq_stop_cpu,
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530502 .attr = powernv_cpu_freq_attr,
503};
504
Shilpasri G Bhat053819e2015-07-16 13:34:18 +0530505static int init_chip_info(void)
506{
507 unsigned int chip[256];
508 unsigned int cpu, i;
509 unsigned int prev_chip_id = UINT_MAX;
510
511 for_each_possible_cpu(cpu) {
512 unsigned int id = cpu_to_chip_id(cpu);
513
514 if (prev_chip_id != id) {
515 prev_chip_id = id;
516 chip[nr_chips++] = id;
517 }
518 }
519
520 chips = kmalloc_array(nr_chips, sizeof(struct chip), GFP_KERNEL);
521 if (!chips)
522 return -ENOMEM;
523
524 for (i = 0; i < nr_chips; i++) {
525 chips[i].id = chip[i];
526 chips[i].throttled = false;
527 }
528
529 return 0;
530}
531
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530532static int __init powernv_cpufreq_init(void)
533{
534 int rc = 0;
535
Vaidyanathan Srinivasan6174bac2014-08-03 14:54:05 +0530536 /* Don't probe on pseries (guest) platforms */
537 if (!firmware_has_feature(FW_FEATURE_OPALv3))
538 return -ENODEV;
539
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530540 /* Discover pstates from device tree and init */
541 rc = init_powernv_pstates();
542 if (rc) {
543 pr_info("powernv-cpufreq disabled. System does not support PState control\n");
544 return rc;
545 }
546
Shilpasri G Bhat053819e2015-07-16 13:34:18 +0530547 /* Populate chip info */
548 rc = init_chip_info();
549 if (rc)
550 return rc;
551
Shilpasri G Bhatcf30af762014-09-29 15:49:11 +0200552 register_reboot_notifier(&powernv_cpufreq_reboot_nb);
Shilpasri G Bhatcb166fa2015-07-16 13:34:20 +0530553 opal_message_notifier_register(OPAL_MSG_OCC, &powernv_cpufreq_opal_nb);
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530554 return cpufreq_register_driver(&powernv_cpufreq_driver);
555}
556module_init(powernv_cpufreq_init);
557
558static void __exit powernv_cpufreq_exit(void)
559{
Shilpasri G Bhatcf30af762014-09-29 15:49:11 +0200560 unregister_reboot_notifier(&powernv_cpufreq_reboot_nb);
Shilpasri G Bhatcb166fa2015-07-16 13:34:20 +0530561 opal_message_notifier_unregister(OPAL_MSG_OCC,
562 &powernv_cpufreq_opal_nb);
Vaidyanathan Srinivasanb3d627a2014-04-01 12:43:26 +0530563 cpufreq_unregister_driver(&powernv_cpufreq_driver);
564}
565module_exit(powernv_cpufreq_exit);
566
567MODULE_LICENSE("GPL");
568MODULE_AUTHOR("Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com>");