diff options
| -rw-r--r-- | arch/x86/include/asm/uv/uv.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/uv/uv_hub.h | 57 | ||||
| -rw-r--r-- | arch/x86/include/asm/uv/uv_mmrs.h | 31 | ||||
| -rw-r--r-- | arch/x86/kernel/apic/x2apic_uv_x.c | 70 | ||||
| -rw-r--r-- | arch/x86/platform/uv/Makefile | 2 | ||||
| -rw-r--r-- | arch/x86/platform/uv/uv_nmi.c | 700 | ||||
| -rw-r--r-- | include/linux/kdb.h | 1 | ||||
| -rw-r--r-- | include/linux/kgdb.h | 1 | ||||
| -rw-r--r-- | kernel/debug/debug_core.c | 32 | ||||
| -rw-r--r-- | kernel/debug/debug_core.h | 3 | ||||
| -rw-r--r-- | kernel/debug/kdb/kdb_debugger.c | 5 | ||||
| -rw-r--r-- | kernel/debug/kdb/kdb_main.c | 3 |
12 files changed, 832 insertions, 75 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/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index 2c32df95bb78..a30836c8ac4d 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h | |||
| @@ -502,8 +502,8 @@ struct uv_blade_info { | |||
| 502 | unsigned short nr_online_cpus; | 502 | unsigned short nr_online_cpus; |
| 503 | unsigned short pnode; | 503 | unsigned short pnode; |
| 504 | short memory_nid; | 504 | short memory_nid; |
| 505 | spinlock_t nmi_lock; | 505 | spinlock_t nmi_lock; /* obsolete, see uv_hub_nmi */ |
| 506 | unsigned long nmi_count; | 506 | unsigned long nmi_count; /* obsolete, see uv_hub_nmi */ |
| 507 | }; | 507 | }; |
| 508 | extern struct uv_blade_info *uv_blade_info; | 508 | extern struct uv_blade_info *uv_blade_info; |
| 509 | extern short *uv_node_to_blade; | 509 | extern short *uv_node_to_blade; |
| @@ -576,6 +576,59 @@ static inline int uv_num_possible_blades(void) | |||
| 576 | return uv_possible_blades; | 576 | return uv_possible_blades; |
| 577 | } | 577 | } |
| 578 | 578 | ||
| 579 | /* Per Hub NMI support */ | ||
| 580 | extern void uv_nmi_setup(void); | ||
| 581 | |||
| 582 | /* BMC sets a bit this MMR non-zero before sending an NMI */ | ||
| 583 | #define UVH_NMI_MMR UVH_SCRATCH5 | ||
| 584 | #define UVH_NMI_MMR_CLEAR UVH_SCRATCH5_ALIAS | ||
| 585 | #define UVH_NMI_MMR_SHIFT 63 | ||
| 586 | #define UVH_NMI_MMR_TYPE "SCRATCH5" | ||
| 587 | |||
| 588 | /* Newer SMM NMI handler, not present in all systems */ | ||
| 589 | #define UVH_NMI_MMRX UVH_EVENT_OCCURRED0 | ||
| 590 | #define UVH_NMI_MMRX_CLEAR UVH_EVENT_OCCURRED0_ALIAS | ||
| 591 | #define UVH_NMI_MMRX_SHIFT (is_uv1_hub() ? \ | ||
| 592 | UV1H_EVENT_OCCURRED0_EXTIO_INT0_SHFT :\ | ||
| 593 | UVXH_EVENT_OCCURRED0_EXTIO_INT0_SHFT) | ||
| 594 | #define UVH_NMI_MMRX_TYPE "EXTIO_INT0" | ||
| 595 | |||
| 596 | /* Non-zero indicates newer SMM NMI handler present */ | ||
| 597 | #define UVH_NMI_MMRX_SUPPORTED UVH_EXTIO_INT0_BROADCAST | ||
| 598 | |||
| 599 | /* Indicates to BIOS that we want to use the newer SMM NMI handler */ | ||
| 600 | #define UVH_NMI_MMRX_REQ UVH_SCRATCH5_ALIAS_2 | ||
| 601 | #define UVH_NMI_MMRX_REQ_SHIFT 62 | ||
| 602 | |||
| 603 | struct uv_hub_nmi_s { | ||
| 604 | raw_spinlock_t nmi_lock; | ||
| 605 | atomic_t in_nmi; /* flag this node in UV NMI IRQ */ | ||
| 606 | atomic_t cpu_owner; /* last locker of this struct */ | ||
| 607 | atomic_t read_mmr_count; /* count of MMR reads */ | ||
| 608 | atomic_t nmi_count; /* count of true UV NMIs */ | ||
| 609 | unsigned long nmi_value; /* last value read from NMI MMR */ | ||
| 610 | }; | ||
| 611 | |||
| 612 | struct uv_cpu_nmi_s { | ||
| 613 | struct uv_hub_nmi_s *hub; | ||
| 614 | atomic_t state; | ||
| 615 | atomic_t pinging; | ||
| 616 | int queries; | ||
| 617 | int pings; | ||
| 618 | }; | ||
| 619 | |||
| 620 | DECLARE_PER_CPU(struct uv_cpu_nmi_s, __uv_cpu_nmi); | ||
| 621 | #define uv_cpu_nmi (__get_cpu_var(__uv_cpu_nmi)) | ||
| 622 | #define uv_hub_nmi (uv_cpu_nmi.hub) | ||
| 623 | #define uv_cpu_nmi_per(cpu) (per_cpu(__uv_cpu_nmi, cpu)) | ||
| 624 | #define uv_hub_nmi_per(cpu) (uv_cpu_nmi_per(cpu).hub) | ||
| 625 | |||
| 626 | /* uv_cpu_nmi_states */ | ||
| 627 | #define UV_NMI_STATE_OUT 0 | ||
| 628 | #define UV_NMI_STATE_IN 1 | ||
| 629 | #define UV_NMI_STATE_DUMP 2 | ||
| 630 | #define UV_NMI_STATE_DUMP_DONE 3 | ||
| 631 | |||
| 579 | /* Update SCIR state */ | 632 | /* Update SCIR state */ |
| 580 | static inline void uv_set_scir_bits(unsigned char value) | 633 | static inline void uv_set_scir_bits(unsigned char value) |
| 581 | { | 634 | { |
diff --git a/arch/x86/include/asm/uv/uv_mmrs.h b/arch/x86/include/asm/uv/uv_mmrs.h index bd5f80e58a23..e42249bcf7e1 100644 --- a/arch/x86/include/asm/uv/uv_mmrs.h +++ b/arch/x86/include/asm/uv/uv_mmrs.h | |||
| @@ -461,6 +461,23 @@ union uvh_event_occurred0_u { | |||
| 461 | 461 | ||
| 462 | 462 | ||
| 463 | /* ========================================================================= */ | 463 | /* ========================================================================= */ |
| 464 | /* UVH_EXTIO_INT0_BROADCAST */ | ||
| 465 | /* ========================================================================= */ | ||
| 466 | #define UVH_EXTIO_INT0_BROADCAST 0x61448UL | ||
| 467 | #define UVH_EXTIO_INT0_BROADCAST_32 0x3f0 | ||
| 468 | |||
| 469 | #define UVH_EXTIO_INT0_BROADCAST_ENABLE_SHFT 0 | ||
| 470 | #define UVH_EXTIO_INT0_BROADCAST_ENABLE_MASK 0x0000000000000001UL | ||
| 471 | |||
| 472 | union uvh_extio_int0_broadcast_u { | ||
| 473 | unsigned long v; | ||
| 474 | struct uvh_extio_int0_broadcast_s { | ||
| 475 | unsigned long enable:1; /* RW */ | ||
| 476 | unsigned long rsvd_1_63:63; | ||
| 477 | } s; | ||
| 478 | }; | ||
| 479 | |||
| 480 | /* ========================================================================= */ | ||
| 464 | /* UVH_GR0_TLB_INT0_CONFIG */ | 481 | /* UVH_GR0_TLB_INT0_CONFIG */ |
| 465 | /* ========================================================================= */ | 482 | /* ========================================================================= */ |
| 466 | #define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL | 483 | #define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL |
| @@ -2606,6 +2623,20 @@ union uvh_scratch5_u { | |||
| 2606 | }; | 2623 | }; |
| 2607 | 2624 | ||
| 2608 | /* ========================================================================= */ | 2625 | /* ========================================================================= */ |
| 2626 | /* UVH_SCRATCH5_ALIAS */ | ||
| 2627 | /* ========================================================================= */ | ||
| 2628 | #define UVH_SCRATCH5_ALIAS 0x2d0208UL | ||
| 2629 | #define UVH_SCRATCH5_ALIAS_32 0x780 | ||
| 2630 | |||
| 2631 | |||
| 2632 | /* ========================================================================= */ | ||
| 2633 | /* UVH_SCRATCH5_ALIAS_2 */ | ||
| 2634 | /* ========================================================================= */ | ||
| 2635 | #define UVH_SCRATCH5_ALIAS_2 0x2d0210UL | ||
| 2636 | #define UVH_SCRATCH5_ALIAS_2_32 0x788 | ||
| 2637 | |||
| 2638 | |||
| 2639 | /* ========================================================================= */ | ||
| 2609 | /* UVXH_EVENT_OCCURRED2 */ | 2640 | /* UVXH_EVENT_OCCURRED2 */ |
| 2610 | /* ========================================================================= */ | 2641 | /* ========================================================================= */ |
| 2611 | #define UVXH_EVENT_OCCURRED2 0x70100UL | 2642 | #define UVXH_EVENT_OCCURRED2 0x70100UL |
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index a419814cea57..ad0dc0428baf 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; |
| @@ -1046,6 +977,7 @@ void __init uv_system_init(void) | |||
| 1046 | map_mmr_high(max_pnode); | 977 | map_mmr_high(max_pnode); |
| 1047 | map_mmioh_high(min_pnode, max_pnode); | 978 | map_mmioh_high(min_pnode, max_pnode); |
| 1048 | 979 | ||
| 980 | uv_nmi_setup(); | ||
| 1049 | uv_cpu_init(); | 981 | uv_cpu_init(); |
| 1050 | uv_scir_register_cpu_notifier(); | 982 | uv_scir_register_cpu_notifier(); |
| 1051 | uv_register_nmi_notifier(); | 983 | uv_register_nmi_notifier(); |
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 | |||
diff --git a/include/linux/kdb.h b/include/linux/kdb.h index 7f6fe6e015bc..290db1269c4c 100644 --- a/include/linux/kdb.h +++ b/include/linux/kdb.h | |||
| @@ -109,6 +109,7 @@ typedef enum { | |||
| 109 | KDB_REASON_RECURSE, /* Recursive entry to kdb; | 109 | KDB_REASON_RECURSE, /* Recursive entry to kdb; |
| 110 | * regs probably valid */ | 110 | * regs probably valid */ |
| 111 | KDB_REASON_SSTEP, /* Single Step trap. - regs valid */ | 111 | KDB_REASON_SSTEP, /* Single Step trap. - regs valid */ |
| 112 | KDB_REASON_SYSTEM_NMI, /* In NMI due to SYSTEM cmd; regs valid */ | ||
| 112 | } kdb_reason_t; | 113 | } kdb_reason_t; |
| 113 | 114 | ||
| 114 | extern int kdb_trap_printk; | 115 | extern int kdb_trap_printk; |
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index c6e091bf39a5..dfb4f2ffdaa2 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h | |||
| @@ -310,6 +310,7 @@ extern int | |||
| 310 | kgdb_handle_exception(int ex_vector, int signo, int err_code, | 310 | kgdb_handle_exception(int ex_vector, int signo, int err_code, |
| 311 | struct pt_regs *regs); | 311 | struct pt_regs *regs); |
| 312 | extern int kgdb_nmicallback(int cpu, void *regs); | 312 | extern int kgdb_nmicallback(int cpu, void *regs); |
| 313 | extern int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *snd_rdy); | ||
| 313 | extern void gdbstub_exit(int status); | 314 | extern void gdbstub_exit(int status); |
| 314 | 315 | ||
| 315 | extern int kgdb_single_step; | 316 | extern int kgdb_single_step; |
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 0506d447aed2..7d2f35e5df2f 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
| @@ -575,8 +575,12 @@ return_normal: | |||
| 575 | raw_spin_lock(&dbg_slave_lock); | 575 | raw_spin_lock(&dbg_slave_lock); |
| 576 | 576 | ||
| 577 | #ifdef CONFIG_SMP | 577 | #ifdef CONFIG_SMP |
| 578 | /* If send_ready set, slaves are already waiting */ | ||
| 579 | if (ks->send_ready) | ||
| 580 | atomic_set(ks->send_ready, 1); | ||
| 581 | |||
| 578 | /* Signal the other CPUs to enter kgdb_wait() */ | 582 | /* Signal the other CPUs to enter kgdb_wait() */ |
| 579 | if ((!kgdb_single_step) && kgdb_do_roundup) | 583 | else if ((!kgdb_single_step) && kgdb_do_roundup) |
| 580 | kgdb_roundup_cpus(flags); | 584 | kgdb_roundup_cpus(flags); |
| 581 | #endif | 585 | #endif |
| 582 | 586 | ||
| @@ -678,11 +682,11 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |||
| 678 | if (arch_kgdb_ops.enable_nmi) | 682 | if (arch_kgdb_ops.enable_nmi) |
| 679 | arch_kgdb_ops.enable_nmi(0); | 683 | arch_kgdb_ops.enable_nmi(0); |
| 680 | 684 | ||
| 685 | memset(ks, 0, sizeof(struct kgdb_state)); | ||
| 681 | ks->cpu = raw_smp_processor_id(); | 686 | ks->cpu = raw_smp_processor_id(); |
| 682 | ks->ex_vector = evector; | 687 | ks->ex_vector = evector; |
| 683 | ks->signo = signo; | 688 | ks->signo = signo; |
| 684 | ks->err_code = ecode; | 689 | ks->err_code = ecode; |
| 685 | ks->kgdb_usethreadid = 0; | ||
| 686 | ks->linux_regs = regs; | 690 | ks->linux_regs = regs; |
| 687 | 691 | ||
| 688 | if (kgdb_reenter_check(ks)) | 692 | if (kgdb_reenter_check(ks)) |
| @@ -732,6 +736,30 @@ int kgdb_nmicallback(int cpu, void *regs) | |||
| 732 | return 1; | 736 | return 1; |
| 733 | } | 737 | } |
| 734 | 738 | ||
| 739 | int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *send_ready) | ||
| 740 | { | ||
| 741 | #ifdef CONFIG_SMP | ||
| 742 | if (!kgdb_io_ready(0) || !send_ready) | ||
| 743 | return 1; | ||
| 744 | |||
| 745 | if (kgdb_info[cpu].enter_kgdb == 0) { | ||
| 746 | struct kgdb_state kgdb_var; | ||
| 747 | struct kgdb_state *ks = &kgdb_var; | ||
| 748 | |||
| 749 | memset(ks, 0, sizeof(struct kgdb_state)); | ||
| 750 | ks->cpu = cpu; | ||
| 751 | ks->ex_vector = trapnr; | ||
| 752 | ks->signo = SIGTRAP; | ||
| 753 | ks->err_code = KGDB_KDB_REASON_SYSTEM_NMI; | ||
| 754 | ks->linux_regs = regs; | ||
| 755 | ks->send_ready = send_ready; | ||
| 756 | kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER); | ||
| 757 | return 0; | ||
| 758 | } | ||
| 759 | #endif | ||
| 760 | return 1; | ||
| 761 | } | ||
| 762 | |||
| 735 | static void kgdb_console_write(struct console *co, const char *s, | 763 | static void kgdb_console_write(struct console *co, const char *s, |
| 736 | unsigned count) | 764 | unsigned count) |
| 737 | { | 765 | { |
diff --git a/kernel/debug/debug_core.h b/kernel/debug/debug_core.h index 2235967e78b0..572aa4f5677c 100644 --- a/kernel/debug/debug_core.h +++ b/kernel/debug/debug_core.h | |||
| @@ -26,6 +26,7 @@ struct kgdb_state { | |||
| 26 | unsigned long threadid; | 26 | unsigned long threadid; |
| 27 | long kgdb_usethreadid; | 27 | long kgdb_usethreadid; |
| 28 | struct pt_regs *linux_regs; | 28 | struct pt_regs *linux_regs; |
| 29 | atomic_t *send_ready; | ||
| 29 | }; | 30 | }; |
| 30 | 31 | ||
| 31 | /* Exception state values */ | 32 | /* Exception state values */ |
| @@ -74,11 +75,13 @@ extern int kdb_stub(struct kgdb_state *ks); | |||
| 74 | extern int kdb_parse(const char *cmdstr); | 75 | extern int kdb_parse(const char *cmdstr); |
| 75 | extern int kdb_common_init_state(struct kgdb_state *ks); | 76 | extern int kdb_common_init_state(struct kgdb_state *ks); |
| 76 | extern int kdb_common_deinit_state(void); | 77 | extern int kdb_common_deinit_state(void); |
| 78 | #define KGDB_KDB_REASON_SYSTEM_NMI KDB_REASON_SYSTEM_NMI | ||
| 77 | #else /* ! CONFIG_KGDB_KDB */ | 79 | #else /* ! CONFIG_KGDB_KDB */ |
| 78 | static inline int kdb_stub(struct kgdb_state *ks) | 80 | static inline int kdb_stub(struct kgdb_state *ks) |
| 79 | { | 81 | { |
| 80 | return DBG_PASS_EVENT; | 82 | return DBG_PASS_EVENT; |
| 81 | } | 83 | } |
| 84 | #define KGDB_KDB_REASON_SYSTEM_NMI 0 | ||
| 82 | #endif /* CONFIG_KGDB_KDB */ | 85 | #endif /* CONFIG_KGDB_KDB */ |
| 83 | 86 | ||
| 84 | #endif /* _DEBUG_CORE_H_ */ | 87 | #endif /* _DEBUG_CORE_H_ */ |
diff --git a/kernel/debug/kdb/kdb_debugger.c b/kernel/debug/kdb/kdb_debugger.c index 328d18ef31e4..8859ca34dcfe 100644 --- a/kernel/debug/kdb/kdb_debugger.c +++ b/kernel/debug/kdb/kdb_debugger.c | |||
| @@ -69,7 +69,10 @@ int kdb_stub(struct kgdb_state *ks) | |||
| 69 | if (atomic_read(&kgdb_setting_breakpoint)) | 69 | if (atomic_read(&kgdb_setting_breakpoint)) |
| 70 | reason = KDB_REASON_KEYBOARD; | 70 | reason = KDB_REASON_KEYBOARD; |
| 71 | 71 | ||
| 72 | if (in_nmi()) | 72 | if (ks->err_code == KDB_REASON_SYSTEM_NMI && ks->signo == SIGTRAP) |
| 73 | reason = KDB_REASON_SYSTEM_NMI; | ||
| 74 | |||
| 75 | else if (in_nmi()) | ||
| 73 | reason = KDB_REASON_NMI; | 76 | reason = KDB_REASON_NMI; |
| 74 | 77 | ||
| 75 | for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) { | 78 | for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) { |
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 00eb8f7fbf41..0b097c8a1e50 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c | |||
| @@ -1200,6 +1200,9 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs, | |||
| 1200 | instruction_pointer(regs)); | 1200 | instruction_pointer(regs)); |
| 1201 | kdb_dumpregs(regs); | 1201 | kdb_dumpregs(regs); |
| 1202 | break; | 1202 | break; |
| 1203 | case KDB_REASON_SYSTEM_NMI: | ||
| 1204 | kdb_printf("due to System NonMaskable Interrupt\n"); | ||
| 1205 | break; | ||
| 1203 | case KDB_REASON_NMI: | 1206 | case KDB_REASON_NMI: |
| 1204 | kdb_printf("due to NonMaskable Interrupt @ " | 1207 | kdb_printf("due to NonMaskable Interrupt @ " |
| 1205 | kdb_machreg_fmt "\n", | 1208 | kdb_machreg_fmt "\n", |
