blob: dc900ed751789215955a77d5c4d8f04ca24faacd [file] [log] [blame]
Dave Jiang81d87cb2007-07-19 01:49:52 -07001/*
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 */
Dave Jiangc0d12172007-07-19 01:49:46 -070012#include <linux/edac.h>
Douglas Thompson7c9281d2007-07-19 01:49:33 -070013
Douglas Thompson20bcb7a2007-07-19 01:49:47 -070014#include "edac_core.h"
Douglas Thompson7c9281d2007-07-19 01:49:33 -070015#include "edac_module.h"
16
Douglas Thompson20bcb7a2007-07-19 01:49:47 -070017#define EDAC_MC_VERSION "Ver: 2.0.4 " __DATE__
Douglas Thompson7c9281d2007-07-19 01:49:33 -070018
19#ifdef CONFIG_EDAC_DEBUG
20/* Values of 0 to 4 will generate output */
21int edac_debug_level = 1;
22EXPORT_SYMBOL_GPL(edac_debug_level);
23#endif
24
Douglas Thompsone27e3da2007-07-19 01:49:36 -070025/* scope is to module level only */
26struct workqueue_struct *edac_workqueue;
27
Douglas Thompsone27e3da2007-07-19 01:49:36 -070028/*
29 * sysfs object: /sys/devices/system/edac
30 * need to export to other files in this modules
31 */
32static struct sysdev_class edac_class = {
33 set_kset_name("edac"),
34};
35static int edac_class_valid = 0;
36
37/*
38 * edac_get_edac_class()
39 *
40 * return pointer to the edac class of 'edac'
41 */
42struct 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 */
61static 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 */
82static 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
Douglas Thompson7c9281d2007-07-19 01:49:33 -070091/*
Douglas Thompsone27e3da2007-07-19 01:49:36 -070092 * edac_workqueue_setup
93 * initialize the edac work queue for polling operations
94 */
95static 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 */
108static 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/*
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700119 * edac_init
120 * module initialization entry point
121 */
122static int __init edac_init(void)
123{
Douglas Thompsone27e3da2007-07-19 01:49:36 -0700124 int err = 0;
125
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700126 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
Douglas Thompsone27e3da2007-07-19 01:49:36 -0700137 /*
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 */
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700149 if (edac_sysfs_memctrl_setup()) {
150 edac_printk(KERN_ERR, EDAC_MC,
151 "Error initializing sysfs code\n");
Douglas Thompsone27e3da2007-07-19 01:49:36 -0700152 err = -ENODEV;
153 goto error_sysfs;
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700154 }
155
156 /* Create the PCI parity sysfs entries */
157 if (edac_sysfs_pci_setup()) {
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700158 edac_printk(KERN_ERR, EDAC_MC,
159 "PCI: Error initializing sysfs code\n");
Douglas Thompsone27e3da2007-07-19 01:49:36 -0700160 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;
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700169 }
170
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700171 return 0;
Douglas Thompsone27e3da2007-07-19 01:49:36 -0700172
173 /* Error teardown stack */
Douglas Thompsone27e3da2007-07-19 01:49:36 -0700174error_pci:
175 edac_sysfs_pci_teardown();
176error_mem:
177 edac_sysfs_memctrl_teardown();
178error_sysfs:
179 edac_unregister_sysfs_edac_name();
180error:
181 return err;
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700182}
183
184/*
185 * edac_exit()
186 * module exit/termination function
187 */
188static void __exit edac_exit(void)
189{
190 debugf0("%s()\n", __func__);
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700191
Douglas Thompsone27e3da2007-07-19 01:49:36 -0700192 /* tear down the various subsystems*/
193 edac_workqueue_teardown();
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700194 edac_sysfs_memctrl_teardown();
195 edac_sysfs_pci_teardown();
Douglas Thompsone27e3da2007-07-19 01:49:36 -0700196 edac_unregister_sysfs_edac_name();
Douglas Thompson7c9281d2007-07-19 01:49:33 -0700197}
198
199/*
200 * Inform the kernel of our entry and exit points
201 */
202module_init(edac_init);
203module_exit(edac_exit);
204
205MODULE_LICENSE("GPL");
206MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al");
207MODULE_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
212module_param(edac_debug_level, int, 0644);
213MODULE_PARM_DESC(edac_debug_level, "Debug level");
214#endif
215