diff options
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/edac_core.h | 52 | ||||
-rw-r--r-- | drivers/edac/edac_device_sysfs.c | 51 | ||||
-rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 60 |
3 files changed, 141 insertions, 22 deletions
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index b955c58672e2..8c114572b722 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h | |||
@@ -326,6 +326,18 @@ struct csrow_info { | |||
326 | struct channel_info *channels; | 326 | struct channel_info *channels; |
327 | }; | 327 | }; |
328 | 328 | ||
329 | /* mcidev_sysfs_attribute structure | ||
330 | * used for driver sysfs attributes and in mem_ctl_info | ||
331 | * sysfs top level entries | ||
332 | */ | ||
333 | struct mcidev_sysfs_attribute { | ||
334 | struct attribute attr; | ||
335 | ssize_t (*show)(struct mem_ctl_info *,char *); | ||
336 | ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); | ||
337 | }; | ||
338 | |||
339 | /* MEMORY controller information structure | ||
340 | */ | ||
329 | struct mem_ctl_info { | 341 | struct mem_ctl_info { |
330 | struct list_head link; /* for global list of mem_ctl_info structs */ | 342 | struct list_head link; /* for global list of mem_ctl_info structs */ |
331 | unsigned long mtype_cap; /* memory types supported by mc */ | 343 | unsigned long mtype_cap; /* memory types supported by mc */ |
@@ -353,6 +365,7 @@ struct mem_ctl_info { | |||
353 | */ | 365 | */ |
354 | int (*get_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw); | 366 | int (*get_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw); |
355 | 367 | ||
368 | |||
356 | /* pointer to edac checking routine */ | 369 | /* pointer to edac checking routine */ |
357 | void (*edac_check) (struct mem_ctl_info * mci); | 370 | void (*edac_check) (struct mem_ctl_info * mci); |
358 | 371 | ||
@@ -394,6 +407,18 @@ struct mem_ctl_info { | |||
394 | struct kobject edac_mci_kobj; | 407 | struct kobject edac_mci_kobj; |
395 | struct completion kobj_complete; | 408 | struct completion kobj_complete; |
396 | 409 | ||
410 | /* Additional top controller level attributes, but specified | ||
411 | * by the low level driver. | ||
412 | * | ||
413 | * Set by the low level driver to provide attributes at the | ||
414 | * controller level, same level as 'ue_count' and 'ce_count' above. | ||
415 | * An array of structures, NULL terminated | ||
416 | * | ||
417 | * If attributes are desired, then set to array of attributes | ||
418 | * If no attributes are desired, leave NULL | ||
419 | */ | ||
420 | struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes; | ||
421 | |||
397 | /* work struct for this MC */ | 422 | /* work struct for this MC */ |
398 | struct delayed_work work; | 423 | struct delayed_work work; |
399 | 424 | ||
@@ -402,7 +427,7 @@ struct mem_ctl_info { | |||
402 | }; | 427 | }; |
403 | 428 | ||
404 | /* | 429 | /* |
405 | * The following are the structures to provide for a generice | 430 | * The following are the structures to provide for a generic |
406 | * or abstract 'edac_device'. This set of structures and the | 431 | * or abstract 'edac_device'. This set of structures and the |
407 | * code that implements the APIs for the same, provide for | 432 | * code that implements the APIs for the same, provide for |
408 | * registering EDAC type devices which are NOT standard memory. | 433 | * registering EDAC type devices which are NOT standard memory. |
@@ -505,6 +530,16 @@ struct edac_device_instance { | |||
505 | struct completion kobj_complete; | 530 | struct completion kobj_complete; |
506 | }; | 531 | }; |
507 | 532 | ||
533 | /* edac_dev_sysfs_attribute structure | ||
534 | * used for driver sysfs attributes and in mem_ctl_info | ||
535 | * sysfs top level entries | ||
536 | */ | ||
537 | struct edac_dev_sysfs_attribute { | ||
538 | struct attribute attr; | ||
539 | ssize_t (*show)(struct edac_device_ctl_info *,char *); | ||
540 | ssize_t (*store)(struct edac_device_ctl_info *, const char *,size_t); | ||
541 | }; | ||
542 | |||
508 | /* | 543 | /* |
509 | * Abstract edac_device control info structure | 544 | * Abstract edac_device control info structure |
510 | * | 545 | * |
@@ -522,7 +557,20 @@ struct edac_device_ctl_info { | |||
522 | unsigned poll_msec; /* number of milliseconds to poll interval */ | 557 | unsigned poll_msec; /* number of milliseconds to poll interval */ |
523 | unsigned long delay; /* number of jiffies for poll_msec */ | 558 | unsigned long delay; /* number of jiffies for poll_msec */ |
524 | 559 | ||
525 | struct sysdev_class *edac_class; /* pointer to class */ | 560 | /* Additional top controller level attributes, but specified |
561 | * by the low level driver. | ||
562 | * | ||
563 | * Set by the low level driver to provide attributes at the | ||
564 | * controller level, same level as 'ue_count' and 'ce_count' above. | ||
565 | * An array of structures, NULL terminated | ||
566 | * | ||
567 | * If attributes are desired, then set to array of attributes | ||
568 | * If no attributes are desired, leave NULL | ||
569 | */ | ||
570 | struct edac_dev_sysfs_attribute *sysfs_attributes; | ||
571 | |||
572 | /* pointer to main 'edac' class in sysfs */ | ||
573 | struct sysdev_class *edac_class; | ||
526 | 574 | ||
527 | /* the internal state of this controller instance */ | 575 | /* the internal state of this controller instance */ |
528 | int op_state; | 576 | int op_state; |
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 849d569dd2ce..32b2a8e53dc7 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c | |||
@@ -9,8 +9,6 @@ | |||
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/sysdev.h> | ||
14 | #include <linux/ctype.h> | 12 | #include <linux/ctype.h> |
15 | 13 | ||
16 | #include "edac_core.h" | 14 | #include "edac_core.h" |
@@ -622,6 +620,34 @@ static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev) | |||
622 | /******************* edac_dev sysfs ctor/dtor code *************/ | 620 | /******************* edac_dev sysfs ctor/dtor code *************/ |
623 | 621 | ||
624 | /* | 622 | /* |
623 | * edac_device_add_sysfs_attributes | ||
624 | * add some attributes to this instance's main kobject | ||
625 | */ | ||
626 | static int edac_device_add_sysfs_attributes( | ||
627 | struct edac_device_ctl_info *edac_dev) | ||
628 | { | ||
629 | int err; | ||
630 | struct edac_dev_sysfs_attribute *sysfs_attrib; | ||
631 | |||
632 | /* point to the start of the array and iterate over it | ||
633 | * adding each attribute listed to this mci instance's kobject | ||
634 | */ | ||
635 | sysfs_attrib = edac_dev->sysfs_attributes; | ||
636 | |||
637 | while (sysfs_attrib->attr.name != NULL) { | ||
638 | err = sysfs_create_file(&edac_dev->kobj, | ||
639 | (struct attribute*) sysfs_attrib); | ||
640 | if (err) { | ||
641 | return err; | ||
642 | } | ||
643 | |||
644 | sysfs_attrib++; | ||
645 | } | ||
646 | |||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | /* | ||
625 | * edac_device_create_sysfs() Constructor | 651 | * edac_device_create_sysfs() Constructor |
626 | * | 652 | * |
627 | * Create a new edac_device kobject instance, | 653 | * Create a new edac_device kobject instance, |
@@ -642,6 +668,18 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev) | |||
642 | 668 | ||
643 | debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx); | 669 | debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx); |
644 | 670 | ||
671 | /* If the low level driver requests some sysfs entries | ||
672 | * then go create them here | ||
673 | */ | ||
674 | if (edac_dev->sysfs_attributes != NULL) { | ||
675 | err = edac_device_add_sysfs_attributes(edac_dev); | ||
676 | if (err) { | ||
677 | debugf0("%s() failed to add sysfs attribs\n", | ||
678 | __func__); | ||
679 | goto err_unreg_object; | ||
680 | } | ||
681 | } | ||
682 | |||
645 | /* create a symlink from the edac device | 683 | /* create a symlink from the edac device |
646 | * to the platform 'device' being used for this | 684 | * to the platform 'device' being used for this |
647 | */ | 685 | */ |
@@ -650,7 +688,7 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev) | |||
650 | if (err) { | 688 | if (err) { |
651 | debugf0("%s() sysfs_create_link() returned err= %d\n", | 689 | debugf0("%s() sysfs_create_link() returned err= %d\n", |
652 | __func__, err); | 690 | __func__, err); |
653 | return err; | 691 | goto err_unreg_object; |
654 | } | 692 | } |
655 | 693 | ||
656 | debugf0("%s() calling create-instances, idx=%d\n", | 694 | debugf0("%s() calling create-instances, idx=%d\n", |
@@ -659,14 +697,17 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev) | |||
659 | /* Create the first level instance directories */ | 697 | /* Create the first level instance directories */ |
660 | err = edac_device_create_instances(edac_dev); | 698 | err = edac_device_create_instances(edac_dev); |
661 | if (err) { | 699 | if (err) { |
662 | goto error0; | 700 | goto err_remove_link; |
663 | } | 701 | } |
664 | 702 | ||
665 | return 0; | 703 | return 0; |
666 | 704 | ||
667 | /* Error unwind stack */ | 705 | /* Error unwind stack */ |
706 | err_remove_link: | ||
707 | /* remove the sym link */ | ||
708 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); | ||
668 | 709 | ||
669 | error0: | 710 | err_unreg_object: |
670 | edac_device_unregister_main_kobj(edac_dev); | 711 | edac_device_unregister_main_kobj(edac_dev); |
671 | 712 | ||
672 | return err; | 713 | return err; |
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 8eaa1d6a8a9f..029ce8979a71 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
@@ -1,15 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * edac_mc kernel module | 2 | * edac_mc kernel module |
3 | * (C) 2005, 2006 Linux Networx (http://lnxi.com) | 3 | * (C) 2005-2007 Linux Networx (http://lnxi.com) |
4 | * | ||
4 | * This file may be distributed under the terms of the | 5 | * This file may be distributed under the terms of the |
5 | * GNU General Public License. | 6 | * GNU General Public License. |
6 | * | 7 | * |
7 | * Written Doug Thompson <norsk5@xmission.com> | 8 | * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com |
8 | * | 9 | * |
9 | */ | 10 | */ |
10 | 11 | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/sysdev.h> | ||
13 | #include <linux/ctype.h> | 12 | #include <linux/ctype.h> |
14 | 13 | ||
15 | #include "edac_core.h" | 14 | #include "edac_core.h" |
@@ -661,21 +660,15 @@ static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data) | |||
661 | return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages)); | 660 | return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages)); |
662 | } | 661 | } |
663 | 662 | ||
664 | struct mcidev_attribute { | ||
665 | struct attribute attr; | ||
666 | ssize_t(*show) (struct mem_ctl_info *, char *); | ||
667 | ssize_t(*store) (struct mem_ctl_info *, const char *, size_t); | ||
668 | }; | ||
669 | |||
670 | #define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj) | 663 | #define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj) |
671 | #define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr) | 664 | #define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr) |
672 | 665 | ||
673 | /* MCI show/store functions for top most object */ | 666 | /* MCI show/store functions for top most object */ |
674 | static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, | 667 | static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, |
675 | char *buffer) | 668 | char *buffer) |
676 | { | 669 | { |
677 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); | 670 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); |
678 | struct mcidev_attribute *mcidev_attr = to_mcidev_attr(attr); | 671 | struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); |
679 | 672 | ||
680 | if (mcidev_attr->show) | 673 | if (mcidev_attr->show) |
681 | return mcidev_attr->show(mem_ctl_info, buffer); | 674 | return mcidev_attr->show(mem_ctl_info, buffer); |
@@ -687,7 +680,7 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, | |||
687 | const char *buffer, size_t count) | 680 | const char *buffer, size_t count) |
688 | { | 681 | { |
689 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); | 682 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); |
690 | struct mcidev_attribute *mcidev_attr = to_mcidev_attr(attr); | 683 | struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); |
691 | 684 | ||
692 | if (mcidev_attr->store) | 685 | if (mcidev_attr->store) |
693 | return mcidev_attr->store(mem_ctl_info, buffer, count); | 686 | return mcidev_attr->store(mem_ctl_info, buffer, count); |
@@ -701,7 +694,7 @@ static struct sysfs_ops mci_ops = { | |||
701 | }; | 694 | }; |
702 | 695 | ||
703 | #define MCIDEV_ATTR(_name,_mode,_show,_store) \ | 696 | #define MCIDEV_ATTR(_name,_mode,_show,_store) \ |
704 | static struct mcidev_attribute mci_attr_##_name = { \ | 697 | static struct mcidev_sysfs_attribute mci_attr_##_name = { \ |
705 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | 698 | .attr = {.name = __stringify(_name), .mode = _mode }, \ |
706 | .show = _show, \ | 699 | .show = _show, \ |
707 | .store = _store, \ | 700 | .store = _store, \ |
@@ -723,7 +716,7 @@ MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL); | |||
723 | MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show, | 716 | MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show, |
724 | mci_sdram_scrub_rate_store); | 717 | mci_sdram_scrub_rate_store); |
725 | 718 | ||
726 | static struct mcidev_attribute *mci_attr[] = { | 719 | static struct mcidev_sysfs_attribute *mci_attr[] = { |
727 | &mci_attr_reset_counters, | 720 | &mci_attr_reset_counters, |
728 | &mci_attr_mc_name, | 721 | &mci_attr_mc_name, |
729 | &mci_attr_size_mb, | 722 | &mci_attr_size_mb, |
@@ -757,6 +750,34 @@ static struct kobj_type ktype_mci = { | |||
757 | #define EDAC_DEVICE_SYMLINK "device" | 750 | #define EDAC_DEVICE_SYMLINK "device" |
758 | 751 | ||
759 | /* | 752 | /* |
753 | * edac_create_driver_attributes | ||
754 | * create MC driver specific attributes at the topmost level | ||
755 | * directory of this mci instance. | ||
756 | */ | ||
757 | static int edac_create_driver_attributes(struct mem_ctl_info *mci) | ||
758 | { | ||
759 | int err; | ||
760 | struct mcidev_sysfs_attribute *sysfs_attrib; | ||
761 | |||
762 | /* point to the start of the array and iterate over it | ||
763 | * adding each attribute listed to this mci instance's kobject | ||
764 | */ | ||
765 | sysfs_attrib = mci->mc_driver_sysfs_attributes; | ||
766 | |||
767 | while (sysfs_attrib->attr.name != NULL) { | ||
768 | err = sysfs_create_file(&mci->edac_mci_kobj, | ||
769 | (struct attribute*) sysfs_attrib); | ||
770 | if (err) { | ||
771 | return err; | ||
772 | } | ||
773 | |||
774 | sysfs_attrib++; | ||
775 | } | ||
776 | |||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | /* | ||
760 | * Create a new Memory Controller kobject instance, | 781 | * Create a new Memory Controller kobject instance, |
761 | * mc<id> under the 'mc' directory | 782 | * mc<id> under the 'mc' directory |
762 | * | 783 | * |
@@ -794,6 +815,15 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | |||
794 | if (err) | 815 | if (err) |
795 | goto fail0; | 816 | goto fail0; |
796 | 817 | ||
818 | /* If the low level driver desires some attributes, | ||
819 | * then create them now for the driver. | ||
820 | */ | ||
821 | if (mci->mc_driver_sysfs_attributes) { | ||
822 | err = edac_create_driver_attributes(mci); | ||
823 | if (err) | ||
824 | goto fail0; | ||
825 | } | ||
826 | |||
797 | /* Make directories for each CSROW object | 827 | /* Make directories for each CSROW object |
798 | * under the mc<id> kobject | 828 | * under the mc<id> kobject |
799 | */ | 829 | */ |