Linux Audio

Check our new training course

Loading...
v6.2
  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/device.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 DEVICE_ATTR(name, 0444, show_##name, NULL)
 39
 40#define define_one_rw(name) 						\
 41static DEVICE_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 device *dev, struct device_attribute *attr,	\
 59		char *buf)						\
 60{									\
 61	u32 cpu=dev->id;						\
 62	return sprintf(buf, "%llx\n", name[cpu]);			\
 63}
 64
 65#define store(name)							\
 66static ssize_t 								\
 67store_##name(struct device *dev, struct device_attribute *attr,	\
 68					const char *buf, size_t size)	\
 69{									\
 70	unsigned int cpu=dev->id;					\
 71	name[cpu] = simple_strtoull(buf, NULL, 16);			\
 72	return size;							\
 73}
 74
 75show(call_start)
 76
 77/* It's user's responsibility to call the PAL procedure on a specific
 78 * processor. The cpu number in driver is only used for storing data.
 79 */
 80static ssize_t
 81store_call_start(struct device *dev, struct device_attribute *attr,
 82		const char *buf, size_t size)
 83{
 84	unsigned int cpu=dev->id;
 85	unsigned long call_start = simple_strtoull(buf, NULL, 16);
 86
 87#ifdef ERR_INJ_DEBUG
 88	printk(KERN_DEBUG "pal_mc_err_inject for cpu%d:\n", cpu);
 89	printk(KERN_DEBUG "err_type_info=%llx,\n", err_type_info[cpu]);
 90	printk(KERN_DEBUG "err_struct_info=%llx,\n", err_struct_info[cpu]);
 91	printk(KERN_DEBUG "err_data_buffer=%llx, %llx, %llx.\n",
 92			  err_data_buffer[cpu].data1,
 93			  err_data_buffer[cpu].data2,
 94			  err_data_buffer[cpu].data3);
 95#endif
 96	switch (call_start) {
 97	    case 0: /* Do nothing. */
 98		break;
 99	    case 1: /* Call pal_mc_error_inject in physical mode. */
100		status[cpu]=ia64_pal_mc_error_inject_phys(err_type_info[cpu],
101					err_struct_info[cpu],
102					ia64_tpa(&err_data_buffer[cpu]),
103					&capabilities[cpu],
104			 		&resources[cpu]);
105		break;
106	    case 2: /* Call pal_mc_error_inject in virtual mode. */
107		status[cpu]=ia64_pal_mc_error_inject_virt(err_type_info[cpu],
108					err_struct_info[cpu],
109					ia64_tpa(&err_data_buffer[cpu]),
110					&capabilities[cpu],
111			 		&resources[cpu]);
112		break;
113	    default:
114		status[cpu] = -EINVAL;
115		break;
116	}
117
118#ifdef ERR_INJ_DEBUG
119	printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]);
120	printk(KERN_DEBUG "capabilities=%llx,\n", capabilities[cpu]);
121	printk(KERN_DEBUG "resources=%llx\n", resources[cpu]);
122#endif
123	return size;
124}
125
126show(err_type_info)
127store(err_type_info)
128
129static ssize_t
130show_virtual_to_phys(struct device *dev, struct device_attribute *attr,
131			char *buf)
132{
133	unsigned int cpu=dev->id;
134	return sprintf(buf, "%llx\n", phys_addr[cpu]);
135}
136
137static ssize_t
138store_virtual_to_phys(struct device *dev, struct device_attribute *attr,
139			const char *buf, size_t size)
140{
141	unsigned int cpu=dev->id;
142	u64 virt_addr=simple_strtoull(buf, NULL, 16);
143	int ret;
144
145	ret = get_user_pages_fast(virt_addr, 1, FOLL_WRITE, NULL);
 
146	if (ret<=0) {
147#ifdef ERR_INJ_DEBUG
148		printk("Virtual address %llx is not existing.\n", virt_addr);
149#endif
150		return -EINVAL;
151	}
152
153	phys_addr[cpu] = ia64_tpa(virt_addr);
154	return size;
155}
156
157show(err_struct_info)
158store(err_struct_info)
159
160static ssize_t
161show_err_data_buffer(struct device *dev,
162			struct device_attribute *attr, char *buf)
163{
164	unsigned int cpu=dev->id;
165
166	return sprintf(buf, "%llx, %llx, %llx\n",
167			err_data_buffer[cpu].data1,
168			err_data_buffer[cpu].data2,
169			err_data_buffer[cpu].data3);
170}
171
172static ssize_t
173store_err_data_buffer(struct device *dev,
174			struct device_attribute *attr,
175			const char *buf, size_t size)
176{
177	unsigned int cpu=dev->id;
178	int ret;
179
180#ifdef ERR_INJ_DEBUG
181	printk("write err_data_buffer=[%llx,%llx,%llx] on cpu%d\n",
182		 err_data_buffer[cpu].data1,
183		 err_data_buffer[cpu].data2,
184		 err_data_buffer[cpu].data3,
185		 cpu);
186#endif
187	ret = sscanf(buf, "%llx, %llx, %llx",
188			&err_data_buffer[cpu].data1,
189			&err_data_buffer[cpu].data2,
190			&err_data_buffer[cpu].data3);
191	if (ret!=ERR_DATA_BUFFER_SIZE)
192		return -EINVAL;
193
194	return size;
195}
196
197show(status)
198show(capabilities)
199show(resources)
200
201define_one_rw(call_start);
202define_one_rw(err_type_info);
203define_one_rw(err_struct_info);
204define_one_rw(err_data_buffer);
205define_one_rw(virtual_to_phys);
206define_one_ro(status);
207define_one_ro(capabilities);
208define_one_ro(resources);
209
210static struct attribute *default_attrs[] = {
211	&dev_attr_call_start.attr,
212	&dev_attr_virtual_to_phys.attr,
213	&dev_attr_err_type_info.attr,
214	&dev_attr_err_struct_info.attr,
215	&dev_attr_err_data_buffer.attr,
216	&dev_attr_status.attr,
217	&dev_attr_capabilities.attr,
218	&dev_attr_resources.attr,
219	NULL
220};
221
222static struct attribute_group err_inject_attr_group = {
223	.attrs = default_attrs,
224	.name = "err_inject"
225};
226/* Add/Remove err_inject interface for CPU device */
227static int err_inject_add_dev(unsigned int cpu)
228{
229	struct device *sys_dev = get_cpu_device(cpu);
230
231	return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group);
232}
233
234static int err_inject_remove_dev(unsigned int cpu)
235{
236	struct device *sys_dev = get_cpu_device(cpu);
237
238	sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
239	return 0;
240}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
242static enum cpuhp_state hp_online;
 
243
244static int __init err_inject_init(void)
245{
246	int ret;
 
 
 
 
 
 
 
247#ifdef ERR_INJ_DEBUG
248	printk(KERN_INFO "Enter error injection driver.\n");
249#endif
250
251	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "ia64/err_inj:online",
252				err_inject_add_dev, err_inject_remove_dev);
253	if (ret >= 0) {
254		hp_online = ret;
255		ret = 0;
256	}
257	return ret;
 
 
 
258}
259
260static void __exit err_inject_exit(void)
 
261{
 
 
 
262#ifdef ERR_INJ_DEBUG
263	printk(KERN_INFO "Exit error injection driver.\n");
264#endif
265	cpuhp_remove_state(hp_online);
 
 
 
 
266}
267
268module_init(err_inject_init);
269module_exit(err_inject_exit);
270
271MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>");
272MODULE_DESCRIPTION("MC error injection kernel sysfs interface");
273MODULE_LICENSE("GPL");
v3.1
  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, struct sysdev_attribute *attr,	\
 59		char *buf)						\
 60{									\
 61	u32 cpu=dev->id;						\
 62	return sprintf(buf, "%lx\n", name[cpu]);			\
 63}
 64
 65#define store(name)							\
 66static ssize_t 								\
 67store_##name(struct sys_device *dev, struct sysdev_attribute *attr,	\
 68					const char *buf, size_t size)	\
 69{									\
 70	unsigned int cpu=dev->id;					\
 71	name[cpu] = simple_strtoull(buf, NULL, 16);			\
 72	return size;							\
 73}
 74
 75show(call_start)
 76
 77/* It's user's responsibility to call the PAL procedure on a specific
 78 * processor. The cpu number in driver is only used for storing data.
 79 */
 80static ssize_t
 81store_call_start(struct sys_device *dev, struct sysdev_attribute *attr,
 82		const char *buf, size_t size)
 83{
 84	unsigned int cpu=dev->id;
 85	unsigned long call_start = simple_strtoull(buf, NULL, 16);
 86
 87#ifdef ERR_INJ_DEBUG
 88	printk(KERN_DEBUG "pal_mc_err_inject for cpu%d:\n", cpu);
 89	printk(KERN_DEBUG "err_type_info=%lx,\n", err_type_info[cpu]);
 90	printk(KERN_DEBUG "err_struct_info=%lx,\n", err_struct_info[cpu]);
 91	printk(KERN_DEBUG "err_data_buffer=%lx, %lx, %lx.\n",
 92			  err_data_buffer[cpu].data1,
 93			  err_data_buffer[cpu].data2,
 94			  err_data_buffer[cpu].data3);
 95#endif
 96	switch (call_start) {
 97	    case 0: /* Do nothing. */
 98		break;
 99	    case 1: /* Call pal_mc_error_inject in physical mode. */
100		status[cpu]=ia64_pal_mc_error_inject_phys(err_type_info[cpu],
101					err_struct_info[cpu],
102					ia64_tpa(&err_data_buffer[cpu]),
103					&capabilities[cpu],
104			 		&resources[cpu]);
105		break;
106	    case 2: /* Call pal_mc_error_inject in virtual mode. */
107		status[cpu]=ia64_pal_mc_error_inject_virt(err_type_info[cpu],
108					err_struct_info[cpu],
109					ia64_tpa(&err_data_buffer[cpu]),
110					&capabilities[cpu],
111			 		&resources[cpu]);
112		break;
113	    default:
114		status[cpu] = -EINVAL;
115		break;
116	}
117
118#ifdef ERR_INJ_DEBUG
119	printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]);
120	printk(KERN_DEBUG "capapbilities=%lx,\n", capabilities[cpu]);
121	printk(KERN_DEBUG "resources=%lx\n", resources[cpu]);
122#endif
123	return size;
124}
125
126show(err_type_info)
127store(err_type_info)
128
129static ssize_t
130show_virtual_to_phys(struct sys_device *dev, struct sysdev_attribute *attr,
131			char *buf)
132{
133	unsigned int cpu=dev->id;
134	return sprintf(buf, "%lx\n", phys_addr[cpu]);
135}
136
137static ssize_t
138store_virtual_to_phys(struct sys_device *dev, struct sysdev_attribute *attr,
139			const char *buf, size_t size)
140{
141	unsigned int cpu=dev->id;
142	u64 virt_addr=simple_strtoull(buf, NULL, 16);
143	int ret;
144
145        ret = get_user_pages(current, current->mm, virt_addr,
146                        1, VM_READ, 0, NULL, NULL);
147	if (ret<=0) {
148#ifdef ERR_INJ_DEBUG
149		printk("Virtual address %lx is not existing.\n",virt_addr);
150#endif
151		return -EINVAL;
152	}
153
154	phys_addr[cpu] = ia64_tpa(virt_addr);
155	return size;
156}
157
158show(err_struct_info)
159store(err_struct_info)
160
161static ssize_t
162show_err_data_buffer(struct sys_device *dev,
163			struct sysdev_attribute *attr, char *buf)
164{
165	unsigned int cpu=dev->id;
166
167	return sprintf(buf, "%lx, %lx, %lx\n",
168			err_data_buffer[cpu].data1,
169			err_data_buffer[cpu].data2,
170			err_data_buffer[cpu].data3);
171}
172
173static ssize_t
174store_err_data_buffer(struct sys_device *dev,
175			struct sysdev_attribute *attr,
176			const char *buf, size_t size)
177{
178	unsigned int cpu=dev->id;
179	int ret;
180
181#ifdef ERR_INJ_DEBUG
182	printk("write err_data_buffer=[%lx,%lx,%lx] on cpu%d\n",
183		 err_data_buffer[cpu].data1,
184		 err_data_buffer[cpu].data2,
185		 err_data_buffer[cpu].data3,
186		 cpu);
187#endif
188	ret=sscanf(buf, "%lx, %lx, %lx",
189			&err_data_buffer[cpu].data1,
190			&err_data_buffer[cpu].data2,
191			&err_data_buffer[cpu].data3);
192	if (ret!=ERR_DATA_BUFFER_SIZE)
193		return -EINVAL;
194
195	return size;
196}
197
198show(status)
199show(capabilities)
200show(resources)
201
202define_one_rw(call_start);
203define_one_rw(err_type_info);
204define_one_rw(err_struct_info);
205define_one_rw(err_data_buffer);
206define_one_rw(virtual_to_phys);
207define_one_ro(status);
208define_one_ro(capabilities);
209define_one_ro(resources);
210
211static struct attribute *default_attrs[] = {
212	&attr_call_start.attr,
213	&attr_virtual_to_phys.attr,
214	&attr_err_type_info.attr,
215	&attr_err_struct_info.attr,
216	&attr_err_data_buffer.attr,
217	&attr_status.attr,
218	&attr_capabilities.attr,
219	&attr_resources.attr,
220	NULL
221};
222
223static struct attribute_group err_inject_attr_group = {
224	.attrs = default_attrs,
225	.name = "err_inject"
226};
227/* Add/Remove err_inject interface for CPU device */
228static int __cpuinit err_inject_add_dev(struct sys_device * sys_dev)
229{
 
 
230	return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group);
231}
232
233static int __cpuinit err_inject_remove_dev(struct sys_device * sys_dev)
234{
 
 
235	sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
236	return 0;
237}
238static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
239		unsigned long action, void *hcpu)
240{
241	unsigned int cpu = (unsigned long)hcpu;
242	struct sys_device *sys_dev;
243
244	sys_dev = get_cpu_sysdev(cpu);
245	switch (action) {
246	case CPU_ONLINE:
247	case CPU_ONLINE_FROZEN:
248		err_inject_add_dev(sys_dev);
249		break;
250	case CPU_DEAD:
251	case CPU_DEAD_FROZEN:
252		err_inject_remove_dev(sys_dev);
253		break;
254	}
255
256	return NOTIFY_OK;
257}
258
259static struct notifier_block __cpuinitdata err_inject_cpu_notifier =
260{
261	.notifier_call = err_inject_cpu_callback,
262};
263
264static int __init
265err_inject_init(void)
266{
267	int i;
268
269#ifdef ERR_INJ_DEBUG
270	printk(KERN_INFO "Enter error injection driver.\n");
271#endif
272	for_each_online_cpu(i) {
273		err_inject_cpu_callback(&err_inject_cpu_notifier, CPU_ONLINE,
274				(void *)(long)i);
 
 
 
275	}
276
277	register_hotcpu_notifier(&err_inject_cpu_notifier);
278
279	return 0;
280}
281
282static void __exit
283err_inject_exit(void)
284{
285	int i;
286	struct sys_device *sys_dev;
287
288#ifdef ERR_INJ_DEBUG
289	printk(KERN_INFO "Exit error injection driver.\n");
290#endif
291	for_each_online_cpu(i) {
292		sys_dev = get_cpu_sysdev(i);
293		sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
294	}
295	unregister_hotcpu_notifier(&err_inject_cpu_notifier);
296}
297
298module_init(err_inject_init);
299module_exit(err_inject_exit);
300
301MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>");
302MODULE_DESCRIPTION("MC error injection kernel sysfs interface");
303MODULE_LICENSE("GPL");