cpufreq: powernv: Remove flag use-case of policy->driver_data
[linux-2.6-block.git] / drivers / cpufreq / powernv-cpufreq.c
index 50bf12033bbc080c70b5de72de3f89c2dc8bd3a6..e2e221904d2554ea3f22394162464b8fb6f8da49 100644 (file)
@@ -44,7 +44,6 @@
 
 static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
 static bool rebooting, throttled, occ_reset;
-static unsigned int *core_to_chip_map;
 
 static const char * const throttle_reason[] = {
        "No throttling",
@@ -55,6 +54,16 @@ static const char * const throttle_reason[] = {
        "OCC Reset"
 };
 
+enum throttle_reason_type {
+       NO_THROTTLE = 0,
+       POWERCAP,
+       CPU_OVERTEMP,
+       POWER_SUPPLY_FAILURE,
+       OVERCURRENT,
+       OCC_RESET_THROTTLE,
+       OCC_MAX_REASON
+};
+
 static struct chip {
        unsigned int id;
        bool throttled;
@@ -62,9 +71,13 @@ static struct chip {
        u8 throttle_reason;
        cpumask_t mask;
        struct work_struct throttle;
+       int throttle_turbo;
+       int throttle_sub_turbo;
+       int reason[OCC_MAX_REASON];
 } *chips;
 
 static int nr_chips;
+static DEFINE_PER_CPU(struct chip *, chip_info);
 
 /*
  * Note: The set of pstates consists of contiguous integers, the
@@ -196,6 +209,42 @@ static struct freq_attr *powernv_cpu_freq_attr[] = {
        NULL,
 };
 
+#define throttle_attr(name, member)                                    \
+static ssize_t name##_show(struct cpufreq_policy *policy, char *buf)   \
+{                                                                      \
+       struct chip *chip = per_cpu(chip_info, policy->cpu);            \
+                                                                       \
+       return sprintf(buf, "%u\n", chip->member);                      \
+}                                                                      \
+                                                                       \
+static struct freq_attr throttle_attr_##name = __ATTR_RO(name)         \
+
+throttle_attr(unthrottle, reason[NO_THROTTLE]);
+throttle_attr(powercap, reason[POWERCAP]);
+throttle_attr(overtemp, reason[CPU_OVERTEMP]);
+throttle_attr(supply_fault, reason[POWER_SUPPLY_FAILURE]);
+throttle_attr(overcurrent, reason[OVERCURRENT]);
+throttle_attr(occ_reset, reason[OCC_RESET_THROTTLE]);
+throttle_attr(turbo_stat, throttle_turbo);
+throttle_attr(sub_turbo_stat, throttle_sub_turbo);
+
+static struct attribute *throttle_attrs[] = {
+       &throttle_attr_unthrottle.attr,
+       &throttle_attr_powercap.attr,
+       &throttle_attr_overtemp.attr,
+       &throttle_attr_supply_fault.attr,
+       &throttle_attr_overcurrent.attr,
+       &throttle_attr_occ_reset.attr,
+       &throttle_attr_turbo_stat.attr,
+       &throttle_attr_sub_turbo_stat.attr,
+       NULL,
+};
+
+static const struct attribute_group throttle_attr_grp = {
+       .name   = "throttle_stats",
+       .attrs  = throttle_attrs,
+};
+
 /* Helper routines */
 
 /* Access helpers to power mgt SPR */
@@ -324,34 +373,35 @@ static inline unsigned int get_nominal_index(void)
 
 static void powernv_cpufreq_throttle_check(void *data)
 {
+       struct chip *chip;
        unsigned int cpu = smp_processor_id();
-       unsigned int chip_id = core_to_chip_map[cpu_core_index_of_thread(cpu)];
        unsigned long pmsr;
-       int pmsr_pmax, i;
+       int pmsr_pmax;
 
        pmsr = get_pmspr(SPRN_PMSR);
-
-       for (i = 0; i < nr_chips; i++)
-               if (chips[i].id == chip_id)
-                       break;
+       chip = this_cpu_read(chip_info);
 
        /* Check for Pmax Capping */
        pmsr_pmax = (s8)PMSR_MAX(pmsr);
        if (pmsr_pmax != powernv_pstate_info.max) {
-               if (chips[i].throttled)
+               if (chip->throttled)
                        goto next;
-               chips[i].throttled = true;
-               if (pmsr_pmax < powernv_pstate_info.nominal)
+               chip->throttled = true;
+               if (pmsr_pmax < powernv_pstate_info.nominal) {
                        pr_warn_once("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
-                                    cpu, chips[i].id, pmsr_pmax,
+                                    cpu, chip->id, pmsr_pmax,
                                     powernv_pstate_info.nominal);
-               trace_powernv_throttle(chips[i].id,
-                                     throttle_reason[chips[i].throttle_reason],
+                       chip->throttle_sub_turbo++;
+               } else {
+                       chip->throttle_turbo++;
+               }
+               trace_powernv_throttle(chip->id,
+                                     throttle_reason[chip->throttle_reason],
                                      pmsr_pmax);
-       } else if (chips[i].throttled) {
-               chips[i].throttled = false;
-               trace_powernv_throttle(chips[i].id,
-                                     throttle_reason[chips[i].throttle_reason],
+       } else if (chip->throttled) {
+               chip->throttled = false;
+               trace_powernv_throttle(chip->id,
+                                     throttle_reason[chip->throttle_reason],
                                      pmsr_pmax);
        }
 
@@ -405,12 +455,26 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
 static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
        int base, i;
+       struct kernfs_node *kn;
 
        base = cpu_first_thread_sibling(policy->cpu);
 
        for (i = 0; i < threads_per_core; i++)
                cpumask_set_cpu(base + i, policy->cpus);
 
+       kn = kernfs_find_and_get(policy->kobj.sd, throttle_attr_grp.name);
+       if (!kn) {
+               int ret;
+
+               ret = sysfs_create_group(&policy->kobj, &throttle_attr_grp);
+               if (ret) {
+                       pr_info("Failed to create throttle stats directory for cpu %d\n",
+                               policy->cpu);
+                       return ret;
+               }
+       } else {
+               kernfs_put(kn);
+       }
        return cpufreq_table_validate_and_show(policy, powernv_freqs);
 }
 
@@ -517,8 +581,10 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb,
                                break;
 
                if (omsg.throttle_status >= 0 &&
-                   omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS)
+                   omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS) {
                        chips[i].throttle_reason = omsg.throttle_status;
+                       chips[i].reason[omsg.throttle_status]++;
+               }
 
                if (!omsg.throttle_status)
                        chips[i].restore = true;
@@ -558,47 +624,34 @@ static int init_chip_info(void)
        unsigned int chip[256];
        unsigned int cpu, i;
        unsigned int prev_chip_id = UINT_MAX;
-       cpumask_t cpu_mask;
-       int ret = -ENOMEM;
-
-       core_to_chip_map = kcalloc(cpu_nr_cores(), sizeof(unsigned int),
-                                  GFP_KERNEL);
-       if (!core_to_chip_map)
-               goto out;
 
-       cpumask_copy(&cpu_mask, cpu_possible_mask);
-       for_each_cpu(cpu, &cpu_mask) {
+       for_each_possible_cpu(cpu) {
                unsigned int id = cpu_to_chip_id(cpu);
 
                if (prev_chip_id != id) {
                        prev_chip_id = id;
                        chip[nr_chips++] = id;
                }
-               core_to_chip_map[cpu_core_index_of_thread(cpu)] = id;
-               cpumask_andnot(&cpu_mask, &cpu_mask, cpu_sibling_mask(cpu));
        }
 
        chips = kcalloc(nr_chips, sizeof(struct chip), GFP_KERNEL);
        if (!chips)
-               goto free_chip_map;
+               return -ENOMEM;
 
        for (i = 0; i < nr_chips; i++) {
                chips[i].id = chip[i];
                cpumask_copy(&chips[i].mask, cpumask_of_node(chip[i]));
                INIT_WORK(&chips[i].throttle, powernv_cpufreq_work_fn);
+               for_each_cpu(cpu, &chips[i].mask)
+                       per_cpu(chip_info, cpu) =  &chips[i];
        }
 
        return 0;
-free_chip_map:
-       kfree(core_to_chip_map);
-out:
-       return ret;
 }
 
 static inline void clean_chip_info(void)
 {
        kfree(chips);
-       kfree(core_to_chip_map);
 }
 
 static inline void unregister_all_notifiers(void)