err_inject.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. #define ERR_INJ_DEBUG
  33. #define ERR_DATA_BUFFER_SIZE 3 // Three 8-byte;
  34. #define define_one_ro(name) \
  35. static SYSDEV_ATTR(name, 0444, show_##name, NULL)
  36. #define define_one_rw(name) \
  37. static SYSDEV_ATTR(name, 0644, show_##name, store_##name)
  38. static u64 call_start[NR_CPUS];
  39. static u64 phys_addr[NR_CPUS];
  40. static u64 err_type_info[NR_CPUS];
  41. static u64 err_struct_info[NR_CPUS];
  42. static struct {
  43. u64 data1;
  44. u64 data2;
  45. u64 data3;
  46. } __attribute__((__aligned__(16))) err_data_buffer[NR_CPUS];
  47. static s64 status[NR_CPUS];
  48. static u64 capabilities[NR_CPUS];
  49. static u64 resources[NR_CPUS];
  50. #define show(name) \
  51. static ssize_t \
  52. show_##name(struct sys_device *dev, char *buf) \
  53. { \
  54. u32 cpu=dev->id; \
  55. return sprintf(buf, "%lx\n", name[cpu]); \
  56. }
  57. #define store(name) \
  58. static ssize_t \
  59. store_##name(struct sys_device *dev, const char *buf, size_t size) \
  60. { \
  61. unsigned int cpu=dev->id; \
  62. name[cpu] = simple_strtoull(buf, NULL, 16); \
  63. return size; \
  64. }
  65. show(call_start)
  66. /* It's user's responsibility to call the PAL procedure on a specific
  67. * processor. The cpu number in driver is only used for storing data.
  68. */
  69. static ssize_t
  70. store_call_start(struct sys_device *dev, const char *buf, size_t size)
  71. {
  72. unsigned int cpu=dev->id;
  73. unsigned long call_start = simple_strtoull(buf, NULL, 16);
  74. #ifdef ERR_INJ_DEBUG
  75. printk(KERN_DEBUG "pal_mc_err_inject for cpu%d:\n", cpu);
  76. printk(KERN_DEBUG "err_type_info=%lx,\n", err_type_info[cpu]);
  77. printk(KERN_DEBUG "err_struct_info=%lx,\n", err_struct_info[cpu]);
  78. printk(KERN_DEBUG "err_data_buffer=%lx, %lx, %lx.\n",
  79. err_data_buffer[cpu].data1,
  80. err_data_buffer[cpu].data2,
  81. err_data_buffer[cpu].data3);
  82. #endif
  83. switch (call_start) {
  84. case 0: /* Do nothing. */
  85. break;
  86. case 1: /* Call pal_mc_error_inject in physical mode. */
  87. status[cpu]=ia64_pal_mc_error_inject_phys(err_type_info[cpu],
  88. err_struct_info[cpu],
  89. ia64_tpa(&err_data_buffer[cpu]),
  90. &capabilities[cpu],
  91. &resources[cpu]);
  92. break;
  93. case 2: /* Call pal_mc_error_inject in virtual mode. */
  94. status[cpu]=ia64_pal_mc_error_inject_virt(err_type_info[cpu],
  95. err_struct_info[cpu],
  96. ia64_tpa(&err_data_buffer[cpu]),
  97. &capabilities[cpu],
  98. &resources[cpu]);
  99. break;
  100. default:
  101. status[cpu] = -EINVAL;
  102. break;
  103. }
  104. #ifdef ERR_INJ_DEBUG
  105. printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]);
  106. printk(KERN_DEBUG "capapbilities=%lx,\n", capabilities[cpu]);
  107. printk(KERN_DEBUG "resources=%lx\n", resources[cpu]);
  108. #endif
  109. return size;
  110. }
  111. show(err_type_info)
  112. store(err_type_info)
  113. static ssize_t
  114. show_virtual_to_phys(struct sys_device *dev, char *buf)
  115. {
  116. unsigned int cpu=dev->id;
  117. return sprintf(buf, "%lx\n", phys_addr[cpu]);
  118. }
  119. static ssize_t
  120. store_virtual_to_phys(struct sys_device *dev, const char *buf, size_t size)
  121. {
  122. unsigned int cpu=dev->id;
  123. u64 virt_addr=simple_strtoull(buf, NULL, 16);
  124. int ret;
  125. ret = get_user_pages(current, current->mm, virt_addr,
  126. 1, VM_READ, 0, NULL, NULL);
  127. if (ret<=0) {
  128. #ifdef ERR_INJ_DEBUG
  129. printk("Virtual address %lx is not existing.\n",virt_addr);
  130. #endif
  131. return -EINVAL;
  132. }
  133. phys_addr[cpu] = ia64_tpa(virt_addr);
  134. return size;
  135. }
  136. show(err_struct_info)
  137. store(err_struct_info)
  138. static ssize_t
  139. show_err_data_buffer(struct sys_device *dev, char *buf)
  140. {
  141. unsigned int cpu=dev->id;
  142. return sprintf(buf, "%lx, %lx, %lx\n",
  143. err_data_buffer[cpu].data1,
  144. err_data_buffer[cpu].data2,
  145. err_data_buffer[cpu].data3);
  146. }
  147. static ssize_t
  148. store_err_data_buffer(struct sys_device *dev, const char *buf, size_t size)
  149. {
  150. unsigned int cpu=dev->id;
  151. int ret;
  152. #ifdef ERR_INJ_DEBUG
  153. printk("write err_data_buffer=[%lx,%lx,%lx] on cpu%d\n",
  154. err_data_buffer[cpu].data1,
  155. err_data_buffer[cpu].data2,
  156. err_data_buffer[cpu].data3,
  157. cpu);
  158. #endif
  159. ret=sscanf(buf, "%lx, %lx, %lx",
  160. &err_data_buffer[cpu].data1,
  161. &err_data_buffer[cpu].data2,
  162. &err_data_buffer[cpu].data3);
  163. if (ret!=ERR_DATA_BUFFER_SIZE)
  164. return -EINVAL;
  165. return size;
  166. }
  167. show(status)
  168. show(capabilities)
  169. show(resources)
  170. define_one_rw(call_start);
  171. define_one_rw(err_type_info);
  172. define_one_rw(err_struct_info);
  173. define_one_rw(err_data_buffer);
  174. define_one_rw(virtual_to_phys);
  175. define_one_ro(status);
  176. define_one_ro(capabilities);
  177. define_one_ro(resources);
  178. static struct attribute *default_attrs[] = {
  179. &attr_call_start.attr,
  180. &attr_virtual_to_phys.attr,
  181. &attr_err_type_info.attr,
  182. &attr_err_struct_info.attr,
  183. &attr_err_data_buffer.attr,
  184. &attr_status.attr,
  185. &attr_capabilities.attr,
  186. &attr_resources.attr,
  187. NULL
  188. };
  189. static struct attribute_group err_inject_attr_group = {
  190. .attrs = default_attrs,
  191. .name = "err_inject"
  192. };
  193. /* Add/Remove err_inject interface for CPU device */
  194. static int __cpuinit err_inject_add_dev(struct sys_device * sys_dev)
  195. {
  196. return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group);
  197. }
  198. static int __cpuinit err_inject_remove_dev(struct sys_device * sys_dev)
  199. {
  200. sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
  201. return 0;
  202. }
  203. static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
  204. unsigned long action, void *hcpu)
  205. {
  206. unsigned int cpu = (unsigned long)hcpu;
  207. struct sys_device *sys_dev;
  208. sys_dev = get_cpu_sysdev(cpu);
  209. switch (action) {
  210. case CPU_ONLINE:
  211. case CPU_ONLINE_FROZEN:
  212. err_inject_add_dev(sys_dev);
  213. break;
  214. case CPU_DEAD:
  215. case CPU_DEAD_FROZEN:
  216. err_inject_remove_dev(sys_dev);
  217. break;
  218. }
  219. return NOTIFY_OK;
  220. }
  221. static struct notifier_block __cpuinitdata err_inject_cpu_notifier =
  222. {
  223. .notifier_call = err_inject_cpu_callback,
  224. };
  225. static int __init
  226. err_inject_init(void)
  227. {
  228. int i;
  229. #ifdef ERR_INJ_DEBUG
  230. printk(KERN_INFO "Enter error injection driver.\n");
  231. #endif
  232. for_each_online_cpu(i) {
  233. err_inject_cpu_callback(&err_inject_cpu_notifier, CPU_ONLINE,
  234. (void *)(long)i);
  235. }
  236. register_hotcpu_notifier(&err_inject_cpu_notifier);
  237. return 0;
  238. }
  239. static void __exit
  240. err_inject_exit(void)
  241. {
  242. int i;
  243. struct sys_device *sys_dev;
  244. #ifdef ERR_INJ_DEBUG
  245. printk(KERN_INFO "Exit error injection driver.\n");
  246. #endif
  247. for_each_online_cpu(i) {
  248. sys_dev = get_cpu_sysdev(i);
  249. sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
  250. }
  251. unregister_hotcpu_notifier(&err_inject_cpu_notifier);
  252. }
  253. module_init(err_inject_init);
  254. module_exit(err_inject_exit);
  255. MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>");
  256. MODULE_DESCRIPTION("MC error injection kernel sysfs interface");
  257. MODULE_LICENSE("GPL");