diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-11 22:01:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-11 22:01:14 -0500 |
commit | 9b66bfb28049594fe2bb2b91607ba302f511ce8b (patch) | |
tree | e96e79b1864699800c3f2c2e06b482a995744daf /arch/x86/platform | |
parent | c2136301e43cbb3b71d0163a9949f30dafcb4590 (diff) | |
parent | b5dfcb09debc38582c3cb72a3c1a88b919b07f2d (diff) |
Merge branch 'x86-uv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 UV debug changes from Ingo Molnar:
"Various SGI UV debuggability improvements, amongst them KDB support,
with related core KDB enabling patches changing kernel/debug/kdb/"
* 'x86-uv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
Revert "x86/UV: Add uvtrace support"
x86/UV: Add call to KGDB/KDB from NMI handler
kdb: Add support for external NMI handler to call KGDB/KDB
x86/UV: Check for alloc_cpumask_var() failures properly in uv_nmi_setup()
x86/UV: Add uvtrace support
x86/UV: Add kdump to UV NMI handler
x86/UV: Add summary of cpu activity to UV NMI handler
x86/UV: Update UV support for external NMI signals
x86/UV: Move NMI support
Diffstat (limited to 'arch/x86/platform')
-rw-r--r-- | arch/x86/platform/uv/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/platform/uv/uv_nmi.c | 700 |
2 files changed, 701 insertions, 1 deletions
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..2e863ad4a772 --- /dev/null +++ b/arch/x86/platform/uv/uv_nmi.c | |||
@@ -0,0 +1,700 @@ | |||
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/delay.h> | ||
24 | #include <linux/kdb.h> | ||
25 | #include <linux/kexec.h> | ||
26 | #include <linux/kgdb.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/nmi.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/slab.h> | ||
31 | |||
32 | #include <asm/apic.h> | ||
33 | #include <asm/current.h> | ||
34 | #include <asm/kdebug.h> | ||
35 | #include <asm/local64.h> | ||
36 | #include <asm/nmi.h> | ||
37 | #include <asm/traps.h> | ||
38 | #include <asm/uv/uv.h> | ||
39 | #include <asm/uv/uv_hub.h> | ||
40 | #include <asm/uv/uv_mmrs.h> | ||
41 | |||
42 | /* | ||
43 | * UV handler for NMI | ||
44 | * | ||
45 | * Handle system-wide NMI events generated by the global 'power nmi' command. | ||
46 | * | ||
47 | * Basic operation is to field the NMI interrupt on each cpu and wait | ||
48 | * until all cpus have arrived into the nmi handler. If some cpus do not | ||
49 | * make it into the handler, try and force them in with the IPI(NMI) signal. | ||
50 | * | ||
51 | * We also have to lessen UV Hub MMR accesses as much as possible as this | ||
52 | * disrupts the UV Hub's primary mission of directing NumaLink traffic and | ||
53 | * can cause system problems to occur. | ||
54 | * | ||
55 | * To do this we register our primary NMI notifier on the NMI_UNKNOWN | ||
56 | * chain. This reduces the number of false NMI calls when the perf | ||
57 | * tools are running which generate an enormous number of NMIs per | ||
58 | * second (~4M/s for 1024 cpu threads). Our secondary NMI handler is | ||
59 | * very short as it only checks that if it has been "pinged" with the | ||
60 | * IPI(NMI) signal as mentioned above, and does not read the UV Hub's MMR. | ||
61 | * | ||
62 | */ | ||
63 | |||
64 | static struct uv_hub_nmi_s **uv_hub_nmi_list; | ||
65 | |||
66 | DEFINE_PER_CPU(struct uv_cpu_nmi_s, __uv_cpu_nmi); | ||
67 | EXPORT_PER_CPU_SYMBOL_GPL(__uv_cpu_nmi); | ||
68 | |||
69 | static unsigned long nmi_mmr; | ||
70 | static unsigned long nmi_mmr_clear; | ||
71 | static unsigned long nmi_mmr_pending; | ||
72 | |||
73 | static atomic_t uv_in_nmi; | ||
74 | static atomic_t uv_nmi_cpu = ATOMIC_INIT(-1); | ||
75 | static atomic_t uv_nmi_cpus_in_nmi = ATOMIC_INIT(-1); | ||
76 | static atomic_t uv_nmi_slave_continue; | ||
77 | static atomic_t uv_nmi_kexec_failed; | ||
78 | static cpumask_var_t uv_nmi_cpu_mask; | ||
79 | |||
80 | /* Values for uv_nmi_slave_continue */ | ||
81 | #define SLAVE_CLEAR 0 | ||
82 | #define SLAVE_CONTINUE 1 | ||
83 | #define SLAVE_EXIT 2 | ||
84 | |||
85 | /* | ||
86 | * Default is all stack dumps go to the console and buffer. | ||
87 | * Lower level to send to log buffer only. | ||
88 | */ | ||
89 | static int uv_nmi_loglevel = 7; | ||
90 | module_param_named(dump_loglevel, uv_nmi_loglevel, int, 0644); | ||
91 | |||
92 | /* | ||
93 | * The following values show statistics on how perf events are affecting | ||
94 | * this system. | ||
95 | */ | ||
96 | static int param_get_local64(char *buffer, const struct kernel_param *kp) | ||
97 | { | ||
98 | return sprintf(buffer, "%lu\n", local64_read((local64_t *)kp->arg)); | ||
99 | } | ||
100 | |||
101 | static int param_set_local64(const char *val, const struct kernel_param *kp) | ||
102 | { | ||
103 | /* clear on any write */ | ||
104 | local64_set((local64_t *)kp->arg, 0); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static struct kernel_param_ops param_ops_local64 = { | ||
109 | .get = param_get_local64, | ||
110 | .set = param_set_local64, | ||
111 | }; | ||
112 | #define param_check_local64(name, p) __param_check(name, p, local64_t) | ||
113 | |||
114 | static local64_t uv_nmi_count; | ||
115 | module_param_named(nmi_count, uv_nmi_count, local64, 0644); | ||
116 | |||
117 | static local64_t uv_nmi_misses; | ||
118 | module_param_named(nmi_misses, uv_nmi_misses, local64, 0644); | ||
119 | |||
120 | static local64_t uv_nmi_ping_count; | ||
121 | module_param_named(ping_count, uv_nmi_ping_count, local64, 0644); | ||
122 | |||
123 | static local64_t uv_nmi_ping_misses; | ||
124 | module_param_named(ping_misses, uv_nmi_ping_misses, local64, 0644); | ||
125 | |||
126 | /* | ||
127 | * Following values allow tuning for large systems under heavy loading | ||
128 | */ | ||
129 | static int uv_nmi_initial_delay = 100; | ||
130 | module_param_named(initial_delay, uv_nmi_initial_delay, int, 0644); | ||
131 | |||
132 | static int uv_nmi_slave_delay = 100; | ||
133 | module_param_named(slave_delay, uv_nmi_slave_delay, int, 0644); | ||
134 | |||
135 | static int uv_nmi_loop_delay = 100; | ||
136 | module_param_named(loop_delay, uv_nmi_loop_delay, int, 0644); | ||
137 | |||
138 | static int uv_nmi_trigger_delay = 10000; | ||
139 | module_param_named(trigger_delay, uv_nmi_trigger_delay, int, 0644); | ||
140 | |||
141 | static int uv_nmi_wait_count = 100; | ||
142 | module_param_named(wait_count, uv_nmi_wait_count, int, 0644); | ||
143 | |||
144 | static int uv_nmi_retry_count = 500; | ||
145 | module_param_named(retry_count, uv_nmi_retry_count, int, 0644); | ||
146 | |||
147 | /* | ||
148 | * Valid NMI Actions: | ||
149 | * "dump" - dump process stack for each cpu | ||
150 | * "ips" - dump IP info for each cpu | ||
151 | * "kdump" - do crash dump | ||
152 | * "kdb" - enter KDB/KGDB (default) | ||
153 | */ | ||
154 | static char uv_nmi_action[8] = "kdb"; | ||
155 | module_param_string(action, uv_nmi_action, sizeof(uv_nmi_action), 0644); | ||
156 | |||
157 | static inline bool uv_nmi_action_is(const char *action) | ||
158 | { | ||
159 | return (strncmp(uv_nmi_action, action, strlen(action)) == 0); | ||
160 | } | ||
161 | |||
162 | /* Setup which NMI support is present in system */ | ||
163 | static void uv_nmi_setup_mmrs(void) | ||
164 | { | ||
165 | if (uv_read_local_mmr(UVH_NMI_MMRX_SUPPORTED)) { | ||
166 | uv_write_local_mmr(UVH_NMI_MMRX_REQ, | ||
167 | 1UL << UVH_NMI_MMRX_REQ_SHIFT); | ||
168 | nmi_mmr = UVH_NMI_MMRX; | ||
169 | nmi_mmr_clear = UVH_NMI_MMRX_CLEAR; | ||
170 | nmi_mmr_pending = 1UL << UVH_NMI_MMRX_SHIFT; | ||
171 | pr_info("UV: SMI NMI support: %s\n", UVH_NMI_MMRX_TYPE); | ||
172 | } else { | ||
173 | nmi_mmr = UVH_NMI_MMR; | ||
174 | nmi_mmr_clear = UVH_NMI_MMR_CLEAR; | ||
175 | nmi_mmr_pending = 1UL << UVH_NMI_MMR_SHIFT; | ||
176 | pr_info("UV: SMI NMI support: %s\n", UVH_NMI_MMR_TYPE); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /* Read NMI MMR and check if NMI flag was set by BMC. */ | ||
181 | static inline int uv_nmi_test_mmr(struct uv_hub_nmi_s *hub_nmi) | ||
182 | { | ||
183 | hub_nmi->nmi_value = uv_read_local_mmr(nmi_mmr); | ||
184 | atomic_inc(&hub_nmi->read_mmr_count); | ||
185 | return !!(hub_nmi->nmi_value & nmi_mmr_pending); | ||
186 | } | ||
187 | |||
188 | static inline void uv_local_mmr_clear_nmi(void) | ||
189 | { | ||
190 | uv_write_local_mmr(nmi_mmr_clear, nmi_mmr_pending); | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * If first cpu in on this hub, set hub_nmi "in_nmi" and "owner" values and | ||
195 | * return true. If first cpu in on the system, set global "in_nmi" flag. | ||
196 | */ | ||
197 | static int uv_set_in_nmi(int cpu, struct uv_hub_nmi_s *hub_nmi) | ||
198 | { | ||
199 | int first = atomic_add_unless(&hub_nmi->in_nmi, 1, 1); | ||
200 | |||
201 | if (first) { | ||
202 | atomic_set(&hub_nmi->cpu_owner, cpu); | ||
203 | if (atomic_add_unless(&uv_in_nmi, 1, 1)) | ||
204 | atomic_set(&uv_nmi_cpu, cpu); | ||
205 | |||
206 | atomic_inc(&hub_nmi->nmi_count); | ||
207 | } | ||
208 | return first; | ||
209 | } | ||
210 | |||
211 | /* Check if this is a system NMI event */ | ||
212 | static int uv_check_nmi(struct uv_hub_nmi_s *hub_nmi) | ||
213 | { | ||
214 | int cpu = smp_processor_id(); | ||
215 | int nmi = 0; | ||
216 | |||
217 | local64_inc(&uv_nmi_count); | ||
218 | uv_cpu_nmi.queries++; | ||
219 | |||
220 | do { | ||
221 | nmi = atomic_read(&hub_nmi->in_nmi); | ||
222 | if (nmi) | ||
223 | break; | ||
224 | |||
225 | if (raw_spin_trylock(&hub_nmi->nmi_lock)) { | ||
226 | |||
227 | /* check hub MMR NMI flag */ | ||
228 | if (uv_nmi_test_mmr(hub_nmi)) { | ||
229 | uv_set_in_nmi(cpu, hub_nmi); | ||
230 | nmi = 1; | ||
231 | break; | ||
232 | } | ||
233 | |||
234 | /* MMR NMI flag is clear */ | ||
235 | raw_spin_unlock(&hub_nmi->nmi_lock); | ||
236 | |||
237 | } else { | ||
238 | /* wait a moment for the hub nmi locker to set flag */ | ||
239 | cpu_relax(); | ||
240 | udelay(uv_nmi_slave_delay); | ||
241 | |||
242 | /* re-check hub in_nmi flag */ | ||
243 | nmi = atomic_read(&hub_nmi->in_nmi); | ||
244 | if (nmi) | ||
245 | break; | ||
246 | } | ||
247 | |||
248 | /* check if this BMC missed setting the MMR NMI flag */ | ||
249 | if (!nmi) { | ||
250 | nmi = atomic_read(&uv_in_nmi); | ||
251 | if (nmi) | ||
252 | uv_set_in_nmi(cpu, hub_nmi); | ||
253 | } | ||
254 | |||
255 | } while (0); | ||
256 | |||
257 | if (!nmi) | ||
258 | local64_inc(&uv_nmi_misses); | ||
259 | |||
260 | return nmi; | ||
261 | } | ||
262 | |||
263 | /* Need to reset the NMI MMR register, but only once per hub. */ | ||
264 | static inline void uv_clear_nmi(int cpu) | ||
265 | { | ||
266 | struct uv_hub_nmi_s *hub_nmi = uv_hub_nmi; | ||
267 | |||
268 | if (cpu == atomic_read(&hub_nmi->cpu_owner)) { | ||
269 | atomic_set(&hub_nmi->cpu_owner, -1); | ||
270 | atomic_set(&hub_nmi->in_nmi, 0); | ||
271 | uv_local_mmr_clear_nmi(); | ||
272 | raw_spin_unlock(&hub_nmi->nmi_lock); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | /* Print non-responding cpus */ | ||
277 | static void uv_nmi_nr_cpus_pr(char *fmt) | ||
278 | { | ||
279 | static char cpu_list[1024]; | ||
280 | int len = sizeof(cpu_list); | ||
281 | int c = cpumask_weight(uv_nmi_cpu_mask); | ||
282 | int n = cpulist_scnprintf(cpu_list, len, uv_nmi_cpu_mask); | ||
283 | |||
284 | if (n >= len-1) | ||
285 | strcpy(&cpu_list[len - 6], "...\n"); | ||
286 | |||
287 | printk(fmt, c, cpu_list); | ||
288 | } | ||
289 | |||
290 | /* Ping non-responding cpus attemping to force them into the NMI handler */ | ||
291 | static void uv_nmi_nr_cpus_ping(void) | ||
292 | { | ||
293 | int cpu; | ||
294 | |||
295 | for_each_cpu(cpu, uv_nmi_cpu_mask) | ||
296 | atomic_set(&uv_cpu_nmi_per(cpu).pinging, 1); | ||
297 | |||
298 | apic->send_IPI_mask(uv_nmi_cpu_mask, APIC_DM_NMI); | ||
299 | } | ||
300 | |||
301 | /* Clean up flags for cpus that ignored both NMI and ping */ | ||
302 | static void uv_nmi_cleanup_mask(void) | ||
303 | { | ||
304 | int cpu; | ||
305 | |||
306 | for_each_cpu(cpu, uv_nmi_cpu_mask) { | ||
307 | atomic_set(&uv_cpu_nmi_per(cpu).pinging, 0); | ||
308 | atomic_set(&uv_cpu_nmi_per(cpu).state, UV_NMI_STATE_OUT); | ||
309 | cpumask_clear_cpu(cpu, uv_nmi_cpu_mask); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | /* Loop waiting as cpus enter nmi handler */ | ||
314 | static int uv_nmi_wait_cpus(int first) | ||
315 | { | ||
316 | int i, j, k, n = num_online_cpus(); | ||
317 | int last_k = 0, waiting = 0; | ||
318 | |||
319 | if (first) { | ||
320 | cpumask_copy(uv_nmi_cpu_mask, cpu_online_mask); | ||
321 | k = 0; | ||
322 | } else { | ||
323 | k = n - cpumask_weight(uv_nmi_cpu_mask); | ||
324 | } | ||
325 | |||
326 | udelay(uv_nmi_initial_delay); | ||
327 | for (i = 0; i < uv_nmi_retry_count; i++) { | ||
328 | int loop_delay = uv_nmi_loop_delay; | ||
329 | |||
330 | for_each_cpu(j, uv_nmi_cpu_mask) { | ||
331 | if (atomic_read(&uv_cpu_nmi_per(j).state)) { | ||
332 | cpumask_clear_cpu(j, uv_nmi_cpu_mask); | ||
333 | if (++k >= n) | ||
334 | break; | ||
335 | } | ||
336 | } | ||
337 | if (k >= n) { /* all in? */ | ||
338 | k = n; | ||
339 | break; | ||
340 | } | ||
341 | if (last_k != k) { /* abort if no new cpus coming in */ | ||
342 | last_k = k; | ||
343 | waiting = 0; | ||
344 | } else if (++waiting > uv_nmi_wait_count) | ||
345 | break; | ||
346 | |||
347 | /* extend delay if waiting only for cpu 0 */ | ||
348 | if (waiting && (n - k) == 1 && | ||
349 | cpumask_test_cpu(0, uv_nmi_cpu_mask)) | ||
350 | loop_delay *= 100; | ||
351 | |||
352 | udelay(loop_delay); | ||
353 | } | ||
354 | atomic_set(&uv_nmi_cpus_in_nmi, k); | ||
355 | return n - k; | ||
356 | } | ||
357 | |||
358 | /* Wait until all slave cpus have entered UV NMI handler */ | ||
359 | static void uv_nmi_wait(int master) | ||
360 | { | ||
361 | /* indicate this cpu is in */ | ||
362 | atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_IN); | ||
363 | |||
364 | /* if not the first cpu in (the master), then we are a slave cpu */ | ||
365 | if (!master) | ||
366 | return; | ||
367 | |||
368 | do { | ||
369 | /* wait for all other cpus to gather here */ | ||
370 | if (!uv_nmi_wait_cpus(1)) | ||
371 | break; | ||
372 | |||
373 | /* if not all made it in, send IPI NMI to them */ | ||
374 | uv_nmi_nr_cpus_pr(KERN_ALERT | ||
375 | "UV: Sending NMI IPI to %d non-responding CPUs: %s\n"); | ||
376 | uv_nmi_nr_cpus_ping(); | ||
377 | |||
378 | /* if all cpus are in, then done */ | ||
379 | if (!uv_nmi_wait_cpus(0)) | ||
380 | break; | ||
381 | |||
382 | uv_nmi_nr_cpus_pr(KERN_ALERT | ||
383 | "UV: %d CPUs not in NMI loop: %s\n"); | ||
384 | } while (0); | ||
385 | |||
386 | pr_alert("UV: %d of %d CPUs in NMI\n", | ||
387 | atomic_read(&uv_nmi_cpus_in_nmi), num_online_cpus()); | ||
388 | } | ||
389 | |||
390 | static void uv_nmi_dump_cpu_ip_hdr(void) | ||
391 | { | ||
392 | printk(KERN_DEFAULT | ||
393 | "\nUV: %4s %6s %-32s %s (Note: PID 0 not listed)\n", | ||
394 | "CPU", "PID", "COMMAND", "IP"); | ||
395 | } | ||
396 | |||
397 | static void uv_nmi_dump_cpu_ip(int cpu, struct pt_regs *regs) | ||
398 | { | ||
399 | printk(KERN_DEFAULT "UV: %4d %6d %-32.32s ", | ||
400 | cpu, current->pid, current->comm); | ||
401 | |||
402 | printk_address(regs->ip, 1); | ||
403 | } | ||
404 | |||
405 | /* Dump this cpu's state */ | ||
406 | static void uv_nmi_dump_state_cpu(int cpu, struct pt_regs *regs) | ||
407 | { | ||
408 | const char *dots = " ................................. "; | ||
409 | |||
410 | if (uv_nmi_action_is("ips")) { | ||
411 | if (cpu == 0) | ||
412 | uv_nmi_dump_cpu_ip_hdr(); | ||
413 | |||
414 | if (current->pid != 0) | ||
415 | uv_nmi_dump_cpu_ip(cpu, regs); | ||
416 | |||
417 | } else if (uv_nmi_action_is("dump")) { | ||
418 | printk(KERN_DEFAULT | ||
419 | "UV:%sNMI process trace for CPU %d\n", dots, cpu); | ||
420 | show_regs(regs); | ||
421 | } | ||
422 | atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_DUMP_DONE); | ||
423 | } | ||
424 | |||
425 | /* Trigger a slave cpu to dump it's state */ | ||
426 | static void uv_nmi_trigger_dump(int cpu) | ||
427 | { | ||
428 | int retry = uv_nmi_trigger_delay; | ||
429 | |||
430 | if (atomic_read(&uv_cpu_nmi_per(cpu).state) != UV_NMI_STATE_IN) | ||
431 | return; | ||
432 | |||
433 | atomic_set(&uv_cpu_nmi_per(cpu).state, UV_NMI_STATE_DUMP); | ||
434 | do { | ||
435 | cpu_relax(); | ||
436 | udelay(10); | ||
437 | if (atomic_read(&uv_cpu_nmi_per(cpu).state) | ||
438 | != UV_NMI_STATE_DUMP) | ||
439 | return; | ||
440 | } while (--retry > 0); | ||
441 | |||
442 | pr_crit("UV: CPU %d stuck in process dump function\n", cpu); | ||
443 | atomic_set(&uv_cpu_nmi_per(cpu).state, UV_NMI_STATE_DUMP_DONE); | ||
444 | } | ||
445 | |||
446 | /* Wait until all cpus ready to exit */ | ||
447 | static void uv_nmi_sync_exit(int master) | ||
448 | { | ||
449 | atomic_dec(&uv_nmi_cpus_in_nmi); | ||
450 | if (master) { | ||
451 | while (atomic_read(&uv_nmi_cpus_in_nmi) > 0) | ||
452 | cpu_relax(); | ||
453 | atomic_set(&uv_nmi_slave_continue, SLAVE_CLEAR); | ||
454 | } else { | ||
455 | while (atomic_read(&uv_nmi_slave_continue)) | ||
456 | cpu_relax(); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | /* Walk through cpu list and dump state of each */ | ||
461 | static void uv_nmi_dump_state(int cpu, struct pt_regs *regs, int master) | ||
462 | { | ||
463 | if (master) { | ||
464 | int tcpu; | ||
465 | int ignored = 0; | ||
466 | int saved_console_loglevel = console_loglevel; | ||
467 | |||
468 | pr_alert("UV: tracing %s for %d CPUs from CPU %d\n", | ||
469 | uv_nmi_action_is("ips") ? "IPs" : "processes", | ||
470 | atomic_read(&uv_nmi_cpus_in_nmi), cpu); | ||
471 | |||
472 | console_loglevel = uv_nmi_loglevel; | ||
473 | atomic_set(&uv_nmi_slave_continue, SLAVE_EXIT); | ||
474 | for_each_online_cpu(tcpu) { | ||
475 | if (cpumask_test_cpu(tcpu, uv_nmi_cpu_mask)) | ||
476 | ignored++; | ||
477 | else if (tcpu == cpu) | ||
478 | uv_nmi_dump_state_cpu(tcpu, regs); | ||
479 | else | ||
480 | uv_nmi_trigger_dump(tcpu); | ||
481 | } | ||
482 | if (ignored) | ||
483 | printk(KERN_DEFAULT "UV: %d CPUs ignored NMI\n", | ||
484 | ignored); | ||
485 | |||
486 | console_loglevel = saved_console_loglevel; | ||
487 | pr_alert("UV: process trace complete\n"); | ||
488 | } else { | ||
489 | while (!atomic_read(&uv_nmi_slave_continue)) | ||
490 | cpu_relax(); | ||
491 | while (atomic_read(&uv_cpu_nmi.state) != UV_NMI_STATE_DUMP) | ||
492 | cpu_relax(); | ||
493 | uv_nmi_dump_state_cpu(cpu, regs); | ||
494 | } | ||
495 | uv_nmi_sync_exit(master); | ||
496 | } | ||
497 | |||
498 | static void uv_nmi_touch_watchdogs(void) | ||
499 | { | ||
500 | touch_softlockup_watchdog_sync(); | ||
501 | clocksource_touch_watchdog(); | ||
502 | rcu_cpu_stall_reset(); | ||
503 | touch_nmi_watchdog(); | ||
504 | } | ||
505 | |||
506 | #if defined(CONFIG_KEXEC) | ||
507 | static void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs) | ||
508 | { | ||
509 | /* Call crash to dump system state */ | ||
510 | if (master) { | ||
511 | pr_emerg("UV: NMI executing crash_kexec on CPU%d\n", cpu); | ||
512 | crash_kexec(regs); | ||
513 | |||
514 | pr_emerg("UV: crash_kexec unexpectedly returned, "); | ||
515 | if (!kexec_crash_image) { | ||
516 | pr_cont("crash kernel not loaded\n"); | ||
517 | atomic_set(&uv_nmi_kexec_failed, 1); | ||
518 | uv_nmi_sync_exit(1); | ||
519 | return; | ||
520 | } | ||
521 | pr_cont("kexec busy, stalling cpus while waiting\n"); | ||
522 | } | ||
523 | |||
524 | /* If crash exec fails the slaves should return, otherwise stall */ | ||
525 | while (atomic_read(&uv_nmi_kexec_failed) == 0) | ||
526 | mdelay(10); | ||
527 | |||
528 | /* Crash kernel most likely not loaded, return in an orderly fashion */ | ||
529 | uv_nmi_sync_exit(0); | ||
530 | } | ||
531 | |||
532 | #else /* !CONFIG_KEXEC */ | ||
533 | static inline void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs) | ||
534 | { | ||
535 | if (master) | ||
536 | pr_err("UV: NMI kdump: KEXEC not supported in this kernel\n"); | ||
537 | } | ||
538 | #endif /* !CONFIG_KEXEC */ | ||
539 | |||
540 | #ifdef CONFIG_KGDB_KDB | ||
541 | /* Call KDB from NMI handler */ | ||
542 | static void uv_call_kdb(int cpu, struct pt_regs *regs, int master) | ||
543 | { | ||
544 | int ret; | ||
545 | |||
546 | if (master) { | ||
547 | /* call KGDB NMI handler as MASTER */ | ||
548 | ret = kgdb_nmicallin(cpu, X86_TRAP_NMI, regs, | ||
549 | &uv_nmi_slave_continue); | ||
550 | if (ret) { | ||
551 | pr_alert("KDB returned error, is kgdboc set?\n"); | ||
552 | atomic_set(&uv_nmi_slave_continue, SLAVE_EXIT); | ||
553 | } | ||
554 | } else { | ||
555 | /* wait for KGDB signal that it's ready for slaves to enter */ | ||
556 | int sig; | ||
557 | |||
558 | do { | ||
559 | cpu_relax(); | ||
560 | sig = atomic_read(&uv_nmi_slave_continue); | ||
561 | } while (!sig); | ||
562 | |||
563 | /* call KGDB as slave */ | ||
564 | if (sig == SLAVE_CONTINUE) | ||
565 | kgdb_nmicallback(cpu, regs); | ||
566 | } | ||
567 | uv_nmi_sync_exit(master); | ||
568 | } | ||
569 | |||
570 | #else /* !CONFIG_KGDB_KDB */ | ||
571 | static inline void uv_call_kdb(int cpu, struct pt_regs *regs, int master) | ||
572 | { | ||
573 | pr_err("UV: NMI error: KGDB/KDB is not enabled in this kernel\n"); | ||
574 | } | ||
575 | #endif /* !CONFIG_KGDB_KDB */ | ||
576 | |||
577 | /* | ||
578 | * UV NMI handler | ||
579 | */ | ||
580 | int uv_handle_nmi(unsigned int reason, struct pt_regs *regs) | ||
581 | { | ||
582 | struct uv_hub_nmi_s *hub_nmi = uv_hub_nmi; | ||
583 | int cpu = smp_processor_id(); | ||
584 | int master = 0; | ||
585 | unsigned long flags; | ||
586 | |||
587 | local_irq_save(flags); | ||
588 | |||
589 | /* If not a UV System NMI, ignore */ | ||
590 | if (!atomic_read(&uv_cpu_nmi.pinging) && !uv_check_nmi(hub_nmi)) { | ||
591 | local_irq_restore(flags); | ||
592 | return NMI_DONE; | ||
593 | } | ||
594 | |||
595 | /* Indicate we are the first CPU into the NMI handler */ | ||
596 | master = (atomic_read(&uv_nmi_cpu) == cpu); | ||
597 | |||
598 | /* If NMI action is "kdump", then attempt to do it */ | ||
599 | if (uv_nmi_action_is("kdump")) | ||
600 | uv_nmi_kdump(cpu, master, regs); | ||
601 | |||
602 | /* Pause as all cpus enter the NMI handler */ | ||
603 | uv_nmi_wait(master); | ||
604 | |||
605 | /* Dump state of each cpu */ | ||
606 | if (uv_nmi_action_is("ips") || uv_nmi_action_is("dump")) | ||
607 | uv_nmi_dump_state(cpu, regs, master); | ||
608 | |||
609 | /* Call KDB if enabled */ | ||
610 | else if (uv_nmi_action_is("kdb")) | ||
611 | uv_call_kdb(cpu, regs, master); | ||
612 | |||
613 | /* Clear per_cpu "in nmi" flag */ | ||
614 | atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_OUT); | ||
615 | |||
616 | /* Clear MMR NMI flag on each hub */ | ||
617 | uv_clear_nmi(cpu); | ||
618 | |||
619 | /* Clear global flags */ | ||
620 | if (master) { | ||
621 | if (cpumask_weight(uv_nmi_cpu_mask)) | ||
622 | uv_nmi_cleanup_mask(); | ||
623 | atomic_set(&uv_nmi_cpus_in_nmi, -1); | ||
624 | atomic_set(&uv_nmi_cpu, -1); | ||
625 | atomic_set(&uv_in_nmi, 0); | ||
626 | } | ||
627 | |||
628 | uv_nmi_touch_watchdogs(); | ||
629 | local_irq_restore(flags); | ||
630 | |||
631 | return NMI_HANDLED; | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * NMI handler for pulling in CPUs when perf events are grabbing our NMI | ||
636 | */ | ||
637 | int uv_handle_nmi_ping(unsigned int reason, struct pt_regs *regs) | ||
638 | { | ||
639 | int ret; | ||
640 | |||
641 | uv_cpu_nmi.queries++; | ||
642 | if (!atomic_read(&uv_cpu_nmi.pinging)) { | ||
643 | local64_inc(&uv_nmi_ping_misses); | ||
644 | return NMI_DONE; | ||
645 | } | ||
646 | |||
647 | uv_cpu_nmi.pings++; | ||
648 | local64_inc(&uv_nmi_ping_count); | ||
649 | ret = uv_handle_nmi(reason, regs); | ||
650 | atomic_set(&uv_cpu_nmi.pinging, 0); | ||
651 | return ret; | ||
652 | } | ||
653 | |||
654 | void uv_register_nmi_notifier(void) | ||
655 | { | ||
656 | if (register_nmi_handler(NMI_UNKNOWN, uv_handle_nmi, 0, "uv")) | ||
657 | pr_warn("UV: NMI handler failed to register\n"); | ||
658 | |||
659 | if (register_nmi_handler(NMI_LOCAL, uv_handle_nmi_ping, 0, "uvping")) | ||
660 | pr_warn("UV: PING NMI handler failed to register\n"); | ||
661 | } | ||
662 | |||
663 | void uv_nmi_init(void) | ||
664 | { | ||
665 | unsigned int value; | ||
666 | |||
667 | /* | ||
668 | * Unmask NMI on all cpus | ||
669 | */ | ||
670 | value = apic_read(APIC_LVT1) | APIC_DM_NMI; | ||
671 | value &= ~APIC_LVT_MASKED; | ||
672 | apic_write(APIC_LVT1, value); | ||
673 | } | ||
674 | |||
675 | void uv_nmi_setup(void) | ||
676 | { | ||
677 | int size = sizeof(void *) * (1 << NODES_SHIFT); | ||
678 | int cpu, nid; | ||
679 | |||
680 | /* Setup hub nmi info */ | ||
681 | uv_nmi_setup_mmrs(); | ||
682 | uv_hub_nmi_list = kzalloc(size, GFP_KERNEL); | ||
683 | pr_info("UV: NMI hub list @ 0x%p (%d)\n", uv_hub_nmi_list, size); | ||
684 | BUG_ON(!uv_hub_nmi_list); | ||
685 | size = sizeof(struct uv_hub_nmi_s); | ||
686 | for_each_present_cpu(cpu) { | ||
687 | nid = cpu_to_node(cpu); | ||
688 | if (uv_hub_nmi_list[nid] == NULL) { | ||
689 | uv_hub_nmi_list[nid] = kzalloc_node(size, | ||
690 | GFP_KERNEL, nid); | ||
691 | BUG_ON(!uv_hub_nmi_list[nid]); | ||
692 | raw_spin_lock_init(&(uv_hub_nmi_list[nid]->nmi_lock)); | ||
693 | atomic_set(&uv_hub_nmi_list[nid]->cpu_owner, -1); | ||
694 | } | ||
695 | uv_hub_nmi_per(cpu) = uv_hub_nmi_list[nid]; | ||
696 | } | ||
697 | BUG_ON(!alloc_cpumask_var(&uv_nmi_cpu_mask, GFP_KERNEL)); | ||
698 | } | ||
699 | |||
700 | |||