]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/cpufreq/powernv-cpufreq.c
Merge remote-tracking branch 'rcu/rcu/next'
[karo-tx-linux.git] / drivers / cpufreq / powernv-cpufreq.c
index 547890fd9572179eba4c6ce81caf5bbc8b06b947..1bbc10a54c59c8a7cf6e82b06607f44c7988f3fb 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/of.h>
 #include <linux/reboot.h>
 #include <linux/slab.h>
+#include <linux/cpu.h>
+#include <trace/events/power.h>
 
 #include <asm/cputhreads.h>
 #include <asm/firmware.h>
 
 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",
+       "Power Cap",
+       "Processor Over Temperature",
+       "Power Supply Failure",
+       "Over Current",
+       "OCC Reset"
+};
 
 static struct chip {
        unsigned int id;
        bool throttled;
+       bool restore;
+       u8 throttle_reason;
        cpumask_t mask;
        struct work_struct throttle;
-       bool restore;
 } *chips;
 
 static int nr_chips;
@@ -312,13 +325,14 @@ static inline unsigned int get_nominal_index(void)
 static void powernv_cpufreq_throttle_check(void *data)
 {
        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;
 
        pmsr = get_pmspr(SPRN_PMSR);
 
        for (i = 0; i < nr_chips; i++)
-               if (chips[i].id == cpu_to_chip_id(cpu))
+               if (chips[i].id == chip_id)
                        break;
 
        /* Check for Pmax Capping */
@@ -328,17 +342,17 @@ static void powernv_cpufreq_throttle_check(void *data)
                        goto next;
                chips[i].throttled = true;
                if (pmsr_pmax < powernv_pstate_info.nominal)
-                       pr_crit("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
-                               cpu, chips[i].id, pmsr_pmax,
-                               powernv_pstate_info.nominal);
-               else
-                       pr_info("CPU %d on Chip %u has Pmax reduced below turbo frequency (%d < %d)\n",
-                               cpu, chips[i].id, pmsr_pmax,
-                               powernv_pstate_info.max);
+                       pr_warn_once("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
+                                    cpu, chips[i].id, pmsr_pmax,
+                                    powernv_pstate_info.nominal);
+               trace_powernv_throttle(chips[i].id,
+                                     throttle_reason[chips[i].throttle_reason],
+                                     pmsr_pmax);
        } else if (chips[i].throttled) {
                chips[i].throttled = false;
-               pr_info("CPU %d on Chip %u has Pmax restored to %d\n", cpu,
-                       chips[i].id, pmsr_pmax);
+               trace_powernv_throttle(chips[i].id,
+                                     throttle_reason[chips[i].throttle_reason],
+                                     pmsr_pmax);
        }
 
        /* Check if Psafe_mode_active is set in PMSR. */
@@ -356,7 +370,7 @@ next:
 
        if (throttled) {
                pr_info("PMSR = %16lx\n", pmsr);
-               pr_crit("CPU Frequency could be throttled\n");
+               pr_warn("CPU Frequency could be throttled\n");
        }
 }
 
@@ -423,18 +437,19 @@ void powernv_cpufreq_work_fn(struct work_struct *work)
 {
        struct chip *chip = container_of(work, struct chip, throttle);
        unsigned int cpu;
-       cpumask_var_t mask;
+       cpumask_t mask;
 
-       smp_call_function_any(&chip->mask,
+       get_online_cpus();
+       cpumask_and(&mask, &chip->mask, cpu_online_mask);
+       smp_call_function_any(&mask,
                              powernv_cpufreq_throttle_check, NULL, 0);
 
        if (!chip->restore)
-               return;
+               goto out;
 
        chip->restore = false;
-       cpumask_copy(mask, &chip->mask);
-       for_each_cpu_and(cpu, mask, cpu_online_mask) {
-               int index, tcpu;
+       for_each_cpu(cpu, &mask) {
+               int index;
                struct cpufreq_policy policy;
 
                cpufreq_get_policy(&policy, cpu);
@@ -442,20 +457,12 @@ void powernv_cpufreq_work_fn(struct work_struct *work)
                                               policy.cur,
                                               CPUFREQ_RELATION_C, &index);
                powernv_cpufreq_target_index(&policy, index);
-               for_each_cpu(tcpu, policy.cpus)
-                       cpumask_clear_cpu(tcpu, mask);
+               cpumask_andnot(&mask, &mask, policy.cpus);
        }
+out:
+       put_online_cpus();
 }
 
-static char throttle_reason[][30] = {
-                                       "No throttling",
-                                       "Power Cap",
-                                       "Processor Over Temperature",
-                                       "Power Supply Failure",
-                                       "Over Current",
-                                       "OCC Reset"
-                                    };
-
 static int powernv_cpufreq_occ_msg(struct notifier_block *nb,
                                   unsigned long msg_type, void *_msg)
 {
@@ -481,7 +488,7 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb,
                 */
                if (!throttled) {
                        throttled = true;
-                       pr_crit("CPU frequency is throttled for duration\n");
+                       pr_warn("CPU frequency is throttled for duration\n");
                }
 
                break;
@@ -505,23 +512,18 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb,
                        return 0;
                }
 
-               if (omsg.throttle_status &&
+               for (i = 0; i < nr_chips; i++)
+                       if (chips[i].id == omsg.chip)
+                               break;
+
+               if (omsg.throttle_status >= 0 &&
                    omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS)
-                       pr_info("OCC: Chip %u Pmax reduced due to %s\n",
-                               (unsigned int)omsg.chip,
-                               throttle_reason[omsg.throttle_status]);
-               else if (!omsg.throttle_status)
-                       pr_info("OCC: Chip %u %s\n", (unsigned int)omsg.chip,
-                               throttle_reason[omsg.throttle_status]);
-               else
-                       return 0;
+                       chips[i].throttle_reason = omsg.throttle_status;
 
-               for (i = 0; i < nr_chips; i++)
-                       if (chips[i].id == omsg.chip) {
-                               if (!omsg.throttle_status)
-                                       chips[i].restore = true;
-                               schedule_work(&chips[i].throttle);
-                       }
+               if (!omsg.throttle_status)
+                       chips[i].restore = true;
+
+               schedule_work(&chips[i].throttle);
        }
        return 0;
 }
@@ -556,29 +558,41 @@ 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;
 
-       for_each_possible_cpu(cpu) {
+       cpumask_copy(&cpu_mask, cpu_possible_mask);
+       for_each_cpu(cpu, &cpu_mask) {
                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 = kmalloc_array(nr_chips, sizeof(struct chip), GFP_KERNEL);
+       chips = kcalloc(nr_chips, sizeof(struct chip), GFP_KERNEL);
        if (!chips)
-               return -ENOMEM;
+               goto free_chip_map;
 
        for (i = 0; i < nr_chips; i++) {
                chips[i].id = chip[i];
-               chips[i].throttled = false;
                cpumask_copy(&chips[i].mask, cpumask_of_node(chip[i]));
                INIT_WORK(&chips[i].throttle, powernv_cpufreq_work_fn);
-               chips[i].restore = false;
        }
 
        return 0;
+free_chip_map:
+       kfree(core_to_chip_map);
+out:
+       return ret;
 }
 
 static int __init powernv_cpufreq_init(void)
@@ -612,6 +626,8 @@ static void __exit powernv_cpufreq_exit(void)
        unregister_reboot_notifier(&powernv_cpufreq_reboot_nb);
        opal_message_notifier_unregister(OPAL_MSG_OCC,
                                         &powernv_cpufreq_opal_nb);
+       kfree(chips);
+       kfree(core_to_chip_map);
        cpufreq_unregister_driver(&powernv_cpufreq_driver);
 }
 module_exit(powernv_cpufreq_exit);