edac_core: Allow the creation of sysfs groups

Currently, all sysfs nodes are stored at /sys/.*/mc. (regex)
However, sometimes it is needed to create attribute groups.

This patch extends edac_core to allow groups creation.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 418b65f..655aa1a 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -728,26 +728,43 @@
 
 /*
  * edac_create_mci_instance_attributes
- *	create MC driver specific attributes at the topmost level
- *	directory of this mci instance.
+ *	create MC driver specific attributes bellow an specified kobj
+ * This routine calls itself recursively, in order to create an entire
+ * object tree.
  */
-static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
+static int edac_create_mci_instance_attributes(
+				struct mcidev_sysfs_attribute *sysfs_attrib,
+				struct kobject *kobj)
 {
 	int err;
-	struct mcidev_sysfs_attribute *sysfs_attrib;
 
-	/* point to the start of the array and iterate over it
-	 * adding each attribute listed to this mci instance's kobject
-	 */
-	sysfs_attrib = mci->mc_driver_sysfs_attributes;
+	while (sysfs_attrib) {
+		if (sysfs_attrib->grp) {
+			struct kobject *newkobj = &sysfs_attrib->grp->kobj;
+			debugf0("%s() grp %s\n", __func__,
+				sysfs_attrib->grp->name);
 
-	while (sysfs_attrib && sysfs_attrib->attr.name) {
-		err = sysfs_create_file(&mci->edac_mci_kobj,
-					(struct attribute*) sysfs_attrib);
+			err = kobject_init_and_add(newkobj, NULL,
+						kobj,
+						sysfs_attrib->grp->name);
+			if (err)
+				return err;
+
+			err = edac_create_mci_instance_attributes(
+					sysfs_attrib->grp->mcidev_attr, newkobj);
+			if (err)
+				return err;
+		} else if (sysfs_attrib->attr.name) {
+			debugf0("%s() file %s\n", __func__,
+				sysfs_attrib->attr.name);
+
+			err = sysfs_create_file(kobj, &sysfs_attrib->attr);
+		} else
+			break;
+
 		if (err) {
 			return err;
 		}
-
 		sysfs_attrib++;
 	}
 
@@ -759,19 +776,28 @@
  *	remove MC driver specific attributes at the topmost level
  *	directory of this mci instance.
  */
-static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci)
+static void edac_remove_mci_instance_attributes(
+				struct mcidev_sysfs_attribute *sysfs_attrib,
+				struct kobject *kobj)
 {
-	struct mcidev_sysfs_attribute *sysfs_attrib;
-
-	/* point to the start of the array and iterate over it
-	 * adding each attribute listed to this mci instance's kobject
-	 */
-	sysfs_attrib = mci->mc_driver_sysfs_attributes;
-
 	/* loop if there are attributes and until we hit a NULL entry */
-	while (sysfs_attrib && sysfs_attrib->attr.name) {
-		sysfs_remove_file(&mci->edac_mci_kobj,
-					(struct attribute *) sysfs_attrib);
+	while (sysfs_attrib) {
+		if (sysfs_attrib->grp) {
+			struct kobject *newkobj = &sysfs_attrib->grp->kobj;
+
+			debugf0("%s() grp %s\n", __func__,
+				sysfs_attrib->grp->name);
+
+			edac_remove_mci_instance_attributes(
+				sysfs_attrib->grp->mcidev_attr, newkobj);
+
+			kobject_put(newkobj);
+		} else  if (sysfs_attrib->attr.name) {
+			debugf0("%s() file %s\n", __func__,
+				sysfs_attrib->attr.name);
+			sysfs_remove_file(kobj, &sysfs_attrib->attr);
+		} else
+			break;
 		sysfs_attrib++;
 	}
 }
@@ -806,7 +832,9 @@
 	 * then create them now for the driver.
 	 */
 	if (mci->mc_driver_sysfs_attributes) {
-		err = edac_create_mci_instance_attributes(mci);
+		err = edac_create_mci_instance_attributes(
+					mci->mc_driver_sysfs_attributes,
+					&mci->edac_mci_kobj);
 		if (err) {
 			debugf1("%s() failure to create mci attributes\n",
 				__func__);
@@ -841,7 +869,8 @@
 	}
 
 	/* remove the mci instance's attributes, if any */
-	edac_remove_mci_instance_attributes(mci);
+	edac_remove_mci_instance_attributes(
+		mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj);
 
 	/* remove the symlink */
 	sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
@@ -875,8 +904,8 @@
 	debugf0("%s()  remove_mci_instance\n", __func__);
 
 	/* remove this mci instance's attribtes */
-	edac_remove_mci_instance_attributes(mci);
-
+	edac_remove_mci_instance_attributes(mci->mc_driver_sysfs_attributes,
+					    &mci->edac_mci_kobj);
 	debugf0("%s()  unregister this mci kobj\n", __func__);
 
 	/* unregister this instance's kobject */