Merge branch 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm
[cascardo/linux.git] / drivers / cpufreq / powernv-cpufreq.c
index 2dfd4fd..ebef0d8 100644 (file)
 #include <asm/smp.h> /* Required for cpu_sibling_mask() in UP configs */
 
 #define POWERNV_MAX_PSTATES    256
+#define PMSR_PSAFE_ENABLE      (1UL << 30)
+#define PMSR_SPR_EM_DISABLE    (1UL << 31)
+#define PMSR_MAX(x)            ((x >> 32) & 0xFF)
+#define PMSR_LP(x)             ((x >> 48) & 0xFF)
 
 static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
-static bool rebooting;
+static bool rebooting, throttled;
 
 /*
  * Note: The set of pstates consists of contiguous integers, the
@@ -294,6 +298,44 @@ static inline unsigned int get_nominal_index(void)
        return powernv_pstate_info.max - powernv_pstate_info.nominal;
 }
 
+static void powernv_cpufreq_throttle_check(unsigned int cpu)
+{
+       unsigned long pmsr;
+       int pmsr_pmax, pmsr_lp;
+
+       pmsr = get_pmspr(SPRN_PMSR);
+
+       /* Check for Pmax Capping */
+       pmsr_pmax = (s8)PMSR_MAX(pmsr);
+       if (pmsr_pmax != powernv_pstate_info.max) {
+               throttled = true;
+               pr_info("CPU %d Pmax is reduced to %d\n", cpu, pmsr_pmax);
+               pr_info("Max allowed Pstate is capped\n");
+       }
+
+       /*
+        * Check for Psafe by reading LocalPstate
+        * or check if Psafe_mode_active is set in PMSR.
+        */
+       pmsr_lp = (s8)PMSR_LP(pmsr);
+       if ((pmsr_lp < powernv_pstate_info.min) ||
+                               (pmsr & PMSR_PSAFE_ENABLE)) {
+               throttled = true;
+               pr_info("Pstate set to safe frequency\n");
+       }
+
+       /* Check if SPR_EM_DISABLE is set in PMSR */
+       if (pmsr & PMSR_SPR_EM_DISABLE) {
+               throttled = true;
+               pr_info("Frequency Control disabled from OS\n");
+       }
+
+       if (throttled) {
+               pr_info("PMSR = %16lx\n", pmsr);
+               pr_crit("CPU Frequency could be throttled\n");
+       }
+}
+
 /*
  * powernv_cpufreq_target_index: Sets the frequency corresponding to
  * the cpufreq table entry indexed by new_index on the cpus in the
@@ -307,6 +349,9 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
        if (unlikely(rebooting) && new_index != get_nominal_index())
                return 0;
 
+       if (!throttled)
+               powernv_cpufreq_throttle_check(smp_processor_id());
+
        freq_data.pstate_id = powernv_freqs[new_index].driver_data;
 
        /*