1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Machine check injection support.
4 * Copyright 2008 Intel Corporation.
5 *
6 * Authors:
7 * Andi Kleen
8 * Ying Huang
9 *
10 * The AMD part (from mce_amd_inj.c): a simple MCE injection facility
11 * for testing different aspects of the RAS code. This driver should be
12 * built as module so that it can be loaded on production kernels for
13 * testing purposes.
14 *
15 * Copyright (c) 2010-17: Borislav Petkov <bp@alien8.de>
16 * Advanced Micro Devices Inc.
17 */
18
19 #include <linux/cpu.h>
20 #include <linux/debugfs.h>
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/notifier.h>
24 #include <linux/pci.h>
25 #include <linux/uaccess.h>
26
27 #include <asm/amd_nb.h>
28 #include <asm/apic.h>
29 #include <asm/irq_vectors.h>
30 #include <asm/mce.h>
31 #include <asm/nmi.h>
32 #include <asm/smp.h>
33
34 #include "internal.h"
35
36 /*
37 * Collect all the MCi_XXX settings
38 */
39 static struct mce i_mce;
40 static struct dentry *dfs_inj;
41
42 #define MAX_FLAG_OPT_SIZE 4
43 #define NBCFG 0x44
44
45 enum injection_type {
46 SW_INJ = 0, /* SW injection, simply decode the error */
47 HW_INJ, /* Trigger a #MC */
48 DFR_INT_INJ, /* Trigger Deferred error interrupt */
49 THR_INT_INJ, /* Trigger threshold interrupt */
50 N_INJ_TYPES,
51 };
52
53 static const char * const flags_options[] = {
54 [SW_INJ] = "sw",
55 [HW_INJ] = "hw",
56 [DFR_INT_INJ] = "df",
57 [THR_INT_INJ] = "th",
58 NULL
59 };
60
61 /* Set default injection to SW_INJ */
62 static enum injection_type inj_type = SW_INJ;
63
64 #define MCE_INJECT_SET(reg) \
65 static int inj_##reg##_set(void *data, u64 val) \
66 { \
67 struct mce *m = (struct mce *)data; \
68 \
69 m->reg = val; \
70 return 0; \
71 }
72
73 MCE_INJECT_SET(status);
74 MCE_INJECT_SET(misc);
75 MCE_INJECT_SET(addr);
76 MCE_INJECT_SET(synd);
77 MCE_INJECT_SET(ipid);
78
79 #define MCE_INJECT_GET(reg) \
80 static int inj_##reg##_get(void *data, u64 *val) \
81 { \
82 struct mce *m = (struct mce *)data; \
83 \
84 *val = m->reg; \
85 return 0; \
86 }
87
88 MCE_INJECT_GET(status);
89 MCE_INJECT_GET(misc);
90 MCE_INJECT_GET(addr);
91 MCE_INJECT_GET(synd);
92 MCE_INJECT_GET(ipid);
93
94 DEFINE_SIMPLE_ATTRIBUTE(status_fops, inj_status_get, inj_status_set, "%llx\n");
95 DEFINE_SIMPLE_ATTRIBUTE(misc_fops, inj_misc_get, inj_misc_set, "%llx\n");
96 DEFINE_SIMPLE_ATTRIBUTE(addr_fops, inj_addr_get, inj_addr_set, "%llx\n");
97 DEFINE_SIMPLE_ATTRIBUTE(synd_fops, inj_synd_get, inj_synd_set, "%llx\n");
98 DEFINE_SIMPLE_ATTRIBUTE(ipid_fops, inj_ipid_get, inj_ipid_set, "%llx\n");
99
setup_inj_struct(struct mce * m)100 static void setup_inj_struct(struct mce *m)
101 {
102 memset(m, 0, sizeof(struct mce));
103
104 m->cpuvendor = boot_cpu_data.x86_vendor;
105 m->time = ktime_get_real_seconds();
106 m->cpuid = cpuid_eax(1);
107 m->microcode = boot_cpu_data.microcode;
108 }
109
110 /* Update fake mce registers on current CPU. */
inject_mce(struct mce * m)111 static void inject_mce(struct mce *m)
112 {
113 struct mce *i = &per_cpu(injectm, m->extcpu);
114
115 /* Make sure no one reads partially written injectm */
116 i->finished = 0;
117 mb();
118 m->finished = 0;
119 /* First set the fields after finished */
120 i->extcpu = m->extcpu;
121 mb();
122 /* Now write record in order, finished last (except above) */
123 memcpy(i, m, sizeof(struct mce));
124 /* Finally activate it */
125 mb();
126 i->finished = 1;
127 }
128
raise_poll(struct mce * m)129 static void raise_poll(struct mce *m)
130 {
131 unsigned long flags;
132 mce_banks_t b;
133
134 memset(&b, 0xff, sizeof(mce_banks_t));
135 local_irq_save(flags);
136 machine_check_poll(0, &b);
137 local_irq_restore(flags);
138 m->finished = 0;
139 }
140
raise_exception(struct mce * m,struct pt_regs * pregs)141 static void raise_exception(struct mce *m, struct pt_regs *pregs)
142 {
143 struct pt_regs regs;
144 unsigned long flags;
145
146 if (!pregs) {
147 memset(®s, 0, sizeof(struct pt_regs));
148 regs.ip = m->ip;
149 regs.cs = m->cs;
150 pregs = ®s;
151 }
152 /* do_machine_check() expects interrupts disabled -- at least */
153 local_irq_save(flags);
154 do_machine_check(pregs);
155 local_irq_restore(flags);
156 m->finished = 0;
157 }
158
159 static cpumask_var_t mce_inject_cpumask;
160 static DEFINE_MUTEX(mce_inject_mutex);
161
mce_raise_notify(unsigned int cmd,struct pt_regs * regs)162 static int mce_raise_notify(unsigned int cmd, struct pt_regs *regs)
163 {
164 int cpu = smp_processor_id();
165 struct mce *m = this_cpu_ptr(&injectm);
166 if (!cpumask_test_cpu(cpu, mce_inject_cpumask))
167 return NMI_DONE;
168 cpumask_clear_cpu(cpu, mce_inject_cpumask);
169 if (m->inject_flags & MCJ_EXCEPTION)
170 raise_exception(m, regs);
171 else if (m->status)
172 raise_poll(m);
173 return NMI_HANDLED;
174 }
175
mce_irq_ipi(void * info)176 static void mce_irq_ipi(void *info)
177 {
178 int cpu = smp_processor_id();
179 struct mce *m = this_cpu_ptr(&injectm);
180
181 if (cpumask_test_cpu(cpu, mce_inject_cpumask) &&
182 m->inject_flags & MCJ_EXCEPTION) {
183 cpumask_clear_cpu(cpu, mce_inject_cpumask);
184 raise_exception(m, NULL);
185 }
186 }
187
188 /* Inject mce on current CPU */
raise_local(void)189 static int raise_local(void)
190 {
191 struct mce *m = this_cpu_ptr(&injectm);
192 int context = MCJ_CTX(m->inject_flags);
193 int ret = 0;
194 int cpu = m->extcpu;
195
196 if (m->inject_flags & MCJ_EXCEPTION) {
197 pr_info("Triggering MCE exception on CPU %d\n", cpu);
198 switch (context) {
199 case MCJ_CTX_IRQ:
200 /*
201 * Could do more to fake interrupts like
202 * calling irq_enter, but the necessary
203 * machinery isn't exported currently.
204 */
205 fallthrough;
206 case MCJ_CTX_PROCESS:
207 raise_exception(m, NULL);
208 break;
209 default:
210 pr_info("Invalid MCE context\n");
211 ret = -EINVAL;
212 }
213 pr_info("MCE exception done on CPU %d\n", cpu);
214 } else if (m->status) {
215 pr_info("Starting machine check poll CPU %d\n", cpu);
216 raise_poll(m);
217 mce_notify_irq();
218 pr_info("Machine check poll done on CPU %d\n", cpu);
219 } else
220 m->finished = 0;
221
222 return ret;
223 }
224
raise_mce(struct mce * m)225 static void __maybe_unused raise_mce(struct mce *m)
226 {
227 int context = MCJ_CTX(m->inject_flags);
228
229 inject_mce(m);
230
231 if (context == MCJ_CTX_RANDOM)
232 return;
233
234 if (m->inject_flags & (MCJ_IRQ_BROADCAST | MCJ_NMI_BROADCAST)) {
235 unsigned long start;
236 int cpu;
237
238 cpus_read_lock();
239 cpumask_copy(mce_inject_cpumask, cpu_online_mask);
240 cpumask_clear_cpu(get_cpu(), mce_inject_cpumask);
241 for_each_online_cpu(cpu) {
242 struct mce *mcpu = &per_cpu(injectm, cpu);
243 if (!mcpu->finished ||
244 MCJ_CTX(mcpu->inject_flags) != MCJ_CTX_RANDOM)
245 cpumask_clear_cpu(cpu, mce_inject_cpumask);
246 }
247 if (!cpumask_empty(mce_inject_cpumask)) {
248 if (m->inject_flags & MCJ_IRQ_BROADCAST) {
249 /*
250 * don't wait because mce_irq_ipi is necessary
251 * to be sync with following raise_local
252 */
253 preempt_disable();
254 smp_call_function_many(mce_inject_cpumask,
255 mce_irq_ipi, NULL, 0);
256 preempt_enable();
257 } else if (m->inject_flags & MCJ_NMI_BROADCAST)
258 apic->send_IPI_mask(mce_inject_cpumask,
259 NMI_VECTOR);
260 }
261 start = jiffies;
262 while (!cpumask_empty(mce_inject_cpumask)) {
263 if (!time_before(jiffies, start + 2*HZ)) {
264 pr_err("Timeout waiting for mce inject %lx\n",
265 *cpumask_bits(mce_inject_cpumask));
266 break;
267 }
268 cpu_relax();
269 }
270 raise_local();
271 put_cpu();
272 cpus_read_unlock();
273 } else {
274 preempt_disable();
275 raise_local();
276 preempt_enable();
277 }
278 }
279
mce_inject_raise(struct notifier_block * nb,unsigned long val,void * data)280 static int mce_inject_raise(struct notifier_block *nb, unsigned long val,
281 void *data)
282 {
283 struct mce *m = (struct mce *)data;
284
285 if (!m)
286 return NOTIFY_DONE;
287
288 mutex_lock(&mce_inject_mutex);
289 raise_mce(m);
290 mutex_unlock(&mce_inject_mutex);
291
292 return NOTIFY_DONE;
293 }
294
295 static struct notifier_block inject_nb = {
296 .notifier_call = mce_inject_raise,
297 };
298
299 /*
300 * Caller needs to be make sure this cpu doesn't disappear
301 * from under us, i.e.: get_cpu/put_cpu.
302 */
toggle_hw_mce_inject(unsigned int cpu,bool enable)303 static int toggle_hw_mce_inject(unsigned int cpu, bool enable)
304 {
305 u32 l, h;
306 int err;
307
308 err = rdmsr_on_cpu(cpu, MSR_K7_HWCR, &l, &h);
309 if (err) {
310 pr_err("%s: error reading HWCR\n", __func__);
311 return err;
312 }
313
314 enable ? (l |= BIT(18)) : (l &= ~BIT(18));
315
316 err = wrmsr_on_cpu(cpu, MSR_K7_HWCR, l, h);
317 if (err)
318 pr_err("%s: error writing HWCR\n", __func__);
319
320 return err;
321 }
322
__set_inj(const char * buf)323 static int __set_inj(const char *buf)
324 {
325 int i;
326
327 for (i = 0; i < N_INJ_TYPES; i++) {
328 if (!strncmp(flags_options[i], buf, strlen(flags_options[i]))) {
329 inj_type = i;
330 return 0;
331 }
332 }
333 return -EINVAL;
334 }
335
flags_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)336 static ssize_t flags_read(struct file *filp, char __user *ubuf,
337 size_t cnt, loff_t *ppos)
338 {
339 char buf[MAX_FLAG_OPT_SIZE];
340 int n;
341
342 n = sprintf(buf, "%s\n", flags_options[inj_type]);
343
344 return simple_read_from_buffer(ubuf, cnt, ppos, buf, n);
345 }
346
flags_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)347 static ssize_t flags_write(struct file *filp, const char __user *ubuf,
348 size_t cnt, loff_t *ppos)
349 {
350 char buf[MAX_FLAG_OPT_SIZE], *__buf;
351 int err;
352
353 if (cnt > MAX_FLAG_OPT_SIZE)
354 return -EINVAL;
355
356 if (copy_from_user(&buf, ubuf, cnt))
357 return -EFAULT;
358
359 buf[cnt - 1] = 0;
360
361 /* strip whitespace */
362 __buf = strstrip(buf);
363
364 err = __set_inj(__buf);
365 if (err) {
366 pr_err("%s: Invalid flags value: %s\n", __func__, __buf);
367 return err;
368 }
369
370 *ppos += cnt;
371
372 return cnt;
373 }
374
375 static const struct file_operations flags_fops = {
376 .read = flags_read,
377 .write = flags_write,
378 .llseek = generic_file_llseek,
379 };
380
381 /*
382 * On which CPU to inject?
383 */
384 MCE_INJECT_GET(extcpu);
385
inj_extcpu_set(void * data,u64 val)386 static int inj_extcpu_set(void *data, u64 val)
387 {
388 struct mce *m = (struct mce *)data;
389
390 if (val >= nr_cpu_ids || !cpu_online(val)) {
391 pr_err("%s: Invalid CPU: %llu\n", __func__, val);
392 return -EINVAL;
393 }
394 m->extcpu = val;
395 return 0;
396 }
397
398 DEFINE_SIMPLE_ATTRIBUTE(extcpu_fops, inj_extcpu_get, inj_extcpu_set, "%llu\n");
399
trigger_mce(void * info)400 static void trigger_mce(void *info)
401 {
402 asm volatile("int $18");
403 }
404
trigger_dfr_int(void * info)405 static void trigger_dfr_int(void *info)
406 {
407 asm volatile("int %0" :: "i" (DEFERRED_ERROR_VECTOR));
408 }
409
trigger_thr_int(void * info)410 static void trigger_thr_int(void *info)
411 {
412 asm volatile("int %0" :: "i" (THRESHOLD_APIC_VECTOR));
413 }
414
get_nbc_for_node(int node_id)415 static u32 get_nbc_for_node(int node_id)
416 {
417 struct cpuinfo_x86 *c = &boot_cpu_data;
418 u32 cores_per_node;
419
420 cores_per_node = (c->x86_max_cores * smp_num_siblings) / amd_get_nodes_per_socket();
421
422 return cores_per_node * node_id;
423 }
424
toggle_nb_mca_mst_cpu(u16 nid)425 static void toggle_nb_mca_mst_cpu(u16 nid)
426 {
427 struct amd_northbridge *nb;
428 struct pci_dev *F3;
429 u32 val;
430 int err;
431
432 nb = node_to_amd_nb(nid);
433 if (!nb)
434 return;
435
436 F3 = nb->misc;
437 if (!F3)
438 return;
439
440 err = pci_read_config_dword(F3, NBCFG, &val);
441 if (err) {
442 pr_err("%s: Error reading F%dx%03x.\n",
443 __func__, PCI_FUNC(F3->devfn), NBCFG);
444 return;
445 }
446
447 if (val & BIT(27))
448 return;
449
450 pr_err("%s: Set D18F3x44[NbMcaToMstCpuEn] which BIOS hasn't done.\n",
451 __func__);
452
453 val |= BIT(27);
454 err = pci_write_config_dword(F3, NBCFG, val);
455 if (err)
456 pr_err("%s: Error writing F%dx%03x.\n",
457 __func__, PCI_FUNC(F3->devfn), NBCFG);
458 }
459
prepare_msrs(void * info)460 static void prepare_msrs(void *info)
461 {
462 struct mce m = *(struct mce *)info;
463 u8 b = m.bank;
464
465 wrmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
466
467 if (boot_cpu_has(X86_FEATURE_SMCA)) {
468 if (m.inject_flags == DFR_INT_INJ) {
469 wrmsrl(MSR_AMD64_SMCA_MCx_DESTAT(b), m.status);
470 wrmsrl(MSR_AMD64_SMCA_MCx_DEADDR(b), m.addr);
471 } else {
472 wrmsrl(MSR_AMD64_SMCA_MCx_STATUS(b), m.status);
473 wrmsrl(MSR_AMD64_SMCA_MCx_ADDR(b), m.addr);
474 }
475
476 wrmsrl(MSR_AMD64_SMCA_MCx_MISC(b), m.misc);
477 wrmsrl(MSR_AMD64_SMCA_MCx_SYND(b), m.synd);
478 } else {
479 wrmsrl(MSR_IA32_MCx_STATUS(b), m.status);
480 wrmsrl(MSR_IA32_MCx_ADDR(b), m.addr);
481 wrmsrl(MSR_IA32_MCx_MISC(b), m.misc);
482 }
483 }
484
do_inject(void)485 static void do_inject(void)
486 {
487 u64 mcg_status = 0;
488 unsigned int cpu = i_mce.extcpu;
489 u8 b = i_mce.bank;
490
491 i_mce.tsc = rdtsc_ordered();
492
493 if (i_mce.misc)
494 i_mce.status |= MCI_STATUS_MISCV;
495
496 if (i_mce.synd)
497 i_mce.status |= MCI_STATUS_SYNDV;
498
499 if (inj_type == SW_INJ) {
500 mce_log(&i_mce);
501 return;
502 }
503
504 /* prep MCE global settings for the injection */
505 mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
506
507 if (!(i_mce.status & MCI_STATUS_PCC))
508 mcg_status |= MCG_STATUS_RIPV;
509
510 /*
511 * Ensure necessary status bits for deferred errors:
512 * - MCx_STATUS[Deferred]: make sure it is a deferred error
513 * - MCx_STATUS[UC] cleared: deferred errors are _not_ UC
514 */
515 if (inj_type == DFR_INT_INJ) {
516 i_mce.status |= MCI_STATUS_DEFERRED;
517 i_mce.status &= ~MCI_STATUS_UC;
518 }
519
520 /*
521 * For multi node CPUs, logging and reporting of bank 4 errors happens
522 * only on the node base core. Refer to D18F3x44[NbMcaToMstCpuEn] for
523 * Fam10h and later BKDGs.
524 */
525 if (boot_cpu_has(X86_FEATURE_AMD_DCM) &&
526 b == 4 &&
527 boot_cpu_data.x86 < 0x17) {
528 toggle_nb_mca_mst_cpu(topology_die_id(cpu));
529 cpu = get_nbc_for_node(topology_die_id(cpu));
530 }
531
532 cpus_read_lock();
533 if (!cpu_online(cpu))
534 goto err;
535
536 toggle_hw_mce_inject(cpu, true);
537
538 i_mce.mcgstatus = mcg_status;
539 i_mce.inject_flags = inj_type;
540 smp_call_function_single(cpu, prepare_msrs, &i_mce, 0);
541
542 toggle_hw_mce_inject(cpu, false);
543
544 switch (inj_type) {
545 case DFR_INT_INJ:
546 smp_call_function_single(cpu, trigger_dfr_int, NULL, 0);
547 break;
548 case THR_INT_INJ:
549 smp_call_function_single(cpu, trigger_thr_int, NULL, 0);
550 break;
551 default:
552 smp_call_function_single(cpu, trigger_mce, NULL, 0);
553 }
554
555 err:
556 cpus_read_unlock();
557
558 }
559
560 /*
561 * This denotes into which bank we're injecting and triggers
562 * the injection, at the same time.
563 */
inj_bank_set(void * data,u64 val)564 static int inj_bank_set(void *data, u64 val)
565 {
566 struct mce *m = (struct mce *)data;
567 u8 n_banks;
568 u64 cap;
569
570 /* Get bank count on target CPU so we can handle non-uniform values. */
571 rdmsrl_on_cpu(m->extcpu, MSR_IA32_MCG_CAP, &cap);
572 n_banks = cap & MCG_BANKCNT_MASK;
573
574 if (val >= n_banks) {
575 pr_err("MCA bank %llu non-existent on CPU%d\n", val, m->extcpu);
576 return -EINVAL;
577 }
578
579 m->bank = val;
580 do_inject();
581
582 /* Reset injection struct */
583 setup_inj_struct(&i_mce);
584
585 return 0;
586 }
587
588 MCE_INJECT_GET(bank);
589
590 DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n");
591
592 static const char readme_msg[] =
593 "Description of the files and their usages:\n"
594 "\n"
595 "Note1: i refers to the bank number below.\n"
596 "Note2: See respective BKDGs for the exact bit definitions of the files below\n"
597 "as they mirror the hardware registers.\n"
598 "\n"
599 "status:\t Set MCi_STATUS: the bits in that MSR control the error type and\n"
600 "\t attributes of the error which caused the MCE.\n"
601 "\n"
602 "misc:\t Set MCi_MISC: provide auxiliary info about the error. It is mostly\n"
603 "\t used for error thresholding purposes and its validity is indicated by\n"
604 "\t MCi_STATUS[MiscV].\n"
605 "\n"
606 "synd:\t Set MCi_SYND: provide syndrome info about the error. Only valid on\n"
607 "\t Scalable MCA systems, and its validity is indicated by MCi_STATUS[SyndV].\n"
608 "\n"
609 "addr:\t Error address value to be written to MCi_ADDR. Log address information\n"
610 "\t associated with the error.\n"
611 "\n"
612 "cpu:\t The CPU to inject the error on.\n"
613 "\n"
614 "bank:\t Specify the bank you want to inject the error into: the number of\n"
615 "\t banks in a processor varies and is family/model-specific, therefore, the\n"
616 "\t supplied value is sanity-checked. Setting the bank value also triggers the\n"
617 "\t injection.\n"
618 "\n"
619 "flags:\t Injection type to be performed. Writing to this file will trigger a\n"
620 "\t real machine check, an APIC interrupt or invoke the error decoder routines\n"
621 "\t for AMD processors.\n"
622 "\n"
623 "\t Allowed error injection types:\n"
624 "\t - \"sw\": Software error injection. Decode error to a human-readable \n"
625 "\t format only. Safe to use.\n"
626 "\t - \"hw\": Hardware error injection. Causes the #MC exception handler to \n"
627 "\t handle the error. Be warned: might cause system panic if MCi_STATUS[PCC] \n"
628 "\t is set. Therefore, consider setting (debugfs_mountpoint)/mce/fake_panic \n"
629 "\t before injecting.\n"
630 "\t - \"df\": Trigger APIC interrupt for Deferred error. Causes deferred \n"
631 "\t error APIC interrupt handler to handle the error if the feature is \n"
632 "\t is present in hardware. \n"
633 "\t - \"th\": Trigger APIC interrupt for Threshold errors. Causes threshold \n"
634 "\t APIC interrupt handler to handle the error. \n"
635 "\n"
636 "ipid:\t IPID (AMD-specific)\n"
637 "\n";
638
639 static ssize_t
inj_readme_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)640 inj_readme_read(struct file *filp, char __user *ubuf,
641 size_t cnt, loff_t *ppos)
642 {
643 return simple_read_from_buffer(ubuf, cnt, ppos,
644 readme_msg, strlen(readme_msg));
645 }
646
647 static const struct file_operations readme_fops = {
648 .read = inj_readme_read,
649 };
650
651 static struct dfs_node {
652 char *name;
653 const struct file_operations *fops;
654 umode_t perm;
655 } dfs_fls[] = {
656 { .name = "status", .fops = &status_fops, .perm = S_IRUSR | S_IWUSR },
657 { .name = "misc", .fops = &misc_fops, .perm = S_IRUSR | S_IWUSR },
658 { .name = "addr", .fops = &addr_fops, .perm = S_IRUSR | S_IWUSR },
659 { .name = "synd", .fops = &synd_fops, .perm = S_IRUSR | S_IWUSR },
660 { .name = "ipid", .fops = &ipid_fops, .perm = S_IRUSR | S_IWUSR },
661 { .name = "bank", .fops = &bank_fops, .perm = S_IRUSR | S_IWUSR },
662 { .name = "flags", .fops = &flags_fops, .perm = S_IRUSR | S_IWUSR },
663 { .name = "cpu", .fops = &extcpu_fops, .perm = S_IRUSR | S_IWUSR },
664 { .name = "README", .fops = &readme_fops, .perm = S_IRUSR | S_IRGRP | S_IROTH },
665 };
666
debugfs_init(void)667 static void __init debugfs_init(void)
668 {
669 unsigned int i;
670
671 dfs_inj = debugfs_create_dir("mce-inject", NULL);
672
673 for (i = 0; i < ARRAY_SIZE(dfs_fls); i++)
674 debugfs_create_file(dfs_fls[i].name, dfs_fls[i].perm, dfs_inj,
675 &i_mce, dfs_fls[i].fops);
676 }
677
inject_init(void)678 static int __init inject_init(void)
679 {
680 if (!alloc_cpumask_var(&mce_inject_cpumask, GFP_KERNEL))
681 return -ENOMEM;
682
683 debugfs_init();
684
685 register_nmi_handler(NMI_LOCAL, mce_raise_notify, 0, "mce_notify");
686 mce_register_injector_chain(&inject_nb);
687
688 setup_inj_struct(&i_mce);
689
690 pr_info("Machine check injector initialized\n");
691
692 return 0;
693 }
694
inject_exit(void)695 static void __exit inject_exit(void)
696 {
697
698 mce_unregister_injector_chain(&inject_nb);
699 unregister_nmi_handler(NMI_LOCAL, "mce_notify");
700
701 debugfs_remove_recursive(dfs_inj);
702 dfs_inj = NULL;
703
704 memset(&dfs_fls, 0, sizeof(dfs_fls));
705
706 free_cpumask_var(mce_inject_cpumask);
707 }
708
709 module_init(inject_init);
710 module_exit(inject_exit);
711 MODULE_LICENSE("GPL");
712