drivers/base/property.c became a bit of a kitchen sink, with code handling
generic device/fwnode properties intermingled with code handling static
properties (pset). Let's split them apart to not pollute each other.

Signed-off-by: Dmitry Torokhov <dmitry.torok...@gmail.com>
---
 drivers/base/Makefile        |   4 +-
 drivers/base/property.c      | 525 ----------------------------------
 drivers/base/pset_property.c | 540 +++++++++++++++++++++++++++++++++++
 3 files changed, 542 insertions(+), 527 deletions(-)
 create mode 100644 drivers/base/pset_property.c

diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 704f44295810..5f72cd5ab8ba 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -5,8 +5,8 @@ obj-y                   := component.o core.o bus.o dd.o 
syscore.o \
                           driver.o class.o platform.o \
                           cpu.o firmware.o init.o map.o devres.o \
                           attribute_container.o transport_class.o \
-                          topology.o container.o property.o cacheinfo.o \
-                          devcon.o
+                          topology.o container.o cacheinfo.o \
+                          property.o pset_property.o devcon.o
 obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
 obj-y                  += power/
 obj-$(CONFIG_ISA_BUS_API)      += isa.o
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 240ab5230ff6..d57df94e396c 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -18,236 +18,6 @@
 #include <linux/etherdevice.h>
 #include <linux/phy.h>
 
-struct property_set {
-       struct device *dev;
-       struct fwnode_handle fwnode;
-       const struct property_entry *properties;
-};
-
-static const struct fwnode_operations pset_fwnode_ops;
-
-static inline bool is_pset_node(const struct fwnode_handle *fwnode)
-{
-       return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &pset_fwnode_ops;
-}
-
-#define to_pset_node(__fwnode)                                         \
-       ({                                                              \
-               typeof(__fwnode) __to_pset_node_fwnode = __fwnode;      \
-                                                                       \
-               is_pset_node(__to_pset_node_fwnode) ?                   \
-                       container_of(__to_pset_node_fwnode,             \
-                                    struct property_set, fwnode) :     \
-                       NULL;                                           \
-       })
-
-static const struct property_entry *
-pset_prop_get(const struct property_set *pset, const char *name)
-{
-       const struct property_entry *prop;
-
-       if (!pset || !pset->properties)
-               return NULL;
-
-       for (prop = pset->properties; prop->name; prop++)
-               if (!strcmp(name, prop->name))
-                       return prop;
-
-       return NULL;
-}
-
-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:
-               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 *pset_prop_find(const struct property_set *pset,
-                                 const char *propname, size_t length)
-{
-       const struct property_entry *prop;
-       const void *pointer;
-
-       prop = pset_prop_get(pset, propname);
-       if (!prop)
-               return ERR_PTR(-EINVAL);
-       pointer = property_get_pointer(prop);
-       if (!pointer)
-               return ERR_PTR(-ENODATA);
-       if (length > prop->length)
-               return ERR_PTR(-EOVERFLOW);
-       return pointer;
-}
-
-static int pset_prop_read_u8_array(const struct property_set *pset,
-                                  const char *propname,
-                                  u8 *values, size_t nval)
-{
-       const void *pointer;
-       size_t length = nval * sizeof(*values);
-
-       pointer = pset_prop_find(pset, propname, length);
-       if (IS_ERR(pointer))
-               return PTR_ERR(pointer);
-
-       memcpy(values, pointer, length);
-       return 0;
-}
-
-static int pset_prop_read_u16_array(const struct property_set *pset,
-                                   const char *propname,
-                                   u16 *values, size_t nval)
-{
-       const void *pointer;
-       size_t length = nval * sizeof(*values);
-
-       pointer = pset_prop_find(pset, propname, length);
-       if (IS_ERR(pointer))
-               return PTR_ERR(pointer);
-
-       memcpy(values, pointer, length);
-       return 0;
-}
-
-static int pset_prop_read_u32_array(const struct property_set *pset,
-                                   const char *propname,
-                                   u32 *values, size_t nval)
-{
-       const void *pointer;
-       size_t length = nval * sizeof(*values);
-
-       pointer = pset_prop_find(pset, propname, length);
-       if (IS_ERR(pointer))
-               return PTR_ERR(pointer);
-
-       memcpy(values, pointer, length);
-       return 0;
-}
-
-static int pset_prop_read_u64_array(const struct property_set *pset,
-                                   const char *propname,
-                                   u64 *values, size_t nval)
-{
-       const void *pointer;
-       size_t length = nval * sizeof(*values);
-
-       pointer = pset_prop_find(pset, propname, length);
-       if (IS_ERR(pointer))
-               return PTR_ERR(pointer);
-
-       memcpy(values, pointer, length);
-       return 0;
-}
-
-static int pset_prop_count_elems_of_size(const struct property_set *pset,
-                                        const char *propname, size_t length)
-{
-       const struct property_entry *prop;
-
-       prop = pset_prop_get(pset, propname);
-       if (!prop)
-               return -EINVAL;
-
-       return prop->length / length;
-}
-
-static int pset_prop_read_string_array(const struct property_set *pset,
-                                      const char *propname,
-                                      const char **strings, size_t nval)
-{
-       const struct property_entry *prop;
-       const void *pointer;
-       size_t array_len, length;
-
-       /* Find out the array length. */
-       prop = pset_prop_get(pset, propname);
-       if (!prop)
-               return -EINVAL;
-
-       if (!prop->is_array)
-               /* The array length for a non-array string property is 1. */
-               array_len = 1;
-       else
-               /* Find the length of an array. */
-               array_len = pset_prop_count_elems_of_size(pset, propname,
-                                                         sizeof(const char *));
-
-       /* Return how many there are if strings is NULL. */
-       if (!strings)
-               return array_len;
-
-       array_len = min(nval, array_len);
-       length = array_len * sizeof(*strings);
-
-       pointer = pset_prop_find(pset, propname, length);
-       if (IS_ERR(pointer))
-               return PTR_ERR(pointer);
-
-       memcpy(strings, pointer, length);
-
-       return array_len;
-}
-
 struct fwnode_handle *dev_fwnode(struct device *dev)
 {
        return IS_ENABLED(CONFIG_OF) && dev->of_node ?
@@ -255,51 +25,6 @@ struct fwnode_handle *dev_fwnode(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dev_fwnode);
 
-static bool pset_fwnode_property_present(const struct fwnode_handle *fwnode,
-                                        const char *propname)
-{
-       return !!pset_prop_get(to_pset_node(fwnode), propname);
-}
-
-static int pset_fwnode_read_int_array(const struct fwnode_handle *fwnode,
-                                     const char *propname,
-                                     unsigned int elem_size, void *val,
-                                     size_t nval)
-{
-       const struct property_set *node = to_pset_node(fwnode);
-
-       if (!val)
-               return pset_prop_count_elems_of_size(node, propname, elem_size);
-
-       switch (elem_size) {
-       case sizeof(u8):
-               return pset_prop_read_u8_array(node, propname, val, nval);
-       case sizeof(u16):
-               return pset_prop_read_u16_array(node, propname, val, nval);
-       case sizeof(u32):
-               return pset_prop_read_u32_array(node, propname, val, nval);
-       case sizeof(u64):
-               return pset_prop_read_u64_array(node, propname, val, nval);
-       }
-
-       return -ENXIO;
-}
-
-static int
-pset_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
-                                      const char *propname,
-                                      const char **val, size_t nval)
-{
-       return pset_prop_read_string_array(to_pset_node(fwnode), propname,
-                                          val, nval);
-}
-
-static const struct fwnode_operations pset_fwnode_ops = {
-       .property_present = pset_fwnode_property_present,
-       .property_read_int_array = pset_fwnode_read_int_array,
-       .property_read_string_array = pset_fwnode_property_read_string_array,
-};
-
 /**
  * device_property_present - check if a property of a device is present
  * @dev: Device whose property is being checked
@@ -759,256 +484,6 @@ int fwnode_property_get_reference_args(const struct 
fwnode_handle *fwnode,
 }
 EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
 
-static void property_entry_free_data(const struct property_entry *p)
-{
-       const void *pointer = property_get_pointer(p);
-       size_t i, nval;
-
-       if (p->is_array) {
-               if (p->type == DEV_PROP_STRING && p->pointer.str) {
-                       nval = p->length / sizeof(const char *);
-                       for (i = 0; i < nval; i++)
-                               kfree(p->pointer.str[i]);
-               }
-               kfree(pointer);
-       } else if (p->type == DEV_PROP_STRING) {
-               kfree(p->value.str);
-       }
-       kfree(p->name);
-}
-
-static int property_copy_string_array(struct property_entry *dst,
-                                     const struct property_entry *src)
-{
-       const char **d;
-       size_t nval = src->length / sizeof(*d);
-       int i;
-
-       d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
-       if (!d)
-               return -ENOMEM;
-
-       for (i = 0; i < nval; i++) {
-               d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL);
-               if (!d[i] && src->pointer.str[i]) {
-                       while (--i >= 0)
-                               kfree(d[i]);
-                       kfree(d);
-                       return -ENOMEM;
-               }
-       }
-
-       dst->pointer.str = d;
-       return 0;
-}
-
-static int property_entry_copy_data(struct property_entry *dst,
-                                   const struct property_entry *src)
-{
-       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;
-               } else {
-                       new = kmemdup(pointer, src->length, GFP_KERNEL);
-                       if (!new)
-                               return -ENOMEM;
-               }
-       } else if (src->type == DEV_PROP_STRING) {
-               new = kstrdup(src->value.str, GFP_KERNEL);
-               if (!new && src->value.str)
-                       return -ENOMEM;
-       } else {
-               new = pointer;
-       }
-
-       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;
-
-       return 0;
-
-out_free_data:
-       property_entry_free_data(dst);
-       return -ENOMEM;
-}
-
-/**
- * property_entries_dup - duplicate array of properties
- * @properties: array of properties to copy
- *
- * This function creates a deep copy of the given NULL-terminated array
- * of property entries.
- */
-struct property_entry *
-property_entries_dup(const struct property_entry *properties)
-{
-       struct property_entry *p;
-       int i, n = 0;
-
-       while (properties[n].name)
-               n++;
-
-       p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return ERR_PTR(-ENOMEM);
-
-       for (i = 0; i < n; i++) {
-               int ret = property_entry_copy_data(&p[i], &properties[i]);
-               if (ret) {
-                       while (--i >= 0)
-                               property_entry_free_data(&p[i]);
-                       kfree(p);
-                       return ERR_PTR(ret);
-               }
-       }
-
-       return p;
-}
-EXPORT_SYMBOL_GPL(property_entries_dup);
-
-/**
- * property_entries_free - free previously allocated array of properties
- * @properties: array of properties to destroy
- *
- * This function frees given NULL-terminated array of property entries,
- * along with their data.
- */
-void property_entries_free(const struct property_entry *properties)
-{
-       const struct property_entry *p;
-
-       for (p = properties; p->name; p++)
-               property_entry_free_data(p);
-
-       kfree(properties);
-}
-EXPORT_SYMBOL_GPL(property_entries_free);
-
-/**
- * pset_free_set - releases memory allocated for copied property set
- * @pset: Property set to release
- *
- * Function takes previously copied property set and releases all the
- * memory allocated to it.
- */
-static void pset_free_set(struct property_set *pset)
-{
-       if (!pset)
-               return;
-
-       property_entries_free(pset->properties);
-       kfree(pset);
-}
-
-/**
- * pset_copy_set - copies property set
- * @pset: Property set to copy
- *
- * This function takes a deep copy of the given property set and returns
- * pointer to the copy. Call device_free_property_set() to free resources
- * allocated in this function.
- *
- * Return: Pointer to the new property set or error pointer.
- */
-static struct property_set *pset_copy_set(const struct property_set *pset)
-{
-       struct property_entry *properties;
-       struct property_set *p;
-
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return ERR_PTR(-ENOMEM);
-
-       properties = property_entries_dup(pset->properties);
-       if (IS_ERR(properties)) {
-               kfree(p);
-               return ERR_CAST(properties);
-       }
-
-       p->properties = properties;
-       return p;
-}
-
-/**
- * device_remove_properties - Remove properties from a device object.
- * @dev: Device whose properties to remove.
- *
- * The function removes properties previously associated to the device
- * secondary firmware node with device_add_properties(). Memory allocated
- * to the properties will also be released.
- */
-void device_remove_properties(struct device *dev)
-{
-       struct fwnode_handle *fwnode;
-       struct property_set *pset;
-
-       fwnode = dev_fwnode(dev);
-       if (!fwnode)
-               return;
-       /*
-        * Pick either primary or secondary node depending which one holds
-        * the pset. If there is no real firmware node (ACPI/DT) primary
-        * will hold the pset.
-        */
-       pset = to_pset_node(fwnode);
-       if (pset) {
-               set_primary_fwnode(dev, NULL);
-       } else {
-               pset = to_pset_node(fwnode->secondary);
-               if (pset && dev == pset->dev)
-                       set_secondary_fwnode(dev, NULL);
-       }
-       if (pset && dev == pset->dev)
-               pset_free_set(pset);
-}
-EXPORT_SYMBOL_GPL(device_remove_properties);
-
-/**
- * device_add_properties - Add a collection of properties to a device object.
- * @dev: Device to add properties to.
- * @properties: Collection of properties to add.
- *
- * Associate a collection of device properties represented by @properties with
- * @dev as its secondary firmware node. The function takes a copy of
- * @properties.
- */
-int device_add_properties(struct device *dev,
-                         const struct property_entry *properties)
-{
-       struct property_set *p, pset;
-
-       if (!properties)
-               return -EINVAL;
-
-       pset.properties = properties;
-
-       p = pset_copy_set(&pset);
-       if (IS_ERR(p))
-               return PTR_ERR(p);
-
-       p->fwnode.ops = &pset_fwnode_ops;
-       set_secondary_fwnode(dev, &p->fwnode);
-       p->dev = dev;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(device_add_properties);
-
 /**
  * fwnode_get_next_parent - Iterate to the node's parent
  * @fwnode: Firmware whose parent is retrieved
diff --git a/drivers/base/pset_property.c b/drivers/base/pset_property.c
new file mode 100644
index 000000000000..08ecc13080ae
--- /dev/null
+++ b/drivers/base/pset_property.c
@@ -0,0 +1,540 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Handling of device properties defined in legacy board files.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <rafael.j.wyso...@intel.com>
+ *          Mika Westerberg <mika.westerb...@linux.intel.com>
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+
+struct property_set {
+       struct device *dev;
+       struct fwnode_handle fwnode;
+       const struct property_entry *properties;
+};
+
+static const struct fwnode_operations pset_fwnode_ops;
+
+static inline bool is_pset_node(const struct fwnode_handle *fwnode)
+{
+       return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &pset_fwnode_ops;
+}
+
+#define to_pset_node(__fwnode)                                         \
+       ({                                                              \
+               typeof(__fwnode) __to_pset_node_fwnode = __fwnode;      \
+                                                                       \
+               is_pset_node(__to_pset_node_fwnode) ?                   \
+                       container_of(__to_pset_node_fwnode,             \
+                                    struct property_set, fwnode) :     \
+                       NULL;                                           \
+       })
+
+static const struct property_entry *
+pset_prop_get(const struct property_set *pset, const char *name)
+{
+       const struct property_entry *prop;
+
+       if (!pset || !pset->properties)
+               return NULL;
+
+       for (prop = pset->properties; prop->name; prop++)
+               if (!strcmp(name, prop->name))
+                       return prop;
+
+       return NULL;
+}
+
+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:
+               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 *pset_prop_find(const struct property_set *pset,
+                                 const char *propname, size_t length)
+{
+       const struct property_entry *prop;
+       const void *pointer;
+
+       prop = pset_prop_get(pset, propname);
+       if (!prop)
+               return ERR_PTR(-EINVAL);
+       pointer = property_get_pointer(prop);
+       if (!pointer)
+               return ERR_PTR(-ENODATA);
+       if (length > prop->length)
+               return ERR_PTR(-EOVERFLOW);
+       return pointer;
+}
+
+static int pset_prop_read_u8_array(const struct property_set *pset,
+                                  const char *propname,
+                                  u8 *values, size_t nval)
+{
+       const void *pointer;
+       size_t length = nval * sizeof(*values);
+
+       pointer = pset_prop_find(pset, propname, length);
+       if (IS_ERR(pointer))
+               return PTR_ERR(pointer);
+
+       memcpy(values, pointer, length);
+       return 0;
+}
+
+static int pset_prop_read_u16_array(const struct property_set *pset,
+                                   const char *propname,
+                                   u16 *values, size_t nval)
+{
+       const void *pointer;
+       size_t length = nval * sizeof(*values);
+
+       pointer = pset_prop_find(pset, propname, length);
+       if (IS_ERR(pointer))
+               return PTR_ERR(pointer);
+
+       memcpy(values, pointer, length);
+       return 0;
+}
+
+static int pset_prop_read_u32_array(const struct property_set *pset,
+                                   const char *propname,
+                                   u32 *values, size_t nval)
+{
+       const void *pointer;
+       size_t length = nval * sizeof(*values);
+
+       pointer = pset_prop_find(pset, propname, length);
+       if (IS_ERR(pointer))
+               return PTR_ERR(pointer);
+
+       memcpy(values, pointer, length);
+       return 0;
+}
+
+static int pset_prop_read_u64_array(const struct property_set *pset,
+                                   const char *propname,
+                                   u64 *values, size_t nval)
+{
+       const void *pointer;
+       size_t length = nval * sizeof(*values);
+
+       pointer = pset_prop_find(pset, propname, length);
+       if (IS_ERR(pointer))
+               return PTR_ERR(pointer);
+
+       memcpy(values, pointer, length);
+       return 0;
+}
+
+static int pset_prop_count_elems_of_size(const struct property_set *pset,
+                                        const char *propname, size_t length)
+{
+       const struct property_entry *prop;
+
+       prop = pset_prop_get(pset, propname);
+       if (!prop)
+               return -EINVAL;
+
+       return prop->length / length;
+}
+
+static int pset_prop_read_string_array(const struct property_set *pset,
+                                      const char *propname,
+                                      const char **strings, size_t nval)
+{
+       const struct property_entry *prop;
+       const void *pointer;
+       size_t array_len, length;
+
+       /* Find out the array length. */
+       prop = pset_prop_get(pset, propname);
+       if (!prop)
+               return -EINVAL;
+
+       if (!prop->is_array)
+               /* The array length for a non-array string property is 1. */
+               array_len = 1;
+       else
+               /* Find the length of an array. */
+               array_len = pset_prop_count_elems_of_size(pset, propname,
+                                                         sizeof(const char *));
+
+       /* Return how many there are if strings is NULL. */
+       if (!strings)
+               return array_len;
+
+       array_len = min(nval, array_len);
+       length = array_len * sizeof(*strings);
+
+       pointer = pset_prop_find(pset, propname, length);
+       if (IS_ERR(pointer))
+               return PTR_ERR(pointer);
+
+       memcpy(strings, pointer, length);
+
+       return array_len;
+}
+
+static bool pset_fwnode_property_present(const struct fwnode_handle *fwnode,
+                                        const char *propname)
+{
+       return !!pset_prop_get(to_pset_node(fwnode), propname);
+}
+
+static int pset_fwnode_read_int_array(const struct fwnode_handle *fwnode,
+                                     const char *propname,
+                                     unsigned int elem_size, void *val,
+                                     size_t nval)
+{
+       const struct property_set *node = to_pset_node(fwnode);
+
+       if (!val)
+               return pset_prop_count_elems_of_size(node, propname, elem_size);
+
+       switch (elem_size) {
+       case sizeof(u8):
+               return pset_prop_read_u8_array(node, propname, val, nval);
+       case sizeof(u16):
+               return pset_prop_read_u16_array(node, propname, val, nval);
+       case sizeof(u32):
+               return pset_prop_read_u32_array(node, propname, val, nval);
+       case sizeof(u64):
+               return pset_prop_read_u64_array(node, propname, val, nval);
+       }
+
+       return -ENXIO;
+}
+
+static int
+pset_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
+                                      const char *propname,
+                                      const char **val, size_t nval)
+{
+       return pset_prop_read_string_array(to_pset_node(fwnode), propname,
+                                          val, nval);
+}
+
+static const struct fwnode_operations pset_fwnode_ops = {
+       .property_present = pset_fwnode_property_present,
+       .property_read_int_array = pset_fwnode_read_int_array,
+       .property_read_string_array = pset_fwnode_property_read_string_array,
+};
+
+static void property_entry_free_data(const struct property_entry *p)
+{
+       const void *pointer = property_get_pointer(p);
+       size_t i, nval;
+
+       if (p->is_array) {
+               if (p->type == DEV_PROP_STRING && p->pointer.str) {
+                       nval = p->length / sizeof(const char *);
+                       for (i = 0; i < nval; i++)
+                               kfree(p->pointer.str[i]);
+               }
+               kfree(pointer);
+       } else if (p->type == DEV_PROP_STRING) {
+               kfree(p->value.str);
+       }
+       kfree(p->name);
+}
+
+static int property_copy_string_array(struct property_entry *dst,
+                                     const struct property_entry *src)
+{
+       const char **d;
+       size_t nval = src->length / sizeof(*d);
+       int i;
+
+       d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
+       if (!d)
+               return -ENOMEM;
+
+       for (i = 0; i < nval; i++) {
+               d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL);
+               if (!d[i] && src->pointer.str[i]) {
+                       while (--i >= 0)
+                               kfree(d[i]);
+                       kfree(d);
+                       return -ENOMEM;
+               }
+       }
+
+       dst->pointer.str = d;
+       return 0;
+}
+
+static int property_entry_copy_data(struct property_entry *dst,
+                                   const struct property_entry *src)
+{
+       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;
+               } else {
+                       new = kmemdup(pointer, src->length, GFP_KERNEL);
+                       if (!new)
+                               return -ENOMEM;
+               }
+       } else if (src->type == DEV_PROP_STRING) {
+               new = kstrdup(src->value.str, GFP_KERNEL);
+               if (!new && src->value.str)
+                       return -ENOMEM;
+       } else {
+               new = pointer;
+       }
+
+       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;
+
+       return 0;
+
+out_free_data:
+       property_entry_free_data(dst);
+       return -ENOMEM;
+}
+
+/**
+ * property_entries_dup - duplicate array of properties
+ * @properties: array of properties to copy
+ *
+ * This function creates a deep copy of the given NULL-terminated array
+ * of property entries.
+ */
+struct property_entry *
+property_entries_dup(const struct property_entry *properties)
+{
+       struct property_entry *p;
+       int i, n = 0;
+
+       while (properties[n].name)
+               n++;
+
+       p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return ERR_PTR(-ENOMEM);
+
+       for (i = 0; i < n; i++) {
+               int ret = property_entry_copy_data(&p[i], &properties[i]);
+               if (ret) {
+                       while (--i >= 0)
+                               property_entry_free_data(&p[i]);
+                       kfree(p);
+                       return ERR_PTR(ret);
+               }
+       }
+
+       return p;
+}
+EXPORT_SYMBOL_GPL(property_entries_dup);
+
+/**
+ * property_entries_free - free previously allocated array of properties
+ * @properties: array of properties to destroy
+ *
+ * This function frees given NULL-terminated array of property entries,
+ * along with their data.
+ */
+void property_entries_free(const struct property_entry *properties)
+{
+       const struct property_entry *p;
+
+       for (p = properties; p->name; p++)
+               property_entry_free_data(p);
+
+       kfree(properties);
+}
+EXPORT_SYMBOL_GPL(property_entries_free);
+
+/**
+ * pset_free_set - releases memory allocated for copied property set
+ * @pset: Property set to release
+ *
+ * Function takes previously copied property set and releases all the
+ * memory allocated to it.
+ */
+static void pset_free_set(struct property_set *pset)
+{
+       if (!pset)
+               return;
+
+       property_entries_free(pset->properties);
+       kfree(pset);
+}
+
+/**
+ * pset_copy_set - copies property set
+ * @pset: Property set to copy
+ *
+ * This function takes a deep copy of the given property set and returns
+ * pointer to the copy. Call device_free_property_set() to free resources
+ * allocated in this function.
+ *
+ * Return: Pointer to the new property set or error pointer.
+ */
+static struct property_set *pset_copy_set(const struct property_set *pset)
+{
+       struct property_entry *properties;
+       struct property_set *p;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return ERR_PTR(-ENOMEM);
+
+       properties = property_entries_dup(pset->properties);
+       if (IS_ERR(properties)) {
+               kfree(p);
+               return ERR_CAST(properties);
+       }
+
+       p->properties = properties;
+       return p;
+}
+
+/**
+ * device_remove_properties - Remove properties from a device object.
+ * @dev: Device whose properties to remove.
+ *
+ * The function removes properties previously associated to the device
+ * secondary firmware node with device_add_properties(). Memory allocated
+ * to the properties will also be released.
+ */
+void device_remove_properties(struct device *dev)
+{
+       struct fwnode_handle *fwnode;
+       struct property_set *pset;
+
+       fwnode = dev_fwnode(dev);
+       if (!fwnode)
+               return;
+       /*
+        * Pick either primary or secondary node depending which one holds
+        * the pset. If there is no real firmware node (ACPI/DT) primary
+        * will hold the pset.
+        */
+       pset = to_pset_node(fwnode);
+       if (pset) {
+               set_primary_fwnode(dev, NULL);
+       } else {
+               pset = to_pset_node(fwnode->secondary);
+               if (pset && dev == pset->dev)
+                       set_secondary_fwnode(dev, NULL);
+       }
+       if (pset && dev == pset->dev)
+               pset_free_set(pset);
+}
+EXPORT_SYMBOL_GPL(device_remove_properties);
+
+/**
+ * device_add_properties - Add a collection of properties to a device object.
+ * @dev: Device to add properties to.
+ * @properties: Collection of properties to add.
+ *
+ * Associate a collection of device properties represented by @properties with
+ * @dev as its secondary firmware node. The function takes a copy of
+ * @properties.
+ */
+int device_add_properties(struct device *dev,
+                         const struct property_entry *properties)
+{
+       struct property_set *p, pset;
+
+       if (!properties)
+               return -EINVAL;
+
+       pset.properties = properties;
+
+       p = pset_copy_set(&pset);
+       if (IS_ERR(p))
+               return PTR_ERR(p);
+
+       p->fwnode.ops = &pset_fwnode_ops;
+       set_secondary_fwnode(dev, &p->fwnode);
+       p->dev = dev;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(device_add_properties);
-- 
2.19.0.397.gdd90340f6a-goog

Reply via email to