diff options
author | Douglas Thompson <dougthompson@xmission.com> | 2007-07-19 01:50:25 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 10:04:56 -0700 |
commit | fd309a9d8e63e9176759d00630b65d772ae06e0c (patch) | |
tree | 6862ba1ef11429b8ed51b005ad7db6ae4144e970 /drivers/edac/edac_device.c | |
parent | 7d8536fb484360f35c0a9e3631641948bf168e2b (diff) | |
download | linux-fd309a9d8e63e9176759d00630b65d772ae06e0c.tar.gz linux-fd309a9d8e63e9176759d00630b65d772ae06e0c.tar.bz2 linux-fd309a9d8e63e9176759d00630b65d772ae06e0c.zip |
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/edac_device.c')
-rw-r--r-- | drivers/edac/edac_device.c | 94 |
1 files changed, 63 insertions, 31 deletions
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( char *edac_device_name, unsigned nr_instances, char *edac_block_name, unsigned nr_blocks, unsigned offset_value, /* zero, 1, or other based offset */ - struct edac_attrib_spec *attrib_spec, unsigned nr_attribs) + struct edac_dev_sysfs_block_attribute *attrib_spec, unsigned nr_attrib) { struct edac_device_ctl_info *dev_ctl; struct edac_device_instance *dev_inst, *inst; struct edac_device_block *dev_blk, *blk_p, *blk; - struct edac_attrib *dev_attrib, *attrib_p, *attrib; + struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib; unsigned total_size; unsigned count; unsigned instance, block, attr; @@ -81,29 +81,47 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info( debugf1("%s() instances=%d blocks=%d\n", __func__, nr_instances, nr_blocks); - /* Figure out the offsets of the various items from the start of an - * ctl_info structure. We want the alignment of each item + /* Calculate the size of memory we need to allocate AND + * determine the offsets of the various item arrays + * (instance,block,attrib) from the start of an allocated structure. + * We want the alignment of each item (instance,block,attrib) * to be at least as stringent as what the compiler would * provide if we could simply hardcode everything into a single struct. */ dev_ctl = (struct edac_device_ctl_info *)NULL; - /* Calc the 'end' offset past the ctl_info structure */ + /* Calc the 'end' offset past end of ONE ctl_info structure + * which will become the start of the 'instance' array + */ dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst)); - /* Calc the 'end' offset past the instance array */ + /* Calc the 'end' offset past the instance array within the ctl_info + * which will become the start of the block array + */ dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk)); - /* Calc the 'end' offset past the dev_blk array */ + /* Calc the 'end' offset past the dev_blk array + * which will become the start of the attrib array, if any. + */ count = nr_instances * nr_blocks; dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib)); - /* Check for case of NO attributes specified */ - if (nr_attribs > 0) - count *= nr_attribs; + /* Check for case of when an attribute array is specified */ + if (nr_attrib > 0) { + /* calc how many nr_attrib we need */ + count *= nr_attrib; - /* Calc the 'end' offset past the attributes array */ - pvt = edac_align_ptr(&dev_attrib[count], sz_private); + /* Calc the 'end' offset past the attributes array */ + pvt = edac_align_ptr(&dev_attrib[count], sz_private); + } else { + /* no attribute array specificed */ + pvt = edac_align_ptr(dev_attrib, sz_private); + } + + /* 'pvt' now points to where the private data area is. + * At this point 'pvt' (like dev_inst,dev_blk and dev_attrib) + * is baselined at ZERO + */ total_size = ((unsigned long)pvt) + sz_private; /* 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( if (dev_ctl == NULL) return NULL; - /* Adjust pointers so they point within the memory we just allocated - * rather than an imaginary chunk of memory located at address 0. + /* Adjust pointers so they point within the actual memory we + * just allocated rather than an imaginary chunk of memory + * located at address 0. + * 'dev_ctl' points to REAL memory, while the others are + * ZERO based and thus need to be adjusted to point within + * the allocated memory. */ dev_inst = (struct edac_device_instance *) (((char *)dev_ctl) + ((unsigned long)dev_inst)); dev_blk = (struct edac_device_block *) (((char *)dev_ctl) + ((unsigned long)dev_blk)); - dev_attrib = (struct edac_attrib *) + dev_attrib = (struct edac_dev_sysfs_block_attribute *) (((char *)dev_ctl) + ((unsigned long)dev_attrib)); pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL; + /* Begin storing the information into the control info structure */ dev_ctl->nr_instances = nr_instances; dev_ctl->instances = dev_inst; dev_ctl->pvt_info = pvt; @@ -145,28 +168,37 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info( for (block = 0; block < nr_blocks; block++) { blk = &blk_p[block]; blk->instance = inst; - blk->nr_attribs = nr_attribs; - attrib_p = &dev_attrib[block * nr_attribs]; - blk->attribs = attrib_p; snprintf(blk->name, sizeof(blk->name), "%s%d", edac_block_name, block+offset_value); debugf1("%s() instance=%d block=%d name=%s\n", __func__, instance, block, blk->name); - if (attrib_spec != NULL) { - /* when there is an attrib_spec passed int then - * Initialize every attrib of each block - */ - for (attr = 0; attr < nr_attribs; attr++) { - attrib = &attrib_p[attr]; - attrib->block = blk; - - /* Link each attribute to the caller's - * spec entry, for name and type - */ - attrib->spec = &attrib_spec[attr]; - } + /* if there are NO attributes OR no attribute pointer + * then continue on to next block iteration + */ + if ((nr_attrib == 0) || (attrib_spec == NULL)) + continue; + + /* setup the attribute array for this block */ + blk->nr_attribs = nr_attrib; + attrib_p = &dev_attrib[block*nr_instances*nr_attrib]; + blk->block_attributes = attrib_p; + + /* Initialize every user specified attribute in this + * block with the data the caller passed in + */ + for (attr = 0; attr < nr_attrib; attr++) { + attrib = &attrib_p[attr]; + attrib->attr = attrib_spec->attr; + attrib->show = attrib_spec->show; + attrib->store = attrib_spec->store; + + /* up reference this block */ + attrib->block = blk; + + /* bump the attrib_spec */ + attrib_spec++; } } } |