xref: /openbmc/linux/drivers/edac/edac_module.c (revision a36954f5)
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, 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