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