xref: /linux/drivers/edac/edac_module.c (revision c4ee0af3fa0dc65f690fc908f02b8355f9576ea0)
1 /*
2  * edac_module.c
3  *
4  * (C) 2007 www.softwarebitmaker.com
5  *
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  *
10  * Author: Doug Thompson <dougthompson@xmission.com>
11  *
12  */
13 #include <linux/edac.h>
14 
15 #include "edac_core.h"
16 #include "edac_module.h"
17 
18 #define EDAC_VERSION "Ver: 3.0.0"
19 
20 #ifdef CONFIG_EDAC_DEBUG
21 
22 static int edac_set_debug_level(const char *buf, struct kernel_param *kp)
23 {
24 	unsigned long val;
25 	int ret;
26 
27 	ret = kstrtoul(buf, 0, &val);
28 	if (ret)
29 		return ret;
30 
31 	if (val < 0 || val > 4)
32 		return -EINVAL;
33 
34 	return param_set_int(buf, kp);
35 }
36 
37 /* Values of 0 to 4 will generate output */
38 int edac_debug_level = 2;
39 EXPORT_SYMBOL_GPL(edac_debug_level);
40 
41 module_param_call(edac_debug_level, edac_set_debug_level, param_get_int,
42 		  &edac_debug_level, 0644);
43 MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2");
44 #endif
45 
46 /* scope is to module level only */
47 struct workqueue_struct *edac_workqueue;
48 
49 /*
50  * edac_op_state_to_string()
51  */
52 char *edac_op_state_to_string(int opstate)
53 {
54 	if (opstate == OP_RUNNING_POLL)
55 		return "POLLED";
56 	else if (opstate == OP_RUNNING_INTERRUPT)
57 		return "INTERRUPT";
58 	else if (opstate == OP_RUNNING_POLL_INTR)
59 		return "POLL-INTR";
60 	else if (opstate == OP_ALLOC)
61 		return "ALLOC";
62 	else if (opstate == OP_OFFLINE)
63 		return "OFFLINE";
64 
65 	return "UNKNOWN";
66 }
67 
68 /*
69  * edac_workqueue_setup
70  *	initialize the edac work queue for polling operations
71  */
72 static int edac_workqueue_setup(void)
73 {
74 	edac_workqueue = create_singlethread_workqueue("edac-poller");
75 	if (edac_workqueue == NULL)
76 		return -ENODEV;
77 	else
78 		return 0;
79 }
80 
81 /*
82  * edac_workqueue_teardown
83  *	teardown the edac workqueue
84  */
85 static void edac_workqueue_teardown(void)
86 {
87 	if (edac_workqueue) {
88 		flush_workqueue(edac_workqueue);
89 		destroy_workqueue(edac_workqueue);
90 		edac_workqueue = NULL;
91 	}
92 }
93 
94 /*
95  * edac_init
96  *      module initialization entry point
97  */
98 static int __init edac_init(void)
99 {
100 	int err = 0;
101 
102 	edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n");
103 
104 	/*
105 	 * Harvest and clear any boot/initialization PCI parity errors
106 	 *
107 	 * FIXME: This only clears errors logged by devices present at time of
108 	 *      module initialization.  We should also do an initial clear
109 	 *      of each newly hotplugged device.
110 	 */
111 	edac_pci_clear_parity_errors();
112 
113 	err = edac_mc_sysfs_init();
114 	if (err)
115 		goto error;
116 
117 	edac_debugfs_init();
118 
119 	/* Setup/Initialize the workq for this core */
120 	err = edac_workqueue_setup();
121 	if (err) {
122 		edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
123 		goto error;
124 	}
125 
126 	return 0;
127 
128 error:
129 	return err;
130 }
131 
132 /*
133  * edac_exit()
134  *      module exit/termination function
135  */
136 static void __exit edac_exit(void)
137 {
138 	edac_dbg(0, "\n");
139 
140 	/* tear down the various subsystems */
141 	edac_workqueue_teardown();
142 	edac_mc_sysfs_exit();
143 	edac_debugfs_exit();
144 }
145 
146 /*
147  * Inform the kernel of our entry and exit points
148  */
149 subsys_initcall(edac_init);
150 module_exit(edac_exit);
151 
152 MODULE_LICENSE("GPL");
153 MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al");
154 MODULE_DESCRIPTION("Core library routines for EDAC reporting");
155