diff options
author | Douglas Thompson <dougthompson@xmission.com> | 2007-07-19 04:49:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 13:04:53 -0400 |
commit | e27e3dac651771fe3250f6305dee277bce29fc5d (patch) | |
tree | 9c0ac81a0948d8e52a72865ff9fbae4a12031a32 /drivers/edac/edac_mc_sysfs.c | |
parent | 7c9281d76c1c0b130f79d5fc021084e9749959d4 (diff) |
drivers/edac: add edac_device class
This patch adds the new 'class' of object to be managed, named: 'edac_device'.
As a peer of the 'edac_mc' class of object, it provides a non-memory centric
view of an ERROR DETECTING device in hardware. It provides a sysfs interface
and an abstraction for varioius EDAC type devices.
Multiple 'instances' within the class are possible, with each 'instance'
able to have multiple 'blocks', and each 'block' having 'attributes'.
At the 'block' level there are the 'ce_count' and 'ue_count' fields
which the device driver can update and/or call edac_device_handle_XX()
functions. At each higher level are additional 'total' count fields,
which are a summation of counts below that level.
This 'edac_device' has been used to capture and present ECC errors
which are found in a a L1 and L2 system on a per CORE/CPU basis.
Signed-off-by: Douglas Thompson <dougthompson@xmission.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_mc_sysfs.c')
-rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 70 |
1 files changed, 31 insertions, 39 deletions
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 4a5e335f61d3..35bcf926017f 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
@@ -94,14 +94,6 @@ static const char *edac_caps[] = { | |||
94 | [EDAC_S16ECD16ED] = "S16ECD16ED" | 94 | [EDAC_S16ECD16ED] = "S16ECD16ED" |
95 | }; | 95 | }; |
96 | 96 | ||
97 | /* | ||
98 | * sysfs object: /sys/devices/system/edac | ||
99 | * need to export to other files in this modules | ||
100 | */ | ||
101 | struct sysdev_class edac_class = { | ||
102 | set_kset_name("edac"), | ||
103 | }; | ||
104 | |||
105 | /* sysfs object: | 97 | /* sysfs object: |
106 | * /sys/devices/system/edac/mc | 98 | * /sys/devices/system/edac/mc |
107 | */ | 99 | */ |
@@ -224,43 +216,38 @@ static struct kobj_type ktype_memctrl = { | |||
224 | int edac_sysfs_memctrl_setup(void) | 216 | int edac_sysfs_memctrl_setup(void) |
225 | { | 217 | { |
226 | int err = 0; | 218 | int err = 0; |
219 | struct sysdev_class *edac_class; | ||
227 | 220 | ||
228 | debugf1("%s()\n", __func__); | 221 | debugf1("%s()\n", __func__); |
229 | 222 | ||
230 | /* create the /sys/devices/system/edac directory */ | 223 | /* get the /sys/devices/system/edac class reference */ |
231 | err = sysdev_class_register(&edac_class); | 224 | edac_class = edac_get_edac_class(); |
232 | 225 | if (edac_class == NULL) { | |
233 | if (err) { | 226 | debugf1("%s() no edac_class error=%d\n", __func__, err); |
234 | debugf1("%s() error=%d\n", __func__, err); | ||
235 | return err; | 227 | return err; |
236 | } | 228 | } |
237 | 229 | ||
238 | /* Init the MC's kobject */ | 230 | /* Init the MC's kobject */ |
239 | memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj)); | 231 | memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj)); |
240 | edac_memctrl_kobj.parent = &edac_class.kset.kobj; | 232 | edac_memctrl_kobj.parent = &edac_class->kset.kobj; |
241 | edac_memctrl_kobj.ktype = &ktype_memctrl; | 233 | edac_memctrl_kobj.ktype = &ktype_memctrl; |
242 | 234 | ||
243 | /* generate sysfs "..../edac/mc" */ | 235 | /* generate sysfs "..../edac/mc" */ |
244 | err = kobject_set_name(&edac_memctrl_kobj,"mc"); | 236 | err = kobject_set_name(&edac_memctrl_kobj,"mc"); |
245 | 237 | if (err) { | |
246 | if (err) | 238 | debugf1("%s() Failed to set name '.../edac/mc'\n", __func__ ); |
247 | goto fail; | 239 | return err; |
240 | } | ||
248 | 241 | ||
249 | /* FIXME: maybe new sysdev_create_subdir() */ | 242 | /* FIXME: maybe new sysdev_create_subdir() */ |
250 | err = kobject_register(&edac_memctrl_kobj); | 243 | err = kobject_register(&edac_memctrl_kobj); |
251 | |||
252 | if (err) { | 244 | if (err) { |
253 | debugf1("Failed to register '.../edac/mc'\n"); | 245 | debugf1("%s() Failed to register '.../edac/mc'\n", __func__ ); |
254 | goto fail; | 246 | return err; |
255 | } | 247 | } |
256 | 248 | ||
257 | debugf1("Registered '.../edac/mc' kobject\n"); | 249 | debugf1("%s() Registered '.../edac/mc' kobject\n",__func__); |
258 | |||
259 | return 0; | 250 | return 0; |
260 | |||
261 | fail: | ||
262 | sysdev_class_unregister(&edac_class); | ||
263 | return err; | ||
264 | } | 251 | } |
265 | 252 | ||
266 | /* | 253 | /* |
@@ -276,9 +263,6 @@ void edac_sysfs_memctrl_teardown(void) | |||
276 | init_completion(&edac_memctrl_kobj_complete); | 263 | init_completion(&edac_memctrl_kobj_complete); |
277 | kobject_unregister(&edac_memctrl_kobj); | 264 | kobject_unregister(&edac_memctrl_kobj); |
278 | wait_for_completion(&edac_memctrl_kobj_complete); | 265 | wait_for_completion(&edac_memctrl_kobj_complete); |
279 | |||
280 | /* Unregister the 'edac' object */ | ||
281 | sysdev_class_unregister(&edac_class); | ||
282 | } | 266 | } |
283 | 267 | ||
284 | 268 | ||
@@ -286,32 +270,38 @@ void edac_sysfs_memctrl_teardown(void) | |||
286 | */ | 270 | */ |
287 | 271 | ||
288 | /* Set of more default csrow<id> attribute show/store functions */ | 272 | /* Set of more default csrow<id> attribute show/store functions */ |
289 | static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, int private) | 273 | static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, |
274 | int private) | ||
290 | { | 275 | { |
291 | return sprintf(data,"%u\n", csrow->ue_count); | 276 | return sprintf(data,"%u\n", csrow->ue_count); |
292 | } | 277 | } |
293 | 278 | ||
294 | static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, int private) | 279 | static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, |
280 | int private) | ||
295 | { | 281 | { |
296 | return sprintf(data,"%u\n", csrow->ce_count); | 282 | return sprintf(data,"%u\n", csrow->ce_count); |
297 | } | 283 | } |
298 | 284 | ||
299 | static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private) | 285 | static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, |
286 | int private) | ||
300 | { | 287 | { |
301 | return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages)); | 288 | return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages)); |
302 | } | 289 | } |
303 | 290 | ||
304 | static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private) | 291 | static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, |
292 | int private) | ||
305 | { | 293 | { |
306 | return sprintf(data,"%s\n", mem_types[csrow->mtype]); | 294 | return sprintf(data,"%s\n", mem_types[csrow->mtype]); |
307 | } | 295 | } |
308 | 296 | ||
309 | static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private) | 297 | static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, |
298 | int private) | ||
310 | { | 299 | { |
311 | return sprintf(data,"%s\n", dev_types[csrow->dtype]); | 300 | return sprintf(data,"%s\n", dev_types[csrow->dtype]); |
312 | } | 301 | } |
313 | 302 | ||
314 | static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private) | 303 | static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, |
304 | int private) | ||
315 | { | 305 | { |
316 | return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]); | 306 | return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]); |
317 | } | 307 | } |
@@ -509,9 +499,10 @@ static int edac_create_channel_files(struct kobject *kobj, int chan) | |||
509 | if (!err) { | 499 | if (!err) { |
510 | /* create the CE Count attribute file */ | 500 | /* create the CE Count attribute file */ |
511 | err = sysfs_create_file(kobj, | 501 | err = sysfs_create_file(kobj, |
512 | (struct attribute *) dynamic_csrow_ce_count_attr[chan]); | 502 | (struct attribute *)dynamic_csrow_ce_count_attr[chan]); |
513 | } else { | 503 | } else { |
514 | debugf1("%s() dimm labels and ce_count files created", __func__); | 504 | debugf1("%s() dimm labels and ce_count files created", |
505 | __func__); | ||
515 | } | 506 | } |
516 | 507 | ||
517 | return err; | 508 | return err; |
@@ -643,7 +634,7 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data) | |||
643 | } else { | 634 | } else { |
644 | /* FIXME: produce "not implemented" ERROR for user-side. */ | 635 | /* FIXME: produce "not implemented" ERROR for user-side. */ |
645 | edac_printk(KERN_WARNING, EDAC_MC, | 636 | edac_printk(KERN_WARNING, EDAC_MC, |
646 | "Memory scrubbing 'get' control is not implemented!\n"); | 637 | "Memory scrubbing 'get' control is not implemented\n"); |
647 | } | 638 | } |
648 | return sprintf(data, "%d\n", bandwidth); | 639 | return sprintf(data, "%d\n", bandwidth); |
649 | } | 640 | } |
@@ -755,7 +746,8 @@ MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL); | |||
755 | MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL); | 746 | MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL); |
756 | 747 | ||
757 | /* memory scrubber attribute file */ | 748 | /* memory scrubber attribute file */ |
758 | MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store); | 749 | MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,\ |
750 | mci_sdram_scrub_rate_store); | ||
759 | 751 | ||
760 | static struct mcidev_attribute *mci_attr[] = { | 752 | static struct mcidev_attribute *mci_attr[] = { |
761 | &mci_attr_reset_counters, | 753 | &mci_attr_reset_counters, |