Root/
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 <linux/module.h> |
13 | #include <linux/types.h> |
14 | #include <linux/smp.h> |
15 | #include <linux/init.h> |
16 | #include <linux/sysctl.h> |
17 | #include <linux/highmem.h> |
18 | #include <linux/timer.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/spinlock.h> |
21 | #include <linux/list.h> |
22 | #include <linux/sysdev.h> |
23 | #include <linux/ctype.h> |
24 | #include <linux/workqueue.h> |
25 | #include <asm/uaccess.h> |
26 | #include <asm/page.h> |
27 | |
28 | #include "edac_core.h" |
29 | #include "edac_module.h" |
30 | |
31 | static DEFINE_MUTEX(edac_pci_ctls_mutex); |
32 | static LIST_HEAD(edac_pci_list); |
33 | static atomic_t pci_indexes = ATOMIC_INIT(0); |
34 | |
35 | /* |
36 | * edac_pci_alloc_ctl_info |
37 | * |
38 | * The alloc() function for the 'edac_pci' control info |
39 | * structure. The chip driver will allocate one of these for each |
40 | * edac_pci it is going to control/register with the EDAC CORE. |
41 | */ |
42 | struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, |
43 | const char *edac_pci_name) |
44 | { |
45 | struct edac_pci_ctl_info *pci; |
46 | void *pvt; |
47 | unsigned int size; |
48 | |
49 | debugf1("%s()\n", __func__); |
50 | |
51 | pci = (struct edac_pci_ctl_info *)0; |
52 | pvt = edac_align_ptr(&pci[1], sz_pvt); |
53 | size = ((unsigned long)pvt) + sz_pvt; |
54 | |
55 | /* Alloc the needed control struct memory */ |
56 | pci = kzalloc(size, GFP_KERNEL); |
57 | if (pci == NULL) |
58 | return NULL; |
59 | |
60 | /* Now much private space */ |
61 | pvt = sz_pvt ? ((char *)pci) + ((unsigned long)pvt) : NULL; |
62 | |
63 | pci->pvt_info = pvt; |
64 | pci->op_state = OP_ALLOC; |
65 | |
66 | snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name); |
67 | |
68 | return pci; |
69 | } |
70 | EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info); |
71 | |
72 | /* |
73 | * edac_pci_free_ctl_info() |
74 | * |
75 | * Last action on the pci control structure. |
76 | * |
77 | * call the remove sysfs information, which will unregister |
78 | * this control struct's kobj. When that kobj's ref count |
79 | * goes to zero, its release function will be call and then |
80 | * kfree() the memory. |
81 | */ |
82 | void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci) |
83 | { |
84 | debugf1("%s()\n", __func__); |
85 | |
86 | edac_pci_remove_sysfs(pci); |
87 | } |
88 | EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info); |
89 | |
90 | /* |
91 | * find_edac_pci_by_dev() |
92 | * scans the edac_pci list for a specific 'struct device *' |
93 | * |
94 | * return NULL if not found, or return control struct pointer |
95 | */ |
96 | static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev) |
97 | { |
98 | struct edac_pci_ctl_info *pci; |
99 | struct list_head *item; |
100 | |
101 | debugf1("%s()\n", __func__); |
102 | |
103 | list_for_each(item, &edac_pci_list) { |
104 | pci = list_entry(item, struct edac_pci_ctl_info, link); |
105 | |
106 | if (pci->dev == dev) |
107 | return pci; |
108 | } |
109 | |
110 | return NULL; |
111 | } |
112 | |
113 | /* |
114 | * add_edac_pci_to_global_list |
115 | * Before calling this function, caller must assign a unique value to |
116 | * edac_dev->pci_idx. |
117 | * Return: |
118 | * 0 on success |
119 | * 1 on failure |
120 | */ |
121 | static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci) |
122 | { |
123 | struct list_head *item, *insert_before; |
124 | struct edac_pci_ctl_info *rover; |
125 | |
126 | debugf1("%s()\n", __func__); |
127 | |
128 | insert_before = &edac_pci_list; |
129 | |
130 | /* Determine if already on the list */ |
131 | rover = find_edac_pci_by_dev(pci->dev); |
132 | if (unlikely(rover != NULL)) |
133 | goto fail0; |
134 | |
135 | /* Insert in ascending order by 'pci_idx', so find position */ |
136 | list_for_each(item, &edac_pci_list) { |
137 | rover = list_entry(item, struct edac_pci_ctl_info, link); |
138 | |
139 | if (rover->pci_idx >= pci->pci_idx) { |
140 | if (unlikely(rover->pci_idx == pci->pci_idx)) |
141 | goto fail1; |
142 | |
143 | insert_before = item; |
144 | break; |
145 | } |
146 | } |
147 | |
148 | list_add_tail_rcu(&pci->link, insert_before); |
149 | return 0; |
150 | |
151 | fail0: |
152 | edac_printk(KERN_WARNING, EDAC_PCI, |
153 | "%s (%s) %s %s already assigned %d\n", |
154 | dev_name(rover->dev), edac_dev_name(rover), |
155 | rover->mod_name, rover->ctl_name, rover->pci_idx); |
156 | return 1; |
157 | |
158 | fail1: |
159 | edac_printk(KERN_WARNING, EDAC_PCI, |
160 | "but in low-level driver: attempt to assign\n" |
161 | "\tduplicate pci_idx %d in %s()\n", rover->pci_idx, |
162 | __func__); |
163 | return 1; |
164 | } |
165 | |
166 | /* |
167 | * complete_edac_pci_list_del |
168 | * |
169 | * RCU completion callback to indicate item is deleted |
170 | */ |
171 | static void complete_edac_pci_list_del(struct rcu_head *head) |
172 | { |
173 | struct edac_pci_ctl_info *pci; |
174 | |
175 | pci = container_of(head, struct edac_pci_ctl_info, rcu); |
176 | INIT_LIST_HEAD(&pci->link); |
177 | } |
178 | |
179 | /* |
180 | * del_edac_pci_from_global_list |
181 | * |
182 | * remove the PCI control struct from the global list |
183 | */ |
184 | static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci) |
185 | { |
186 | list_del_rcu(&pci->link); |
187 | call_rcu(&pci->rcu, complete_edac_pci_list_del); |
188 | rcu_barrier(); |
189 | } |
190 | |
191 | #if 0 |
192 | /* Older code, but might use in the future */ |
193 | |
194 | /* |
195 | * edac_pci_find() |
196 | * Search for an edac_pci_ctl_info structure whose index is 'idx' |
197 | * |
198 | * If found, return a pointer to the structure |
199 | * Else return NULL. |
200 | * |
201 | * Caller must hold pci_ctls_mutex. |
202 | */ |
203 | struct edac_pci_ctl_info *edac_pci_find(int idx) |
204 | { |
205 | struct list_head *item; |
206 | struct edac_pci_ctl_info *pci; |
207 | |
208 | /* Iterage over list, looking for exact match of ID */ |
209 | list_for_each(item, &edac_pci_list) { |
210 | pci = list_entry(item, struct edac_pci_ctl_info, link); |
211 | |
212 | if (pci->pci_idx >= idx) { |
213 | if (pci->pci_idx == idx) |
214 | return pci; |
215 | |
216 | /* not on list, so terminate early */ |
217 | break; |
218 | } |
219 | } |
220 | |
221 | return NULL; |
222 | } |
223 | EXPORT_SYMBOL_GPL(edac_pci_find); |
224 | #endif |
225 | |
226 | /* |
227 | * edac_pci_workq_function() |
228 | * |
229 | * periodic function that performs the operation |
230 | * scheduled by a workq request, for a given PCI control struct |
231 | */ |
232 | static void edac_pci_workq_function(struct work_struct *work_req) |
233 | { |
234 | struct delayed_work *d_work = to_delayed_work(work_req); |
235 | struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work); |
236 | int msec; |
237 | unsigned long delay; |
238 | |
239 | debugf3("%s() checking\n", __func__); |
240 | |
241 | mutex_lock(&edac_pci_ctls_mutex); |
242 | |
243 | if (pci->op_state == OP_RUNNING_POLL) { |
244 | /* we might be in POLL mode, but there may NOT be a poll func |
245 | */ |
246 | if ((pci->edac_check != NULL) && edac_pci_get_check_errors()) |
247 | pci->edac_check(pci); |
248 | |
249 | /* if we are on a one second period, then use round */ |
250 | msec = edac_pci_get_poll_msec(); |
251 | if (msec == 1000) |
252 | delay = round_jiffies_relative(msecs_to_jiffies(msec)); |
253 | else |
254 | delay = msecs_to_jiffies(msec); |
255 | |
256 | /* Reschedule only if we are in POLL mode */ |
257 | queue_delayed_work(edac_workqueue, &pci->work, delay); |
258 | } |
259 | |
260 | mutex_unlock(&edac_pci_ctls_mutex); |
261 | } |
262 | |
263 | /* |
264 | * edac_pci_workq_setup() |
265 | * initialize a workq item for this edac_pci instance |
266 | * passing in the new delay period in msec |
267 | * |
268 | * locking model: |
269 | * called when 'edac_pci_ctls_mutex' is locked |
270 | */ |
271 | static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci, |
272 | unsigned int msec) |
273 | { |
274 | debugf0("%s()\n", __func__); |
275 | |
276 | INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function); |
277 | queue_delayed_work(edac_workqueue, &pci->work, |
278 | msecs_to_jiffies(edac_pci_get_poll_msec())); |
279 | } |
280 | |
281 | /* |
282 | * edac_pci_workq_teardown() |
283 | * stop the workq processing on this edac_pci instance |
284 | */ |
285 | static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci) |
286 | { |
287 | int status; |
288 | |
289 | debugf0("%s()\n", __func__); |
290 | |
291 | status = cancel_delayed_work(&pci->work); |
292 | if (status == 0) |
293 | flush_workqueue(edac_workqueue); |
294 | } |
295 | |
296 | /* |
297 | * edac_pci_reset_delay_period |
298 | * |
299 | * called with a new period value for the workq period |
300 | * a) stop current workq timer |
301 | * b) restart workq timer with new value |
302 | */ |
303 | void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci, |
304 | unsigned long value) |
305 | { |
306 | debugf0("%s()\n", __func__); |
307 | |
308 | edac_pci_workq_teardown(pci); |
309 | |
310 | /* need to lock for the setup */ |
311 | mutex_lock(&edac_pci_ctls_mutex); |
312 | |
313 | edac_pci_workq_setup(pci, value); |
314 | |
315 | mutex_unlock(&edac_pci_ctls_mutex); |
316 | } |
317 | EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period); |
318 | |
319 | /* |
320 | * edac_pci_alloc_index: Allocate a unique PCI index number |
321 | * |
322 | * Return: |
323 | * allocated index number |
324 | * |
325 | */ |
326 | int edac_pci_alloc_index(void) |
327 | { |
328 | return atomic_inc_return(&pci_indexes) - 1; |
329 | } |
330 | EXPORT_SYMBOL_GPL(edac_pci_alloc_index); |
331 | |
332 | /* |
333 | * edac_pci_add_device: Insert the 'edac_dev' structure into the |
334 | * edac_pci global list and create sysfs entries associated with |
335 | * edac_pci structure. |
336 | * @pci: pointer to the edac_device structure to be added to the list |
337 | * @edac_idx: A unique numeric identifier to be assigned to the |
338 | * 'edac_pci' structure. |
339 | * |
340 | * Return: |
341 | * 0 Success |
342 | * !0 Failure |
343 | */ |
344 | int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx) |
345 | { |
346 | debugf0("%s()\n", __func__); |
347 | |
348 | pci->pci_idx = edac_idx; |
349 | pci->start_time = jiffies; |
350 | |
351 | mutex_lock(&edac_pci_ctls_mutex); |
352 | |
353 | if (add_edac_pci_to_global_list(pci)) |
354 | goto fail0; |
355 | |
356 | if (edac_pci_create_sysfs(pci)) { |
357 | edac_pci_printk(pci, KERN_WARNING, |
358 | "failed to create sysfs pci\n"); |
359 | goto fail1; |
360 | } |
361 | |
362 | if (pci->edac_check != NULL) { |
363 | pci->op_state = OP_RUNNING_POLL; |
364 | |
365 | edac_pci_workq_setup(pci, 1000); |
366 | } else { |
367 | pci->op_state = OP_RUNNING_INTERRUPT; |
368 | } |
369 | |
370 | edac_pci_printk(pci, KERN_INFO, |
371 | "Giving out device to module '%s' controller '%s':" |
372 | " DEV '%s' (%s)\n", |
373 | pci->mod_name, |
374 | pci->ctl_name, |
375 | edac_dev_name(pci), edac_op_state_to_string(pci->op_state)); |
376 | |
377 | mutex_unlock(&edac_pci_ctls_mutex); |
378 | return 0; |
379 | |
380 | /* error unwind stack */ |
381 | fail1: |
382 | del_edac_pci_from_global_list(pci); |
383 | fail0: |
384 | mutex_unlock(&edac_pci_ctls_mutex); |
385 | return 1; |
386 | } |
387 | EXPORT_SYMBOL_GPL(edac_pci_add_device); |
388 | |
389 | /* |
390 | * edac_pci_del_device() |
391 | * Remove sysfs entries for specified edac_pci structure and |
392 | * then remove edac_pci structure from global list |
393 | * |
394 | * @dev: |
395 | * Pointer to 'struct device' representing edac_pci structure |
396 | * to remove |
397 | * |
398 | * Return: |
399 | * Pointer to removed edac_pci structure, |
400 | * or NULL if device not found |
401 | */ |
402 | struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev) |
403 | { |
404 | struct edac_pci_ctl_info *pci; |
405 | |
406 | debugf0("%s()\n", __func__); |
407 | |
408 | mutex_lock(&edac_pci_ctls_mutex); |
409 | |
410 | /* ensure the control struct is on the global list |
411 | * if not, then leave |
412 | */ |
413 | pci = find_edac_pci_by_dev(dev); |
414 | if (pci == NULL) { |
415 | mutex_unlock(&edac_pci_ctls_mutex); |
416 | return NULL; |
417 | } |
418 | |
419 | pci->op_state = OP_OFFLINE; |
420 | |
421 | del_edac_pci_from_global_list(pci); |
422 | |
423 | mutex_unlock(&edac_pci_ctls_mutex); |
424 | |
425 | /* stop the workq timer */ |
426 | edac_pci_workq_teardown(pci); |
427 | |
428 | edac_printk(KERN_INFO, EDAC_PCI, |
429 | "Removed device %d for %s %s: DEV %s\n", |
430 | pci->pci_idx, pci->mod_name, pci->ctl_name, edac_dev_name(pci)); |
431 | |
432 | return pci; |
433 | } |
434 | EXPORT_SYMBOL_GPL(edac_pci_del_device); |
435 | |
436 | /* |
437 | * edac_pci_generic_check |
438 | * |
439 | * a Generic parity check API |
440 | */ |
441 | static void edac_pci_generic_check(struct edac_pci_ctl_info *pci) |
442 | { |
443 | debugf4("%s()\n", __func__); |
444 | edac_pci_do_parity_check(); |
445 | } |
446 | |
447 | /* free running instance index counter */ |
448 | static int edac_pci_idx; |
449 | #define EDAC_PCI_GENCTL_NAME "EDAC PCI controller" |
450 | |
451 | struct edac_pci_gen_data { |
452 | int edac_idx; |
453 | }; |
454 | |
455 | /* |
456 | * edac_pci_create_generic_ctl |
457 | * |
458 | * A generic constructor for a PCI parity polling device |
459 | * Some systems have more than one domain of PCI busses. |
460 | * For systems with one domain, then this API will |
461 | * provide for a generic poller. |
462 | * |
463 | * This routine calls the edac_pci_alloc_ctl_info() for |
464 | * the generic device, with default values |
465 | */ |
466 | struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev, |
467 | const char *mod_name) |
468 | { |
469 | struct edac_pci_ctl_info *pci; |
470 | struct edac_pci_gen_data *pdata; |
471 | |
472 | pci = edac_pci_alloc_ctl_info(sizeof(*pdata), EDAC_PCI_GENCTL_NAME); |
473 | if (!pci) |
474 | return NULL; |
475 | |
476 | pdata = pci->pvt_info; |
477 | pci->dev = dev; |
478 | dev_set_drvdata(pci->dev, pci); |
479 | pci->dev_name = pci_name(to_pci_dev(dev)); |
480 | |
481 | pci->mod_name = mod_name; |
482 | pci->ctl_name = EDAC_PCI_GENCTL_NAME; |
483 | pci->edac_check = edac_pci_generic_check; |
484 | |
485 | pdata->edac_idx = edac_pci_idx++; |
486 | |
487 | if (edac_pci_add_device(pci, pdata->edac_idx) > 0) { |
488 | debugf3("%s(): failed edac_pci_add_device()\n", __func__); |
489 | edac_pci_free_ctl_info(pci); |
490 | return NULL; |
491 | } |
492 | |
493 | return pci; |
494 | } |
495 | EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl); |
496 | |
497 | /* |
498 | * edac_pci_release_generic_ctl |
499 | * |
500 | * The release function of a generic EDAC PCI polling device |
501 | */ |
502 | void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci) |
503 | { |
504 | debugf0("%s() pci mod=%s\n", __func__, pci->mod_name); |
505 | |
506 | edac_pci_del_device(pci->dev); |
507 | edac_pci_free_ctl_info(pci); |
508 | } |
509 | EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl); |
510 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9