aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/edac_device.c
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/edac_device.c
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/edac_device.c')
-rw-r--r--drivers/edac/edac_device.c94
1 files changed, 63 insertions, 31 deletions
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index b53e8d51d9a..8264e3728c7 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 }