dc900ed751789215955a77d5c4d8f04ca24faacd
[linux-3.10.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