diff options
| -rw-r--r-- | arch/x86/kernel/cpu/perfctr-watchdog.c | 45 | ||||
| -rw-r--r-- | arch/x86/kernel/nmi.c | 11 | ||||
| -rw-r--r-- | include/asm-x86/nmi.h | 1 |
3 files changed, 43 insertions, 14 deletions
diff --git a/arch/x86/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c index 62c010063974..6bff382094f5 100644 --- a/arch/x86/kernel/cpu/perfctr-watchdog.c +++ b/arch/x86/kernel/cpu/perfctr-watchdog.c | |||
| @@ -295,13 +295,19 @@ static int setup_k7_watchdog(unsigned nmi_hz) | |||
| 295 | /* setup the timer */ | 295 | /* setup the timer */ |
| 296 | wrmsr(evntsel_msr, evntsel, 0); | 296 | wrmsr(evntsel_msr, evntsel, 0); |
| 297 | write_watchdog_counter(perfctr_msr, "K7_PERFCTR0",nmi_hz); | 297 | write_watchdog_counter(perfctr_msr, "K7_PERFCTR0",nmi_hz); |
| 298 | apic_write(APIC_LVTPC, APIC_DM_NMI); | ||
| 299 | evntsel |= K7_EVNTSEL_ENABLE; | ||
| 300 | wrmsr(evntsel_msr, evntsel, 0); | ||
| 301 | 298 | ||
| 299 | /* initialize the wd struct before enabling */ | ||
| 302 | wd->perfctr_msr = perfctr_msr; | 300 | wd->perfctr_msr = perfctr_msr; |
| 303 | wd->evntsel_msr = evntsel_msr; | 301 | wd->evntsel_msr = evntsel_msr; |
| 304 | wd->cccr_msr = 0; /* unused */ | 302 | wd->cccr_msr = 0; /* unused */ |
| 303 | |||
| 304 | /* ok, everything is initialized, announce that we're set */ | ||
| 305 | cpu_nmi_set_wd_enabled(); | ||
| 306 | |||
| 307 | apic_write(APIC_LVTPC, APIC_DM_NMI); | ||
| 308 | evntsel |= K7_EVNTSEL_ENABLE; | ||
| 309 | wrmsr(evntsel_msr, evntsel, 0); | ||
| 310 | |||
| 305 | return 1; | 311 | return 1; |
| 306 | } | 312 | } |
| 307 | 313 | ||
| @@ -379,13 +385,19 @@ static int setup_p6_watchdog(unsigned nmi_hz) | |||
| 379 | wrmsr(evntsel_msr, evntsel, 0); | 385 | wrmsr(evntsel_msr, evntsel, 0); |
| 380 | nmi_hz = adjust_for_32bit_ctr(nmi_hz); | 386 | nmi_hz = adjust_for_32bit_ctr(nmi_hz); |
| 381 | write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0",nmi_hz); | 387 | write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0",nmi_hz); |
| 382 | apic_write(APIC_LVTPC, APIC_DM_NMI); | ||
| 383 | evntsel |= P6_EVNTSEL0_ENABLE; | ||
| 384 | wrmsr(evntsel_msr, evntsel, 0); | ||
| 385 | 388 | ||
| 389 | /* initialize the wd struct before enabling */ | ||
| 386 | wd->perfctr_msr = perfctr_msr; | 390 | wd->perfctr_msr = perfctr_msr; |
| 387 | wd->evntsel_msr = evntsel_msr; | 391 | wd->evntsel_msr = evntsel_msr; |
| 388 | wd->cccr_msr = 0; /* unused */ | 392 | wd->cccr_msr = 0; /* unused */ |
| 393 | |||
| 394 | /* ok, everything is initialized, announce that we're set */ | ||
| 395 | cpu_nmi_set_wd_enabled(); | ||
| 396 | |||
| 397 | apic_write(APIC_LVTPC, APIC_DM_NMI); | ||
| 398 | evntsel |= P6_EVNTSEL0_ENABLE; | ||
| 399 | wrmsr(evntsel_msr, evntsel, 0); | ||
| 400 | |||
| 389 | return 1; | 401 | return 1; |
| 390 | } | 402 | } |
| 391 | 403 | ||
| @@ -540,12 +552,17 @@ static int setup_p4_watchdog(unsigned nmi_hz) | |||
| 540 | wrmsr(evntsel_msr, evntsel, 0); | 552 | wrmsr(evntsel_msr, evntsel, 0); |
| 541 | wrmsr(cccr_msr, cccr_val, 0); | 553 | wrmsr(cccr_msr, cccr_val, 0); |
| 542 | write_watchdog_counter(perfctr_msr, "P4_IQ_COUNTER0", nmi_hz); | 554 | write_watchdog_counter(perfctr_msr, "P4_IQ_COUNTER0", nmi_hz); |
| 543 | apic_write(APIC_LVTPC, APIC_DM_NMI); | 555 | |
| 544 | cccr_val |= P4_CCCR_ENABLE; | ||
| 545 | wrmsr(cccr_msr, cccr_val, 0); | ||
| 546 | wd->perfctr_msr = perfctr_msr; | 556 | wd->perfctr_msr = perfctr_msr; |
| 547 | wd->evntsel_msr = evntsel_msr; | 557 | wd->evntsel_msr = evntsel_msr; |
| 548 | wd->cccr_msr = cccr_msr; | 558 | wd->cccr_msr = cccr_msr; |
| 559 | |||
| 560 | /* ok, everything is initialized, announce that we're set */ | ||
| 561 | cpu_nmi_set_wd_enabled(); | ||
| 562 | |||
| 563 | apic_write(APIC_LVTPC, APIC_DM_NMI); | ||
| 564 | cccr_val |= P4_CCCR_ENABLE; | ||
| 565 | wrmsr(cccr_msr, cccr_val, 0); | ||
| 549 | return 1; | 566 | return 1; |
| 550 | } | 567 | } |
| 551 | 568 | ||
| @@ -661,13 +678,17 @@ static int setup_intel_arch_watchdog(unsigned nmi_hz) | |||
| 661 | wrmsr(evntsel_msr, evntsel, 0); | 678 | wrmsr(evntsel_msr, evntsel, 0); |
| 662 | nmi_hz = adjust_for_32bit_ctr(nmi_hz); | 679 | nmi_hz = adjust_for_32bit_ctr(nmi_hz); |
| 663 | write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0", nmi_hz); | 680 | write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0", nmi_hz); |
| 664 | apic_write(APIC_LVTPC, APIC_DM_NMI); | ||
| 665 | evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE; | ||
| 666 | wrmsr(evntsel_msr, evntsel, 0); | ||
| 667 | 681 | ||
| 668 | wd->perfctr_msr = perfctr_msr; | 682 | wd->perfctr_msr = perfctr_msr; |
| 669 | wd->evntsel_msr = evntsel_msr; | 683 | wd->evntsel_msr = evntsel_msr; |
| 670 | wd->cccr_msr = 0; /* unused */ | 684 | wd->cccr_msr = 0; /* unused */ |
| 685 | |||
| 686 | /* ok, everything is initialized, announce that we're set */ | ||
| 687 | cpu_nmi_set_wd_enabled(); | ||
| 688 | |||
| 689 | apic_write(APIC_LVTPC, APIC_DM_NMI); | ||
| 690 | evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE; | ||
| 691 | wrmsr(evntsel_msr, evntsel, 0); | ||
| 671 | intel_arch_wd_ops.checkbit = 1ULL << (eax.split.bit_width - 1); | 692 | intel_arch_wd_ops.checkbit = 1ULL << (eax.split.bit_width - 1); |
| 672 | return 1; | 693 | return 1; |
| 673 | } | 694 | } |
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c index abb78a2cc4ad..2c97f07f1c2c 100644 --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c | |||
| @@ -299,6 +299,15 @@ void acpi_nmi_disable(void) | |||
| 299 | on_each_cpu(__acpi_nmi_disable, NULL, 1); | 299 | on_each_cpu(__acpi_nmi_disable, NULL, 1); |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | /* | ||
| 303 | * This function is called as soon the LAPIC NMI watchdog driver has everything | ||
| 304 | * in place and it's ready to check if the NMIs belong to the NMI watchdog | ||
| 305 | */ | ||
| 306 | void cpu_nmi_set_wd_enabled(void) | ||
| 307 | { | ||
| 308 | __get_cpu_var(wd_enabled) = 1; | ||
| 309 | } | ||
| 310 | |||
| 302 | void setup_apic_nmi_watchdog(void *unused) | 311 | void setup_apic_nmi_watchdog(void *unused) |
| 303 | { | 312 | { |
| 304 | if (__get_cpu_var(wd_enabled)) | 313 | if (__get_cpu_var(wd_enabled)) |
| @@ -311,8 +320,6 @@ void setup_apic_nmi_watchdog(void *unused) | |||
| 311 | 320 | ||
| 312 | switch (nmi_watchdog) { | 321 | switch (nmi_watchdog) { |
| 313 | case NMI_LOCAL_APIC: | 322 | case NMI_LOCAL_APIC: |
| 314 | /* enable it before to avoid race with handler */ | ||
| 315 | __get_cpu_var(wd_enabled) = 1; | ||
| 316 | if (lapic_watchdog_init(nmi_hz) < 0) { | 323 | if (lapic_watchdog_init(nmi_hz) < 0) { |
| 317 | __get_cpu_var(wd_enabled) = 0; | 324 | __get_cpu_var(wd_enabled) = 0; |
| 318 | return; | 325 | return; |
diff --git a/include/asm-x86/nmi.h b/include/asm-x86/nmi.h index 21f8d0202a82..02bfc81cbd62 100644 --- a/include/asm-x86/nmi.h +++ b/include/asm-x86/nmi.h | |||
| @@ -34,6 +34,7 @@ extern void stop_apic_nmi_watchdog(void *); | |||
| 34 | extern void disable_timer_nmi_watchdog(void); | 34 | extern void disable_timer_nmi_watchdog(void); |
| 35 | extern void enable_timer_nmi_watchdog(void); | 35 | extern void enable_timer_nmi_watchdog(void); |
| 36 | extern int nmi_watchdog_tick(struct pt_regs *regs, unsigned reason); | 36 | extern int nmi_watchdog_tick(struct pt_regs *regs, unsigned reason); |
| 37 | extern void cpu_nmi_set_wd_enabled(void); | ||
| 37 | 38 | ||
| 38 | extern atomic_t nmi_active; | 39 | extern atomic_t nmi_active; |
| 39 | extern unsigned int nmi_watchdog; | 40 | extern unsigned int nmi_watchdog; |
