linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/5]  of: dynamic: Changesets helpers & fixes
@ 2016-05-16 16:41 Pantelis Antoniou
  2016-05-16 16:41 ` [PATCH v2 1/5] of: dynamic: Add __of_node_dupv() Pantelis Antoniou
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Pantelis Antoniou @ 2016-05-16 16:41 UTC (permalink / raw)
  To: Rob Herring
  Cc: Frank Rowand, Matt Porter, Koen Kooi, Guenter Roeck, Marek Vasut,
	Wolfram Sang, devicetree, linux-kernel, linux-i2c,
	Pantelis Antoniou, Pantelis Antoniou

This patchset introduces changeset helpers which makes working with
changeset much easier and less error prone.

The first patch exports an internal method which is used for the third patch
which contains the bulk of the changes.

The second introduces a of_changeset_node_move method that helps when
moving subtrees.

The third contains the changesets unittests.

The final patch converts an in-kernel user to the helpers.

Finally the last patch adds a unittest for the changeset helpers.

Changes since v1:
* Dropped accepted patch
* Addressed maintainer comments
* Made a lot of methods that made sense into static inlines.
* Split out of_changeset_node_move method into a seperate patch
* Add in-kernel conversion i2c-demux patch

Pantelis Antoniou (5):
  of: dynamic: Add __of_node_dupv()
  of: changesets: Introduce changeset helper methods
  of: changeset: Add of_changeset_node_move method
  of: unittest: changeset helpers
  i2c: demux: Use changeset helpers for clarity

 drivers/i2c/muxes/i2c-demux-pinctrl.c |   5 +-
 drivers/of/dynamic.c                  | 321 +++++++++++++++++++++++++++++++-
 drivers/of/unittest.c                 |  54 ++++++
 include/linux/of.h                    | 337 ++++++++++++++++++++++++++++++++++
 4 files changed, 708 insertions(+), 9 deletions(-)

-- 
1.7.12

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/5] of: dynamic: Add __of_node_dupv()
  2016-05-16 16:41 [PATCH v2 0/5] of: dynamic: Changesets helpers & fixes Pantelis Antoniou
@ 2016-05-16 16:41 ` Pantelis Antoniou
  2016-05-16 16:41 ` [PATCH v2 2/5] of: changesets: Introduce changeset helper methods Pantelis Antoniou
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Pantelis Antoniou @ 2016-05-16 16:41 UTC (permalink / raw)
  To: Rob Herring
  Cc: Frank Rowand, Matt Porter, Koen Kooi, Guenter Roeck, Marek Vasut,
	Wolfram Sang, devicetree, linux-kernel, linux-i2c,
	Pantelis Antoniou, Pantelis Antoniou

Add an __of_node_dupv() private method and make __of_node_dup() use it.
This is required for the subsequent changeset accessors which will
make use of it.

Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
 drivers/of/dynamic.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 4145b44..e4dea94 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -394,8 +394,9 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
 }
 
 /**
- * __of_node_dup() - Duplicate or create an empty device node dynamically.
- * @fmt: Format string (plus vargs) for new full name of the device node
+ * __of_node_dupv() - Duplicate or create an empty device node dynamically.
+ * @fmt: Format string for new full name of the device node
+ * @vargs: va_list containing the arugments for the node full name
  *
  * Create an device tree node, either by duplicating an empty node or by allocating
  * an empty one suitable for further modification.  The node data are
@@ -403,17 +404,15 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
  * OF_DETACHED bits set. Returns the newly allocated node or NULL on out of
  * memory error.
  */
-struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...)
+struct device_node *__of_node_dupv(const struct device_node *np,
+		const char *fmt, va_list vargs)
 {
-	va_list vargs;
 	struct device_node *node;
 
 	node = kzalloc(sizeof(*node), GFP_KERNEL);
 	if (!node)
 		return NULL;
-	va_start(vargs, fmt);
 	node->full_name = kvasprintf(GFP_KERNEL, fmt, vargs);
-	va_end(vargs);
 	if (!node->full_name) {
 		kfree(node);
 		return NULL;
@@ -445,6 +444,24 @@ struct device_node *__of_node_dup(const struct device_node *np, const char *fmt,
 	return NULL;
 }
 
+/**
+ * __of_node_dup() - Duplicate or create an empty device node dynamically.
+ * @fmt: Format string (plus vargs) for new full name of the device node
+ *
+ * See: __of_node_dupv()
+ */
+struct device_node *__of_node_dup(const struct device_node *np,
+		const char *fmt, ...)
+{
+	va_list vargs;
+	struct device_node *node;
+
+	va_start(vargs, fmt);
+	node = __of_node_dupv(np, fmt, vargs);
+	va_end(vargs);
+	return node;
+}
+
 static void __of_changeset_entry_destroy(struct of_changeset_entry *ce)
 {
 	of_node_put(ce->np);
-- 
1.7.12

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/5] of: changesets: Introduce changeset helper methods
  2016-05-16 16:41 [PATCH v2 0/5] of: dynamic: Changesets helpers & fixes Pantelis Antoniou
  2016-05-16 16:41 ` [PATCH v2 1/5] of: dynamic: Add __of_node_dupv() Pantelis Antoniou
@ 2016-05-16 16:41 ` Pantelis Antoniou
  2016-05-17 10:25   ` Peter Rosin
  2016-05-16 16:41 ` [PATCH v2 3/5] of: changeset: Add of_changeset_node_move method Pantelis Antoniou
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Pantelis Antoniou @ 2016-05-16 16:41 UTC (permalink / raw)
  To: Rob Herring
  Cc: Frank Rowand, Matt Porter, Koen Kooi, Guenter Roeck, Marek Vasut,
	Wolfram Sang, devicetree, linux-kernel, linux-i2c,
	Pantelis Antoniou, Pantelis Antoniou

Changesets are very powerful, but the lack of a helper API
makes using them cumbersome. Introduce a simple copy based
API that makes things considerably easier.

To wit, adding a property using the raw API.

	struct property *prop;
	prop = kzalloc(sizeof(*prop)), GFP_KERNEL);
	prop->name = kstrdup("compatible");
	prop->value = kstrdup("foo,bar");
	prop->length = strlen(prop->value) + 1;
	of_changeset_add_property(ocs, np, prop);

while using the helper API

	of_changeset_add_property_string(ocs, np, "compatible",
			"foo,bar");

Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
 drivers/of/dynamic.c | 226 +++++++++++++++++++++++++++++++++++
 include/linux/of.h   | 328 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 554 insertions(+)

diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index e4dea94..83cc801 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -828,3 +828,229 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(of_changeset_action);
+
+/* changeset helpers */
+
+/**
+ * of_changeset_create_device_node - Create an empty device node
+ *
+ * @ocs:	changeset pointer
+ * @parent:	parent device node
+ * @fmt:	format string for the node's full_name
+ * @args:	argument list for the format string
+ *
+ * Create an empty device node, marking it as detached and allocated.
+ *
+ * Returns a device node on success, an error encoded pointer otherwise
+ */
+struct device_node *of_changeset_create_device_nodev(
+	struct of_changeset *ocs, struct device_node *parent,
+	const char *fmt, va_list vargs)
+{
+	struct device_node *node;
+
+	node = __of_node_dupv(NULL, fmt, vargs);
+	if (!node)
+		return ERR_PTR(-ENOMEM);
+
+	node->parent = parent;
+	return node;
+}
+EXPORT_SYMBOL_GPL(of_changeset_create_device_nodev);
+
+/**
+ * of_changeset_create_device_node - Create an empty device node
+ *
+ * @ocs:	changeset pointer
+ * @parent:	parent device node
+ * @fmt:	Format string for the node's full_name
+ * ...		Arguments
+ *
+ * Create an empty device node, marking it as detached and allocated.
+ *
+ * Returns a device node on success, an error encoded pointer otherwise
+ */
+__printf(3, 4) struct device_node *
+of_changeset_create_device_node(struct of_changeset *ocs,
+	struct device_node *parent, const char *fmt, ...)
+{
+	va_list vargs;
+	struct device_node *node;
+
+	va_start(vargs, fmt);
+	node = of_changeset_create_device_nodev(ocs, parent, fmt, vargs);
+	va_end(vargs);
+	return node;
+}
+EXPORT_SYMBOL_GPL(of_changeset_create_device_node);
+
+/**
+ * __of_changeset_add_property_copy - Create/update a new property copying
+ *                                    name & value
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @value:	pointer to the value data
+ * @length:	length of the value in bytes
+ * @update:	True on update operation
+ *
+ * Adds/updates a property to the changeset by making copies of the name & value
+ * entries. The @update parameter controls whether an add or update takes place.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int __of_changeset_add_update_property_copy(struct of_changeset *ocs,
+		struct device_node *np, const char *name, const void *value,
+		int length, bool update)
+{
+	struct property *prop;
+	char *new_name;
+	void *new_value;
+	int ret = -ENOMEM;
+
+	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+	if (!prop)
+		return -ENOMEM;
+
+	new_name = kstrdup(name, GFP_KERNEL);
+	if (!new_name)
+		goto out_err;
+
+	/*
+	 * NOTE: There is no check for zero length value.
+	 * In case of a boolean property, this will allocate a value
+	 * of zero bytes. We do this to work around the use
+	 * of of_get_property() calls on boolean values.
+	 */
+	new_value = kmemdup(value, length, GFP_KERNEL);
+	if (!new_value)
+		goto out_err;
+
+	of_property_set_flag(prop, OF_DYNAMIC);
+
+	prop->name = new_name;
+	prop->value = new_value;
+	prop->length = length;
+
+	if (!update)
+		ret = of_changeset_add_property(ocs, np, prop);
+	else
+		ret = of_changeset_update_property(ocs, np, prop);
+
+	if (!ret)
+		return 0;
+
+out_err:
+	kfree(prop->value);
+	kfree(prop->name);
+	kfree(prop);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(__of_changeset_add_update_property_copy);
+
+/**
+ * of_changeset_add_property_stringf - Create a new formatted string property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @fmt:	format of string property
+ * ...		arguments of the format string
+ *
+ * Adds a string property to the changeset by making copies of the name
+ * and the formatted value.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+__printf(4, 5) int of_changeset_add_property_stringf(
+		struct of_changeset *ocs, struct device_node *np,
+		const char *name, const char *fmt, ...)
+{
+	va_list vargs;
+	int ret;
+
+	va_start(vargs, fmt);
+	ret = __of_changeset_add_update_property_stringv(ocs, np, name, fmt,
+			vargs, false);
+	va_end(vargs);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(of_changeset_add_property_stringf);
+
+/**
+ * of_changeset_update_property_stringf - Update formatted string property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @fmt:	format of string property
+ * ...		arguments of the format string
+ *
+ * Updates a string property to the changeset by making copies of the name
+ * and the formatted value.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int of_changeset_update_property_stringf(
+	struct of_changeset *ocs, struct device_node *np,
+	const char *name, const char *fmt, ...)
+{
+	va_list vargs;
+	int ret;
+
+	va_start(vargs, fmt);
+	ret = __of_changeset_add_update_property_stringv(ocs, np, name, fmt,
+			vargs, true);
+	va_end(vargs);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(of_changeset_update_property_stringf);
+
+/**
+ * __of_changeset_add_update_property_string_list - Create/update a string
+ *                                                  list property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @strs:	pointer to the string list
+ * @count:	string count
+ * @update:	True on update operation
+ *
+ * Adds a string list property to the changeset.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int __of_changeset_add_update_property_string_list(
+		struct of_changeset *ocs, struct device_node *np,
+		const char *name, const char **strs, int count, bool update)
+{
+	int total = 0, i, ret;
+	char *value, *s;
+
+	for (i = 0; i < count; i++) {
+		/* check if  it's NULL */
+		if (!strs[i])
+			return -EINVAL;
+		total += strlen(strs[i]) + 1;
+	}
+
+	value = kmalloc(total, GFP_KERNEL);
+	if (!value)
+		return -ENOMEM;
+
+	for (i = 0, s = value; i < count; i++) {
+		/* no need to check for NULL, check above */
+		strcpy(s, strs[i]);
+		s += strlen(strs[i]) + 1;
+	}
+
+	ret = __of_changeset_add_update_property_copy(ocs, np, name, value,
+			total, update);
+
+	kfree(value);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(__of_changeset_add_update_property_string_list);
diff --git a/include/linux/of.h b/include/linux/of.h
index 3175803..9df3b71 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -994,6 +994,8 @@ enum of_reconfig_change {
 };
 
 #ifdef CONFIG_OF_DYNAMIC
+#include <linux/slab.h>
+
 extern int of_reconfig_notifier_register(struct notifier_block *);
 extern int of_reconfig_notifier_unregister(struct notifier_block *);
 extern int of_reconfig_notify(unsigned long, struct of_reconfig_data *rd);
@@ -1037,6 +1039,23 @@ static inline int of_changeset_update_property(struct of_changeset *ocs,
 {
 	return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, prop);
 }
+
+struct device_node *of_changeset_create_device_nodev(
+	struct of_changeset *ocs, struct device_node *parent,
+	const char *fmt, va_list vargs);
+
+__printf(3, 4) struct device_node *
+of_changeset_create_device_node(struct of_changeset *ocs,
+	struct device_node *parent, const char *fmt, ...);
+
+int __of_changeset_add_update_property_copy(struct of_changeset *ocs,
+		struct device_node *np, const char *name, const void *value,
+		int length, bool update);
+
+int __of_changeset_add_update_property_string_list(
+		struct of_changeset *ocs, struct device_node *np,
+		const char *name, const char **strs, int count, bool update);
+
 #else /* CONFIG_OF_DYNAMIC */
 static inline int of_reconfig_notifier_register(struct notifier_block *nb)
 {
@@ -1056,8 +1075,317 @@ static inline int of_reconfig_get_state_change(unsigned long action,
 {
 	return -EINVAL;
 }
+
+static inline struct device_node *of_changeset_create_device_nodev(
+	struct of_changeset *ocs, struct device_node *parent,
+	const char *fmt, va_list vargs)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline __printf(3, 4) struct device_node *
+of_changeset_create_device_node(struct of_changeset *ocs,
+	struct device_node *parent, const char *fmt, ...)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int __of_changeset_add_update_property_copy(
+	struct of_changeset *ocs, struct device_node *np,
+	const char *name, const void *value, int length, bool update)
+{
+	return -EINVAL;
+}
+
+static inline __printf(4, 5) int of_changeset_add_property_stringf(
+		struct of_changeset *ocs, struct device_node *np,
+		const char *name, const char *fmt, ...)
+{
+	return -EINVAL;
+}
+
+static inline int of_changeset_update_property_stringf(
+	struct of_changeset *ocs, struct device_node *np,
+	const char *name, const char *fmt, ...)
+{
+	return -EINVAL;
+}
+
+static inline int __of_changeset_add_update_property_string_list(
+		struct of_changeset *ocs, struct device_node *np,
+		const char *name, const char **strs, int count, bool update)
+{
+	return -EINVAL;
+}
+
 #endif /* CONFIG_OF_DYNAMIC */
 
+/**
+ * of_changeset_add_property_copy - Create a new property copying name & value
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @value:	pointer to the value data
+ * @length:	length of the value in bytes
+ *
+ * Adds a property to the changeset by making copies of the name & value
+ * entries.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int of_changeset_add_property_copy(struct of_changeset *ocs,
+	struct device_node *np, const char *name,
+	const void *value, int length)
+{
+	return __of_changeset_add_update_property_copy(ocs, np, name, value,
+			length, false);
+}
+
+/**
+ * of_changeset_update_property_copy - Update a property copying name & value
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @value:	pointer to the value data
+ * @length:	length of the value in bytes
+ *
+ * Update a property to the changeset by making copies of the name & value
+ * entries.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int of_changeset_update_property_copy(struct of_changeset *ocs,
+	struct device_node *np, const char *name,
+	const void *value, int length)
+{
+	return __of_changeset_add_update_property_copy(ocs, np, name, value,
+			length, true);
+}
+
+/**
+ * __of_changeset_add_update_property_string - Create/update a string property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @str:	string property value
+ * @update:	True on update operation
+ *
+ * Adds/updates a string property to the changeset by making copies of the name
+ * and the given value. The @update parameter controls whether an add or
+ * update takes place.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int __of_changeset_add_update_property_string(
+	struct of_changeset *ocs, struct device_node *np, const char *name,
+	const char *str, bool update)
+{
+	return __of_changeset_add_update_property_copy(ocs, np, name, str,
+			strlen(str) + 1, update);
+}
+
+/**
+ * __of_changeset_add_update_property_stringv - Create/update a formatted
+ *						string property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @fmt:	format of string property
+ * @vargs:	arguments of the format string
+ * @update:	True on update operation
+ *
+ * Adds/updates a string property to the changeset by making copies of the name
+ * and the formatted value. The @update parameter controls whether an add or
+ * update takes place.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int __of_changeset_add_update_property_stringv(
+	struct of_changeset *ocs, struct device_node *np, const char *name,
+	const char *fmt, va_list vargs, bool update)
+{
+	char *str;
+	int ret;
+
+	str = kvasprintf(GFP_KERNEL, fmt, vargs);
+	if (!str)
+		return -ENOMEM;
+	ret = __of_changeset_add_update_property_string(ocs, np, name, str,
+			update);
+	kfree(str);
+
+	return ret;
+}
+
+/**
+ * of_changeset_add_property_string_list - Create a new string list property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @strs:	pointer to the string list
+ * @count:	string count
+ *
+ * Adds a string list property to the changeset.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int of_changeset_add_property_string_list(
+	struct of_changeset *ocs, struct device_node *np, const char *name,
+	const char **strs, int count)
+{
+	return __of_changeset_add_update_property_string_list(ocs, np, name,
+			strs, count, false);
+}
+
+/**
+ * of_changeset_update_property_string_list - Update string list property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @strs:	pointer to the string list
+ * @count:	string count
+ *
+ * Updates a string list property to the changeset.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int of_changeset_update_property_string_list(
+	struct of_changeset *ocs, struct device_node *np,
+	const char *name, const char **strs, int count)
+{
+	return __of_changeset_add_update_property_string_list(ocs, np, name,
+			strs, count, true);
+}
+
+/**
+ * of_changeset_add_property_string - Adds a string property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @str:	string property
+ *
+ * Adds a string property to the changeset by making copies of the name
+ * and the string value.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int of_changeset_add_property_string(
+	struct of_changeset *ocs, struct device_node *np,
+	const char *name, const char *str)
+{
+	return __of_changeset_add_update_property_string(ocs, np, name, str,
+			false);
+}
+
+/**
+ * of_changeset_update_property_string - Update a string property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @str:	string property
+ *
+ * Updates a string property to the changeset by making copies of the name
+ * and the string value.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int of_changeset_update_property_string(
+	struct of_changeset *ocs, struct device_node *np,
+	const char *name, const char *str)
+{
+	return __of_changeset_add_update_property_string(ocs, np, name, str,
+			true);
+}
+
+/**
+ * of_changeset_add_property_u32 - Create a new u32 property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @val:	value in host endian format
+ *
+ * Adds a u32 property to the changeset.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int of_changeset_add_property_u32(struct of_changeset *ocs,
+		struct device_node *np, const char *name, u32 val)
+{
+	val = cpu_to_be32(val);
+	return __of_changeset_add_update_property_copy(ocs, np, name, &val,
+			sizeof(val), false);
+}
+
+/**
+ * of_changeset_update_property_u32 - Update u32 property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @val:	value in host endian format
+ *
+ * Updates a u32 property to the changeset.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int of_changeset_update_property_u32(
+	struct of_changeset *ocs, struct device_node *np,
+	const char *name, u32 val)
+{
+	val = cpu_to_be32(val);
+	return __of_changeset_add_update_property_copy(ocs, np, name, &val,
+			sizeof(val), true);
+}
+
+/**
+ * of_changeset_add_property_bool - Create a new u32 property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ *
+ * Adds a bool property to the changeset. Note that there is
+ * no option to set the value to false, since the property
+ * existing sets it to true.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int of_changeset_add_property_bool(
+	struct of_changeset *ocs, struct device_node *np, const char *name)
+{
+	return __of_changeset_add_update_property_copy(ocs, np, name, "", 0,
+			false);
+}
+
+/**
+ * of_changeset_update_property_bool - Update a bool property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ *
+ * Updates a property to the changeset. Note that there is
+ * no option to set the value to false, since the property
+ * existing sets it to true.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+static inline int of_changeset_update_property_bool(struct of_changeset *ocs,
+		struct device_node *np, const char *name)
+{
+	return __of_changeset_add_update_property_copy(ocs, np, name, "", 0,
+			true);
+}
+
 /* CONFIG_OF_RESOLVE api */
 extern int of_resolve_phandles(struct device_node *tree);
 
-- 
1.7.12

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/5] of: changeset: Add of_changeset_node_move method
  2016-05-16 16:41 [PATCH v2 0/5] of: dynamic: Changesets helpers & fixes Pantelis Antoniou
  2016-05-16 16:41 ` [PATCH v2 1/5] of: dynamic: Add __of_node_dupv() Pantelis Antoniou
  2016-05-16 16:41 ` [PATCH v2 2/5] of: changesets: Introduce changeset helper methods Pantelis Antoniou
@ 2016-05-16 16:41 ` Pantelis Antoniou
  2016-05-16 16:41 ` [PATCH v2 4/5] of: unittest: changeset helpers Pantelis Antoniou
  2016-05-16 16:41 ` [PATCH v2 5/5] i2c: demux: Use changeset helpers for clarity Pantelis Antoniou
  4 siblings, 0 replies; 8+ messages in thread
From: Pantelis Antoniou @ 2016-05-16 16:41 UTC (permalink / raw)
  To: Rob Herring
  Cc: Frank Rowand, Matt Porter, Koen Kooi, Guenter Roeck, Marek Vasut,
	Wolfram Sang, devicetree, linux-kernel, linux-i2c,
	Pantelis Antoniou, Pantelis Antoniou

Adds a changeset helper for moving a subtree to a different place
in the running tree. This is useful in advances cases of dynamic
device tree construction.

Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
 drivers/of/dynamic.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/of.h   |  9 +++++++
 2 files changed, 75 insertions(+)

diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 83cc801..b07fec2 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -1054,3 +1054,69 @@ int __of_changeset_add_update_property_string_list(
 	return ret;
 }
 EXPORT_SYMBOL_GPL(__of_changeset_add_update_property_string_list);
+
+static struct device_node *
+__of_changeset_node_move_one(struct of_changeset *ocs,
+		struct device_node *np, struct device_node *new_parent)
+{
+	struct device_node *np2;
+	const char *unitname;
+	int err;
+
+	err = of_changeset_detach_node(ocs, np);
+	if (err)
+		return ERR_PTR(err);
+
+	unitname = strrchr(np->full_name, '/');
+	if (!unitname)
+		unitname = np->full_name;
+
+	np2 = __of_node_dup(np, "%s/%s",
+			new_parent->full_name, unitname);
+	if (!np2)
+		return ERR_PTR(-ENOMEM);
+	np2->parent = new_parent;
+
+	err = of_changeset_attach_node(ocs, np2);
+	if (err)
+		return ERR_PTR(err);
+
+	return np2;
+}
+
+/**
+ * of_changeset_node_move_to - Moves a subtree to a new place in
+ *                             the tree
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer to be moved
+ * @to:		device node of the new parent
+ *
+ * Moves a subtree to a new place in the tree.
+ * Note that a move is a safe operation because the phandles
+ * remain valid.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int of_changeset_node_move(struct of_changeset *ocs,
+		struct device_node *np, struct device_node *new_parent)
+{
+	struct device_node *npc, *nppc;
+
+	/* move the root first */
+	nppc = __of_changeset_node_move_one(ocs, np, new_parent);
+	if (IS_ERR(nppc))
+		return PTR_ERR(nppc);
+
+	/* move the subtrees next */
+	for_each_child_of_node(np, npc) {
+		nppc = __of_changeset_node_move_one(ocs, npc, nppc);
+		if (IS_ERR(nppc)) {
+			of_node_put(npc);
+			return PTR_ERR(nppc);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_changeset_node_move);
diff --git a/include/linux/of.h b/include/linux/of.h
index 9df3b71..97ac5c8 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1056,6 +1056,9 @@ int __of_changeset_add_update_property_string_list(
 		struct of_changeset *ocs, struct device_node *np,
 		const char *name, const char **strs, int count, bool update);
 
+int of_changeset_node_move(struct of_changeset *ocs,
+	struct device_node *np, struct device_node *new_parent);
+
 #else /* CONFIG_OF_DYNAMIC */
 static inline int of_reconfig_notifier_register(struct notifier_block *nb)
 {
@@ -1118,6 +1121,12 @@ static inline int __of_changeset_add_update_property_string_list(
 	return -EINVAL;
 }
 
+static inline int of_changeset_node_move(struct of_changeset *ocs,
+		struct device_node *np, struct device_node *new_parent)
+{
+	return -EINVAL;
+}
+
 #endif /* CONFIG_OF_DYNAMIC */
 
 /**
-- 
1.7.12

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/5] of: unittest: changeset helpers
  2016-05-16 16:41 [PATCH v2 0/5] of: dynamic: Changesets helpers & fixes Pantelis Antoniou
                   ` (2 preceding siblings ...)
  2016-05-16 16:41 ` [PATCH v2 3/5] of: changeset: Add of_changeset_node_move method Pantelis Antoniou
@ 2016-05-16 16:41 ` Pantelis Antoniou
  2016-05-16 16:41 ` [PATCH v2 5/5] i2c: demux: Use changeset helpers for clarity Pantelis Antoniou
  4 siblings, 0 replies; 8+ messages in thread
From: Pantelis Antoniou @ 2016-05-16 16:41 UTC (permalink / raw)
  To: Rob Herring
  Cc: Frank Rowand, Matt Porter, Koen Kooi, Guenter Roeck, Marek Vasut,
	Wolfram Sang, devicetree, linux-kernel, linux-i2c,
	Pantelis Antoniou, Pantelis Antoniou

Add a unitest specific for the new changeset helpers.

Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
 drivers/of/unittest.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index e986e6e..ff6939b 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -543,6 +543,59 @@ static void __init of_unittest_changeset(void)
 #endif
 }
 
+static void __init of_unittest_changeset_helper(void)
+{
+#ifdef CONFIG_OF_DYNAMIC
+	struct device_node *n1, *n2, *n21, *parent, *np;
+	struct of_changeset chgset;
+
+	of_changeset_init(&chgset);
+
+	parent = of_find_node_by_path("/testcase-data/changeset");
+
+	unittest(parent, "testcase setup failure\n");
+	n1 = of_changeset_create_device_node(&chgset,
+			parent, "/testcase-data/changeset/n1");
+	unittest(n1, "testcase setup failure\n");
+	n2 = of_changeset_create_device_node(&chgset,
+			parent, "/testcase-data/changeset/n2");
+	unittest(n2, "testcase setup failure\n");
+	n21 = of_changeset_create_device_node(&chgset, n2, "%s/%s",
+			"/testcase-data/changeset/n2", "n21");
+	unittest(n21, "testcase setup failure\n");
+
+	unittest(!of_changeset_add_property_string(&chgset, parent,
+				"prop-add", "foo"), "fail add prop\n");
+
+	unittest(!of_changeset_attach_node(&chgset, n1), "fail n1 attach\n");
+	unittest(!of_changeset_attach_node(&chgset, n2), "fail n2 attach\n");
+	unittest(!of_changeset_attach_node(&chgset, n21), "fail n21 attach\n");
+
+	unittest(!of_changeset_apply(&chgset), "apply failed\n");
+
+	/* Make sure node names are constructed correctly */
+	np = of_find_node_by_path("/testcase-data/changeset/n1");
+	unittest(np, "'%s' not added\n", n1->full_name);
+	of_node_put(np);
+
+	/* Make sure node names are constructed correctly */
+	np = of_find_node_by_path("/testcase-data/changeset/n2");
+	unittest(np, "'%s' not added\n", n2->full_name);
+	of_node_put(np);
+
+	np = of_find_node_by_path("/testcase-data/changeset/n2/n21");
+	unittest(np, "'%s' not added\n", n21->full_name);
+	of_node_put(np);
+
+	unittest(!of_changeset_revert(&chgset), "revert failed\n");
+
+	of_changeset_destroy(&chgset);
+
+	of_node_put(parent);
+#endif
+}
+
+
 static void __init of_unittest_parse_interrupts(void)
 {
 	struct device_node *np;
@@ -1969,6 +2022,7 @@ static int __init of_unittest(void)
 	of_unittest_property_string();
 	of_unittest_property_copy();
 	of_unittest_changeset();
+	of_unittest_changeset_helper();
 	of_unittest_parse_interrupts();
 	of_unittest_parse_interrupts_extended();
 	of_unittest_match_node();
-- 
1.7.12

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 5/5] i2c: demux: Use changeset helpers for clarity
  2016-05-16 16:41 [PATCH v2 0/5] of: dynamic: Changesets helpers & fixes Pantelis Antoniou
                   ` (3 preceding siblings ...)
  2016-05-16 16:41 ` [PATCH v2 4/5] of: unittest: changeset helpers Pantelis Antoniou
@ 2016-05-16 16:41 ` Pantelis Antoniou
  2016-05-26 18:58   ` Wolfram Sang
  4 siblings, 1 reply; 8+ messages in thread
From: Pantelis Antoniou @ 2016-05-16 16:41 UTC (permalink / raw)
  To: Rob Herring
  Cc: Frank Rowand, Matt Porter, Koen Kooi, Guenter Roeck, Marek Vasut,
	Wolfram Sang, devicetree, linux-kernel, linux-i2c,
	Pantelis Antoniou, Pantelis Antoniou

The changeset helpers are easier to use, use them instead of
using the static property.

Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
 drivers/i2c/muxes/i2c-demux-pinctrl.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c
index 8de073a..ddaca9e 100644
--- a/drivers/i2c/muxes/i2c-demux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c
@@ -37,8 +37,6 @@ struct i2c_demux_pinctrl_priv {
 	struct i2c_demux_pinctrl_chan chan[];
 };
 
-static struct property status_okay = { .name = "status", .length = 3, .value = "ok" };
-
 static int i2c_demux_master_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
 	struct i2c_demux_pinctrl_priv *priv = adap->algo_data;
@@ -219,7 +217,8 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev)
 		priv->chan[i].parent_np = adap_np;
 
 		of_changeset_init(&priv->chan[i].chgset);
-		of_changeset_update_property(&priv->chan[i].chgset, adap_np, &status_okay);
+		of_changeset_update_property_string(&priv->chan[i].chgset,
+				adap_np, "status", "okay");
 	}
 
 	priv->num_chan = num_chan;
-- 
1.7.12

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/5] of: changesets: Introduce changeset helper methods
  2016-05-16 16:41 ` [PATCH v2 2/5] of: changesets: Introduce changeset helper methods Pantelis Antoniou
@ 2016-05-17 10:25   ` Peter Rosin
  0 siblings, 0 replies; 8+ messages in thread
From: Peter Rosin @ 2016-05-17 10:25 UTC (permalink / raw)
  To: Pantelis Antoniou, Rob Herring
  Cc: Frank Rowand, Matt Porter, Koen Kooi, Guenter Roeck, Marek Vasut,
	Wolfram Sang, devicetree, linux-kernel, linux-i2c,
	Pantelis Antoniou

Hi!

I found a resource management bug in this patch.

Cheers,
Peter

On 2016-05-16 18:41, Pantelis Antoniou wrote:
> Changesets are very powerful, but the lack of a helper API
> makes using them cumbersome. Introduce a simple copy based
> API that makes things considerably easier.
> 
> To wit, adding a property using the raw API.
> 
> 	struct property *prop;
> 	prop = kzalloc(sizeof(*prop)), GFP_KERNEL);
> 	prop->name = kstrdup("compatible");
> 	prop->value = kstrdup("foo,bar");
> 	prop->length = strlen(prop->value) + 1;
> 	of_changeset_add_property(ocs, np, prop);
> 
> while using the helper API
> 
> 	of_changeset_add_property_string(ocs, np, "compatible",
> 			"foo,bar");
> 
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
> ---
>  drivers/of/dynamic.c | 226 +++++++++++++++++++++++++++++++++++
>  include/linux/of.h   | 328 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 554 insertions(+)
> 
> diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
> index e4dea94..83cc801 100644
> --- a/drivers/of/dynamic.c
> +++ b/drivers/of/dynamic.c
> @@ -828,3 +828,229 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action,
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(of_changeset_action);
> +
> +/* changeset helpers */
> +
> +/**
> + * of_changeset_create_device_node - Create an empty device node
> + *
> + * @ocs:	changeset pointer
> + * @parent:	parent device node
> + * @fmt:	format string for the node's full_name
> + * @args:	argument list for the format string
> + *
> + * Create an empty device node, marking it as detached and allocated.
> + *
> + * Returns a device node on success, an error encoded pointer otherwise
> + */
> +struct device_node *of_changeset_create_device_nodev(
> +	struct of_changeset *ocs, struct device_node *parent,
> +	const char *fmt, va_list vargs)
> +{
> +	struct device_node *node;
> +
> +	node = __of_node_dupv(NULL, fmt, vargs);
> +	if (!node)
> +		return ERR_PTR(-ENOMEM);
> +
> +	node->parent = parent;
> +	return node;
> +}
> +EXPORT_SYMBOL_GPL(of_changeset_create_device_nodev);
> +
> +/**
> + * of_changeset_create_device_node - Create an empty device node
> + *
> + * @ocs:	changeset pointer
> + * @parent:	parent device node
> + * @fmt:	Format string for the node's full_name
> + * ...		Arguments
> + *
> + * Create an empty device node, marking it as detached and allocated.
> + *
> + * Returns a device node on success, an error encoded pointer otherwise
> + */
> +__printf(3, 4) struct device_node *
> +of_changeset_create_device_node(struct of_changeset *ocs,
> +	struct device_node *parent, const char *fmt, ...)
> +{
> +	va_list vargs;
> +	struct device_node *node;
> +
> +	va_start(vargs, fmt);
> +	node = of_changeset_create_device_nodev(ocs, parent, fmt, vargs);
> +	va_end(vargs);
> +	return node;
> +}
> +EXPORT_SYMBOL_GPL(of_changeset_create_device_node);
> +
> +/**
> + * __of_changeset_add_property_copy - Create/update a new property copying
> + *                                    name & value
> + *
> + * @ocs:	changeset pointer
> + * @np:		device node pointer
> + * @name:	name of the property
> + * @value:	pointer to the value data
> + * @length:	length of the value in bytes
> + * @update:	True on update operation
> + *
> + * Adds/updates a property to the changeset by making copies of the name & value
> + * entries. The @update parameter controls whether an add or update takes place.
> + *
> + * Returns zero on success, a negative error value otherwise.
> + */
> +int __of_changeset_add_update_property_copy(struct of_changeset *ocs,
> +		struct device_node *np, const char *name, const void *value,
> +		int length, bool update)
> +{
> +	struct property *prop;
> +	char *new_name;
> +	void *new_value;
> +	int ret = -ENOMEM;
> +
> +	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> +	if (!prop)
> +		return -ENOMEM;
> +
> +	new_name = kstrdup(name, GFP_KERNEL);
> +	if (!new_name)
> +		goto out_err;
> +
> +	/*
> +	 * NOTE: There is no check for zero length value.
> +	 * In case of a boolean property, this will allocate a value
> +	 * of zero bytes. We do this to work around the use
> +	 * of of_get_property() calls on boolean values.
> +	 */
> +	new_value = kmemdup(value, length, GFP_KERNEL);
> +	if (!new_value)

You leak new_name here.

> +		goto out_err;
> +
> +	of_property_set_flag(prop, OF_DYNAMIC);
> +
> +	prop->name = new_name;
> +	prop->value = new_value;
> +	prop->length = length;
> +
> +	if (!update)
> +		ret = of_changeset_add_property(ocs, np, prop);
> +	else
> +		ret = of_changeset_update_property(ocs, np, prop);
> +
> +	if (!ret)
> +		return 0;
> +
> +out_err:
> +	kfree(prop->value);
> +	kfree(prop->name);
> +	kfree(prop);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(__of_changeset_add_update_property_copy);

*snip*

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 5/5] i2c: demux: Use changeset helpers for clarity
  2016-05-16 16:41 ` [PATCH v2 5/5] i2c: demux: Use changeset helpers for clarity Pantelis Antoniou
@ 2016-05-26 18:58   ` Wolfram Sang
  0 siblings, 0 replies; 8+ messages in thread
From: Wolfram Sang @ 2016-05-26 18:58 UTC (permalink / raw)
  To: Pantelis Antoniou
  Cc: Rob Herring, Frank Rowand, Matt Porter, Koen Kooi, Guenter Roeck,
	Marek Vasut, devicetree, linux-kernel, linux-i2c,
	Pantelis Antoniou

[-- Attachment #1: Type: text/plain, Size: 409 bytes --]

On Mon, May 16, 2016 at 07:41:28PM +0300, Pantelis Antoniou wrote:
> The changeset helpers are easier to use, use them instead of
> using the static property.
> 
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>

If you think this is worthwhile, then it's fine with me :)

Acked-by: Wolfram Sang <wsa@the-dreams.de>

> +				adap_np, "status", "okay");

"ok" would be shorter?


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-05-26 18:58 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-16 16:41 [PATCH v2 0/5] of: dynamic: Changesets helpers & fixes Pantelis Antoniou
2016-05-16 16:41 ` [PATCH v2 1/5] of: dynamic: Add __of_node_dupv() Pantelis Antoniou
2016-05-16 16:41 ` [PATCH v2 2/5] of: changesets: Introduce changeset helper methods Pantelis Antoniou
2016-05-17 10:25   ` Peter Rosin
2016-05-16 16:41 ` [PATCH v2 3/5] of: changeset: Add of_changeset_node_move method Pantelis Antoniou
2016-05-16 16:41 ` [PATCH v2 4/5] of: unittest: changeset helpers Pantelis Antoniou
2016-05-16 16:41 ` [PATCH v2 5/5] i2c: demux: Use changeset helpers for clarity Pantelis Antoniou
2016-05-26 18:58   ` Wolfram Sang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).