// SPDX-License-Identifier: GPL-2.0-or-later
/*
* SGI NMI support routines
*
* Copyright (C) 2007-2017 Silicon Graphics, Inc. All rights reserved.
* Copyright (c) Mike Travis
*/
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/kdb.h>
#include <linux/kexec.h>
#include <linux/kgdb.h>
#include <linux/moduleparam.h>
#include <linux/nmi.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/slab.h>
#include <linux/clocksource.h>
#include <asm/apic.h>
#include <asm/current.h>
#include <asm/kdebug.h>
#include <asm/local64.h>
#include <asm/nmi.h>
#include <asm/traps.h>
#include <asm/uv/uv.h>
#include <asm/uv/uv_hub.h>
#include <asm/uv/uv_mmrs.h>
/*
* UV handler for NMI
*
* Handle system-wide NMI events generated by the global 'power nmi' command.
*
* Basic operation is to field the NMI interrupt on each CPU and wait
* until all CPU's have arrived into the nmi handler. If some CPU's do not
* make it into the handler, try and force them in with the IPI(NMI) signal.
*
* We also have to lessen UV Hub MMR accesses as much as possible as this
* disrupts the UV Hub's primary mission of directing NumaLink traffic and
* can cause system problems to occur.
*
* To do this we register our primary NMI notifier on the NMI_UNKNOWN
* chain. This reduces the number of false NMI calls when the perf
* tools are running which generate an enormous number of NMIs per
* second (~4M/s for 1024 CPU threads). Our secondary NMI handler is
* very short as it only checks that if it has been "pinged" with the
* IPI(NMI) signal as mentioned above, and does not read the UV Hub's MMR.
*
*/
static struct uv_hub_nmi_s **uv_hub_nmi_list;
DEFINE_PER_CPU(struct uv_cpu_nmi_s, uv_cpu_nmi);
/* Newer SMM NMI handler, not present in all systems */
static unsigned long uvh_nmi_mmrx; /* UVH_EVENT_OCCURRED0/1 */
static unsigned long uvh_nmi_mmrx_clear; /* UVH_EVENT_OCCURRED0/1_ALIAS */
static int uvh_nmi_mmrx_shift; /* UVH_EVENT_OCCURRED0/1_EXTIO_INT0_SHFT */
static int uvh_nmi_mmrx_mask; /* UVH_EVENT_OCCURRED0/1_EXTIO_INT0_MASK */
static char *uvh_nmi_mmrx_type; /* "EXTIO_INT0" */
/* Non-zero indicates newer SMM NMI handler present */
static unsigned long uvh_nmi_mmrx_supported; /* UVH_EXTIO_INT0_BROADCAST */
/* Indicates to BIOS that we want to use the newer SMM NMI handler */
static unsigned long uvh_nmi_mmrx_req; /* UVH_BIOS_KERNEL_MMR_ALIAS_2 */
static int uvh_nmi_mmrx_req_shift; /* 62 */
/* UV hubless values */
#define NMI_CONTROL_PORT 0x70
#define NMI_DUMMY_PORT 0x71
#define PAD_OWN_GPP_D_0 0x2c
#define GPI_NMI_STS_GPP_D_0 0x164
#define GPI_NMI_ENA_GPP_D_0 0x174
#define STS_GPP_D_0_MASK 0x1
#define PAD_CFG_DW0_GPP_D_0 0x4c0
#define GPIROUTNMI (1ul << 17)
#define PCH_PCR_GPIO_1_BASE 0xfdae0000ul
#define PCH_PCR_GPIO_ADDRESS(offset) (int *)((u64)(pch_base) | (u64)(offset))
static u64 *pch_base;
static unsigned long nmi_mmr;
static unsigned long nmi_mmr_clear;
static unsigned long nmi_mmr_pending;
static atomic_t uv_in_nmi;
static atomic_t uv_nmi_cpu = ATOMIC_INIT(-1);
static atomic_t uv_nmi_cpus_in_nmi = ATOMIC_INIT(-1);
static atomic_t uv_nmi_slave_continue;
static cpumask_var_t uv_nmi_cpu_mask;
/* Values for uv_nmi_slave_continue */
#define SLAVE_CLEAR 0
#define SLAVE_CONTINUE 1
#define SLAVE_EXIT 2
/*
* Default is all stack dumps go to the console and buffer.
* Lower level to send to log buffer only.
*/
static int uv_nmi_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
module_param_named(dump_loglevel, uv_nmi_loglevel, int, 0644);
/*
* The following values show statistics on how perf events are affecting
* this system.
*/
static int param_get_local64(char *buffer, const struct kernel_param *kp)
{
return sprintf(buffer, "%lu\n", local64_read((local64_t *)kp->arg));
}
static int param_set_local64(const char *val, const struct kernel_param *kp)
{
/* Clear on any write */
local64_set((local64_t *)kp->arg, 0);
return 0;
}
static const struct kernel_param_ops param_ops_local64 = {
.get = param_get_local64,
.set = param_set_local64,
};
#define param_check_local64(name, p) __param_check(name, p, local64_t)
static local64_t uv_nmi_count;
module_param_named(nmi_count, uv_nmi_count, local64, 0644);
static local64_t uv_nmi_misses;
module_param_named(nmi_misses, uv_nmi_misses, local64, 0644);
static local64_t uv_nmi_ping_count;
module_param_named(ping_count, uv_nmi_ping_count, local64, 0644);
static local64_t uv_nmi_ping_misses;
module_param_named(ping_misses, uv_nmi_ping_misses, local64, 0644);
/*
* Following values allow tuning for large systems under heavy loading
*/
static int uv_nmi_initial_delay = 100;
module_param_named(initial_delay, uv_nmi_initial_delay, int, 0644);
static int uv_nmi_slave_delay = 100;
module_param_named(slave_delay, uv_nmi_slave_delay, int, 0644);
static int uv_nmi_loop_delay = 100;
module_param_named(loop_delay, uv_nmi_loop_delay, int, 0644);
static int uv_nmi_trigger_delay = 10000;
module_param_named(trigger_delay, uv_nmi_trigger_delay, int, 0644);
static int uv_nmi_wait_count