0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
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
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,
0049 HW_INJ,
0050 DFR_INT_INJ,
0051 THR_INT_INJ,
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
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
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
0126 static void inject_mce(struct mce *m)
0127 {
0128 struct mce *i = &per_cpu(injectm, m->extcpu);
0129
0130
0131 i->finished = 0;
0132 mb();
0133 m->finished = 0;
0134
0135 i->extcpu = m->extcpu;
0136 mb();
0137
0138 memcpy(i, m, sizeof(struct mce));
0139
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(®s, 0, sizeof(struct pt_regs));
0163 regs.ip = m->ip;
0164 regs.cs = m->cs;
0165 pregs = ®s;
0166 }
0167
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
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
0217
0218
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
0266
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
0316
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
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
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
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
0531
0532
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
0541
0542
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
0581
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
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
0602
0603
0604 if (inj_type == SW_INJ)
0605 goto inject;
0606
0607
0608
0609
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
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
0731
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
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");