aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/edac_core.h67
-rw-r--r--drivers/edac/edac_device.c94
-rw-r--r--drivers/edac/edac_device_sysfs.c22
3 files changed, 115 insertions, 68 deletions
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index e49dce069d1f..fca1990945a9 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -468,32 +468,34 @@ struct edac_device_counter {
468 u32 ce_count; 468 u32 ce_count;
469}; 469};
470 470
471/* 471/* forward reference */
472 * An array of these is passed to the alloc() function 472struct edac_device_ctl_info;
473 * to specify attributes of the edac_block 473struct edac_device_block;
474 */
475struct edac_attrib_spec {
476 char name[EDAC_DEVICE_NAME_LEN + 1];
477 474
478 int type; 475/* edac_dev_sysfs_attribute structure
479#define EDAC_ATTR_INT 0x01 476 * used for driver sysfs attributes in mem_ctl_info
480#define EDAC_ATTR_CHAR 0x02 477 * for extra controls and attributes:
478 * like high level error Injection controls
479 */
480struct edac_dev_sysfs_attribute {
481 struct attribute attr;
482 ssize_t (*show)(struct edac_device_ctl_info *, char *);
483 ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t);
481}; 484};
482 485
483/* Attribute control structure 486/* edac_dev_sysfs_block_attribute structure
484 * In this structure is a pointer to the driver's edac_attrib_spec 487 * used in leaf 'block' nodes for adding controls/attributes
485 * The life of this pointer is inclusive in the life of the driver's
486 * life cycle.
487 */ 488 */
488struct edac_attrib { 489struct edac_dev_sysfs_block_attribute {
489 struct edac_device_block *block; /* Up Pointer */ 490 struct attribute attr;
490 491 ssize_t (*show)(struct kobject *, struct attribute *, char *);
491 struct edac_attrib_spec *spec; /* ptr to module spec entry */ 492 ssize_t (*store)(struct kobject *, struct attribute *,
492 493 const char *, size_t);
493 union { /* actual value */ 494 struct edac_device_block *block;
494 int edac_attrib_int_value; 495
495 char edac_attrib_char_value[EDAC_ATTRIB_VALUE_LEN + 1]; 496 /* low driver use */
496 } edac_attrib_value; 497 void *arg;
498 unsigned int value;
497}; 499};
498 500
499/* device block control structure */ 501/* device block control structure */
@@ -504,7 +506,9 @@ struct edac_device_block {
504 struct edac_device_counter counters; /* basic UE and CE counters */ 506 struct edac_device_counter counters; /* basic UE and CE counters */
505 507
506 int nr_attribs; /* how many attributes */ 508 int nr_attribs; /* how many attributes */
507 struct edac_attrib *attribs; /* this block's attributes */ 509
510 /* this block's attributes, could be NULL */
511 struct edac_dev_sysfs_block_attribute *block_attributes;
508 512
509 /* edac sysfs device control */ 513 /* edac sysfs device control */
510 struct kobject kobj; 514 struct kobject kobj;
@@ -526,15 +530,6 @@ struct edac_device_instance {
526 struct completion kobj_complete; 530 struct completion kobj_complete;
527}; 531};
528 532
529/* edac_dev_sysfs_attribute structure
530 * used for driver sysfs attributes and in mem_ctl_info
531 * sysfs top level entries
532 */
533struct edac_dev_sysfs_attribute {
534 struct attribute attr;
535 ssize_t (*show)(struct edac_device_ctl_info *,char *);
536 ssize_t (*store)(struct edac_device_ctl_info *, const char *,size_t);
537};
538 533
539/* 534/*
540 * Abstract edac_device control info structure 535 * Abstract edac_device control info structure
@@ -635,12 +630,10 @@ struct edac_device_ctl_info {
635 */ 630 */
636extern struct edac_device_ctl_info *edac_device_alloc_ctl_info( 631extern struct edac_device_ctl_info *edac_device_alloc_ctl_info(
637 unsigned sizeof_private, 632 unsigned sizeof_private,
638 char *edac_device_name, 633 char *edac_device_name, unsigned nr_instances,
639 unsigned nr_instances, 634 char *edac_block_name, unsigned nr_blocks,
640 char *edac_block_name,
641 unsigned nr_blocks,
642 unsigned offset_value, 635 unsigned offset_value,
643 struct edac_attrib_spec *attrib_spec, 636 struct edac_dev_sysfs_block_attribute *block_attributes,
644 unsigned nr_attribs); 637 unsigned nr_attribs);
645 638
646/* The offset value can be: 639/* The offset value can be:
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index b53e8d51d9a5..8264e3728c79 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -67,12 +67,12 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
67 char *edac_device_name, unsigned nr_instances, 67 char *edac_device_name, unsigned nr_instances,
68 char *edac_block_name, unsigned nr_blocks, 68 char *edac_block_name, unsigned nr_blocks,
69 unsigned offset_value, /* zero, 1, or other based offset */ 69 unsigned offset_value, /* zero, 1, or other based offset */
70 struct edac_attrib_spec *attrib_spec, unsigned nr_attribs) 70 struct edac_dev_sysfs_block_attribute *attrib_spec, unsigned nr_attrib)
71{ 71{
72 struct edac_device_ctl_info *dev_ctl; 72 struct edac_device_ctl_info *dev_ctl;
73 struct edac_device_instance *dev_inst, *inst; 73 struct edac_device_instance *dev_inst, *inst;
74 struct edac_device_block *dev_blk, *blk_p, *blk; 74 struct edac_device_block *dev_blk, *blk_p, *blk;
75 struct edac_attrib *dev_attrib, *attrib_p, *attrib; 75 struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib;
76 unsigned total_size; 76 unsigned total_size;
77 unsigned count; 77 unsigned count;
78 unsigned instance, block, attr; 78 unsigned instance, block, attr;
@@ -81,29 +81,47 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
81 debugf1("%s() instances=%d blocks=%d\n", 81 debugf1("%s() instances=%d blocks=%d\n",
82 __func__, nr_instances, nr_blocks); 82 __func__, nr_instances, nr_blocks);
83 83
84 /* Figure out the offsets of the various items from the start of an 84 /* Calculate the size of memory we need to allocate AND
85 * ctl_info structure. We want the alignment of each item 85 * determine the offsets of the various item arrays
86 * (instance,block,attrib) from the start of an allocated structure.
87 * We want the alignment of each item (instance,block,attrib)
86 * to be at least as stringent as what the compiler would 88 * to be at least as stringent as what the compiler would
87 * provide if we could simply hardcode everything into a single struct. 89 * provide if we could simply hardcode everything into a single struct.
88 */ 90 */
89 dev_ctl = (struct edac_device_ctl_info *)NULL; 91 dev_ctl = (struct edac_device_ctl_info *)NULL;
90 92
91 /* Calc the 'end' offset past the ctl_info structure */ 93 /* Calc the 'end' offset past end of ONE ctl_info structure
94 * which will become the start of the 'instance' array
95 */
92 dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst)); 96 dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst));
93 97
94 /* Calc the 'end' offset past the instance array */ 98 /* Calc the 'end' offset past the instance array within the ctl_info
99 * which will become the start of the block array
100 */
95 dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk)); 101 dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk));
96 102
97 /* Calc the 'end' offset past the dev_blk array */ 103 /* Calc the 'end' offset past the dev_blk array
104 * which will become the start of the attrib array, if any.
105 */
98 count = nr_instances * nr_blocks; 106 count = nr_instances * nr_blocks;
99 dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib)); 107 dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib));
100 108
101 /* Check for case of NO attributes specified */ 109 /* Check for case of when an attribute array is specified */
102 if (nr_attribs > 0) 110 if (nr_attrib > 0) {
103 count *= nr_attribs; 111 /* calc how many nr_attrib we need */
112 count *= nr_attrib;
104 113
105 /* Calc the 'end' offset past the attributes array */ 114 /* Calc the 'end' offset past the attributes array */
106 pvt = edac_align_ptr(&dev_attrib[count], sz_private); 115 pvt = edac_align_ptr(&dev_attrib[count], sz_private);
116 } else {
117 /* no attribute array specificed */
118 pvt = edac_align_ptr(dev_attrib, sz_private);
119 }
120
121 /* 'pvt' now points to where the private data area is.
122 * At this point 'pvt' (like dev_inst,dev_blk and dev_attrib)
123 * is baselined at ZERO
124 */
107 total_size = ((unsigned long)pvt) + sz_private; 125 total_size = ((unsigned long)pvt) + sz_private;
108 126
109 /* Allocate the amount of memory for the set of control structures */ 127 /* Allocate the amount of memory for the set of control structures */
@@ -111,17 +129,22 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
111 if (dev_ctl == NULL) 129 if (dev_ctl == NULL)
112 return NULL; 130 return NULL;
113 131
114 /* Adjust pointers so they point within the memory we just allocated 132 /* Adjust pointers so they point within the actual memory we
115 * rather than an imaginary chunk of memory located at address 0. 133 * just allocated rather than an imaginary chunk of memory
134 * located at address 0.
135 * 'dev_ctl' points to REAL memory, while the others are
136 * ZERO based and thus need to be adjusted to point within
137 * the allocated memory.
116 */ 138 */
117 dev_inst = (struct edac_device_instance *) 139 dev_inst = (struct edac_device_instance *)
118 (((char *)dev_ctl) + ((unsigned long)dev_inst)); 140 (((char *)dev_ctl) + ((unsigned long)dev_inst));
119 dev_blk = (struct edac_device_block *) 141 dev_blk = (struct edac_device_block *)
120 (((char *)dev_ctl) + ((unsigned long)dev_blk)); 142 (((char *)dev_ctl) + ((unsigned long)dev_blk));
121 dev_attrib = (struct edac_attrib *) 143 dev_attrib = (struct edac_dev_sysfs_block_attribute *)
122 (((char *)dev_ctl) + ((unsigned long)dev_attrib)); 144 (((char *)dev_ctl) + ((unsigned long)dev_attrib));
123 pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL; 145 pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL;
124 146
147 /* Begin storing the information into the control info structure */
125 dev_ctl->nr_instances = nr_instances; 148 dev_ctl->nr_instances = nr_instances;
126 dev_ctl->instances = dev_inst; 149 dev_ctl->instances = dev_inst;
127 dev_ctl->pvt_info = pvt; 150 dev_ctl->pvt_info = pvt;
@@ -145,28 +168,37 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
145 for (block = 0; block < nr_blocks; block++) { 168 for (block = 0; block < nr_blocks; block++) {
146 blk = &blk_p[block]; 169 blk = &blk_p[block];
147 blk->instance = inst; 170 blk->instance = inst;
148 blk->nr_attribs = nr_attribs;
149 attrib_p = &dev_attrib[block * nr_attribs];
150 blk->attribs = attrib_p;
151 snprintf(blk->name, sizeof(blk->name), 171 snprintf(blk->name, sizeof(blk->name),
152 "%s%d", edac_block_name, block+offset_value); 172 "%s%d", edac_block_name, block+offset_value);
153 173
154 debugf1("%s() instance=%d block=%d name=%s\n", 174 debugf1("%s() instance=%d block=%d name=%s\n",
155 __func__, instance, block, blk->name); 175 __func__, instance, block, blk->name);
156 176
157 if (attrib_spec != NULL) { 177 /* if there are NO attributes OR no attribute pointer
158 /* when there is an attrib_spec passed int then 178 * then continue on to next block iteration
159 * Initialize every attrib of each block 179 */
160 */ 180 if ((nr_attrib == 0) || (attrib_spec == NULL))
161 for (attr = 0; attr < nr_attribs; attr++) { 181 continue;
162 attrib = &attrib_p[attr]; 182
163 attrib->block = blk; 183 /* setup the attribute array for this block */
164 184 blk->nr_attribs = nr_attrib;
165 /* Link each attribute to the caller's 185 attrib_p = &dev_attrib[block*nr_instances*nr_attrib];
166 * spec entry, for name and type 186 blk->block_attributes = attrib_p;
167 */ 187
168 attrib->spec = &attrib_spec[attr]; 188 /* Initialize every user specified attribute in this
169 } 189 * block with the data the caller passed in
190 */
191 for (attr = 0; attr < nr_attrib; attr++) {
192 attrib = &attrib_p[attr];
193 attrib->attr = attrib_spec->attr;
194 attrib->show = attrib_spec->show;
195 attrib->store = attrib_spec->store;
196
197 /* up reference this block */
198 attrib->block = blk;
199
200 /* bump the attrib_spec */
201 attrib_spec++;
170 } 202 }
171 } 203 }
172 } 204 }
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
index 7a233e6e2b36..235b4c79355d 100644
--- a/drivers/edac/edac_device_sysfs.c
+++ b/drivers/edac/edac_device_sysfs.c
@@ -456,8 +456,10 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
456 struct edac_device_instance *instance, 456 struct edac_device_instance *instance,
457 int idx) 457 int idx)
458{ 458{
459 int i;
459 int err; 460 int err;
460 struct edac_device_block *block; 461 struct edac_device_block *block;
462 struct edac_dev_sysfs_block_attribute *sysfs_attrib;
461 463
462 block = &instance->blocks[idx]; 464 block = &instance->blocks[idx];
463 465
@@ -480,7 +482,27 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
480 return err; 482 return err;
481 } 483 }
482 484
485 /* If there are driver level block attributes, then added them
486 * to the block kobject
487 */
488 sysfs_attrib = block->block_attributes;
489 if (sysfs_attrib != NULL) {
490 for (i = 0; i < block->nr_attribs; i++) {
491 err = sysfs_create_file(&block->kobj,
492 (struct attribute *) &sysfs_attrib[i]);
493 if (err)
494 goto err_on_attrib;
495
496 sysfs_attrib++;
497 }
498 }
499
483 return 0; 500 return 0;
501
502err_on_attrib:
503 kobject_unregister(&block->kobj);
504
505 return err;
484} 506}
485 507
486/* 508/*