diff options
author | Douglas Thompson <dougthompson@xmission.com> | 2007-07-19 04:50:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 13:04:56 -0400 |
commit | fd309a9d8e63e9176759d00630b65d772ae06e0c (patch) | |
tree | 6862ba1ef11429b8ed51b005ad7db6ae4144e970 /drivers/edac/edac_device.c | |
parent | 7d8536fb484360f35c0a9e3631641948bf168e2b (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.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( | |||
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 | } |