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