diff options
author | Douglas Thompson <dougthompson@xmission.com> | 2007-07-19 04:50:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 13:04:55 -0400 |
commit | 42a8e397a80c277afb2aeb22232bc70114035bb1 (patch) | |
tree | b178b3379d2de5607b5ddb29a2def3472e9d99fe /drivers/edac/edac_mc_sysfs.c | |
parent | 456a2f9552e7849475f4aea1a9aa4c0e54b3ddda (diff) |
drivers/edac: add device sysfs attributes
Added new controls for the edac_device and edac_mc sysfs folder.
These can be initialized by the low level driver to provide misc
controls into the low level driver for its use
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 | 60 |
1 files changed, 45 insertions, 15 deletions
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 | */ |