aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorDouglas Thompson <dougthompson@xmission.com>2007-07-19 04:50:25 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:56 -0400
commitfd309a9d8e63e9176759d00630b65d772ae06e0c (patch)
tree6862ba1ef11429b8ed51b005ad7db6ae4144e970 /drivers/edac
parent7d8536fb484360f35c0a9e3631641948bf168e2b (diff)
drivers/edac: fix leaf sysfs attribute
This patch fixes and enhances the driver level set of sysfs attributes that can be added to the 'block' level of an edac_device type of driver. There is a controller information structure, which contains one or more instances of device. Each instance will have one or more blocks of device specific counters. This patch fixes the ability to have more detailed attributes/controls for each of the 'blocks', providing for the addition of controls/attributes from the low level driver to user space via sysfs. Cc: Alan Cox alan@lxorguk.ukuu.org.uk Signed-off-by: Douglas Thompson <dougthompson@xmission.com> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
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/*