aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/nmi.c
diff options
context:
space:
mode:
authorDon Zickus <dzickus@redhat.com>2006-09-26 04:52:26 -0400
committerAndi Kleen <andi@basil.nowhere.org>2006-09-26 04:52:26 -0400
commit3adbbcce9a49b900d4cc118cdccfdefa78bf1afb (patch)
tree3163758ed23d973a54b396593957c63470f39a0d /arch/x86_64/kernel/nmi.c
parentb7471c6da94d30d3deadc55986cc38d1ff57f9ca (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/nmi.c')
-rw-r--r--arch/x86_64/kernel/nmi.c26
1 files changed, 19 insertions, 7 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
685void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) 685int __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 }
751done: 761done:
752 return; 762 return rc;
753} 763}
754 764
755static __kprobes int dummy_nmi_callback(struct pt_regs * regs, int cpu) 765static __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
762asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code) 772asmlinkage __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
780int do_nmi_callback(struct pt_regs * regs, int cpu)
781{
782 return rcu_dereference(nmi_callback)(regs, cpu);
783}
784
773void set_nmi_callback(nmi_callback_t callback) 785void set_nmi_callback(nmi_callback_t callback)
774{ 786{
775 vmalloc_sync_all(); 787 vmalloc_sync_all();