at v4.13-rc2 167 lines 3.4 kB view raw
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 22static 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 */ 38int edac_debug_level = 2; 39EXPORT_SYMBOL_GPL(edac_debug_level); 40 41module_param_call(edac_debug_level, edac_set_debug_level, param_get_int, 42 &edac_debug_level, 0644); 43MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2"); 44#endif 45 46/* 47 * edac_op_state_to_string() 48 */ 49char *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 */ 69static struct bus_type edac_subsys = { 70 .name = "edac", 71 .dev_name = "edac", 72}; 73 74static 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 86static void edac_subsys_exit(void) 87{ 88 bus_unregister(&edac_subsys); 89} 90 91/* return pointer to the 'edac' node in sysfs */ 92struct bus_type *edac_get_sysfs_subsys(void) 93{ 94 return &edac_subsys; 95} 96EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys); 97/* 98 * edac_init 99 * module initialization entry point 100 */ 101static 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 134err_wq: 135 edac_debugfs_exit(); 136 edac_mc_sysfs_exit(); 137 138err_sysfs: 139 edac_subsys_exit(); 140 141 return err; 142} 143 144/* 145 * edac_exit() 146 * module exit/termination function 147 */ 148static 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 */ 162subsys_initcall(edac_init); 163module_exit(edac_exit); 164 165MODULE_LICENSE("GPL"); 166MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al"); 167MODULE_DESCRIPTION("Core library routines for EDAC reporting");