Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
[cascardo/linux.git] / arch / x86 / kernel / cpu / mcheck / therm_throt.c
index 2f3a799..41e8e00 100644 (file)
@@ -55,12 +55,24 @@ struct thermal_state {
        struct _thermal_state package_power_limit;
        struct _thermal_state core_thresh0;
        struct _thermal_state core_thresh1;
+       struct _thermal_state pkg_thresh0;
+       struct _thermal_state pkg_thresh1;
 };
 
 /* Callback to handle core threshold interrupts */
 int (*platform_thermal_notify)(__u64 msr_val);
 EXPORT_SYMBOL(platform_thermal_notify);
 
+/* Callback to handle core package threshold_interrupts */
+int (*platform_thermal_package_notify)(__u64 msr_val);
+EXPORT_SYMBOL_GPL(platform_thermal_package_notify);
+
+/* Callback support of rate control, return true, if
+ * callback has rate control */
+bool (*platform_thermal_package_rate_control)(void);
+EXPORT_SYMBOL_GPL(platform_thermal_package_rate_control);
+
+
 static DEFINE_PER_CPU(struct thermal_state, thermal_state);
 
 static atomic_t therm_throt_en = ATOMIC_INIT(0);
@@ -182,11 +194,6 @@ static int therm_throt_process(bool new_event, int event, int level)
                                this_cpu,
                                level == CORE_LEVEL ? "Core" : "Package",
                                state->count);
-               else
-                       printk(KERN_CRIT "CPU%d: %s power limit notification (total events = %lu)\n",
-                               this_cpu,
-                               level == CORE_LEVEL ? "Core" : "Package",
-                               state->count);
                return 1;
        }
        if (old_event) {
@@ -194,31 +201,42 @@ static int therm_throt_process(bool new_event, int event, int level)
                        printk(KERN_INFO "CPU%d: %s temperature/speed normal\n",
                                this_cpu,
                                level == CORE_LEVEL ? "Core" : "Package");
-               else
-                       printk(KERN_INFO "CPU%d: %s power limit normal\n",
-                               this_cpu,
-                               level == CORE_LEVEL ? "Core" : "Package");
                return 1;
        }
 
        return 0;
 }
 
-static int thresh_event_valid(int event)
+static int thresh_event_valid(int level, int event)
 {
        struct _thermal_state *state;
        unsigned int this_cpu = smp_processor_id();
        struct thermal_state *pstate = &per_cpu(thermal_state, this_cpu);
        u64 now = get_jiffies_64();
 
-       state = (event == 0) ? &pstate->core_thresh0 : &pstate->core_thresh1;
+       if (level == PACKAGE_LEVEL)
+               state = (event == 0) ? &pstate->pkg_thresh0 :
+                                               &pstate->pkg_thresh1;
+       else
+               state = (event == 0) ? &pstate->core_thresh0 :
+                                               &pstate->core_thresh1;
 
        if (time_before64(now, state->next_check))
                return 0;
 
        state->next_check = now + CHECK_INTERVAL;
+
+       return 1;
+}
+
+static bool int_pln_enable;
+static int __init int_pln_enable_setup(char *s)
+{
+       int_pln_enable = true;
+
        return 1;
 }
+__setup("int_pln_enable", int_pln_enable_setup);
 
 #ifdef CONFIG_SYSFS
 /* Add/Remove thermal_throttle interface for CPU device: */
@@ -232,7 +250,7 @@ static __cpuinit int thermal_throttle_add_dev(struct device *dev,
        if (err)
                return err;
 
-       if (cpu_has(c, X86_FEATURE_PLN))
+       if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
                err = sysfs_add_file_to_group(&dev->kobj,
                                              &dev_attr_core_power_limit_count.attr,
                                              thermal_attr_group.name);
@@ -240,7 +258,7 @@ static __cpuinit int thermal_throttle_add_dev(struct device *dev,
                err = sysfs_add_file_to_group(&dev->kobj,
                                              &dev_attr_package_throttle_count.attr,
                                              thermal_attr_group.name);
-               if (cpu_has(c, X86_FEATURE_PLN))
+               if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
                        err = sysfs_add_file_to_group(&dev->kobj,
                                        &dev_attr_package_power_limit_count.attr,
                                        thermal_attr_group.name);
@@ -322,6 +340,39 @@ device_initcall(thermal_throttle_init_device);
 
 #endif /* CONFIG_SYSFS */
 
+static void notify_package_thresholds(__u64 msr_val)
+{
+       bool notify_thres_0 = false;
+       bool notify_thres_1 = false;
+
+       if (!platform_thermal_package_notify)
+               return;
+
+       /* lower threshold check */
+       if (msr_val & THERM_LOG_THRESHOLD0)
+               notify_thres_0 = true;
+       /* higher threshold check */
+       if (msr_val & THERM_LOG_THRESHOLD1)
+               notify_thres_1 = true;
+
+       if (!notify_thres_0 && !notify_thres_1)
+               return;
+
+       if (platform_thermal_package_rate_control &&
+               platform_thermal_package_rate_control()) {
+               /* Rate control is implemented in callback */
+               platform_thermal_package_notify(msr_val);
+               return;
+       }
+
+       /* lower threshold reached */
+       if (notify_thres_0 && thresh_event_valid(PACKAGE_LEVEL, 0))
+               platform_thermal_package_notify(msr_val);
+       /* higher threshold reached */
+       if (notify_thres_1 && thresh_event_valid(PACKAGE_LEVEL, 1))
+               platform_thermal_package_notify(msr_val);
+}
+
 static void notify_thresholds(__u64 msr_val)
 {
        /* check whether the interrupt handler is defined;
@@ -331,10 +382,12 @@ static void notify_thresholds(__u64 msr_val)
                return;
 
        /* lower threshold reached */
-       if ((msr_val & THERM_LOG_THRESHOLD0) && thresh_event_valid(0))
+       if ((msr_val & THERM_LOG_THRESHOLD0) &&
+                       thresh_event_valid(CORE_LEVEL, 0))
                platform_thermal_notify(msr_val);
        /* higher threshold reached */
-       if ((msr_val & THERM_LOG_THRESHOLD1) && thresh_event_valid(1))
+       if ((msr_val & THERM_LOG_THRESHOLD1) &&
+                       thresh_event_valid(CORE_LEVEL, 1))
                platform_thermal_notify(msr_val);
 }
 
@@ -353,17 +406,19 @@ static void intel_thermal_interrupt(void)
                                CORE_LEVEL) != 0)
                mce_log_therm_throt_event(msr_val);
 
-       if (this_cpu_has(X86_FEATURE_PLN))
+       if (this_cpu_has(X86_FEATURE_PLN) && int_pln_enable)
                therm_throt_process(msr_val & THERM_STATUS_POWER_LIMIT,
                                        POWER_LIMIT_EVENT,
                                        CORE_LEVEL);
 
        if (this_cpu_has(X86_FEATURE_PTS)) {
                rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+               /* check violations of package thermal thresholds */
+               notify_package_thresholds(msr_val);
                therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
                                        THERMAL_THROTTLING_EVENT,
                                        PACKAGE_LEVEL);
-               if (this_cpu_has(X86_FEATURE_PLN))
+               if (this_cpu_has(X86_FEATURE_PLN) && int_pln_enable)
                        therm_throt_process(msr_val &
                                        PACKAGE_THERM_STATUS_POWER_LIMIT,
                                        POWER_LIMIT_EVENT,
@@ -482,9 +537,13 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
        apic_write(APIC_LVTTHMR, h);
 
        rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
-       if (cpu_has(c, X86_FEATURE_PLN))
+       if (cpu_has(c, X86_FEATURE_PLN) && !int_pln_enable)
+               wrmsr(MSR_IA32_THERM_INTERRUPT,
+                       (l | (THERM_INT_LOW_ENABLE
+                       | THERM_INT_HIGH_ENABLE)) & ~THERM_INT_PLN_ENABLE, h);
+       else if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
                wrmsr(MSR_IA32_THERM_INTERRUPT,
-                     l | (THERM_INT_LOW_ENABLE
+                       l | (THERM_INT_LOW_ENABLE
                        | THERM_INT_HIGH_ENABLE | THERM_INT_PLN_ENABLE), h);
        else
                wrmsr(MSR_IA32_THERM_INTERRUPT,
@@ -492,9 +551,14 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
 
        if (cpu_has(c, X86_FEATURE_PTS)) {
                rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
-               if (cpu_has(c, X86_FEATURE_PLN))
+               if (cpu_has(c, X86_FEATURE_PLN) && !int_pln_enable)
                        wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
-                             l | (PACKAGE_THERM_INT_LOW_ENABLE
+                               (l | (PACKAGE_THERM_INT_LOW_ENABLE
+                               | PACKAGE_THERM_INT_HIGH_ENABLE))
+                               & ~PACKAGE_THERM_INT_PLN_ENABLE, h);
+               else if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
+                       wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
+                               l | (PACKAGE_THERM_INT_LOW_ENABLE
                                | PACKAGE_THERM_INT_HIGH_ENABLE
                                | PACKAGE_THERM_INT_PLN_ENABLE), h);
                else