112237550SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 221afaf18SBorislav Petkov /* 321afaf18SBorislav Petkov * Machine check injection support. 421afaf18SBorislav Petkov * Copyright 2008 Intel Corporation. 521afaf18SBorislav Petkov * 621afaf18SBorislav Petkov * Authors: 721afaf18SBorislav Petkov * Andi Kleen 821afaf18SBorislav Petkov * Ying Huang 921afaf18SBorislav Petkov * 1021afaf18SBorislav Petkov * The AMD part (from mce_amd_inj.c): a simple MCE injection facility 1121afaf18SBorislav Petkov * for testing different aspects of the RAS code. This driver should be 1221afaf18SBorislav Petkov * built as module so that it can be loaded on production kernels for 1321afaf18SBorislav Petkov * testing purposes. 1421afaf18SBorislav Petkov * 1521afaf18SBorislav Petkov * Copyright (c) 2010-17: Borislav Petkov <bp@alien8.de> 1621afaf18SBorislav Petkov * Advanced Micro Devices Inc. 1721afaf18SBorislav Petkov */ 1821afaf18SBorislav Petkov 1921afaf18SBorislav Petkov #include <linux/cpu.h> 2021afaf18SBorislav Petkov #include <linux/debugfs.h> 2121afaf18SBorislav Petkov #include <linux/kernel.h> 2221afaf18SBorislav Petkov #include <linux/module.h> 2321afaf18SBorislav Petkov #include <linux/notifier.h> 2421afaf18SBorislav Petkov #include <linux/pci.h> 2521afaf18SBorislav Petkov #include <linux/uaccess.h> 2621afaf18SBorislav Petkov 2721afaf18SBorislav Petkov #include <asm/amd_nb.h> 2821afaf18SBorislav Petkov #include <asm/apic.h> 2921afaf18SBorislav Petkov #include <asm/irq_vectors.h> 3021afaf18SBorislav Petkov #include <asm/mce.h> 3121afaf18SBorislav Petkov #include <asm/nmi.h> 3221afaf18SBorislav Petkov #include <asm/smp.h> 3321afaf18SBorislav Petkov 3421afaf18SBorislav Petkov #include "internal.h" 3521afaf18SBorislav Petkov 36891e465aSSmita Koralahalli static bool hw_injection_possible = true; 37891e465aSSmita Koralahalli 3821afaf18SBorislav Petkov /* 3921afaf18SBorislav Petkov * Collect all the MCi_XXX settings 4021afaf18SBorislav Petkov */ 4121afaf18SBorislav Petkov static struct mce i_mce; 4221afaf18SBorislav Petkov static struct dentry *dfs_inj; 4321afaf18SBorislav Petkov 4421afaf18SBorislav Petkov #define MAX_FLAG_OPT_SIZE 4 4521afaf18SBorislav Petkov #define NBCFG 0x44 4621afaf18SBorislav Petkov 4721afaf18SBorislav Petkov enum injection_type { 4821afaf18SBorislav Petkov SW_INJ = 0, /* SW injection, simply decode the error */ 4921afaf18SBorislav Petkov HW_INJ, /* Trigger a #MC */ 5021afaf18SBorislav Petkov DFR_INT_INJ, /* Trigger Deferred error interrupt */ 5121afaf18SBorislav Petkov THR_INT_INJ, /* Trigger threshold interrupt */ 5221afaf18SBorislav Petkov N_INJ_TYPES, 5321afaf18SBorislav Petkov }; 5421afaf18SBorislav Petkov 5521afaf18SBorislav Petkov static const char * const flags_options[] = { 5621afaf18SBorislav Petkov [SW_INJ] = "sw", 5721afaf18SBorislav Petkov [HW_INJ] = "hw", 5821afaf18SBorislav Petkov [DFR_INT_INJ] = "df", 5921afaf18SBorislav Petkov [THR_INT_INJ] = "th", 6021afaf18SBorislav Petkov NULL 6121afaf18SBorislav Petkov }; 6221afaf18SBorislav Petkov 6321afaf18SBorislav Petkov /* Set default injection to SW_INJ */ 6421afaf18SBorislav Petkov static enum injection_type inj_type = SW_INJ; 6521afaf18SBorislav Petkov 6621afaf18SBorislav Petkov #define MCE_INJECT_SET(reg) \ 6721afaf18SBorislav Petkov static int inj_##reg##_set(void *data, u64 val) \ 6821afaf18SBorislav Petkov { \ 6921afaf18SBorislav Petkov struct mce *m = (struct mce *)data; \ 7021afaf18SBorislav Petkov \ 7121afaf18SBorislav Petkov m->reg = val; \ 7221afaf18SBorislav Petkov return 0; \ 7321afaf18SBorislav Petkov } 7421afaf18SBorislav Petkov 7521afaf18SBorislav Petkov MCE_INJECT_SET(status); 7621afaf18SBorislav Petkov MCE_INJECT_SET(misc); 7721afaf18SBorislav Petkov MCE_INJECT_SET(addr); 7821afaf18SBorislav Petkov MCE_INJECT_SET(synd); 7921afaf18SBorislav Petkov 8021afaf18SBorislav Petkov #define MCE_INJECT_GET(reg) \ 8121afaf18SBorislav Petkov static int inj_##reg##_get(void *data, u64 *val) \ 8221afaf18SBorislav Petkov { \ 8321afaf18SBorislav Petkov struct mce *m = (struct mce *)data; \ 8421afaf18SBorislav Petkov \ 8521afaf18SBorislav Petkov *val = m->reg; \ 8621afaf18SBorislav Petkov return 0; \ 8721afaf18SBorislav Petkov } 8821afaf18SBorislav Petkov 8921afaf18SBorislav Petkov MCE_INJECT_GET(status); 9021afaf18SBorislav Petkov MCE_INJECT_GET(misc); 9121afaf18SBorislav Petkov MCE_INJECT_GET(addr); 9221afaf18SBorislav Petkov MCE_INJECT_GET(synd); 932ffdc2c3SBorislav Petkov MCE_INJECT_GET(ipid); 9421afaf18SBorislav Petkov 9521afaf18SBorislav Petkov DEFINE_SIMPLE_ATTRIBUTE(status_fops, inj_status_get, inj_status_set, "%llx\n"); 9621afaf18SBorislav Petkov DEFINE_SIMPLE_ATTRIBUTE(misc_fops, inj_misc_get, inj_misc_set, "%llx\n"); 9721afaf18SBorislav Petkov DEFINE_SIMPLE_ATTRIBUTE(addr_fops, inj_addr_get, inj_addr_set, "%llx\n"); 9821afaf18SBorislav Petkov DEFINE_SIMPLE_ATTRIBUTE(synd_fops, inj_synd_get, inj_synd_set, "%llx\n"); 99e48d008bSSmita Koralahalli 100e48d008bSSmita Koralahalli /* Use the user provided IPID value on a sw injection. */ 101e48d008bSSmita Koralahalli static int inj_ipid_set(void *data, u64 val) 102e48d008bSSmita Koralahalli { 103e48d008bSSmita Koralahalli struct mce *m = (struct mce *)data; 104e48d008bSSmita Koralahalli 105e48d008bSSmita Koralahalli if (cpu_feature_enabled(X86_FEATURE_SMCA)) { 106e48d008bSSmita Koralahalli if (inj_type == SW_INJ) 107e48d008bSSmita Koralahalli m->ipid = val; 108e48d008bSSmita Koralahalli } 109e48d008bSSmita Koralahalli 110e48d008bSSmita Koralahalli return 0; 111e48d008bSSmita Koralahalli } 112e48d008bSSmita Koralahalli 1132ffdc2c3SBorislav Petkov DEFINE_SIMPLE_ATTRIBUTE(ipid_fops, inj_ipid_get, inj_ipid_set, "%llx\n"); 11421afaf18SBorislav Petkov 11521afaf18SBorislav Petkov static void setup_inj_struct(struct mce *m) 11621afaf18SBorislav Petkov { 11721afaf18SBorislav Petkov memset(m, 0, sizeof(struct mce)); 11821afaf18SBorislav Petkov 11921afaf18SBorislav Petkov m->cpuvendor = boot_cpu_data.x86_vendor; 12021afaf18SBorislav Petkov m->time = ktime_get_real_seconds(); 12121afaf18SBorislav Petkov m->cpuid = cpuid_eax(1); 12221afaf18SBorislav Petkov m->microcode = boot_cpu_data.microcode; 12321afaf18SBorislav Petkov } 12421afaf18SBorislav Petkov 12521afaf18SBorislav Petkov /* Update fake mce registers on current CPU. */ 12621afaf18SBorislav Petkov static void inject_mce(struct mce *m) 12721afaf18SBorislav Petkov { 12821afaf18SBorislav Petkov struct mce *i = &per_cpu(injectm, m->extcpu); 12921afaf18SBorislav Petkov 13021afaf18SBorislav Petkov /* Make sure no one reads partially written injectm */ 13121afaf18SBorislav Petkov i->finished = 0; 13221afaf18SBorislav Petkov mb(); 13321afaf18SBorislav Petkov m->finished = 0; 13421afaf18SBorislav Petkov /* First set the fields after finished */ 13521afaf18SBorislav Petkov i->extcpu = m->extcpu; 13621afaf18SBorislav Petkov mb(); 13721afaf18SBorislav Petkov /* Now write record in order, finished last (except above) */ 13821afaf18SBorislav Petkov memcpy(i, m, sizeof(struct mce)); 13921afaf18SBorislav Petkov /* Finally activate it */ 14021afaf18SBorislav Petkov mb(); 14121afaf18SBorislav Petkov i->finished = 1; 14221afaf18SBorislav Petkov } 14321afaf18SBorislav Petkov 14421afaf18SBorislav Petkov static void raise_poll(struct mce *m) 14521afaf18SBorislav Petkov { 14621afaf18SBorislav Petkov unsigned long flags; 14721afaf18SBorislav Petkov mce_banks_t b; 14821afaf18SBorislav Petkov 14921afaf18SBorislav Petkov memset(&b, 0xff, sizeof(mce_banks_t)); 15021afaf18SBorislav Petkov local_irq_save(flags); 15121afaf18SBorislav Petkov machine_check_poll(0, &b); 15221afaf18SBorislav Petkov local_irq_restore(flags); 15321afaf18SBorislav Petkov m->finished = 0; 15421afaf18SBorislav Petkov } 15521afaf18SBorislav Petkov 15621afaf18SBorislav Petkov static void raise_exception(struct mce *m, struct pt_regs *pregs) 15721afaf18SBorislav Petkov { 15821afaf18SBorislav Petkov struct pt_regs regs; 15921afaf18SBorislav Petkov unsigned long flags; 16021afaf18SBorislav Petkov 16121afaf18SBorislav Petkov if (!pregs) { 16221afaf18SBorislav Petkov memset(®s, 0, sizeof(struct pt_regs)); 16321afaf18SBorislav Petkov regs.ip = m->ip; 16421afaf18SBorislav Petkov regs.cs = m->cs; 16521afaf18SBorislav Petkov pregs = ®s; 16621afaf18SBorislav Petkov } 1678cd501c1SThomas Gleixner /* do_machine_check() expects interrupts disabled -- at least */ 16821afaf18SBorislav Petkov local_irq_save(flags); 1698cd501c1SThomas Gleixner do_machine_check(pregs); 17021afaf18SBorislav Petkov local_irq_restore(flags); 17121afaf18SBorislav Petkov m->finished = 0; 17221afaf18SBorislav Petkov } 17321afaf18SBorislav Petkov 17421afaf18SBorislav Petkov static cpumask_var_t mce_inject_cpumask; 17521afaf18SBorislav Petkov static DEFINE_MUTEX(mce_inject_mutex); 17621afaf18SBorislav Petkov 17721afaf18SBorislav Petkov static int mce_raise_notify(unsigned int cmd, struct pt_regs *regs) 17821afaf18SBorislav Petkov { 17921afaf18SBorislav Petkov int cpu = smp_processor_id(); 18021afaf18SBorislav Petkov struct mce *m = this_cpu_ptr(&injectm); 18121afaf18SBorislav Petkov if (!cpumask_test_cpu(cpu, mce_inject_cpumask)) 18221afaf18SBorislav Petkov return NMI_DONE; 18321afaf18SBorislav Petkov cpumask_clear_cpu(cpu, mce_inject_cpumask); 18421afaf18SBorislav Petkov if (m->inject_flags & MCJ_EXCEPTION) 18521afaf18SBorislav Petkov raise_exception(m, regs); 18621afaf18SBorislav Petkov else if (m->status) 18721afaf18SBorislav Petkov raise_poll(m); 18821afaf18SBorislav Petkov return NMI_HANDLED; 18921afaf18SBorislav Petkov } 19021afaf18SBorislav Petkov 19121afaf18SBorislav Petkov static void mce_irq_ipi(void *info) 19221afaf18SBorislav Petkov { 19321afaf18SBorislav Petkov int cpu = smp_processor_id(); 19421afaf18SBorislav Petkov struct mce *m = this_cpu_ptr(&injectm); 19521afaf18SBorislav Petkov 19621afaf18SBorislav Petkov if (cpumask_test_cpu(cpu, mce_inject_cpumask) && 19721afaf18SBorislav Petkov m->inject_flags & MCJ_EXCEPTION) { 19821afaf18SBorislav Petkov cpumask_clear_cpu(cpu, mce_inject_cpumask); 19921afaf18SBorislav Petkov raise_exception(m, NULL); 20021afaf18SBorislav Petkov } 20121afaf18SBorislav Petkov } 20221afaf18SBorislav Petkov 20321afaf18SBorislav Petkov /* Inject mce on current CPU */ 20421afaf18SBorislav Petkov static int raise_local(void) 20521afaf18SBorislav Petkov { 20621afaf18SBorislav Petkov struct mce *m = this_cpu_ptr(&injectm); 20721afaf18SBorislav Petkov int context = MCJ_CTX(m->inject_flags); 20821afaf18SBorislav Petkov int ret = 0; 20921afaf18SBorislav Petkov int cpu = m->extcpu; 21021afaf18SBorislav Petkov 21121afaf18SBorislav Petkov if (m->inject_flags & MCJ_EXCEPTION) { 21221afaf18SBorislav Petkov pr_info("Triggering MCE exception on CPU %d\n", cpu); 21321afaf18SBorislav Petkov switch (context) { 21421afaf18SBorislav Petkov case MCJ_CTX_IRQ: 21521afaf18SBorislav Petkov /* 21621afaf18SBorislav Petkov * Could do more to fake interrupts like 21721afaf18SBorislav Petkov * calling irq_enter, but the necessary 21821afaf18SBorislav Petkov * machinery isn't exported currently. 21921afaf18SBorislav Petkov */ 220df561f66SGustavo A. R. Silva fallthrough; 22121afaf18SBorislav Petkov case MCJ_CTX_PROCESS: 22221afaf18SBorislav Petkov raise_exception(m, NULL); 22321afaf18SBorislav Petkov break; 22421afaf18SBorislav Petkov default: 22521afaf18SBorislav Petkov pr_info("Invalid MCE context\n"); 22621afaf18SBorislav Petkov ret = -EINVAL; 22721afaf18SBorislav Petkov } 22821afaf18SBorislav Petkov pr_info("MCE exception done on CPU %d\n", cpu); 22921afaf18SBorislav Petkov } else if (m->status) { 23021afaf18SBorislav Petkov pr_info("Starting machine check poll CPU %d\n", cpu); 23121afaf18SBorislav Petkov raise_poll(m); 23221afaf18SBorislav Petkov mce_notify_irq(); 23321afaf18SBorislav Petkov pr_info("Machine check poll done on CPU %d\n", cpu); 23421afaf18SBorislav Petkov } else 23521afaf18SBorislav Petkov m->finished = 0; 23621afaf18SBorislav Petkov 23721afaf18SBorislav Petkov return ret; 23821afaf18SBorislav Petkov } 23921afaf18SBorislav Petkov 24021afaf18SBorislav Petkov static void __maybe_unused raise_mce(struct mce *m) 24121afaf18SBorislav Petkov { 24221afaf18SBorislav Petkov int context = MCJ_CTX(m->inject_flags); 24321afaf18SBorislav Petkov 24421afaf18SBorislav Petkov inject_mce(m); 24521afaf18SBorislav Petkov 24621afaf18SBorislav Petkov if (context == MCJ_CTX_RANDOM) 24721afaf18SBorislav Petkov return; 24821afaf18SBorislav Petkov 24921afaf18SBorislav Petkov if (m->inject_flags & (MCJ_IRQ_BROADCAST | MCJ_NMI_BROADCAST)) { 25021afaf18SBorislav Petkov unsigned long start; 25121afaf18SBorislav Petkov int cpu; 25221afaf18SBorislav Petkov 2538ae9e3f6SSebastian Andrzej Siewior cpus_read_lock(); 25421afaf18SBorislav Petkov cpumask_copy(mce_inject_cpumask, cpu_online_mask); 25521afaf18SBorislav Petkov cpumask_clear_cpu(get_cpu(), mce_inject_cpumask); 25621afaf18SBorislav Petkov for_each_online_cpu(cpu) { 25721afaf18SBorislav Petkov struct mce *mcpu = &per_cpu(injectm, cpu); 25821afaf18SBorislav Petkov if (!mcpu->finished || 25921afaf18SBorislav Petkov MCJ_CTX(mcpu->inject_flags) != MCJ_CTX_RANDOM) 26021afaf18SBorislav Petkov cpumask_clear_cpu(cpu, mce_inject_cpumask); 26121afaf18SBorislav Petkov } 26221afaf18SBorislav Petkov if (!cpumask_empty(mce_inject_cpumask)) { 26321afaf18SBorislav Petkov if (m->inject_flags & MCJ_IRQ_BROADCAST) { 26421afaf18SBorislav Petkov /* 26521afaf18SBorislav Petkov * don't wait because mce_irq_ipi is necessary 26621afaf18SBorislav Petkov * to be sync with following raise_local 26721afaf18SBorislav Petkov */ 26821afaf18SBorislav Petkov preempt_disable(); 26921afaf18SBorislav Petkov smp_call_function_many(mce_inject_cpumask, 27021afaf18SBorislav Petkov mce_irq_ipi, NULL, 0); 27121afaf18SBorislav Petkov preempt_enable(); 27221afaf18SBorislav Petkov } else if (m->inject_flags & MCJ_NMI_BROADCAST) 27328b82352SDave Hansen __apic_send_IPI_mask(mce_inject_cpumask, NMI_VECTOR); 27421afaf18SBorislav Petkov } 27521afaf18SBorislav Petkov start = jiffies; 27621afaf18SBorislav Petkov while (!cpumask_empty(mce_inject_cpumask)) { 27721afaf18SBorislav Petkov if (!time_before(jiffies, start + 2*HZ)) { 27821afaf18SBorislav Petkov pr_err("Timeout waiting for mce inject %lx\n", 27921afaf18SBorislav Petkov *cpumask_bits(mce_inject_cpumask)); 28021afaf18SBorislav Petkov break; 28121afaf18SBorislav Petkov } 28221afaf18SBorislav Petkov cpu_relax(); 28321afaf18SBorislav Petkov } 28421afaf18SBorislav Petkov raise_local(); 28521afaf18SBorislav Petkov put_cpu(); 2868ae9e3f6SSebastian Andrzej Siewior cpus_read_unlock(); 28721afaf18SBorislav Petkov } else { 28821afaf18SBorislav Petkov preempt_disable(); 28921afaf18SBorislav Petkov raise_local(); 29021afaf18SBorislav Petkov preempt_enable(); 29121afaf18SBorislav Petkov } 29221afaf18SBorislav Petkov } 29321afaf18SBorislav Petkov 29421afaf18SBorislav Petkov static int mce_inject_raise(struct notifier_block *nb, unsigned long val, 29521afaf18SBorislav Petkov void *data) 29621afaf18SBorislav Petkov { 29721afaf18SBorislav Petkov struct mce *m = (struct mce *)data; 29821afaf18SBorislav Petkov 29921afaf18SBorislav Petkov if (!m) 30021afaf18SBorislav Petkov return NOTIFY_DONE; 30121afaf18SBorislav Petkov 30221afaf18SBorislav Petkov mutex_lock(&mce_inject_mutex); 30321afaf18SBorislav Petkov raise_mce(m); 30421afaf18SBorislav Petkov mutex_unlock(&mce_inject_mutex); 30521afaf18SBorislav Petkov 30621afaf18SBorislav Petkov return NOTIFY_DONE; 30721afaf18SBorislav Petkov } 30821afaf18SBorislav Petkov 30921afaf18SBorislav Petkov static struct notifier_block inject_nb = { 31021afaf18SBorislav Petkov .notifier_call = mce_inject_raise, 31121afaf18SBorislav Petkov }; 31221afaf18SBorislav Petkov 31321afaf18SBorislav Petkov /* 31421afaf18SBorislav Petkov * Caller needs to be make sure this cpu doesn't disappear 31521afaf18SBorislav Petkov * from under us, i.e.: get_cpu/put_cpu. 31621afaf18SBorislav Petkov */ 31721afaf18SBorislav Petkov static int toggle_hw_mce_inject(unsigned int cpu, bool enable) 31821afaf18SBorislav Petkov { 31921afaf18SBorislav Petkov u32 l, h; 32021afaf18SBorislav Petkov int err; 32121afaf18SBorislav Petkov 32221afaf18SBorislav Petkov err = rdmsr_on_cpu(cpu, MSR_K7_HWCR, &l, &h); 32321afaf18SBorislav Petkov if (err) { 32421afaf18SBorislav Petkov pr_err("%s: error reading HWCR\n", __func__); 32521afaf18SBorislav Petkov return err; 32621afaf18SBorislav Petkov } 32721afaf18SBorislav Petkov 32821afaf18SBorislav Petkov enable ? (l |= BIT(18)) : (l &= ~BIT(18)); 32921afaf18SBorislav Petkov 33021afaf18SBorislav Petkov err = wrmsr_on_cpu(cpu, MSR_K7_HWCR, l, h); 33121afaf18SBorislav Petkov if (err) 33221afaf18SBorislav Petkov pr_err("%s: error writing HWCR\n", __func__); 33321afaf18SBorislav Petkov 33421afaf18SBorislav Petkov return err; 33521afaf18SBorislav Petkov } 33621afaf18SBorislav Petkov 33721afaf18SBorislav Petkov static int __set_inj(const char *buf) 33821afaf18SBorislav Petkov { 33921afaf18SBorislav Petkov int i; 34021afaf18SBorislav Petkov 34121afaf18SBorislav Petkov for (i = 0; i < N_INJ_TYPES; i++) { 34221afaf18SBorislav Petkov if (!strncmp(flags_options[i], buf, strlen(flags_options[i]))) { 343891e465aSSmita Koralahalli if (i > SW_INJ && !hw_injection_possible) 344891e465aSSmita Koralahalli continue; 34521afaf18SBorislav Petkov inj_type = i; 34621afaf18SBorislav Petkov return 0; 34721afaf18SBorislav Petkov } 34821afaf18SBorislav Petkov } 34921afaf18SBorislav Petkov return -EINVAL; 35021afaf18SBorislav Petkov } 35121afaf18SBorislav Petkov 35221afaf18SBorislav Petkov static ssize_t flags_read(struct file *filp, char __user *ubuf, 35321afaf18SBorislav Petkov size_t cnt, loff_t *ppos) 35421afaf18SBorislav Petkov { 35521afaf18SBorislav Petkov char buf[MAX_FLAG_OPT_SIZE]; 35621afaf18SBorislav Petkov int n; 35721afaf18SBorislav Petkov 35821afaf18SBorislav Petkov n = sprintf(buf, "%s\n", flags_options[inj_type]); 35921afaf18SBorislav Petkov 36021afaf18SBorislav Petkov return simple_read_from_buffer(ubuf, cnt, ppos, buf, n); 36121afaf18SBorislav Petkov } 36221afaf18SBorislav Petkov 36321afaf18SBorislav Petkov static ssize_t flags_write(struct file *filp, const char __user *ubuf, 36421afaf18SBorislav Petkov size_t cnt, loff_t *ppos) 36521afaf18SBorislav Petkov { 36621afaf18SBorislav Petkov char buf[MAX_FLAG_OPT_SIZE], *__buf; 36721afaf18SBorislav Petkov int err; 36821afaf18SBorislav Petkov 369de768416SZhang Zixun if (!cnt || cnt > MAX_FLAG_OPT_SIZE) 37021afaf18SBorislav Petkov return -EINVAL; 37121afaf18SBorislav Petkov 37221afaf18SBorislav Petkov if (copy_from_user(&buf, ubuf, cnt)) 37321afaf18SBorislav Petkov return -EFAULT; 37421afaf18SBorislav Petkov 37521afaf18SBorislav Petkov buf[cnt - 1] = 0; 37621afaf18SBorislav Petkov 37721afaf18SBorislav Petkov /* strip whitespace */ 37821afaf18SBorislav Petkov __buf = strstrip(buf); 37921afaf18SBorislav Petkov 38021afaf18SBorislav Petkov err = __set_inj(__buf); 38121afaf18SBorislav Petkov if (err) { 38221afaf18SBorislav Petkov pr_err("%s: Invalid flags value: %s\n", __func__, __buf); 38321afaf18SBorislav Petkov return err; 38421afaf18SBorislav Petkov } 38521afaf18SBorislav Petkov 38621afaf18SBorislav Petkov *ppos += cnt; 38721afaf18SBorislav Petkov 38821afaf18SBorislav Petkov return cnt; 38921afaf18SBorislav Petkov } 39021afaf18SBorislav Petkov 39121afaf18SBorislav Petkov static const struct file_operations flags_fops = { 39221afaf18SBorislav Petkov .read = flags_read, 39321afaf18SBorislav Petkov .write = flags_write, 39421afaf18SBorislav Petkov .llseek = generic_file_llseek, 39521afaf18SBorislav Petkov }; 39621afaf18SBorislav Petkov 39721afaf18SBorislav Petkov /* 39821afaf18SBorislav Petkov * On which CPU to inject? 39921afaf18SBorislav Petkov */ 40021afaf18SBorislav Petkov MCE_INJECT_GET(extcpu); 40121afaf18SBorislav Petkov 40221afaf18SBorislav Petkov static int inj_extcpu_set(void *data, u64 val) 40321afaf18SBorislav Petkov { 40421afaf18SBorislav Petkov struct mce *m = (struct mce *)data; 40521afaf18SBorislav Petkov 40621afaf18SBorislav Petkov if (val >= nr_cpu_ids || !cpu_online(val)) { 40721afaf18SBorislav Petkov pr_err("%s: Invalid CPU: %llu\n", __func__, val); 40821afaf18SBorislav Petkov return -EINVAL; 40921afaf18SBorislav Petkov } 41021afaf18SBorislav Petkov m->extcpu = val; 41121afaf18SBorislav Petkov return 0; 41221afaf18SBorislav Petkov } 41321afaf18SBorislav Petkov 41421afaf18SBorislav Petkov DEFINE_SIMPLE_ATTRIBUTE(extcpu_fops, inj_extcpu_get, inj_extcpu_set, "%llu\n"); 41521afaf18SBorislav Petkov 41621afaf18SBorislav Petkov static void trigger_mce(void *info) 41721afaf18SBorislav Petkov { 41821afaf18SBorislav Petkov asm volatile("int $18"); 41921afaf18SBorislav Petkov } 42021afaf18SBorislav Petkov 42121afaf18SBorislav Petkov static void trigger_dfr_int(void *info) 42221afaf18SBorislav Petkov { 42321afaf18SBorislav Petkov asm volatile("int %0" :: "i" (DEFERRED_ERROR_VECTOR)); 42421afaf18SBorislav Petkov } 42521afaf18SBorislav Petkov 42621afaf18SBorislav Petkov static void trigger_thr_int(void *info) 42721afaf18SBorislav Petkov { 42821afaf18SBorislav Petkov asm volatile("int %0" :: "i" (THRESHOLD_APIC_VECTOR)); 42921afaf18SBorislav Petkov } 43021afaf18SBorislav Petkov 43121afaf18SBorislav Petkov static u32 get_nbc_for_node(int node_id) 43221afaf18SBorislav Petkov { 43321afaf18SBorislav Petkov struct cpuinfo_x86 *c = &boot_cpu_data; 43421afaf18SBorislav Petkov u32 cores_per_node; 43521afaf18SBorislav Petkov 43621afaf18SBorislav Petkov cores_per_node = (c->x86_max_cores * smp_num_siblings) / amd_get_nodes_per_socket(); 43721afaf18SBorislav Petkov 43821afaf18SBorislav Petkov return cores_per_node * node_id; 43921afaf18SBorislav Petkov } 44021afaf18SBorislav Petkov 44121afaf18SBorislav Petkov static void toggle_nb_mca_mst_cpu(u16 nid) 44221afaf18SBorislav Petkov { 44321afaf18SBorislav Petkov struct amd_northbridge *nb; 44421afaf18SBorislav Petkov struct pci_dev *F3; 44521afaf18SBorislav Petkov u32 val; 44621afaf18SBorislav Petkov int err; 44721afaf18SBorislav Petkov 44821afaf18SBorislav Petkov nb = node_to_amd_nb(nid); 44921afaf18SBorislav Petkov if (!nb) 45021afaf18SBorislav Petkov return; 45121afaf18SBorislav Petkov 45221afaf18SBorislav Petkov F3 = nb->misc; 45321afaf18SBorislav Petkov if (!F3) 45421afaf18SBorislav Petkov return; 45521afaf18SBorislav Petkov 45621afaf18SBorislav Petkov err = pci_read_config_dword(F3, NBCFG, &val); 45721afaf18SBorislav Petkov if (err) { 45821afaf18SBorislav Petkov pr_err("%s: Error reading F%dx%03x.\n", 45921afaf18SBorislav Petkov __func__, PCI_FUNC(F3->devfn), NBCFG); 46021afaf18SBorislav Petkov return; 46121afaf18SBorislav Petkov } 46221afaf18SBorislav Petkov 46321afaf18SBorislav Petkov if (val & BIT(27)) 46421afaf18SBorislav Petkov return; 46521afaf18SBorislav Petkov 46621afaf18SBorislav Petkov pr_err("%s: Set D18F3x44[NbMcaToMstCpuEn] which BIOS hasn't done.\n", 46721afaf18SBorislav Petkov __func__); 46821afaf18SBorislav Petkov 46921afaf18SBorislav Petkov val |= BIT(27); 47021afaf18SBorislav Petkov err = pci_write_config_dword(F3, NBCFG, val); 47121afaf18SBorislav Petkov if (err) 47221afaf18SBorislav Petkov pr_err("%s: Error writing F%dx%03x.\n", 47321afaf18SBorislav Petkov __func__, PCI_FUNC(F3->devfn), NBCFG); 47421afaf18SBorislav Petkov } 47521afaf18SBorislav Petkov 47621afaf18SBorislav Petkov static void prepare_msrs(void *info) 47721afaf18SBorislav Petkov { 47821afaf18SBorislav Petkov struct mce m = *(struct mce *)info; 47921afaf18SBorislav Petkov u8 b = m.bank; 48021afaf18SBorislav Petkov 48121afaf18SBorislav Petkov wrmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus); 48221afaf18SBorislav Petkov 48321afaf18SBorislav Petkov if (boot_cpu_has(X86_FEATURE_SMCA)) { 48421afaf18SBorislav Petkov if (m.inject_flags == DFR_INT_INJ) { 48521afaf18SBorislav Petkov wrmsrl(MSR_AMD64_SMCA_MCx_DESTAT(b), m.status); 48621afaf18SBorislav Petkov wrmsrl(MSR_AMD64_SMCA_MCx_DEADDR(b), m.addr); 48721afaf18SBorislav Petkov } else { 48821afaf18SBorislav Petkov wrmsrl(MSR_AMD64_SMCA_MCx_STATUS(b), m.status); 48921afaf18SBorislav Petkov wrmsrl(MSR_AMD64_SMCA_MCx_ADDR(b), m.addr); 49021afaf18SBorislav Petkov } 49121afaf18SBorislav Petkov 49221afaf18SBorislav Petkov wrmsrl(MSR_AMD64_SMCA_MCx_MISC(b), m.misc); 49321afaf18SBorislav Petkov wrmsrl(MSR_AMD64_SMCA_MCx_SYND(b), m.synd); 49421afaf18SBorislav Petkov } else { 49521afaf18SBorislav Petkov wrmsrl(MSR_IA32_MCx_STATUS(b), m.status); 49621afaf18SBorislav Petkov wrmsrl(MSR_IA32_MCx_ADDR(b), m.addr); 49721afaf18SBorislav Petkov wrmsrl(MSR_IA32_MCx_MISC(b), m.misc); 49821afaf18SBorislav Petkov } 49921afaf18SBorislav Petkov } 50021afaf18SBorislav Petkov 50121afaf18SBorislav Petkov static void do_inject(void) 50221afaf18SBorislav Petkov { 50321afaf18SBorislav Petkov u64 mcg_status = 0; 50421afaf18SBorislav Petkov unsigned int cpu = i_mce.extcpu; 50521afaf18SBorislav Petkov u8 b = i_mce.bank; 50621afaf18SBorislav Petkov 50721afaf18SBorislav Petkov i_mce.tsc = rdtsc_ordered(); 50821afaf18SBorislav Petkov 5091e56279aSSmita Koralahalli i_mce.status |= MCI_STATUS_VAL; 5101e56279aSSmita Koralahalli 51121afaf18SBorislav Petkov if (i_mce.misc) 51221afaf18SBorislav Petkov i_mce.status |= MCI_STATUS_MISCV; 51321afaf18SBorislav Petkov 51421afaf18SBorislav Petkov if (i_mce.synd) 51521afaf18SBorislav Petkov i_mce.status |= MCI_STATUS_SYNDV; 51621afaf18SBorislav Petkov 51721afaf18SBorislav Petkov if (inj_type == SW_INJ) { 51881736abdSJan H. Schönherr mce_log(&i_mce); 51921afaf18SBorislav Petkov return; 52021afaf18SBorislav Petkov } 52121afaf18SBorislav Petkov 52221afaf18SBorislav Petkov /* prep MCE global settings for the injection */ 52321afaf18SBorislav Petkov mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV; 52421afaf18SBorislav Petkov 52521afaf18SBorislav Petkov if (!(i_mce.status & MCI_STATUS_PCC)) 52621afaf18SBorislav Petkov mcg_status |= MCG_STATUS_RIPV; 52721afaf18SBorislav Petkov 52821afaf18SBorislav Petkov /* 52921afaf18SBorislav Petkov * Ensure necessary status bits for deferred errors: 53021afaf18SBorislav Petkov * - MCx_STATUS[Deferred]: make sure it is a deferred error 53121afaf18SBorislav Petkov * - MCx_STATUS[UC] cleared: deferred errors are _not_ UC 53221afaf18SBorislav Petkov */ 53321afaf18SBorislav Petkov if (inj_type == DFR_INT_INJ) { 53421afaf18SBorislav Petkov i_mce.status |= MCI_STATUS_DEFERRED; 5355d7f7d1dSZhenzhong Duan i_mce.status &= ~MCI_STATUS_UC; 53621afaf18SBorislav Petkov } 53721afaf18SBorislav Petkov 53821afaf18SBorislav Petkov /* 53921afaf18SBorislav Petkov * For multi node CPUs, logging and reporting of bank 4 errors happens 54021afaf18SBorislav Petkov * only on the node base core. Refer to D18F3x44[NbMcaToMstCpuEn] for 54121afaf18SBorislav Petkov * Fam10h and later BKDGs. 54221afaf18SBorislav Petkov */ 54367e87d43SBorislav Petkov if (boot_cpu_has(X86_FEATURE_AMD_DCM) && 54421afaf18SBorislav Petkov b == 4 && 54521afaf18SBorislav Petkov boot_cpu_data.x86 < 0x17) { 546db970bd2SYazen Ghannam toggle_nb_mca_mst_cpu(topology_die_id(cpu)); 547db970bd2SYazen Ghannam cpu = get_nbc_for_node(topology_die_id(cpu)); 54821afaf18SBorislav Petkov } 54921afaf18SBorislav Petkov 5508ae9e3f6SSebastian Andrzej Siewior cpus_read_lock(); 55121afaf18SBorislav Petkov if (!cpu_online(cpu)) 55221afaf18SBorislav Petkov goto err; 55321afaf18SBorislav Petkov 55421afaf18SBorislav Petkov toggle_hw_mce_inject(cpu, true); 55521afaf18SBorislav Petkov 55621afaf18SBorislav Petkov i_mce.mcgstatus = mcg_status; 55721afaf18SBorislav Petkov i_mce.inject_flags = inj_type; 55821afaf18SBorislav Petkov smp_call_function_single(cpu, prepare_msrs, &i_mce, 0); 55921afaf18SBorislav Petkov 56021afaf18SBorislav Petkov toggle_hw_mce_inject(cpu, false); 56121afaf18SBorislav Petkov 56221afaf18SBorislav Petkov switch (inj_type) { 56321afaf18SBorislav Petkov case DFR_INT_INJ: 56421afaf18SBorislav Petkov smp_call_function_single(cpu, trigger_dfr_int, NULL, 0); 56521afaf18SBorislav Petkov break; 56621afaf18SBorislav Petkov case THR_INT_INJ: 56721afaf18SBorislav Petkov smp_call_function_single(cpu, trigger_thr_int, NULL, 0); 56821afaf18SBorislav Petkov break; 56921afaf18SBorislav Petkov default: 57021afaf18SBorislav Petkov smp_call_function_single(cpu, trigger_mce, NULL, 0); 57121afaf18SBorislav Petkov } 57221afaf18SBorislav Petkov 57321afaf18SBorislav Petkov err: 5748ae9e3f6SSebastian Andrzej Siewior cpus_read_unlock(); 57521afaf18SBorislav Petkov 57621afaf18SBorislav Petkov } 57721afaf18SBorislav Petkov 57821afaf18SBorislav Petkov /* 57921afaf18SBorislav Petkov * This denotes into which bank we're injecting and triggers 58021afaf18SBorislav Petkov * the injection, at the same time. 58121afaf18SBorislav Petkov */ 58221afaf18SBorislav Petkov static int inj_bank_set(void *data, u64 val) 58321afaf18SBorislav Petkov { 58421afaf18SBorislav Petkov struct mce *m = (struct mce *)data; 585006c0770SYazen Ghannam u8 n_banks; 586006c0770SYazen Ghannam u64 cap; 587006c0770SYazen Ghannam 588006c0770SYazen Ghannam /* Get bank count on target CPU so we can handle non-uniform values. */ 589006c0770SYazen Ghannam rdmsrl_on_cpu(m->extcpu, MSR_IA32_MCG_CAP, &cap); 590006c0770SYazen Ghannam n_banks = cap & MCG_BANKCNT_MASK; 59121afaf18SBorislav Petkov 59221afaf18SBorislav Petkov if (val >= n_banks) { 593006c0770SYazen Ghannam pr_err("MCA bank %llu non-existent on CPU%d\n", val, m->extcpu); 59421afaf18SBorislav Petkov return -EINVAL; 59521afaf18SBorislav Petkov } 59621afaf18SBorislav Petkov 59721afaf18SBorislav Petkov m->bank = val; 598e48d008bSSmita Koralahalli 599e48d008bSSmita Koralahalli /* 600e48d008bSSmita Koralahalli * sw-only injection allows to write arbitrary values into the MCA 601e48d008bSSmita Koralahalli * registers because it tests only the decoding paths. 602e48d008bSSmita Koralahalli */ 603e48d008bSSmita Koralahalli if (inj_type == SW_INJ) 604e48d008bSSmita Koralahalli goto inject; 605e48d008bSSmita Koralahalli 606e48d008bSSmita Koralahalli /* 607e48d008bSSmita Koralahalli * Read IPID value to determine if a bank is populated on the target 608e48d008bSSmita Koralahalli * CPU. 609e48d008bSSmita Koralahalli */ 610e48d008bSSmita Koralahalli if (cpu_feature_enabled(X86_FEATURE_SMCA)) { 611e48d008bSSmita Koralahalli u64 ipid; 612e48d008bSSmita Koralahalli 613e48d008bSSmita Koralahalli if (rdmsrl_on_cpu(m->extcpu, MSR_AMD64_SMCA_MCx_IPID(val), &ipid)) { 614e48d008bSSmita Koralahalli pr_err("Error reading IPID on CPU%d\n", m->extcpu); 615e48d008bSSmita Koralahalli return -EINVAL; 616e48d008bSSmita Koralahalli } 617e48d008bSSmita Koralahalli 618e48d008bSSmita Koralahalli if (!ipid) { 619e48d008bSSmita Koralahalli pr_err("Cannot inject into unpopulated bank %llu\n", val); 620e48d008bSSmita Koralahalli return -ENODEV; 621e48d008bSSmita Koralahalli } 622e48d008bSSmita Koralahalli } 623e48d008bSSmita Koralahalli 624e48d008bSSmita Koralahalli inject: 62521afaf18SBorislav Petkov do_inject(); 62621afaf18SBorislav Petkov 62721afaf18SBorislav Petkov /* Reset injection struct */ 62821afaf18SBorislav Petkov setup_inj_struct(&i_mce); 62921afaf18SBorislav Petkov 63021afaf18SBorislav Petkov return 0; 63121afaf18SBorislav Petkov } 63221afaf18SBorislav Petkov 63321afaf18SBorislav Petkov MCE_INJECT_GET(bank); 63421afaf18SBorislav Petkov 63521afaf18SBorislav Petkov DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n"); 63621afaf18SBorislav Petkov 63721afaf18SBorislav Petkov static const char readme_msg[] = 63821afaf18SBorislav Petkov "Description of the files and their usages:\n" 63921afaf18SBorislav Petkov "\n" 64021afaf18SBorislav Petkov "Note1: i refers to the bank number below.\n" 64121afaf18SBorislav Petkov "Note2: See respective BKDGs for the exact bit definitions of the files below\n" 64221afaf18SBorislav Petkov "as they mirror the hardware registers.\n" 64321afaf18SBorislav Petkov "\n" 64421afaf18SBorislav Petkov "status:\t Set MCi_STATUS: the bits in that MSR control the error type and\n" 64521afaf18SBorislav Petkov "\t attributes of the error which caused the MCE.\n" 64621afaf18SBorislav Petkov "\n" 64721afaf18SBorislav Petkov "misc:\t Set MCi_MISC: provide auxiliary info about the error. It is mostly\n" 64821afaf18SBorislav Petkov "\t used for error thresholding purposes and its validity is indicated by\n" 64921afaf18SBorislav Petkov "\t MCi_STATUS[MiscV].\n" 65021afaf18SBorislav Petkov "\n" 65121afaf18SBorislav Petkov "synd:\t Set MCi_SYND: provide syndrome info about the error. Only valid on\n" 65221afaf18SBorislav Petkov "\t Scalable MCA systems, and its validity is indicated by MCi_STATUS[SyndV].\n" 65321afaf18SBorislav Petkov "\n" 65421afaf18SBorislav Petkov "addr:\t Error address value to be written to MCi_ADDR. Log address information\n" 65521afaf18SBorislav Petkov "\t associated with the error.\n" 65621afaf18SBorislav Petkov "\n" 65721afaf18SBorislav Petkov "cpu:\t The CPU to inject the error on.\n" 65821afaf18SBorislav Petkov "\n" 65921afaf18SBorislav Petkov "bank:\t Specify the bank you want to inject the error into: the number of\n" 66021afaf18SBorislav Petkov "\t banks in a processor varies and is family/model-specific, therefore, the\n" 66121afaf18SBorislav Petkov "\t supplied value is sanity-checked. Setting the bank value also triggers the\n" 66221afaf18SBorislav Petkov "\t injection.\n" 66321afaf18SBorislav Petkov "\n" 66421afaf18SBorislav Petkov "flags:\t Injection type to be performed. Writing to this file will trigger a\n" 66521afaf18SBorislav Petkov "\t real machine check, an APIC interrupt or invoke the error decoder routines\n" 66621afaf18SBorislav Petkov "\t for AMD processors.\n" 66721afaf18SBorislav Petkov "\n" 66821afaf18SBorislav Petkov "\t Allowed error injection types:\n" 66921afaf18SBorislav Petkov "\t - \"sw\": Software error injection. Decode error to a human-readable \n" 67021afaf18SBorislav Petkov "\t format only. Safe to use.\n" 67121afaf18SBorislav Petkov "\t - \"hw\": Hardware error injection. Causes the #MC exception handler to \n" 67221afaf18SBorislav Petkov "\t handle the error. Be warned: might cause system panic if MCi_STATUS[PCC] \n" 67321afaf18SBorislav Petkov "\t is set. Therefore, consider setting (debugfs_mountpoint)/mce/fake_panic \n" 67421afaf18SBorislav Petkov "\t before injecting.\n" 67521afaf18SBorislav Petkov "\t - \"df\": Trigger APIC interrupt for Deferred error. Causes deferred \n" 67621afaf18SBorislav Petkov "\t error APIC interrupt handler to handle the error if the feature is \n" 67721afaf18SBorislav Petkov "\t is present in hardware. \n" 67821afaf18SBorislav Petkov "\t - \"th\": Trigger APIC interrupt for Threshold errors. Causes threshold \n" 67921afaf18SBorislav Petkov "\t APIC interrupt handler to handle the error. \n" 6802ffdc2c3SBorislav Petkov "\n" 6812ffdc2c3SBorislav Petkov "ipid:\t IPID (AMD-specific)\n" 68221afaf18SBorislav Petkov "\n"; 68321afaf18SBorislav Petkov 68421afaf18SBorislav Petkov static ssize_t 68521afaf18SBorislav Petkov inj_readme_read(struct file *filp, char __user *ubuf, 68621afaf18SBorislav Petkov size_t cnt, loff_t *ppos) 68721afaf18SBorislav Petkov { 68821afaf18SBorislav Petkov return simple_read_from_buffer(ubuf, cnt, ppos, 68921afaf18SBorislav Petkov readme_msg, strlen(readme_msg)); 69021afaf18SBorislav Petkov } 69121afaf18SBorislav Petkov 69221afaf18SBorislav Petkov static const struct file_operations readme_fops = { 69321afaf18SBorislav Petkov .read = inj_readme_read, 69421afaf18SBorislav Petkov }; 69521afaf18SBorislav Petkov 69621afaf18SBorislav Petkov static struct dfs_node { 69721afaf18SBorislav Petkov char *name; 69821afaf18SBorislav Petkov const struct file_operations *fops; 69921afaf18SBorislav Petkov umode_t perm; 70021afaf18SBorislav Petkov } dfs_fls[] = { 70121afaf18SBorislav Petkov { .name = "status", .fops = &status_fops, .perm = S_IRUSR | S_IWUSR }, 70221afaf18SBorislav Petkov { .name = "misc", .fops = &misc_fops, .perm = S_IRUSR | S_IWUSR }, 70321afaf18SBorislav Petkov { .name = "addr", .fops = &addr_fops, .perm = S_IRUSR | S_IWUSR }, 70421afaf18SBorislav Petkov { .name = "synd", .fops = &synd_fops, .perm = S_IRUSR | S_IWUSR }, 7052ffdc2c3SBorislav Petkov { .name = "ipid", .fops = &ipid_fops, .perm = S_IRUSR | S_IWUSR }, 70621afaf18SBorislav Petkov { .name = "bank", .fops = &bank_fops, .perm = S_IRUSR | S_IWUSR }, 70721afaf18SBorislav Petkov { .name = "flags", .fops = &flags_fops, .perm = S_IRUSR | S_IWUSR }, 70821afaf18SBorislav Petkov { .name = "cpu", .fops = &extcpu_fops, .perm = S_IRUSR | S_IWUSR }, 70921afaf18SBorislav Petkov { .name = "README", .fops = &readme_fops, .perm = S_IRUSR | S_IRGRP | S_IROTH }, 71021afaf18SBorislav Petkov }; 71121afaf18SBorislav Petkov 7126e4f929eSGreg Kroah-Hartman static void __init debugfs_init(void) 71321afaf18SBorislav Petkov { 71421afaf18SBorislav Petkov unsigned int i; 71521afaf18SBorislav Petkov 71621afaf18SBorislav Petkov dfs_inj = debugfs_create_dir("mce-inject", NULL); 71721afaf18SBorislav Petkov 7186e4f929eSGreg Kroah-Hartman for (i = 0; i < ARRAY_SIZE(dfs_fls); i++) 7196e4f929eSGreg Kroah-Hartman debugfs_create_file(dfs_fls[i].name, dfs_fls[i].perm, dfs_inj, 7206e4f929eSGreg Kroah-Hartman &i_mce, dfs_fls[i].fops); 72121afaf18SBorislav Petkov } 72221afaf18SBorislav Petkov 723891e465aSSmita Koralahalli static void check_hw_inj_possible(void) 724891e465aSSmita Koralahalli { 725891e465aSSmita Koralahalli int cpu; 726891e465aSSmita Koralahalli u8 bank; 727891e465aSSmita Koralahalli 728891e465aSSmita Koralahalli /* 729891e465aSSmita Koralahalli * This behavior exists only on SMCA systems though its not directly 730891e465aSSmita Koralahalli * related to SMCA. 731891e465aSSmita Koralahalli */ 732891e465aSSmita Koralahalli if (!cpu_feature_enabled(X86_FEATURE_SMCA)) 733891e465aSSmita Koralahalli return; 734891e465aSSmita Koralahalli 735891e465aSSmita Koralahalli cpu = get_cpu(); 736891e465aSSmita Koralahalli 737891e465aSSmita Koralahalli for (bank = 0; bank < MAX_NR_BANKS; ++bank) { 738891e465aSSmita Koralahalli u64 status = MCI_STATUS_VAL, ipid; 739891e465aSSmita Koralahalli 740891e465aSSmita Koralahalli /* Check whether bank is populated */ 741891e465aSSmita Koralahalli rdmsrl(MSR_AMD64_SMCA_MCx_IPID(bank), ipid); 742891e465aSSmita Koralahalli if (!ipid) 743891e465aSSmita Koralahalli continue; 744891e465aSSmita Koralahalli 745891e465aSSmita Koralahalli toggle_hw_mce_inject(cpu, true); 746891e465aSSmita Koralahalli 747891e465aSSmita Koralahalli wrmsrl_safe(mca_msr_reg(bank, MCA_STATUS), status); 748891e465aSSmita Koralahalli rdmsrl_safe(mca_msr_reg(bank, MCA_STATUS), &status); 749*6175b407SYazen Ghannam wrmsrl_safe(mca_msr_reg(bank, MCA_STATUS), 0); 750891e465aSSmita Koralahalli 751891e465aSSmita Koralahalli if (!status) { 752891e465aSSmita Koralahalli hw_injection_possible = false; 753891e465aSSmita Koralahalli pr_warn("Platform does not allow *hardware* error injection." 754891e465aSSmita Koralahalli "Try using APEI EINJ instead.\n"); 755891e465aSSmita Koralahalli } 756891e465aSSmita Koralahalli 757891e465aSSmita Koralahalli toggle_hw_mce_inject(cpu, false); 758891e465aSSmita Koralahalli 759891e465aSSmita Koralahalli break; 760891e465aSSmita Koralahalli } 761891e465aSSmita Koralahalli 762891e465aSSmita Koralahalli put_cpu(); 763891e465aSSmita Koralahalli } 764891e465aSSmita Koralahalli 76521afaf18SBorislav Petkov static int __init inject_init(void) 76621afaf18SBorislav Petkov { 76721afaf18SBorislav Petkov if (!alloc_cpumask_var(&mce_inject_cpumask, GFP_KERNEL)) 76821afaf18SBorislav Petkov return -ENOMEM; 76921afaf18SBorislav Petkov 770891e465aSSmita Koralahalli check_hw_inj_possible(); 771891e465aSSmita Koralahalli 7726e4f929eSGreg Kroah-Hartman debugfs_init(); 77321afaf18SBorislav Petkov 77421afaf18SBorislav Petkov register_nmi_handler(NMI_LOCAL, mce_raise_notify, 0, "mce_notify"); 77521afaf18SBorislav Petkov mce_register_injector_chain(&inject_nb); 77621afaf18SBorislav Petkov 77721afaf18SBorislav Petkov setup_inj_struct(&i_mce); 77821afaf18SBorislav Petkov 77921afaf18SBorislav Petkov pr_info("Machine check injector initialized\n"); 78021afaf18SBorislav Petkov 78121afaf18SBorislav Petkov return 0; 78221afaf18SBorislav Petkov } 78321afaf18SBorislav Petkov 78421afaf18SBorislav Petkov static void __exit inject_exit(void) 78521afaf18SBorislav Petkov { 78621afaf18SBorislav Petkov 78721afaf18SBorislav Petkov mce_unregister_injector_chain(&inject_nb); 78821afaf18SBorislav Petkov unregister_nmi_handler(NMI_LOCAL, "mce_notify"); 78921afaf18SBorislav Petkov 79021afaf18SBorislav Petkov debugfs_remove_recursive(dfs_inj); 79121afaf18SBorislav Petkov dfs_inj = NULL; 79221afaf18SBorislav Petkov 79321afaf18SBorislav Petkov memset(&dfs_fls, 0, sizeof(dfs_fls)); 79421afaf18SBorislav Petkov 79521afaf18SBorislav Petkov free_cpumask_var(mce_inject_cpumask); 79621afaf18SBorislav Petkov } 79721afaf18SBorislav Petkov 79821afaf18SBorislav Petkov module_init(inject_init); 79921afaf18SBorislav Petkov module_exit(inject_exit); 80021afaf18SBorislav Petkov MODULE_LICENSE("GPL"); 801