diff options
author | Mike Travis <travis@sgi.com> | 2013-09-23 17:25:00 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-09-24 03:02:02 -0400 |
commit | 1e019421bca68cfae1a61a09d9d49cf6a9e2143b (patch) | |
tree | 94779604797b1147ff48565e6e681206cea29f74 /arch | |
parent | 4a10c2ac2f368583138b774ca41fac4207911983 (diff) |
x86/UV: Move NMI support
This patch moves the UV NMI support from the x2apic file to a
new separate uv_nmi.c file in preparation for the next sequence
of patches. It prevents upcoming bloat of the x2apic file, and
has the added benefit of putting the upcoming /sys/module
parameters under the name 'uv_nmi' instead of 'x2apic_uv_x',
which was obscure.
Signed-off-by: Mike Travis <travis@sgi.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Reviewed-by: Hedi Berriche <hedi@sgi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Jason Wessel <jason.wessel@windriver.com>
Link: http://lkml.kernel.org/r/20130923212500.183295611@asylum.americas.sgi.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/uv/uv.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/apic/x2apic_uv_x.c | 69 | ||||
-rw-r--r-- | arch/x86/platform/uv/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/platform/uv/uv_nmi.c | 102 |
4 files changed, 105 insertions, 70 deletions
diff --git a/arch/x86/include/asm/uv/uv.h b/arch/x86/include/asm/uv/uv.h index 062921ef34e9..6b964a0b86d1 100644 --- a/arch/x86/include/asm/uv/uv.h +++ b/arch/x86/include/asm/uv/uv.h | |||
@@ -12,6 +12,7 @@ extern enum uv_system_type get_uv_system_type(void); | |||
12 | extern int is_uv_system(void); | 12 | extern int is_uv_system(void); |
13 | extern void uv_cpu_init(void); | 13 | extern void uv_cpu_init(void); |
14 | extern void uv_nmi_init(void); | 14 | extern void uv_nmi_init(void); |
15 | extern void uv_register_nmi_notifier(void); | ||
15 | extern void uv_system_init(void); | 16 | extern void uv_system_init(void); |
16 | extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, | 17 | extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, |
17 | struct mm_struct *mm, | 18 | struct mm_struct *mm, |
@@ -25,6 +26,7 @@ static inline enum uv_system_type get_uv_system_type(void) { return UV_NONE; } | |||
25 | static inline int is_uv_system(void) { return 0; } | 26 | static inline int is_uv_system(void) { return 0; } |
26 | static inline void uv_cpu_init(void) { } | 27 | static inline void uv_cpu_init(void) { } |
27 | static inline void uv_system_init(void) { } | 28 | static inline void uv_system_init(void) { } |
29 | static inline void uv_register_nmi_notifier(void) { } | ||
28 | static inline const struct cpumask * | 30 | static inline const struct cpumask * |
29 | uv_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm, | 31 | uv_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm, |
30 | unsigned long start, unsigned long end, unsigned int cpu) | 32 | unsigned long start, unsigned long end, unsigned int cpu) |
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 1191ac1c9d25..9e47c06ae5ab 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c | |||
@@ -39,12 +39,6 @@ | |||
39 | #include <asm/x86_init.h> | 39 | #include <asm/x86_init.h> |
40 | #include <asm/nmi.h> | 40 | #include <asm/nmi.h> |
41 | 41 | ||
42 | /* BMC sets a bit this MMR non-zero before sending an NMI */ | ||
43 | #define UVH_NMI_MMR UVH_SCRATCH5 | ||
44 | #define UVH_NMI_MMR_CLEAR (UVH_NMI_MMR + 8) | ||
45 | #define UV_NMI_PENDING_MASK (1UL << 63) | ||
46 | DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count); | ||
47 | |||
48 | DEFINE_PER_CPU(int, x2apic_extra_bits); | 42 | DEFINE_PER_CPU(int, x2apic_extra_bits); |
49 | 43 | ||
50 | #define PR_DEVEL(fmt, args...) pr_devel("%s: " fmt, __func__, args) | 44 | #define PR_DEVEL(fmt, args...) pr_devel("%s: " fmt, __func__, args) |
@@ -58,7 +52,6 @@ int uv_min_hub_revision_id; | |||
58 | EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); | 52 | EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); |
59 | unsigned int uv_apicid_hibits; | 53 | unsigned int uv_apicid_hibits; |
60 | EXPORT_SYMBOL_GPL(uv_apicid_hibits); | 54 | EXPORT_SYMBOL_GPL(uv_apicid_hibits); |
61 | static DEFINE_SPINLOCK(uv_nmi_lock); | ||
62 | 55 | ||
63 | static struct apic apic_x2apic_uv_x; | 56 | static struct apic apic_x2apic_uv_x; |
64 | 57 | ||
@@ -847,68 +840,6 @@ void uv_cpu_init(void) | |||
847 | set_x2apic_extra_bits(uv_hub_info->pnode); | 840 | set_x2apic_extra_bits(uv_hub_info->pnode); |
848 | } | 841 | } |
849 | 842 | ||
850 | /* | ||
851 | * When NMI is received, print a stack trace. | ||
852 | */ | ||
853 | int uv_handle_nmi(unsigned int reason, struct pt_regs *regs) | ||
854 | { | ||
855 | unsigned long real_uv_nmi; | ||
856 | int bid; | ||
857 | |||
858 | /* | ||
859 | * Each blade has an MMR that indicates when an NMI has been sent | ||
860 | * to cpus on the blade. If an NMI is detected, atomically | ||
861 | * clear the MMR and update a per-blade NMI count used to | ||
862 | * cause each cpu on the blade to notice a new NMI. | ||
863 | */ | ||
864 | bid = uv_numa_blade_id(); | ||
865 | real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK); | ||
866 | |||
867 | if (unlikely(real_uv_nmi)) { | ||
868 | spin_lock(&uv_blade_info[bid].nmi_lock); | ||
869 | real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK); | ||
870 | if (real_uv_nmi) { | ||
871 | uv_blade_info[bid].nmi_count++; | ||
872 | uv_write_local_mmr(UVH_NMI_MMR_CLEAR, UV_NMI_PENDING_MASK); | ||
873 | } | ||
874 | spin_unlock(&uv_blade_info[bid].nmi_lock); | ||
875 | } | ||
876 | |||
877 | if (likely(__get_cpu_var(cpu_last_nmi_count) == uv_blade_info[bid].nmi_count)) | ||
878 | return NMI_DONE; | ||
879 | |||
880 | __get_cpu_var(cpu_last_nmi_count) = uv_blade_info[bid].nmi_count; | ||
881 | |||
882 | /* | ||
883 | * Use a lock so only one cpu prints at a time. | ||
884 | * This prevents intermixed output. | ||
885 | */ | ||
886 | spin_lock(&uv_nmi_lock); | ||
887 | pr_info("UV NMI stack dump cpu %u:\n", smp_processor_id()); | ||
888 | dump_stack(); | ||
889 | spin_unlock(&uv_nmi_lock); | ||
890 | |||
891 | return NMI_HANDLED; | ||
892 | } | ||
893 | |||
894 | void uv_register_nmi_notifier(void) | ||
895 | { | ||
896 | if (register_nmi_handler(NMI_UNKNOWN, uv_handle_nmi, 0, "uv")) | ||
897 | printk(KERN_WARNING "UV NMI handler failed to register\n"); | ||
898 | } | ||
899 | |||
900 | void uv_nmi_init(void) | ||
901 | { | ||
902 | unsigned int value; | ||
903 | |||
904 | /* | ||
905 | * Unmask NMI on all cpus | ||
906 | */ | ||
907 | value = apic_read(APIC_LVT1) | APIC_DM_NMI; | ||
908 | value &= ~APIC_LVT_MASKED; | ||
909 | apic_write(APIC_LVT1, value); | ||
910 | } | ||
911 | |||
912 | void __init uv_system_init(void) | 843 | void __init uv_system_init(void) |
913 | { | 844 | { |
914 | union uvh_rh_gam_config_mmr_u m_n_config; | 845 | union uvh_rh_gam_config_mmr_u m_n_config; |
diff --git a/arch/x86/platform/uv/Makefile b/arch/x86/platform/uv/Makefile index 6c40995fefb8..52079bebd014 100644 --- a/arch/x86/platform/uv/Makefile +++ b/arch/x86/platform/uv/Makefile | |||
@@ -1 +1 @@ | |||
obj-$(CONFIG_X86_UV) += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o | obj-$(CONFIG_X86_UV) += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o uv_nmi.o | ||
diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c new file mode 100644 index 000000000000..37feb60618b1 --- /dev/null +++ b/arch/x86/platform/uv/uv_nmi.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * SGI NMI support routines | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * Copyright (c) 2009-2013 Silicon Graphics, Inc. All Rights Reserved. | ||
19 | * Copyright (c) Mike Travis | ||
20 | */ | ||
21 | |||
22 | #include <linux/cpu.h> | ||
23 | #include <linux/nmi.h> | ||
24 | |||
25 | #include <asm/apic.h> | ||
26 | #include <asm/nmi.h> | ||
27 | #include <asm/uv/uv.h> | ||
28 | #include <asm/uv/uv_hub.h> | ||
29 | #include <asm/uv/uv_mmrs.h> | ||
30 | |||
31 | /* BMC sets a bit this MMR non-zero before sending an NMI */ | ||
32 | #define UVH_NMI_MMR UVH_SCRATCH5 | ||
33 | #define UVH_NMI_MMR_CLEAR (UVH_NMI_MMR + 8) | ||
34 | #define UV_NMI_PENDING_MASK (1UL << 63) | ||
35 | DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count); | ||
36 | static DEFINE_SPINLOCK(uv_nmi_lock); | ||
37 | |||
38 | /* | ||
39 | * When NMI is received, print a stack trace. | ||
40 | */ | ||
41 | int uv_handle_nmi(unsigned int reason, struct pt_regs *regs) | ||
42 | { | ||
43 | unsigned long real_uv_nmi; | ||
44 | int bid; | ||
45 | |||
46 | /* | ||
47 | * Each blade has an MMR that indicates when an NMI has been sent | ||
48 | * to cpus on the blade. If an NMI is detected, atomically | ||
49 | * clear the MMR and update a per-blade NMI count used to | ||
50 | * cause each cpu on the blade to notice a new NMI. | ||
51 | */ | ||
52 | bid = uv_numa_blade_id(); | ||
53 | real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK); | ||
54 | |||
55 | if (unlikely(real_uv_nmi)) { | ||
56 | spin_lock(&uv_blade_info[bid].nmi_lock); | ||
57 | real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & | ||
58 | UV_NMI_PENDING_MASK); | ||
59 | if (real_uv_nmi) { | ||
60 | uv_blade_info[bid].nmi_count++; | ||
61 | uv_write_local_mmr(UVH_NMI_MMR_CLEAR, | ||
62 | UV_NMI_PENDING_MASK); | ||
63 | } | ||
64 | spin_unlock(&uv_blade_info[bid].nmi_lock); | ||
65 | } | ||
66 | |||
67 | if (likely(__get_cpu_var(cpu_last_nmi_count) == | ||
68 | uv_blade_info[bid].nmi_count)) | ||
69 | return NMI_DONE; | ||
70 | |||
71 | __get_cpu_var(cpu_last_nmi_count) = uv_blade_info[bid].nmi_count; | ||
72 | |||
73 | /* | ||
74 | * Use a lock so only one cpu prints at a time. | ||
75 | * This prevents intermixed output. | ||
76 | */ | ||
77 | spin_lock(&uv_nmi_lock); | ||
78 | pr_info("UV NMI stack dump cpu %u:\n", smp_processor_id()); | ||
79 | dump_stack(); | ||
80 | spin_unlock(&uv_nmi_lock); | ||
81 | |||
82 | return NMI_HANDLED; | ||
83 | } | ||
84 | |||
85 | void uv_register_nmi_notifier(void) | ||
86 | { | ||
87 | if (register_nmi_handler(NMI_UNKNOWN, uv_handle_nmi, 0, "uv")) | ||
88 | pr_warn("UV NMI handler failed to register\n"); | ||
89 | } | ||
90 | |||
91 | void uv_nmi_init(void) | ||
92 | { | ||
93 | unsigned int value; | ||
94 | |||
95 | /* | ||
96 | * Unmask NMI on all cpus | ||
97 | */ | ||
98 | value = apic_read(APIC_LVT1) | APIC_DM_NMI; | ||
99 | value &= ~APIC_LVT_MASKED; | ||
100 | apic_write(APIC_LVT1, value); | ||
101 | } | ||
102 | |||