aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Thompson <dougthompson@xmission.com>2007-07-19 04:49:36 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:53 -0400
commite27e3dac651771fe3250f6305dee277bce29fc5d (patch)
tree9c0ac81a0948d8e52a72865ff9fbae4a12031a32
parent7c9281d76c1c0b130f79d5fc021084e9749959d4 (diff)
drivers/edac: add edac_device class
This patch adds the new 'class' of object to be managed, named: 'edac_device'. As a peer of the 'edac_mc' class of object, it provides a non-memory centric view of an ERROR DETECTING device in hardware. It provides a sysfs interface and an abstraction for varioius EDAC type devices. Multiple 'instances' within the class are possible, with each 'instance' able to have multiple 'blocks', and each 'block' having 'attributes'. At the 'block' level there are the 'ce_count' and 'ue_count' fields which the device driver can update and/or call edac_device_handle_XX() functions. At each higher level are additional 'total' count fields, which are a summation of counts below that level. This 'edac_device' has been used to capture and present ECC errors which are found in a a L1 and L2 system on a per CORE/CPU basis. Signed-off-by: Douglas Thompson <dougthompson@xmission.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/edac/Makefile4
-rw-r--r--drivers/edac/edac_core.h252
-rw-r--r--drivers/edac/edac_device.c669
-rw-r--r--drivers/edac/edac_device_sysfs.c837
-rw-r--r--drivers/edac/edac_mc.c8
-rw-r--r--drivers/edac/edac_mc_sysfs.c70
-rw-r--r--drivers/edac/edac_module.c147
-rw-r--r--drivers/edac/edac_module.h9
8 files changed, 1936 insertions, 60 deletions
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 51f59aa84d30..1c67cc809218 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -10,9 +10,9 @@
10 10
11obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o 11obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
12 12
13edac_core-objs := edac_mc.o edac_mc_sysfs.o edac_pci_sysfs.o 13edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
14 14
15edac_core-objs += edac_module.o 15edac_core-objs += edac_module.o edac_device_sysfs.o
16 16
17obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o 17obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o
18obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o 18obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index 397f144791ec..a3e4b97fe4fe 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -32,9 +32,14 @@
32#include <linux/completion.h> 32#include <linux/completion.h>
33#include <linux/kobject.h> 33#include <linux/kobject.h>
34#include <linux/platform_device.h> 34#include <linux/platform_device.h>
35#include <linux/sysdev.h>
36#include <linux/workqueue.h>
37#include <linux/version.h>
35 38
36#define EDAC_MC_LABEL_LEN 31 39#define EDAC_MC_LABEL_LEN 31
37#define MC_PROC_NAME_MAX_LEN 7 40#define EDAC_DEVICE_NAME_LEN 31
41#define EDAC_ATTRIB_VALUE_LEN 15
42#define MC_PROC_NAME_MAX_LEN 7
38 43
39#if PAGE_SHIFT < 20 44#if PAGE_SHIFT < 20
40#define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) ) 45#define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) )
@@ -51,6 +56,10 @@
51#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \ 56#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \
52 printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg) 57 printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg)
53 58
59/* edac_device printk */
60#define edac_device_printk(ctl, level, fmt, arg...) \
61 printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg)
62
54/* prefixes for edac_printk() and edac_mc_printk() */ 63/* prefixes for edac_printk() and edac_mc_printk() */
55#define EDAC_MC "MC" 64#define EDAC_MC "MC"
56#define EDAC_PCI "PCI" 65#define EDAC_PCI "PCI"
@@ -62,7 +71,7 @@ extern int edac_debug_level;
62#define edac_debug_printk(level, fmt, arg...) \ 71#define edac_debug_printk(level, fmt, arg...) \
63 do { \ 72 do { \
64 if (level <= edac_debug_level) \ 73 if (level <= edac_debug_level) \
65 edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \ 74 edac_printk(KERN_EMERG, EDAC_DEBUG, fmt, ##arg); \
66 } while(0) 75 } while(0)
67 76
68#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ ) 77#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
@@ -195,6 +204,8 @@ enum scrub_type {
195 204
196/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ 205/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
197 206
207extern char * edac_align_ptr(void *ptr, unsigned size);
208
198/* 209/*
199 * There are several things to be aware of that aren't at all obvious: 210 * There are several things to be aware of that aren't at all obvious:
200 * 211 *
@@ -376,6 +387,231 @@ struct mem_ctl_info {
376 struct completion kobj_complete; 387 struct completion kobj_complete;
377}; 388};
378 389
390/*
391 * The following are the structures to provide for a generice
392 * or abstract 'edac_device'. This set of structures and the
393 * code that implements the APIs for the same, provide for
394 * registering EDAC type devices which are NOT standard memory.
395 *
396 * CPU caches (L1 and L2)
397 * DMA engines
398 * Core CPU swithces
399 * Fabric switch units
400 * PCIe interface controllers
401 * other EDAC/ECC type devices that can be monitored for
402 * errors, etc.
403 *
404 * It allows for a 2 level set of hiearchry. For example:
405 *
406 * cache could be composed of L1, L2 and L3 levels of cache.
407 * Each CPU core would have its own L1 cache, while sharing
408 * L2 and maybe L3 caches.
409 *
410 * View them arranged, via the sysfs presentation:
411 * /sys/devices/system/edac/..
412 *
413 * mc/ <existing memory device directory>
414 * cpu/cpu0/.. <L1 and L2 block directory>
415 * /L1-cache/ce_count
416 * /ue_count
417 * /L2-cache/ce_count
418 * /ue_count
419 * cpu/cpu1/.. <L1 and L2 block directory>
420 * /L1-cache/ce_count
421 * /ue_count
422 * /L2-cache/ce_count
423 * /ue_count
424 * ...
425 *
426 * the L1 and L2 directories would be "edac_device_block's"
427 */
428
429struct edac_device_counter {
430 u32 ue_count;
431 u32 ce_count;
432};
433
434#define INC_COUNTER(cnt) (cnt++)
435
436/*
437 * An array of these is passed to the alloc() function
438 * to specify attributes of the edac_block
439 */
440struct edac_attrib_spec {
441 char name[EDAC_DEVICE_NAME_LEN + 1];
442
443 int type;
444#define EDAC_ATTR_INT 0x01
445#define EDAC_ATTR_CHAR 0x02
446};
447
448
449/* Attribute control structure
450 * In this structure is a pointer to the driver's edac_attrib_spec
451 * The life of this pointer is inclusive in the life of the driver's
452 * life cycle.
453 */
454struct edac_attrib {
455 struct edac_device_block *block; /* Up Pointer */
456
457 struct edac_attrib_spec *spec; /* ptr to module spec entry */
458
459 union { /* actual value */
460 int edac_attrib_int_value;
461 char edac_attrib_char_value[EDAC_ATTRIB_VALUE_LEN + 1];
462 } edac_attrib_value;
463};
464
465/* device block control structure */
466struct edac_device_block {
467 struct edac_device_instance *instance; /* Up Pointer */
468 char name[EDAC_DEVICE_NAME_LEN + 1];
469
470 struct edac_device_counter counters; /* basic UE and CE counters */
471
472 int nr_attribs; /* how many attributes */
473 struct edac_attrib *attribs; /* this block's attributes */
474
475 /* edac sysfs device control */
476 struct kobject kobj;
477 struct completion kobj_complete;
478};
479
480/* device instance control structure */
481struct edac_device_instance {
482 struct edac_device_ctl_info *ctl; /* Up pointer */
483 char name[EDAC_DEVICE_NAME_LEN + 4];
484
485 struct edac_device_counter counters; /* instance counters */
486
487 u32 nr_blocks; /* how many blocks */
488 struct edac_device_block *blocks; /* block array */
489
490 /* edac sysfs device control */
491 struct kobject kobj;
492 struct completion kobj_complete;
493};
494
495
496/*
497 * Abstract edac_device control info structure
498 *
499 */
500struct edac_device_ctl_info {
501 /* for global list of edac_device_ctl_info structs */
502 struct list_head link;
503
504 int dev_idx;
505
506 /* Per instance controls for this edac_device */
507 int log_ue; /* boolean for logging UEs */
508 int log_ce; /* boolean for logging CEs */
509 int panic_on_ue; /* boolean for panic'ing on an UE */
510 unsigned poll_msec; /* number of milliseconds to poll interval */
511 unsigned long delay; /* number of jiffies for poll_msec */
512
513 struct sysdev_class *edac_class; /* pointer to class */
514
515 /* the internal state of this controller instance */
516 int op_state;
517#define OP_ALLOC 0x100
518#define OP_RUNNING_POLL 0x201
519#define OP_RUNNING_INTERRUPT 0x202
520#define OP_RUNNING_POLL_INTR 0x203
521#define OP_OFFLINE 0x300
522
523 /* work struct for this instance */
524#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
525 struct delayed_work work;
526#else
527 struct work_struct work;
528#endif
529
530 /* pointer to edac polling checking routine:
531 * If NOT NULL: points to polling check routine
532 * If NULL: Then assumes INTERRUPT operation, where
533 * MC driver will receive events
534 */
535 void (*edac_check) (struct edac_device_ctl_info * edac_dev);
536
537 struct device *dev; /* pointer to device structure */
538
539 const char *mod_name; /* module name */
540 const char *ctl_name; /* edac controller name */
541
542 void *pvt_info; /* pointer to 'private driver' info */
543
544 unsigned long start_time;/* edac_device load start time (jiffies)*/
545
546 /* these are for safe removal of mc devices from global list while
547 * NMI handlers may be traversing list
548 */
549 struct rcu_head rcu;
550 struct completion complete;
551
552 /* sysfs top name under 'edac' directory
553 * and instance name:
554 * cpu/cpu0/...
555 * cpu/cpu1/...
556 * cpu/cpu2/...
557 * ...
558 */
559 char name[EDAC_DEVICE_NAME_LEN + 1];
560
561 /* Number of instances supported on this control structure
562 * and the array of those instances
563 */
564 u32 nr_instances;
565 struct edac_device_instance *instances;
566
567 /* Event counters for the this whole EDAC Device */
568 struct edac_device_counter counters;
569
570 /* edac sysfs device control for the 'name'
571 * device this structure controls
572 */
573 struct kobject kobj;
574 struct completion kobj_complete;
575};
576
577/* To get from the instance's wq to the beginning of the ctl structure */
578#define to_edac_device_ctl_work(w) \
579 container_of(w,struct edac_device_ctl_info,work)
580
581/* Function to calc the number of delay jiffies from poll_msec */
582static inline void edac_device_calc_delay(
583 struct edac_device_ctl_info *edac_dev)
584{
585 /* convert from msec to jiffies */
586 edac_dev->delay = edac_dev->poll_msec * HZ / 1000;
587}
588
589/*
590 * The alloc() and free() functions for the 'edac_device' control info
591 * structure. A MC driver will allocate one of these for each edac_device
592 * it is going to control/register with the EDAC CORE.
593 */
594extern struct edac_device_ctl_info *edac_device_alloc_ctl_info(
595 unsigned sizeof_private,
596 char *edac_device_name,
597 unsigned nr_instances,
598 char *edac_block_name,
599 unsigned nr_blocks,
600 unsigned offset_value,
601 struct edac_attrib_spec *attrib_spec,
602 unsigned nr_attribs
603);
604
605/* The offset value can be:
606 * -1 indicating no offset value
607 * 0 for zero-based block numbers
608 * 1 for 1-based block number
609 * other for other-based block number
610 */
611#define BLOCK_OFFSET_VALUE_OFF ((unsigned) -1)
612
613extern void edac_device_free_ctl_info( struct edac_device_ctl_info *ctl_info);
614
379#ifdef CONFIG_PCI 615#ifdef CONFIG_PCI
380 616
381/* write all or some bits in a byte-register*/ 617/* write all or some bits in a byte-register*/
@@ -466,13 +702,17 @@ extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
466 char *msg); 702 char *msg);
467 703
468/* 704/*
469 * This kmalloc's and initializes all the structures. 705 * edac_device APIs
470 * Can't be used if all structures don't have the same lifetime.
471 */ 706 */
472extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, 707extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
473 unsigned nr_chans); 708 unsigned nr_chans);
474
475/* Free an mc previously allocated by edac_mc_alloc() */
476extern void edac_mc_free(struct mem_ctl_info *mci); 709extern void edac_mc_free(struct mem_ctl_info *mci);
710extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev, int edac_idx);
711extern struct edac_device_ctl_info * edac_device_del_device(struct device *dev);
712extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
713 int inst_nr, int block_nr, const char *msg);
714extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
715 int inst_nr, int block_nr, const char *msg);
716
477 717
478#endif /* _EDAC_CORE_H_ */ 718#endif /* _EDAC_CORE_H_ */
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
new file mode 100644
index 000000000000..c579c498cc75
--- /dev/null
+++ b/drivers/edac/edac_device.c
@@ -0,0 +1,669 @@
1
2/*
3 * edac_device.c
4 * (C) 2007 www.douglaskthompson.com
5 *
6 * This file may be distributed under the terms of the
7 * GNU General Public License.
8 *
9 * Written by Doug Thompson <norsk5@xmission.com>
10 *
11 * edac_device API implementation
12 * 19 Jan 2007
13 */
14
15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/smp.h>
18#include <linux/init.h>
19#include <linux/sysctl.h>
20#include <linux/highmem.h>
21#include <linux/timer.h>
22#include <linux/slab.h>
23#include <linux/spinlock.h>
24#include <linux/list.h>
25#include <linux/sysdev.h>
26#include <linux/ctype.h>
27#include <linux/workqueue.h>
28#include <asm/uaccess.h>
29#include <asm/page.h>
30
31#include "edac_core.h"
32#include "edac_module.h"
33
34/* lock to memory controller's control array */
35static DECLARE_MUTEX(device_ctls_mutex);
36static struct list_head edac_device_list = LIST_HEAD_INIT(edac_device_list);
37
38
39static inline void lock_device_list(void)
40{
41 down(&device_ctls_mutex);
42}
43
44static inline void unlock_device_list(void)
45{
46 up(&device_ctls_mutex);
47}
48
49
50#ifdef CONFIG_EDAC_DEBUG
51static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
52{
53 debugf3("\tedac_dev = %p dev_idx=%d \n", edac_dev,edac_dev->dev_idx);
54 debugf4("\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
55 debugf3("\tdev = %p\n", edac_dev->dev);
56 debugf3("\tmod_name:ctl_name = %s:%s\n",
57 edac_dev->mod_name, edac_dev->ctl_name);
58 debugf3("\tpvt_info = %p\n\n", edac_dev->pvt_info);
59}
60#endif /* CONFIG_EDAC_DEBUG */
61
62/*
63 * The alloc() and free() functions for the 'edac_device' control info
64 * structure. A MC driver will allocate one of these for each edac_device
65 * it is going to control/register with the EDAC CORE.
66 */
67struct edac_device_ctl_info *edac_device_alloc_ctl_info(
68 unsigned sz_private,
69 char *edac_device_name,
70 unsigned nr_instances,
71 char *edac_block_name,
72 unsigned nr_blocks,
73 unsigned offset_value,
74 struct edac_attrib_spec *attrib_spec,
75 unsigned nr_attribs)
76{
77 struct edac_device_ctl_info *dev_ctl;
78 struct edac_device_instance *dev_inst, *inst;
79 struct edac_device_block *dev_blk, *blk_p, *blk;
80 struct edac_attrib *dev_attrib, *attrib_p, *attrib;
81 unsigned total_size;
82 unsigned count;
83 unsigned instance, block, attr;
84 void *pvt;
85
86 debugf1("%s() instances=%d blocks=%d\n",
87 __func__,nr_instances,nr_blocks);
88
89 /* Figure out the offsets of the various items from the start of an
90 * ctl_info structure. We want the alignment of each item
91 * to be at least as stringent as what the compiler would
92 * provide if we could simply hardcode everything into a single struct.
93 */
94 dev_ctl = (struct edac_device_ctl_info *) 0;
95
96 /* Calc the 'end' offset past the ctl_info structure */
97 dev_inst = (struct edac_device_instance *)
98 edac_align_ptr(&dev_ctl[1],sizeof(*dev_inst));
99
100 /* Calc the 'end' offset past the instance array */
101 dev_blk = (struct edac_device_block *)
102 edac_align_ptr(&dev_inst[nr_instances],sizeof(*dev_blk));
103
104 /* Calc the 'end' offset past the dev_blk array */
105 count = nr_instances * nr_blocks;
106 dev_attrib = (struct edac_attrib *)
107 edac_align_ptr(&dev_blk[count],sizeof(*dev_attrib));
108
109 /* Check for case of NO attributes specified */
110 if (nr_attribs > 0)
111 count *= nr_attribs;
112
113 /* Calc the 'end' offset past the attributes array */
114 pvt = edac_align_ptr(&dev_attrib[count],sz_private);
115 total_size = ((unsigned long) pvt) + sz_private;
116
117 /* Allocate the amount of memory for the set of control structures */
118 if ((dev_ctl = kmalloc(total_size, GFP_KERNEL)) == NULL)
119 return NULL;
120
121 /* Adjust pointers so they point within the memory we just allocated
122 * rather than an imaginary chunk of memory located at address 0.
123 */
124 dev_inst = (struct edac_device_instance *)
125 (((char *) dev_ctl) + ((unsigned long) dev_inst));
126 dev_blk = (struct edac_device_block *)
127 (((char *) dev_ctl) + ((unsigned long) dev_blk));
128 dev_attrib = (struct edac_attrib *)
129 (((char *) dev_ctl) + ((unsigned long) dev_attrib));
130 pvt = sz_private ?
131 (((char *) dev_ctl) + ((unsigned long) pvt)) : NULL;
132
133 memset(dev_ctl, 0, total_size); /* clear all fields */
134 dev_ctl->nr_instances = nr_instances;
135 dev_ctl->instances = dev_inst;
136 dev_ctl->pvt_info = pvt;
137
138 /* Name of this edac device, ensure null terminated */
139 snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s", edac_device_name);
140 dev_ctl->name[sizeof(dev_ctl->name)-1] = '\0';
141
142 /* Initialize every Instance */
143 for (instance = 0; instance < nr_instances; instance++) {
144 inst = &dev_inst[instance];
145 inst->ctl = dev_ctl;
146 inst->nr_blocks = nr_blocks;
147 blk_p = &dev_blk[instance * nr_blocks];
148 inst->blocks = blk_p;
149
150 /* name of this instance */
151 snprintf(inst->name, sizeof(inst->name),
152 "%s%u", edac_device_name, instance);
153 inst->name[sizeof(inst->name)-1] = '\0';
154
155 /* Initialize every block in each instance */
156 for ( block = 0;
157 block < nr_blocks;
158 block++) {
159 blk = &blk_p[block];
160 blk->instance = inst;
161 blk->nr_attribs = nr_attribs;
162 attrib_p = &dev_attrib[block * nr_attribs];
163 blk->attribs = attrib_p;
164 snprintf(blk->name, sizeof(blk->name),
165 "%s%d", edac_block_name,block+1);
166 blk->name[sizeof(blk->name)-1] = '\0';
167
168 debugf1("%s() instance=%d block=%d name=%s\n",
169 __func__, instance,block,blk->name);
170
171 if (attrib_spec != NULL) {
172 /* when there is an attrib_spec passed int then
173 * Initialize every attrib of each block
174 */
175 for (attr = 0; attr < nr_attribs; attr++) {
176 attrib = &attrib_p[attr];
177 attrib->block = blk;
178
179 /* Link each attribute to the caller's
180 * spec entry, for name and type
181 */
182 attrib->spec = &attrib_spec[attr];
183 }
184 }
185 }
186 }
187
188 /* Mark this instance as merely ALLOCATED */
189 dev_ctl->op_state = OP_ALLOC;
190
191 return dev_ctl;
192}
193EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
194
195/*
196 * edac_device_free_ctl_info()
197 * frees the memory allocated by the edac_device_alloc_ctl_info()
198 * function
199 */
200void edac_device_free_ctl_info( struct edac_device_ctl_info *ctl_info) {
201 kfree(ctl_info);
202}
203EXPORT_SYMBOL_GPL(edac_device_free_ctl_info);
204
205
206
207/*
208 * find_edac_device_by_dev
209 * scans the edac_device list for a specific 'struct device *'
210 */
211static struct edac_device_ctl_info *
212find_edac_device_by_dev(struct device *dev)
213{
214 struct edac_device_ctl_info *edac_dev;
215 struct list_head *item;
216
217 debugf3("%s()\n", __func__);
218
219 list_for_each(item, &edac_device_list) {
220 edac_dev = list_entry(item, struct edac_device_ctl_info, link);
221
222 if (edac_dev->dev == dev)
223 return edac_dev;
224 }
225
226 return NULL;
227}
228
229/*
230 * add_edac_dev_to_global_list
231 * Before calling this function, caller must
232 * assign a unique value to edac_dev->dev_idx.
233 * Return:
234 * 0 on success
235 * 1 on failure.
236 */
237static int add_edac_dev_to_global_list (struct edac_device_ctl_info *edac_dev)
238{
239 struct list_head *item, *insert_before;
240 struct edac_device_ctl_info *rover;
241
242 insert_before = &edac_device_list;
243
244 /* Determine if already on the list */
245 if (unlikely((rover = find_edac_device_by_dev(edac_dev->dev)) != NULL))
246 goto fail0;
247
248 /* Insert in ascending order by 'dev_idx', so find position */
249 list_for_each(item, &edac_device_list) {
250 rover = list_entry(item, struct edac_device_ctl_info, link);
251
252 if (rover->dev_idx >= edac_dev->dev_idx) {
253 if (unlikely(rover->dev_idx == edac_dev->dev_idx))
254 goto fail1;
255
256 insert_before = item;
257 break;
258 }
259 }
260
261 list_add_tail_rcu(&edac_dev->link, insert_before);
262 return 0;
263
264fail0:
265 edac_printk(KERN_WARNING, EDAC_MC,
266 "%s (%s) %s %s already assigned %d\n",
267 rover->dev->bus_id, dev_name(rover->dev),
268 rover->mod_name, rover->ctl_name, rover->dev_idx);
269 return 1;
270
271fail1:
272 edac_printk(KERN_WARNING, EDAC_MC,
273 "bug in low-level driver: attempt to assign\n"
274 " duplicate dev_idx %d in %s()\n", rover->dev_idx, __func__);
275 return 1;
276}
277
278/*
279 * complete_edac_device_list_del
280 */
281static void complete_edac_device_list_del(struct rcu_head *head)
282{
283 struct edac_device_ctl_info *edac_dev;
284
285 edac_dev = container_of(head, struct edac_device_ctl_info, rcu);
286 INIT_LIST_HEAD(&edac_dev->link);
287 complete(&edac_dev->complete);
288}
289
290/*
291 * del_edac_device_from_global_list
292 */
293static void del_edac_device_from_global_list(
294 struct edac_device_ctl_info *edac_device)
295{
296 list_del_rcu(&edac_device->link);
297 init_completion(&edac_device->complete);
298 call_rcu(&edac_device->rcu, complete_edac_device_list_del);
299 wait_for_completion(&edac_device->complete);
300}
301
302/**
303 * edac_device_find
304 * Search for a edac_device_ctl_info structure whose index is 'idx'.
305 *
306 * If found, return a pointer to the structure.
307 * Else return NULL.
308 *
309 * Caller must hold device_ctls_mutex.
310 */
311struct edac_device_ctl_info * edac_device_find(int idx)
312{
313 struct list_head *item;
314 struct edac_device_ctl_info *edac_dev;
315
316 /* Iterate over list, looking for exact match of ID */
317 list_for_each(item, &edac_device_list) {
318 edac_dev = list_entry(item, struct edac_device_ctl_info, link);
319
320 if (edac_dev->dev_idx >= idx) {
321 if (edac_dev->dev_idx == idx)
322 return edac_dev;
323
324 /* not on list, so terminate early */
325 break;
326 }
327 }
328
329 return NULL;
330}
331EXPORT_SYMBOL(edac_device_find);
332
333
334/*
335 * edac_workq_function
336 * performs the operation scheduled by a workq request
337 */
338#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
339static void edac_workq_function(struct work_struct *work_req)
340{
341 struct delayed_work *d_work = (struct delayed_work*) work_req;
342 struct edac_device_ctl_info *edac_dev =
343 to_edac_device_ctl_work(d_work);
344#else
345static void edac_workq_function(void *ptr)
346{
347 struct edac_device_ctl_info *edac_dev =
348 (struct edac_device_ctl_info *) ptr;
349#endif
350
351 //debugf0("%s() here and running\n", __func__);
352 lock_device_list();
353
354 /* Only poll controllers that are running polled and have a check */
355 if ((edac_dev->op_state == OP_RUNNING_POLL) &&
356 (edac_dev->edac_check != NULL)) {
357 edac_dev->edac_check(edac_dev);
358 }
359
360 unlock_device_list();
361
362 /* Reschedule */
363 queue_delayed_work(edac_workqueue,&edac_dev->work, edac_dev->delay);
364}
365
366/*
367 * edac_workq_setup
368 * initialize a workq item for this edac_device instance
369 * passing in the new delay period in msec
370 */
371void edac_workq_setup(struct edac_device_ctl_info *edac_dev, unsigned msec)
372{
373 debugf0("%s()\n", __func__);
374
375 edac_dev->poll_msec = msec;
376 edac_device_calc_delay(edac_dev); /* Calc delay jiffies */
377
378#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
379 INIT_DELAYED_WORK(&edac_dev->work,edac_workq_function);
380#else
381 INIT_WORK(&edac_dev->work,edac_workq_function,edac_dev);
382#endif
383 queue_delayed_work(edac_workqueue,&edac_dev->work, edac_dev->delay);
384}
385
386/*
387 * edac_workq_teardown
388 * stop the workq processing on this edac_dev
389 */
390void edac_workq_teardown(struct edac_device_ctl_info *edac_dev)
391{
392 int status;
393
394 status = cancel_delayed_work(&edac_dev->work);
395 if (status == 0) {
396 /* workq instance might be running, wait for it */
397 flush_workqueue(edac_workqueue);
398 }
399}
400
401/*
402 * edac_device_reset_delay_period
403 */
404
405void edac_device_reset_delay_period(
406 struct edac_device_ctl_info *edac_dev,
407 unsigned long value)
408{
409 lock_device_list();
410
411 /* cancel the current workq request */
412 edac_workq_teardown(edac_dev);
413
414 /* restart the workq request, with new delay value */
415 edac_workq_setup(edac_dev, value);
416
417 unlock_device_list();
418}
419
420/*
421 * edac_op_state_toString(edac_dev)
422 */
423static char *edac_op_state_toString(struct edac_device_ctl_info *edac_dev)
424{
425 int opstate = edac_dev->op_state;
426
427 if (opstate == OP_RUNNING_POLL)
428 return "POLLED";
429 else if (opstate == OP_RUNNING_INTERRUPT)
430 return "INTERRUPT";
431 else if (opstate == OP_RUNNING_POLL_INTR)
432 return "POLL-INTR";
433 else if (opstate == OP_ALLOC)
434 return "ALLOC";
435 else if (opstate == OP_OFFLINE)
436 return "OFFLINE";
437
438 return "UNKNOWN";
439}
440
441/**
442 * edac_device_add_device: Insert the 'edac_dev' structure into the
443 * edac_device global list and create sysfs entries associated with
444 * edac_device structure.
445 * @edac_device: pointer to the edac_device structure to be added to the list
446 * @edac_idx: A unique numeric identifier to be assigned to the
447 * 'edac_device' structure.
448 *
449 * Return:
450 * 0 Success
451 * !0 Failure
452 */
453int edac_device_add_device(struct edac_device_ctl_info *edac_dev, int edac_idx)
454{
455 debugf0("%s()\n", __func__);
456
457 edac_dev->dev_idx = edac_idx;
458#ifdef CONFIG_EDAC_DEBUG
459 if (edac_debug_level >= 3)
460 edac_device_dump_device(edac_dev);
461#endif
462 lock_device_list();
463
464 if (add_edac_dev_to_global_list(edac_dev))
465 goto fail0;
466
467 /* set load time so that error rate can be tracked */
468 edac_dev->start_time = jiffies;
469
470 /* create this instance's sysfs entries */
471 if (edac_device_create_sysfs(edac_dev)) {
472 edac_device_printk(edac_dev, KERN_WARNING,
473 "failed to create sysfs device\n");
474 goto fail1;
475 }
476
477 /* If there IS a check routine, then we are running POLLED */
478 if (edac_dev->edac_check != NULL) {
479 /* This instance is NOW RUNNING */
480 edac_dev->op_state = OP_RUNNING_POLL;
481
482 /* enable workq processing on this instance, default = 1000 msec */
483 edac_workq_setup(edac_dev, 1000);
484 } else {
485 edac_dev->op_state = OP_RUNNING_INTERRUPT;
486 }
487
488
489 /* Report action taken */
490 edac_device_printk(edac_dev, KERN_INFO,
491 "Giving out device to module '%s' controller '%s': DEV '%s' (%s)\n",
492 edac_dev->mod_name,
493 edac_dev->ctl_name,
494 dev_name(edac_dev->dev),
495 edac_op_state_toString(edac_dev)
496 );
497
498 unlock_device_list();
499 return 0;
500
501fail1:
502 /* Some error, so remove the entry from the lsit */
503 del_edac_device_from_global_list(edac_dev);
504
505fail0:
506 unlock_device_list();
507 return 1;
508}
509EXPORT_SYMBOL_GPL(edac_device_add_device);
510
511/**
512 * edac_device_del_device:
513 * Remove sysfs entries for specified edac_device structure and
514 * then remove edac_device structure from global list
515 *
516 * @pdev:
517 * Pointer to 'struct device' representing edac_device
518 * structure to remove.
519 *
520 * Return:
521 * Pointer to removed edac_device structure,
522 * OR NULL if device not found.
523 */
524struct edac_device_ctl_info * edac_device_del_device(struct device *dev)
525{
526 struct edac_device_ctl_info *edac_dev;
527
528 debugf0("MC: %s()\n", __func__);
529
530 lock_device_list();
531
532 if ((edac_dev = find_edac_device_by_dev(dev)) == NULL) {
533 unlock_device_list();
534 return NULL;
535 }
536
537 /* mark this instance as OFFLINE */
538 edac_dev->op_state = OP_OFFLINE;
539
540 /* clear workq processing on this instance */
541 edac_workq_teardown(edac_dev);
542
543 /* Tear down the sysfs entries for this instance */
544 edac_device_remove_sysfs(edac_dev);
545
546 /* deregister from global list */
547 del_edac_device_from_global_list(edac_dev);
548
549 unlock_device_list();
550
551 edac_printk(KERN_INFO, EDAC_MC,
552 "Removed device %d for %s %s: DEV %s\n",
553 edac_dev->dev_idx,
554 edac_dev->mod_name,
555 edac_dev->ctl_name,
556 dev_name(edac_dev->dev));
557
558 return edac_dev;
559}
560EXPORT_SYMBOL_GPL(edac_device_del_device);
561
562
563static inline int edac_device_get_log_ce(struct edac_device_ctl_info *edac_dev)
564{
565 return edac_dev->log_ce;
566}
567
568static inline int edac_device_get_log_ue(struct edac_device_ctl_info *edac_dev)
569{
570 return edac_dev->log_ue;
571}
572
573static inline int edac_device_get_panic_on_ue(
574 struct edac_device_ctl_info *edac_dev)
575{
576 return edac_dev->panic_on_ue;
577}
578
579/*
580 * edac_device_handle_ce
581 * perform a common output and handling of an 'edac_dev' CE event
582 */
583void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
584 int inst_nr, int block_nr, const char *msg)
585{
586 struct edac_device_instance *instance;
587 struct edac_device_block *block = NULL;
588
589 if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
590 edac_device_printk(edac_dev, KERN_ERR,
591 "INTERNAL ERROR: 'instance' out of range "
592 "(%d >= %d)\n", inst_nr, edac_dev->nr_instances);
593 return;
594 }
595
596 instance = edac_dev->instances + inst_nr;
597
598 if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
599 edac_device_printk(edac_dev, KERN_ERR,
600 "INTERNAL ERROR: instance %d 'block' out of range "
601 "(%d >= %d)\n", inst_nr, block_nr, instance->nr_blocks);
602 return;
603 }
604
605 if (instance->nr_blocks > 0) {
606 block = instance->blocks + block_nr;
607 block->counters.ce_count++;
608 }
609
610 /* Propogate the count up the 'totals' tree */
611 instance->counters.ce_count++;
612 edac_dev->counters.ce_count++;
613
614 if (edac_device_get_log_ce(edac_dev))
615 edac_device_printk(edac_dev, KERN_WARNING,
616 "CE ctl: %s, instance: %s, block: %s: %s\n",
617 edac_dev->ctl_name, instance->name,
618 block ? block->name : "N/A", msg);
619}
620EXPORT_SYMBOL_GPL(edac_device_handle_ce);
621
622/*
623 * edac_device_handle_ue
624 * perform a common output and handling of an 'edac_dev' UE event
625 */
626void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
627 int inst_nr, int block_nr, const char *msg)
628{
629 struct edac_device_instance *instance;
630 struct edac_device_block *block = NULL;
631
632 if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
633 edac_device_printk(edac_dev, KERN_ERR,
634 "INTERNAL ERROR: 'instance' out of range "
635 "(%d >= %d)\n", inst_nr, edac_dev->nr_instances);
636 return;
637 }
638
639 instance = edac_dev->instances + inst_nr;
640
641 if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
642 edac_device_printk(edac_dev, KERN_ERR,
643 "INTERNAL ERROR: instance %d 'block' out of range "
644 "(%d >= %d)\n", inst_nr, block_nr, instance->nr_blocks);
645 return;
646 }
647
648 if (instance->nr_blocks > 0) {
649 block = instance->blocks + block_nr;
650 block->counters.ue_count++;
651 }
652
653 /* Propogate the count up the 'totals' tree */
654 instance->counters.ue_count++;
655 edac_dev->counters.ue_count++;
656
657 if (edac_device_get_log_ue(edac_dev))
658 edac_device_printk(edac_dev, KERN_EMERG,
659 "UE ctl: %s, instance: %s, block: %s: %s\n",
660 edac_dev->ctl_name, instance->name,
661 block ? block->name : "N/A", msg);
662
663 if (edac_device_get_panic_on_ue(edac_dev))
664 panic("EDAC %s: UE instance: %s, block %s: %s\n",
665 edac_dev->ctl_name, instance->name,
666 block ? block->name : "N/A", msg);
667}
668EXPORT_SYMBOL_GPL(edac_device_handle_ue);
669
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
new file mode 100644
index 000000000000..afb190502646
--- /dev/null
+++ b/drivers/edac/edac_device_sysfs.c
@@ -0,0 +1,837 @@
1/*
2 * file for managing the edac_device class of devices for EDAC
3 *
4 * (C) 2007 SoftwareBitMaker(http://www.softwarebitmaker.com)
5 * This file may be distributed under the terms of the
6 * GNU General Public License.
7 *
8 * Written Doug Thompson <norsk5@xmission.com>
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/sysdev.h>
14#include <linux/ctype.h>
15
16#include "edac_core.h"
17#include "edac_module.h"
18
19
20#define EDAC_DEVICE_SYMLINK "device"
21
22#define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj)
23#define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr)
24
25#ifdef DKT
26
27static ssize_t edac_dev_ue_count_show(struct edac_device_ctl_info *edac_dev,
28 char *data)
29{
30 return sprintf(data,"%d\n", edac_dev->ue_count);
31}
32
33static ssize_t edac_dev_ce_count_show(struct edac_device_ctl_info *edac_dev,
34 char *data)
35{
36 return sprintf(data,"%d\n", edac_dev->ce_count);
37}
38
39static ssize_t edac_dev_seconds_show(struct edac_device_ctl_info *edac_dev,
40 char *data)
41{
42 return sprintf(data,"%ld\n", (jiffies - edac_dev->start_time) / HZ);
43}
44
45static ssize_t edac_dev_ctl_name_show(struct edac_device_ctl_info *edac_dev,
46 char *data)
47{
48 return sprintf(data,"%s\n", edac_dev->ctl_name);
49}
50
51
52struct edacdev_attribute {
53 struct attribute attr;
54 ssize_t (*show)(struct edac_device_ctl_info *,char *);
55 ssize_t (*store)(struct edac_device_ctl_info *, const char *,size_t);
56};
57
58
59/* EDAC DEVICE show/store functions for top most object */
60static ssize_t edacdev_show(struct kobject *kobj, struct attribute *attr,
61 char *buffer)
62{
63 struct edac_device_ctl_info *edac_dev = to_edacdev(kobj);
64 struct edacdev_attribute * edacdev_attr = to_edacdev_attr(attr);
65
66 if (edacdev_attr->show)
67 return edacdev_attr->show(edac_dev, buffer);
68
69 return -EIO;
70}
71
72static ssize_t edacdev_store(struct kobject *kobj, struct attribute *attr,
73 const char *buffer, size_t count)
74{
75 struct edac_device_ctl_info *edac_dev = to_edacdev(kobj);
76 struct edacdev_attribute * edacdev_attr = to_edacdev_attr(attr);
77
78 if (edacdev_attr->store)
79 return edacdev_attr->store(edac_dev, buffer, count);
80
81 return -EIO;
82}
83
84static struct sysfs_ops edac_dev_ops = {
85 .show = edacdev_show,
86 .store = edacdev_store
87};
88
89#define EDACDEV_ATTR(_name,_mode,_show,_store) \
90static struct edacdev_attribute edac_dev_attr_##_name = { \
91 .attr = {.name = __stringify(_name), .mode = _mode }, \
92 .show = _show, \
93 .store = _store, \
94};
95
96/* default Control file */
97EDACDEV_ATTR(reset_counters,S_IWUSR,NULL,edac_dev_reset_counters_store);
98
99/* default Attribute files */
100EDACDEV_ATTR(mc_name,S_IRUGO,edac_dev_ctl_name_show,NULL);
101EDACDEV_ATTR(seconds_since_reset,S_IRUGO,edac_dev_seconds_show,NULL);
102EDACDEV_ATTR(ue_count,S_IRUGO,edac_dev_ue_count_show,NULL);
103EDACDEV_ATTR(ce_count,S_IRUGO,edac_dev_ce_count_show,NULL);
104
105
106static struct edacdev_attribute *edacdev_attr[] = {
107 &edacdev_attr_reset_counters,
108 &edacdev_attr_mc_name,
109 &edacdev_attr_seconds_since_reset,
110 &edacdev_attr_ue_count,
111 &edacdev_attr_ce_count,
112 NULL
113};
114
115/*
116 * Release of a Edac Device controlling instance
117 */
118static void edac_dev_instance_release(struct kobject *kobj)
119{
120 struct edac_device_ctl_info *edac_dev;
121
122 edac_dev = to_edacdev(kobj);
123 debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx);
124 complete(&edac_dev->kobj_complete);
125}
126
127static struct kobj_type ktype_device = {
128 .release = edac_dev_instance_release,
129 .sysfs_ops = &edacdev_ops,
130 .default_attrs = (struct attribute **) edacdev_attr,
131};
132
133#endif
134
135/************************** edac_device sysfs code and data **************/
136
137/*
138 * Set of edac_device_ctl_info attribute store/show functions
139 */
140
141/* 'log_ue' */
142static ssize_t edac_device_ctl_log_ue_show(
143 struct edac_device_ctl_info *ctl_info, char *data)
144{
145 return sprintf(data,"%u\n", ctl_info->log_ue);
146}
147
148static ssize_t edac_device_ctl_log_ue_store(
149 struct edac_device_ctl_info *ctl_info,
150 const char *data,size_t count)
151{
152 /* if parameter is zero, turn off flag, if non-zero turn on flag */
153 ctl_info->log_ue = (simple_strtoul(data,NULL,0) != 0);
154
155 return count;
156}
157
158/* 'log_ce' */
159static ssize_t edac_device_ctl_log_ce_show(
160 struct edac_device_ctl_info *ctl_info,char *data)
161{
162 return sprintf(data,"%u\n", ctl_info->log_ce);
163}
164
165static ssize_t edac_device_ctl_log_ce_store(
166 struct edac_device_ctl_info *ctl_info,
167 const char *data,size_t count)
168{
169 /* if parameter is zero, turn off flag, if non-zero turn on flag */
170 ctl_info->log_ce = (simple_strtoul(data,NULL,0) != 0);
171
172 return count;
173}
174
175
176/* 'panic_on_ue' */
177static ssize_t edac_device_ctl_panic_on_ue_show(
178 struct edac_device_ctl_info *ctl_info, char *data)
179{
180 return sprintf(data,"%u\n", ctl_info->panic_on_ue);
181}
182
183static ssize_t edac_device_ctl_panic_on_ue_store(
184 struct edac_device_ctl_info *ctl_info,
185 const char *data,size_t count)
186{
187 /* if parameter is zero, turn off flag, if non-zero turn on flag */
188 ctl_info->panic_on_ue = (simple_strtoul(data,NULL,0) != 0);
189
190 return count;
191}
192
193/* 'poll_msec' show and store functions*/
194static ssize_t edac_device_ctl_poll_msec_show(
195 struct edac_device_ctl_info *ctl_info, char *data)
196{
197 return sprintf(data,"%u\n", ctl_info->poll_msec);
198}
199
200static ssize_t edac_device_ctl_poll_msec_store(
201 struct edac_device_ctl_info *ctl_info,
202 const char *data,size_t count)
203{
204 unsigned long value;
205
206 /* get the value and enforce that it is non-zero, must be at least
207 * one millisecond for the delay period, between scans
208 * Then cancel last outstanding delay for the work request
209 * and set a new one.
210 */
211 value = simple_strtoul(data,NULL,0);
212 edac_device_reset_delay_period(ctl_info,value);
213
214 return count;
215}
216
217
218/* edac_device_ctl_info specific attribute structure */
219struct ctl_info_attribute {
220 struct attribute attr;
221 ssize_t (*show)(struct edac_device_ctl_info *,char *);
222 ssize_t (*store)(struct edac_device_ctl_info *,const char *,size_t);
223};
224
225#define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj)
226#define to_ctl_info_attr(a) container_of(a,struct ctl_info_attribute,attr)
227
228/* Function to 'show' fields from the edac_dev 'ctl_info' structure */
229static ssize_t edac_dev_ctl_info_show(struct kobject *kobj,
230 struct attribute *attr,
231 char *buffer)
232{
233 struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
234 struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
235
236 if (ctl_info_attr->show)
237 return ctl_info_attr->show(edac_dev,buffer);
238 return -EIO;
239}
240
241/* Function to 'store' fields into the edac_dev 'ctl_info' structure */
242static ssize_t edac_dev_ctl_info_store(struct kobject *kobj,
243 struct attribute *attr,
244 const char *buffer, size_t count)
245{
246 struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
247 struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
248
249 if (ctl_info_attr->store)
250 return ctl_info_attr->store(edac_dev, buffer, count);
251 return -EIO;
252}
253
254/* edac_dev file operations for an 'ctl_info' */
255static struct sysfs_ops device_ctl_info_ops = {
256 .show = edac_dev_ctl_info_show,
257 .store = edac_dev_ctl_info_store
258};
259
260#define CTL_INFO_ATTR(_name,_mode,_show,_store) \
261static struct ctl_info_attribute attr_ctl_info_##_name = { \
262 .attr = {.name = __stringify(_name), .mode = _mode }, \
263 .show = _show, \
264 .store = _store, \
265};
266
267
268/* Declare the various ctl_info attributes here and their respective ops */
269CTL_INFO_ATTR(log_ue,S_IRUGO|S_IWUSR,
270 edac_device_ctl_log_ue_show,
271 edac_device_ctl_log_ue_store);
272CTL_INFO_ATTR(log_ce,S_IRUGO|S_IWUSR,
273 edac_device_ctl_log_ce_show,
274 edac_device_ctl_log_ce_store);
275CTL_INFO_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,
276 edac_device_ctl_panic_on_ue_show,
277 edac_device_ctl_panic_on_ue_store);
278CTL_INFO_ATTR(poll_msec,S_IRUGO|S_IWUSR,
279 edac_device_ctl_poll_msec_show,
280 edac_device_ctl_poll_msec_store);
281
282
283/* Base Attributes of the EDAC_DEVICE ECC object */
284static struct ctl_info_attribute *device_ctrl_attr[] = {
285 &attr_ctl_info_panic_on_ue,
286 &attr_ctl_info_log_ue,
287 &attr_ctl_info_log_ce,
288 &attr_ctl_info_poll_msec,
289 NULL,
290};
291
292/* Main DEVICE kobject release() function */
293static void edac_device_ctrl_master_release(struct kobject *kobj)
294{
295 struct edac_device_ctl_info *edac_dev;
296
297 edac_dev = to_edacdev(kobj);
298
299 debugf1("%s()\n", __func__);
300 complete(&edac_dev->kobj_complete);
301}
302
303static struct kobj_type ktype_device_ctrl = {
304 .release = edac_device_ctrl_master_release,
305 .sysfs_ops = &device_ctl_info_ops,
306 .default_attrs = (struct attribute **) device_ctrl_attr,
307};
308
309
310/**************** edac_device main kobj ctor/dtor code *********************/
311
312/*
313 * edac_device_register_main_kobj
314 *
315 * perform the high level setup for the new edac_device instance
316 *
317 * Return: 0 SUCCESS
318 * !0 FAILURE
319 */
320static int edac_device_register_main_kobj(
321 struct edac_device_ctl_info *edac_dev)
322{
323 int err = 0;
324 struct sysdev_class *edac_class;
325
326 debugf1("%s()\n", __func__);
327
328 /* get the /sys/devices/system/edac reference */
329 edac_class = edac_get_edac_class();
330 if (edac_class == NULL) {
331 debugf1("%s() no edac_class error=%d\n", __func__, err);
332 return err;
333 }
334
335 /* Point to the 'edac_class' this instance 'reports' to */
336 edac_dev->edac_class = edac_class;
337
338 /* Init the devices's kobject */
339 memset(&edac_dev->kobj, 0, sizeof (struct kobject));
340 edac_dev->kobj.ktype = &ktype_device_ctrl;
341
342 /* set this new device under the edac_class kobject */
343 edac_dev->kobj.parent = &edac_class->kset.kobj;
344
345 /* generate sysfs "..../edac/<name>" */
346 debugf1("%s() set name of kobject to: %s\n",
347 __func__, edac_dev->name);
348 err = kobject_set_name(&edac_dev->kobj,"%s",edac_dev->name);
349 if (err)
350 return err;
351 err = kobject_register(&edac_dev->kobj);
352 if (err) {
353 debugf1("%s()Failed to register '.../edac/%s'\n",
354 __func__,edac_dev->name);
355 return err;
356 }
357
358 debugf1("%s() Registered '.../edac/%s' kobject\n",
359 __func__, edac_dev->name);
360
361 return 0;
362}
363
364/*
365 * edac_device_unregister_main_kobj:
366 * the '..../edac/<name>' kobject
367 */
368static void edac_device_unregister_main_kobj(
369 struct edac_device_ctl_info *edac_dev)
370{
371 debugf0("%s()\n", __func__);
372 debugf1("%s() name of kobject is: %s\n",
373 __func__, kobject_name(&edac_dev->kobj));
374
375 init_completion(&edac_dev->kobj_complete);
376
377 /*
378 * Unregister the edac device's kobject and
379 * wait for reference count to reach 0.
380 */
381 kobject_unregister(&edac_dev->kobj);
382 wait_for_completion(&edac_dev->kobj_complete);
383}
384
385
386/*************** edac_dev -> instance information ***********/
387
388/*
389 * Set of low-level instance attribute show functions
390 */
391static ssize_t instance_ue_count_show(
392 struct edac_device_instance *instance, char *data)
393{
394 return sprintf(data,"%u\n", instance->counters.ue_count);
395}
396
397static ssize_t instance_ce_count_show(
398 struct edac_device_instance *instance, char *data)
399{
400 return sprintf(data,"%u\n", instance->counters.ce_count);
401}
402
403
404
405#define to_instance(k) container_of(k, struct edac_device_instance, kobj)
406#define to_instance_attr(a) container_of(a,struct instance_attribute,attr)
407
408/* DEVICE instance kobject release() function */
409static void edac_device_ctrl_instance_release(struct kobject *kobj)
410{
411 struct edac_device_instance *instance;
412
413 debugf1("%s()\n", __func__);
414
415 instance = to_instance(kobj);
416 complete(&instance->kobj_complete);
417}
418
419
420/* instance specific attribute structure */
421struct instance_attribute {
422 struct attribute attr;
423 ssize_t (*show)(struct edac_device_instance *,char *);
424 ssize_t (*store)(struct edac_device_instance *,const char *,size_t);
425};
426
427
428/* Function to 'show' fields from the edac_dev 'instance' structure */
429static ssize_t edac_dev_instance_show(struct kobject *kobj,
430 struct attribute *attr,
431 char *buffer)
432{
433 struct edac_device_instance *instance = to_instance(kobj);
434 struct instance_attribute *instance_attr = to_instance_attr(attr);
435
436 if (instance_attr->show)
437 return instance_attr->show(instance,buffer);
438 return -EIO;
439}
440
441
442/* Function to 'store' fields into the edac_dev 'instance' structure */
443static ssize_t edac_dev_instance_store(struct kobject *kobj,
444 struct attribute *attr,
445 const char *buffer, size_t count)
446{
447 struct edac_device_instance *instance = to_instance(kobj);
448 struct instance_attribute *instance_attr = to_instance_attr(attr);
449
450 if (instance_attr->store)
451 return instance_attr->store(instance, buffer, count);
452 return -EIO;
453}
454
455
456
457/* edac_dev file operations for an 'instance' */
458static struct sysfs_ops device_instance_ops = {
459 .show = edac_dev_instance_show,
460 .store = edac_dev_instance_store
461};
462
463#define INSTANCE_ATTR(_name,_mode,_show,_store) \
464static struct instance_attribute attr_instance_##_name = { \
465 .attr = {.name = __stringify(_name), .mode = _mode }, \
466 .show = _show, \
467 .store = _store, \
468};
469
470/*
471 * Define attributes visible for the edac_device instance object
472 * Each contains a pointer to a show and an optional set
473 * function pointer that does the low level output/input
474 */
475INSTANCE_ATTR(ce_count,S_IRUGO,instance_ce_count_show,NULL);
476INSTANCE_ATTR(ue_count,S_IRUGO,instance_ue_count_show,NULL);
477
478/* list of edac_dev 'instance' attributes */
479static struct instance_attribute *device_instance_attr[] = {
480 &attr_instance_ce_count,
481 &attr_instance_ue_count,
482 NULL,
483};
484
485/* The 'ktype' for each edac_dev 'instance' */
486static struct kobj_type ktype_instance_ctrl = {
487 .release = edac_device_ctrl_instance_release,
488 .sysfs_ops = &device_instance_ops,
489 .default_attrs = (struct attribute **) device_instance_attr,
490};
491
492
493/*************** edac_dev -> instance -> block information *********/
494
495/*
496 * Set of low-level block attribute show functions
497 */
498static ssize_t block_ue_count_show(
499 struct edac_device_block *block, char *data)
500{
501 return sprintf(data,"%u\n", block->counters.ue_count);
502}
503
504static ssize_t block_ce_count_show(
505 struct edac_device_block *block, char *data)
506{
507 return sprintf(data,"%u\n", block->counters.ce_count);
508}
509
510
511
512#define to_block(k) container_of(k, struct edac_device_block, kobj)
513#define to_block_attr(a) container_of(a,struct block_attribute,attr)
514
515/* DEVICE block kobject release() function */
516static void edac_device_ctrl_block_release(struct kobject *kobj)
517{
518 struct edac_device_block *block;
519
520 debugf1("%s()\n", __func__);
521
522 block = to_block(kobj);
523 complete(&block->kobj_complete);
524}
525
526/* block specific attribute structure */
527struct block_attribute {
528 struct attribute attr;
529 ssize_t (*show)(struct edac_device_block *,char *);
530 ssize_t (*store)(struct edac_device_block *,const char *,size_t);
531};
532
533/* Function to 'show' fields from the edac_dev 'block' structure */
534static ssize_t edac_dev_block_show(struct kobject *kobj,
535 struct attribute *attr,
536 char *buffer)
537{
538 struct edac_device_block *block = to_block(kobj);
539 struct block_attribute *block_attr = to_block_attr(attr);
540
541 if (block_attr->show)
542 return block_attr->show(block,buffer);
543 return -EIO;
544}
545
546
547/* Function to 'store' fields into the edac_dev 'block' structure */
548static ssize_t edac_dev_block_store(struct kobject *kobj,
549 struct attribute *attr,
550 const char *buffer, size_t count)
551{
552 struct edac_device_block *block = to_block(kobj);
553 struct block_attribute *block_attr = to_block_attr(attr);
554
555 if (block_attr->store)
556 return block_attr->store(block, buffer, count);
557 return -EIO;
558}
559
560
561/* edac_dev file operations for a 'block' */
562static struct sysfs_ops device_block_ops = {
563 .show = edac_dev_block_show,
564 .store = edac_dev_block_store
565};
566
567
568#define BLOCK_ATTR(_name,_mode,_show,_store) \
569static struct block_attribute attr_block_##_name = { \
570 .attr = {.name = __stringify(_name), .mode = _mode }, \
571 .show = _show, \
572 .store = _store, \
573};
574
575BLOCK_ATTR(ce_count,S_IRUGO,block_ce_count_show,NULL);
576BLOCK_ATTR(ue_count,S_IRUGO,block_ue_count_show,NULL);
577
578
579/* list of edac_dev 'block' attributes */
580static struct block_attribute *device_block_attr[] = {
581 &attr_block_ce_count,
582 &attr_block_ue_count,
583 NULL,
584};
585
586/* The 'ktype' for each edac_dev 'block' */
587static struct kobj_type ktype_block_ctrl = {
588 .release = edac_device_ctrl_block_release,
589 .sysfs_ops = &device_block_ops,
590 .default_attrs = (struct attribute **) device_block_attr,
591};
592
593
594/************** block ctor/dtor code ************/
595
596/*
597 * edac_device_create_block
598 */
599static int edac_device_create_block(
600 struct edac_device_ctl_info *edac_dev,
601 struct edac_device_instance *instance,
602 int idx)
603{
604 int err;
605 struct edac_device_block *block;
606
607 block = &instance->blocks[idx];
608
609 debugf1("%s() Instance '%s' block[%d] '%s'\n",
610 __func__,instance->name, idx, block->name);
611
612 /* init this block's kobject */
613 memset(&block->kobj, 0, sizeof (struct kobject));
614 block->kobj.parent = &instance->kobj;
615 block->kobj.ktype = &ktype_block_ctrl;
616
617 err = kobject_set_name(&block->kobj,"%s",block->name);
618 if (err)
619 return err;
620
621 err = kobject_register(&block->kobj);
622 if (err) {
623 debugf1("%s()Failed to register instance '%s'\n",
624 __func__,block->name);
625 return err;
626 }
627
628 return 0;
629}
630
631/*
632 * edac_device_delete_block(edac_dev,j);
633 */
634static void edac_device_delete_block(
635 struct edac_device_ctl_info *edac_dev,
636 struct edac_device_instance *instance,
637 int idx)
638{
639 struct edac_device_block *block;
640
641 block = &instance->blocks[idx];
642
643 /* unregister this block's kobject */
644 init_completion(&block->kobj_complete);
645 kobject_unregister(&block->kobj);
646 wait_for_completion(&block->kobj_complete);
647}
648
649/************** instance ctor/dtor code ************/
650
651/*
652 * edac_device_create_instance
653 * create just one instance of an edac_device 'instance'
654 */
655static int edac_device_create_instance(
656 struct edac_device_ctl_info *edac_dev, int idx)
657{
658 int i, j;
659 int err;
660 struct edac_device_instance *instance;
661
662 instance = &edac_dev->instances[idx];
663
664 /* Init the instance's kobject */
665 memset(&instance->kobj, 0, sizeof (struct kobject));
666
667 /* set this new device under the edac_device main kobject */
668 instance->kobj.parent = &edac_dev->kobj;
669 instance->kobj.ktype = &ktype_instance_ctrl;
670
671 err = kobject_set_name(&instance->kobj,"%s",instance->name);
672 if (err)
673 return err;
674
675 err = kobject_register(&instance->kobj);
676 if (err != 0) {
677 debugf2("%s() Failed to register instance '%s'\n",
678 __func__,instance->name);
679 return err;
680 }
681
682 debugf1("%s() now register '%d' blocks for instance %d\n",
683 __func__,instance->nr_blocks,idx);
684
685 /* register all blocks of this instance */
686 for (i = 0; i < instance->nr_blocks; i++ ) {
687 err = edac_device_create_block(edac_dev,instance,i);
688 if (err) {
689 for (j = 0; j < i; j++) {
690 edac_device_delete_block(edac_dev,instance,j);
691 }
692 return err;
693 }
694 }
695
696 debugf1("%s() Registered instance %d '%s' kobject\n",
697 __func__, idx, instance->name);
698
699 return 0;
700}
701
702/*
703 * edac_device_remove_instance
704 * remove an edac_device instance
705 */
706static void edac_device_delete_instance(
707 struct edac_device_ctl_info *edac_dev, int idx)
708{
709 int i;
710 struct edac_device_instance *instance;
711
712 instance = &edac_dev->instances[idx];
713
714 /* unregister all blocks in this instance */
715 for (i = 0; i < instance->nr_blocks; i++) {
716 edac_device_delete_block(edac_dev,instance,i);
717 }
718
719 /* unregister this instance's kobject */
720 init_completion(&instance->kobj_complete);
721 kobject_unregister(&instance->kobj);
722 wait_for_completion(&instance->kobj_complete);
723}
724
725/*
726 * edac_device_create_instances
727 * create the first level of 'instances' for this device
728 * (ie 'cache' might have 'cache0', 'cache1', 'cache2', etc
729 */
730static int edac_device_create_instances(struct edac_device_ctl_info *edac_dev)
731{
732 int i, j;
733 int err;
734
735 debugf0("%s()\n", __func__);
736
737 /* iterate over creation of the instances */
738 for (i = 0; i < edac_dev->nr_instances; i++ ) {
739 err = edac_device_create_instance(edac_dev,i);
740 if (err) {
741 /* unwind previous instances on error */
742 for (j = 0; j < i; j++) {
743 edac_device_delete_instance(edac_dev,j);
744 }
745 return err;
746 }
747 }
748
749 return 0;
750}
751
752/*
753 * edac_device_delete_instances(edac_dev);
754 * unregister all the kobjects of the instances
755 */
756static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev)
757{
758 int i;
759
760 /* iterate over creation of the instances */
761 for (i = 0; i < edac_dev->nr_instances; i++ ) {
762 edac_device_delete_instance(edac_dev,i);
763 }
764}
765
766/******************* edac_dev sysfs ctor/dtor code *************/
767
768/*
769 * edac_device_create_sysfs() Constructor
770 *
771 * Create a new edac_device kobject instance,
772 *
773 * Return:
774 * 0 Success
775 * !0 Failure
776 */
777int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
778{
779 int err;
780 struct kobject *edac_kobj=&edac_dev->kobj;
781
782 /* register this instance's main kobj with the edac class kobj */
783 err = edac_device_register_main_kobj(edac_dev);
784 if (err)
785 return err;
786
787 debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx);
788
789 /* create a symlink from the edac device
790 * to the platform 'device' being used for this
791 */
792 err = sysfs_create_link(edac_kobj,
793 &edac_dev->dev->kobj,
794 EDAC_DEVICE_SYMLINK);
795 if (err) {
796 debugf0("%s() sysfs_create_link() returned err= %d\n",
797 __func__, err);
798 return err;
799 }
800
801 debugf0("%s() calling create-instances, idx=%d\n",
802 __func__, edac_dev->dev_idx);
803
804 /* Create the first level instance directories */
805 err = edac_device_create_instances(edac_dev);
806 if (err) {
807 goto error0;
808 }
809
810 return 0;
811
812 /* Error unwind stack */
813
814error0:
815 edac_device_unregister_main_kobj(edac_dev);
816
817 return err;
818}
819
820/*
821 * edac_device_remove_sysfs() destructor
822 *
823 * remove a edac_device instance
824 */
825void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev)
826{
827 debugf0("%s()\n", __func__);
828
829 edac_device_delete_instances(edac_dev);
830
831 /* remove the sym link */
832 sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
833
834 /* unregister the instance's main kobj */
835 edac_device_unregister_main_kobj(edac_dev);
836}
837
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 3be5b7fe79cd..1f22d8cad6f7 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -88,7 +88,7 @@ static void edac_mc_dump_mci(struct mem_ctl_info *mci)
88 * If 'size' is a constant, the compiler will optimize this whole function 88 * If 'size' is a constant, the compiler will optimize this whole function
89 * down to either a no-op or the addition of a constant to the value of 'ptr'. 89 * down to either a no-op or the addition of a constant to the value of 'ptr'.
90 */ 90 */
91static inline char * align_ptr(void *ptr, unsigned size) 91char * edac_align_ptr(void *ptr, unsigned size)
92{ 92{
93 unsigned align, r; 93 unsigned align, r;
94 94
@@ -147,10 +147,10 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
147 * hardcode everything into a single struct. 147 * hardcode everything into a single struct.
148 */ 148 */
149 mci = (struct mem_ctl_info *) 0; 149 mci = (struct mem_ctl_info *) 0;
150 csi = (struct csrow_info *)align_ptr(&mci[1], sizeof(*csi)); 150 csi = (struct csrow_info *)edac_align_ptr(&mci[1], sizeof(*csi));
151 chi = (struct channel_info *) 151 chi = (struct channel_info *)
152 align_ptr(&csi[nr_csrows], sizeof(*chi)); 152 edac_align_ptr(&csi[nr_csrows], sizeof(*chi));
153 pvt = align_ptr(&chi[nr_chans * nr_csrows], sz_pvt); 153 pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt);
154 size = ((unsigned long) pvt) + sz_pvt; 154 size = ((unsigned long) pvt) + sz_pvt;
155 155
156 if ((mci = kmalloc(size, GFP_KERNEL)) == NULL) 156 if ((mci = kmalloc(size, GFP_KERNEL)) == NULL)
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 4a5e335f61d3..35bcf926017f 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -94,14 +94,6 @@ static const char *edac_caps[] = {
94 [EDAC_S16ECD16ED] = "S16ECD16ED" 94 [EDAC_S16ECD16ED] = "S16ECD16ED"
95}; 95};
96 96
97/*
98 * sysfs object: /sys/devices/system/edac
99 * need to export to other files in this modules
100 */
101struct sysdev_class edac_class = {
102 set_kset_name("edac"),
103};
104
105/* sysfs object: 97/* sysfs object:
106 * /sys/devices/system/edac/mc 98 * /sys/devices/system/edac/mc
107 */ 99 */
@@ -224,43 +216,38 @@ static struct kobj_type ktype_memctrl = {
224int edac_sysfs_memctrl_setup(void) 216int edac_sysfs_memctrl_setup(void)
225{ 217{
226 int err = 0; 218 int err = 0;
219 struct sysdev_class *edac_class;
227 220
228 debugf1("%s()\n", __func__); 221 debugf1("%s()\n", __func__);
229 222
230 /* create the /sys/devices/system/edac directory */ 223 /* get the /sys/devices/system/edac class reference */
231 err = sysdev_class_register(&edac_class); 224 edac_class = edac_get_edac_class();
232 225 if (edac_class == NULL) {
233 if (err) { 226 debugf1("%s() no edac_class error=%d\n", __func__, err);
234 debugf1("%s() error=%d\n", __func__, err);
235 return err; 227 return err;
236 } 228 }
237 229
238 /* Init the MC's kobject */ 230 /* Init the MC's kobject */
239 memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj)); 231 memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj));
240 edac_memctrl_kobj.parent = &edac_class.kset.kobj; 232 edac_memctrl_kobj.parent = &edac_class->kset.kobj;
241 edac_memctrl_kobj.ktype = &ktype_memctrl; 233 edac_memctrl_kobj.ktype = &ktype_memctrl;
242 234
243 /* generate sysfs "..../edac/mc" */ 235 /* generate sysfs "..../edac/mc" */
244 err = kobject_set_name(&edac_memctrl_kobj,"mc"); 236 err = kobject_set_name(&edac_memctrl_kobj,"mc");
245 237 if (err) {
246 if (err) 238 debugf1("%s() Failed to set name '.../edac/mc'\n", __func__ );
247 goto fail; 239 return err;
240 }
248 241
249 /* FIXME: maybe new sysdev_create_subdir() */ 242 /* FIXME: maybe new sysdev_create_subdir() */
250 err = kobject_register(&edac_memctrl_kobj); 243 err = kobject_register(&edac_memctrl_kobj);
251
252 if (err) { 244 if (err) {
253 debugf1("Failed to register '.../edac/mc'\n"); 245 debugf1("%s() Failed to register '.../edac/mc'\n", __func__ );
254 goto fail; 246 return err;
255 } 247 }
256 248
257 debugf1("Registered '.../edac/mc' kobject\n"); 249 debugf1("%s() Registered '.../edac/mc' kobject\n",__func__);
258
259 return 0; 250 return 0;
260
261fail:
262 sysdev_class_unregister(&edac_class);
263 return err;
264} 251}
265 252
266/* 253/*
@@ -276,9 +263,6 @@ void edac_sysfs_memctrl_teardown(void)
276 init_completion(&edac_memctrl_kobj_complete); 263 init_completion(&edac_memctrl_kobj_complete);
277 kobject_unregister(&edac_memctrl_kobj); 264 kobject_unregister(&edac_memctrl_kobj);
278 wait_for_completion(&edac_memctrl_kobj_complete); 265 wait_for_completion(&edac_memctrl_kobj_complete);
279
280 /* Unregister the 'edac' object */
281 sysdev_class_unregister(&edac_class);
282} 266}
283 267
284 268
@@ -286,32 +270,38 @@ void edac_sysfs_memctrl_teardown(void)
286 */ 270 */
287 271
288/* Set of more default csrow<id> attribute show/store functions */ 272/* Set of more default csrow<id> attribute show/store functions */
289static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, int private) 273static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data,
274 int private)
290{ 275{
291 return sprintf(data,"%u\n", csrow->ue_count); 276 return sprintf(data,"%u\n", csrow->ue_count);
292} 277}
293 278
294static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, int private) 279static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
280 int private)
295{ 281{
296 return sprintf(data,"%u\n", csrow->ce_count); 282 return sprintf(data,"%u\n", csrow->ce_count);
297} 283}
298 284
299static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private) 285static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
286 int private)
300{ 287{
301 return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages)); 288 return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages));
302} 289}
303 290
304static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private) 291static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
292 int private)
305{ 293{
306 return sprintf(data,"%s\n", mem_types[csrow->mtype]); 294 return sprintf(data,"%s\n", mem_types[csrow->mtype]);
307} 295}
308 296
309static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private) 297static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
298 int private)
310{ 299{
311 return sprintf(data,"%s\n", dev_types[csrow->dtype]); 300 return sprintf(data,"%s\n", dev_types[csrow->dtype]);
312} 301}
313 302
314static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private) 303static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
304 int private)
315{ 305{
316 return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]); 306 return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]);
317} 307}
@@ -509,9 +499,10 @@ static int edac_create_channel_files(struct kobject *kobj, int chan)
509 if (!err) { 499 if (!err) {
510 /* create the CE Count attribute file */ 500 /* create the CE Count attribute file */
511 err = sysfs_create_file(kobj, 501 err = sysfs_create_file(kobj,
512 (struct attribute *) dynamic_csrow_ce_count_attr[chan]); 502 (struct attribute *)dynamic_csrow_ce_count_attr[chan]);
513 } else { 503 } else {
514 debugf1("%s() dimm labels and ce_count files created", __func__); 504 debugf1("%s() dimm labels and ce_count files created",
505 __func__);
515 } 506 }
516 507
517 return err; 508 return err;
@@ -643,7 +634,7 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
643 } else { 634 } else {
644 /* FIXME: produce "not implemented" ERROR for user-side. */ 635 /* FIXME: produce "not implemented" ERROR for user-side. */
645 edac_printk(KERN_WARNING, EDAC_MC, 636 edac_printk(KERN_WARNING, EDAC_MC,
646 "Memory scrubbing 'get' control is not implemented!\n"); 637 "Memory scrubbing 'get' control is not implemented\n");
647 } 638 }
648 return sprintf(data, "%d\n", bandwidth); 639 return sprintf(data, "%d\n", bandwidth);
649} 640}
@@ -755,7 +746,8 @@ MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL);
755MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL); 746MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL);
756 747
757/* memory scrubber attribute file */ 748/* memory scrubber attribute file */
758MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store); 749MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,\
750 mci_sdram_scrub_rate_store);
759 751
760static struct mcidev_attribute *mci_attr[] = { 752static struct mcidev_attribute *mci_attr[] = {
761 &mci_attr_reset_counters, 753 &mci_attr_reset_counters,
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
index 8db0471a9476..3cd3a236821c 100644
--- a/drivers/edac/edac_module.c
+++ b/drivers/edac/edac_module.c
@@ -13,8 +13,77 @@ int edac_debug_level = 1;
13EXPORT_SYMBOL_GPL(edac_debug_level); 13EXPORT_SYMBOL_GPL(edac_debug_level);
14#endif 14#endif
15 15
16/* scope is to module level only */
17struct workqueue_struct *edac_workqueue;
18
19/* private to this file */
16static struct task_struct *edac_thread; 20static struct task_struct *edac_thread;
17 21
22
23/*
24 * sysfs object: /sys/devices/system/edac
25 * need to export to other files in this modules
26 */
27static struct sysdev_class edac_class = {
28 set_kset_name("edac"),
29};
30static int edac_class_valid = 0;
31
32/*
33 * edac_get_edac_class()
34 *
35 * return pointer to the edac class of 'edac'
36 */
37struct sysdev_class *edac_get_edac_class(void)
38{
39 struct sysdev_class *classptr=NULL;
40
41 if (edac_class_valid)
42 classptr = &edac_class;
43
44 return classptr;
45}
46
47/*
48 * edac_register_sysfs_edac_name()
49 *
50 * register the 'edac' into /sys/devices/system
51 *
52 * return:
53 * 0 success
54 * !0 error
55 */
56static int edac_register_sysfs_edac_name(void)
57{
58 int err;
59
60 /* create the /sys/devices/system/edac directory */
61 err = sysdev_class_register(&edac_class);
62
63 if (err) {
64 debugf1("%s() error=%d\n", __func__, err);
65 return err;
66 }
67
68 edac_class_valid = 1;
69 return 0;
70}
71
72/*
73 * sysdev_class_unregister()
74 *
75 * unregister the 'edac' from /sys/devices/system
76 */
77static void edac_unregister_sysfs_edac_name(void)
78{
79 /* only if currently registered, then unregister it */
80 if (edac_class_valid)
81 sysdev_class_unregister(&edac_class);
82
83 edac_class_valid = 0;
84}
85
86
18/* 87/*
19 * Check MC status every edac_get_poll_msec(). 88 * Check MC status every edac_get_poll_msec().
20 * Check PCI status every edac_get_poll_msec() as well. 89 * Check PCI status every edac_get_poll_msec() as well.
@@ -53,11 +122,40 @@ static int edac_kernel_thread(void *arg)
53} 122}
54 123
55/* 124/*
125 * edac_workqueue_setup
126 * initialize the edac work queue for polling operations
127 */
128static int edac_workqueue_setup(void)
129{
130 edac_workqueue = create_singlethread_workqueue("edac-poller");
131 if (edac_workqueue == NULL)
132 return -ENODEV;
133 else
134 return 0;
135}
136
137/*
138 * edac_workqueue_teardown
139 * teardown the edac workqueue
140 */
141static void edac_workqueue_teardown(void)
142{
143 if (edac_workqueue) {
144 flush_workqueue(edac_workqueue);
145 destroy_workqueue(edac_workqueue);
146 edac_workqueue = NULL;
147 }
148}
149
150
151/*
56 * edac_init 152 * edac_init
57 * module initialization entry point 153 * module initialization entry point
58 */ 154 */
59static int __init edac_init(void) 155static int __init edac_init(void)
60{ 156{
157 int err = 0;
158
61 edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n"); 159 edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n");
62 160
63 /* 161 /*
@@ -69,32 +167,61 @@ static int __init edac_init(void)
69 */ 167 */
70 edac_pci_clear_parity_errors(); 168 edac_pci_clear_parity_errors();
71 169
72 /* Create the MC sysfs entries */ 170 /*
171 * perform the registration of the /sys/devices/system/edac object
172 */
173 if (edac_register_sysfs_edac_name()) {
174 edac_printk(KERN_ERR, EDAC_MC,
175 "Error initializing 'edac' kobject\n");
176 err = -ENODEV;
177 goto error;
178 }
179
180 /* Create the MC sysfs entries, must be first
181 */
73 if (edac_sysfs_memctrl_setup()) { 182 if (edac_sysfs_memctrl_setup()) {
74 edac_printk(KERN_ERR, EDAC_MC, 183 edac_printk(KERN_ERR, EDAC_MC,
75 "Error initializing sysfs code\n"); 184 "Error initializing sysfs code\n");
76 return -ENODEV; 185 err = -ENODEV;
186 goto error_sysfs;
77 } 187 }
78 188
79 /* Create the PCI parity sysfs entries */ 189 /* Create the PCI parity sysfs entries */
80 if (edac_sysfs_pci_setup()) { 190 if (edac_sysfs_pci_setup()) {
81 edac_sysfs_memctrl_teardown();
82 edac_printk(KERN_ERR, EDAC_MC, 191 edac_printk(KERN_ERR, EDAC_MC,
83 "PCI: Error initializing sysfs code\n"); 192 "PCI: Error initializing sysfs code\n");
84 return -ENODEV; 193 err = -ENODEV;
194 goto error_mem;
195 }
196
197 /* Setup/Initialize the edac_device system */
198 err = edac_workqueue_setup();
199 if (err) {
200 edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
201 goto error_pci;
85 } 202 }
86 203
87 /* create our kernel thread */ 204 /* create our kernel thread */
88 edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac"); 205 edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac");
89 206
90 if (IS_ERR(edac_thread)) { 207 if (IS_ERR(edac_thread)) {
91 /* remove the sysfs entries */ 208 err = PTR_ERR(edac_thread);
92 edac_sysfs_memctrl_teardown(); 209 goto error_work;
93 edac_sysfs_pci_teardown();
94 return PTR_ERR(edac_thread);
95 } 210 }
96 211
97 return 0; 212 return 0;
213
214 /* Error teardown stack */
215error_work:
216 edac_workqueue_teardown();
217error_pci:
218 edac_sysfs_pci_teardown();
219error_mem:
220 edac_sysfs_memctrl_teardown();
221error_sysfs:
222 edac_unregister_sysfs_edac_name();
223error:
224 return err;
98} 225}
99 226
100/* 227/*
@@ -106,9 +233,11 @@ static void __exit edac_exit(void)
106 debugf0("%s()\n", __func__); 233 debugf0("%s()\n", __func__);
107 kthread_stop(edac_thread); 234 kthread_stop(edac_thread);
108 235
109 /* tear down the sysfs device */ 236 /* tear down the various subsystems*/
237 edac_workqueue_teardown();
110 edac_sysfs_memctrl_teardown(); 238 edac_sysfs_memctrl_teardown();
111 edac_sysfs_pci_teardown(); 239 edac_sysfs_pci_teardown();
240 edac_unregister_sysfs_edac_name();
112} 241}
113 242
114/* 243/*
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index 69c77f85bcd4..2758d03c3e03 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -33,6 +33,15 @@ extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
33extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev); 33extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
34extern struct sysdev_class *edac_get_edac_class(void); 34extern struct sysdev_class *edac_get_edac_class(void);
35 35
36/* edac core workqueue: single CPU mode */
37extern struct workqueue_struct *edac_workqueue;
38extern void edac_workq_setup(struct edac_device_ctl_info *edac_dev,
39 unsigned msec);
40extern void edac_workq_teardown(struct edac_device_ctl_info *edac_dev);
41extern void edac_device_reset_delay_period(
42 struct edac_device_ctl_info *edac_dev,
43 unsigned long value);
44
36 45
37/* 46/*
38 * EDAC PCI functions 47 * EDAC PCI functions