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