diff options
Diffstat (limited to 'arch/i386/kernel/nmi.c')
-rw-r--r-- | arch/i386/kernel/nmi.c | 107 |
1 files changed, 87 insertions, 20 deletions
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 1a6f8bb8881c..821df34d2b3a 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/dmi.h> | 23 | #include <linux/dmi.h> |
24 | #include <linux/kprobes.h> | 24 | #include <linux/kprobes.h> |
25 | #include <linux/cpumask.h> | 25 | #include <linux/cpumask.h> |
26 | #include <linux/kernel_stat.h> | ||
26 | 27 | ||
27 | #include <asm/smp.h> | 28 | #include <asm/smp.h> |
28 | #include <asm/nmi.h> | 29 | #include <asm/nmi.h> |
@@ -185,7 +186,8 @@ static __cpuinit inline int nmi_known_cpu(void) | |||
185 | { | 186 | { |
186 | switch (boot_cpu_data.x86_vendor) { | 187 | switch (boot_cpu_data.x86_vendor) { |
187 | case X86_VENDOR_AMD: | 188 | case X86_VENDOR_AMD: |
188 | return ((boot_cpu_data.x86 == 15) || (boot_cpu_data.x86 == 6)); | 189 | return ((boot_cpu_data.x86 == 15) || (boot_cpu_data.x86 == 6) |
190 | || (boot_cpu_data.x86 == 16)); | ||
189 | case X86_VENDOR_INTEL: | 191 | case X86_VENDOR_INTEL: |
190 | if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) | 192 | if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) |
191 | return 1; | 193 | return 1; |
@@ -216,6 +218,28 @@ static __init void nmi_cpu_busy(void *data) | |||
216 | } | 218 | } |
217 | #endif | 219 | #endif |
218 | 220 | ||
221 | static unsigned int adjust_for_32bit_ctr(unsigned int hz) | ||
222 | { | ||
223 | u64 counter_val; | ||
224 | unsigned int retval = hz; | ||
225 | |||
226 | /* | ||
227 | * On Intel CPUs with P6/ARCH_PERFMON only 32 bits in the counter | ||
228 | * are writable, with higher bits sign extending from bit 31. | ||
229 | * So, we can only program the counter with 31 bit values and | ||
230 | * 32nd bit should be 1, for 33.. to be 1. | ||
231 | * Find the appropriate nmi_hz | ||
232 | */ | ||
233 | counter_val = (u64)cpu_khz * 1000; | ||
234 | do_div(counter_val, retval); | ||
235 | if (counter_val > 0x7fffffffULL) { | ||
236 | u64 count = (u64)cpu_khz * 1000; | ||
237 | do_div(count, 0x7fffffffUL); | ||
238 | retval = count + 1; | ||
239 | } | ||
240 | return retval; | ||
241 | } | ||
242 | |||
219 | static int __init check_nmi_watchdog(void) | 243 | static int __init check_nmi_watchdog(void) |
220 | { | 244 | { |
221 | unsigned int *prev_nmi_count; | 245 | unsigned int *prev_nmi_count; |
@@ -281,18 +305,10 @@ static int __init check_nmi_watchdog(void) | |||
281 | struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); | 305 | struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); |
282 | 306 | ||
283 | nmi_hz = 1; | 307 | nmi_hz = 1; |
284 | /* | 308 | |
285 | * On Intel CPUs with ARCH_PERFMON only 32 bits in the counter | 309 | if (wd->perfctr_msr == MSR_P6_PERFCTR0 || |
286 | * are writable, with higher bits sign extending from bit 31. | 310 | wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { |
287 | * So, we can only program the counter with 31 bit values and | 311 | nmi_hz = adjust_for_32bit_ctr(nmi_hz); |
288 | * 32nd bit should be 1, for 33.. to be 1. | ||
289 | * Find the appropriate nmi_hz | ||
290 | */ | ||
291 | if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0 && | ||
292 | ((u64)cpu_khz * 1000) > 0x7fffffffULL) { | ||
293 | u64 count = (u64)cpu_khz * 1000; | ||
294 | do_div(count, 0x7fffffffUL); | ||
295 | nmi_hz = count + 1; | ||
296 | } | 312 | } |
297 | } | 313 | } |
298 | 314 | ||
@@ -369,6 +385,34 @@ void enable_timer_nmi_watchdog(void) | |||
369 | } | 385 | } |
370 | } | 386 | } |
371 | 387 | ||
388 | static void __acpi_nmi_disable(void *__unused) | ||
389 | { | ||
390 | apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED); | ||
391 | } | ||
392 | |||
393 | /* | ||
394 | * Disable timer based NMIs on all CPUs: | ||
395 | */ | ||
396 | void acpi_nmi_disable(void) | ||
397 | { | ||
398 | if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC) | ||
399 | on_each_cpu(__acpi_nmi_disable, NULL, 0, 1); | ||
400 | } | ||
401 | |||
402 | static void __acpi_nmi_enable(void *__unused) | ||
403 | { | ||
404 | apic_write_around(APIC_LVT0, APIC_DM_NMI); | ||
405 | } | ||
406 | |||
407 | /* | ||
408 | * Enable timer based NMIs on all CPUs: | ||
409 | */ | ||
410 | void acpi_nmi_enable(void) | ||
411 | { | ||
412 | if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC) | ||
413 | on_each_cpu(__acpi_nmi_enable, NULL, 0, 1); | ||
414 | } | ||
415 | |||
372 | #ifdef CONFIG_PM | 416 | #ifdef CONFIG_PM |
373 | 417 | ||
374 | static int nmi_pm_active; /* nmi_active before suspend */ | 418 | static int nmi_pm_active; /* nmi_active before suspend */ |
@@ -442,6 +486,17 @@ static void write_watchdog_counter(unsigned int perfctr_msr, const char *descr) | |||
442 | wrmsrl(perfctr_msr, 0 - count); | 486 | wrmsrl(perfctr_msr, 0 - count); |
443 | } | 487 | } |
444 | 488 | ||
489 | static void write_watchdog_counter32(unsigned int perfctr_msr, | ||
490 | const char *descr) | ||
491 | { | ||
492 | u64 count = (u64)cpu_khz * 1000; | ||
493 | |||
494 | do_div(count, nmi_hz); | ||
495 | if(descr) | ||
496 | Dprintk("setting %s to -0x%08Lx\n", descr, count); | ||
497 | wrmsr(perfctr_msr, (u32)(-count), 0); | ||
498 | } | ||
499 | |||
445 | /* Note that these events don't tick when the CPU idles. This means | 500 | /* Note that these events don't tick when the CPU idles. This means |
446 | the frequency varies with CPU load. */ | 501 | the frequency varies with CPU load. */ |
447 | 502 | ||
@@ -531,7 +586,8 @@ static int setup_p6_watchdog(void) | |||
531 | 586 | ||
532 | /* setup the timer */ | 587 | /* setup the timer */ |
533 | wrmsr(evntsel_msr, evntsel, 0); | 588 | wrmsr(evntsel_msr, evntsel, 0); |
534 | write_watchdog_counter(perfctr_msr, "P6_PERFCTR0"); | 589 | nmi_hz = adjust_for_32bit_ctr(nmi_hz); |
590 | write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0"); | ||
535 | apic_write(APIC_LVTPC, APIC_DM_NMI); | 591 | apic_write(APIC_LVTPC, APIC_DM_NMI); |
536 | evntsel |= P6_EVNTSEL0_ENABLE; | 592 | evntsel |= P6_EVNTSEL0_ENABLE; |
537 | wrmsr(evntsel_msr, evntsel, 0); | 593 | wrmsr(evntsel_msr, evntsel, 0); |
@@ -704,7 +760,8 @@ static int setup_intel_arch_watchdog(void) | |||
704 | 760 | ||
705 | /* setup the timer */ | 761 | /* setup the timer */ |
706 | wrmsr(evntsel_msr, evntsel, 0); | 762 | wrmsr(evntsel_msr, evntsel, 0); |
707 | write_watchdog_counter(perfctr_msr, "INTEL_ARCH_PERFCTR0"); | 763 | nmi_hz = adjust_for_32bit_ctr(nmi_hz); |
764 | write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0"); | ||
708 | apic_write(APIC_LVTPC, APIC_DM_NMI); | 765 | apic_write(APIC_LVTPC, APIC_DM_NMI); |
709 | evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE; | 766 | evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE; |
710 | wrmsr(evntsel_msr, evntsel, 0); | 767 | wrmsr(evntsel_msr, evntsel, 0); |
@@ -762,7 +819,8 @@ void setup_apic_nmi_watchdog (void *unused) | |||
762 | if (nmi_watchdog == NMI_LOCAL_APIC) { | 819 | if (nmi_watchdog == NMI_LOCAL_APIC) { |
763 | switch (boot_cpu_data.x86_vendor) { | 820 | switch (boot_cpu_data.x86_vendor) { |
764 | case X86_VENDOR_AMD: | 821 | case X86_VENDOR_AMD: |
765 | if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15) | 822 | if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 && |
823 | boot_cpu_data.x86 != 16) | ||
766 | return; | 824 | return; |
767 | if (!setup_k7_watchdog()) | 825 | if (!setup_k7_watchdog()) |
768 | return; | 826 | return; |
@@ -916,9 +974,13 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) | |||
916 | cpu_clear(cpu, backtrace_mask); | 974 | cpu_clear(cpu, backtrace_mask); |
917 | } | 975 | } |
918 | 976 | ||
919 | sum = per_cpu(irq_stat, cpu).apic_timer_irqs; | 977 | /* |
978 | * Take the local apic timer and PIT/HPET into account. We don't | ||
979 | * know which one is active, when we have highres/dyntick on | ||
980 | */ | ||
981 | sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_irqs(0); | ||
920 | 982 | ||
921 | /* if the apic timer isn't firing, this cpu isn't doing much */ | 983 | /* if the none of the timers isn't firing, this cpu isn't doing much */ |
922 | if (!touched && last_irq_sums[cpu] == sum) { | 984 | if (!touched && last_irq_sums[cpu] == sum) { |
923 | /* | 985 | /* |
924 | * Ayiee, looks like this CPU is stuck ... | 986 | * Ayiee, looks like this CPU is stuck ... |
@@ -956,6 +1018,8 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) | |||
956 | dummy &= ~P4_CCCR_OVF; | 1018 | dummy &= ~P4_CCCR_OVF; |
957 | wrmsrl(wd->cccr_msr, dummy); | 1019 | wrmsrl(wd->cccr_msr, dummy); |
958 | apic_write(APIC_LVTPC, APIC_DM_NMI); | 1020 | apic_write(APIC_LVTPC, APIC_DM_NMI); |
1021 | /* start the cycle over again */ | ||
1022 | write_watchdog_counter(wd->perfctr_msr, NULL); | ||
959 | } | 1023 | } |
960 | else if (wd->perfctr_msr == MSR_P6_PERFCTR0 || | 1024 | else if (wd->perfctr_msr == MSR_P6_PERFCTR0 || |
961 | wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { | 1025 | wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { |
@@ -964,9 +1028,12 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) | |||
964 | * other P6 variant. | 1028 | * other P6 variant. |
965 | * ArchPerfom/Core Duo also needs this */ | 1029 | * ArchPerfom/Core Duo also needs this */ |
966 | apic_write(APIC_LVTPC, APIC_DM_NMI); | 1030 | apic_write(APIC_LVTPC, APIC_DM_NMI); |
1031 | /* P6/ARCH_PERFMON has 32 bit counter write */ | ||
1032 | write_watchdog_counter32(wd->perfctr_msr, NULL); | ||
1033 | } else { | ||
1034 | /* start the cycle over again */ | ||
1035 | write_watchdog_counter(wd->perfctr_msr, NULL); | ||
967 | } | 1036 | } |
968 | /* start the cycle over again */ | ||
969 | write_watchdog_counter(wd->perfctr_msr, NULL); | ||
970 | rc = 1; | 1037 | rc = 1; |
971 | } else if (nmi_watchdog == NMI_IO_APIC) { | 1038 | } else if (nmi_watchdog == NMI_IO_APIC) { |
972 | /* don't know how to accurately check for this. | 1039 | /* don't know how to accurately check for this. |