diff options
Diffstat (limited to 'arch/x86/kernel/cpu/mcheck')
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/therm_throt.c | 63 |
1 files changed, 59 insertions, 4 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 98f2083832eb..41e8e00a6637 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c | |||
@@ -55,12 +55,24 @@ struct thermal_state { | |||
55 | struct _thermal_state package_power_limit; | 55 | struct _thermal_state package_power_limit; |
56 | struct _thermal_state core_thresh0; | 56 | struct _thermal_state core_thresh0; |
57 | struct _thermal_state core_thresh1; | 57 | struct _thermal_state core_thresh1; |
58 | struct _thermal_state pkg_thresh0; | ||
59 | struct _thermal_state pkg_thresh1; | ||
58 | }; | 60 | }; |
59 | 61 | ||
60 | /* Callback to handle core threshold interrupts */ | 62 | /* Callback to handle core threshold interrupts */ |
61 | int (*platform_thermal_notify)(__u64 msr_val); | 63 | int (*platform_thermal_notify)(__u64 msr_val); |
62 | EXPORT_SYMBOL(platform_thermal_notify); | 64 | EXPORT_SYMBOL(platform_thermal_notify); |
63 | 65 | ||
66 | /* Callback to handle core package threshold_interrupts */ | ||
67 | int (*platform_thermal_package_notify)(__u64 msr_val); | ||
68 | EXPORT_SYMBOL_GPL(platform_thermal_package_notify); | ||
69 | |||
70 | /* Callback support of rate control, return true, if | ||
71 | * callback has rate control */ | ||
72 | bool (*platform_thermal_package_rate_control)(void); | ||
73 | EXPORT_SYMBOL_GPL(platform_thermal_package_rate_control); | ||
74 | |||
75 | |||
64 | static DEFINE_PER_CPU(struct thermal_state, thermal_state); | 76 | static DEFINE_PER_CPU(struct thermal_state, thermal_state); |
65 | 77 | ||
66 | static atomic_t therm_throt_en = ATOMIC_INIT(0); | 78 | static atomic_t therm_throt_en = ATOMIC_INIT(0); |
@@ -195,19 +207,25 @@ static int therm_throt_process(bool new_event, int event, int level) | |||
195 | return 0; | 207 | return 0; |
196 | } | 208 | } |
197 | 209 | ||
198 | static int thresh_event_valid(int event) | 210 | static int thresh_event_valid(int level, int event) |
199 | { | 211 | { |
200 | struct _thermal_state *state; | 212 | struct _thermal_state *state; |
201 | unsigned int this_cpu = smp_processor_id(); | 213 | unsigned int this_cpu = smp_processor_id(); |
202 | struct thermal_state *pstate = &per_cpu(thermal_state, this_cpu); | 214 | struct thermal_state *pstate = &per_cpu(thermal_state, this_cpu); |
203 | u64 now = get_jiffies_64(); | 215 | u64 now = get_jiffies_64(); |
204 | 216 | ||
205 | state = (event == 0) ? &pstate->core_thresh0 : &pstate->core_thresh1; | 217 | if (level == PACKAGE_LEVEL) |
218 | state = (event == 0) ? &pstate->pkg_thresh0 : | ||
219 | &pstate->pkg_thresh1; | ||
220 | else | ||
221 | state = (event == 0) ? &pstate->core_thresh0 : | ||
222 | &pstate->core_thresh1; | ||
206 | 223 | ||
207 | if (time_before64(now, state->next_check)) | 224 | if (time_before64(now, state->next_check)) |
208 | return 0; | 225 | return 0; |
209 | 226 | ||
210 | state->next_check = now + CHECK_INTERVAL; | 227 | state->next_check = now + CHECK_INTERVAL; |
228 | |||
211 | return 1; | 229 | return 1; |
212 | } | 230 | } |
213 | 231 | ||
@@ -322,6 +340,39 @@ device_initcall(thermal_throttle_init_device); | |||
322 | 340 | ||
323 | #endif /* CONFIG_SYSFS */ | 341 | #endif /* CONFIG_SYSFS */ |
324 | 342 | ||
343 | static void notify_package_thresholds(__u64 msr_val) | ||
344 | { | ||
345 | bool notify_thres_0 = false; | ||
346 | bool notify_thres_1 = false; | ||
347 | |||
348 | if (!platform_thermal_package_notify) | ||
349 | return; | ||
350 | |||
351 | /* lower threshold check */ | ||
352 | if (msr_val & THERM_LOG_THRESHOLD0) | ||
353 | notify_thres_0 = true; | ||
354 | /* higher threshold check */ | ||
355 | if (msr_val & THERM_LOG_THRESHOLD1) | ||
356 | notify_thres_1 = true; | ||
357 | |||
358 | if (!notify_thres_0 && !notify_thres_1) | ||
359 | return; | ||
360 | |||
361 | if (platform_thermal_package_rate_control && | ||
362 | platform_thermal_package_rate_control()) { | ||
363 | /* Rate control is implemented in callback */ | ||
364 | platform_thermal_package_notify(msr_val); | ||
365 | return; | ||
366 | } | ||
367 | |||
368 | /* lower threshold reached */ | ||
369 | if (notify_thres_0 && thresh_event_valid(PACKAGE_LEVEL, 0)) | ||
370 | platform_thermal_package_notify(msr_val); | ||
371 | /* higher threshold reached */ | ||
372 | if (notify_thres_1 && thresh_event_valid(PACKAGE_LEVEL, 1)) | ||
373 | platform_thermal_package_notify(msr_val); | ||
374 | } | ||
375 | |||
325 | static void notify_thresholds(__u64 msr_val) | 376 | static void notify_thresholds(__u64 msr_val) |
326 | { | 377 | { |
327 | /* check whether the interrupt handler is defined; | 378 | /* check whether the interrupt handler is defined; |
@@ -331,10 +382,12 @@ static void notify_thresholds(__u64 msr_val) | |||
331 | return; | 382 | return; |
332 | 383 | ||
333 | /* lower threshold reached */ | 384 | /* lower threshold reached */ |
334 | if ((msr_val & THERM_LOG_THRESHOLD0) && thresh_event_valid(0)) | 385 | if ((msr_val & THERM_LOG_THRESHOLD0) && |
386 | thresh_event_valid(CORE_LEVEL, 0)) | ||
335 | platform_thermal_notify(msr_val); | 387 | platform_thermal_notify(msr_val); |
336 | /* higher threshold reached */ | 388 | /* higher threshold reached */ |
337 | if ((msr_val & THERM_LOG_THRESHOLD1) && thresh_event_valid(1)) | 389 | if ((msr_val & THERM_LOG_THRESHOLD1) && |
390 | thresh_event_valid(CORE_LEVEL, 1)) | ||
338 | platform_thermal_notify(msr_val); | 391 | platform_thermal_notify(msr_val); |
339 | } | 392 | } |
340 | 393 | ||
@@ -360,6 +413,8 @@ static void intel_thermal_interrupt(void) | |||
360 | 413 | ||
361 | if (this_cpu_has(X86_FEATURE_PTS)) { | 414 | if (this_cpu_has(X86_FEATURE_PTS)) { |
362 | rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val); | 415 | rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val); |
416 | /* check violations of package thermal thresholds */ | ||
417 | notify_package_thresholds(msr_val); | ||
363 | therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT, | 418 | therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT, |
364 | THERMAL_THROTTLING_EVENT, | 419 | THERMAL_THROTTLING_EVENT, |
365 | PACKAGE_LEVEL); | 420 | PACKAGE_LEVEL); |