1 /* 2 * edac_module.c 3 * 4 * (C) 2007 www.softwarebitmaker.com 5 * 6 * This file is licensed under the terms of the GNU General Public 7 * License version 2. This program is licensed "as is" without any 8 * warranty of any kind, whether express or implied. 9 * 10 * Author: Doug Thompson <dougthompson@xmission.com> 11 * 12 */ 13 #include <linux/edac.h> 14 15 #include "edac_mc.h" 16 #include "edac_module.h" 17 18 #define EDAC_VERSION "Ver: 3.0.0" 19 20 #ifdef CONFIG_EDAC_DEBUG 21 22 static int edac_set_debug_level(const char *buf, 23 const struct kernel_param *kp) 24 { 25 unsigned long val; 26 int ret; 27 28 ret = kstrtoul(buf, 0, &val); 29 if (ret) 30 return ret; 31 32 if (val > 4) 33 return -EINVAL; 34 35 return param_set_int(buf, kp); 36 } 37 38 /* Values of 0 to 4 will generate output */ 39 int edac_debug_level = 2; 40 EXPORT_SYMBOL_GPL(edac_debug_level); 41 42 module_param_call(edac_debug_level, edac_set_debug_level, param_get_int, 43 &edac_debug_level, 0644); 44 MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2"); 45 #endif 46 47 /* 48 * edac_op_state_to_string() 49 */ 50 char *edac_op_state_to_string(int opstate) 51 { 52 if (opstate == OP_RUNNING_POLL) 53 return "POLLED"; 54 else if (opstate == OP_RUNNING_INTERRUPT) 55 return "INTERRUPT"; 56 else if (opstate == OP_RUNNING_POLL_INTR) 57 return "POLL-INTR"; 58 else if (opstate == OP_ALLOC) 59 return "ALLOC"; 60 else if (opstate == OP_OFFLINE) 61 return "OFFLINE"; 62 63 return "UNKNOWN"; 64 } 65 66 /* 67 * sysfs object: /sys/devices/system/edac 68 * need to export to other files 69 */ 70 static struct bus_type edac_subsys = { 71 .name = "edac", 72 .dev_name = "edac", 73 }; 74 75 static int edac_subsys_init(void) 76 { 77 int err; 78 79 /* create the /sys/devices/system/edac directory */ 80 err = subsys_system_register(&edac_subsys, NULL); 81 if (err) 82 printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n"); 83 84 return err; 85 } 86 87 static void edac_subsys_exit(void) 88 { 89 bus_unregister(&edac_subsys); 90 } 91 92 /* return pointer to the 'edac' node in sysfs */ 93 struct bus_type *edac_get_sysfs_subsys(void) 94 { 95 return &edac_subsys; 96 } 97 EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys); 98 /* 99 * edac_init 100 * module initialization entry point 101 */ 102 static int __init edac_init(void) 103 { 104 int err = 0; 105 106 edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n"); 107 108 err = edac_subsys_init(); 109 if (err) 110 return err; 111 112 /* 113 * Harvest and clear any boot/initialization PCI parity errors 114 * 115 * FIXME: This only clears errors logged by devices present at time of 116 * module initialization. We should also do an initial clear 117 * of each newly hotplugged device. 118 */ 119 edac_pci_clear_parity_errors(); 120 121 err = edac_mc_sysfs_init(); 122 if (err) 123 goto err_sysfs; 124 125 edac_debugfs_init(); 126 127 err = edac_workqueue_setup(); 128 if (err) { 129 edac_printk(KERN_ERR, EDAC_MC, "Failure initializing workqueue\n"); 130 goto err_wq; 131 } 132 133 return 0; 134 135 err_wq: 136 edac_debugfs_exit(); 137 edac_mc_sysfs_exit(); 138 139 err_sysfs: 140 edac_subsys_exit(); 141 142 return err; 143 } 144 145 /* 146 * edac_exit() 147 * module exit/termination function 148 */ 149 static void __exit edac_exit(void) 150 { 151 edac_dbg(0, "\n"); 152 153 /* tear down the various subsystems */ 154 edac_workqueue_teardown(); 155 edac_mc_sysfs_exit(); 156 edac_debugfs_exit(); 157 edac_subsys_exit(); 158 } 159 160 /* 161 * Inform the kernel of our entry and exit points 162 */ 163 subsys_initcall(edac_init); 164 module_exit(edac_exit); 165 166 MODULE_LICENSE("GPL"); 167 MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al"); 168 MODULE_DESCRIPTION("Core library routines for EDAC reporting"); 169