Commit | Line | Data |
---|---|---|
81d87cb1 DJ |
1 | /* |
2 | * edac_module.c | |
3 | * | |
fb3fb206 DT |
4 | * (C) 2007 www.softwarebitmaker.com |
5 | * | |
81d87cb1 DJ |
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 | * | |
fb3fb206 | 10 | * Author: Doug Thompson <dougthompson@xmission.com> |
81d87cb1 DJ |
11 | * |
12 | */ | |
c0d12172 | 13 | #include <linux/edac.h> |
7c9281d7 | 14 | |
78d88e8a | 15 | #include "edac_mc.h" |
7c9281d7 DT |
16 | #include "edac_module.h" |
17 | ||
5156a5f4 | 18 | #define EDAC_VERSION "Ver: 3.0.0" |
7c9281d7 DT |
19 | |
20 | #ifdef CONFIG_EDAC_DEBUG | |
37929874 | 21 | |
e4dca7b7 KC |
22 | static int edac_set_debug_level(const char *buf, |
23 | const struct kernel_param *kp) | |
37929874 BP |
24 | { |
25 | unsigned long val; | |
26 | int ret; | |
27 | ||
28 | ret = kstrtoul(buf, 0, &val); | |
29 | if (ret) | |
30 | return ret; | |
31 | ||
6866b390 | 32 | if (val > 4) |
37929874 BP |
33 | return -EINVAL; |
34 | ||
35 | return param_set_int(buf, kp); | |
36 | } | |
37 | ||
7c9281d7 | 38 | /* Values of 0 to 4 will generate output */ |
8096cfaf | 39 | int edac_debug_level = 2; |
7c9281d7 | 40 | EXPORT_SYMBOL_GPL(edac_debug_level); |
37929874 BP |
41 | |
42 | module_param_call(edac_debug_level, edac_set_debug_level, param_get_int, | |
43 | &edac_debug_level, 0644); | |
44 | MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2"); | |
7c9281d7 DT |
45 | #endif |
46 | ||
91b99041 | 47 | /* |
494d0d55 | 48 | * edac_op_state_to_string() |
91b99041 | 49 | */ |
494d0d55 | 50 | char *edac_op_state_to_string(int opstate) |
91b99041 DJ |
51 | { |
52 | if (opstate == OP_RUNNING_POLL) | |
53 | return "POLLED"; | |
54 | else if (opstate == OP_RUNNING_INTERRUPT) | |
55 | return "INTERRUPT"; | |
56 | else if (opstate == OP_RUNNING_POLL_INTR) | |
57 | return "POLL-INTR"; | |
58 | else if (opstate == OP_ALLOC) | |
59 | return "ALLOC"; | |
60 | else if (opstate == OP_OFFLINE) | |
61 | return "OFFLINE"; | |
62 | ||
63 | return "UNKNOWN"; | |
64 | } | |
65 | ||
733476cf BP |
66 | /* |
67 | * sysfs object: /sys/devices/system/edac | |
68 | * need to export to other files | |
69 | */ | |
a97d2627 | 70 | static struct bus_type edac_subsys = { |
733476cf BP |
71 | .name = "edac", |
72 | .dev_name = "edac", | |
73 | }; | |
733476cf BP |
74 | |
75 | static int edac_subsys_init(void) | |
76 | { | |
77 | int err; | |
78 | ||
79 | /* create the /sys/devices/system/edac directory */ | |
80 | err = subsys_system_register(&edac_subsys, NULL); | |
81 | if (err) | |
82 | printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n"); | |
83 | ||
84 | return err; | |
85 | } | |
86 | ||
87 | static void edac_subsys_exit(void) | |
88 | { | |
89 | bus_unregister(&edac_subsys); | |
90 | } | |
91 | ||
92 | /* return pointer to the 'edac' node in sysfs */ | |
93 | struct bus_type *edac_get_sysfs_subsys(void) | |
94 | { | |
95 | return &edac_subsys; | |
96 | } | |
97 | EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys); | |
7c9281d7 DT |
98 | /* |
99 | * edac_init | |
100 | * module initialization entry point | |
101 | */ | |
102 | static int __init edac_init(void) | |
103 | { | |
e27e3dac DT |
104 | int err = 0; |
105 | ||
fb3fb206 | 106 | edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n"); |
7c9281d7 | 107 | |
733476cf BP |
108 | err = edac_subsys_init(); |
109 | if (err) | |
110 | return err; | |
111 | ||
7c9281d7 DT |
112 | /* |
113 | * Harvest and clear any boot/initialization PCI parity errors | |
114 | * | |
115 | * FIXME: This only clears errors logged by devices present at time of | |
079708b9 DT |
116 | * module initialization. We should also do an initial clear |
117 | * of each newly hotplugged device. | |
7c9281d7 DT |
118 | */ |
119 | edac_pci_clear_parity_errors(); | |
120 | ||
7a623c03 | 121 | err = edac_mc_sysfs_init(); |
8096cfaf | 122 | if (err) |
c6b97bcf | 123 | goto err_sysfs; |
7c9281d7 | 124 | |
e7930ba4 RH |
125 | edac_debugfs_init(); |
126 | ||
e27e3dac DT |
127 | err = edac_workqueue_setup(); |
128 | if (err) { | |
c6b97bcf AK |
129 | edac_printk(KERN_ERR, EDAC_MC, "Failure initializing workqueue\n"); |
130 | goto err_wq; | |
7c9281d7 DT |
131 | } |
132 | ||
7c9281d7 | 133 | return 0; |
e27e3dac | 134 | |
c6b97bcf AK |
135 | err_wq: |
136 | edac_debugfs_exit(); | |
137 | edac_mc_sysfs_exit(); | |
138 | ||
139 | err_sysfs: | |
733476cf BP |
140 | edac_subsys_exit(); |
141 | ||
e27e3dac | 142 | return err; |
7c9281d7 DT |
143 | } |
144 | ||
145 | /* | |
146 | * edac_exit() | |
147 | * module exit/termination function | |
148 | */ | |
149 | static void __exit edac_exit(void) | |
150 | { | |
956b9ba1 | 151 | edac_dbg(0, "\n"); |
7c9281d7 | 152 | |
079708b9 | 153 | /* tear down the various subsystems */ |
e27e3dac | 154 | edac_workqueue_teardown(); |
7a623c03 | 155 | edac_mc_sysfs_exit(); |
e7930ba4 | 156 | edac_debugfs_exit(); |
733476cf | 157 | edac_subsys_exit(); |
7c9281d7 DT |
158 | } |
159 | ||
160 | /* | |
161 | * Inform the kernel of our entry and exit points | |
162 | */ | |
4ab19b06 | 163 | subsys_initcall(edac_init); |
7c9281d7 DT |
164 | module_exit(edac_exit); |
165 | ||
166 | MODULE_LICENSE("GPL"); | |
167 | MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al"); | |
168 | MODULE_DESCRIPTION("Core library routines for EDAC reporting"); |