Branch data Line data Source code
1 : : /*
2 : : * EDAC PCI component
3 : : *
4 : : * Author: Dave Jiang <djiang@mvista.com>
5 : : *
6 : : * 2007 (c) MontaVista Software, Inc. This file is licensed under
7 : : * the terms of the GNU General Public License version 2. This program
8 : : * is licensed "as is" without any warranty of any kind, whether express
9 : : * or implied.
10 : : *
11 : : */
12 : : #include <asm/page.h>
13 : : #include <linux/uaccess.h>
14 : : #include <linux/ctype.h>
15 : : #include <linux/highmem.h>
16 : : #include <linux/init.h>
17 : : #include <linux/module.h>
18 : : #include <linux/slab.h>
19 : : #include <linux/smp.h>
20 : : #include <linux/spinlock.h>
21 : : #include <linux/sysctl.h>
22 : : #include <linux/timer.h>
23 : :
24 : : #include "edac_pci.h"
25 : : #include "edac_module.h"
26 : :
27 : : static DEFINE_MUTEX(edac_pci_ctls_mutex);
28 : : static LIST_HEAD(edac_pci_list);
29 : : static atomic_t pci_indexes = ATOMIC_INIT(0);
30 : :
31 : 0 : struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
32 : : const char *edac_pci_name)
33 : : {
34 : 0 : struct edac_pci_ctl_info *pci;
35 : 0 : void *p = NULL, *pvt;
36 : 0 : unsigned int size;
37 : :
38 : 0 : edac_dbg(1, "\n");
39 : :
40 : 0 : pci = edac_align_ptr(&p, sizeof(*pci), 1);
41 : 0 : pvt = edac_align_ptr(&p, 1, sz_pvt);
42 : 0 : size = ((unsigned long)pvt) + sz_pvt;
43 : :
44 : : /* Alloc the needed control struct memory */
45 : 0 : pci = kzalloc(size, GFP_KERNEL);
46 [ # # ]: 0 : if (pci == NULL)
47 : : return NULL;
48 : :
49 : : /* Now much private space */
50 [ # # ]: 0 : pvt = sz_pvt ? ((char *)pci) + ((unsigned long)pvt) : NULL;
51 : :
52 : 0 : pci->pvt_info = pvt;
53 : 0 : pci->op_state = OP_ALLOC;
54 : :
55 : 0 : snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name);
56 : :
57 : 0 : return pci;
58 : : }
59 : : EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
60 : :
61 : 0 : void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)
62 : : {
63 : 0 : edac_dbg(1, "\n");
64 : :
65 : 0 : edac_pci_remove_sysfs(pci);
66 : 0 : }
67 : : EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info);
68 : :
69 : : /*
70 : : * find_edac_pci_by_dev()
71 : : * scans the edac_pci list for a specific 'struct device *'
72 : : *
73 : : * return NULL if not found, or return control struct pointer
74 : : */
75 : 0 : static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev)
76 : : {
77 : 0 : struct edac_pci_ctl_info *pci;
78 : 0 : struct list_head *item;
79 : :
80 : 0 : edac_dbg(1, "\n");
81 : :
82 [ # # # # ]: 0 : list_for_each(item, &edac_pci_list) {
83 : 0 : pci = list_entry(item, struct edac_pci_ctl_info, link);
84 : :
85 [ # # # # ]: 0 : if (pci->dev == dev)
86 : : return pci;
87 : : }
88 : :
89 : : return NULL;
90 : : }
91 : :
92 : : /*
93 : : * add_edac_pci_to_global_list
94 : : * Before calling this function, caller must assign a unique value to
95 : : * edac_dev->pci_idx.
96 : : * Return:
97 : : * 0 on success
98 : : * 1 on failure
99 : : */
100 : 0 : static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
101 : : {
102 : 0 : struct list_head *item, *insert_before;
103 : 0 : struct edac_pci_ctl_info *rover;
104 : :
105 : 0 : edac_dbg(1, "\n");
106 : :
107 : 0 : insert_before = &edac_pci_list;
108 : :
109 : : /* Determine if already on the list */
110 : 0 : rover = find_edac_pci_by_dev(pci->dev);
111 [ # # ]: 0 : if (unlikely(rover != NULL))
112 : 0 : goto fail0;
113 : :
114 : : /* Insert in ascending order by 'pci_idx', so find position */
115 [ # # ]: 0 : list_for_each(item, &edac_pci_list) {
116 : 0 : rover = list_entry(item, struct edac_pci_ctl_info, link);
117 : :
118 [ # # ]: 0 : if (rover->pci_idx >= pci->pci_idx) {
119 [ # # ]: 0 : if (unlikely(rover->pci_idx == pci->pci_idx))
120 : 0 : goto fail1;
121 : :
122 : : insert_before = item;
123 : : break;
124 : : }
125 : : }
126 : :
127 : 0 : list_add_tail_rcu(&pci->link, insert_before);
128 : 0 : return 0;
129 : :
130 : : fail0:
131 [ # # ]: 0 : edac_printk(KERN_WARNING, EDAC_PCI,
132 : : "%s (%s) %s %s already assigned %d\n",
133 : : dev_name(rover->dev), edac_dev_name(rover),
134 : : rover->mod_name, rover->ctl_name, rover->pci_idx);
135 : 0 : return 1;
136 : :
137 : : fail1:
138 : 0 : edac_printk(KERN_WARNING, EDAC_PCI,
139 : : "but in low-level driver: attempt to assign\n"
140 : : "\tduplicate pci_idx %d in %s()\n", rover->pci_idx,
141 : : __func__);
142 : 0 : return 1;
143 : : }
144 : :
145 : : /*
146 : : * del_edac_pci_from_global_list
147 : : *
148 : : * remove the PCI control struct from the global list
149 : : */
150 : 0 : static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
151 : : {
152 : 0 : list_del_rcu(&pci->link);
153 : :
154 : : /* these are for safe removal of devices from global list while
155 : : * NMI handlers may be traversing list
156 : : */
157 : 0 : synchronize_rcu();
158 : 0 : INIT_LIST_HEAD(&pci->link);
159 : 0 : }
160 : :
161 : : /*
162 : : * edac_pci_workq_function()
163 : : *
164 : : * periodic function that performs the operation
165 : : * scheduled by a workq request, for a given PCI control struct
166 : : */
167 : 0 : static void edac_pci_workq_function(struct work_struct *work_req)
168 : : {
169 : 0 : struct delayed_work *d_work = to_delayed_work(work_req);
170 : 0 : struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work);
171 : 0 : int msec;
172 : 0 : unsigned long delay;
173 : :
174 : 0 : edac_dbg(3, "checking\n");
175 : :
176 : 0 : mutex_lock(&edac_pci_ctls_mutex);
177 : :
178 [ # # ]: 0 : if (pci->op_state != OP_RUNNING_POLL) {
179 : 0 : mutex_unlock(&edac_pci_ctls_mutex);
180 : 0 : return;
181 : : }
182 : :
183 [ # # ]: 0 : if (edac_pci_get_check_errors())
184 : 0 : pci->edac_check(pci);
185 : :
186 : : /* if we are on a one second period, then use round */
187 : 0 : msec = edac_pci_get_poll_msec();
188 [ # # ]: 0 : if (msec == 1000)
189 : 0 : delay = round_jiffies_relative(msecs_to_jiffies(msec));
190 : : else
191 [ # # ]: 0 : delay = msecs_to_jiffies(msec);
192 : :
193 : 0 : edac_queue_work(&pci->work, delay);
194 : :
195 : 0 : mutex_unlock(&edac_pci_ctls_mutex);
196 : : }
197 : :
198 : 0 : int edac_pci_alloc_index(void)
199 : : {
200 : 0 : return atomic_inc_return(&pci_indexes) - 1;
201 : : }
202 : : EXPORT_SYMBOL_GPL(edac_pci_alloc_index);
203 : :
204 : 0 : int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
205 : : {
206 : 0 : edac_dbg(0, "\n");
207 : :
208 : 0 : pci->pci_idx = edac_idx;
209 : 0 : pci->start_time = jiffies;
210 : :
211 : 0 : mutex_lock(&edac_pci_ctls_mutex);
212 : :
213 [ # # ]: 0 : if (add_edac_pci_to_global_list(pci))
214 : 0 : goto fail0;
215 : :
216 [ # # ]: 0 : if (edac_pci_create_sysfs(pci)) {
217 : 0 : edac_pci_printk(pci, KERN_WARNING,
218 : : "failed to create sysfs pci\n");
219 : 0 : goto fail1;
220 : : }
221 : :
222 [ # # ]: 0 : if (pci->edac_check) {
223 : 0 : pci->op_state = OP_RUNNING_POLL;
224 : :
225 : 0 : INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
226 [ # # ]: 0 : edac_queue_work(&pci->work, msecs_to_jiffies(edac_pci_get_poll_msec()));
227 : :
228 : : } else {
229 : 0 : pci->op_state = OP_RUNNING_INTERRUPT;
230 : : }
231 : :
232 : 0 : edac_pci_printk(pci, KERN_INFO,
233 : : "Giving out device to module %s controller %s: DEV %s (%s)\n",
234 : : pci->mod_name, pci->ctl_name, pci->dev_name,
235 : : edac_op_state_to_string(pci->op_state));
236 : :
237 : 0 : mutex_unlock(&edac_pci_ctls_mutex);
238 : 0 : return 0;
239 : :
240 : : /* error unwind stack */
241 : : fail1:
242 : 0 : del_edac_pci_from_global_list(pci);
243 : 0 : fail0:
244 : 0 : mutex_unlock(&edac_pci_ctls_mutex);
245 : 0 : return 1;
246 : : }
247 : : EXPORT_SYMBOL_GPL(edac_pci_add_device);
248 : :
249 : 0 : struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
250 : : {
251 : 0 : struct edac_pci_ctl_info *pci;
252 : :
253 : 0 : edac_dbg(0, "\n");
254 : :
255 : 0 : mutex_lock(&edac_pci_ctls_mutex);
256 : :
257 : : /* ensure the control struct is on the global list
258 : : * if not, then leave
259 : : */
260 : 0 : pci = find_edac_pci_by_dev(dev);
261 [ # # ]: 0 : if (pci == NULL) {
262 : 0 : mutex_unlock(&edac_pci_ctls_mutex);
263 : 0 : return NULL;
264 : : }
265 : :
266 : 0 : pci->op_state = OP_OFFLINE;
267 : :
268 : 0 : del_edac_pci_from_global_list(pci);
269 : :
270 : 0 : mutex_unlock(&edac_pci_ctls_mutex);
271 : :
272 [ # # ]: 0 : if (pci->edac_check)
273 : 0 : edac_stop_work(&pci->work);
274 : :
275 : 0 : edac_printk(KERN_INFO, EDAC_PCI,
276 : : "Removed device %d for %s %s: DEV %s\n",
277 : : pci->pci_idx, pci->mod_name, pci->ctl_name, edac_dev_name(pci));
278 : :
279 : 0 : return pci;
280 : : }
281 : : EXPORT_SYMBOL_GPL(edac_pci_del_device);
282 : :
283 : : /*
284 : : * edac_pci_generic_check
285 : : *
286 : : * a Generic parity check API
287 : : */
288 : 0 : static void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
289 : : {
290 : 0 : edac_dbg(4, "\n");
291 : 0 : edac_pci_do_parity_check();
292 : 0 : }
293 : :
294 : : /* free running instance index counter */
295 : : static int edac_pci_idx;
296 : : #define EDAC_PCI_GENCTL_NAME "EDAC PCI controller"
297 : :
298 : : struct edac_pci_gen_data {
299 : : int edac_idx;
300 : : };
301 : :
302 : 0 : struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
303 : : const char *mod_name)
304 : : {
305 : 0 : struct edac_pci_ctl_info *pci;
306 : 0 : struct edac_pci_gen_data *pdata;
307 : :
308 : 0 : pci = edac_pci_alloc_ctl_info(sizeof(*pdata), EDAC_PCI_GENCTL_NAME);
309 [ # # ]: 0 : if (!pci)
310 : : return NULL;
311 : :
312 : 0 : pdata = pci->pvt_info;
313 : 0 : pci->dev = dev;
314 [ # # ]: 0 : dev_set_drvdata(pci->dev, pci);
315 [ # # ]: 0 : pci->dev_name = pci_name(to_pci_dev(dev));
316 : :
317 : 0 : pci->mod_name = mod_name;
318 : 0 : pci->ctl_name = EDAC_PCI_GENCTL_NAME;
319 [ # # ]: 0 : if (edac_op_state == EDAC_OPSTATE_POLL)
320 : 0 : pci->edac_check = edac_pci_generic_check;
321 : :
322 : 0 : pdata->edac_idx = edac_pci_idx++;
323 : :
324 [ # # ]: 0 : if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
325 : 0 : edac_dbg(3, "failed edac_pci_add_device()\n");
326 : 0 : edac_pci_free_ctl_info(pci);
327 : 0 : return NULL;
328 : : }
329 : :
330 : : return pci;
331 : : }
332 : : EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl);
333 : :
334 : 0 : void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)
335 : : {
336 : 0 : edac_dbg(0, "pci mod=%s\n", pci->mod_name);
337 : :
338 : 0 : edac_pci_del_device(pci->dev);
339 : 0 : edac_pci_free_ctl_info(pci);
340 : 0 : }
341 : : EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl);
|