aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMike Travis <travis@sgi.com>2013-09-23 17:25:00 -0400
committerIngo Molnar <mingo@kernel.org>2013-09-24 03:02:02 -0400
commit1e019421bca68cfae1a61a09d9d49cf6a9e2143b (patch)
tree94779604797b1147ff48565e6e681206cea29f74 /arch
parent4a10c2ac2f368583138b774ca41fac4207911983 (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.h2
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c69
-rw-r--r--arch/x86/platform/uv/Makefile2
-rw-r--r--arch/x86/platform/uv/uv_nmi.c102
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);
12extern int is_uv_system(void); 12extern int is_uv_system(void);
13extern void uv_cpu_init(void); 13extern void uv_cpu_init(void);
14extern void uv_nmi_init(void); 14extern void uv_nmi_init(void);
15extern void uv_register_nmi_notifier(void);
15extern void uv_system_init(void); 16extern void uv_system_init(void);
16extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, 17extern 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; }
25static inline int is_uv_system(void) { return 0; } 26static inline int is_uv_system(void) { return 0; }
26static inline void uv_cpu_init(void) { } 27static inline void uv_cpu_init(void) { }
27static inline void uv_system_init(void) { } 28static inline void uv_system_init(void) { }
29static inline void uv_register_nmi_notifier(void) { }
28static inline const struct cpumask * 30static inline const struct cpumask *
29uv_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm, 31uv_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)
46DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count);
47
48DEFINE_PER_CPU(int, x2apic_extra_bits); 42DEFINE_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;
58EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); 52EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
59unsigned int uv_apicid_hibits; 53unsigned int uv_apicid_hibits;
60EXPORT_SYMBOL_GPL(uv_apicid_hibits); 54EXPORT_SYMBOL_GPL(uv_apicid_hibits);
61static DEFINE_SPINLOCK(uv_nmi_lock);
62 55
63static struct apic apic_x2apic_uv_x; 56static 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 */
853int 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
894void 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
900void 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
912void __init uv_system_init(void) 843void __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)
35DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count);
36static DEFINE_SPINLOCK(uv_nmi_lock);
37
38/*
39 * When NMI is received, print a stack trace.
40 */
41int 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
85void 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
91void 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