]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - drivers/edac/edac_module.c
drivers/edac: mod MC to use workq instead of kthread
[mirror_ubuntu-zesty-kernel.git] / drivers / edac / edac_module.c
1 /*
2 * edac_module.c
3 *
4 * (C) 2007 www.douglaskthompson.com
5 * This file is licensed under the terms of the GNU General Public
6 * License version 2. This program is licensed "as is" without any
7 * warranty of any kind, whether express or implied.
8 *
9 * Author: Doug Thompson <norsk5@xmission.com>
10 *
11 */
12 #include <linux/edac.h>
13
14 #include "edac_core.h"
15 #include "edac_module.h"
16
17 #define EDAC_MC_VERSION "Ver: 2.0.4 " __DATE__
18
19 #ifdef CONFIG_EDAC_DEBUG
20 /* Values of 0 to 4 will generate output */
21 int edac_debug_level = 1;
22 EXPORT_SYMBOL_GPL(edac_debug_level);
23 #endif
24
25 /* scope is to module level only */
26 struct workqueue_struct *edac_workqueue;
27
28 /*
29 * sysfs object: /sys/devices/system/edac
30 * need to export to other files in this modules
31 */
32 static struct sysdev_class edac_class = {
33 set_kset_name("edac"),
34 };
35 static int edac_class_valid = 0;
36
37 /*
38 * edac_get_edac_class()
39 *
40 * return pointer to the edac class of 'edac'
41 */
42 struct sysdev_class *edac_get_edac_class(void)
43 {
44 struct sysdev_class *classptr=NULL;
45
46 if (edac_class_valid)
47 classptr = &edac_class;
48
49 return classptr;
50 }
51
52 /*
53 * edac_register_sysfs_edac_name()
54 *
55 * register the 'edac' into /sys/devices/system
56 *
57 * return:
58 * 0 success
59 * !0 error
60 */
61 static int edac_register_sysfs_edac_name(void)
62 {
63 int err;
64
65 /* create the /sys/devices/system/edac directory */
66 err = sysdev_class_register(&edac_class);
67
68 if (err) {
69 debugf1("%s() error=%d\n", __func__, err);
70 return err;
71 }
72
73 edac_class_valid = 1;
74 return 0;
75 }
76
77 /*
78 * sysdev_class_unregister()
79 *
80 * unregister the 'edac' from /sys/devices/system
81 */
82 static void edac_unregister_sysfs_edac_name(void)
83 {
84 /* only if currently registered, then unregister it */
85 if (edac_class_valid)
86 sysdev_class_unregister(&edac_class);
87
88 edac_class_valid = 0;
89 }
90
91 /*
92 * edac_workqueue_setup
93 * initialize the edac work queue for polling operations
94 */
95 static int edac_workqueue_setup(void)
96 {
97 edac_workqueue = create_singlethread_workqueue("edac-poller");
98 if (edac_workqueue == NULL)
99 return -ENODEV;
100 else
101 return 0;
102 }
103
104 /*
105 * edac_workqueue_teardown
106 * teardown the edac workqueue
107 */
108 static void edac_workqueue_teardown(void)
109 {
110 if (edac_workqueue) {
111 flush_workqueue(edac_workqueue);
112 destroy_workqueue(edac_workqueue);
113 edac_workqueue = NULL;
114 }
115 }
116
117
118 /*
119 * edac_init
120 * module initialization entry point
121 */
122 static int __init edac_init(void)
123 {
124 int err = 0;
125
126 edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n");
127
128 /*
129 * Harvest and clear any boot/initialization PCI parity errors
130 *
131 * FIXME: This only clears errors logged by devices present at time of
132 * module initialization. We should also do an initial clear
133 * of each newly hotplugged device.
134 */
135 edac_pci_clear_parity_errors();
136
137 /*
138 * perform the registration of the /sys/devices/system/edac object
139 */
140 if (edac_register_sysfs_edac_name()) {
141 edac_printk(KERN_ERR, EDAC_MC,
142 "Error initializing 'edac' kobject\n");
143 err = -ENODEV;
144 goto error;
145 }
146
147 /* Create the MC sysfs entries, must be first
148 */
149 if (edac_sysfs_memctrl_setup()) {
150 edac_printk(KERN_ERR, EDAC_MC,
151 "Error initializing sysfs code\n");
152 err = -ENODEV;
153 goto error_sysfs;
154 }
155
156 /* Create the PCI parity sysfs entries */
157 if (edac_sysfs_pci_setup()) {
158 edac_printk(KERN_ERR, EDAC_MC,
159 "PCI: Error initializing sysfs code\n");
160 err = -ENODEV;
161 goto error_mem;
162 }
163
164 /* Setup/Initialize the edac_device system */
165 err = edac_workqueue_setup();
166 if (err) {
167 edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
168 goto error_pci;
169 }
170
171 return 0;
172
173 /* Error teardown stack */
174 error_pci:
175 edac_sysfs_pci_teardown();
176 error_mem:
177 edac_sysfs_memctrl_teardown();
178 error_sysfs:
179 edac_unregister_sysfs_edac_name();
180 error:
181 return err;
182 }
183
184 /*
185 * edac_exit()
186 * module exit/termination function
187 */
188 static void __exit edac_exit(void)
189 {
190 debugf0("%s()\n", __func__);
191
192 /* tear down the various subsystems*/
193 edac_workqueue_teardown();
194 edac_sysfs_memctrl_teardown();
195 edac_sysfs_pci_teardown();
196 edac_unregister_sysfs_edac_name();
197 }
198
199 /*
200 * Inform the kernel of our entry and exit points
201 */
202 module_init(edac_init);
203 module_exit(edac_exit);
204
205 MODULE_LICENSE("GPL");
206 MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al");
207 MODULE_DESCRIPTION("Core library routines for EDAC reporting");
208
209 /* refer to *_sysfs.c files for parameters that are exported via sysfs */
210
211 #ifdef CONFIG_EDAC_DEBUG
212 module_param(edac_debug_level, int, 0644);
213 MODULE_PARM_DESC(edac_debug_level, "Debug level");
214 #endif
215