summaryrefslogtreecommitdiffstats
path: root/0009-device-property-Take-a-copy-of-the-property-set.patch
diff options
context:
space:
mode:
Diffstat (limited to '0009-device-property-Take-a-copy-of-the-property-set.patch')
-rw-r--r--0009-device-property-Take-a-copy-of-the-property-set.patch247
1 files changed, 247 insertions, 0 deletions
diff --git a/0009-device-property-Take-a-copy-of-the-property-set.patch b/0009-device-property-Take-a-copy-of-the-property-set.patch
new file mode 100644
index 000000000..de24e9f4d
--- /dev/null
+++ b/0009-device-property-Take-a-copy-of-the-property-set.patch
@@ -0,0 +1,247 @@
+From 13141e1cb842ad6286c1cfa9a6b7c1577478d03b Mon Sep 17 00:00:00 2001
+From: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Mon, 30 Nov 2015 17:11:37 +0200
+Subject: [PATCH 09/16] device property: Take a copy of the property set
+
+It is convenient if the property set associated with the device secondary
+firmware node is a copy of the original. This allows passing property set
+from a stack for example for devices created dynamically. This also ties
+the property set lifetime to the associated device.
+
+Because of that we provide new function device_remove_property_set() that
+is used to disassociate and release memory allocated for the property set.
+
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/base/property.c | 191 ++++++++++++++++++++++++++++++++++++++++++-----
+ include/linux/property.h | 3 +-
+ 2 files changed, 175 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/base/property.c b/drivers/base/property.c
+index ebcbe34..0b22c8a 100644
+--- a/drivers/base/property.c
++++ b/drivers/base/property.c
+@@ -19,24 +19,6 @@
+ #include <linux/etherdevice.h>
+ #include <linux/phy.h>
+
+-/**
+- * device_add_property_set - Add a collection of properties to a device object.
+- * @dev: Device to add properties to.
+- * @pset: Collection of properties to add.
+- *
+- * Associate a collection of device properties represented by @pset with @dev
+- * as its secondary firmware node.
+- */
+-void device_add_property_set(struct device *dev, struct property_set *pset)
+-{
+- if (!pset)
+- return;
+-
+- pset->fwnode.type = FWNODE_PDATA;
+- set_secondary_fwnode(dev, &pset->fwnode);
+-}
+-EXPORT_SYMBOL_GPL(device_add_property_set);
+-
+ static inline bool is_pset_node(struct fwnode_handle *fwnode)
+ {
+ return fwnode && fwnode->type == FWNODE_PDATA;
+@@ -693,6 +675,179 @@ out:
+ EXPORT_SYMBOL_GPL(fwnode_property_match_string);
+
+ /**
++ * 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)
++{
++ const struct property_entry *prop;
++ size_t i, nval;
++
++ if (!pset)
++ return;
++
++ for (prop = pset->properties; prop->name; prop++) {
++ if (prop->is_array) {
++ if (prop->is_string && prop->pointer.str) {
++ nval = prop->length / sizeof(const char *);
++ for (i = 0; i < nval; i++)
++ kfree(prop->pointer.str[i]);
++ }
++ kfree(prop->pointer.raw_data);
++ } else if (prop->is_string) {
++ kfree(prop->value.str);
++ }
++ kfree(prop->name);
++ }
++
++ kfree(pset->properties);
++ kfree(pset);
++}
++
++static int pset_copy_entry(struct property_entry *dst,
++ const struct property_entry *src)
++{
++ const char **d, **s;
++ size_t i, nval;
++
++ dst->name = kstrdup(src->name, GFP_KERNEL);
++ if (!dst->name)
++ return -ENOMEM;
++
++ if (src->is_array) {
++ if (src->is_string) {
++ nval = src->length / sizeof(const char *);
++ dst->pointer.str = kcalloc(nval, sizeof(const char *),
++ GFP_KERNEL);
++ if (!dst->pointer.str)
++ return -ENOMEM;
++
++ d = dst->pointer.str;
++ s = src->pointer.str;
++ for (i = 0; i < nval; i++) {
++ d[i] = kstrdup(s[i], GFP_KERNEL);
++ if (!d[i] && s[i])
++ return -ENOMEM;
++ }
++ } else {
++ dst->pointer.raw_data = kmemdup(src->pointer.raw_data,
++ src->length, GFP_KERNEL);
++ if (!dst->pointer.raw_data)
++ return -ENOMEM;
++ }
++ } else if (src->is_string) {
++ dst->value.str = kstrdup(src->value.str, GFP_KERNEL);
++ if (!dst->value.str && src->value.str)
++ return -ENOMEM;
++ } else {
++ dst->value.raw_data = src->value.raw_data;
++ }
++
++ dst->length = src->length;
++ dst->is_array = src->is_array;
++ dst->is_string = src->is_string;
++
++ return 0;
++}
++
++/**
++ * 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)
++{
++ const struct property_entry *entry;
++ struct property_set *p;
++ size_t i, n = 0;
++
++ p = kzalloc(sizeof(*p), GFP_KERNEL);
++ if (!p)
++ return ERR_PTR(-ENOMEM);
++
++ while (pset->properties[n].name)
++ n++;
++
++ p->properties = kcalloc(n + 1, sizeof(*entry), GFP_KERNEL);
++ if (!p->properties) {
++ kfree(p);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ for (i = 0; i < n; i++) {
++ int ret = pset_copy_entry(&p->properties[i],
++ &pset->properties[i]);
++ if (ret) {
++ pset_free_set(p);
++ return ERR_PTR(ret);
++ }
++ }
++
++ return p;
++}
++
++/**
++ * device_remove_property_set - 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_property_set(). Memory allocated
++ * to the properties will also be released.
++ */
++void device_remove_property_set(struct device *dev)
++{
++ struct fwnode_handle *fwnode;
++
++ 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.
++ */
++ if (!is_pset_node(fwnode))
++ fwnode = fwnode->secondary;
++ if (!IS_ERR(fwnode) && is_pset_node(fwnode))
++ pset_free_set(to_pset_node(fwnode));
++ set_secondary_fwnode(dev, NULL);
++}
++EXPORT_SYMBOL_GPL(device_remove_property_set);
++
++/**
++ * device_add_property_set - Add a collection of properties to a device object.
++ * @dev: Device to add properties to.
++ * @pset: Collection of properties to add.
++ *
++ * Associate a collection of device properties represented by @pset with @dev
++ * as its secondary firmware node. The function takes a copy of @pset.
++ */
++int device_add_property_set(struct device *dev, const struct property_set *pset)
++{
++ struct property_set *p;
++
++ if (!pset)
++ return -EINVAL;
++
++ p = pset_copy_set(pset);
++ if (IS_ERR(p))
++ return PTR_ERR(p);
++
++ p->fwnode.type = FWNODE_PDATA;
++ set_secondary_fwnode(dev, &p->fwnode);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(device_add_property_set);
++
++/**
+ * device_get_next_child_node - Return the next child node handle for a device
+ * @dev: Device to find the next child node for.
+ * @child: Handle to one of the device's child nodes or a null handle.
+diff --git a/include/linux/property.h b/include/linux/property.h
+index d1cf208..3a8c7d7 100644
+--- a/include/linux/property.h
++++ b/include/linux/property.h
+@@ -240,7 +240,8 @@ struct property_set {
+ struct property_entry *properties;
+ };
+
+-void device_add_property_set(struct device *dev, struct property_set *pset);
++int device_add_property_set(struct device *dev, const struct property_set *pset);
++void device_remove_property_set(struct device *dev);
+
+ bool device_dma_supported(struct device *dev);
+
+--
+2.5.0
+