[PATCH 9/9] x86/UV: Add ability to disable UV NMI handler

From: Mike Travis
Date: Thu Sep 05 2013 - 19:06:38 EST


For performance reasons, the NMI handler may be disabled to lessen the
performance impact caused by the multiple perf tools running concurently.
If the system nmi command is issued when the UV NMI handler is disabled,
the "Dazed and Confused" messages occur for all cpus. The NMI handler is
disabled by setting the nmi disabled variable to '1'. Setting it back to
'0' will re-enable the NMI handler.

Signed-off-by: Mike Travis <travis@xxxxxxx>
Reviewed-by: Dimitri Sivanich <sivanich@xxxxxxx>
Reviewed-by: Hedi Berriche <hberrich@xxxxxxx>
---
arch/x86/platform/uv/uv_nmi.c | 69 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)

--- linux.orig/arch/x86/platform/uv/uv_nmi.c
+++ linux/arch/x86/platform/uv/uv_nmi.c
@@ -73,6 +73,7 @@ static struct uv_hub_nmi_s **uv_hub_nmi_
DEFINE_PER_CPU(struct uv_cpu_nmi_s, __uv_cpu_nmi);
EXPORT_PER_CPU_SYMBOL_GPL(__uv_cpu_nmi);

+static int uv_nmi_registered;
static unsigned long nmi_mmr;
static unsigned long nmi_mmr_clear;
static unsigned long nmi_mmr_pending;
@@ -130,6 +131,31 @@ module_param_named(ping_count, uv_nmi_pi
static local64_t uv_nmi_ping_misses;
module_param_named(ping_misses, uv_nmi_ping_misses, local64, 0644);

+static int uv_nmi_disabled;
+static int param_get_disabled(char *buffer, const struct kernel_param *kp)
+{
+ return sprintf(buffer, "%u\n", uv_nmi_disabled);
+}
+
+static void uv_nmi_notify_disabled(void);
+static int param_set_disabled(const char *val, const struct kernel_param *kp)
+{
+ int ret = param_set_bint(val, kp);
+
+ if (ret)
+ return ret;
+
+ uv_nmi_notify_disabled();
+ return 0;
+}
+
+static struct kernel_param_ops param_ops_disabled = {
+ .get = param_get_disabled,
+ .set = param_set_disabled,
+};
+#define param_check_disabled(name, p) __param_check(name, p, int)
+module_param_named(disabled, uv_nmi_disabled, disabled, 0644);
+
/*
* Following values allow tuning for large systems under heavy loading
*/
@@ -634,6 +660,8 @@ int uv_handle_nmi(unsigned int reason, s
atomic_set(&uv_nmi_cpus_in_nmi, -1);
atomic_set(&uv_nmi_cpu, -1);
atomic_set(&uv_in_nmi, 0);
+ if (uv_nmi_disabled)
+ uv_nmi_notify_disabled();
}

uv_nmi_touch_watchdogs();
@@ -664,11 +692,30 @@ int uv_handle_nmi_ping(unsigned int reas

void uv_register_nmi_notifier(void)
{
+ if (uv_nmi_registered || uv_nmi_disabled)
+ return;
+
if (register_nmi_handler(NMI_UNKNOWN, uv_handle_nmi, 0, "uv"))
pr_warn("UV: NMI handler failed to register\n");

if (register_nmi_handler(NMI_LOCAL, uv_handle_nmi_ping, 0, "uvping"))
pr_warn("UV: PING NMI handler failed to register\n");
+
+ uv_nmi_registered = 1;
+ pr_info("UV: NMI handler registered\n");
+}
+
+static void uv_nmi_disabled_msg(void)
+{
+ pr_err("UV: NMI handler disabled, power nmi command will be ignored\n");
+}
+
+static void uv_unregister_nmi_notifier(void)
+{
+ unregister_nmi_handler(NMI_UNKNOWN, "uv");
+ unregister_nmi_handler(NMI_LOCAL, "uvping");
+ uv_nmi_registered = 0;
+ uv_nmi_disabled_msg();
}

void uv_nmi_init(void)
@@ -688,6 +735,11 @@ void uv_nmi_setup(void)
int size = sizeof(void *) * (1 << NODES_SHIFT);
int cpu, nid;

+ if (uv_nmi_disabled) {
+ uv_nmi_disabled_msg();
+ return;
+ }
+
/* Setup hub nmi info */
uv_nmi_setup_mmrs();
uv_hub_nmi_list = kzalloc(size, GFP_KERNEL);
@@ -709,4 +761,21 @@ void uv_nmi_setup(void)
BUG_ON(!uv_nmi_cpu_mask);
}

+static void uv_nmi_notify_disabled(void)
+{
+ if (uv_nmi_disabled) {
+ /* if in nmi, handler will disable when finished */
+ if (atomic_read(&uv_in_nmi))
+ return;

+ if (uv_nmi_registered)
+ uv_unregister_nmi_notifier();
+
+ } else {
+ /* nmi control lists not yet allocated? */
+ if (!uv_hub_nmi_list)
+ uv_nmi_setup();
+
+ uv_register_nmi_notifier();
+ }
+}

--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/