diff options
author | Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com> | 2016-03-22 09:27:09 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-03-22 18:11:18 -0400 |
commit | 1b0289848d5dcea74a6e5115d6c9892b0dbe9c8f (patch) | |
tree | 9c5e57f419938d5acc48ad5c63d275d07e20774d /drivers/cpufreq/powernv-cpufreq.c | |
parent | ac13b9967de7eeb7746f6533673e4dec94933bc9 (diff) |
cpufreq: powernv: Add sysfs attributes to show throttle stats
Create sysfs attributes to export throttle information in
/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats directory. The
newly added sysfs files are as follows:
1)/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/turbo_stat
2)/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/sub-turbo_stat
3)/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/unthrottle
4)/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/powercap
5)/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/overtemp
6)/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/supply_fault
7)/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/overcurrent
8)/sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/occ_reset
Detailed explanation of each attribute is added to
Documentation/ABI/testing/sysfs-devices-system-cpu
Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq/powernv-cpufreq.c')
-rw-r--r-- | drivers/cpufreq/powernv-cpufreq.c | 74 |
1 files changed, 72 insertions, 2 deletions
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index a00bcc2cef09..39ac78c94be0 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c | |||
@@ -54,6 +54,16 @@ static const char * const throttle_reason[] = { | |||
54 | "OCC Reset" | 54 | "OCC Reset" |
55 | }; | 55 | }; |
56 | 56 | ||
57 | enum throttle_reason_type { | ||
58 | NO_THROTTLE = 0, | ||
59 | POWERCAP, | ||
60 | CPU_OVERTEMP, | ||
61 | POWER_SUPPLY_FAILURE, | ||
62 | OVERCURRENT, | ||
63 | OCC_RESET_THROTTLE, | ||
64 | OCC_MAX_REASON | ||
65 | }; | ||
66 | |||
57 | static struct chip { | 67 | static struct chip { |
58 | unsigned int id; | 68 | unsigned int id; |
59 | bool throttled; | 69 | bool throttled; |
@@ -61,6 +71,9 @@ static struct chip { | |||
61 | u8 throttle_reason; | 71 | u8 throttle_reason; |
62 | cpumask_t mask; | 72 | cpumask_t mask; |
63 | struct work_struct throttle; | 73 | struct work_struct throttle; |
74 | int throttle_turbo; | ||
75 | int throttle_sub_turbo; | ||
76 | int reason[OCC_MAX_REASON]; | ||
64 | } *chips; | 77 | } *chips; |
65 | 78 | ||
66 | static int nr_chips; | 79 | static int nr_chips; |
@@ -196,6 +209,42 @@ static struct freq_attr *powernv_cpu_freq_attr[] = { | |||
196 | NULL, | 209 | NULL, |
197 | }; | 210 | }; |
198 | 211 | ||
212 | #define throttle_attr(name, member) \ | ||
213 | static ssize_t name##_show(struct cpufreq_policy *policy, char *buf) \ | ||
214 | { \ | ||
215 | struct chip *chip = per_cpu(chip_info, policy->cpu); \ | ||
216 | \ | ||
217 | return sprintf(buf, "%u\n", chip->member); \ | ||
218 | } \ | ||
219 | \ | ||
220 | static struct freq_attr throttle_attr_##name = __ATTR_RO(name) \ | ||
221 | |||
222 | throttle_attr(unthrottle, reason[NO_THROTTLE]); | ||
223 | throttle_attr(powercap, reason[POWERCAP]); | ||
224 | throttle_attr(overtemp, reason[CPU_OVERTEMP]); | ||
225 | throttle_attr(supply_fault, reason[POWER_SUPPLY_FAILURE]); | ||
226 | throttle_attr(overcurrent, reason[OVERCURRENT]); | ||
227 | throttle_attr(occ_reset, reason[OCC_RESET_THROTTLE]); | ||
228 | throttle_attr(turbo_stat, throttle_turbo); | ||
229 | throttle_attr(sub_turbo_stat, throttle_sub_turbo); | ||
230 | |||
231 | static struct attribute *throttle_attrs[] = { | ||
232 | &throttle_attr_unthrottle.attr, | ||
233 | &throttle_attr_powercap.attr, | ||
234 | &throttle_attr_overtemp.attr, | ||
235 | &throttle_attr_supply_fault.attr, | ||
236 | &throttle_attr_overcurrent.attr, | ||
237 | &throttle_attr_occ_reset.attr, | ||
238 | &throttle_attr_turbo_stat.attr, | ||
239 | &throttle_attr_sub_turbo_stat.attr, | ||
240 | NULL, | ||
241 | }; | ||
242 | |||
243 | static const struct attribute_group throttle_attr_grp = { | ||
244 | .name = "throttle_stats", | ||
245 | .attrs = throttle_attrs, | ||
246 | }; | ||
247 | |||
199 | /* Helper routines */ | 248 | /* Helper routines */ |
200 | 249 | ||
201 | /* Access helpers to power mgt SPR */ | 250 | /* Access helpers to power mgt SPR */ |
@@ -338,10 +387,14 @@ static void powernv_cpufreq_throttle_check(void *data) | |||
338 | if (chip->throttled) | 387 | if (chip->throttled) |
339 | goto next; | 388 | goto next; |
340 | chip->throttled = true; | 389 | chip->throttled = true; |
341 | if (pmsr_pmax < powernv_pstate_info.nominal) | 390 | if (pmsr_pmax < powernv_pstate_info.nominal) { |
342 | pr_warn_once("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n", | 391 | pr_warn_once("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n", |
343 | cpu, chip->id, pmsr_pmax, | 392 | cpu, chip->id, pmsr_pmax, |
344 | powernv_pstate_info.nominal); | 393 | powernv_pstate_info.nominal); |
394 | chip->throttle_sub_turbo++; | ||
395 | } else { | ||
396 | chip->throttle_turbo++; | ||
397 | } | ||
345 | trace_powernv_throttle(chip->id, | 398 | trace_powernv_throttle(chip->id, |
346 | throttle_reason[chip->throttle_reason], | 399 | throttle_reason[chip->throttle_reason], |
347 | pmsr_pmax); | 400 | pmsr_pmax); |
@@ -408,6 +461,21 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
408 | for (i = 0; i < threads_per_core; i++) | 461 | for (i = 0; i < threads_per_core; i++) |
409 | cpumask_set_cpu(base + i, policy->cpus); | 462 | cpumask_set_cpu(base + i, policy->cpus); |
410 | 463 | ||
464 | if (!policy->driver_data) { | ||
465 | int ret; | ||
466 | |||
467 | ret = sysfs_create_group(&policy->kobj, &throttle_attr_grp); | ||
468 | if (ret) { | ||
469 | pr_info("Failed to create throttle stats directory for cpu %d\n", | ||
470 | policy->cpu); | ||
471 | return ret; | ||
472 | } | ||
473 | /* | ||
474 | * policy->driver_data is used as a flag for one-time | ||
475 | * creation of throttle sysfs files. | ||
476 | */ | ||
477 | policy->driver_data = policy; | ||
478 | } | ||
411 | return cpufreq_table_validate_and_show(policy, powernv_freqs); | 479 | return cpufreq_table_validate_and_show(policy, powernv_freqs); |
412 | } | 480 | } |
413 | 481 | ||
@@ -514,8 +582,10 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb, | |||
514 | break; | 582 | break; |
515 | 583 | ||
516 | if (omsg.throttle_status >= 0 && | 584 | if (omsg.throttle_status >= 0 && |
517 | omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS) | 585 | omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS) { |
518 | chips[i].throttle_reason = omsg.throttle_status; | 586 | chips[i].throttle_reason = omsg.throttle_status; |
587 | chips[i].reason[omsg.throttle_status]++; | ||
588 | } | ||
519 | 589 | ||
520 | if (!omsg.throttle_status) | 590 | if (!omsg.throttle_status) |
521 | chips[i].restore = true; | 591 | chips[i].restore = true; |