aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/edac_module.c
diff options
context:
space:
mode:
authorDouglas Thompson <dougthompson@xmission.com>2007-07-19 04:49:36 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:53 -0400
commite27e3dac651771fe3250f6305dee277bce29fc5d (patch)
tree9c0ac81a0948d8e52a72865ff9fbae4a12031a32 /drivers/edac/edac_module.c
parent7c9281d76c1c0b130f79d5fc021084e9749959d4 (diff)
drivers/edac: add edac_device class
This patch adds the new 'class' of object to be managed, named: 'edac_device'. As a peer of the 'edac_mc' class of object, it provides a non-memory centric view of an ERROR DETECTING device in hardware. It provides a sysfs interface and an abstraction for varioius EDAC type devices. Multiple 'instances' within the class are possible, with each 'instance' able to have multiple 'blocks', and each 'block' having 'attributes'. At the 'block' level there are the 'ce_count' and 'ue_count' fields which the device driver can update and/or call edac_device_handle_XX() functions. At each higher level are additional 'total' count fields, which are a summation of counts below that level. This 'edac_device' has been used to capture and present ECC errors which are found in a a L1 and L2 system on a per CORE/CPU basis. Signed-off-by: Douglas Thompson <dougthompson@xmission.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/edac/edac_module.c')
-rw-r--r--drivers/edac/edac_module.c147
1 files changed, 138 insertions, 9 deletions
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
index 8db0471a9476..3cd3a236821c 100644
--- a/drivers/edac/edac_module.c
+++ b/drivers/edac/edac_module.c
@@ -13,8 +13,77 @@ int edac_debug_level = 1;
13EXPORT_SYMBOL_GPL(edac_debug_level); 13EXPORT_SYMBOL_GPL(edac_debug_level);
14#endif 14#endif
15 15
16/* scope is to module level only */
17struct workqueue_struct *edac_workqueue;
18
19/* private to this file */
16static struct task_struct *edac_thread; 20static struct task_struct *edac_thread;
17 21
22
23/*
24 * sysfs object: /sys/devices/system/edac
25 * need to export to other files in this modules
26 */
27static struct sysdev_class edac_class = {
28 set_kset_name("edac"),
29};
30static int edac_class_valid = 0;
31
32/*
33 * edac_get_edac_class()
34 *
35 * return pointer to the edac class of 'edac'
36 */
37struct sysdev_class *edac_get_edac_class(void)
38{
39 struct sysdev_class *classptr=NULL;
40
41 if (edac_class_valid)
42 classptr = &edac_class;
43
44 return classptr;
45}
46
47/*
48 * edac_register_sysfs_edac_name()
49 *
50 * register the 'edac' into /sys/devices/system
51 *
52 * return:
53 * 0 success
54 * !0 error
55 */
56static int edac_register_sysfs_edac_name(void)
57{
58 int err;
59
60 /* create the /sys/devices/system/edac directory */
61 err = sysdev_class_register(&edac_class);
62
63 if (err) {
64 debugf1("%s() error=%d\n", __func__, err);
65 return err;
66 }
67
68 edac_class_valid = 1;
69 return 0;
70}
71
72/*
73 * sysdev_class_unregister()
74 *
75 * unregister the 'edac' from /sys/devices/system
76 */
77static void edac_unregister_sysfs_edac_name(void)
78{
79 /* only if currently registered, then unregister it */
80 if (edac_class_valid)
81 sysdev_class_unregister(&edac_class);
82
83 edac_class_valid = 0;
84}
85
86
18/* 87/*
19 * Check MC status every edac_get_poll_msec(). 88 * Check MC status every edac_get_poll_msec().
20 * Check PCI status every edac_get_poll_msec() as well. 89 * Check PCI status every edac_get_poll_msec() as well.
@@ -53,11 +122,40 @@ static int edac_kernel_thread(void *arg)
53} 122}
54 123
55/* 124/*
125 * edac_workqueue_setup
126 * initialize the edac work queue for polling operations
127 */
128static int edac_workqueue_setup(void)
129{
130 edac_workqueue = create_singlethread_workqueue("edac-poller");
131 if (edac_workqueue == NULL)
132 return -ENODEV;
133 else
134 return 0;
135}
136
137/*
138 * edac_workqueue_teardown
139 * teardown the edac workqueue
140 */
141static void edac_workqueue_teardown(void)
142{
143 if (edac_workqueue) {
144 flush_workqueue(edac_workqueue);
145 destroy_workqueue(edac_workqueue);
146 edac_workqueue = NULL;
147 }
148}
149
150
151/*
56 * edac_init 152 * edac_init
57 * module initialization entry point 153 * module initialization entry point
58 */ 154 */
59static int __init edac_init(void) 155static int __init edac_init(void)
60{ 156{
157 int err = 0;
158
61 edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n"); 159 edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n");
62 160
63 /* 161 /*
@@ -69,32 +167,61 @@ static int __init edac_init(void)
69 */ 167 */
70 edac_pci_clear_parity_errors(); 168 edac_pci_clear_parity_errors();
71 169
72 /* Create the MC sysfs entries */ 170 /*
171 * perform the registration of the /sys/devices/system/edac object
172 */
173 if (edac_register_sysfs_edac_name()) {
174 edac_printk(KERN_ERR, EDAC_MC,
175 "Error initializing 'edac' kobject\n");
176 err = -ENODEV;
177 goto error;
178 }
179
180 /* Create the MC sysfs entries, must be first
181 */
73 if (edac_sysfs_memctrl_setup()) { 182 if (edac_sysfs_memctrl_setup()) {
74 edac_printk(KERN_ERR, EDAC_MC, 183 edac_printk(KERN_ERR, EDAC_MC,
75 "Error initializing sysfs code\n"); 184 "Error initializing sysfs code\n");
76 return -ENODEV; 185 err = -ENODEV;
186 goto error_sysfs;
77 } 187 }
78 188
79 /* Create the PCI parity sysfs entries */ 189 /* Create the PCI parity sysfs entries */
80 if (edac_sysfs_pci_setup()) { 190 if (edac_sysfs_pci_setup()) {
81 edac_sysfs_memctrl_teardown();
82 edac_printk(KERN_ERR, EDAC_MC, 191 edac_printk(KERN_ERR, EDAC_MC,
83 "PCI: Error initializing sysfs code\n"); 192 "PCI: Error initializing sysfs code\n");
84 return -ENODEV; 193 err = -ENODEV;
194 goto error_mem;
195 }
196
197 /* Setup/Initialize the edac_device system */
198 err = edac_workqueue_setup();
199 if (err) {
200 edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
201 goto error_pci;
85 } 202 }
86 203
87 /* create our kernel thread */ 204 /* create our kernel thread */
88 edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac"); 205 edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac");
89 206
90 if (IS_ERR(edac_thread)) { 207 if (IS_ERR(edac_thread)) {
91 /* remove the sysfs entries */ 208 err = PTR_ERR(edac_thread);
92 edac_sysfs_memctrl_teardown(); 209 goto error_work;
93 edac_sysfs_pci_teardown();
94 return PTR_ERR(edac_thread);
95 } 210 }
96 211
97 return 0; 212 return 0;
213
214 /* Error teardown stack */
215error_work:
216 edac_workqueue_teardown();
217error_pci:
218 edac_sysfs_pci_teardown();
219error_mem:
220 edac_sysfs_memctrl_teardown();
221error_sysfs:
222 edac_unregister_sysfs_edac_name();
223error:
224 return err;
98} 225}
99 226
100/* 227/*
@@ -106,9 +233,11 @@ static void __exit edac_exit(void)
106 debugf0("%s()\n", __func__); 233 debugf0("%s()\n", __func__);
107 kthread_stop(edac_thread); 234 kthread_stop(edac_thread);
108 235
109 /* tear down the sysfs device */ 236 /* tear down the various subsystems*/
237 edac_workqueue_teardown();
110 edac_sysfs_memctrl_teardown(); 238 edac_sysfs_memctrl_teardown();
111 edac_sysfs_pci_teardown(); 239 edac_sysfs_pci_teardown();
240 edac_unregister_sysfs_edac_name();
112} 241}
113 242
114/* 243/*