Merge branch 'for_rmk' of git://git.mnementh.co.uk/linux-2.6-im into devel
[linux-2.6] / drivers / edac / edac_module.c
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: 2.1.0 " __DATE__
19
20 #ifdef CONFIG_EDAC_DEBUG
21 /* Values of 0 to 4 will generate output */
22 int edac_debug_level = 2;
23 EXPORT_SYMBOL_GPL(edac_debug_level);
24 #endif
25
26 /* scope is to module level only */
27 struct workqueue_struct *edac_workqueue;
28
29 /*
30  * sysfs object: /sys/devices/system/edac
31  *      need to export to other files in this modules
32  */
33 static struct sysdev_class edac_class = {
34         .name = "edac",
35 };
36 static int edac_class_valid;
37
38 /*
39  * edac_op_state_to_string()
40  */
41 char *edac_op_state_to_string(int opstate)
42 {
43         if (opstate == OP_RUNNING_POLL)
44                 return "POLLED";
45         else if (opstate == OP_RUNNING_INTERRUPT)
46                 return "INTERRUPT";
47         else if (opstate == OP_RUNNING_POLL_INTR)
48                 return "POLL-INTR";
49         else if (opstate == OP_ALLOC)
50                 return "ALLOC";
51         else if (opstate == OP_OFFLINE)
52                 return "OFFLINE";
53
54         return "UNKNOWN";
55 }
56
57 /*
58  * edac_get_edac_class()
59  *
60  *      return pointer to the edac class of 'edac'
61  */
62 struct sysdev_class *edac_get_edac_class(void)
63 {
64         struct sysdev_class *classptr = NULL;
65
66         if (edac_class_valid)
67                 classptr = &edac_class;
68
69         return classptr;
70 }
71
72 /*
73  * edac_register_sysfs_edac_name()
74  *
75  *      register the 'edac' into /sys/devices/system
76  *
77  * return:
78  *      0  success
79  *      !0 error
80  */
81 static int edac_register_sysfs_edac_name(void)
82 {
83         int err;
84
85         /* create the /sys/devices/system/edac directory */
86         err = sysdev_class_register(&edac_class);
87
88         if (err) {
89                 debugf1("%s() error=%d\n", __func__, err);
90                 return err;
91         }
92
93         edac_class_valid = 1;
94         return 0;
95 }
96
97 /*
98  * sysdev_class_unregister()
99  *
100  *      unregister the 'edac' from /sys/devices/system
101  */
102 static void edac_unregister_sysfs_edac_name(void)
103 {
104         /* only if currently registered, then unregister it */
105         if (edac_class_valid)
106                 sysdev_class_unregister(&edac_class);
107
108         edac_class_valid = 0;
109 }
110
111 /*
112  * edac_workqueue_setup
113  *      initialize the edac work queue for polling operations
114  */
115 static int edac_workqueue_setup(void)
116 {
117         edac_workqueue = create_singlethread_workqueue("edac-poller");
118         if (edac_workqueue == NULL)
119                 return -ENODEV;
120         else
121                 return 0;
122 }
123
124 /*
125  * edac_workqueue_teardown
126  *      teardown the edac workqueue
127  */
128 static void edac_workqueue_teardown(void)
129 {
130         if (edac_workqueue) {
131                 flush_workqueue(edac_workqueue);
132                 destroy_workqueue(edac_workqueue);
133                 edac_workqueue = NULL;
134         }
135 }
136
137 /*
138  * edac_init
139  *      module initialization entry point
140  */
141 static int __init edac_init(void)
142 {
143         int err = 0;
144
145         edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n");
146
147         /*
148          * Harvest and clear any boot/initialization PCI parity errors
149          *
150          * FIXME: This only clears errors logged by devices present at time of
151          *      module initialization.  We should also do an initial clear
152          *      of each newly hotplugged device.
153          */
154         edac_pci_clear_parity_errors();
155
156         /*
157          * perform the registration of the /sys/devices/system/edac class object
158          */
159         if (edac_register_sysfs_edac_name()) {
160                 edac_printk(KERN_ERR, EDAC_MC,
161                         "Error initializing 'edac' kobject\n");
162                 err = -ENODEV;
163                 goto error;
164         }
165
166         /*
167          * now set up the mc_kset under the edac class object
168          */
169         err = edac_sysfs_setup_mc_kset();
170         if (err)
171                 goto sysfs_setup_fail;
172
173         /* Setup/Initialize the workq for this core */
174         err = edac_workqueue_setup();
175         if (err) {
176                 edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
177                 goto workq_fail;
178         }
179
180         return 0;
181
182         /* Error teardown stack */
183 workq_fail:
184         edac_sysfs_teardown_mc_kset();
185
186 sysfs_setup_fail:
187         edac_unregister_sysfs_edac_name();
188
189 error:
190         return err;
191 }
192
193 /*
194  * edac_exit()
195  *      module exit/termination function
196  */
197 static void __exit edac_exit(void)
198 {
199         debugf0("%s()\n", __func__);
200
201         /* tear down the various subsystems */
202         edac_workqueue_teardown();
203         edac_sysfs_teardown_mc_kset();
204         edac_unregister_sysfs_edac_name();
205 }
206
207 /*
208  * Inform the kernel of our entry and exit points
209  */
210 module_init(edac_init);
211 module_exit(edac_exit);
212
213 MODULE_LICENSE("GPL");
214 MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al");
215 MODULE_DESCRIPTION("Core library routines for EDAC reporting");
216
217 /* refer to *_sysfs.c files for parameters that are exported via sysfs */
218
219 #ifdef CONFIG_EDAC_DEBUG
220 module_param(edac_debug_level, int, 0644);
221 MODULE_PARM_DESC(edac_debug_level, "Debug level");
222 #endif