diff mbox series

[1/3] software node: implement reference properties

Message ID 20190906043809.18990-1-dmitry.torokhov@gmail.com (mailing list archive)
State Deferred, archived
Headers show
Series [1/3] software node: implement reference properties | expand

Commit Message

Dmitry Torokhov Sept. 6, 2019, 4:38 a.m. UTC
It is possible to store references to software nodes in the same fashion as
other static properties, so that users do not need to define separate
structures:

const struct software_node gpio_bank_b_node = {
	.name = "B",
};

const struct property_entry simone_key_enter_props[] __initconst = {
	PROPERTY_ENTRY_U32("linux,code", KEY_ENTER),
	PROPERTY_ENTRY_STRING("label", "enter"),
	PROPERTY_ENTRY_REF("gpios", &gpio_bank_b_node, 123, GPIO_ACTIVE_LOW),
	{ }
};

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/base/swnode.c    | 34 +++++++++++++++++++------
 include/linux/property.h | 54 +++++++++++++++++++++++++++++-----------
 2 files changed, 65 insertions(+), 23 deletions(-)

Comments

Heikki Krogerus Sept. 6, 2019, 11:17 a.m. UTC | #1
On Thu, Sep 05, 2019 at 09:38:07PM -0700, Dmitry Torokhov wrote:
> It is possible to store references to software nodes in the same fashion as
> other static properties, so that users do not need to define separate
> structures:
> 
> const struct software_node gpio_bank_b_node = {
> 	.name = "B",
> };
> 
> const struct property_entry simone_key_enter_props[] __initconst = {
> 	PROPERTY_ENTRY_U32("linux,code", KEY_ENTER),
> 	PROPERTY_ENTRY_STRING("label", "enter"),
> 	PROPERTY_ENTRY_REF("gpios", &gpio_bank_b_node, 123, GPIO_ACTIVE_LOW),
> 	{ }
> };
> 
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

This looks really good to me. I'll wait for Andy's comments on the
idea, but to me it makes sense.

Thanks Dmitry!
Andy Shevchenko Sept. 6, 2019, 12:27 p.m. UTC | #2
On Thu, Sep 05, 2019 at 09:38:07PM -0700, Dmitry Torokhov wrote:
> It is possible to store references to software nodes in the same fashion as
> other static properties, so that users do not need to define separate
> structures:
> 
> const struct software_node gpio_bank_b_node = {
> 	.name = "B",
> };

Why this can't be __initconst?

> const struct property_entry simone_key_enter_props[] __initconst = {
> 	PROPERTY_ENTRY_U32("linux,code", KEY_ENTER),
> 	PROPERTY_ENTRY_STRING("label", "enter"),
> 	PROPERTY_ENTRY_REF("gpios", &gpio_bank_b_node, 123, GPIO_ACTIVE_LOW),
> 	{ }
> };

So it's basically mimics the concept of phandle, right?

> +		ref_args = prop->is_array ?
> +				&prop->pointer.ref[index] : &prop->value.ref;

Better to do if with explicit 'if ()' as it's done in the rest of the code.

	if (prop->is_array)
		ref_args = ...;
	else
		ref_args = ...;

> -	DEV_PROP_MAX,
> +	DEV_PROP_MAX

It seems it wasn't ever used, so, can be dropped completely.

> @@ -240,6 +255,7 @@ struct property_entry {
>  			const u32 *u32_data;
>  			const u64 *u64_data;
>  			const char * const *str;
> +			const struct software_node_ref_args *ref;
>  		} pointer;
>  		union {
>  			u8 u8_data;
> @@ -247,6 +263,7 @@ struct property_entry {
>  			u32 u32_data;
>  			u64 u64_data;
>  			const char *str;
> +			struct software_node_ref_args ref;

Hmm... This bumps the size of union a lot for each existing property_entry.
Is there any other way? Maybe we can keep pointer and allocate memory for it
when copying?

>  		} value;

> +#define PROPERTY_ENTRY_REF_ARRAY(_name_, _val_)			\
> +(struct property_entry) {					\
> +	.name = _name_,						\
> +	.length = ARRAY_SIZE(_val_) *				\
> +			sizeof(struct software_node_ref_args),	\

I would rather leave it on one line and shift right all \:s in this macro.

> +	.is_array = true,					\
> +	.type = DEV_PROP_REF,					\
> +	.pointer.ref = _val_,					\
> +}
> +

> +#define PROPERTY_ENTRY_REF(_name_, _ref_, ...)			\
> +(struct property_entry) {					\
> +	.name = _name_,						\
> +	.length = sizeof(struct software_node_ref_args),	\
> +	.type = DEV_PROP_REF,					\
> +	.value.ref.node = _ref_,				\

> +	.value.ref.nargs =					\
> +		ARRAY_SIZE(((u64[]){ 0, ##__VA_ARGS__ })) - 1,	\

Ditto.

> +	.value.ref.args = { __VA_ARGS__ },			\
> +}
Andy Shevchenko Sept. 6, 2019, 12:40 p.m. UTC | #3
On Fri, Sep 06, 2019 at 02:17:44PM +0300, Heikki Krogerus wrote:
> On Thu, Sep 05, 2019 at 09:38:07PM -0700, Dmitry Torokhov wrote:
> > It is possible to store references to software nodes in the same fashion as
> > other static properties, so that users do not need to define separate
> > structures:
> > 
> > const struct software_node gpio_bank_b_node = {
> > 	.name = "B",
> > };
> > 
> > const struct property_entry simone_key_enter_props[] __initconst = {
> > 	PROPERTY_ENTRY_U32("linux,code", KEY_ENTER),
> > 	PROPERTY_ENTRY_STRING("label", "enter"),
> > 	PROPERTY_ENTRY_REF("gpios", &gpio_bank_b_node, 123, GPIO_ACTIVE_LOW),
> > 	{ }
> > };
> > 
> > Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> 
> This looks really good to me. I'll wait for Andy's comments on the
> idea, but to me it makes sense.

Idea in general is fine. Though, taking into consideration, for example,
drivers/mfd/intel-lpss-pci.c, the size of predefined structures bumps a lot.
I think we always should keep a pointer. In this case we may not add another
property type.
Heikki Krogerus Sept. 6, 2019, 1:31 p.m. UTC | #4
On Fri, Sep 06, 2019 at 03:40:43PM +0300, Andy Shevchenko wrote:
> On Fri, Sep 06, 2019 at 02:17:44PM +0300, Heikki Krogerus wrote:
> > On Thu, Sep 05, 2019 at 09:38:07PM -0700, Dmitry Torokhov wrote:
> > > It is possible to store references to software nodes in the same fashion as
> > > other static properties, so that users do not need to define separate
> > > structures:
> > > 
> > > const struct software_node gpio_bank_b_node = {
> > > 	.name = "B",
> > > };
> > > 
> > > const struct property_entry simone_key_enter_props[] __initconst = {
> > > 	PROPERTY_ENTRY_U32("linux,code", KEY_ENTER),
> > > 	PROPERTY_ENTRY_STRING("label", "enter"),
> > > 	PROPERTY_ENTRY_REF("gpios", &gpio_bank_b_node, 123, GPIO_ACTIVE_LOW),
> > > 	{ }
> > > };
> > > 
> > > Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > 
> > This looks really good to me. I'll wait for Andy's comments on the
> > idea, but to me it makes sense.
> 
> Idea in general is fine. Though, taking into consideration, for example,
> drivers/mfd/intel-lpss-pci.c, the size of predefined structures bumps a lot.
> I think we always should keep a pointer. In this case we may not add another
> property type.

Yeah, you have a point.

thanks,
Dmitry Torokhov Sept. 6, 2019, 10:34 p.m. UTC | #5
On Fri, Sep 06, 2019 at 03:27:43PM +0300, Andy Shevchenko wrote:
> On Thu, Sep 05, 2019 at 09:38:07PM -0700, Dmitry Torokhov wrote:
> > It is possible to store references to software nodes in the same fashion as
> > other static properties, so that users do not need to define separate
> > structures:
> > 
> > const struct software_node gpio_bank_b_node = {
> > 	.name = "B",
> > };
> 
> Why this can't be __initconst?

It may or it may not. I'll remove __inticonst from below as well to not
confuse things.

> 
> > const struct property_entry simone_key_enter_props[] __initconst = {
> > 	PROPERTY_ENTRY_U32("linux,code", KEY_ENTER),
> > 	PROPERTY_ENTRY_STRING("label", "enter"),
> > 	PROPERTY_ENTRY_REF("gpios", &gpio_bank_b_node, 123, GPIO_ACTIVE_LOW),
> > 	{ }
> > };
> 
> So it's basically mimics the concept of phandle, right?

Yes.

> 
> > +		ref_args = prop->is_array ?
> > +				&prop->pointer.ref[index] : &prop->value.ref;
> 
> Better to do if with explicit 'if ()' as it's done in the rest of the code.
> 
> 	if (prop->is_array)
> 		ref_args = ...;
> 	else
> 		ref_args = ...;

OK, it will be gone actually.

> 
> > -	DEV_PROP_MAX,
> > +	DEV_PROP_MAX
> 
> It seems it wasn't ever used, so, can be dropped completely.

OK.

> 
> > @@ -240,6 +255,7 @@ struct property_entry {
> >  			const u32 *u32_data;
> >  			const u64 *u64_data;
> >  			const char * const *str;
> > +			const struct software_node_ref_args *ref;
> >  		} pointer;
> >  		union {
> >  			u8 u8_data;
> > @@ -247,6 +263,7 @@ struct property_entry {
> >  			u32 u32_data;
> >  			u64 u64_data;
> >  			const char *str;
> > +			struct software_node_ref_args ref;
> 
> Hmm... This bumps the size of union a lot for each existing property_entry.
> Is there any other way? Maybe we can keep pointer and allocate memory for it
> when copying?

Right, I think we can always store references as arrays, even when we
only need single entry, thus we do not need to increase the size of the
structure.

I just posted v2 implementing that, please take another look.

Thanks.
diff mbox series

Patch

diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index e7b3aa3bd55a..01325705b8e4 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -568,21 +568,39 @@  software_node_get_reference_args(const struct fwnode_handle *fwnode,
 {
 	struct swnode *swnode = to_swnode(fwnode);
 	const struct software_node_reference *ref;
+	const struct software_node_ref_args *ref_args;
 	const struct property_entry *prop;
 	struct fwnode_handle *refnode;
 	int i;
 
-	if (!swnode || !swnode->node->references)
+	if (!swnode)
 		return -ENOENT;
 
-	for (ref = swnode->node->references; ref->name; ref++)
-		if (!strcmp(ref->name, propname))
-			break;
+	prop = property_entry_get(swnode->node->properties, propname);
+	if (prop) {
+		if (prop->type != DEV_PROP_REF)
+			return -EINVAL;
 
-	if (!ref->name || index > (ref->nrefs - 1))
-		return -ENOENT;
+		if (index * sizeof(*ref_args) >= prop->length)
+			return -ENOENT;
+
+		ref_args = prop->is_array ?
+				&prop->pointer.ref[index] : &prop->value.ref;
+	} else {
+		if (!swnode->node->references)
+			return -ENOENT;
+
+		for (ref = swnode->node->references; ref->name; ref++)
+			if (!strcmp(ref->name, propname))
+				break;
+
+		if (!ref->name || index > (ref->nrefs - 1))
+			return -ENOENT;
+
+		ref_args = &ref->refs[index];
+	}
 
-	refnode = software_node_fwnode(ref->refs[index].node);
+	refnode = software_node_fwnode(ref_args->node);
 	if (!refnode)
 		return -ENOENT;
 
@@ -601,7 +619,7 @@  software_node_get_reference_args(const struct fwnode_handle *fwnode,
 	args->nargs = nargs;
 
 	for (i = 0; i < nargs; i++)
-		args->args[i] = ref->refs[index].args[i];
+		args->args[i] = ref_args->args[i];
 
 	return 0;
 }
diff --git a/include/linux/property.h b/include/linux/property.h
index 5a910ad79591..b25440344743 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -22,7 +22,8 @@  enum dev_prop_type {
 	DEV_PROP_U32,
 	DEV_PROP_U64,
 	DEV_PROP_STRING,
-	DEV_PROP_MAX,
+	DEV_PROP_REF,
+	DEV_PROP_MAX
 };
 
 enum dev_dma_attr {
@@ -219,6 +220,20 @@  static inline int fwnode_property_count_u64(const struct fwnode_handle *fwnode,
 	return fwnode_property_read_u64_array(fwnode, propname, NULL, 0);
 }
 
+struct software_node;
+
+/**
+ * struct software_node_ref_args - Reference property with additional arguments
+ * @node: Reference to a software node
+ * @nargs: Number of elements in @args array
+ * @args: Integer arguments
+ */
+struct software_node_ref_args {
+	const struct software_node *node;
+	unsigned int nargs;
+	u64 args[NR_FWNODE_REFERENCE_ARGS];
+};
+
 /**
  * struct property_entry - "Built-in" device property representation.
  * @name: Name of the property.
@@ -240,6 +255,7 @@  struct property_entry {
 			const u32 *u32_data;
 			const u64 *u64_data;
 			const char * const *str;
+			const struct software_node_ref_args *ref;
 		} pointer;
 		union {
 			u8 u8_data;
@@ -247,6 +263,7 @@  struct property_entry {
 			u32 u32_data;
 			u64 u64_data;
 			const char *str;
+			struct software_node_ref_args ref;
 		} value;
 	};
 };
@@ -284,6 +301,16 @@  struct property_entry {
 	{ .pointer = { .str = _val_ } },			\
 }
 
+#define PROPERTY_ENTRY_REF_ARRAY(_name_, _val_)			\
+(struct property_entry) {					\
+	.name = _name_,						\
+	.length = ARRAY_SIZE(_val_) *				\
+			sizeof(struct software_node_ref_args),	\
+	.is_array = true,					\
+	.type = DEV_PROP_REF,					\
+	.pointer.ref = _val_,					\
+}
+
 #define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_)	\
 (struct property_entry) {					\
 	.name = _name_,						\
@@ -314,6 +341,17 @@  struct property_entry {
 	.name = _name_,				\
 }
 
+#define PROPERTY_ENTRY_REF(_name_, _ref_, ...)			\
+(struct property_entry) {					\
+	.name = _name_,						\
+	.length = sizeof(struct software_node_ref_args),	\
+	.type = DEV_PROP_REF,					\
+	.value.ref.node = _ref_,				\
+	.value.ref.nargs =					\
+		ARRAY_SIZE(((u64[]){ 0, ##__VA_ARGS__ })) - 1,	\
+	.value.ref.args = { __VA_ARGS__ },			\
+}
+
 struct property_entry *
 property_entries_dup(const struct property_entry *properties);
 
@@ -377,20 +415,6 @@  int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
 /* -------------------------------------------------------------------------- */
 /* Software fwnode support - when HW description is incomplete or missing */
 
-struct software_node;
-
-/**
- * struct software_node_ref_args - Reference with additional arguments
- * @node: Reference to a software node
- * @nargs: Number of elements in @args array
- * @args: Integer arguments
- */
-struct software_node_ref_args {
-	const struct software_node *node;
-	unsigned int nargs;
-	u64 args[NR_FWNODE_REFERENCE_ARGS];
-};
-
 /**
  * struct software_node_reference - Named software node reference property
  * @name: Name of the property