Messages in this thread Patch in this message |  | | Date | Tue, 15 Oct 2002 23:33:19 +0100 | | From | John Levon <> | | Subject | [PATCH] [4/7] oprofile - NMI hook |
| |
This patch provides a simple api to let oprofile hook into the NMI interrupt for the perfctr profiler.
diff -Naur -X dontdiff linux-linus/arch/i386/kernel/i386_ksyms.c linux-linus2/arch/i386/kernel/i386_ksyms.c --- linux-linus/arch/i386/kernel/i386_ksyms.c Tue Oct 15 22:46:47 2002 +++ linux-linus2/arch/i386/kernel/i386_ksyms.c Tue Oct 15 22:47:19 2002 @@ -29,6 +29,7 @@ #include <asm/pgtable.h> #include <asm/pgalloc.h> #include <asm/tlbflush.h> +#include <asm/nmi.h> extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -151,6 +152,10 @@ EXPORT_SYMBOL(flush_tlb_page); #endif +#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM) +EXPORT_SYMBOL_GPL(set_nmi_pm_callback); +EXPORT_SYMBOL_GPL(unset_nmi_pm_callback); +#endif #ifdef CONFIG_X86_IO_APIC EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); #endif @@ -169,6 +174,8 @@ EXPORT_SYMBOL_GPL(register_profile_notifier); EXPORT_SYMBOL_GPL(unregister_profile_notifier); +EXPORT_SYMBOL_GPL(set_nmi_callback); +EXPORT_SYMBOL_GPL(unset_nmi_callback); #undef memcpy #undef memset diff -Naur -X dontdiff linux-linus/arch/i386/kernel/nmi.c linux-linus2/arch/i386/kernel/nmi.c --- linux-linus/arch/i386/kernel/nmi.c Sun Oct 13 19:51:03 2002 +++ linux-linus2/arch/i386/kernel/nmi.c Tue Oct 15 22:47:02 2002 @@ -175,6 +175,18 @@ return 0; } +struct pm_dev * set_nmi_pm_callback(pm_callback callback) +{ + apic_pm_unregister(nmi_pmdev); + return apic_pm_register(PM_SYS_DEV, 0, callback); +} + +void unset_nmi_pm_callback(struct pm_dev * dev) +{ + apic_pm_unregister(dev); + nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback); +} + static void nmi_pm_init(void) { if (!nmi_pmdev) diff -Naur -X dontdiff linux-linus/arch/i386/kernel/traps.c linux-linus2/arch/i386/kernel/traps.c --- linux-linus/arch/i386/kernel/traps.c Sun Oct 13 19:51:03 2002 +++ linux-linus2/arch/i386/kernel/traps.c Tue Oct 15 22:47:02 2002 @@ -40,6 +40,7 @@ #include <asm/debugreg.h> #include <asm/desc.h> #include <asm/i387.h> +#include <asm/nmi.h> #include <asm/smp.h> #include <asm/pgalloc.h> @@ -478,17 +479,16 @@ return; } #endif - printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); + printk("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", + reason, smp_processor_id()); printk("Dazed and confused, but trying to continue\n"); printk("Do you have a strange power saving mode enabled?\n"); } -asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +static void default_do_nmi(struct pt_regs * regs) { unsigned char reason = inb(0x61); - - ++nmi_count(smp_processor_id()); - + if (!(reason & 0xc0)) { #if CONFIG_X86_LOCAL_APIC /* @@ -515,6 +515,33 @@ inb(0x71); /* dummy */ outb(0x0f, 0x70); inb(0x71); /* dummy */ +} + +static int dummy_nmi_callback(struct pt_regs * regs, int cpu) +{ + return 0; +} + +static nmi_callback_t nmi_callback = dummy_nmi_callback; + +asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +{ + int cpu = smp_processor_id(); + + ++nmi_count(cpu); + + if (!nmi_callback(regs, cpu)) + default_do_nmi(regs); +} + +void set_nmi_callback(nmi_callback_t callback) +{ + nmi_callback = callback; +} + +void unset_nmi_callback(void) +{ + nmi_callback = dummy_nmi_callback; } /* diff -Naur -X dontdiff linux-linus/include/asm-i386/nmi.h linux-linus2/include/asm-i386/nmi.h --- linux-linus/include/asm-i386/nmi.h Thu Jan 1 01:00:00 1970 +++ linux-linus2/include/asm-i386/nmi.h Tue Oct 15 22:47:02 2002 @@ -0,0 +1,49 @@ +/* + * linux/include/asm-i386/nmi.h + */ +#ifndef ASM_NMI_H +#define ASM_NMI_H + +#include <linux/pm.h> + +struct pt_regs; + +typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu); + +/** + * set_nmi_callback + * + * Set a handler for an NMI. Only one handler may be + * set. Return 1 if the NMI was handled. + */ +void set_nmi_callback(nmi_callback_t callback); + +/** + * unset_nmi_callback + * + * Remove the handler previously set. + */ +void unset_nmi_callback(void); + +#ifdef CONFIG_PM + +/** Replace the PM callback routine for NMI. */ +struct pm_dev * set_nmi_pm_callback(pm_callback callback); + +/** Unset the PM callback routine back to the default. */ +void unset_nmi_pm_callback(struct pm_dev * dev); + +#else + +static inline struct pm_dev * set_nmi_pm_callback(pm_callback callback) +{ + return 0; +} + +static inline void unset_nmi_pm_callback(struct pm_dev * dev) +{ +} + +#endif /* CONFIG_PM */ + +#endif /* ASM_NMI_H */ - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
|  |