aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/mcheck
diff options
context:
space:
mode:
authorFenghua Yu <fenghua.yu@intel.com>2010-07-29 20:13:44 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2010-08-03 18:58:56 -0400
commit55d435a227bd28c77afab326de44dfacc0b15059 (patch)
tree5aa00f63286b62044220c4b1a4a0f22e241c1e1e /arch/x86/kernel/cpu/mcheck
parentcb84b19474384c572ba3aa2345815e555112ebf5 (diff)
x86, hwmon: Package Level Thermal/Power: thermal throttling handler
Add package level thermal throttle interrupt support. The interrupt handler increases package level thermal throttle count. It also logs the event in MCE log. The package level thermal throttle interrupt happens across threads in a package. Each thread handles the interrupt individually. User level application is supposed to retrieve correct event count and log based on package/thread topology. This is the same situation for core level interrupt handler. In the future, interrupt may be reported only per package or per core. core_throttle_count and package_throttle_count are used for user interface. Previously only throttle_count is used for core throttle count. If you think new core_throttle_count name breaks user interface, I can change this part. Signed-off-by: Fenghua Yu <fenghua.yu@intel.com> LKML-Reference: <1280448826-12004-4-git-send-email-fenghua.yu@intel.com> Reviewed-by: Len Brown <len.brown@intel.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/kernel/cpu/mcheck')
-rw-r--r--arch/x86/kernel/cpu/mcheck/therm_throt.c89
1 files changed, 71 insertions, 18 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index e1a0a3bf9716..d307f9f64c23 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -37,7 +37,7 @@
37/* 37/*
38 * Current thermal throttling state: 38 * Current thermal throttling state:
39 */ 39 */
40struct thermal_state { 40struct _thermal_state {
41 bool is_throttled; 41 bool is_throttled;
42 42
43 u64 next_check; 43 u64 next_check;
@@ -45,6 +45,11 @@ struct thermal_state {
45 unsigned long last_throttle_count; 45 unsigned long last_throttle_count;
46}; 46};
47 47
48struct thermal_state {
49 struct _thermal_state core;
50 struct _thermal_state package;
51};
52
48static DEFINE_PER_CPU(struct thermal_state, thermal_state); 53static DEFINE_PER_CPU(struct thermal_state, thermal_state);
49 54
50static atomic_t therm_throt_en = ATOMIC_INIT(0); 55static atomic_t therm_throt_en = ATOMIC_INIT(0);
@@ -53,11 +58,13 @@ static u32 lvtthmr_init __read_mostly;
53 58
54#ifdef CONFIG_SYSFS 59#ifdef CONFIG_SYSFS
55#define define_therm_throt_sysdev_one_ro(_name) \ 60#define define_therm_throt_sysdev_one_ro(_name) \
56 static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL) 61 static SYSDEV_ATTR(_name, 0444, \
62 therm_throt_sysdev_show_##_name, \
63 NULL) \
57 64
58#define define_therm_throt_sysdev_show_func(name) \ 65#define define_therm_throt_sysdev_show_func(level, name) \
59 \ 66 \
60static ssize_t therm_throt_sysdev_show_##name( \ 67static ssize_t therm_throt_sysdev_show_##level##_##name( \
61 struct sys_device *dev, \ 68 struct sys_device *dev, \
62 struct sysdev_attribute *attr, \ 69 struct sysdev_attribute *attr, \
63 char *buf) \ 70 char *buf) \
@@ -66,21 +73,24 @@ static ssize_t therm_throt_sysdev_show_##name( \
66 ssize_t ret; \ 73 ssize_t ret; \
67 \ 74 \
68 preempt_disable(); /* CPU hotplug */ \ 75 preempt_disable(); /* CPU hotplug */ \
69 if (cpu_online(cpu)) \ 76 if (cpu_online(cpu)) { \
70 ret = sprintf(buf, "%lu\n", \ 77 ret = sprintf(buf, "%lu\n", \
71 per_cpu(thermal_state, cpu).name); \ 78 per_cpu(thermal_state, cpu).level.name); \
72 else \ 79 } else \
73 ret = 0; \ 80 ret = 0; \
74 preempt_enable(); \ 81 preempt_enable(); \
75 \ 82 \
76 return ret; \ 83 return ret; \
77} 84}
78 85
79define_therm_throt_sysdev_show_func(throttle_count); 86define_therm_throt_sysdev_show_func(core, throttle_count);
80define_therm_throt_sysdev_one_ro(throttle_count); 87define_therm_throt_sysdev_one_ro(core_throttle_count);
88
89define_therm_throt_sysdev_show_func(package, throttle_count);
90define_therm_throt_sysdev_one_ro(package_throttle_count);
81 91
82static struct attribute *thermal_throttle_attrs[] = { 92static struct attribute *thermal_throttle_attrs[] = {
83 &attr_throttle_count.attr, 93 &attr_core_throttle_count.attr,
84 NULL 94 NULL
85}; 95};
86 96
@@ -106,16 +116,21 @@ static struct attribute_group thermal_throttle_attr_group = {
106 * 1 : Event should be logged further, and a message has been 116 * 1 : Event should be logged further, and a message has been
107 * printed to the syslog. 117 * printed to the syslog.
108 */ 118 */
109static int therm_throt_process(bool is_throttled) 119#define CORE_LEVEL 0
120#define PACKAGE_LEVEL 1
121static int therm_throt_process(bool is_throttled, int level)
110{ 122{
111 struct thermal_state *state; 123 struct _thermal_state *state;
112 unsigned int this_cpu; 124 unsigned int this_cpu;
113 bool was_throttled; 125 bool was_throttled;
114 u64 now; 126 u64 now;
115 127
116 this_cpu = smp_processor_id(); 128 this_cpu = smp_processor_id();
117 now = get_jiffies_64(); 129 now = get_jiffies_64();
118 state = &per_cpu(thermal_state, this_cpu); 130 if (level == CORE_LEVEL)
131 state = &per_cpu(thermal_state, this_cpu).core;
132 else
133 state = &per_cpu(thermal_state, this_cpu).package;
119 134
120 was_throttled = state->is_throttled; 135 was_throttled = state->is_throttled;
121 state->is_throttled = is_throttled; 136 state->is_throttled = is_throttled;
@@ -132,13 +147,18 @@ static int therm_throt_process(bool is_throttled)
132 147
133 /* if we just entered the thermal event */ 148 /* if we just entered the thermal event */
134 if (is_throttled) { 149 if (is_throttled) {
135 printk(KERN_CRIT "CPU%d: Temperature above threshold, cpu clock throttled (total events = %lu)\n", this_cpu, state->throttle_count); 150 printk(KERN_CRIT "CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n",
151 this_cpu,
152 level == CORE_LEVEL ? "Core" : "Package",
153 state->throttle_count);
136 154
137 add_taint(TAINT_MACHINE_CHECK); 155 add_taint(TAINT_MACHINE_CHECK);
138 return 1; 156 return 1;
139 } 157 }
140 if (was_throttled) { 158 if (was_throttled) {
141 printk(KERN_INFO "CPU%d: Temperature/speed normal\n", this_cpu); 159 printk(KERN_INFO "CPU%d: %s temperature/speed normal\n",
160 this_cpu,
161 level == CORE_LEVEL ? "Core" : "Package");
142 return 1; 162 return 1;
143 } 163 }
144 164
@@ -149,8 +169,19 @@ static int therm_throt_process(bool is_throttled)
149/* Add/Remove thermal_throttle interface for CPU device: */ 169/* Add/Remove thermal_throttle interface for CPU device: */
150static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev) 170static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev)
151{ 171{
152 return sysfs_create_group(&sys_dev->kobj, 172 int err;
153 &thermal_throttle_attr_group); 173 struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
174
175 err = sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group);
176 if (err)
177 return err;
178
179 if (cpu_has(c, X86_FEATURE_PTS))
180 err = sysfs_add_file_to_group(&sys_dev->kobj,
181 &attr_package_throttle_count.attr,
182 thermal_throttle_attr_group.name);
183
184 return err;
154} 185}
155 186
156static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev) 187static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev)
@@ -230,10 +261,25 @@ device_initcall(thermal_throttle_init_device);
230static void intel_thermal_interrupt(void) 261static void intel_thermal_interrupt(void)
231{ 262{
232 __u64 msr_val; 263 __u64 msr_val;
264 struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
233 265
234 rdmsrl(MSR_IA32_THERM_STATUS, msr_val); 266 rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
235 if (therm_throt_process((msr_val & THERM_STATUS_PROCHOT) != 0)) 267 if (therm_throt_process(msr_val & THERM_STATUS_PROCHOT,
268 CORE_LEVEL) != 0)
236 mce_log_therm_throt_event(msr_val); 269 mce_log_therm_throt_event(msr_val);
270
271 if (cpu_has(c, X86_FEATURE_PTS)) {
272 rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
273 if (therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
274 PACKAGE_LEVEL) != 0)
275 /*
276 * Set up the most significant bit to notify mce log
277 * that this thermal event is a package level event.
278 * This is a temp solution. May be changed in the future
279 * with mce log infrasture.
280 */
281 mce_log_therm_throt_event(((__u64)1 << 63) | msr_val);
282 }
237} 283}
238 284
239static void unexpected_thermal_interrupt(void) 285static void unexpected_thermal_interrupt(void)
@@ -338,6 +384,13 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
338 wrmsr(MSR_IA32_THERM_INTERRUPT, 384 wrmsr(MSR_IA32_THERM_INTERRUPT,
339 l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h); 385 l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h);
340 386
387 if (cpu_has(c, X86_FEATURE_PTS)) {
388 rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
389 wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
390 l | (PACKAGE_THERM_INT_LOW_ENABLE
391 | PACKAGE_THERM_INT_HIGH_ENABLE), h);
392 }
393
341 smp_thermal_vector = intel_thermal_interrupt; 394 smp_thermal_vector = intel_thermal_interrupt;
342 395
343 rdmsr(MSR_IA32_MISC_ENABLE, l, h); 396 rdmsr(MSR_IA32_MISC_ENABLE, l, h);