aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/edac_mc_sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edac/edac_mc_sysfs.c')
-rw-r--r--drivers/edac/edac_mc_sysfs.c175
1 files changed, 149 insertions, 26 deletions
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 418b65f1a1da..c200c2fd43ea 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -557,6 +557,8 @@ static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
557 struct mem_ctl_info *mem_ctl_info = to_mci(kobj); 557 struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
558 struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); 558 struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
559 559
560 debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
561
560 if (mcidev_attr->show) 562 if (mcidev_attr->show)
561 return mcidev_attr->show(mem_ctl_info, buffer); 563 return mcidev_attr->show(mem_ctl_info, buffer);
562 564
@@ -569,6 +571,8 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
569 struct mem_ctl_info *mem_ctl_info = to_mci(kobj); 571 struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
570 struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); 572 struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
571 573
574 debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
575
572 if (mcidev_attr->store) 576 if (mcidev_attr->store)
573 return mcidev_attr->store(mem_ctl_info, buffer, count); 577 return mcidev_attr->store(mem_ctl_info, buffer, count);
574 578
@@ -726,28 +730,118 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
726 730
727#define EDAC_DEVICE_SYMLINK "device" 731#define EDAC_DEVICE_SYMLINK "device"
728 732
733#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci)
734
735/* MCI show/store functions for top most object */
736static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr,
737 char *buffer)
738{
739 struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
740 struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
741
742 debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
743
744 if (mcidev_attr->show)
745 return mcidev_attr->show(mem_ctl_info, buffer);
746
747 return -EIO;
748}
749
750static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr,
751 const char *buffer, size_t count)
752{
753 struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
754 struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
755
756 debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
757
758 if (mcidev_attr->store)
759 return mcidev_attr->store(mem_ctl_info, buffer, count);
760
761 return -EIO;
762}
763
764/* No memory to release for this kobj */
765static void edac_inst_grp_release(struct kobject *kobj)
766{
767 struct mcidev_sysfs_group_kobj *grp;
768 struct mem_ctl_info *mci;
769
770 debugf1("%s()\n", __func__);
771
772 grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
773 mci = grp->mci;
774
775 kobject_put(&mci->edac_mci_kobj);
776}
777
778/* Intermediate show/store table */
779static struct sysfs_ops inst_grp_ops = {
780 .show = inst_grp_show,
781 .store = inst_grp_store
782};
783
784/* the kobj_type instance for a instance group */
785static struct kobj_type ktype_inst_grp = {
786 .release = edac_inst_grp_release,
787 .sysfs_ops = &inst_grp_ops,
788};
789
790
729/* 791/*
730 * edac_create_mci_instance_attributes 792 * edac_create_mci_instance_attributes
731 * create MC driver specific attributes at the topmost level 793 * create MC driver specific attributes bellow an specified kobj
732 * directory of this mci instance. 794 * This routine calls itself recursively, in order to create an entire
795 * object tree.
733 */ 796 */
734static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci) 797static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
798 struct mcidev_sysfs_attribute *sysfs_attrib,
799 struct kobject *kobj)
735{ 800{
736 int err; 801 int err;
737 struct mcidev_sysfs_attribute *sysfs_attrib;
738 802
739 /* point to the start of the array and iterate over it 803 debugf1("%s()\n", __func__);
740 * adding each attribute listed to this mci instance's kobject 804
741 */ 805 while (sysfs_attrib) {
742 sysfs_attrib = mci->mc_driver_sysfs_attributes; 806 if (sysfs_attrib->grp) {
807 struct mcidev_sysfs_group_kobj *grp_kobj;
808
809 grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL);
810 if (!grp_kobj)
811 return -ENOMEM;
812
813 list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
814
815 grp_kobj->grp = sysfs_attrib->grp;
816 grp_kobj->mci = mci;
817
818 debugf0("%s() grp %s, mci %p\n", __func__,
819 sysfs_attrib->grp->name, mci);
820
821 err = kobject_init_and_add(&grp_kobj->kobj,
822 &ktype_inst_grp,
823 &mci->edac_mci_kobj,
824 sysfs_attrib->grp->name);
825 if (err)
826 return err;
827
828 err = edac_create_mci_instance_attributes(mci,
829 grp_kobj->grp->mcidev_attr,
830 &grp_kobj->kobj);
831
832 if (err)
833 return err;
834 } else if (sysfs_attrib->attr.name) {
835 debugf0("%s() file %s\n", __func__,
836 sysfs_attrib->attr.name);
837
838 err = sysfs_create_file(kobj, &sysfs_attrib->attr);
839 } else
840 break;
743 841
744 while (sysfs_attrib && sysfs_attrib->attr.name) {
745 err = sysfs_create_file(&mci->edac_mci_kobj,
746 (struct attribute*) sysfs_attrib);
747 if (err) { 842 if (err) {
748 return err; 843 return err;
749 } 844 }
750
751 sysfs_attrib++; 845 sysfs_attrib++;
752 } 846 }
753 847
@@ -759,21 +853,44 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
759 * remove MC driver specific attributes at the topmost level 853 * remove MC driver specific attributes at the topmost level
760 * directory of this mci instance. 854 * directory of this mci instance.
761 */ 855 */
762static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci) 856static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
857 struct mcidev_sysfs_attribute *sysfs_attrib,
858 struct kobject *kobj, int count)
763{ 859{
764 struct mcidev_sysfs_attribute *sysfs_attrib; 860 struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
765 861
766 /* point to the start of the array and iterate over it 862 debugf1("%s()\n", __func__);
767 * adding each attribute listed to this mci instance's kobject
768 */
769 sysfs_attrib = mci->mc_driver_sysfs_attributes;
770 863
771 /* loop if there are attributes and until we hit a NULL entry */ 864 /*
772 while (sysfs_attrib && sysfs_attrib->attr.name) { 865 * loop if there are attributes and until we hit a NULL entry
773 sysfs_remove_file(&mci->edac_mci_kobj, 866 * Remove first all the atributes
774 (struct attribute *) sysfs_attrib); 867 */
868 while (sysfs_attrib) {
869 if (sysfs_attrib->grp) {
870 list_for_each_entry(grp_kobj, &mci->grp_kobj_list,
871 list)
872 if (grp_kobj->grp == sysfs_attrib->grp)
873 edac_remove_mci_instance_attributes(mci,
874 grp_kobj->grp->mcidev_attr,
875 &grp_kobj->kobj, count + 1);
876 } else if (sysfs_attrib->attr.name) {
877 debugf0("%s() file %s\n", __func__,
878 sysfs_attrib->attr.name);
879 sysfs_remove_file(kobj, &sysfs_attrib->attr);
880 } else
881 break;
775 sysfs_attrib++; 882 sysfs_attrib++;
776 } 883 }
884
885 /*
886 * Now that all attributes got removed, it is save to remove all groups
887 */
888 if (!count)
889 list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list,
890 list) {
891 debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name);
892 kobject_put(&grp_kobj->kobj);
893 }
777} 894}
778 895
779 896
@@ -794,6 +911,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
794 911
795 debugf0("%s() idx=%d\n", __func__, mci->mc_idx); 912 debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
796 913
914 INIT_LIST_HEAD(&mci->grp_kobj_list);
915
797 /* create a symlink for the device */ 916 /* create a symlink for the device */
798 err = sysfs_create_link(kobj_mci, &mci->dev->kobj, 917 err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
799 EDAC_DEVICE_SYMLINK); 918 EDAC_DEVICE_SYMLINK);
@@ -806,7 +925,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
806 * then create them now for the driver. 925 * then create them now for the driver.
807 */ 926 */
808 if (mci->mc_driver_sysfs_attributes) { 927 if (mci->mc_driver_sysfs_attributes) {
809 err = edac_create_mci_instance_attributes(mci); 928 err = edac_create_mci_instance_attributes(mci,
929 mci->mc_driver_sysfs_attributes,
930 &mci->edac_mci_kobj);
810 if (err) { 931 if (err) {
811 debugf1("%s() failure to create mci attributes\n", 932 debugf1("%s() failure to create mci attributes\n",
812 __func__); 933 __func__);
@@ -841,7 +962,8 @@ fail1:
841 } 962 }
842 963
843 /* remove the mci instance's attributes, if any */ 964 /* remove the mci instance's attributes, if any */
844 edac_remove_mci_instance_attributes(mci); 965 edac_remove_mci_instance_attributes(mci,
966 mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0);
845 967
846 /* remove the symlink */ 968 /* remove the symlink */
847 sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK); 969 sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
@@ -875,8 +997,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
875 debugf0("%s() remove_mci_instance\n", __func__); 997 debugf0("%s() remove_mci_instance\n", __func__);
876 998
877 /* remove this mci instance's attribtes */ 999 /* remove this mci instance's attribtes */
878 edac_remove_mci_instance_attributes(mci); 1000 edac_remove_mci_instance_attributes(mci,
879 1001 mci->mc_driver_sysfs_attributes,
1002 &mci->edac_mci_kobj, 0);
880 debugf0("%s() unregister this mci kobj\n", __func__); 1003 debugf0("%s() unregister this mci kobj\n", __func__);
881 1004
882 /* unregister this instance's kobject */ 1005 /* unregister this instance's kobject */