* A per overlay can_remove sysfs attribute that reports whether
the overlay can be removed or not due to another overlapping overlay.

* A target sysfs attribute listing the target of each fragment,
in a group named after the name of the fragment.

Signed-off-by: Pantelis Antoniou <pantelis.anton...@konsulko.com>
---
 drivers/of/overlay.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 99 insertions(+), 4 deletions(-)

diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 067404e..2d51d9e2 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -25,8 +25,23 @@
 
 #include "of_private.h"
 
+/* fwd. decl */
+struct of_overlay;
+struct of_overlay_info;
+
+/* an attribute for each fragment */
+struct fragment_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct kobject *kobj, struct fragment_attribute *fattr,
+                       char *buf);
+       ssize_t (*store)(struct kobject *kobj, struct fragment_attribute *fattr,
+                        const char *buf, size_t count);
+       struct of_overlay_info *ovinfo;
+};
+
 /**
  * struct of_overlay_info - Holds a single overlay info
+ * @info:      info node that contains the target and overlay
  * @target:    target of the overlay operation
  * @overlay:   pointer to the overlay contents node
  *
@@ -34,8 +49,13 @@
  * records.
  */
 struct of_overlay_info {
+       struct of_overlay *ov;
+       struct device_node *info;
        struct device_node *target;
        struct device_node *overlay;
+       struct attribute_group attr_group;
+       struct attribute *attrs[2];
+       struct fragment_attribute target_attr;
 };
 
 /**
@@ -52,6 +72,7 @@ struct of_overlay {
        struct list_head node;
        int count;
        struct of_overlay_info *ovinfo_tab;
+       const struct attribute_group **attr_groups;
        struct of_changeset cset;
        struct kobject kobj;
 };
@@ -245,6 +266,8 @@ static int of_fill_overlay_info(struct of_overlay *ov,
        if (ovinfo->target == NULL)
                goto err_fail;
 
+       ovinfo->info = of_node_get(info_node);
+
        return 0;
 
 err_fail:
@@ -255,6 +278,17 @@ err_fail:
        return -EINVAL;
 }
 
+static ssize_t target_show(struct kobject *kobj,
+               struct fragment_attribute *fattr, char *buf)
+{
+       struct of_overlay_info *ovinfo = fattr->ovinfo;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       of_node_full_name(ovinfo->target));
+}
+
+static const struct fragment_attribute target_template_attr = 
__ATTR_RO(target);
+
 /**
  * of_build_overlay_info() - Build an overlay info array
  * @ov         Overlay to build
@@ -272,7 +306,7 @@ static int of_build_overlay_info(struct of_overlay *ov,
 {
        struct device_node *node;
        struct of_overlay_info *ovinfo;
-       int cnt, err;
+       int i, cnt, err;
 
        /* worst case; every child is a node */
        cnt = 0;
@@ -293,14 +327,45 @@ static int of_build_overlay_info(struct of_overlay *ov,
 
        /* if nothing filled, return error */
        if (cnt == 0) {
-               kfree(ovinfo);
-               return -ENODEV;
+               err = -ENODEV;
+               goto err_free_ovinfo;
        }
 
        ov->count = cnt;
        ov->ovinfo_tab = ovinfo;
 
+       ov->attr_groups = kcalloc(cnt + 1,
+                       sizeof(struct attribute_group *), GFP_KERNEL);
+       if (ov->attr_groups == NULL) {
+               err = -ENOMEM;
+               goto err_free_ovinfo;
+       }
+
+       for (i = 0; i < cnt; i++) {
+               ovinfo = &ov->ovinfo_tab[i];
+
+               ov->attr_groups[i] = &ovinfo->attr_group;
+
+               ovinfo->target_attr = target_template_attr;
+               /* make lockdep happy */
+               sysfs_attr_init(&ovinfo->target_attr.attr);
+               ovinfo->target_attr.ovinfo = ovinfo;
+
+               ovinfo->attrs[0] = &ovinfo->target_attr.attr;
+               ovinfo->attrs[1] = NULL;
+
+               /* NOTE: direct reference to the full_name */
+               ovinfo->attr_group.name = kbasename(ovinfo->info->full_name);
+               ovinfo->attr_group.attrs = ovinfo->attrs;
+
+       }
+       ov->attr_groups[i] = NULL;
+
        return 0;
+
+err_free_ovinfo:
+       kfree(ovinfo);
+       return err;
 }
 
 /**
@@ -317,12 +382,16 @@ static int of_free_overlay_info(struct of_overlay *ov)
        struct of_overlay_info *ovinfo;
        int i;
 
+       /* free attribute groups space */
+       kfree(ov->attr_groups);
+
        /* do it in reverse */
        for (i = ov->count - 1; i >= 0; i--) {
                ovinfo = &ov->ovinfo_tab[i];
 
                of_node_put(ovinfo->target);
                of_node_put(ovinfo->overlay);
+               of_node_put(ovinfo->info);
        }
        kfree(ov->ovinfo_tab);
 
@@ -373,8 +442,25 @@ static const struct attribute *overlay_global_attrs[] = {
        NULL
 };
 
+static ssize_t can_remove_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       struct of_overlay *ov = kobj_to_overlay(kobj);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", overlay_removal_is_ok(ov));
+}
+
+static struct kobj_attribute can_remove_attr = __ATTR_RO(can_remove);
+
+static struct attribute *overlay_attrs[] = {
+       &can_remove_attr.attr,
+       NULL
+};
+
 static struct kobj_type of_overlay_ktype = {
        .release = of_overlay_release,
+       .sysfs_ops = &kobj_sysfs_ops,   /* default kobj sysfs ops */
+       .default_attrs = overlay_attrs,
 };
 
 static struct kset *ov_kset;
@@ -454,13 +540,21 @@ int of_overlay_create(struct device_node *tree)
                goto err_cancel_overlay;
        }
 
+       err = sysfs_create_groups(&ov->kobj, ov->attr_groups);
+       if (err != 0) {
+               pr_err("%s: sysfs_create_groups() failed for tree@%s\n",
+                               __func__, tree->full_name);
+               goto err_remove_kobj;
+       }
+
        /* add to the tail of the overlay list */
        list_add_tail(&ov->node, &ov_list);
 
        mutex_unlock(&of_mutex);
 
        return id;
-
+err_remove_kobj:
+       kobject_put(&ov->kobj);
 err_cancel_overlay:
        of_changeset_revert(&ov->cset);
 err_revert_overlay:
@@ -579,6 +673,7 @@ int of_overlay_destroy(int id)
 
 
        list_del(&ov->node);
+       sysfs_remove_groups(&ov->kobj, ov->attr_groups);
        of_changeset_revert(&ov->cset);
        of_free_overlay_info(ov);
        idr_remove(&ov_idr, id);
-- 
1.7.12

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to