Skip to contentSkip to conversation

software node: add support for reference properties

PATCH Superseded Dmitry Torokhov 2 participants 46 messages Oct 11, 2019 – Oct 17, 2019

Subsystems (5)

v5 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v5 cover software node: add support for reference properties

These series implement "references" properties for software nodes as true properties, instead of managing them completely separately.

The first 10 patches are generic cleanups and consolidation and unification of the existing code; patch #11 implements moving of small properties inline when copying property entries; patch #12 implements PROPERTY_ENTRY_REF() and friends; patch #13 converts the user of references to the property syntax, and patch #14 removes the remains of references as entities that are managed separately.

Changes in v5:
- rebased onto next-20191011

Changes in v4:
- dealt with union aliasing concerns
- inline small properties on copy

Changes in v3:
- added various cleanups before implementing reference properties

Changes in v2:
- reworked code so that even single-entry reference properties are stored as arrays (i.e. the software_node_ref_args instances are not part of property_entry structure) to avoid size increase. From user's POV nothing is changed, one can still use PROPERTY_ENTRY_REF macro to define reference "inline".
- dropped unused DEV_PROP_MAX
- rebased on linux-next

Dmitry Torokhov (14):
software node: remove DEV_PROP_MAX
software node: introduce PROPERTY_ENTRY_ARRAY_XXX_LEN() efi/apple-properties: use PROPERTY_ENTRY_U8_ARRAY_LEN software node: mark internal macros with double underscores software node: clean up property_copy_string_array() software node: get rid of property_set_pointer() software node: remove property_entry_read_uNN_array functions software node: unify PROPERTY_ENTRY_XXX macros software node: simplify property_entry_read_string_array() software node: rename is_array to is_inline
software node: move small properties inline when copying software node: implement reference properties platform/x86: intel_cht_int33fe: use inline reference properties software node: remove separate handling of references

 drivers/base/swnode.c                    | 266 ++++++++---------------
 drivers/firmware/efi/apple-properties.c  |  18 +-
 drivers/platform/x86/intel_cht_int33fe.c |  81 +++----
 include/linux/property.h                 | 177 +++++++--------
 4 files changed, 230 insertions(+), 312 deletions(-)
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#1 lore raw

PATCH v5 1/14 software node: remove DEV_PROP_MAX

This definition is not used anywhere, let's remove it.

---
 include/linux/property.h | 1 -
 1 file changed, 1 deletion(-)
include/linux/property.h +0 -1
index 9b3d4ca3a73a..44c1704f7163 100644
@@ -22,7 +22,6 @@ enum dev_prop_type {
 	DEV_PROP_U32,
 	DEV_PROP_U64,
 	DEV_PROP_STRING,
-	DEV_PROP_MAX,
 };
 
 enum dev_dma_attr {
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#2 lore raw

PATCH v5 2/14 software node: introduce PROPERTY_ENTRY_ARRAY_XXX_LEN()

In reply to Dmitry Torokhov

Sometimes we want to initialize property entry array from a regular pointer, when we can't determine length automatically via ARRAY_SIZE. Let's introduce PROPERTY_ENTRY_ARRAY_XXX_LEN macros that take explicit "len" argument.

---
 include/linux/property.h | 45 +++++++++++++++++++++++++---------------
 1 file changed, 28 insertions(+), 17 deletions(-)
include/linux/property.h +28 -17
index 44c1704f7163..f89b930ca4b7 100644
@@ -256,33 +256,44 @@ struct property_entry {
  * and structs.
  */
 
-#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _Type_, _val_)	\
+#define PROPERTY_ENTRY_ARRAY_LEN(_name_, _type_, _Type_, _val_, _len_)	\
 (struct property_entry) {						\
 	.name = _name_,							\
-	.length = ARRAY_SIZE(_val_) * sizeof(_type_),			\
+	.length = (_len_) * sizeof(_type_),				\
 	.is_array = true,						\
 	.type = DEV_PROP_##_Type_,					\
 	{ .pointer = { ._type_##_data = _val_ } },			\
 }
 
-#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_)			\
-	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, U8, _val_)
-#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_)			\
-	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, U16, _val_)
-#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_)			\
-	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, U32, _val_)
-#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_)			\
-	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, U64, _val_)
+#define PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, _len_)		\
+	PROPERTY_ENTRY_ARRAY_LEN(_name_, u8, U8, _val_, _len_)
+#define PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, _len_)		\
+	PROPERTY_ENTRY_ARRAY_LEN(_name_, u16, U16, _val_, _len_)
+#define PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, _len_)		\
+	PROPERTY_ENTRY_ARRAY_LEN(_name_, u32, U32, _val_, _len_)
+#define PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, _len_)		\
+	PROPERTY_ENTRY_ARRAY_LEN(_name_, u64, U64, _val_, _len_)
 
-#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_)		\
-(struct property_entry) {					\
-	.name = _name_,						\
-	.length = ARRAY_SIZE(_val_) * sizeof(const char *),	\
-	.is_array = true,					\
-	.type = DEV_PROP_STRING,				\
-	{ .pointer = { .str = _val_ } },			\
+#define PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, _len_)		\
+(struct property_entry) {						\
+	.name = _name_,							\
+	.length = (_len_) * sizeof(const char *),			\
+	.is_array = true,						\
+	.type = DEV_PROP_STRING,					\
+	{ .pointer = { .str = _val_ } },				\
 }
 
+#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_)				\
+	PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
+#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_)				\
+	PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
+#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_)				\
+	PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
+#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_)				\
+	PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
+#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_)			\
+	PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
+
 #define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_)	\
 (struct property_entry) {					\
 	.name = _name_,						\
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
reviewer Reviewed-by on v5 2/14
#3 lore raw

Re: [PATCH v5 02/14] software node: introduce PROPERTY_ENTRY_ARRAY_XXX_LEN()

Quoted 4 lines · Dmitry Torokhov

Sometimes we want to initialize property entry array from a regular pointer, when we can't determine length automatically via ARRAY_SIZE. Let's introduce PROPERTY_ENTRY_ARRAY_XXX_LEN macros that take explicit "len" argument.

Quoted 74 lines
---
 include/linux/property.h | 45 +++++++++++++++++++++++++---------------
 1 file changed, 28 insertions(+), 17 deletions(-)
include/linux/property.h +28 -17
index 44c1704f7163..f89b930ca4b7 100644
@@ -256,33 +256,44 @@ struct property_entry {
  * and structs.
  */
 
-#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _Type_, _val_)	\
+#define PROPERTY_ENTRY_ARRAY_LEN(_name_, _type_, _Type_, _val_, _len_)	\
 (struct property_entry) {						\
 	.name = _name_,							\
-	.length = ARRAY_SIZE(_val_) * sizeof(_type_),			\
+	.length = (_len_) * sizeof(_type_),				\
 	.is_array = true,						\
 	.type = DEV_PROP_##_Type_,					\
 	{ .pointer = { ._type_##_data = _val_ } },			\
 }
 
-#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_)			\
-	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, U8, _val_)
-#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_)			\
-	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, U16, _val_)
-#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_)			\
-	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, U32, _val_)
-#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_)			\
-	PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, U64, _val_)
+#define PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, _len_)		\
+	PROPERTY_ENTRY_ARRAY_LEN(_name_, u8, U8, _val_, _len_)
+#define PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, _len_)		\
+	PROPERTY_ENTRY_ARRAY_LEN(_name_, u16, U16, _val_, _len_)
+#define PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, _len_)		\
+	PROPERTY_ENTRY_ARRAY_LEN(_name_, u32, U32, _val_, _len_)
+#define PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, _len_)		\
+	PROPERTY_ENTRY_ARRAY_LEN(_name_, u64, U64, _val_, _len_)
 
-#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_)		\
-(struct property_entry) {					\
-	.name = _name_,						\
-	.length = ARRAY_SIZE(_val_) * sizeof(const char *),	\
-	.is_array = true,					\
-	.type = DEV_PROP_STRING,				\
-	{ .pointer = { .str = _val_ } },			\
+#define PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, _len_)		\
+(struct property_entry) {						\
+	.name = _name_,							\
+	.length = (_len_) * sizeof(const char *),			\
+	.is_array = true,						\
+	.type = DEV_PROP_STRING,					\
+	{ .pointer = { .str = _val_ } },				\
 }
 
+#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_)				\
+	PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
+#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_)				\
+	PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
+#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_)				\
+	PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
+#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_)				\
+	PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
+#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_)			\
+	PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
+
 #define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_)	\
 (struct property_entry) {					\
 	.name = _name_,						\
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#4 lore raw

PATCH v5 3/14 efi/apple-properties: use PROPERTY_ENTRY_U8_ARRAY_LEN

In reply to Dmitry Torokhov

Let's switch to using PROPERTY_ENTRY_U8_ARRAY_LEN() to initialize property entries. Also, when dumping data, rely on local variables instead of poking into the property entry structure directly.

---
 drivers/firmware/efi/apple-properties.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)
drivers/firmware/efi/apple-properties.c +8 -10
index 0e206c9e0d7a..5ccf39986a14 100644
@@ -53,7 +53,8 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
 
 	for (i = 0; i < dev_header->prop_count; i++) {
 		int remaining = dev_header->len - (ptr - (void *)dev_header);
-		u32 key_len, val_len;
+		u32 key_len, val_len, entry_len;
+		const u8 *entry_data;
 		char *key;
 
 		if (sizeof(key_len) > remaining)
@@ -85,17 +86,14 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
 		ucs2_as_utf8(key, ptr + sizeof(key_len),
 			     key_len - sizeof(key_len));
 
-		entry[i].name = key;
-		entry[i].length = val_len - sizeof(val_len);
-		entry[i].is_array = !!entry[i].length;
-		entry[i].type = DEV_PROP_U8;
-		entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len);
-
+		entry_data = ptr + key_len + sizeof(val_len);
+		entry_len = val_len - sizeof(val_len);
+		entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data,
+						       entry_len);
 		if (dump_properties) {
-			dev_info(dev, "property: %s\n", entry[i].name);
+			dev_info(dev, "property: %s\n", key);
 			print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
-				16, 1, entry[i].pointer.u8_data,
-				entry[i].length, true);
+				16, 1, entry_data, entry_len, true);
 		}
 
 		ptr += key_len + val_len;
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
reviewer Reviewed-by on v5 3/14
#5 lore raw

Re: [PATCH v5 03/14] efi/apple-properties: use PROPERTY_ENTRY_U8_ARRAY_LEN

Quoted 27 lines · Dmitry Torokhov

Let's switch to using PROPERTY_ENTRY_U8_ARRAY_LEN() to initialize property entries. Also, when dumping data, rely on local variables instead of poking into the property entry structure directly.

---
 drivers/firmware/efi/apple-properties.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)
drivers/firmware/efi/apple-properties.c +2 -1
index 0e206c9e0d7a..5ccf39986a14 100644
@@ -53,7 +53,8 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
 
 	for (i = 0; i < dev_header->prop_count; i++) {
 		int remaining = dev_header->len - (ptr - (void *)dev_header);
-		u32 key_len, val_len;
+		u32 key_len, val_len, entry_len;
+		const u8 *entry_data;
 		char *key;
 
 		if (sizeof(key_len) > remaining)
@@ -85,17 +86,14 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
 		ucs2_as_utf8(key, ptr + sizeof(key_len),
 			     key_len - sizeof(key_len));
 

drivers/firmware/efi/apple-properties.c static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, · line 92

Quoted 10 lines
drivers/firmware/efi/apple-properties.c +4 -6
-		entry[i].name = key;
-		entry[i].length = val_len - sizeof(val_len);
-		entry[i].is_array = !!entry[i].length;
-		entry[i].type = DEV_PROP_U8;
-		entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len);
-
+		entry_data = ptr + key_len + sizeof(val_len);
+		entry_len = val_len - sizeof(val_len);
+		entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data,
+						       entry_len);

I would rather leave on one line.
Nevertheless,

Quoted 13 lines
drivers/firmware/efi/apple-properties.c +2 -3
 		if (dump_properties) {
-			dev_info(dev, "property: %s\n", entry[i].name);
+			dev_info(dev, "property: %s\n", key);
 			print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
-				16, 1, entry[i].pointer.u8_data,
-				entry[i].length, true);
+				16, 1, entry_data, entry_len, true);
 		}
 
 		ptr += key_len + val_len;
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#6 lore raw

Re: [PATCH v5 03/14] efi/apple-properties: use PROPERTY_ENTRY_U8_ARRAY_LEN

Quoted 28 lines · Andy Shevchenko
Quoted 27 lines · Dmitry Torokhov

Let's switch to using PROPERTY_ENTRY_U8_ARRAY_LEN() to initialize property entries. Also, when dumping data, rely on local variables instead of poking into the property entry structure directly.

---
 drivers/firmware/efi/apple-properties.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)
drivers/firmware/efi/apple-properties.c +2 -1
index 0e206c9e0d7a..5ccf39986a14 100644
@@ -53,7 +53,8 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
 
 	for (i = 0; i < dev_header->prop_count; i++) {
 		int remaining = dev_header->len - (ptr - (void *)dev_header);
-		u32 key_len, val_len;
+		u32 key_len, val_len, entry_len;
+		const u8 *entry_data;
 		char *key;
 
 		if (sizeof(key_len) > remaining)
@@ -85,17 +86,14 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
 		ucs2_as_utf8(key, ptr + sizeof(key_len),
 			     key_len - sizeof(key_len));
 
Quoted 12 lines

drivers/firmware/efi/apple-properties.c static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, · line 92

Quoted 10 lines
drivers/firmware/efi/apple-properties.c +4 -6
-		entry[i].name = key;
-		entry[i].length = val_len - sizeof(val_len);
-		entry[i].is_array = !!entry[i].length;
-		entry[i].type = DEV_PROP_U8;
-		entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len);
-
+		entry_data = ptr + key_len + sizeof(val_len);
+		entry_len = val_len - sizeof(val_len);
+		entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data,
+						       entry_len);

I would rather leave on one line.

I am trying to stay withing 80 char limit by default, but do not have strong opinion on the code I do not maintain. Up to Ard I suppose.

Quoted 3 lines

Nevertheless,

Thank you for looking the patches over.

Quoted 10 lines
Quoted 10 lines
drivers/firmware/efi/apple-properties.c +2 -3
 		if (dump_properties) {
-			dev_info(dev, "property: %s\n", entry[i].name);
+			dev_info(dev, "property: %s\n", key);
 			print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
-				16, 1, entry[i].pointer.u8_data,
-				entry[i].length, true);
+				16, 1, entry_data, entry_len, true);
 		}
 
Quoted 5 lines
Quoted 4 lines
drivers/firmware/efi/apple-properties.c +0 -0
 		ptr += key_len + val_len;
Signature · 1 line
2.23.0.700.g56cf767bdb-goog

Thanks.

Signature · 1 line
Dmitry
#7 lore raw

PATCH v5 4/14 software node: mark internal macros with double underscores

In reply to Dmitry Torokhov

Let's mark PROPERTY_ENTRY_* macros that are internal with double leading underscores so users are not tempted to use them.

---
 include/linux/property.h | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
include/linux/property.h +10 -10
index f89b930ca4b7..2c9d4d209296 100644
@@ -256,7 +256,7 @@ struct property_entry {
  * and structs.
  */
 
-#define PROPERTY_ENTRY_ARRAY_LEN(_name_, _type_, _Type_, _val_, _len_)	\
+#define __PROPERTY_ENTRY_ARRAY_LEN(_name_, _type_, _Type_, _val_, _len_)\
 (struct property_entry) {						\
 	.name = _name_,							\
 	.length = (_len_) * sizeof(_type_),				\
@@ -266,13 +266,13 @@ struct property_entry {
 }
 
 #define PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, _len_)		\
-	PROPERTY_ENTRY_ARRAY_LEN(_name_, u8, U8, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u8, U8, _val_, _len_)
 #define PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, _len_)		\
-	PROPERTY_ENTRY_ARRAY_LEN(_name_, u16, U16, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u16, U16, _val_, _len_)
 #define PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, _len_)		\
-	PROPERTY_ENTRY_ARRAY_LEN(_name_, u32, U32, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u32, U32, _val_, _len_)
 #define PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, _len_)		\
-	PROPERTY_ENTRY_ARRAY_LEN(_name_, u64, U64, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u64, U64, _val_, _len_)
 
 #define PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, _len_)		\
 (struct property_entry) {						\
@@ -294,7 +294,7 @@ struct property_entry {
 #define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_)			\
 	PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
 
-#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_)	\
+#define __PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_)	\
 (struct property_entry) {					\
 	.name = _name_,						\
 	.length = sizeof(_type_),				\
@@ -303,13 +303,13 @@ struct property_entry {
 }
 
 #define PROPERTY_ENTRY_U8(_name_, _val_)		\
-	PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_)
+	__PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_)
 #define PROPERTY_ENTRY_U16(_name_, _val_)		\
-	PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_)
+	__PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_)
 #define PROPERTY_ENTRY_U32(_name_, _val_)		\
-	PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_)
+	__PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_)
 #define PROPERTY_ENTRY_U64(_name_, _val_)		\
-	PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_)
+	__PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_)
 
 #define PROPERTY_ENTRY_STRING(_name_, _val_)		\
 (struct property_entry) {				\
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#8 lore raw

Re: [PATCH v5 04/14] software node: mark internal macros with double underscores

Quoted 2 lines · Dmitry Torokhov

Let's mark PROPERTY_ENTRY_* macros that are internal with double leading underscores so users are not tempted to use them.

We may undef them at the end of file, right?

Quoted 67 lines
---
 include/linux/property.h | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
include/linux/property.h +10 -10
index f89b930ca4b7..2c9d4d209296 100644
@@ -256,7 +256,7 @@ struct property_entry {
  * and structs.
  */
 
-#define PROPERTY_ENTRY_ARRAY_LEN(_name_, _type_, _Type_, _val_, _len_)	\
+#define __PROPERTY_ENTRY_ARRAY_LEN(_name_, _type_, _Type_, _val_, _len_)\
 (struct property_entry) {						\
 	.name = _name_,							\
 	.length = (_len_) * sizeof(_type_),				\
@@ -266,13 +266,13 @@ struct property_entry {
 }
 
 #define PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, _len_)		\
-	PROPERTY_ENTRY_ARRAY_LEN(_name_, u8, U8, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u8, U8, _val_, _len_)
 #define PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, _len_)		\
-	PROPERTY_ENTRY_ARRAY_LEN(_name_, u16, U16, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u16, U16, _val_, _len_)
 #define PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, _len_)		\
-	PROPERTY_ENTRY_ARRAY_LEN(_name_, u32, U32, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u32, U32, _val_, _len_)
 #define PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, _len_)		\
-	PROPERTY_ENTRY_ARRAY_LEN(_name_, u64, U64, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u64, U64, _val_, _len_)
 
 #define PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, _len_)		\
 (struct property_entry) {						\
@@ -294,7 +294,7 @@ struct property_entry {
 #define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_)			\
 	PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
 
-#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_)	\
+#define __PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_)	\
 (struct property_entry) {					\
 	.name = _name_,						\
 	.length = sizeof(_type_),				\
@@ -303,13 +303,13 @@ struct property_entry {
 }
 
 #define PROPERTY_ENTRY_U8(_name_, _val_)		\
-	PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_)
+	__PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_)
 #define PROPERTY_ENTRY_U16(_name_, _val_)		\
-	PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_)
+	__PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_)
 #define PROPERTY_ENTRY_U32(_name_, _val_)		\
-	PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_)
+	__PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_)
 #define PROPERTY_ENTRY_U64(_name_, _val_)		\
-	PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_)
+	__PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_)
 
 #define PROPERTY_ENTRY_STRING(_name_, _val_)		\
 (struct property_entry) {				\
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#9 lore raw

Re: [PATCH v5 04/14] software node: mark internal macros with double underscores

Quoted 5 lines · Andy Shevchenko
Quoted 2 lines · Dmitry Torokhov

Let's mark PROPERTY_ENTRY_* macros that are internal with double leading underscores so users are not tempted to use them.

We may undef them at the end of file, right?

No... the macro substitution happens at the point of final use, so somewhere in .c file.

Thanks.

Signature · 1 line
Dmitry
#10 lore raw

PATCH v5 5/14 software node: clean up property_copy_string_array()

In reply to Dmitry Torokhov

Because property_copy_string_array() stores the newly allocated pointer in the destination property, we have an awkward code in property_entry_copy_data() where we fetch the new pointer from dst.

Let's change property_copy_string_array() to return pointer and rely on the common path in property_entry_copy_data() to store it in destination structure.

---
 drivers/base/swnode.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)
drivers/base/swnode.c +8 -11
index a1f3f0994f9f..2f2248c9003c 100644
@@ -337,8 +337,8 @@ static void property_entry_free_data(const struct property_entry *p)
 	kfree(p->name);
 }
 
-static int property_copy_string_array(struct property_entry *dst,
-				      const struct property_entry *src)
+static const char * const *
+property_copy_string_array(const struct property_entry *src)
 {
 	const char **d;
 	size_t nval = src->length / sizeof(*d);
@@ -346,7 +346,7 @@ static int property_copy_string_array(struct property_entry *dst,
 
 	d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
 	if (!d)
-		return -ENOMEM;
+		return NULL;
 
 	for (i = 0; i < nval; i++) {
 		d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL);
@@ -354,12 +354,11 @@ static int property_copy_string_array(struct property_entry *dst,
 			while (--i >= 0)
 				kfree(d[i]);
 			kfree(d);
-			return -ENOMEM;
+			return NULL;
 		}
 	}
 
-	dst->pointer.str = d;
-	return 0;
+	return d;
 }
 
 static int property_entry_copy_data(struct property_entry *dst,
@@ -367,17 +366,15 @@ static int property_entry_copy_data(struct property_entry *dst,
 {
 	const void *pointer = property_get_pointer(src);
 	const void *new;
-	int error;
 
 	if (src->is_array) {
 		if (!src->length)
 			return -ENODATA;
 
 		if (src->type == DEV_PROP_STRING) {
-			error = property_copy_string_array(dst, src);
-			if (error)
-				return error;
-			new = dst->pointer.str;
+			new = property_copy_string_array(src);
+			if (!new)
+				return -ENOMEM;
 		} else {
 			new = kmemdup(pointer, src->length, GFP_KERNEL);
 			if (!new)
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#11 lore raw

Re: [PATCH v5 05/14] software node: clean up property_copy_string_array()

Quoted 3 lines · Dmitry Torokhov

Because property_copy_string_array() stores the newly allocated pointer in the destination property, we have an awkward code in property_entry_copy_data() where we fetch the new pointer from dst.

I don't see a problem in this function.

Rather 'awkward code' is a result of use property_set_pointer() which relies on data type.

Quoted 2 lines

Let's change property_copy_string_array() to return pointer and rely on the common path in property_entry_copy_data() to store it in destination structure.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#12 lore raw

Re: [PATCH v5 05/14] software node: clean up property_copy_string_array()

Quoted 9 lines · Andy Shevchenko
Quoted 3 lines · Dmitry Torokhov

Because property_copy_string_array() stores the newly allocated pointer in the destination property, we have an awkward code in property_entry_copy_data() where we fetch the new pointer from dst.

I don't see a problem in this function.

Rather 'awkward code' is a result of use property_set_pointer() which relies on data type.

No, the awkwardness is that we set the pointer once in property_copy_string_array(), then fetch it in property_entry_copy_data() only to set it again via property_set_pointer(). This is confising and awkward and I believe it is cleaner for property_copy_string_array() to give a pointer to a copy of a string array, and then property_entry_copy_data() use it when handling the destination structure.

Thanks.

Signature · 1 line
Dmitry
#13 lore raw

Re: [PATCH v5 05/14] software node: clean up property_copy_string_array()

Quoted 8 lines · Dmitry Torokhov
Quoted 7 lines · Andy Shevchenko
Quoted 3 lines · Dmitry Torokhov

Because property_copy_string_array() stores the newly allocated pointer in the destination property, we have an awkward code in property_entry_copy_data() where we fetch the new pointer from dst.

I don't see a problem in this function.

Quoted 7 lines
Quoted 2 lines

Rather 'awkward code' is a result of use property_set_pointer() which relies on data type.

No, the awkwardness is that we set the pointer once in property_copy_string_array(), then fetch it in property_entry_copy_data() only to set it again via property_set_pointer().

Yes, since property_set_pointer is called independently on the type of the value.

Quoted 4 lines

This is confising and awkward and I believe it
is cleaner for property_copy_string_array() to give a pointer to a copy of a string array, and then property_entry_copy_data() use it when handling the destination structure.

We probably need a 3rd opinion here.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#14 lore raw

Re: [PATCH v5 05/14] software node: clean up property_copy_string_array()

Quoted 12 lines · Andy Shevchenko
Quoted 11 lines · Dmitry Torokhov
Quoted 9 lines · Andy Shevchenko
Quoted 3 lines · Dmitry Torokhov

Because property_copy_string_array() stores the newly allocated pointer in the destination property, we have an awkward code in property_entry_copy_data() where we fetch the new pointer from dst.

I don't see a problem in this function.

Rather 'awkward code' is a result of use property_set_pointer() which relies on data type.

Quoted 7 lines
Quoted 4 lines

No, the awkwardness is that we set the pointer once in property_copy_string_array(), then fetch it in property_entry_copy_data() only to set it again via property_set_pointer().

Yes, since property_set_pointer is called independently on the type of the value.

We still call property_set_pointer() independently of the type of the value even with this patch. The point is that we do not set the pointer in property_copy_string_array(), so we only set the pointer once.

We used to have essentially for string arrays:

copy data
set pointer in dst
get pointer from dst
set pointer in dst

With this patch we have:

copy data
set pointer in dst

Quoted 8 lines
Quoted 6 lines

This is confising and awkward and I believe it
is cleaner for property_copy_string_array() to give a pointer to a copy of a string array, and then property_entry_copy_data() use it when handling the destination structure.

We probably need a 3rd opinion here.

I think I can still convince you ;)

Thanks.

Signature · 1 line
Dmitry
#15 lore raw

Re: [PATCH v5 05/14] software node: clean up property_copy_string_array()

Quoted 23 lines · Dmitry Torokhov
Quoted 5 lines · Andy Shevchenko
Quoted 1 line · Dmitry Torokhov

On Tue, Oct 15, 2019 at 03:07:26PM +0300, Andy Shevchenko wrote:

Yes, since property_set_pointer is called independently on the type of the value.

We still call property_set_pointer() independently of the type of the value even with this patch. The point is that we do not set the pointer in property_copy_string_array(), so we only set the pointer once.

We used to have essentially for string arrays:

copy data
set pointer in dst
get pointer from dst
set pointer in dst

With this patch we have:

copy data
set pointer in dst

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines

This is confising and awkward and I believe it
is cleaner for property_copy_string_array() to give a pointer to a copy of a string array, and then property_entry_copy_data() use it when handling the destination structure.

We probably need a 3rd opinion here.

I think I can still convince you ;)

Probably this is fine.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#16 lore raw

PATCH v5 6/14 software node: get rid of property_set_pointer()

In reply to Dmitry Torokhov

Instead of explicitly setting values of integer types when copying property entries lets just copy entire value union when processing non-array values.

For value arrays we no longer use union of pointers, but rather a single void pointer, which allows us to remove property_set_pointer().

In property_get_pointer() we do not need to handle each data type separately, we can simply return either the pointer or pointer to values union.

We are not losing anything from removing typed pointer union because the upper layers do their accesses through void pointers anyway, and we trust the "type" of the property when interpret the data. We rely on users of property entries on using PROPERTY_ENTRY_XXX() macros to properly initialize entries instead of poking in the instances directly.

---
 drivers/base/swnode.c    | 90 +++++++++-------------------------------
 include/linux/property.h | 12 ++----
 2 files changed, 22 insertions(+), 80 deletions(-)
drivers/base/swnode.c +19 -71
index 2f2248c9003c..26e56dd66436 100644
@@ -103,71 +103,15 @@ property_entry_get(const struct property_entry *prop, const char *name)
 	return NULL;
 }
 
-static void
-property_set_pointer(struct property_entry *prop, const void *pointer)
-{
-	switch (prop->type) {
-	case DEV_PROP_U8:
-		if (prop->is_array)
-			prop->pointer.u8_data = pointer;
-		else
-			prop->value.u8_data = *((u8 *)pointer);
-		break;
-	case DEV_PROP_U16:
-		if (prop->is_array)
-			prop->pointer.u16_data = pointer;
-		else
-			prop->value.u16_data = *((u16 *)pointer);
-		break;
-	case DEV_PROP_U32:
-		if (prop->is_array)
-			prop->pointer.u32_data = pointer;
-		else
-			prop->value.u32_data = *((u32 *)pointer);
-		break;
-	case DEV_PROP_U64:
-		if (prop->is_array)
-			prop->pointer.u64_data = pointer;
-		else
-			prop->value.u64_data = *((u64 *)pointer);
-		break;
-	case DEV_PROP_STRING:
-		if (prop->is_array)
-			prop->pointer.str = pointer;
-		else
-			prop->value.str = pointer;
-		break;
-	default:
-		break;
-	}
-}
-
 static const void *property_get_pointer(const struct property_entry *prop)
 {
-	switch (prop->type) {
-	case DEV_PROP_U8:
-		if (prop->is_array)
-			return prop->pointer.u8_data;
-		return &prop->value.u8_data;
-	case DEV_PROP_U16:
-		if (prop->is_array)
-			return prop->pointer.u16_data;
-		return &prop->value.u16_data;
-	case DEV_PROP_U32:
-		if (prop->is_array)
-			return prop->pointer.u32_data;
-		return &prop->value.u32_data;
-	case DEV_PROP_U64:
-		if (prop->is_array)
-			return prop->pointer.u64_data;
-		return &prop->value.u64_data;
-	case DEV_PROP_STRING:
-		if (prop->is_array)
-			return prop->pointer.str;
-		return &prop->value.str;
-	default:
+	if (!prop->length)
 		return NULL;
-	}
+
+	if (prop->is_array)
+		return prop->pointer;
+
+	return &prop->value;
 }
 
 static const void *property_entry_find(const struct property_entry *props,
@@ -322,13 +266,15 @@ static int property_entry_read_string_array(const struct property_entry *props,
 static void property_entry_free_data(const struct property_entry *p)
 {
 	const void *pointer = property_get_pointer(p);
+	const char * const *src_str;
 	size_t i, nval;
 
 	if (p->is_array) {
-		if (p->type == DEV_PROP_STRING && p->pointer.str) {
+		if (p->type == DEV_PROP_STRING && p->pointer) {
+			src_str = p->pointer;
 			nval = p->length / sizeof(const char *);
 			for (i = 0; i < nval; i++)
-				kfree(p->pointer.str[i]);
+				kfree(src_str[i]);
 		}
 		kfree(pointer);
 	} else if (p->type == DEV_PROP_STRING) {
@@ -341,6 +287,7 @@ static const char * const *
 property_copy_string_array(const struct property_entry *src)
 {
 	const char **d;
+	const char * const *src_str = src->pointer;
 	size_t nval = src->length / sizeof(*d);
 	int i;
 
@@ -349,8 +296,8 @@ property_copy_string_array(const struct property_entry *src)
 		return NULL;
 
 	for (i = 0; i < nval; i++) {
-		d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL);
-		if (!d[i] && src->pointer.str[i]) {
+		d[i] = kstrdup(src_str[i], GFP_KERNEL);
+		if (!d[i] && src_str[i]) {
 			while (--i >= 0)
 				kfree(d[i]);
 			kfree(d);
@@ -380,20 +327,21 @@ static int property_entry_copy_data(struct property_entry *dst,
 			if (!new)
 				return -ENOMEM;
 		}
+
+		dst->is_array = true;
+		dst->pointer = new;
 	} else if (src->type == DEV_PROP_STRING) {
 		new = kstrdup(src->value.str, GFP_KERNEL);
 		if (!new && src->value.str)
 			return -ENOMEM;
+
+		dst->value.str = new;
 	} else {
-		new = pointer;
+		dst->value = src->value;
 	}
 
 	dst->length = src->length;
-	dst->is_array = src->is_array;
 	dst->type = src->type;
-
-	property_set_pointer(dst, new);
-
 	dst->name = kstrdup(src->name, GFP_KERNEL);
 	if (!dst->name)
 		goto out_free_data;
include/linux/property.h +3 -9
index 2c9d4d209296..ec8f84d564a8 100644
@@ -233,13 +233,7 @@ struct property_entry {
 	bool is_array;
 	enum dev_prop_type type;
 	union {
-		union {
-			const u8 *u8_data;
-			const u16 *u16_data;
-			const u32 *u32_data;
-			const u64 *u64_data;
-			const char * const *str;
-		} pointer;
+		const void *pointer;
 		union {
 			u8 u8_data;
 			u16 u16_data;
@@ -262,7 +256,7 @@ struct property_entry {
 	.length = (_len_) * sizeof(_type_),				\
 	.is_array = true,						\
 	.type = DEV_PROP_##_Type_,					\
-	{ .pointer = { ._type_##_data = _val_ } },			\
+	{ .pointer = _val_ },						\
 }
 
 #define PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, _len_)		\
@@ -280,7 +274,7 @@ struct property_entry {
 	.length = (_len_) * sizeof(const char *),			\
 	.is_array = true,						\
 	.type = DEV_PROP_STRING,					\
-	{ .pointer = { .str = _val_ } },				\
+	{ .pointer = _val_ },						\
 }
 
 #define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_)				\
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#17 lore raw

Re: [PATCH v5 06/14] software node: get rid of property_set_pointer()

Quoted 11 lines · Dmitry Torokhov

Instead of explicitly setting values of integer types when copying property entries lets just copy entire value union when processing non-array values.

For value arrays we no longer use union of pointers, but rather a single void pointer, which allows us to remove property_set_pointer().

In property_get_pointer() we do not need to handle each data type separately, we can simply return either the pointer or pointer to values union.

Quoted 5 lines

We are not losing anything from removing typed pointer union because the upper layers do their accesses through void pointers anyway, and we trust the "type" of the property when interpret the data. We rely on users of property entries on using PROPERTY_ENTRY_XXX() macros to properly initialize entries instead of poking in the instances directly.

I'm not sure about this change since the struct definition is still available to use. If we would change it to be opaque pointer, it will be possible to get rid of the type differentiation in cleaner way.

Anyway, perhaps somebody else can look at this.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#18 lore raw

Re: [PATCH v5 06/14] software node: get rid of property_set_pointer()

Quoted 18 lines · Andy Shevchenko
Quoted 11 lines · Dmitry Torokhov

Instead of explicitly setting values of integer types when copying property entries lets just copy entire value union when processing non-array values.

For value arrays we no longer use union of pointers, but rather a single void pointer, which allows us to remove property_set_pointer().

In property_get_pointer() we do not need to handle each data type separately, we can simply return either the pointer or pointer to values union.

Quoted 5 lines

We are not losing anything from removing typed pointer union because the upper layers do their accesses through void pointers anyway, and we trust the "type" of the property when interpret the data. We rely on users of property entries on using PROPERTY_ENTRY_XXX() macros to properly initialize entries instead of poking in the instances directly.

Quoted 3 lines

I'm not sure about this change since the struct definition is still available to use. If we would change it to be opaque pointer, it will be possible to get rid of the type differentiation in cleaner way.

We expose type and other fields that should not be manipulated directly, for the benefit of being able to use static initializers. Having value structure allows for not too ugly non-array initializers.

Thanks.

Signature · 1 line
Dmitry
#19 lore raw

PATCH v5 7/14 software node: remove property_entry_read_uNN_array functions

In reply to Dmitry Torokhov

There is absolutely no reason to have them as we can handle it all nicely in property_entry_read_int_array().

---
 drivers/base/swnode.c | 85 +++++++------------------------------------
 1 file changed, 14 insertions(+), 71 deletions(-)
drivers/base/swnode.c +14 -71
index 26e56dd66436..b11cc4dbff08 100644
@@ -131,66 +131,6 @@ static const void *property_entry_find(const struct property_entry *props,
 	return pointer;
 }
 
-static int property_entry_read_u8_array(const struct property_entry *props,
-					const char *propname,
-					u8 *values, size_t nval)
-{
-	const void *pointer;
-	size_t length = nval * sizeof(*values);
-
-	pointer = property_entry_find(props, propname, length);
-	if (IS_ERR(pointer))
-		return PTR_ERR(pointer);
-
-	memcpy(values, pointer, length);
-	return 0;
-}
-
-static int property_entry_read_u16_array(const struct property_entry *props,
-					 const char *propname,
-					 u16 *values, size_t nval)
-{
-	const void *pointer;
-	size_t length = nval * sizeof(*values);
-
-	pointer = property_entry_find(props, propname, length);
-	if (IS_ERR(pointer))
-		return PTR_ERR(pointer);
-
-	memcpy(values, pointer, length);
-	return 0;
-}
-
-static int property_entry_read_u32_array(const struct property_entry *props,
-					 const char *propname,
-					 u32 *values, size_t nval)
-{
-	const void *pointer;
-	size_t length = nval * sizeof(*values);
-
-	pointer = property_entry_find(props, propname, length);
-	if (IS_ERR(pointer))
-		return PTR_ERR(pointer);
-
-	memcpy(values, pointer, length);
-	return 0;
-}
-
-static int property_entry_read_u64_array(const struct property_entry *props,
-					 const char *propname,
-					 u64 *values, size_t nval)
-{
-	const void *pointer;
-	size_t length = nval * sizeof(*values);
-
-	pointer = property_entry_find(props, propname, length);
-	if (IS_ERR(pointer))
-		return PTR_ERR(pointer);
-
-	memcpy(values, pointer, length);
-	return 0;
-}
-
 static int
 property_entry_count_elems_of_size(const struct property_entry *props,
 				   const char *propname, size_t length)
@@ -209,21 +149,24 @@ static int property_entry_read_int_array(const struct property_entry *props,
 					 unsigned int elem_size, void *val,
 					 size_t nval)
 {
+	const void *pointer;
+	size_t length;
+
 	if (!val)
 		return property_entry_count_elems_of_size(props, name,
 							  elem_size);
-	switch (elem_size) {
-	case sizeof(u8):
-		return property_entry_read_u8_array(props, name, val, nval);
-	case sizeof(u16):
-		return property_entry_read_u16_array(props, name, val, nval);
-	case sizeof(u32):
-		return property_entry_read_u32_array(props, name, val, nval);
-	case sizeof(u64):
-		return property_entry_read_u64_array(props, name, val, nval);
-	}
 
-	return -ENXIO;
+	if (!is_power_of_2(elem_size) || elem_size > sizeof(u64))
+		return -ENXIO;
+
+	length = nval * elem_size;
+
+	pointer = property_entry_find(props, name, length);
+	if (IS_ERR(pointer))
+		return PTR_ERR(pointer);
+
+	memcpy(val, pointer, length);
+	return 0;
 }
 
 static int property_entry_read_string_array(const struct property_entry *props,
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#20 lore raw

PATCH v5 8/14 software node: unify PROPERTY_ENTRY_XXX macros

In reply to Dmitry Torokhov

We can unify string properties initializer macros with integer initializers.

---
 include/linux/property.h | 64 +++++++++++++++++-----------------------
 1 file changed, 27 insertions(+), 37 deletions(-)
include/linux/property.h +27 -37
index ec8f84d564a8..238e1507925f 100644
@@ -245,37 +245,33 @@ struct property_entry {
 };
 
 /*
- * Note: the below four initializers for the anonymous union are carefully
+ * Note: the below initializers for the anonymous union are carefully
  * crafted to avoid gcc-4.4.4's problems with initialization of anon unions
  * and structs.
  */
 
-#define __PROPERTY_ENTRY_ARRAY_LEN(_name_, _type_, _Type_, _val_, _len_)\
+#define __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_)				\
+	sizeof(((struct property_entry *)NULL)->value._elem_)
+
+#define __PROPERTY_ENTRY_ARRAY_LEN(_name_, _elem_, _Type_, _val_, _len_)\
 (struct property_entry) {						\
 	.name = _name_,							\
-	.length = (_len_) * sizeof(_type_),				\
+	.length = (_len_) * __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_),	\
 	.is_array = true,						\
 	.type = DEV_PROP_##_Type_,					\
 	{ .pointer = _val_ },						\
 }
 
 #define PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, _len_)		\
-	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u8, U8, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u8_data, U8, _val_, _len_)
 #define PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, _len_)		\
-	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u16, U16, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u16_data, U16, _val_, _len_)
 #define PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, _len_)		\
-	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u32, U32, _val_, _len_)
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u32_data, U32, _val_, _len_)
 #define PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, _len_)		\
-	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u64, U64, _val_, _len_)
-
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, u64_data, U64, _val_, _len_)
 #define PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, _len_)		\
-(struct property_entry) {						\
-	.name = _name_,							\
-	.length = (_len_) * sizeof(const char *),			\
-	.is_array = true,						\
-	.type = DEV_PROP_STRING,					\
-	{ .pointer = _val_ },						\
-}
+	__PROPERTY_ENTRY_ARRAY_LEN(_name_, str, STRING, _val_, _len_)
 
 #define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_)				\
 	PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
@@ -288,30 +284,24 @@ struct property_entry {
 #define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_)			\
 	PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
 
-#define __PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_)	\
-(struct property_entry) {					\
-	.name = _name_,						\
-	.length = sizeof(_type_),				\
-	.type = DEV_PROP_##_Type_,				\
-	{ .value = { ._type_##_data = _val_ } },		\
+#define __PROPERTY_ENTRY_ELEMENT(_name_, _elem_, _Type_, _val_)		\
+(struct property_entry) {						\
+	.name = _name_,							\
+	.length = __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_),		\
+	.type = DEV_PROP_##_Type_,					\
+	{ .value = { ._elem_ = _val_ } },				\
 }
 
-#define PROPERTY_ENTRY_U8(_name_, _val_)		\
-	__PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_)
-#define PROPERTY_ENTRY_U16(_name_, _val_)		\
-	__PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_)
-#define PROPERTY_ENTRY_U32(_name_, _val_)		\
-	__PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_)
-#define PROPERTY_ENTRY_U64(_name_, _val_)		\
-	__PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_)
-
-#define PROPERTY_ENTRY_STRING(_name_, _val_)		\
-(struct property_entry) {				\
-	.name = _name_,					\
-	.length = sizeof(const char *),			\
-	.type = DEV_PROP_STRING,			\
-	{ .value = { .str = _val_ } },			\
-}
+#define PROPERTY_ENTRY_U8(_name_, _val_)				\
+	__PROPERTY_ENTRY_ELEMENT(_name_, u8_data, U8, _val_)
+#define PROPERTY_ENTRY_U16(_name_, _val_)				\
+	__PROPERTY_ENTRY_ELEMENT(_name_, u16_data, U16, _val_)
+#define PROPERTY_ENTRY_U32(_name_, _val_)				\
+	__PROPERTY_ENTRY_ELEMENT(_name_, u32_data, U32, _val_)
+#define PROPERTY_ENTRY_U64(_name_, _val_)				\
+	__PROPERTY_ENTRY_ELEMENT(_name_, u64_data, U64, _val_)
+#define PROPERTY_ENTRY_STRING(_name_, _val_)				\
+	__PROPERTY_ENTRY_ELEMENT(_name_, str, STRING, _val_)
 
 #define PROPERTY_ENTRY_BOOL(_name_)		\
 (struct property_entry) {			\
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#21 lore raw

PATCH v5 9/14 software node: simplify property_entry_read_string_array()

In reply to Dmitry Torokhov

There is no need to treat string arrays and single strings separately, we can go exclusively by the element length in relation to data type size.

---
 drivers/base/swnode.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)
drivers/base/swnode.c +7 -14
index b11cc4dbff08..8826c9040c80 100644
@@ -173,28 +173,21 @@ static int property_entry_read_string_array(const struct property_entry *props,
 					    const char *propname,
 					    const char **strings, size_t nval)
 {
-	const struct property_entry *prop;
 	const void *pointer;
-	size_t array_len, length;
+	size_t length;
+	int array_len;
 
 	/* Find out the array length. */
-	prop = property_entry_get(props, propname);
-	if (!prop)
-		return -EINVAL;
-
-	if (prop->is_array)
-		/* Find the length of an array. */
-		array_len = property_entry_count_elems_of_size(props, propname,
-							  sizeof(const char *));
-	else
-		/* The array length for a non-array string property is 1. */
-		array_len = 1;
+	array_len = property_entry_count_elems_of_size(props, propname,
+						       sizeof(const char *));
+	if (array_len < 0)
+		return array_len;
 
 	/* Return how many there are if strings is NULL. */
 	if (!strings)
 		return array_len;
 
-	array_len = min(nval, array_len);
+	array_len = min_t(size_t, nval, array_len);
 	length = array_len * sizeof(*strings);
 
 	pointer = property_entry_find(props, propname, length);
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#22 lore raw

PATCH v5 10/14 software node: rename is_array to is_inline

In reply to Dmitry Torokhov

We do not need a special flag to know if we are dealing with an array, as we can get that data from ratio between element length and the data size, however we do need a flag to know whether the data is stored directly inside property_entry or separately.

---
 drivers/base/swnode.c    |  9 +++++----
 include/linux/property.h | 12 +++++++-----
 2 files changed, 12 insertions(+), 9 deletions(-)
drivers/base/swnode.c +5 -4
index 8826c9040c80..ae4b24ee2a54 100644
@@ -108,7 +108,7 @@ static const void *property_get_pointer(const struct property_entry *prop)
 	if (!prop->length)
 		return NULL;
 
-	if (prop->is_array)
+	if (!prop->is_inline)
 		return prop->pointer;
 
 	return &prop->value;
@@ -205,7 +205,7 @@ static void property_entry_free_data(const struct property_entry *p)
 	const char * const *src_str;
 	size_t i, nval;
 
-	if (p->is_array) {
+	if (!p->is_inline) {
 		if (p->type == DEV_PROP_STRING && p->pointer) {
 			src_str = p->pointer;
 			nval = p->length / sizeof(const char *);
@@ -250,7 +250,7 @@ static int property_entry_copy_data(struct property_entry *dst,
 	const void *pointer = property_get_pointer(src);
 	const void *new;
 
-	if (src->is_array) {
+	if (!src->is_inline) {
 		if (!src->length)
 			return -ENODATA;
 
@@ -264,15 +264,16 @@ static int property_entry_copy_data(struct property_entry *dst,
 				return -ENOMEM;
 		}
 
-		dst->is_array = true;
 		dst->pointer = new;
 	} else if (src->type == DEV_PROP_STRING) {
 		new = kstrdup(src->value.str, GFP_KERNEL);
 		if (!new && src->value.str)
 			return -ENOMEM;
 
+		dst->is_inline = true;
 		dst->value.str = new;
 	} else {
+		dst->is_inline = true;
 		dst->value = src->value;
 	}
 
include/linux/property.h +7 -5
index 238e1507925f..ac7823d58cfe 100644
@@ -222,15 +222,17 @@ static inline int fwnode_property_count_u64(const struct fwnode_handle *fwnode,
  * struct property_entry - "Built-in" device property representation.
  * @name: Name of the property.
  * @length: Length of data making up the value.
- * @is_array: True when the property is an array.
+ * @is_inline: True when the property value is stored directly in
+ *     &struct property_entry instance.
  * @type: Type of the data in unions.
- * @pointer: Pointer to the property (an array of items of the given type).
- * @value: Value of the property (when it is a single item of the given type).
+ * @pointer: Pointer to the property when it is stored separately from
+ *     the &struct property_entry instance.
+ * @value: Value of the property when it is stored inline.
  */
 struct property_entry {
 	const char *name;
 	size_t length;
-	bool is_array;
+	bool is_inline;
 	enum dev_prop_type type;
 	union {
 		const void *pointer;
@@ -257,7 +259,6 @@ struct property_entry {
 (struct property_entry) {						\
 	.name = _name_,							\
 	.length = (_len_) * __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_),	\
-	.is_array = true,						\
 	.type = DEV_PROP_##_Type_,					\
 	{ .pointer = _val_ },						\
 }
@@ -288,6 +289,7 @@ struct property_entry {
 (struct property_entry) {						\
 	.name = _name_,							\
 	.length = __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_),		\
+	.is_inline = true,						\
 	.type = DEV_PROP_##_Type_,					\
 	{ .value = { ._elem_ = _val_ } },				\
 }
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#23 lore raw

Re: [PATCH v5 10/14] software node: rename is_array to is_inline

Review

Quoted 13 lines · Dmitry Torokhov

We do not need a special flag to know if we are dealing with an array, as we can get that data from ratio between element length and the data size, however we do need a flag to know whether the data is stored directly inside property_entry or separately.

(quoted diff) +3 -3
-	if (prop->is_array)
+	if (!prop->is_inline)
 
-	if (p->is_array) {
+	if (!p->is_inline) {
 
-	if (src->is_array) {
+	if (!src->is_inline) {

May we have positive conditionals instead?

Quoted 1 line

+ * @is_inline: True when the property value is stored directly in

I think word 'directly' is superfluous here.
Or, perhaps, 'stored directly' -> 'embedded'

Quoted 4 lines

+ * &struct property_entry instance.

+ * @pointer: Pointer to the property when it is stored separately from
+ * the &struct property_entry instance.

'separately from' -> 'outside' ?

Quoted 1 line

+ * @value: Value of the property when it is stored inline.

'stored inline' -> 'embedded in the &struct...' ?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#24 lore raw

Re: [PATCH v5 10/14] software node: rename is_array to is_inline

Quoted 9 lines · Andy Shevchenko
Quoted 7 lines · Dmitry Torokhov

We do not need a special flag to know if we are dealing with an array, as we can get that data from ratio between element length and the data size, however we do need a flag to know whether the data is stored directly inside property_entry or separately.

drivers/base/swnode.c +1 -1
-	if (prop->is_array)
+	if (!prop->is_inline)
Quoted 7 lines

drivers/base/swnode.c static int property_entry_copy_data(struct property_entry *dst, · line 253

Quoted 5 lines
drivers/base/swnode.c +2 -2
-	if (p->is_array) {
+	if (!p->is_inline) {
 
-	if (src->is_array) {
+	if (!src->is_inline) {

May we have positive conditionals instead?

I was trying to limit the context churn. I can definitely change property_get_pointer(), but the other 2 I think are better in the current form.

Quoted 5 lines
Quoted 2 lines

+ * @is_inline: True when the property value is stored directly in

I think word 'directly' is superfluous here.
Or, perhaps, 'stored directly' -> 'embedded'

I'm OK with "embedded".

Quoted 7 lines
Quoted 5 lines

+ * &struct property_entry instance.

+ * @pointer: Pointer to the property when it is stored separately from
+ * the &struct property_entry instance.

'separately from' -> 'outside' ?

Umm, I think I prefer "separately" actually.

Quoted 4 lines
Quoted 2 lines

+ * @value: Value of the property when it is stored inline.

'stored inline' -> 'embedded in the &struct...' ?

I was trying to have a link "stored inline" -> "is_inline".

Do we want to change the flag to be "is_embedded"?

Thanks.

Signature · 1 line
Dmitry
#25 lore raw

Re: [PATCH v5 10/14] software node: rename is_array to is_inline

Quoted 41 lines · Dmitry Torokhov
Quoted 9 lines · Andy Shevchenko
Quoted 7 lines · Dmitry Torokhov

We do not need a special flag to know if we are dealing with an array, as we can get that data from ratio between element length and the data size, however we do need a flag to know whether the data is stored directly inside property_entry or separately.

drivers/base/swnode.c +1 -1
-	if (prop->is_array)
+	if (!prop->is_inline)
Quoted 7 lines

drivers/base/swnode.c static int property_entry_copy_data(struct property_entry *dst, · line 253

Quoted 5 lines
drivers/base/swnode.c +2 -2
-	if (p->is_array) {
+	if (!p->is_inline) {
 
-	if (src->is_array) {
+	if (!src->is_inline) {

May we have positive conditionals instead?

I was trying to limit the context churn. I can definitely change property_get_pointer(), but the other 2 I think are better in the current form.

Quoted 5 lines
Quoted 2 lines

+ * @is_inline: True when the property value is stored directly in

I think word 'directly' is superfluous here.
Or, perhaps, 'stored directly' -> 'embedded'

I'm OK with "embedded".

Quoted 7 lines
Quoted 5 lines

+ * &struct property_entry instance.

+ * @pointer: Pointer to the property when it is stored separately from
+ * the &struct property_entry instance.

'separately from' -> 'outside' ?

Umm, I think I prefer "separately" actually.

Quoted 1 line
Quoted 7 lines
Quoted 3 lines
Quoted 1 line

+ * @value: Value of the property when it is stored inline.

'stored inline' -> 'embedded in the &struct...' ?

I was trying to have a link "stored inline" -> "is_inline".

Do we want to change the flag to be "is_embedded"?

In dictionaries I have

embedded <-> unilateral
inline <-> ???

Perhaps native speaker can jump in and help here.

My point is to be consistent in the terms we are using.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#26 lore raw

Re: [PATCH v5 10/14] software node: rename is_array to is_inline

Quoted 46 lines · Andy Shevchenko
Quoted 45 lines · Dmitry Torokhov
Quoted 9 lines · Andy Shevchenko
Quoted 7 lines · Dmitry Torokhov

We do not need a special flag to know if we are dealing with an array, as we can get that data from ratio between element length and the data size, however we do need a flag to know whether the data is stored directly inside property_entry or separately.

drivers/base/swnode.c +1 -1
-	if (prop->is_array)
+	if (!prop->is_inline)
Quoted 7 lines

drivers/base/swnode.c static int property_entry_copy_data(struct property_entry *dst, · line 253

Quoted 5 lines
drivers/base/swnode.c +2 -2
-	if (p->is_array) {
+	if (!p->is_inline) {
 
-	if (src->is_array) {
+	if (!src->is_inline) {

May we have positive conditionals instead?

I was trying to limit the context churn. I can definitely change property_get_pointer(), but the other 2 I think are better in the current form.

Quoted 5 lines
Quoted 2 lines

+ * @is_inline: True when the property value is stored directly in

I think word 'directly' is superfluous here.
Or, perhaps, 'stored directly' -> 'embedded'

I'm OK with "embedded".

Quoted 7 lines
Quoted 5 lines

+ * &struct property_entry instance.

+ * @pointer: Pointer to the property when it is stored separately from
+ * the &struct property_entry instance.

'separately from' -> 'outside' ?

Umm, I think I prefer "separately" actually.

Quoted 4 lines
Quoted 2 lines

+ * @value: Value of the property when it is stored inline.

'stored inline' -> 'embedded in the &struct...' ?

Quoted 7 lines
Quoted 3 lines

I was trying to have a link "stored inline" -> "is_inline".

Do we want to change the flag to be "is_embedded"?

In dictionaries I have

embedded <-> unilateral

Are you trying to show synonym or antonym here? But I am pretty sure "unilateral" is either.

Antonyms for our use of "embedded" are likely "detached" or "disconnected".

Quoted 1 line

inline <-> ???

"out of line" but I still believe "stored separately" explains precisely what we have here.

Thanks.

Signature · 1 line
Dmitry
#27 lore raw

Re: [PATCH v5 10/14] software node: rename is_array to is_inline

Quoted 9 lines · Dmitry Torokhov
Quoted 8 lines · Andy Shevchenko
Quoted 7 lines · Dmitry Torokhov
Quoted 3 lines · Andy Shevchenko

On Fri, Oct 11, 2019 at 04:07:17PM -0700, Dmitry Torokhov wrote:

'stored inline' -> 'embedded in the &struct...' ?

I was trying to have a link "stored inline" -> "is_inline".

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

Do we want to change the flag to be "is_embedded"?

In dictionaries I have

embedded <-> unilateral

Are you trying to show synonym or antonym here? But I am pretty sure "unilateral" is either.

Antonyms. The 'unilateral' is marked as so in the dictionary.

Quoted 7 lines

Antonyms for our use of "embedded" are likely "detached" or "disconnected".

Quoted 1 line

inline <-> ???

"out of line" but I still believe "stored separately" explains precisely what we have here.

No, 'out of line' is idiom with a special meaning.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#28 lore raw

Re: [PATCH v5 10/14] software node: rename is_array to is_inline

Quoted 12 lines · Andy Shevchenko
Quoted 11 lines · Dmitry Torokhov
Quoted 10 lines · Andy Shevchenko
Quoted 8 lines · Dmitry Torokhov
Quoted 3 lines · Andy Shevchenko

On Fri, Oct 11, 2019 at 04:07:17PM -0700, Dmitry Torokhov wrote:

'stored inline' -> 'embedded in the &struct...' ?

I was trying to have a link "stored inline" -> "is_inline".

Do we want to change the flag to be "is_embedded"?

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

In dictionaries I have

embedded <-> unilateral

Are you trying to show synonym or antonym here? But I am pretty sure "unilateral" is either.

Antonyms. The 'unilateral' is marked as so in the dictionary.

OK, that is not something that I would ever think of as an antonym, so even though I am not a native speaker I do not think we should be using it here as documentation and comments are supposed to be understood by all people from around the world and not by English majors only.

Out of curiosity, is this dictionary available online? I would really want to see to what particular meaning of "embedded" they assign "unilateral" as antonym so that I know better next time I see it used.

Quoted 10 lines
Quoted 8 lines

Antonyms for our use of "embedded" are likely "detached" or "disconnected".

Quoted 1 line

inline <-> ???

"out of line" but I still believe "stored separately" explains precisely what we have here.

No, 'out of line' is idiom with a special meaning.

Yes, and it is also a well defined term in CS.

Thanks.

Signature · 1 line
Dmitry
#29 lore raw

Re: [PATCH v5 10/14] software node: rename is_array to is_inline

In reply to Dmitry Torokhov
Quoted 95 lines · Dmitry Torokhov

We do not need a special flag to know if we are dealing with an array, as we can get that data from ratio between element length and the data size, however we do need a flag to know whether the data is stored directly inside property_entry or separately.

---
 drivers/base/swnode.c    |  9 +++++----
 include/linux/property.h | 12 +++++++-----
 2 files changed, 12 insertions(+), 9 deletions(-)
drivers/base/swnode.c +5 -4
index 8826c9040c80..ae4b24ee2a54 100644
@@ -108,7 +108,7 @@ static const void *property_get_pointer(const struct property_entry *prop)
 	if (!prop->length)
 		return NULL;
 
-	if (prop->is_array)
+	if (!prop->is_inline)
 		return prop->pointer;
 
 	return &prop->value;
@@ -205,7 +205,7 @@ static void property_entry_free_data(const struct property_entry *p)
 	const char * const *src_str;
 	size_t i, nval;
 
-	if (p->is_array) {
+	if (!p->is_inline) {
 		if (p->type == DEV_PROP_STRING && p->pointer) {
 			src_str = p->pointer;
 			nval = p->length / sizeof(const char *);
@@ -250,7 +250,7 @@ static int property_entry_copy_data(struct property_entry *dst,
 	const void *pointer = property_get_pointer(src);
 	const void *new;
 
-	if (src->is_array) {
+	if (!src->is_inline) {
 		if (!src->length)
 			return -ENODATA;
 
@@ -264,15 +264,16 @@ static int property_entry_copy_data(struct property_entry *dst,
 				return -ENOMEM;
 		}
 
-		dst->is_array = true;
 		dst->pointer = new;
 	} else if (src->type == DEV_PROP_STRING) {
 		new = kstrdup(src->value.str, GFP_KERNEL);
 		if (!new && src->value.str)
 			return -ENOMEM;
 
+		dst->is_inline = true;
 		dst->value.str = new;
 	} else {
+		dst->is_inline = true;
 		dst->value = src->value;
 	}
 
include/linux/property.h +6 -5
index 238e1507925f..ac7823d58cfe 100644
@@ -222,15 +222,17 @@ static inline int fwnode_property_count_u64(const struct fwnode_handle *fwnode,
  * struct property_entry - "Built-in" device property representation.
  * @name: Name of the property.
  * @length: Length of data making up the value.
- * @is_array: True when the property is an array.
+ * @is_inline: True when the property value is stored directly in
+ *     &struct property_entry instance.
  * @type: Type of the data in unions.
- * @pointer: Pointer to the property (an array of items of the given type).
- * @value: Value of the property (when it is a single item of the given type).
+ * @pointer: Pointer to the property when it is stored separately from
+ *     the &struct property_entry instance.
+ * @value: Value of the property when it is stored inline.
  */
 struct property_entry {
 	const char *name;
 	size_t length;
-	bool is_array;
+	bool is_inline;
 	enum dev_prop_type type;
 	union {
 		const void *pointer;
@@ -257,7 +259,6 @@ struct property_entry {
 (struct property_entry) {						\
 	.name = _name_,							\
 	.length = (_len_) * __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_),	\
-	.is_array = true,						\
 	.type = DEV_PROP_##_Type_,					\
 	{ .pointer = _val_ },						\
 }

include/linux/property.h struct property_entry { · line 295

Quoted 7 lines
include/linux/property.h +1 -0
@@ -288,6 +289,7 @@ struct property_entry {
 (struct property_entry) {						\
 	.name = _name_,							\
 	.length = __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_),		\
+	.is_inline = true,						\
 	.type = DEV_PROP_##_Type_,					\
 	{ .value = { ._elem_ = _val_ } },				\
 }

The patch also needs to set is_inline in PROPERTY_ENTRY_BOOL(), I'll send updated version after I get more feedback.

Thanks.

Signature · 1 line
Dmitry
#30 lore raw

PATCH v5 11/14 software node: move small properties inline when copying

In reply to Dmitry Torokhov

When copying/duplicating set of properties, move smaller properties that were stored separately directly inside property entry structures. We can move:

- up to 8 bytes from U8 arrays
- up to 4 words
- up to 2 double words
- one U64 value
- one or 2 strings.

---
 drivers/base/swnode.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/base/swnode.c +10 -0
index ae4b24ee2a54..546fc1b20095 100644
@@ -277,6 +277,16 @@ static int property_entry_copy_data(struct property_entry *dst,
 		dst->value = src->value;
 	}
 
+	if (!dst->is_inline && dst->length <= sizeof(dst->value)) {
+		/* We have an opportunity to move the data inline */
+		const void *tmp = dst->pointer;
+
+		memcpy(&dst->value, tmp, dst->length);
+		dst->is_inline = true;
+
+		kfree(tmp);
+	}
+
 	dst->length = src->length;
 	dst->type = src->type;
 	dst->name = kstrdup(src->name, GFP_KERNEL);
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#31 lore raw

Re: [PATCH v5 11/14] software node: move small properties inline when copying

Quoted 9 lines · Dmitry Torokhov

When copying/duplicating set of properties, move smaller properties that were stored separately directly inside property entry structures. We can move:

- up to 8 bytes from U8 arrays
- up to 4 words
- up to 2 double words
- one U64 value
- one or 2 strings.

Can you show where you extract such values?

drivers/base/swnode.c static int property_entry_copy_data(struct property_entry *dst, · line 284

Quoted 6 lines
drivers/base/swnode.c +5 -0
+	if (!dst->is_inline && dst->length <= sizeof(dst->value)) {
+		/* We have an opportunity to move the data inline */
+		const void *tmp = dst->pointer;
+
 
+		memcpy(&dst->value, tmp, dst->length);

...because this is strange trick.

Quoted 4 lines
drivers/base/swnode.c +4 -0
+		dst->is_inline = true;
+
+		kfree(tmp);
+	}
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#32 lore raw

Re: [PATCH v5 11/14] software node: move small properties inline when copying

Quoted 5 lines · Andy Shevchenko
Quoted 4 lines · Dmitry Torokhov

When copying/duplicating set of properties, move smaller properties that were stored separately directly inside property entry structures. We can move:

Quoted 7 lines
Quoted 5 lines

- up to 8 bytes from U8 arrays
- up to 4 words
- up to 2 double words
- one U64 value
- one or 2 strings.

Can you show where you extract such values?

the "value" union's largest member is u64, which is 8 bytes. Strings are pointers, so on 32-bit arches you can stuff 2 pointers into 8 bytes, while on 64-bits you have space for only one.

Quoted 9 lines

drivers/base/swnode.c static int property_entry_copy_data(struct property_entry *dst, · line 284

Quoted 7 lines
drivers/base/swnode.c +5 -0
+	if (!dst->is_inline && dst->length <= sizeof(dst->value)) {
+		/* We have an opportunity to move the data inline */
+		const void *tmp = dst->pointer;
+
 
+		memcpy(&dst->value, tmp, dst->length);

...because this is strange trick.

Not sure what is so strange about it. You just take data that is stored separately and move it into the structure, provided that it is not too big (i.e. it does not exceed sizeof(value union) size).

Quoted 6 lines

drivers/base/swnode.c static int property_entry_copy_data(struct property_entry *dst, · line 288

Quoted 5 lines
drivers/base/swnode.c +4 -0
+		dst->is_inline = true;
+
+		kfree(tmp);
+	}

Thanks.

Signature · 1 line
Dmitry
#33 lore raw

Re: [PATCH v5 11/14] software node: move small properties inline when copying

Quoted 24 lines · Dmitry Torokhov
Quoted 5 lines · Andy Shevchenko
Quoted 4 lines · Dmitry Torokhov

When copying/duplicating set of properties, move smaller properties that were stored separately directly inside property entry structures. We can move:

Quoted 7 lines
Quoted 5 lines

- up to 8 bytes from U8 arrays
- up to 4 words
- up to 2 double words
- one U64 value
- one or 2 strings.

Can you show where you extract such values?

the "value" union's largest member is u64, which is 8 bytes. Strings are pointers, so on 32-bit arches you can stuff 2 pointers into 8 bytes, while on 64-bits you have space for only one.

Quoted 6 lines
Quoted 5 lines
drivers/base/swnode.c +4 -0
+	if (!dst->is_inline && dst->length <= sizeof(dst->value)) {
+		/* We have an opportunity to move the data inline */
+		const void *tmp = dst->pointer;
+
Quoted 7 lines
Quoted 3 lines

drivers/base/swnode.c static int property_entry_copy_data(struct property_entry *dst, · line 284

Quoted 1 line
drivers/base/swnode.c +1 -0
+		memcpy(&dst->value, tmp, dst->length);

...because this is strange trick.

Not sure what is so strange about it. You just take data that is stored separately and move it into the structure, provided that it is not too big (i.e. it does not exceed sizeof(value union) size).

You store a value as union, but going to read as a member of union? I'm pretty sure it breaks standard rules.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#34 lore raw

Re: [PATCH v5 11/14] software node: move small properties inline when copying

Quoted 29 lines · Andy Shevchenko
Quoted 28 lines · Dmitry Torokhov
Quoted 5 lines · Andy Shevchenko
Quoted 4 lines · Dmitry Torokhov

When copying/duplicating set of properties, move smaller properties that were stored separately directly inside property entry structures. We can move:

Quoted 7 lines
Quoted 5 lines

- up to 8 bytes from U8 arrays
- up to 4 words
- up to 2 double words
- one U64 value
- one or 2 strings.

Can you show where you extract such values?

the "value" union's largest member is u64, which is 8 bytes. Strings are pointers, so on 32-bit arches you can stuff 2 pointers into 8 bytes, while on 64-bits you have space for only one.

Quoted 9 lines

drivers/base/swnode.c static int property_entry_copy_data(struct property_entry *dst, · line 284

Quoted 7 lines
drivers/base/swnode.c +5 -0
+	if (!dst->is_inline && dst->length <= sizeof(dst->value)) {
+		/* We have an opportunity to move the data inline */
+		const void *tmp = dst->pointer;
+
 
+		memcpy(&dst->value, tmp, dst->length);

...because this is strange trick.

Quoted 6 lines
Quoted 3 lines

Not sure what is so strange about it. You just take data that is stored separately and move it into the structure, provided that it is not too big (i.e. it does not exceed sizeof(value union) size).

You store a value as union, but going to read as a member of union? I'm pretty sure it breaks standard rules.

No, I move the values _in place_ of the union, and the data is always fetched via void pointers. And copying data via char * or memcpy() is allowed even in C99 and C11.

But I am wondering why are we actually worrying about all of this? The kernel is gnu89 and I think is going to stay this way because we use initializers with a cast in a lot of places:

#define __RAW_SPIN_LOCK_UNLOCKED(lockname) \
(raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)

and C99 and gnu99 do not allow this. See
https://lore.kernel.org/lkml/[email protected]/

Thanks.

Signature · 1 line
Dmitry
#35 lore raw

Re: [PATCH v5 11/14] software node: move small properties inline when copying

Quoted 14 lines · Dmitry Torokhov
Quoted 4 lines · Andy Shevchenko

On Tue, Oct 15, 2019 at 11:25:53AM -0700, Dmitry Torokhov wrote:

You store a value as union, but going to read as a member of union? I'm pretty sure it breaks standard rules.

No, I move the values _in place_ of the union, and the data is always fetched via void pointers. And copying data via char * or memcpy() is allowed even in C99 and C11.

But I am wondering why are we actually worrying about all of this? The kernel is gnu89 and I think is going to stay this way because we use initializers with a cast in a lot of places:

Quoted 5 lines

#define __RAW_SPIN_LOCK_UNLOCKED(lockname) \
(raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)

and C99 and gnu99 do not allow this. See
https://lore.kernel.org/lkml/[email protected]/

This is simple not a cast.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#36 lore raw

Re: [PATCH v5 11/14] software node: move small properties inline when copying

Quoted 15 lines · Andy Shevchenko
Quoted 14 lines · Dmitry Torokhov
Quoted 4 lines · Andy Shevchenko

On Tue, Oct 15, 2019 at 11:25:53AM -0700, Dmitry Torokhov wrote:

You store a value as union, but going to read as a member of union? I'm pretty sure it breaks standard rules.

No, I move the values _in place_ of the union, and the data is always fetched via void pointers. And copying data via char * or memcpy() is allowed even in C99 and C11.

But I am wondering why are we actually worrying about all of this? The kernel is gnu89 and I think is going to stay this way because we use initializers with a cast in a lot of places:

Quoted 7 lines
Quoted 5 lines

#define __RAW_SPIN_LOCK_UNLOCKED(lockname) \
(raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)

and C99 and gnu99 do not allow this. See
https://lore.kernel.org/lkml/[email protected]/

This is simple not a cast.

4.62 Compound literals in C99
ISO C99 supports compound literals. A compound literal looks like a cast followed by an initializer. Its value is an object of the type specified in the cast, containing the elements specified in the initializer. It is an lvalue.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#37 lore raw

Re: [PATCH v5 11/14] software node: move small properties inline when copying

Quoted 22 lines · Andy Shevchenko
Quoted 21 lines · Andy Shevchenko
Quoted 19 lines · Dmitry Torokhov
Quoted 4 lines · Andy Shevchenko

On Tue, Oct 15, 2019 at 11:25:53AM -0700, Dmitry Torokhov wrote:

You store a value as union, but going to read as a member of union? I'm pretty sure it breaks standard rules.

No, I move the values _in place_ of the union, and the data is always fetched via void pointers. And copying data via char * or memcpy() is allowed even in C99 and C11.

But I am wondering why are we actually worrying about all of this? The kernel is gnu89 and I think is going to stay this way because we use initializers with a cast in a lot of places:

#define __RAW_SPIN_LOCK_UNLOCKED(lockname) \
(raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)

and C99 and gnu99 do not allow this. See
https://lore.kernel.org/lkml/[email protected]/

Quoted 6 lines
Quoted 1 line

This is simple not a cast.

4.62 Compound literals in C99
ISO C99 supports compound literals. A compound literal looks like a cast followed by an initializer. Its value is an object of the type specified in the cast, containing the elements specified in the initializer. It is an lvalue.

Yes, these are compound literals. And they can not be used as initializers:

https://lore.kernel.org/lkml/CAHk-=wgXBV57mz46ZB5XivjiSBGkM0cjuvnU2OWyfRF=+41NPQ@mail.gmail.com/

Thanks.

Signature · 1 line
Dmitry
#38 lore raw

Re: [PATCH v5 11/14] software node: move small properties inline when copying

In reply to Dmitry Torokhov
Quoted 22 lines · Dmitry Torokhov

When copying/duplicating set of properties, move smaller properties that were stored separately directly inside property entry structures. We can move:

- up to 8 bytes from U8 arrays
- up to 4 words
- up to 2 double words
- one U64 value
- one or 2 strings.

---
 drivers/base/swnode.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/base/swnode.c +0 -0
index ae4b24ee2a54..546fc1b20095 100644
@@ -277,6 +277,16 @@ static int property_entry_copy_data(struct property_entry *dst,
 		dst->value = src->value;
 	}

drivers/base/swnode.c static int property_entry_copy_data(struct property_entry *dst, · line 288

Quoted 10 lines
drivers/base/swnode.c +9 -0
 
+	if (!dst->is_inline && dst->length <= sizeof(dst->value)) {
+		/* We have an opportunity to move the data inline */
+		const void *tmp = dst->pointer;
+
+		memcpy(&dst->value, tmp, dst->length);
+		dst->is_inline = true;
+
+		kfree(tmp);
+	}

This chunk needs to be moved to after dst->length is assigned. I'll send updated version after I get more feedback.

drivers/base/swnode.c static int property_entry_copy_data(struct property_entry *dst, · line 292

Quoted 4 lines
drivers/base/swnode.c +1 -0
+
 	dst->length = src->length;
 	dst->type = src->type;
 	dst->name = kstrdup(src->name, GFP_KERNEL);

Thanks.

Signature · 1 line
Dmitry
#39 lore raw

PATCH v5 12/14 software node: implement reference properties

In reply to Dmitry Torokhov

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:

static const struct software_node gpio_bank_b_node = {
	.name = "B",
};
static const struct property_entry simone_key_enter_props[] = {
	PROPERTY_ENTRY_U32("linux,code", KEY_ENTER),
	PROPERTY_ENTRY_STRING("label", "enter"),
	PROPERTY_ENTRY_REF("gpios", &gpio_bank_b_node, 123, GPIO_ACTIVE_LOW),
	{ }
};
---
 drivers/base/swnode.c    | 48 +++++++++++++++++++++++++++------
 include/linux/property.h | 57 +++++++++++++++++++++++++++++-----------
 2 files changed, 81 insertions(+), 24 deletions(-)
drivers/base/swnode.c +40 -8
index 546fc1b20095..a5b592a4e956 100644
@@ -265,6 +265,12 @@ static int property_entry_copy_data(struct property_entry *dst,
 		}
 
 		dst->pointer = new;
+	} else if (src->type == DEV_PROP_REF) {
+		/*
+		 * Reference properties are never stored inline as
+		 * they are too big.
+		 */
+		return -EINVAL;
 	} else if (src->type == DEV_PROP_STRING) {
 		new = kstrdup(src->value.str, GFP_KERNEL);
 		if (!new && src->value.str)
@@ -460,21 +466,47 @@ 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_array;
+	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;
+		/*
+		 * We expect that references are never stored inline, even
+		 * single ones, as they are too big.
+		 */
+		if (prop->is_inline)
+			return -EINVAL;
+
+		if (index * sizeof(*ref_args) >= prop->length)
+			return -ENOENT;
+
+		ref_array = prop->pointer;
+		ref_args = &ref_array[index];
+	} 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;
 
@@ -493,7 +525,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;
 }
include/linux/property.h +41 -16

105 lines not on this page · raw message

Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#40 lore raw

PATCH v5 13/14 platform/x86: intel_cht_int33fe: use inline reference properties

In reply to Dmitry Torokhov

Now that static device properties allow defining reference properties together with all other types of properties, instead of managing them separately, let's adjust the driver.

---
 drivers/platform/x86/intel_cht_int33fe.c | 81 ++++++++++++------------
 1 file changed, 41 insertions(+), 40 deletions(-)
drivers/platform/x86/intel_cht_int33fe.c +41 -40
index 1d5d877b9582..4177c5424931 100644
@@ -46,30 +46,6 @@ struct cht_int33fe_data {
 	struct fwnode_handle *dp;
 };
 
-static const struct software_node nodes[];
-
-static const struct software_node_ref_args pi3usb30532_ref = {
-	&nodes[INT33FE_NODE_PI3USB30532]
-};
-
-static const struct software_node_ref_args dp_ref = {
-	&nodes[INT33FE_NODE_DISPLAYPORT]
-};
-
-static struct software_node_ref_args mux_ref;
-
-static const struct software_node_reference usb_connector_refs[] = {
-	{ "orientation-switch", 1, &pi3usb30532_ref},
-	{ "mode-switch", 1, &pi3usb30532_ref},
-	{ "displayport", 1, &dp_ref},
-	{ }
-};
-
-static const struct software_node_reference fusb302_refs[] = {
-	{ "usb-role-switch", 1, &mux_ref},
-	{ }
-};
-
 /*
  * Grrr I severly dislike buggy BIOS-es. At least one BIOS enumerates
  * the max17047 both through the INT33FE ACPI device (it is right there
@@ -105,8 +81,18 @@ static const struct property_entry max17047_props[] = {
 	{ }
 };
 
+/*
+ * We are not using inline property here because those are constant,
+ * and we need to adjust this one at runtime to point to real
+ * software node.
+ */
+static struct software_node_ref_args fusb302_mux_refs[] = {
+	{ .node = NULL },
+};
+
 static const struct property_entry fusb302_props[] = {
 	PROPERTY_ENTRY_STRING("linux,extcon-name", "cht_wcove_pwrsrc"),
+	PROPERTY_ENTRY_REF_ARRAY("usb-role-switch", fusb302_mux_refs),
 	{ }
 };
 
@@ -122,6 +108,8 @@ static const u32 snk_pdo[] = {
 	PDO_VAR(5000, 12000, 3000),
 };
 
+static const struct software_node nodes[];
+
 static const struct property_entry usb_connector_props[] = {
 	PROPERTY_ENTRY_STRING("data-role", "dual"),
 	PROPERTY_ENTRY_STRING("power-role", "dual"),
@@ -129,15 +117,21 @@ static const struct property_entry usb_connector_props[] = {
 	PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo),
 	PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo),
 	PROPERTY_ENTRY_U32("op-sink-microwatt", 2500000),
+	PROPERTY_ENTRY_REF("orientation-switch",
+			   &nodes[INT33FE_NODE_PI3USB30532]),
+	PROPERTY_ENTRY_REF("mode-switch",
+			   &nodes[INT33FE_NODE_PI3USB30532]),
+	PROPERTY_ENTRY_REF("displayport",
+			   &nodes[INT33FE_NODE_DISPLAYPORT]),
 	{ }
 };
 
 static const struct software_node nodes[] = {
-	{ "fusb302", NULL, fusb302_props, fusb302_refs },
+	{ "fusb302", NULL, fusb302_props },
 	{ "max17047", NULL, max17047_props },
 	{ "pi3usb30532" },
 	{ "displayport" },
-	{ "connector", &nodes[0], usb_connector_props, usb_connector_refs },
+	{ "connector", &nodes[0], usb_connector_props },
 	{ }
 };
 
@@ -173,9 +167,10 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
 {
 	software_node_unregister_nodes(nodes);
 
-	if (mux_ref.node) {
-		fwnode_handle_put(software_node_fwnode(mux_ref.node));
-		mux_ref.node = NULL;
+	if (fusb302_mux_refs[0].node) {
+		fwnode_handle_put(
+			software_node_fwnode(fusb302_mux_refs[0].node));
+		fusb302_mux_refs[0].node = NULL;
 	}
 
 	if (data->dp) {
@@ -187,25 +182,31 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
 
 static int cht_int33fe_add_nodes(struct cht_int33fe_data *data)
 {
+	const struct software_node *mux_ref_node;
 	int ret;
 
-	ret = software_node_register_nodes(nodes);
-	if (ret)
-		return ret;
-
-	/* The devices that are not created in this driver need extra steps. */
-
 	/*
 	 * There is no ACPI device node for the USB role mux, so we need to wait
 	 * until the mux driver has created software node for the mux device.
 	 * It means we depend on the mux driver. This function will return
 	 * -EPROBE_DEFER until the mux device is registered.
 	 */
-	mux_ref.node = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
-	if (!mux_ref.node) {
-		ret = -EPROBE_DEFER;
-		goto err_remove_nodes;
-	}
+	mux_ref_node = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
+	if (!mux_ref_node)
+		return -EPROBE_DEFER;
+
+	/*
+	 * Update node used in "usb-role-switch" property. Note that we
+	 * rely on software_node_register_nodes() to use the original
+	 * instance of properties instead of copying them.
+	 */
+	fusb302_mux_refs[0].node = mux_ref_node;
+
+	ret = software_node_register_nodes(nodes);
+	if (ret)
+		return ret;
+
+	/* The devices that are not created in this driver need extra steps. */
 
 	/*
 	 * The DP connector does have ACPI device node. In this case we can just
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
reviewer Acked-by on v5 13/14
#41 lore raw

Re: [PATCH v5 13/14] platform/x86: intel_cht_int33fe: use inline reference properties

Quoted 4 lines · Dmitry Torokhov

Now that static device properties allow defining reference properties together with all other types of properties, instead of managing them separately, let's adjust the driver.

as an idea, whatever implementation we will settle on.

Quoted 152 lines
---
 drivers/platform/x86/intel_cht_int33fe.c | 81 ++++++++++++------------
 1 file changed, 41 insertions(+), 40 deletions(-)
drivers/platform/x86/intel_cht_int33fe.c +41 -40
index 1d5d877b9582..4177c5424931 100644
@@ -46,30 +46,6 @@ struct cht_int33fe_data {
 	struct fwnode_handle *dp;
 };
 
-static const struct software_node nodes[];
-
-static const struct software_node_ref_args pi3usb30532_ref = {
-	&nodes[INT33FE_NODE_PI3USB30532]
-};
-
-static const struct software_node_ref_args dp_ref = {
-	&nodes[INT33FE_NODE_DISPLAYPORT]
-};
-
-static struct software_node_ref_args mux_ref;
-
-static const struct software_node_reference usb_connector_refs[] = {
-	{ "orientation-switch", 1, &pi3usb30532_ref},
-	{ "mode-switch", 1, &pi3usb30532_ref},
-	{ "displayport", 1, &dp_ref},
-	{ }
-};
-
-static const struct software_node_reference fusb302_refs[] = {
-	{ "usb-role-switch", 1, &mux_ref},
-	{ }
-};
-
 /*
  * Grrr I severly dislike buggy BIOS-es. At least one BIOS enumerates
  * the max17047 both through the INT33FE ACPI device (it is right there
@@ -105,8 +81,18 @@ static const struct property_entry max17047_props[] = {
 	{ }
 };
 
+/*
+ * We are not using inline property here because those are constant,
+ * and we need to adjust this one at runtime to point to real
+ * software node.
+ */
+static struct software_node_ref_args fusb302_mux_refs[] = {
+	{ .node = NULL },
+};
+
 static const struct property_entry fusb302_props[] = {
 	PROPERTY_ENTRY_STRING("linux,extcon-name", "cht_wcove_pwrsrc"),
+	PROPERTY_ENTRY_REF_ARRAY("usb-role-switch", fusb302_mux_refs),
 	{ }
 };
 
@@ -122,6 +108,8 @@ static const u32 snk_pdo[] = {
 	PDO_VAR(5000, 12000, 3000),
 };
 
+static const struct software_node nodes[];
+
 static const struct property_entry usb_connector_props[] = {
 	PROPERTY_ENTRY_STRING("data-role", "dual"),
 	PROPERTY_ENTRY_STRING("power-role", "dual"),
@@ -129,15 +117,21 @@ static const struct property_entry usb_connector_props[] = {
 	PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo),
 	PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo),
 	PROPERTY_ENTRY_U32("op-sink-microwatt", 2500000),
+	PROPERTY_ENTRY_REF("orientation-switch",
+			   &nodes[INT33FE_NODE_PI3USB30532]),
+	PROPERTY_ENTRY_REF("mode-switch",
+			   &nodes[INT33FE_NODE_PI3USB30532]),
+	PROPERTY_ENTRY_REF("displayport",
+			   &nodes[INT33FE_NODE_DISPLAYPORT]),
 	{ }
 };
 
 static const struct software_node nodes[] = {
-	{ "fusb302", NULL, fusb302_props, fusb302_refs },
+	{ "fusb302", NULL, fusb302_props },
 	{ "max17047", NULL, max17047_props },
 	{ "pi3usb30532" },
 	{ "displayport" },
-	{ "connector", &nodes[0], usb_connector_props, usb_connector_refs },
+	{ "connector", &nodes[0], usb_connector_props },
 	{ }
 };
 
@@ -173,9 +167,10 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
 {
 	software_node_unregister_nodes(nodes);
 
-	if (mux_ref.node) {
-		fwnode_handle_put(software_node_fwnode(mux_ref.node));
-		mux_ref.node = NULL;
+	if (fusb302_mux_refs[0].node) {
+		fwnode_handle_put(
+			software_node_fwnode(fusb302_mux_refs[0].node));
+		fusb302_mux_refs[0].node = NULL;
 	}
 
 	if (data->dp) {
@@ -187,25 +182,31 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
 
 static int cht_int33fe_add_nodes(struct cht_int33fe_data *data)
 {
+	const struct software_node *mux_ref_node;
 	int ret;
 
-	ret = software_node_register_nodes(nodes);
-	if (ret)
-		return ret;
-
-	/* The devices that are not created in this driver need extra steps. */
-
 	/*
 	 * There is no ACPI device node for the USB role mux, so we need to wait
 	 * until the mux driver has created software node for the mux device.
 	 * It means we depend on the mux driver. This function will return
 	 * -EPROBE_DEFER until the mux device is registered.
 	 */
-	mux_ref.node = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
-	if (!mux_ref.node) {
-		ret = -EPROBE_DEFER;
-		goto err_remove_nodes;
-	}
+	mux_ref_node = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
+	if (!mux_ref_node)
+		return -EPROBE_DEFER;
+
+	/*
+	 * Update node used in "usb-role-switch" property. Note that we
+	 * rely on software_node_register_nodes() to use the original
+	 * instance of properties instead of copying them.
+	 */
+	fusb302_mux_refs[0].node = mux_ref_node;
+
+	ret = software_node_register_nodes(nodes);
+	if (ret)
+		return ret;
+
+	/* The devices that are not created in this driver need extra steps. */
 
 	/*
 	 * The DP connector does have ACPI device node. In this case we can just
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#42 lore raw

PATCH v5 14/14 software node: remove separate handling of references

In reply to Dmitry Torokhov

Now that all users of references have moved to reference properties, we can remove separate handling of references.

---
 drivers/base/swnode.c    | 46 +++++++++++++++-------------------------
 include/linux/property.h | 14 ------------
 2 files changed, 17 insertions(+), 43 deletions(-)
drivers/base/swnode.c +17 -29
index a5b592a4e956..4cb62cd105db 100644
@@ -465,9 +465,8 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
 				 struct fwnode_reference_args *args)
 {
 	struct swnode *swnode = to_swnode(fwnode);
-	const struct software_node_reference *ref;
 	const struct software_node_ref_args *ref_array;
-	const struct software_node_ref_args *ref_args;
+	const struct software_node_ref_args *ref;
 	const struct property_entry *prop;
 	struct fwnode_handle *refnode;
 	int i;
@@ -476,37 +475,26 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
 		return -ENOENT;
 
 	prop = property_entry_get(swnode->node->properties, propname);
-	if (prop) {
-		if (prop->type != DEV_PROP_REF)
-			return -EINVAL;
-
-		/*
-		 * We expect that references are never stored inline, even
-		 * single ones, as they are too big.
-		 */
-		if (prop->is_inline)
-			return -EINVAL;
-
-		if (index * sizeof(*ref_args) >= prop->length)
-			return -ENOENT;
+	if (!prop)
+		return -ENOENT;
 
-		ref_array = prop->pointer;
-		ref_args = &ref_array[index];
-	} else {
-		if (!swnode->node->references)
-			return -ENOENT;
+	if (prop->type != DEV_PROP_REF)
+		return -EINVAL;
 
-		for (ref = swnode->node->references; ref->name; ref++)
-			if (!strcmp(ref->name, propname))
-				break;
+	/*
+	 * We expect that references are never stored inline, even
+	 * single ones, as they are too big.
+	 */
+	if (prop->is_inline)
+		return -EINVAL;
 
-		if (!ref->name || index > (ref->nrefs - 1))
-			return -ENOENT;
+	if (index * sizeof(*ref) >= prop->length)
+		return -ENOENT;
 
-		ref_args = &ref->refs[index];
-	}
+	ref_array = prop->pointer;
+	ref = &ref_array[index];
 
-	refnode = software_node_fwnode(ref_args->node);
+	refnode = software_node_fwnode(ref->node);
 	if (!refnode)
 		return -ENOENT;
 
@@ -525,7 +513,7 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
 	args->nargs = nargs;
 
 	for (i = 0; i < nargs; i++)
-		args->args[i] = ref_args->args[i];
+		args->args[i] = ref->args[i];
 
 	return 0;
 }
include/linux/property.h +0 -14
index 08d3e9d126ef..fa5a2ddc0c7b 100644
@@ -412,30 +412,16 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
 /* -------------------------------------------------------------------------- */
 /* Software fwnode support - when HW description is incomplete or missing */
 
-/**
- * struct software_node_reference - Named software node reference property
- * @name: Name of the property
- * @nrefs: Number of elements in @refs array
- * @refs: Array of references with optional arguments
- */
-struct software_node_reference {
-	const char *name;
-	unsigned int nrefs;
-	const struct software_node_ref_args *refs;
-};
-
 /**
  * struct software_node - Software node description
  * @name: Name of the software node
  * @parent: Parent of the software node
  * @properties: Array of device properties
- * @references: Array of software node reference properties
  */
 struct software_node {
 	const char *name;
 	const struct software_node *parent;
 	const struct property_entry *properties;
-	const struct software_node_reference *references;
 };
 
 bool is_software_node(const struct fwnode_handle *fwnode);
Signature · 1 line
2.23.0.700.g56cf767bdb-goog
#43 lore raw
In reply to Dmitry Torokhov
Quoted 9 lines · Dmitry Torokhov

These series implement "references" properties for software nodes as true properties, instead of managing them completely separately.

The first 10 patches are generic cleanups and consolidation and unification of the existing code; patch #11 implements moving of small properties inline when copying property entries; patch #12 implements PROPERTY_ENTRY_REF() and friends; patch #13 converts the user of references to the property syntax, and patch #14 removes the remains of references as entities that are managed separately.

Can we get some test cases?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#44 lore raw
Quoted 4 lines · Andy Shevchenko
Quoted 3 lines · Dmitry Torokhov

These series implement "references" properties for software nodes as true properties, instead of managing them completely separately.

Quoted 8 lines
Quoted 6 lines

The first 10 patches are generic cleanups and consolidation and unification of the existing code; patch #11 implements moving of small properties inline when copying property entries; patch #12 implements PROPERTY_ENTRY_REF() and friends; patch #13 converts the user of references to the property syntax, and patch #14 removes the remains of references as entities that are managed separately.

Can we get some test cases?

Something like this? (I'll beef it up if we decide KUnit is OK for this).

From 0b8256ceed44760e63becb5b9636099d9fc17a4c Mon Sep 17 00:00:00 2001
From: Dmitry Torokhov <[email protected]>
Date: Mon, 14 Oct 2019 16:55:12 -0700
Subject: [PATCH] software node: add basic init tests

---
 drivers/base/test/Makefile              |  2 +
 drivers/base/test/property-entry-test.c | 56 +++++++++++++++++++++++++
 2 files changed, 58 insertions(+)
 create mode 100644 drivers/base/test/property-entry-test.c
drivers/base/test/Makefile +2 -0
index 0f1f7277a013..22143102e5d2 100644
@@ -1,2 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE)	+= test_async_driver_probe.o
+
+obj-$(CONFIG_KUNIT) += property-entry-test.o
drivers/base/test/property-entry-test.c new file +56 -0

56 lines not on this page · raw message

Signature · 5 lines
2.23.0.700.g56cf767bdb-goog


-- 
Dmitry
#45 lore raw
Quoted 12 lines · Dmitry Torokhov
Quoted 11 lines · Andy Shevchenko
Quoted 9 lines · Dmitry Torokhov

These series implement "references" properties for software nodes as true properties, instead of managing them completely separately.

The first 10 patches are generic cleanups and consolidation and unification of the existing code; patch #11 implements moving of small properties inline when copying property entries; patch #12 implements PROPERTY_ENTRY_REF() and friends; patch #13 converts the user of references to the property syntax, and patch #14 removes the remains of references as entities that are managed separately.

Quoted 4 lines
Quoted 1 line

Can we get some test cases?

Something like this? (I'll beef it up if we decide KUnit is OK for this).

As a starter, yes.

Signature · 2 lines
With Best Regards,
Andy Shevchenko