aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorDoug Thompson <norsk5@xmission.com>2006-07-10 07:45:19 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-10 16:24:25 -0400
commit49c0dab7e6000888b616bedcbbc8cd4710331610 (patch)
tree41f1d5e4b1978843b240f3812d3039e9ef9a17b1 /drivers/edac
parent68e3c5e3b5c29ea76152dc1d1482826434d45019 (diff)
[PATCH] Fix and enable EDAC sysfs operation
When EDAC was first introduced into the kernel it had a sysfs interface, but due to some problems it was disabled in 2.6.16 and remained disabled in 2.6.17. With feedback, several of the control and attribute files of that interface had some good constructive feedback. PCI Blacklist/Whitelist was a major set which has design issues and it has been removed in this patch. Instead of storing PCI broken parity status in EDAC, it has been moved to the pci_dev structure itself by a previous PCI patch. A future patch will enable that feature in EDAC by utilizing the pci_dev info. The sysfs is now enabled in this patch, with a minimal set of control and attribute files for examining EDAC state and for enabling/disabling the memory and PCI operations. The Documentation for EDAC has also been updated to reflect the new state of EDAC operation. Signed-off-by:Doug Thompson <norsk5@xmisson.com> Cc: Greg KH <greg@kroah.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/edac_mc.c687
1 files changed, 194 insertions, 493 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 3a7cfe88b169..4bde30bb3be7 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * edac_mc kernel module 2 * edac_mc kernel module
3 * (C) 2005 Linux Networx (http://lnxi.com) 3 * (C) 2005, 2006 Linux Networx (http://lnxi.com)
4 * This file may be distributed under the terms of the 4 * This file may be distributed under the terms of the
5 * GNU General Public License. 5 * GNU General Public License.
6 * 6 *
@@ -33,13 +33,8 @@
33#include <asm/edac.h> 33#include <asm/edac.h>
34#include "edac_mc.h" 34#include "edac_mc.h"
35 35
36#define EDAC_MC_VERSION "Ver: 2.0.0 " __DATE__ 36#define EDAC_MC_VERSION "Ver: 2.0.1 " __DATE__
37 37
38/* For now, disable the EDAC sysfs code. The sysfs interface that EDAC
39 * presents to user space needs more thought, and is likely to change
40 * substantially.
41 */
42#define DISABLE_EDAC_SYSFS
43 38
44#ifdef CONFIG_EDAC_DEBUG 39#ifdef CONFIG_EDAC_DEBUG
45/* Values of 0 to 4 will generate output */ 40/* Values of 0 to 4 will generate output */
@@ -64,31 +59,12 @@ static int check_pci_parity = 0; /* default YES check PCI parity */
64static int panic_on_pci_parity; /* default no panic on PCI Parity */ 59static int panic_on_pci_parity; /* default no panic on PCI Parity */
65static atomic_t pci_parity_count = ATOMIC_INIT(0); 60static atomic_t pci_parity_count = ATOMIC_INIT(0);
66 61
67/* Structure of the whitelist and blacklist arrays */
68struct edac_pci_device_list {
69 unsigned int vendor; /* Vendor ID */
70 unsigned int device; /* Deviice ID */
71};
72
73#define MAX_LISTED_PCI_DEVICES 32
74
75/* List of PCI devices (vendor-id:device-id) that should be skipped */
76static struct edac_pci_device_list pci_blacklist[MAX_LISTED_PCI_DEVICES];
77static int pci_blacklist_count;
78
79/* List of PCI devices (vendor-id:device-id) that should be scanned */
80static struct edac_pci_device_list pci_whitelist[MAX_LISTED_PCI_DEVICES];
81static int pci_whitelist_count ;
82
83#ifndef DISABLE_EDAC_SYSFS
84static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */ 62static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */
85static struct completion edac_pci_kobj_complete; 63static struct completion edac_pci_kobj_complete;
86#endif /* DISABLE_EDAC_SYSFS */
87#endif /* CONFIG_PCI */ 64#endif /* CONFIG_PCI */
88 65
89/* START sysfs data and methods */ 66/* START sysfs data and methods */
90 67
91#ifndef DISABLE_EDAC_SYSFS
92 68
93static const char *mem_types[] = { 69static const char *mem_types[] = {
94 [MEM_EMPTY] = "Empty", 70 [MEM_EMPTY] = "Empty",
@@ -147,18 +123,10 @@ static struct completion edac_memctrl_kobj_complete;
147 * /sys/devices/system/edac/mc; 123 * /sys/devices/system/edac/mc;
148 * data structures and methods 124 * data structures and methods
149 */ 125 */
150#if 0
151static ssize_t memctrl_string_show(void *ptr, char *buffer)
152{
153 char *value = (char*) ptr;
154 return sprintf(buffer, "%s\n", value);
155}
156#endif
157
158static ssize_t memctrl_int_show(void *ptr, char *buffer) 126static ssize_t memctrl_int_show(void *ptr, char *buffer)
159{ 127{
160 int *value = (int*) ptr; 128 int *value = (int*) ptr;
161 return sprintf(buffer, "%d\n", *value); 129 return sprintf(buffer, "%u\n", *value);
162} 130}
163 131
164static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count) 132static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
@@ -224,11 +192,6 @@ struct memctrl_dev_attribute attr_##_name = { \
224 .store = _store, \ 192 .store = _store, \
225}; 193};
226 194
227/* cwrow<id> attribute f*/
228#if 0
229MEMCTRL_STRING_ATTR(mc_version,EDAC_MC_VERSION,S_IRUGO,memctrl_string_show,NULL);
230#endif
231
232/* csrow<id> control files */ 195/* csrow<id> control files */
233MEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); 196MEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
234MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); 197MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
@@ -257,8 +220,6 @@ static struct kobj_type ktype_memctrl = {
257 .default_attrs = (struct attribute **) memctrl_attr, 220 .default_attrs = (struct attribute **) memctrl_attr,
258}; 221};
259 222
260#endif /* DISABLE_EDAC_SYSFS */
261
262/* Initialize the main sysfs entries for edac: 223/* Initialize the main sysfs entries for edac:
263 * /sys/devices/system/edac 224 * /sys/devices/system/edac
264 * 225 *
@@ -268,11 +229,6 @@ static struct kobj_type ktype_memctrl = {
268 * !0 FAILURE 229 * !0 FAILURE
269 */ 230 */
270static int edac_sysfs_memctrl_setup(void) 231static int edac_sysfs_memctrl_setup(void)
271#ifdef DISABLE_EDAC_SYSFS
272{
273 return 0;
274}
275#else
276{ 232{
277 int err=0; 233 int err=0;
278 234
@@ -304,7 +260,6 @@ static int edac_sysfs_memctrl_setup(void)
304 260
305 return err; 261 return err;
306} 262}
307#endif /* DISABLE_EDAC_SYSFS */
308 263
309/* 264/*
310 * MC teardown: 265 * MC teardown:
@@ -312,7 +267,6 @@ static int edac_sysfs_memctrl_setup(void)
312 */ 267 */
313static void edac_sysfs_memctrl_teardown(void) 268static void edac_sysfs_memctrl_teardown(void)
314{ 269{
315#ifndef DISABLE_EDAC_SYSFS
316 debugf0("MC: " __FILE__ ": %s()\n", __func__); 270 debugf0("MC: " __FILE__ ": %s()\n", __func__);
317 271
318 /* Unregister the MC's kobject and wait for reference count to reach 272 /* Unregister the MC's kobject and wait for reference count to reach
@@ -324,144 +278,9 @@ static void edac_sysfs_memctrl_teardown(void)
324 278
325 /* Unregister the 'edac' object */ 279 /* Unregister the 'edac' object */
326 sysdev_class_unregister(&edac_class); 280 sysdev_class_unregister(&edac_class);
327#endif /* DISABLE_EDAC_SYSFS */
328} 281}
329 282
330#ifdef CONFIG_PCI 283#ifdef CONFIG_PCI
331
332#ifndef DISABLE_EDAC_SYSFS
333
334/*
335 * /sys/devices/system/edac/pci;
336 * data structures and methods
337 */
338
339struct list_control {
340 struct edac_pci_device_list *list;
341 int *count;
342};
343
344#if 0
345/* Output the list as: vendor_id:device:id<,vendor_id:device_id> */
346static ssize_t edac_pci_list_string_show(void *ptr, char *buffer)
347{
348 struct list_control *listctl;
349 struct edac_pci_device_list *list;
350 char *p = buffer;
351 int len=0;
352 int i;
353
354 listctl = ptr;
355 list = listctl->list;
356
357 for (i = 0; i < *(listctl->count); i++, list++ ) {
358 if (len > 0)
359 len += snprintf(p + len, (PAGE_SIZE-len), ",");
360
361 len += snprintf(p + len,
362 (PAGE_SIZE-len),
363 "%x:%x",
364 list->vendor,list->device);
365 }
366
367 len += snprintf(p + len,(PAGE_SIZE-len), "\n");
368 return (ssize_t) len;
369}
370
371/**
372 *
373 * Scan string from **s to **e looking for one 'vendor:device' tuple
374 * where each field is a hex value
375 *
376 * return 0 if an entry is NOT found
377 * return 1 if an entry is found
378 * fill in *vendor_id and *device_id with values found
379 *
380 * In both cases, make sure *s has been moved forward toward *e
381 */
382static int parse_one_device(const char **s,const char **e,
383 unsigned int *vendor_id, unsigned int *device_id)
384{
385 const char *runner, *p;
386
387 /* if null byte, we are done */
388 if (!**s) {
389 (*s)++; /* keep *s moving */
390 return 0;
391 }
392
393 /* skip over newlines & whitespace */
394 if ((**s == '\n') || isspace(**s)) {
395 (*s)++;
396 return 0;
397 }
398
399 if (!isxdigit(**s)) {
400 (*s)++;
401 return 0;
402 }
403
404 /* parse vendor_id */
405 runner = *s;
406
407 while (runner < *e) {
408 /* scan for vendor:device delimiter */
409 if (*runner == ':') {
410 *vendor_id = simple_strtol((char*) *s, (char**) &p, 16);
411 runner = p + 1;
412 break;
413 }
414
415 runner++;
416 }
417
418 if (!isxdigit(*runner)) {
419 *s = ++runner;
420 return 0;
421 }
422
423 /* parse device_id */
424 if (runner < *e) {
425 *device_id = simple_strtol((char*)runner, (char**)&p, 16);
426 runner = p;
427 }
428
429 *s = runner;
430 return 1;
431}
432
433static ssize_t edac_pci_list_string_store(void *ptr, const char *buffer,
434 size_t count)
435{
436 struct list_control *listctl;
437 struct edac_pci_device_list *list;
438 unsigned int vendor_id, device_id;
439 const char *s, *e;
440 int *index;
441
442 s = (char*)buffer;
443 e = s + count;
444 listctl = ptr;
445 list = listctl->list;
446 index = listctl->count;
447 *index = 0;
448
449 while (*index < MAX_LISTED_PCI_DEVICES) {
450 if (parse_one_device(&s,&e,&vendor_id,&device_id)) {
451 list[ *index ].vendor = vendor_id;
452 list[ *index ].device = device_id;
453 (*index)++;
454 }
455
456 /* check for all data consume */
457 if (s >= e)
458 break;
459 }
460
461 return count;
462}
463
464#endif
465static ssize_t edac_pci_int_show(void *ptr, char *buffer) 284static ssize_t edac_pci_int_show(void *ptr, char *buffer)
466{ 285{
467 int *value = ptr; 286 int *value = ptr;
@@ -529,31 +348,6 @@ struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
529 .store = _store, \ 348 .store = _store, \
530}; 349};
531 350
532#if 0
533static struct list_control pci_whitelist_control = {
534 .list = pci_whitelist,
535 .count = &pci_whitelist_count
536};
537
538static struct list_control pci_blacklist_control = {
539 .list = pci_blacklist,
540 .count = &pci_blacklist_count
541};
542
543/* whitelist attribute */
544EDAC_PCI_STRING_ATTR(pci_parity_whitelist,
545 &pci_whitelist_control,
546 S_IRUGO|S_IWUSR,
547 edac_pci_list_string_show,
548 edac_pci_list_string_store);
549
550EDAC_PCI_STRING_ATTR(pci_parity_blacklist,
551 &pci_blacklist_control,
552 S_IRUGO|S_IWUSR,
553 edac_pci_list_string_show,
554 edac_pci_list_string_store);
555#endif
556
557/* PCI Parity control files */ 351/* PCI Parity control files */
558EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, 352EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
559 edac_pci_int_store); 353 edac_pci_int_store);
@@ -582,18 +376,11 @@ static struct kobj_type ktype_edac_pci = {
582 .default_attrs = (struct attribute **) edac_pci_attr, 376 .default_attrs = (struct attribute **) edac_pci_attr,
583}; 377};
584 378
585#endif /* DISABLE_EDAC_SYSFS */
586
587/** 379/**
588 * edac_sysfs_pci_setup() 380 * edac_sysfs_pci_setup()
589 * 381 *
590 */ 382 */
591static int edac_sysfs_pci_setup(void) 383static int edac_sysfs_pci_setup(void)
592#ifdef DISABLE_EDAC_SYSFS
593{
594 return 0;
595}
596#else
597{ 384{
598 int err; 385 int err;
599 386
@@ -617,16 +404,13 @@ static int edac_sysfs_pci_setup(void)
617 404
618 return err; 405 return err;
619} 406}
620#endif /* DISABLE_EDAC_SYSFS */
621 407
622static void edac_sysfs_pci_teardown(void) 408static void edac_sysfs_pci_teardown(void)
623{ 409{
624#ifndef DISABLE_EDAC_SYSFS
625 debugf0("%s()\n", __func__); 410 debugf0("%s()\n", __func__);
626 init_completion(&edac_pci_kobj_complete); 411 init_completion(&edac_pci_kobj_complete);
627 kobject_unregister(&edac_pci_kobj); 412 kobject_unregister(&edac_pci_kobj);
628 wait_for_completion(&edac_pci_kobj_complete); 413 wait_for_completion(&edac_pci_kobj_complete);
629#endif
630} 414}
631 415
632 416
@@ -756,36 +540,6 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev)
756} 540}
757 541
758/* 542/*
759 * check_dev_on_list: Scan for a PCI device on a white/black list
760 * @list: an EDAC &edac_pci_device_list white/black list pointer
761 * @free_index: index of next free entry on the list
762 * @pci_dev: PCI Device pointer
763 *
764 * see if list contains the device.
765 *
766 * Returns: 0 not found
767 * 1 found on list
768 */
769static int check_dev_on_list(struct edac_pci_device_list *list,
770 int free_index, struct pci_dev *dev)
771{
772 int i;
773 int rc = 0; /* Assume not found */
774 unsigned short vendor=dev->vendor;
775 unsigned short device=dev->device;
776
777 /* Scan the list, looking for a vendor/device match */
778 for (i = 0; i < free_index; i++, list++ ) {
779 if ((list->vendor == vendor ) && (list->device == device )) {
780 rc = 1;
781 break;
782 }
783 }
784
785 return rc;
786}
787
788/*
789 * pci_dev parity list iterator 543 * pci_dev parity list iterator
790 * Scan the PCI device list for one iteration, looking for SERRORs 544 * Scan the PCI device list for one iteration, looking for SERRORs
791 * Master Parity ERRORS or Parity ERRORs on primary or secondary devices 545 * Master Parity ERRORS or Parity ERRORs on primary or secondary devices
@@ -799,22 +553,7 @@ static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
799 * bumped until we are done with it 553 * bumped until we are done with it
800 */ 554 */
801 while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { 555 while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
802 /* if whitelist exists then it has priority, so only scan 556 fn(dev);
803 * those devices on the whitelist
804 */
805 if (pci_whitelist_count > 0 ) {
806 if (check_dev_on_list(pci_whitelist,
807 pci_whitelist_count, dev))
808 fn(dev);
809 } else {
810 /*
811 * if no whitelist, then check if this devices is
812 * blacklisted
813 */
814 if (!check_dev_on_list(pci_blacklist,
815 pci_blacklist_count, dev))
816 fn(dev);
817 }
818 } 557 }
819} 558}
820 559
@@ -855,154 +594,101 @@ static inline void clear_pci_parity_errors(void)
855 594
856#else /* CONFIG_PCI */ 595#else /* CONFIG_PCI */
857 596
858static inline void do_pci_parity_check(void) 597/* pre-process these away */
859{ 598#define do_pci_parity_check()
860 /* no-op */ 599#define clear_pci_parity_errors()
861} 600#define edac_sysfs_pci_teardown()
862 601#define edac_sysfs_pci_setup() (0)
863static inline void clear_pci_parity_errors(void)
864{
865 /* no-op */
866}
867
868static void edac_sysfs_pci_teardown(void)
869{
870}
871 602
872static int edac_sysfs_pci_setup(void)
873{
874 return 0;
875}
876#endif /* CONFIG_PCI */ 603#endif /* CONFIG_PCI */
877 604
878#ifndef DISABLE_EDAC_SYSFS 605/* EDAC sysfs CSROW data structures and methods
879 606 */
880/* EDAC sysfs CSROW data structures and methods */
881
882/* Set of more detailed csrow<id> attribute show/store functions */
883static ssize_t csrow_ch0_dimm_label_show(struct csrow_info *csrow, char *data)
884{
885 ssize_t size = 0;
886
887 if (csrow->nr_channels > 0) {
888 size = snprintf(data, EDAC_MC_LABEL_LEN,"%s\n",
889 csrow->channels[0].label);
890 }
891
892 return size;
893}
894 607
895static ssize_t csrow_ch1_dimm_label_show(struct csrow_info *csrow, char *data) 608/* Set of more default csrow<id> attribute show/store functions */
609static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, int private)
896{ 610{
897 ssize_t size = 0; 611 return sprintf(data,"%u\n", csrow->ue_count);
898
899 if (csrow->nr_channels > 0) {
900 size = snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
901 csrow->channels[1].label);
902 }
903
904 return size;
905} 612}
906 613
907static ssize_t csrow_ch0_dimm_label_store(struct csrow_info *csrow, 614static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, int private)
908 const char *data, size_t size)
909{ 615{
910 ssize_t max_size = 0; 616 return sprintf(data,"%u\n", csrow->ce_count);
911
912 if (csrow->nr_channels > 0) {
913 max_size = min((ssize_t)size,(ssize_t)EDAC_MC_LABEL_LEN-1);
914 strncpy(csrow->channels[0].label, data, max_size);
915 csrow->channels[0].label[max_size] = '\0';
916 }
917
918 return size;
919} 617}
920 618
921static ssize_t csrow_ch1_dimm_label_store(struct csrow_info *csrow, 619static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private)
922 const char *data, size_t size)
923{ 620{
924 ssize_t max_size = 0; 621 return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages));
925
926 if (csrow->nr_channels > 1) {
927 max_size = min((ssize_t)size,(ssize_t)EDAC_MC_LABEL_LEN-1);
928 strncpy(csrow->channels[1].label, data, max_size);
929 csrow->channels[1].label[max_size] = '\0';
930 }
931
932 return max_size;
933} 622}
934 623
935static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data) 624static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private)
936{ 625{
937 return sprintf(data,"%u\n", csrow->ue_count); 626 return sprintf(data,"%s\n", mem_types[csrow->mtype]);
938} 627}
939 628
940static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data) 629static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private)
941{ 630{
942 return sprintf(data,"%u\n", csrow->ce_count); 631 return sprintf(data,"%s\n", dev_types[csrow->dtype]);
943} 632}
944 633
945static ssize_t csrow_ch0_ce_count_show(struct csrow_info *csrow, char *data) 634static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private)
946{ 635{
947 ssize_t size = 0; 636 return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]);
948
949 if (csrow->nr_channels > 0) {
950 size = sprintf(data,"%u\n", csrow->channels[0].ce_count);
951 }
952
953 return size;
954} 637}
955 638
956static ssize_t csrow_ch1_ce_count_show(struct csrow_info *csrow, char *data) 639/* show/store functions for DIMM Label attributes */
640static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
641 char *data, int channel)
957{ 642{
958 ssize_t size = 0; 643 return snprintf(data, EDAC_MC_LABEL_LEN,"%s",
959 644 csrow->channels[channel].label);
960 if (csrow->nr_channels > 1) {
961 size = sprintf(data,"%u\n", csrow->channels[1].ce_count);
962 }
963
964 return size;
965} 645}
966 646
967static ssize_t csrow_size_show(struct csrow_info *csrow, char *data) 647static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
648 const char *data,
649 size_t count,
650 int channel)
968{ 651{
969 return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages)); 652 ssize_t max_size = 0;
970}
971 653
972static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data) 654 max_size = min((ssize_t)count,(ssize_t)EDAC_MC_LABEL_LEN-1);
973{ 655 strncpy(csrow->channels[channel].label, data, max_size);
974 return sprintf(data,"%s\n", mem_types[csrow->mtype]); 656 csrow->channels[channel].label[max_size] = '\0';
975}
976 657
977static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data) 658 return max_size;
978{
979 return sprintf(data,"%s\n", dev_types[csrow->dtype]);
980} 659}
981 660
982static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data) 661/* show function for dynamic chX_ce_count attribute */
662static ssize_t channel_ce_count_show(struct csrow_info *csrow,
663 char *data,
664 int channel)
983{ 665{
984 return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]); 666 return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
985} 667}
986 668
669/* csrow specific attribute structure */
987struct csrowdev_attribute { 670struct csrowdev_attribute {
988 struct attribute attr; 671 struct attribute attr;
989 ssize_t (*show)(struct csrow_info *,char *); 672 ssize_t (*show)(struct csrow_info *,char *,int);
990 ssize_t (*store)(struct csrow_info *, const char *,size_t); 673 ssize_t (*store)(struct csrow_info *, const char *,size_t,int);
674 int private;
991}; 675};
992 676
993#define to_csrow(k) container_of(k, struct csrow_info, kobj) 677#define to_csrow(k) container_of(k, struct csrow_info, kobj)
994#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr) 678#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
995 679
996/* Set of show/store higher level functions for csrow objects */ 680/* Set of show/store higher level functions for default csrow attributes */
997static ssize_t csrowdev_show(struct kobject *kobj, struct attribute *attr, 681static ssize_t csrowdev_show(struct kobject *kobj,
998 char *buffer) 682 struct attribute *attr,
683 char *buffer)
999{ 684{
1000 struct csrow_info *csrow = to_csrow(kobj); 685 struct csrow_info *csrow = to_csrow(kobj);
1001 struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr); 686 struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
1002 687
1003 if (csrowdev_attr->show) 688 if (csrowdev_attr->show)
1004 return csrowdev_attr->show(csrow, buffer); 689 return csrowdev_attr->show(csrow,
1005 690 buffer,
691 csrowdev_attr->private);
1006 return -EIO; 692 return -EIO;
1007} 693}
1008 694
@@ -1013,8 +699,10 @@ static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
1013 struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr); 699 struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr);
1014 700
1015 if (csrowdev_attr->store) 701 if (csrowdev_attr->store)
1016 return csrowdev_attr->store(csrow, buffer, count); 702 return csrowdev_attr->store(csrow,
1017 703 buffer,
704 count,
705 csrowdev_attr->private);
1018 return -EIO; 706 return -EIO;
1019} 707}
1020 708
@@ -1023,69 +711,157 @@ static struct sysfs_ops csrowfs_ops = {
1023 .store = csrowdev_store 711 .store = csrowdev_store
1024}; 712};
1025 713
1026#define CSROWDEV_ATTR(_name,_mode,_show,_store) \ 714#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \
1027struct csrowdev_attribute attr_##_name = { \ 715struct csrowdev_attribute attr_##_name = { \
1028 .attr = {.name = __stringify(_name), .mode = _mode }, \ 716 .attr = {.name = __stringify(_name), .mode = _mode }, \
1029 .show = _show, \ 717 .show = _show, \
1030 .store = _store, \ 718 .store = _store, \
719 .private = _private, \
1031}; 720};
1032 721
1033/* cwrow<id>/attribute files */ 722/* default cwrow<id>/attribute files */
1034CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL); 723CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL,0);
1035CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL); 724CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL,0);
1036CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL); 725CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL,0);
1037CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL); 726CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL,0);
1038CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL); 727CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL,0);
1039CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL); 728CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL,0);
1040CSROWDEV_ATTR(ch0_ce_count,S_IRUGO,csrow_ch0_ce_count_show,NULL);
1041CSROWDEV_ATTR(ch1_ce_count,S_IRUGO,csrow_ch1_ce_count_show,NULL);
1042
1043/* control/attribute files */
1044CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR,
1045 csrow_ch0_dimm_label_show,
1046 csrow_ch0_dimm_label_store);
1047CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR,
1048 csrow_ch1_dimm_label_show,
1049 csrow_ch1_dimm_label_store);
1050 729
1051/* Attributes of the CSROW<id> object */ 730/* default attributes of the CSROW<id> object */
1052static struct csrowdev_attribute *csrow_attr[] = { 731static struct csrowdev_attribute *default_csrow_attr[] = {
1053 &attr_dev_type, 732 &attr_dev_type,
1054 &attr_mem_type, 733 &attr_mem_type,
1055 &attr_edac_mode, 734 &attr_edac_mode,
1056 &attr_size_mb, 735 &attr_size_mb,
1057 &attr_ue_count, 736 &attr_ue_count,
1058 &attr_ce_count, 737 &attr_ce_count,
1059 &attr_ch0_ce_count,
1060 &attr_ch1_ce_count,
1061 &attr_ch0_dimm_label,
1062 &attr_ch1_dimm_label,
1063 NULL, 738 NULL,
1064}; 739};
1065 740
1066/* No memory to release */ 741
742/* possible dynamic channel DIMM Label attribute files */
743CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR,
744 channel_dimm_label_show,
745 channel_dimm_label_store,
746 0 );
747CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR,
748 channel_dimm_label_show,
749 channel_dimm_label_store,
750 1 );
751CSROWDEV_ATTR(ch2_dimm_label,S_IRUGO|S_IWUSR,
752 channel_dimm_label_show,
753 channel_dimm_label_store,
754 2 );
755CSROWDEV_ATTR(ch3_dimm_label,S_IRUGO|S_IWUSR,
756 channel_dimm_label_show,
757 channel_dimm_label_store,
758 3 );
759CSROWDEV_ATTR(ch4_dimm_label,S_IRUGO|S_IWUSR,
760 channel_dimm_label_show,
761 channel_dimm_label_store,
762 4 );
763CSROWDEV_ATTR(ch5_dimm_label,S_IRUGO|S_IWUSR,
764 channel_dimm_label_show,
765 channel_dimm_label_store,
766 5 );
767
768/* Total possible dynamic DIMM Label attribute file table */
769static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
770 &attr_ch0_dimm_label,
771 &attr_ch1_dimm_label,
772 &attr_ch2_dimm_label,
773 &attr_ch3_dimm_label,
774 &attr_ch4_dimm_label,
775 &attr_ch5_dimm_label
776};
777
778/* possible dynamic channel ce_count attribute files */
779CSROWDEV_ATTR(ch0_ce_count,S_IRUGO|S_IWUSR,
780 channel_ce_count_show,
781 NULL,
782 0 );
783CSROWDEV_ATTR(ch1_ce_count,S_IRUGO|S_IWUSR,
784 channel_ce_count_show,
785 NULL,
786 1 );
787CSROWDEV_ATTR(ch2_ce_count,S_IRUGO|S_IWUSR,
788 channel_ce_count_show,
789 NULL,
790 2 );
791CSROWDEV_ATTR(ch3_ce_count,S_IRUGO|S_IWUSR,
792 channel_ce_count_show,
793 NULL,
794 3 );
795CSROWDEV_ATTR(ch4_ce_count,S_IRUGO|S_IWUSR,
796 channel_ce_count_show,
797 NULL,
798 4 );
799CSROWDEV_ATTR(ch5_ce_count,S_IRUGO|S_IWUSR,
800 channel_ce_count_show,
801 NULL,
802 5 );
803
804/* Total possible dynamic ce_count attribute file table */
805static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
806 &attr_ch0_ce_count,
807 &attr_ch1_ce_count,
808 &attr_ch2_ce_count,
809 &attr_ch3_ce_count,
810 &attr_ch4_ce_count,
811 &attr_ch5_ce_count
812};
813
814
815#define EDAC_NR_CHANNELS 6
816
817/* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */
818static int edac_create_channel_files(struct kobject *kobj, int chan)
819{
820 int err=-ENODEV;
821
822 if (chan >= EDAC_NR_CHANNELS)
823 return err;
824
825 /* create the DIMM label attribute file */
826 err = sysfs_create_file(kobj,
827 (struct attribute *) dynamic_csrow_dimm_attr[chan]);
828
829 if (!err) {
830 /* create the CE Count attribute file */
831 err = sysfs_create_file(kobj,
832 (struct attribute *) dynamic_csrow_ce_count_attr[chan]);
833 } else {
834 debugf1("%s() dimm labels and ce_count files created", __func__);
835 }
836
837 return err;
838}
839
840/* No memory to release for this kobj */
1067static void edac_csrow_instance_release(struct kobject *kobj) 841static void edac_csrow_instance_release(struct kobject *kobj)
1068{ 842{
1069 struct csrow_info *cs; 843 struct csrow_info *cs;
1070 844
1071 debugf1("%s()\n", __func__);
1072 cs = container_of(kobj, struct csrow_info, kobj); 845 cs = container_of(kobj, struct csrow_info, kobj);
1073 complete(&cs->kobj_complete); 846 complete(&cs->kobj_complete);
1074} 847}
1075 848
849/* the kobj_type instance for a CSROW */
1076static struct kobj_type ktype_csrow = { 850static struct kobj_type ktype_csrow = {
1077 .release = edac_csrow_instance_release, 851 .release = edac_csrow_instance_release,
1078 .sysfs_ops = &csrowfs_ops, 852 .sysfs_ops = &csrowfs_ops,
1079 .default_attrs = (struct attribute **) csrow_attr, 853 .default_attrs = (struct attribute **) default_csrow_attr,
1080}; 854};
1081 855
1082/* Create a CSROW object under specifed edac_mc_device */ 856/* Create a CSROW object under specifed edac_mc_device */
1083static int edac_create_csrow_object(struct kobject *edac_mci_kobj, 857static int edac_create_csrow_object(
1084 struct csrow_info *csrow, int index) 858 struct kobject *edac_mci_kobj,
859 struct csrow_info *csrow,
860 int index)
1085{ 861{
1086 int err = 0; 862 int err = 0;
863 int chan;
1087 864
1088 debugf0("%s()\n", __func__);
1089 memset(&csrow->kobj, 0, sizeof(csrow->kobj)); 865 memset(&csrow->kobj, 0, sizeof(csrow->kobj));
1090 866
1091 /* generate ..../edac/mc/mc<id>/csrow<index> */ 867 /* generate ..../edac/mc/mc<id>/csrow<index> */
@@ -1095,21 +871,27 @@ static int edac_create_csrow_object(struct kobject *edac_mci_kobj,
1095 871
1096 /* name this instance of csrow<id> */ 872 /* name this instance of csrow<id> */
1097 err = kobject_set_name(&csrow->kobj,"csrow%d",index); 873 err = kobject_set_name(&csrow->kobj,"csrow%d",index);
874 if (err)
875 goto error_exit;
1098 876
877 /* Instanstiate the csrow object */
878 err = kobject_register(&csrow->kobj);
1099 if (!err) { 879 if (!err) {
1100 /* Instanstiate the csrow object */ 880 /* Create the dyanmic attribute files on this csrow,
1101 err = kobject_register(&csrow->kobj); 881 * namely, the DIMM labels and the channel ce_count
1102 882 */
1103 if (err) 883 for (chan = 0; chan < csrow->nr_channels; chan++) {
1104 debugf0("Failed to register CSROW%d\n",index); 884 err = edac_create_channel_files(&csrow->kobj,chan);
1105 else 885 if (err)
1106 debugf0("Registered CSROW%d\n",index); 886 break;
887 }
1107 } 888 }
1108 889
890error_exit:
1109 return err; 891 return err;
1110} 892}
1111 893
1112/* sysfs data structures and methods for the MCI kobjects */ 894/* default sysfs methods and data structures for the main MCI kobject */
1113 895
1114static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci, 896static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
1115 const char *data, size_t count) 897 const char *data, size_t count)
@@ -1135,6 +917,7 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
1135 return count; 917 return count;
1136} 918}
1137 919
920/* default attribute files for the MCI object */
1138static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data) 921static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
1139{ 922{
1140 return sprintf(data,"%d\n", mci->ue_count); 923 return sprintf(data,"%d\n", mci->ue_count);
@@ -1160,71 +943,11 @@ static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
1160 return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ); 943 return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ);
1161} 944}
1162 945
1163static ssize_t mci_mod_name_show(struct mem_ctl_info *mci, char *data)
1164{
1165 return sprintf(data,"%s %s\n", mci->mod_name, mci->mod_ver);
1166}
1167
1168static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data) 946static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
1169{ 947{
1170 return sprintf(data,"%s\n", mci->ctl_name); 948 return sprintf(data,"%s\n", mci->ctl_name);
1171} 949}
1172 950
1173static int mci_output_edac_cap(char *buf, unsigned long edac_cap)
1174{
1175 char *p = buf;
1176 int bit_idx;
1177
1178 for (bit_idx = 0; bit_idx < 8 * sizeof(edac_cap); bit_idx++) {
1179 if ((edac_cap >> bit_idx) & 0x1)
1180 p += sprintf(p, "%s ", edac_caps[bit_idx]);
1181 }
1182
1183 return p - buf;
1184}
1185
1186static ssize_t mci_edac_capability_show(struct mem_ctl_info *mci, char *data)
1187{
1188 char *p = data;
1189
1190 p += mci_output_edac_cap(p,mci->edac_ctl_cap);
1191 p += sprintf(p, "\n");
1192 return p - data;
1193}
1194
1195static ssize_t mci_edac_current_capability_show(struct mem_ctl_info *mci,
1196 char *data)
1197{
1198 char *p = data;
1199
1200 p += mci_output_edac_cap(p,mci->edac_cap);
1201 p += sprintf(p, "\n");
1202 return p - data;
1203}
1204
1205static int mci_output_mtype_cap(char *buf, unsigned long mtype_cap)
1206{
1207 char *p = buf;
1208 int bit_idx;
1209
1210 for (bit_idx = 0; bit_idx < 8 * sizeof(mtype_cap); bit_idx++) {
1211 if ((mtype_cap >> bit_idx) & 0x1)
1212 p += sprintf(p, "%s ", mem_types[bit_idx]);
1213 }
1214
1215 return p - buf;
1216}
1217
1218static ssize_t mci_supported_mem_type_show(struct mem_ctl_info *mci,
1219 char *data)
1220{
1221 char *p = data;
1222
1223 p += mci_output_mtype_cap(p,mci->mtype_cap);
1224 p += sprintf(p, "\n");
1225 return p - data;
1226}
1227
1228static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data) 951static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
1229{ 952{
1230 int total_pages, csrow_idx; 953 int total_pages, csrow_idx;
@@ -1251,6 +974,7 @@ struct mcidev_attribute {
1251#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj) 974#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
1252#define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr) 975#define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr)
1253 976
977/* MCI show/store functions for top most object */
1254static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, 978static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
1255 char *buffer) 979 char *buffer)
1256{ 980{
@@ -1287,31 +1011,21 @@ struct mcidev_attribute mci_attr_##_name = { \
1287 .store = _store, \ 1011 .store = _store, \
1288}; 1012};
1289 1013
1290/* Control file */ 1014/* default Control file */
1291MCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store); 1015MCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store);
1292 1016
1293/* Attribute files */ 1017/* default Attribute files */
1294MCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL); 1018MCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL);
1295MCIDEV_ATTR(module_name,S_IRUGO,mci_mod_name_show,NULL);
1296MCIDEV_ATTR(edac_capability,S_IRUGO,mci_edac_capability_show,NULL);
1297MCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL); 1019MCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL);
1298MCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL); 1020MCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL);
1299MCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL); 1021MCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL);
1300MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL); 1022MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL);
1301MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL); 1023MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL);
1302MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL); 1024MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL);
1303MCIDEV_ATTR(edac_current_capability,S_IRUGO,
1304 mci_edac_current_capability_show,NULL);
1305MCIDEV_ATTR(supported_mem_type,S_IRUGO,
1306 mci_supported_mem_type_show,NULL);
1307 1025
1308static struct mcidev_attribute *mci_attr[] = { 1026static struct mcidev_attribute *mci_attr[] = {
1309 &mci_attr_reset_counters, 1027 &mci_attr_reset_counters,
1310 &mci_attr_module_name,
1311 &mci_attr_mc_name, 1028 &mci_attr_mc_name,
1312 &mci_attr_edac_capability,
1313 &mci_attr_edac_current_capability,
1314 &mci_attr_supported_mem_type,
1315 &mci_attr_size_mb, 1029 &mci_attr_size_mb,
1316 &mci_attr_seconds_since_reset, 1030 &mci_attr_seconds_since_reset,
1317 &mci_attr_ue_noinfo_count, 1031 &mci_attr_ue_noinfo_count,
@@ -1339,7 +1053,6 @@ static struct kobj_type ktype_mci = {
1339 .default_attrs = (struct attribute **) mci_attr, 1053 .default_attrs = (struct attribute **) mci_attr,
1340}; 1054};
1341 1055
1342#endif /* DISABLE_EDAC_SYSFS */
1343 1056
1344#define EDAC_DEVICE_SYMLINK "device" 1057#define EDAC_DEVICE_SYMLINK "device"
1345 1058
@@ -1352,11 +1065,6 @@ static struct kobj_type ktype_mci = {
1352 * !0 Failure 1065 * !0 Failure
1353 */ 1066 */
1354static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) 1067static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
1355#ifdef DISABLE_EDAC_SYSFS
1356{
1357 return 0;
1358}
1359#else
1360{ 1068{
1361 int i; 1069 int i;
1362 int err; 1070 int err;
@@ -1368,7 +1076,6 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
1368 1076
1369 /* set the name of the mc<id> object */ 1077 /* set the name of the mc<id> object */
1370 err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx); 1078 err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx);
1371
1372 if (err) 1079 if (err)
1373 return err; 1080 return err;
1374 1081
@@ -1378,14 +1085,12 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
1378 1085
1379 /* register the mc<id> kobject */ 1086 /* register the mc<id> kobject */
1380 err = kobject_register(edac_mci_kobj); 1087 err = kobject_register(edac_mci_kobj);
1381
1382 if (err) 1088 if (err)
1383 return err; 1089 return err;
1384 1090
1385 /* create a symlink for the device */ 1091 /* create a symlink for the device */
1386 err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj, 1092 err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj,
1387 EDAC_DEVICE_SYMLINK); 1093 EDAC_DEVICE_SYMLINK);
1388
1389 if (err) 1094 if (err)
1390 goto fail0; 1095 goto fail0;
1391 1096
@@ -1398,7 +1103,6 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
1398 /* Only expose populated CSROWs */ 1103 /* Only expose populated CSROWs */
1399 if (csrow->nr_pages > 0) { 1104 if (csrow->nr_pages > 0) {
1400 err = edac_create_csrow_object(edac_mci_kobj,csrow,i); 1105 err = edac_create_csrow_object(edac_mci_kobj,csrow,i);
1401
1402 if (err) 1106 if (err)
1403 goto fail1; 1107 goto fail1;
1404 } 1108 }
@@ -1422,14 +1126,12 @@ fail0:
1422 wait_for_completion(&mci->kobj_complete); 1126 wait_for_completion(&mci->kobj_complete);
1423 return err; 1127 return err;
1424} 1128}
1425#endif /* DISABLE_EDAC_SYSFS */
1426 1129
1427/* 1130/*
1428 * remove a Memory Controller instance 1131 * remove a Memory Controller instance
1429 */ 1132 */
1430static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) 1133static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
1431{ 1134{
1432#ifndef DISABLE_EDAC_SYSFS
1433 int i; 1135 int i;
1434 1136
1435 debugf0("%s()\n", __func__); 1137 debugf0("%s()\n", __func__);
@@ -1447,7 +1149,6 @@ static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
1447 init_completion(&mci->kobj_complete); 1149 init_completion(&mci->kobj_complete);
1448 kobject_unregister(&mci->edac_mci_kobj); 1150 kobject_unregister(&mci->edac_mci_kobj);
1449 wait_for_completion(&mci->kobj_complete); 1151 wait_for_completion(&mci->kobj_complete);
1450#endif /* DISABLE_EDAC_SYSFS */
1451} 1152}
1452 1153
1453/* END OF sysfs data and methods */ 1154/* END OF sysfs data and methods */