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