]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/edac/edac_module.c
drivers/edac: mod use edac_core.h
[mirror_ubuntu-artful-kernel.git] / drivers / edac / edac_module.c
1
2 #include <linux/freezer.h>
3 #include <linux/kthread.h>
4 #include <linux/edac.h>
5
6 #include "edac_core.h"
7 #include "edac_module.h"
8
9 #define EDAC_MC_VERSION "Ver: 2.0.4 " __DATE__
10
11 #ifdef CONFIG_EDAC_DEBUG
12 /* Values of 0 to 4 will generate output */
13 int edac_debug_level = 1;
14 EXPORT_SYMBOL_GPL(edac_debug_level);
15 #endif
16
17 /* scope is to module level only */
18 struct workqueue_struct *edac_workqueue;
19
20 /* private to this file */
21 static struct task_struct *edac_thread;
22
23
24 /*
25 * sysfs object: /sys/devices/system/edac
26 * need to export to other files in this modules
27 */
28 static struct sysdev_class edac_class = {
29 set_kset_name("edac"),
30 };
31 static int edac_class_valid = 0;
32
33 /*
34 * edac_get_edac_class()
35 *
36 * return pointer to the edac class of 'edac'
37 */
38 struct sysdev_class *edac_get_edac_class(void)
39 {
40 struct sysdev_class *classptr=NULL;
41
42 if (edac_class_valid)
43 classptr = &edac_class;
44
45 return classptr;
46 }
47
48 /*
49 * edac_register_sysfs_edac_name()
50 *
51 * register the 'edac' into /sys/devices/system
52 *
53 * return:
54 * 0 success
55 * !0 error
56 */
57 static int edac_register_sysfs_edac_name(void)
58 {
59 int err;
60
61 /* create the /sys/devices/system/edac directory */
62 err = sysdev_class_register(&edac_class);
63
64 if (err) {
65 debugf1("%s() error=%d\n", __func__, err);
66 return err;
67 }
68
69 edac_class_valid = 1;
70 return 0;
71 }
72
73 /*
74 * sysdev_class_unregister()
75 *
76 * unregister the 'edac' from /sys/devices/system
77 */
78 static void edac_unregister_sysfs_edac_name(void)
79 {
80 /* only if currently registered, then unregister it */
81 if (edac_class_valid)
82 sysdev_class_unregister(&edac_class);
83
84 edac_class_valid = 0;
85 }
86
87
88 /*
89 * Check MC status every edac_get_poll_msec().
90 * Check PCI status every edac_get_poll_msec() as well.
91 *
92 * This where the work gets done for edac.
93 *
94 * SMP safe, doesn't use NMI, and auto-rate-limits.
95 */
96 static void do_edac_check(void)
97 {
98 debugf3("%s()\n", __func__);
99
100 /* perform the poll activities */
101 edac_check_mc_devices();
102 edac_pci_do_parity_check();
103 }
104
105 /*
106 * handler for EDAC to check if NMI type handler has asserted interrupt
107 */
108 static int edac_assert_error_check_and_clear(void)
109 {
110 int vreg;
111
112 if(edac_op_state == EDAC_OPSTATE_POLL)
113 return 1;
114
115 vreg = atomic_read(&edac_err_assert);
116 if(vreg) {
117 atomic_set(&edac_err_assert, 0);
118 return 1;
119 }
120
121 return 0;
122 }
123
124 /*
125 * Action thread for EDAC to perform the POLL operations
126 */
127 static int edac_kernel_thread(void *arg)
128 {
129 int msec;
130
131 while (!kthread_should_stop()) {
132 if(edac_assert_error_check_and_clear())
133 do_edac_check();
134
135 /* goto sleep for the interval */
136 msec = (HZ * edac_get_poll_msec()) / 1000;
137 schedule_timeout_interruptible(msec);
138 try_to_freeze();
139 }
140
141 return 0;
142 }
143
144 /*
145 * edac_workqueue_setup
146 * initialize the edac work queue for polling operations
147 */
148 static int edac_workqueue_setup(void)
149 {
150 edac_workqueue = create_singlethread_workqueue("edac-poller");
151 if (edac_workqueue == NULL)
152 return -ENODEV;
153 else
154 return 0;
155 }
156
157 /*
158 * edac_workqueue_teardown
159 * teardown the edac workqueue
160 */
161 static void edac_workqueue_teardown(void)
162 {
163 if (edac_workqueue) {
164 flush_workqueue(edac_workqueue);
165 destroy_workqueue(edac_workqueue);
166 edac_workqueue = NULL;
167 }
168 }
169
170
171 /*
172 * edac_init
173 * module initialization entry point
174 */
175 static int __init edac_init(void)
176 {
177 int err = 0;
178
179 edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n");
180
181 /*
182 * Harvest and clear any boot/initialization PCI parity errors
183 *
184 * FIXME: This only clears errors logged by devices present at time of
185 * module initialization. We should also do an initial clear
186 * of each newly hotplugged device.
187 */
188 edac_pci_clear_parity_errors();
189
190 /*
191 * perform the registration of the /sys/devices/system/edac object
192 */
193 if (edac_register_sysfs_edac_name()) {
194 edac_printk(KERN_ERR, EDAC_MC,
195 "Error initializing 'edac' kobject\n");
196 err = -ENODEV;
197 goto error;
198 }
199
200 /* Create the MC sysfs entries, must be first
201 */
202 if (edac_sysfs_memctrl_setup()) {
203 edac_printk(KERN_ERR, EDAC_MC,
204 "Error initializing sysfs code\n");
205 err = -ENODEV;
206 goto error_sysfs;
207 }
208
209 /* Create the PCI parity sysfs entries */
210 if (edac_sysfs_pci_setup()) {
211 edac_printk(KERN_ERR, EDAC_MC,
212 "PCI: Error initializing sysfs code\n");
213 err = -ENODEV;
214 goto error_mem;
215 }
216
217 /* Setup/Initialize the edac_device system */
218 err = edac_workqueue_setup();
219 if (err) {
220 edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
221 goto error_pci;
222 }
223
224 /* create our kernel thread */
225 edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac");
226
227 if (IS_ERR(edac_thread)) {
228 err = PTR_ERR(edac_thread);
229 goto error_work;
230 }
231
232 return 0;
233
234 /* Error teardown stack */
235 error_work:
236 edac_workqueue_teardown();
237 error_pci:
238 edac_sysfs_pci_teardown();
239 error_mem:
240 edac_sysfs_memctrl_teardown();
241 error_sysfs:
242 edac_unregister_sysfs_edac_name();
243 error:
244 return err;
245 }
246
247 /*
248 * edac_exit()
249 * module exit/termination function
250 */
251 static void __exit edac_exit(void)
252 {
253 debugf0("%s()\n", __func__);
254 kthread_stop(edac_thread);
255
256 /* tear down the various subsystems*/
257 edac_workqueue_teardown();
258 edac_sysfs_memctrl_teardown();
259 edac_sysfs_pci_teardown();
260 edac_unregister_sysfs_edac_name();
261 }
262
263 /*
264 * Inform the kernel of our entry and exit points
265 */
266 module_init(edac_init);
267 module_exit(edac_exit);
268
269 MODULE_LICENSE("GPL");
270 MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al");
271 MODULE_DESCRIPTION("Core library routines for EDAC reporting");
272
273 /* refer to *_sysfs.c files for parameters that are exported via sysfs */
274
275 #ifdef CONFIG_EDAC_DEBUG
276 module_param(edac_debug_level, int, 0644);
277 MODULE_PARM_DESC(edac_debug_level, "Debug level");
278 #endif
279