diff options
author | Don Zickus <dzickus@redhat.com> | 2006-09-26 04:52:26 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-09-26 04:52:26 -0400 |
commit | 3adbbcce9a49b900d4cc118cdccfdefa78bf1afb (patch) | |
tree | 3163758ed23d973a54b396593957c63470f39a0d /arch/x86_64/kernel | |
parent | b7471c6da94d30d3deadc55986cc38d1ff57f9ca (diff) |
[PATCH] x86: Cleanup NMI interrupt path
This patch cleans up the NMI interrupt path. Instead of being gated by if
the 'nmi callback' is set, the interrupt handler now calls everyone who is
registered on the die_chain and additionally checks the nmi watchdog,
reseting it if enabled. This allows more subsystems to hook into the NMI if
they need to (without being block by set_nmi_callback).
Signed-off-by: Don Zickus <dzickus@redhat.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/x86_64/kernel')
-rw-r--r-- | arch/x86_64/kernel/nmi.c | 26 | ||||
-rw-r--r-- | arch/x86_64/kernel/traps.c | 8 |
2 files changed, 23 insertions, 11 deletions
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index d42374a952d7..f6b881b23a70 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c | |||
@@ -682,16 +682,18 @@ void touch_nmi_watchdog (void) | |||
682 | touch_softlockup_watchdog(); | 682 | touch_softlockup_watchdog(); |
683 | } | 683 | } |
684 | 684 | ||
685 | void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) | 685 | int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) |
686 | { | 686 | { |
687 | int sum; | 687 | int sum; |
688 | int touched = 0; | 688 | int touched = 0; |
689 | struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); | 689 | struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); |
690 | u64 dummy; | 690 | u64 dummy; |
691 | int rc=0; | ||
691 | 692 | ||
692 | /* check for other users first */ | 693 | /* check for other users first */ |
693 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) | 694 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) |
694 | == NOTIFY_STOP) { | 695 | == NOTIFY_STOP) { |
696 | rc = 1; | ||
695 | touched = 1; | 697 | touched = 1; |
696 | } | 698 | } |
697 | 699 | ||
@@ -746,10 +748,18 @@ void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) | |||
746 | } | 748 | } |
747 | /* start the cycle over again */ | 749 | /* start the cycle over again */ |
748 | wrmsrl(wd->perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz)); | 750 | wrmsrl(wd->perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz)); |
749 | } | 751 | rc = 1; |
752 | } else if (nmi_watchdog == NMI_IO_APIC) { | ||
753 | /* don't know how to accurately check for this. | ||
754 | * just assume it was a watchdog timer interrupt | ||
755 | * This matches the old behaviour. | ||
756 | */ | ||
757 | rc = 1; | ||
758 | } else | ||
759 | printk(KERN_WARNING "Unknown enabled NMI hardware?!\n"); | ||
750 | } | 760 | } |
751 | done: | 761 | done: |
752 | return; | 762 | return rc; |
753 | } | 763 | } |
754 | 764 | ||
755 | static __kprobes int dummy_nmi_callback(struct pt_regs * regs, int cpu) | 765 | static __kprobes int dummy_nmi_callback(struct pt_regs * regs, int cpu) |
@@ -761,15 +771,17 @@ static nmi_callback_t nmi_callback = dummy_nmi_callback; | |||
761 | 771 | ||
762 | asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code) | 772 | asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code) |
763 | { | 773 | { |
764 | int cpu = safe_smp_processor_id(); | ||
765 | |||
766 | nmi_enter(); | 774 | nmi_enter(); |
767 | add_pda(__nmi_count,1); | 775 | add_pda(__nmi_count,1); |
768 | if (!rcu_dereference(nmi_callback)(regs, cpu)) | 776 | default_do_nmi(regs); |
769 | default_do_nmi(regs); | ||
770 | nmi_exit(); | 777 | nmi_exit(); |
771 | } | 778 | } |
772 | 779 | ||
780 | int do_nmi_callback(struct pt_regs * regs, int cpu) | ||
781 | { | ||
782 | return rcu_dereference(nmi_callback)(regs, cpu); | ||
783 | } | ||
784 | |||
773 | void set_nmi_callback(nmi_callback_t callback) | 785 | void set_nmi_callback(nmi_callback_t callback) |
774 | { | 786 | { |
775 | vmalloc_sync_all(); | 787 | vmalloc_sync_all(); |
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index b1249774d1e8..42bc070fdf11 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -781,12 +781,12 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs) | |||
781 | * Ok, so this is none of the documented NMI sources, | 781 | * Ok, so this is none of the documented NMI sources, |
782 | * so it must be the NMI watchdog. | 782 | * so it must be the NMI watchdog. |
783 | */ | 783 | */ |
784 | if (nmi_watchdog > 0) { | 784 | if (nmi_watchdog_tick(regs,reason)) |
785 | nmi_watchdog_tick(regs,reason); | ||
786 | return; | 785 | return; |
787 | } | 786 | if (!do_nmi_callback(regs,cpu)) |
788 | #endif | 787 | #endif |
789 | unknown_nmi_error(reason, regs); | 788 | unknown_nmi_error(reason, regs); |
789 | |||
790 | return; | 790 | return; |
791 | } | 791 | } |
792 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) | 792 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) |