aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/ia64/Kconfig10
-rw-r--r--arch/ia64/defconfig1
-rw-r--r--arch/ia64/kernel/Makefile1
-rw-r--r--arch/ia64/kernel/err_inject.c293
4 files changed, 305 insertions, 0 deletions
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index e19185d26554..09866581a326 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -438,6 +438,16 @@ config IA64_PALINFO
438 To use this option, you have to ensure that the "/proc file system 438 To use this option, you have to ensure that the "/proc file system
439 support" (CONFIG_PROC_FS) is enabled, too. 439 support" (CONFIG_PROC_FS) is enabled, too.
440 440
441config IA64_MC_ERR_INJECT
442 tristate "MC error injection support"
443 help
444 Selets whether support for MC error injection. By enabling the
445 support, kernel provide sysfs interface for user application to
446 call MC error injection PAL procedure to inject various errors.
447 This is a useful tool for MCA testing.
448
449 If you're unsure, do not select this option.
450
441config SGI_SN 451config SGI_SN
442 def_bool y if (IA64_SGI_SN2 || IA64_GENERIC) 452 def_bool y if (IA64_SGI_SN2 || IA64_GENERIC)
443 453
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig
index 153bfdc0182d..90bd9601cdde 100644
--- a/arch/ia64/defconfig
+++ b/arch/ia64/defconfig
@@ -164,6 +164,7 @@ CONFIG_COMPAT=y
164CONFIG_IA64_MCA_RECOVERY=y 164CONFIG_IA64_MCA_RECOVERY=y
165CONFIG_PERFMON=y 165CONFIG_PERFMON=y
166CONFIG_IA64_PALINFO=y 166CONFIG_IA64_PALINFO=y
167# CONFIG_MC_ERR_INJECT is not set
167CONFIG_SGI_SN=y 168CONFIG_SGI_SN=y
168# CONFIG_IA64_ESI is not set 169# CONFIG_IA64_ESI is not set
169 170
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 098ee605bf5e..33e5a598672d 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
34obj-$(CONFIG_AUDIT) += audit.o 34obj-$(CONFIG_AUDIT) += audit.o
35obj-$(CONFIG_PCI_MSI) += msi_ia64.o 35obj-$(CONFIG_PCI_MSI) += msi_ia64.o
36mca_recovery-y += mca_drv.o mca_drv_asm.o 36mca_recovery-y += mca_drv.o mca_drv_asm.o
37obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o
37 38
38obj-$(CONFIG_IA64_ESI) += esi.o 39obj-$(CONFIG_IA64_ESI) += esi.o
39ifneq ($(CONFIG_IA64_ESI),) 40ifneq ($(CONFIG_IA64_ESI),)
diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c
new file mode 100644
index 000000000000..d3e9f33e8bdd
--- /dev/null
+++ b/arch/ia64/kernel/err_inject.c
@@ -0,0 +1,293 @@
1/*
2 * err_inject.c -
3 * 1.) Inject errors to a processor.
4 * 2.) Query error injection capabilities.
5 * This driver along with user space code can be acting as an error
6 * injection tool.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
16 * NON INFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * Written by: Fenghua Yu <fenghua.yu@intel.com>, Intel Corporation
24 * Copyright (C) 2006, Intel Corp. All rights reserved.
25 *
26 */
27#include <linux/sysdev.h>
28#include <linux/init.h>
29#include <linux/mm.h>
30#include <linux/cpu.h>
31#include <linux/module.h>
32
33#define ERR_INJ_DEBUG
34
35#define ERR_DATA_BUFFER_SIZE 3 // Three 8-byte;
36
37#define define_one_ro(name) \
38static SYSDEV_ATTR(name, 0444, show_##name, NULL)
39
40#define define_one_rw(name) \
41static SYSDEV_ATTR(name, 0644, show_##name, store_##name)
42
43static u64 call_start[NR_CPUS];
44static u64 phys_addr[NR_CPUS];
45static u64 err_type_info[NR_CPUS];
46static u64 err_struct_info[NR_CPUS];
47static struct {
48 u64 data1;
49 u64 data2;
50 u64 data3;
51} __attribute__((__aligned__(16))) err_data_buffer[NR_CPUS];
52static s64 status[NR_CPUS];
53static u64 capabilities[NR_CPUS];
54static u64 resources[NR_CPUS];
55
56#define show(name) \
57static ssize_t \
58show_##name(struct sys_device *dev, char *buf) \
59{ \
60 u32 cpu=dev->id; \
61 return sprintf(buf, "%lx\n", name[cpu]); \
62}
63
64#define store(name) \
65static ssize_t \
66store_##name(struct sys_device *dev, const char *buf, size_t size) \
67{ \
68 unsigned int cpu=dev->id; \
69 name[cpu] = simple_strtoull(buf, NULL, 16); \
70 return size; \
71}
72
73show(call_start)
74
75/* It's user's responsibility to call the PAL procedure on a specific
76 * processor. The cpu number in driver is only used for storing data.
77 */
78static ssize_t
79store_call_start(struct sys_device *dev, const char *buf, size_t size)
80{
81 unsigned int cpu=dev->id;
82 unsigned long call_start = simple_strtoull(buf, NULL, 16);
83
84#ifdef ERR_INJ_DEBUG
85 printk(KERN_DEBUG "pal_mc_err_inject for cpu%d:\n", cpu);
86 printk(KERN_DEBUG "err_type_info=%lx,\n", err_type_info[cpu]);
87 printk(KERN_DEBUG "err_struct_info=%lx,\n", err_struct_info[cpu]);
88 printk(KERN_DEBUG "err_data_buffer=%lx, %lx, %lx.\n",
89 err_data_buffer[cpu].data1,
90 err_data_buffer[cpu].data2,
91 err_data_buffer[cpu].data3);
92#endif
93 switch (call_start) {
94 case 0: /* Do nothing. */
95 break;
96 case 1: /* Call pal_mc_error_inject in physical mode. */
97 status[cpu]=ia64_pal_mc_error_inject_phys(err_type_info[cpu],
98 err_struct_info[cpu],
99 ia64_tpa(&err_data_buffer[cpu]),
100 &capabilities[cpu],
101 &resources[cpu]);
102 break;
103 case 2: /* Call pal_mc_error_inject in virtual mode. */
104 status[cpu]=ia64_pal_mc_error_inject_virt(err_type_info[cpu],
105 err_struct_info[cpu],
106 ia64_tpa(&err_data_buffer[cpu]),
107 &capabilities[cpu],
108 &resources[cpu]);
109 break;
110 default:
111 status[cpu] = -EINVAL;
112 break;
113 }
114
115#ifdef ERR_INJ_DEBUG
116 printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]);
117 printk(KERN_DEBUG "capapbilities=%lx,\n", capabilities[cpu]);
118 printk(KERN_DEBUG "resources=%lx\n", resources[cpu]);
119#endif
120 return size;
121}
122
123show(err_type_info)
124store(err_type_info)
125
126static ssize_t
127show_virtual_to_phys(struct sys_device *dev, char *buf)
128{
129 unsigned int cpu=dev->id;
130 return sprintf(buf, "%lx\n", phys_addr[cpu]);
131}
132
133static ssize_t
134store_virtual_to_phys(struct sys_device *dev, const char *buf, size_t size)
135{
136 unsigned int cpu=dev->id;
137 u64 virt_addr=simple_strtoull(buf, NULL, 16);
138 int ret;
139
140 ret = get_user_pages(current, current->mm, virt_addr,
141 1, VM_READ, 0, NULL, NULL);
142 if (ret<=0) {
143#ifdef ERR_INJ_DEBUG
144 printk("Virtual address %lx is not existing.\n",virt_addr);
145#endif
146 return -EINVAL;
147 }
148
149 phys_addr[cpu] = ia64_tpa(virt_addr);
150 return size;
151}
152
153show(err_struct_info)
154store(err_struct_info)
155
156static ssize_t
157show_err_data_buffer(struct sys_device *dev, char *buf)
158{
159 unsigned int cpu=dev->id;
160
161 return sprintf(buf, "%lx, %lx, %lx\n",
162 err_data_buffer[cpu].data1,
163 err_data_buffer[cpu].data2,
164 err_data_buffer[cpu].data3);
165}
166
167static ssize_t
168store_err_data_buffer(struct sys_device *dev, const char *buf, size_t size)
169{
170 unsigned int cpu=dev->id;
171 int ret;
172
173#ifdef ERR_INJ_DEBUG
174 printk("write err_data_buffer=[%lx,%lx,%lx] on cpu%d\n",
175 err_data_buffer[cpu].data1,
176 err_data_buffer[cpu].data2,
177 err_data_buffer[cpu].data3,
178 cpu);
179#endif
180 ret=sscanf(buf, "%lx, %lx, %lx",
181 &err_data_buffer[cpu].data1,
182 &err_data_buffer[cpu].data2,
183 &err_data_buffer[cpu].data3);
184 if (ret!=ERR_DATA_BUFFER_SIZE)
185 return -EINVAL;
186
187 return size;
188}
189
190show(status)
191show(capabilities)
192show(resources)
193
194define_one_rw(call_start);
195define_one_rw(err_type_info);
196define_one_rw(err_struct_info);
197define_one_rw(err_data_buffer);
198define_one_rw(virtual_to_phys);
199define_one_ro(status);
200define_one_ro(capabilities);
201define_one_ro(resources);
202
203static struct attribute *default_attrs[] = {
204 &attr_call_start.attr,
205 &attr_virtual_to_phys.attr,
206 &attr_err_type_info.attr,
207 &attr_err_struct_info.attr,
208 &attr_err_data_buffer.attr,
209 &attr_status.attr,
210 &attr_capabilities.attr,
211 &attr_resources.attr,
212 NULL
213};
214
215static struct attribute_group err_inject_attr_group = {
216 .attrs = default_attrs,
217 .name = "err_inject"
218};
219/* Add/Remove err_inject interface for CPU device */
220static int __cpuinit err_inject_add_dev(struct sys_device * sys_dev)
221{
222 return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group);
223}
224
225static int __cpuinit err_inject_remove_dev(struct sys_device * sys_dev)
226{
227 sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
228 return 0;
229}
230static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
231 unsigned long action, void *hcpu)
232{
233 unsigned int cpu = (unsigned long)hcpu;
234 struct sys_device *sys_dev;
235
236 sys_dev = get_cpu_sysdev(cpu);
237 switch (action) {
238 case CPU_ONLINE:
239 err_inject_add_dev(sys_dev);
240 break;
241 case CPU_DEAD:
242 err_inject_remove_dev(sys_dev);
243 break;
244 }
245
246 return NOTIFY_OK;
247}
248
249static struct notifier_block __cpuinitdata err_inject_cpu_notifier =
250{
251 .notifier_call = err_inject_cpu_callback,
252};
253
254static int __init
255err_inject_init(void)
256{
257 int i;
258
259#ifdef ERR_INJ_DEBUG
260 printk(KERN_INFO "Enter error injection driver.\n");
261#endif
262 for_each_online_cpu(i) {
263 err_inject_cpu_callback(&err_inject_cpu_notifier, CPU_ONLINE,
264 (void *)(long)i);
265 }
266
267 register_hotcpu_notifier(&err_inject_cpu_notifier);
268
269 return 0;
270}
271
272static void __exit
273err_inject_exit(void)
274{
275 int i;
276 struct sys_device *sys_dev;
277
278#ifdef ERR_INJ_DEBUG
279 printk(KERN_INFO "Exit error injection driver.\n");
280#endif
281 for_each_online_cpu(i) {
282 sys_dev = get_cpu_sysdev(i);
283 sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
284 }
285 unregister_hotcpu_notifier(&err_inject_cpu_notifier);
286}
287
288module_init(err_inject_init);
289module_exit(err_inject_exit);
290
291MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>");
292MODULE_DESCRIPTION("MC error injection kenrel sysfs interface");
293MODULE_LICENSE("GPL");