[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1445543427-26275-6-git-send-email-pantelis.antoniou@konsulko.com>
Date: Thu, 22 Oct 2015 22:50:26 +0300
From: Pantelis Antoniou <pantelis.antoniou@...sulko.com>
To: Rob Herring <robherring2@...il.com>
Cc: Frank Rowand <frowand.list@...il.com>,
Matt Porter <mporter@...sulko.com>,
Koen Kooi <koen@...inion.thruhere.net>,
Guenter Roeck <linux@...ck-us.net>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
devicetree@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-api@...r.kernel.org,
Pantelis Antoniou <pantelis.antoniou@...sulko.com>,
Pantelis Antoniou <panto@...oniou-consulting.com>
Subject: [PATCH v7 5/6] of: overlay: add per overlay sysfs attributes
* 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.antoniou@...sulko.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 91f10ed..6398810 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;
};
@@ -252,6 +273,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:
@@ -262,6 +285,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
@@ -279,7 +313,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;
@@ -300,14 +334,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;
}
/**
@@ -324,12 +389,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);
@@ -380,8 +449,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;
@@ -461,13 +547,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:
@@ -586,6 +680,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-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists