aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/nmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/nmi.c')
-rw-r--r--arch/x86_64/kernel/nmi.c75
1 files changed, 60 insertions, 15 deletions
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 9cb42ecb7f89..486f4c61a948 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -172,7 +172,7 @@ static __cpuinit inline int nmi_known_cpu(void)
172{ 172{
173 switch (boot_cpu_data.x86_vendor) { 173 switch (boot_cpu_data.x86_vendor) {
174 case X86_VENDOR_AMD: 174 case X86_VENDOR_AMD:
175 return boot_cpu_data.x86 == 15; 175 return boot_cpu_data.x86 == 15 || boot_cpu_data.x86 == 16;
176 case X86_VENDOR_INTEL: 176 case X86_VENDOR_INTEL:
177 if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) 177 if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
178 return 1; 178 return 1;
@@ -214,6 +214,23 @@ static __init void nmi_cpu_busy(void *data)
214} 214}
215#endif 215#endif
216 216
217static unsigned int adjust_for_32bit_ctr(unsigned int hz)
218{
219 unsigned int retval = hz;
220
221 /*
222 * On Intel CPUs with ARCH_PERFMON only 32 bits in the counter
223 * are writable, with higher bits sign extending from bit 31.
224 * So, we can only program the counter with 31 bit values and
225 * 32nd bit should be 1, for 33.. to be 1.
226 * Find the appropriate nmi_hz
227 */
228 if ((((u64)cpu_khz * 1000) / retval) > 0x7fffffffULL) {
229 retval = ((u64)cpu_khz * 1000) / 0x7fffffffUL + 1;
230 }
231 return retval;
232}
233
217int __init check_nmi_watchdog (void) 234int __init check_nmi_watchdog (void)
218{ 235{
219 int *counts; 236 int *counts;
@@ -268,17 +285,8 @@ int __init check_nmi_watchdog (void)
268 struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); 285 struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
269 286
270 nmi_hz = 1; 287 nmi_hz = 1;
271 /* 288 if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0)
272 * On Intel CPUs with ARCH_PERFMON only 32 bits in the counter 289 nmi_hz = adjust_for_32bit_ctr(nmi_hz);
273 * are writable, with higher bits sign extending from bit 31.
274 * So, we can only program the counter with 31 bit values and
275 * 32nd bit should be 1, for 33.. to be 1.
276 * Find the appropriate nmi_hz
277 */
278 if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0 &&
279 ((u64)cpu_khz * 1000) > 0x7fffffffULL) {
280 nmi_hz = ((u64)cpu_khz * 1000) / 0x7fffffffUL + 1;
281 }
282 } 290 }
283 291
284 kfree(counts); 292 kfree(counts);
@@ -360,6 +368,33 @@ void enable_timer_nmi_watchdog(void)
360 } 368 }
361} 369}
362 370
371static void __acpi_nmi_disable(void *__unused)
372{
373 apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
374}
375
376/*
377 * Disable timer based NMIs on all CPUs:
378 */
379void acpi_nmi_disable(void)
380{
381 if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
382 on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
383}
384
385static void __acpi_nmi_enable(void *__unused)
386{
387 apic_write(APIC_LVT0, APIC_DM_NMI);
388}
389
390/*
391 * Enable timer based NMIs on all CPUs:
392 */
393void acpi_nmi_enable(void)
394{
395 if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
396 on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
397}
363#ifdef CONFIG_PM 398#ifdef CONFIG_PM
364 399
365static int nmi_pm_active; /* nmi_active before suspend */ 400static int nmi_pm_active; /* nmi_active before suspend */
@@ -634,7 +669,9 @@ static int setup_intel_arch_watchdog(void)
634 669
635 /* setup the timer */ 670 /* setup the timer */
636 wrmsr(evntsel_msr, evntsel, 0); 671 wrmsr(evntsel_msr, evntsel, 0);
637 wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz)); 672
673 nmi_hz = adjust_for_32bit_ctr(nmi_hz);
674 wrmsr(perfctr_msr, (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0);
638 675
639 apic_write(APIC_LVTPC, APIC_DM_NMI); 676 apic_write(APIC_LVTPC, APIC_DM_NMI);
640 evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE; 677 evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
@@ -855,15 +892,23 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
855 dummy &= ~P4_CCCR_OVF; 892 dummy &= ~P4_CCCR_OVF;
856 wrmsrl(wd->cccr_msr, dummy); 893 wrmsrl(wd->cccr_msr, dummy);
857 apic_write(APIC_LVTPC, APIC_DM_NMI); 894 apic_write(APIC_LVTPC, APIC_DM_NMI);
895 /* start the cycle over again */
896 wrmsrl(wd->perfctr_msr,
897 -((u64)cpu_khz * 1000 / nmi_hz));
858 } else if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { 898 } else if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
859 /* 899 /*
860 * ArchPerfom/Core Duo needs to re-unmask 900 * ArchPerfom/Core Duo needs to re-unmask
861 * the apic vector 901 * the apic vector
862 */ 902 */
863 apic_write(APIC_LVTPC, APIC_DM_NMI); 903 apic_write(APIC_LVTPC, APIC_DM_NMI);
904 /* ARCH_PERFMON has 32 bit counter writes */
905 wrmsr(wd->perfctr_msr,
906 (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0);
907 } else {
908 /* start the cycle over again */
909 wrmsrl(wd->perfctr_msr,
910 -((u64)cpu_khz * 1000 / nmi_hz));
864 } 911 }
865 /* start the cycle over again */
866 wrmsrl(wd->perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
867 rc = 1; 912 rc = 1;
868 } else if (nmi_watchdog == NMI_IO_APIC) { 913 } else if (nmi_watchdog == NMI_IO_APIC) {
869 /* don't know how to accurately check for this. 914 /* don't know how to accurately check for this.