2 * A simple MCE injection facility for testing the MCE decoding code. This
3 * driver should be built as module so that it can be loaded on production
4 * kernels for testing purposes.
6 * This file may be distributed under the terms of the GNU General Public
9 * Copyright (c) 2010: Borislav Petkov <bp@alien8.de>
10 * Advanced Micro Devices Inc.
13 #include <linux/kobject.h>
14 #include <linux/device.h>
15 #include <linux/edac.h>
16 #include <linux/module.h>
21 struct edac_mce_attr
{
22 struct attribute attr
;
23 ssize_t (*show
) (struct kobject
*kobj
, struct edac_mce_attr
*attr
, char *buf
);
24 ssize_t (*store
)(struct kobject
*kobj
, struct edac_mce_attr
*attr
,
25 const char *buf
, size_t count
);
28 #define EDAC_MCE_ATTR(_name, _mode, _show, _store) \
29 static struct edac_mce_attr mce_attr_##_name = __ATTR(_name, _mode, _show, _store)
31 static struct kobject
*mce_kobj
;
34 * Collect all the MCi_XXX settings
36 static struct mce i_mce
;
38 #define MCE_INJECT_STORE(reg) \
39 static ssize_t edac_inject_##reg##_store(struct kobject *kobj, \
40 struct edac_mce_attr *attr, \
41 const char *data, size_t count)\
44 unsigned long value; \
46 ret = kstrtoul(data, 16, &value); \
48 printk(KERN_ERR "Error writing MCE " #reg " field.\n"); \
55 MCE_INJECT_STORE(status
);
56 MCE_INJECT_STORE(misc
);
57 MCE_INJECT_STORE(addr
);
59 #define MCE_INJECT_SHOW(reg) \
60 static ssize_t edac_inject_##reg##_show(struct kobject *kobj, \
61 struct edac_mce_attr *attr, \
64 return sprintf(buf, "0x%016llx\n", i_mce.reg); \
67 MCE_INJECT_SHOW(status
);
68 MCE_INJECT_SHOW(misc
);
69 MCE_INJECT_SHOW(addr
);
71 EDAC_MCE_ATTR(status
, 0644, edac_inject_status_show
, edac_inject_status_store
);
72 EDAC_MCE_ATTR(misc
, 0644, edac_inject_misc_show
, edac_inject_misc_store
);
73 EDAC_MCE_ATTR(addr
, 0644, edac_inject_addr_show
, edac_inject_addr_store
);
76 * This denotes into which bank we're injecting and triggers
77 * the injection, at the same time.
79 static ssize_t
edac_inject_bank_store(struct kobject
*kobj
,
80 struct edac_mce_attr
*attr
,
81 const char *data
, size_t count
)
86 ret
= kstrtoul(data
, 10, &value
);
88 printk(KERN_ERR
"Invalid bank value!\n");
93 if (boot_cpu_data
.x86
!= 0x15 || value
> 6) {
94 printk(KERN_ERR
"Non-existent MCE bank: %lu\n", value
);
100 amd_decode_mce(NULL
, 0, &i_mce
);
105 static ssize_t
edac_inject_bank_show(struct kobject
*kobj
,
106 struct edac_mce_attr
*attr
, char *buf
)
108 return sprintf(buf
, "%d\n", i_mce
.bank
);
111 EDAC_MCE_ATTR(bank
, 0644, edac_inject_bank_show
, edac_inject_bank_store
);
113 static struct edac_mce_attr
*sysfs_attrs
[] = { &mce_attr_status
, &mce_attr_misc
,
114 &mce_attr_addr
, &mce_attr_bank
117 static int __init
edac_init_mce_inject(void)
119 struct bus_type
*edac_subsys
= NULL
;
122 edac_subsys
= edac_get_sysfs_subsys();
126 mce_kobj
= kobject_create_and_add("mce", &edac_subsys
->dev_root
->kobj
);
128 printk(KERN_ERR
"Error creating a mce kset.\n");
133 for (i
= 0; i
< ARRAY_SIZE(sysfs_attrs
); i
++) {
134 err
= sysfs_create_file(mce_kobj
, &sysfs_attrs
[i
]->attr
);
136 printk(KERN_ERR
"Error creating %s in sysfs.\n",
137 sysfs_attrs
[i
]->attr
.name
);
138 goto err_sysfs_create
;
145 sysfs_remove_file(mce_kobj
, &sysfs_attrs
[i
]->attr
);
147 kobject_del(mce_kobj
);
150 edac_put_sysfs_subsys();
155 static void __exit
edac_exit_mce_inject(void)
159 for (i
= 0; i
< ARRAY_SIZE(sysfs_attrs
); i
++)
160 sysfs_remove_file(mce_kobj
, &sysfs_attrs
[i
]->attr
);
162 kobject_del(mce_kobj
);
164 edac_put_sysfs_subsys();
167 module_init(edac_init_mce_inject
);
168 module_exit(edac_exit_mce_inject
);
170 MODULE_LICENSE("GPL");
171 MODULE_AUTHOR("Borislav Petkov <bp@alien8.de>");
172 MODULE_AUTHOR("AMD Inc.");
173 MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding");