Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Machine check injection support.
0004  * Copyright 2008 Intel Corporation.
0005  *
0006  * Authors:
0007  * Andi Kleen
0008  * Ying Huang
0009  *
0010  * The AMD part (from mce_amd_inj.c): a simple MCE injection facility
0011  * for testing different aspects of the RAS code. This driver should be
0012  * built as module so that it can be loaded on production kernels for
0013  * testing purposes.
0014  *
0015  * Copyright (c) 2010-17:  Borislav Petkov <bp@alien8.de>
0016  *             Advanced Micro Devices Inc.
0017  */
0018 
0019 #include <linux/cpu.h>
0020 #include <linux/debugfs.h>
0021 #include <linux/kernel.h>
0022 #include <linux/module.h>
0023 #include <linux/notifier.h>
0024 #include <linux/pci.h>
0025 #include <linux/uaccess.h>
0026 
0027 #include <asm/amd_nb.h>
0028 #include <asm/apic.h>
0029 #include <asm/irq_vectors.h>
0030 #include <asm/mce.h>
0031 #include <asm/nmi.h>
0032 #include <asm/smp.h>
0033 
0034 #include "internal.h"
0035 
0036 static bool hw_injection_possible = true;
0037 
0038 /*
0039  * Collect all the MCi_XXX settings
0040  */
0041 static struct mce i_mce;
0042 static struct dentry *dfs_inj;
0043 
0044 #define MAX_FLAG_OPT_SIZE   4
0045 #define NBCFG           0x44
0046 
0047 enum injection_type {
0048     SW_INJ = 0, /* SW injection, simply decode the error */
0049     HW_INJ,     /* Trigger a #MC */
0050     DFR_INT_INJ,    /* Trigger Deferred error interrupt */
0051     THR_INT_INJ,    /* Trigger threshold interrupt */
0052     N_INJ_TYPES,
0053 };
0054 
0055 static const char * const flags_options[] = {
0056     [SW_INJ] = "sw",
0057     [HW_INJ] = "hw",
0058     [DFR_INT_INJ] = "df",
0059     [THR_INT_INJ] = "th",
0060     NULL
0061 };
0062 
0063 /* Set default injection to SW_INJ */
0064 static enum injection_type inj_type = SW_INJ;
0065 
0066 #define MCE_INJECT_SET(reg)                     \
0067 static int inj_##reg##_set(void *data, u64 val)             \
0068 {                                   \
0069     struct mce *m = (struct mce *)data;             \
0070                                     \
0071     m->reg = val;                           \
0072     return 0;                           \
0073 }
0074 
0075 MCE_INJECT_SET(status);
0076 MCE_INJECT_SET(misc);
0077 MCE_INJECT_SET(addr);
0078 MCE_INJECT_SET(synd);
0079 
0080 #define MCE_INJECT_GET(reg)                     \
0081 static int inj_##reg##_get(void *data, u64 *val)            \
0082 {                                   \
0083     struct mce *m = (struct mce *)data;             \
0084                                     \
0085     *val = m->reg;                          \
0086     return 0;                           \
0087 }
0088 
0089 MCE_INJECT_GET(status);
0090 MCE_INJECT_GET(misc);
0091 MCE_INJECT_GET(addr);
0092 MCE_INJECT_GET(synd);
0093 MCE_INJECT_GET(ipid);
0094 
0095 DEFINE_SIMPLE_ATTRIBUTE(status_fops, inj_status_get, inj_status_set, "%llx\n");
0096 DEFINE_SIMPLE_ATTRIBUTE(misc_fops, inj_misc_get, inj_misc_set, "%llx\n");
0097 DEFINE_SIMPLE_ATTRIBUTE(addr_fops, inj_addr_get, inj_addr_set, "%llx\n");
0098 DEFINE_SIMPLE_ATTRIBUTE(synd_fops, inj_synd_get, inj_synd_set, "%llx\n");
0099 
0100 /* Use the user provided IPID value on a sw injection. */
0101 static int inj_ipid_set(void *data, u64 val)
0102 {
0103     struct mce *m = (struct mce *)data;
0104 
0105     if (cpu_feature_enabled(X86_FEATURE_SMCA)) {
0106         if (inj_type == SW_INJ)
0107             m->ipid = val;
0108     }
0109 
0110     return 0;
0111 }
0112 
0113 DEFINE_SIMPLE_ATTRIBUTE(ipid_fops, inj_ipid_get, inj_ipid_set, "%llx\n");
0114 
0115 static void setup_inj_struct(struct mce *m)
0116 {
0117     memset(m, 0, sizeof(struct mce));
0118 
0119     m->cpuvendor = boot_cpu_data.x86_vendor;
0120     m->time      = ktime_get_real_seconds();
0121     m->cpuid     = cpuid_eax(1);
0122     m->microcode = boot_cpu_data.microcode;
0123 }
0124 
0125 /* Update fake mce registers on current CPU. */
0126 static void inject_mce(struct mce *m)
0127 {
0128     struct mce *i = &per_cpu(injectm, m->extcpu);
0129 
0130     /* Make sure no one reads partially written injectm */
0131     i->finished = 0;
0132     mb();
0133     m->finished = 0;
0134     /* First set the fields after finished */
0135     i->extcpu = m->extcpu;
0136     mb();
0137     /* Now write record in order, finished last (except above) */
0138     memcpy(i, m, sizeof(struct mce));
0139     /* Finally activate it */
0140     mb();
0141     i->finished = 1;
0142 }
0143 
0144 static void raise_poll(struct mce *m)
0145 {
0146     unsigned long flags;
0147     mce_banks_t b;
0148 
0149     memset(&b, 0xff, sizeof(mce_banks_t));
0150     local_irq_save(flags);
0151     machine_check_poll(0, &b);
0152     local_irq_restore(flags);
0153     m->finished = 0;
0154 }
0155 
0156 static void raise_exception(struct mce *m, struct pt_regs *pregs)
0157 {
0158     struct pt_regs regs;
0159     unsigned long flags;
0160 
0161     if (!pregs) {
0162         memset(&regs, 0, sizeof(struct pt_regs));
0163         regs.ip = m->ip;
0164         regs.cs = m->cs;
0165         pregs = &regs;
0166     }
0167     /* do_machine_check() expects interrupts disabled -- at least */
0168     local_irq_save(flags);
0169     do_machine_check(pregs);
0170     local_irq_restore(flags);
0171     m->finished = 0;
0172 }
0173 
0174 static cpumask_var_t mce_inject_cpumask;
0175 static DEFINE_MUTEX(mce_inject_mutex);
0176 
0177 static int mce_raise_notify(unsigned int cmd, struct pt_regs *regs)
0178 {
0179     int cpu = smp_processor_id();
0180     struct mce *m = this_cpu_ptr(&injectm);
0181     if (!cpumask_test_cpu(cpu, mce_inject_cpumask))
0182         return NMI_DONE;
0183     cpumask_clear_cpu(cpu, mce_inject_cpumask);
0184     if (m->inject_flags & MCJ_EXCEPTION)
0185         raise_exception(m, regs);
0186     else if (m->status)
0187         raise_poll(m);
0188     return NMI_HANDLED;
0189 }
0190 
0191 static void mce_irq_ipi(void *info)
0192 {
0193     int cpu = smp_processor_id();
0194     struct mce *m = this_cpu_ptr(&injectm);
0195 
0196     if (cpumask_test_cpu(cpu, mce_inject_cpumask) &&
0197             m->inject_flags & MCJ_EXCEPTION) {
0198         cpumask_clear_cpu(cpu, mce_inject_cpumask);
0199         raise_exception(m, NULL);
0200     }
0201 }
0202 
0203 /* Inject mce on current CPU */
0204 static int raise_local(void)
0205 {
0206     struct mce *m = this_cpu_ptr(&injectm);
0207     int context = MCJ_CTX(m->inject_flags);
0208     int ret = 0;
0209     int cpu = m->extcpu;
0210 
0211     if (m->inject_flags & MCJ_EXCEPTION) {
0212         pr_info("Triggering MCE exception on CPU %d\n", cpu);
0213         switch (context) {
0214         case MCJ_CTX_IRQ:
0215             /*
0216              * Could do more to fake interrupts like
0217              * calling irq_enter, but the necessary
0218              * machinery isn't exported currently.
0219              */
0220             fallthrough;
0221         case MCJ_CTX_PROCESS:
0222             raise_exception(m, NULL);
0223             break;
0224         default:
0225             pr_info("Invalid MCE context\n");
0226             ret = -EINVAL;
0227         }
0228         pr_info("MCE exception done on CPU %d\n", cpu);
0229     } else if (m->status) {
0230         pr_info("Starting machine check poll CPU %d\n", cpu);
0231         raise_poll(m);
0232         mce_notify_irq();
0233         pr_info("Machine check poll done on CPU %d\n", cpu);
0234     } else
0235         m->finished = 0;
0236 
0237     return ret;
0238 }
0239 
0240 static void __maybe_unused raise_mce(struct mce *m)
0241 {
0242     int context = MCJ_CTX(m->inject_flags);
0243 
0244     inject_mce(m);
0245 
0246     if (context == MCJ_CTX_RANDOM)
0247         return;
0248 
0249     if (m->inject_flags & (MCJ_IRQ_BROADCAST | MCJ_NMI_BROADCAST)) {
0250         unsigned long start;
0251         int cpu;
0252 
0253         cpus_read_lock();
0254         cpumask_copy(mce_inject_cpumask, cpu_online_mask);
0255         cpumask_clear_cpu(get_cpu(), mce_inject_cpumask);
0256         for_each_online_cpu(cpu) {
0257             struct mce *mcpu = &per_cpu(injectm, cpu);
0258             if (!mcpu->finished ||
0259                 MCJ_CTX(mcpu->inject_flags) != MCJ_CTX_RANDOM)
0260                 cpumask_clear_cpu(cpu, mce_inject_cpumask);
0261         }
0262         if (!cpumask_empty(mce_inject_cpumask)) {
0263             if (m->inject_flags & MCJ_IRQ_BROADCAST) {
0264                 /*
0265                  * don't wait because mce_irq_ipi is necessary
0266                  * to be sync with following raise_local
0267                  */
0268                 preempt_disable();
0269                 smp_call_function_many(mce_inject_cpumask,
0270                     mce_irq_ipi, NULL, 0);
0271                 preempt_enable();
0272             } else if (m->inject_flags & MCJ_NMI_BROADCAST)
0273                 apic->send_IPI_mask(mce_inject_cpumask,
0274                         NMI_VECTOR);
0275         }
0276         start = jiffies;
0277         while (!cpumask_empty(mce_inject_cpumask)) {
0278             if (!time_before(jiffies, start + 2*HZ)) {
0279                 pr_err("Timeout waiting for mce inject %lx\n",
0280                     *cpumask_bits(mce_inject_cpumask));
0281                 break;
0282             }
0283             cpu_relax();
0284         }
0285         raise_local();
0286         put_cpu();
0287         cpus_read_unlock();
0288     } else {
0289         preempt_disable();
0290         raise_local();
0291         preempt_enable();
0292     }
0293 }
0294 
0295 static int mce_inject_raise(struct notifier_block *nb, unsigned long val,
0296                 void *data)
0297 {
0298     struct mce *m = (struct mce *)data;
0299 
0300     if (!m)
0301         return NOTIFY_DONE;
0302 
0303     mutex_lock(&mce_inject_mutex);
0304     raise_mce(m);
0305     mutex_unlock(&mce_inject_mutex);
0306 
0307     return NOTIFY_DONE;
0308 }
0309 
0310 static struct notifier_block inject_nb = {
0311     .notifier_call  = mce_inject_raise,
0312 };
0313 
0314 /*
0315  * Caller needs to be make sure this cpu doesn't disappear
0316  * from under us, i.e.: get_cpu/put_cpu.
0317  */
0318 static int toggle_hw_mce_inject(unsigned int cpu, bool enable)
0319 {
0320     u32 l, h;
0321     int err;
0322 
0323     err = rdmsr_on_cpu(cpu, MSR_K7_HWCR, &l, &h);
0324     if (err) {
0325         pr_err("%s: error reading HWCR\n", __func__);
0326         return err;
0327     }
0328 
0329     enable ? (l |= BIT(18)) : (l &= ~BIT(18));
0330 
0331     err = wrmsr_on_cpu(cpu, MSR_K7_HWCR, l, h);
0332     if (err)
0333         pr_err("%s: error writing HWCR\n", __func__);
0334 
0335     return err;
0336 }
0337 
0338 static int __set_inj(const char *buf)
0339 {
0340     int i;
0341 
0342     for (i = 0; i < N_INJ_TYPES; i++) {
0343         if (!strncmp(flags_options[i], buf, strlen(flags_options[i]))) {
0344             if (i > SW_INJ && !hw_injection_possible)
0345                 continue;
0346             inj_type = i;
0347             return 0;
0348         }
0349     }
0350     return -EINVAL;
0351 }
0352 
0353 static ssize_t flags_read(struct file *filp, char __user *ubuf,
0354               size_t cnt, loff_t *ppos)
0355 {
0356     char buf[MAX_FLAG_OPT_SIZE];
0357     int n;
0358 
0359     n = sprintf(buf, "%s\n", flags_options[inj_type]);
0360 
0361     return simple_read_from_buffer(ubuf, cnt, ppos, buf, n);
0362 }
0363 
0364 static ssize_t flags_write(struct file *filp, const char __user *ubuf,
0365                size_t cnt, loff_t *ppos)
0366 {
0367     char buf[MAX_FLAG_OPT_SIZE], *__buf;
0368     int err;
0369 
0370     if (!cnt || cnt > MAX_FLAG_OPT_SIZE)
0371         return -EINVAL;
0372 
0373     if (copy_from_user(&buf, ubuf, cnt))
0374         return -EFAULT;
0375 
0376     buf[cnt - 1] = 0;
0377 
0378     /* strip whitespace */
0379     __buf = strstrip(buf);
0380 
0381     err = __set_inj(__buf);
0382     if (err) {
0383         pr_err("%s: Invalid flags value: %s\n", __func__, __buf);
0384         return err;
0385     }
0386 
0387     *ppos += cnt;
0388 
0389     return cnt;
0390 }
0391 
0392 static const struct file_operations flags_fops = {
0393     .read           = flags_read,
0394     .write          = flags_write,
0395     .llseek         = generic_file_llseek,
0396 };
0397 
0398 /*
0399  * On which CPU to inject?
0400  */
0401 MCE_INJECT_GET(extcpu);
0402 
0403 static int inj_extcpu_set(void *data, u64 val)
0404 {
0405     struct mce *m = (struct mce *)data;
0406 
0407     if (val >= nr_cpu_ids || !cpu_online(val)) {
0408         pr_err("%s: Invalid CPU: %llu\n", __func__, val);
0409         return -EINVAL;
0410     }
0411     m->extcpu = val;
0412     return 0;
0413 }
0414 
0415 DEFINE_SIMPLE_ATTRIBUTE(extcpu_fops, inj_extcpu_get, inj_extcpu_set, "%llu\n");
0416 
0417 static void trigger_mce(void *info)
0418 {
0419     asm volatile("int $18");
0420 }
0421 
0422 static void trigger_dfr_int(void *info)
0423 {
0424     asm volatile("int %0" :: "i" (DEFERRED_ERROR_VECTOR));
0425 }
0426 
0427 static void trigger_thr_int(void *info)
0428 {
0429     asm volatile("int %0" :: "i" (THRESHOLD_APIC_VECTOR));
0430 }
0431 
0432 static u32 get_nbc_for_node(int node_id)
0433 {
0434     struct cpuinfo_x86 *c = &boot_cpu_data;
0435     u32 cores_per_node;
0436 
0437     cores_per_node = (c->x86_max_cores * smp_num_siblings) / amd_get_nodes_per_socket();
0438 
0439     return cores_per_node * node_id;
0440 }
0441 
0442 static void toggle_nb_mca_mst_cpu(u16 nid)
0443 {
0444     struct amd_northbridge *nb;
0445     struct pci_dev *F3;
0446     u32 val;
0447     int err;
0448 
0449     nb = node_to_amd_nb(nid);
0450     if (!nb)
0451         return;
0452 
0453     F3 = nb->misc;
0454     if (!F3)
0455         return;
0456 
0457     err = pci_read_config_dword(F3, NBCFG, &val);
0458     if (err) {
0459         pr_err("%s: Error reading F%dx%03x.\n",
0460                __func__, PCI_FUNC(F3->devfn), NBCFG);
0461         return;
0462     }
0463 
0464     if (val & BIT(27))
0465         return;
0466 
0467     pr_err("%s: Set D18F3x44[NbMcaToMstCpuEn] which BIOS hasn't done.\n",
0468            __func__);
0469 
0470     val |= BIT(27);
0471     err = pci_write_config_dword(F3, NBCFG, val);
0472     if (err)
0473         pr_err("%s: Error writing F%dx%03x.\n",
0474                __func__, PCI_FUNC(F3->devfn), NBCFG);
0475 }
0476 
0477 static void prepare_msrs(void *info)
0478 {
0479     struct mce m = *(struct mce *)info;
0480     u8 b = m.bank;
0481 
0482     wrmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
0483 
0484     if (boot_cpu_has(X86_FEATURE_SMCA)) {
0485         if (m.inject_flags == DFR_INT_INJ) {
0486             wrmsrl(MSR_AMD64_SMCA_MCx_DESTAT(b), m.status);
0487             wrmsrl(MSR_AMD64_SMCA_MCx_DEADDR(b), m.addr);
0488         } else {
0489             wrmsrl(MSR_AMD64_SMCA_MCx_STATUS(b), m.status);
0490             wrmsrl(MSR_AMD64_SMCA_MCx_ADDR(b), m.addr);
0491         }
0492 
0493         wrmsrl(MSR_AMD64_SMCA_MCx_MISC(b), m.misc);
0494         wrmsrl(MSR_AMD64_SMCA_MCx_SYND(b), m.synd);
0495     } else {
0496         wrmsrl(MSR_IA32_MCx_STATUS(b), m.status);
0497         wrmsrl(MSR_IA32_MCx_ADDR(b), m.addr);
0498         wrmsrl(MSR_IA32_MCx_MISC(b), m.misc);
0499     }
0500 }
0501 
0502 static void do_inject(void)
0503 {
0504     u64 mcg_status = 0;
0505     unsigned int cpu = i_mce.extcpu;
0506     u8 b = i_mce.bank;
0507 
0508     i_mce.tsc = rdtsc_ordered();
0509 
0510     i_mce.status |= MCI_STATUS_VAL;
0511 
0512     if (i_mce.misc)
0513         i_mce.status |= MCI_STATUS_MISCV;
0514 
0515     if (i_mce.synd)
0516         i_mce.status |= MCI_STATUS_SYNDV;
0517 
0518     if (inj_type == SW_INJ) {
0519         mce_log(&i_mce);
0520         return;
0521     }
0522 
0523     /* prep MCE global settings for the injection */
0524     mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
0525 
0526     if (!(i_mce.status & MCI_STATUS_PCC))
0527         mcg_status |= MCG_STATUS_RIPV;
0528 
0529     /*
0530      * Ensure necessary status bits for deferred errors:
0531      * - MCx_STATUS[Deferred]: make sure it is a deferred error
0532      * - MCx_STATUS[UC] cleared: deferred errors are _not_ UC
0533      */
0534     if (inj_type == DFR_INT_INJ) {
0535         i_mce.status |= MCI_STATUS_DEFERRED;
0536         i_mce.status &= ~MCI_STATUS_UC;
0537     }
0538 
0539     /*
0540      * For multi node CPUs, logging and reporting of bank 4 errors happens
0541      * only on the node base core. Refer to D18F3x44[NbMcaToMstCpuEn] for
0542      * Fam10h and later BKDGs.
0543      */
0544     if (boot_cpu_has(X86_FEATURE_AMD_DCM) &&
0545         b == 4 &&
0546         boot_cpu_data.x86 < 0x17) {
0547         toggle_nb_mca_mst_cpu(topology_die_id(cpu));
0548         cpu = get_nbc_for_node(topology_die_id(cpu));
0549     }
0550 
0551     cpus_read_lock();
0552     if (!cpu_online(cpu))
0553         goto err;
0554 
0555     toggle_hw_mce_inject(cpu, true);
0556 
0557     i_mce.mcgstatus = mcg_status;
0558     i_mce.inject_flags = inj_type;
0559     smp_call_function_single(cpu, prepare_msrs, &i_mce, 0);
0560 
0561     toggle_hw_mce_inject(cpu, false);
0562 
0563     switch (inj_type) {
0564     case DFR_INT_INJ:
0565         smp_call_function_single(cpu, trigger_dfr_int, NULL, 0);
0566         break;
0567     case THR_INT_INJ:
0568         smp_call_function_single(cpu, trigger_thr_int, NULL, 0);
0569         break;
0570     default:
0571         smp_call_function_single(cpu, trigger_mce, NULL, 0);
0572     }
0573 
0574 err:
0575     cpus_read_unlock();
0576 
0577 }
0578 
0579 /*
0580  * This denotes into which bank we're injecting and triggers
0581  * the injection, at the same time.
0582  */
0583 static int inj_bank_set(void *data, u64 val)
0584 {
0585     struct mce *m = (struct mce *)data;
0586     u8 n_banks;
0587     u64 cap;
0588 
0589     /* Get bank count on target CPU so we can handle non-uniform values. */
0590     rdmsrl_on_cpu(m->extcpu, MSR_IA32_MCG_CAP, &cap);
0591     n_banks = cap & MCG_BANKCNT_MASK;
0592 
0593     if (val >= n_banks) {
0594         pr_err("MCA bank %llu non-existent on CPU%d\n", val, m->extcpu);
0595         return -EINVAL;
0596     }
0597 
0598     m->bank = val;
0599 
0600     /*
0601      * sw-only injection allows to write arbitrary values into the MCA
0602      * registers because it tests only the decoding paths.
0603      */
0604     if (inj_type == SW_INJ)
0605         goto inject;
0606 
0607     /*
0608      * Read IPID value to determine if a bank is populated on the target
0609      * CPU.
0610      */
0611     if (cpu_feature_enabled(X86_FEATURE_SMCA)) {
0612         u64 ipid;
0613 
0614         if (rdmsrl_on_cpu(m->extcpu, MSR_AMD64_SMCA_MCx_IPID(val), &ipid)) {
0615             pr_err("Error reading IPID on CPU%d\n", m->extcpu);
0616             return -EINVAL;
0617         }
0618 
0619         if (!ipid) {
0620             pr_err("Cannot inject into unpopulated bank %llu\n", val);
0621             return -ENODEV;
0622         }
0623     }
0624 
0625 inject:
0626     do_inject();
0627 
0628     /* Reset injection struct */
0629     setup_inj_struct(&i_mce);
0630 
0631     return 0;
0632 }
0633 
0634 MCE_INJECT_GET(bank);
0635 
0636 DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n");
0637 
0638 static const char readme_msg[] =
0639 "Description of the files and their usages:\n"
0640 "\n"
0641 "Note1: i refers to the bank number below.\n"
0642 "Note2: See respective BKDGs for the exact bit definitions of the files below\n"
0643 "as they mirror the hardware registers.\n"
0644 "\n"
0645 "status:\t Set MCi_STATUS: the bits in that MSR control the error type and\n"
0646 "\t attributes of the error which caused the MCE.\n"
0647 "\n"
0648 "misc:\t Set MCi_MISC: provide auxiliary info about the error. It is mostly\n"
0649 "\t used for error thresholding purposes and its validity is indicated by\n"
0650 "\t MCi_STATUS[MiscV].\n"
0651 "\n"
0652 "synd:\t Set MCi_SYND: provide syndrome info about the error. Only valid on\n"
0653 "\t Scalable MCA systems, and its validity is indicated by MCi_STATUS[SyndV].\n"
0654 "\n"
0655 "addr:\t Error address value to be written to MCi_ADDR. Log address information\n"
0656 "\t associated with the error.\n"
0657 "\n"
0658 "cpu:\t The CPU to inject the error on.\n"
0659 "\n"
0660 "bank:\t Specify the bank you want to inject the error into: the number of\n"
0661 "\t banks in a processor varies and is family/model-specific, therefore, the\n"
0662 "\t supplied value is sanity-checked. Setting the bank value also triggers the\n"
0663 "\t injection.\n"
0664 "\n"
0665 "flags:\t Injection type to be performed. Writing to this file will trigger a\n"
0666 "\t real machine check, an APIC interrupt or invoke the error decoder routines\n"
0667 "\t for AMD processors.\n"
0668 "\n"
0669 "\t Allowed error injection types:\n"
0670 "\t  - \"sw\": Software error injection. Decode error to a human-readable \n"
0671 "\t    format only. Safe to use.\n"
0672 "\t  - \"hw\": Hardware error injection. Causes the #MC exception handler to \n"
0673 "\t    handle the error. Be warned: might cause system panic if MCi_STATUS[PCC] \n"
0674 "\t    is set. Therefore, consider setting (debugfs_mountpoint)/mce/fake_panic \n"
0675 "\t    before injecting.\n"
0676 "\t  - \"df\": Trigger APIC interrupt for Deferred error. Causes deferred \n"
0677 "\t    error APIC interrupt handler to handle the error if the feature is \n"
0678 "\t    is present in hardware. \n"
0679 "\t  - \"th\": Trigger APIC interrupt for Threshold errors. Causes threshold \n"
0680 "\t    APIC interrupt handler to handle the error. \n"
0681 "\n"
0682 "ipid:\t IPID (AMD-specific)\n"
0683 "\n";
0684 
0685 static ssize_t
0686 inj_readme_read(struct file *filp, char __user *ubuf,
0687                size_t cnt, loff_t *ppos)
0688 {
0689     return simple_read_from_buffer(ubuf, cnt, ppos,
0690                     readme_msg, strlen(readme_msg));
0691 }
0692 
0693 static const struct file_operations readme_fops = {
0694     .read       = inj_readme_read,
0695 };
0696 
0697 static struct dfs_node {
0698     char *name;
0699     const struct file_operations *fops;
0700     umode_t perm;
0701 } dfs_fls[] = {
0702     { .name = "status", .fops = &status_fops, .perm = S_IRUSR | S_IWUSR },
0703     { .name = "misc",   .fops = &misc_fops,   .perm = S_IRUSR | S_IWUSR },
0704     { .name = "addr",   .fops = &addr_fops,   .perm = S_IRUSR | S_IWUSR },
0705     { .name = "synd",   .fops = &synd_fops,   .perm = S_IRUSR | S_IWUSR },
0706     { .name = "ipid",   .fops = &ipid_fops,   .perm = S_IRUSR | S_IWUSR },
0707     { .name = "bank",   .fops = &bank_fops,   .perm = S_IRUSR | S_IWUSR },
0708     { .name = "flags",  .fops = &flags_fops,  .perm = S_IRUSR | S_IWUSR },
0709     { .name = "cpu",    .fops = &extcpu_fops, .perm = S_IRUSR | S_IWUSR },
0710     { .name = "README", .fops = &readme_fops, .perm = S_IRUSR | S_IRGRP | S_IROTH },
0711 };
0712 
0713 static void __init debugfs_init(void)
0714 {
0715     unsigned int i;
0716 
0717     dfs_inj = debugfs_create_dir("mce-inject", NULL);
0718 
0719     for (i = 0; i < ARRAY_SIZE(dfs_fls); i++)
0720         debugfs_create_file(dfs_fls[i].name, dfs_fls[i].perm, dfs_inj,
0721                     &i_mce, dfs_fls[i].fops);
0722 }
0723 
0724 static void check_hw_inj_possible(void)
0725 {
0726     int cpu;
0727     u8 bank;
0728 
0729     /*
0730      * This behavior exists only on SMCA systems though its not directly
0731      * related to SMCA.
0732      */
0733     if (!cpu_feature_enabled(X86_FEATURE_SMCA))
0734         return;
0735 
0736     cpu = get_cpu();
0737 
0738     for (bank = 0; bank < MAX_NR_BANKS; ++bank) {
0739         u64 status = MCI_STATUS_VAL, ipid;
0740 
0741         /* Check whether bank is populated */
0742         rdmsrl(MSR_AMD64_SMCA_MCx_IPID(bank), ipid);
0743         if (!ipid)
0744             continue;
0745 
0746         toggle_hw_mce_inject(cpu, true);
0747 
0748         wrmsrl_safe(mca_msr_reg(bank, MCA_STATUS), status);
0749         rdmsrl_safe(mca_msr_reg(bank, MCA_STATUS), &status);
0750 
0751         if (!status) {
0752             hw_injection_possible = false;
0753             pr_warn("Platform does not allow *hardware* error injection."
0754                 "Try using APEI EINJ instead.\n");
0755         }
0756 
0757         toggle_hw_mce_inject(cpu, false);
0758 
0759         break;
0760     }
0761 
0762     put_cpu();
0763 }
0764 
0765 static int __init inject_init(void)
0766 {
0767     if (!alloc_cpumask_var(&mce_inject_cpumask, GFP_KERNEL))
0768         return -ENOMEM;
0769 
0770     check_hw_inj_possible();
0771 
0772     debugfs_init();
0773 
0774     register_nmi_handler(NMI_LOCAL, mce_raise_notify, 0, "mce_notify");
0775     mce_register_injector_chain(&inject_nb);
0776 
0777     setup_inj_struct(&i_mce);
0778 
0779     pr_info("Machine check injector initialized\n");
0780 
0781     return 0;
0782 }
0783 
0784 static void __exit inject_exit(void)
0785 {
0786 
0787     mce_unregister_injector_chain(&inject_nb);
0788     unregister_nmi_handler(NMI_LOCAL, "mce_notify");
0789 
0790     debugfs_remove_recursive(dfs_inj);
0791     dfs_inj = NULL;
0792 
0793     memset(&dfs_fls, 0, sizeof(dfs_fls));
0794 
0795     free_cpumask_var(mce_inject_cpumask);
0796 }
0797 
0798 module_init(inject_init);
0799 module_exit(inject_exit);
0800 MODULE_LICENSE("GPL");