summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2019-11-08 05:22:22 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2019-12-03 11:46:20 +0100
commite64b674bc9d76edb4cf1b8c98446b1d29a16b9df (patch)
tree224cbf63c801ee5c3f1e5717260ebd8ca6d04ba1 /drivers/base
parentsoftware node: allow embedding of small arrays into property_entry (diff)
downloadlinux-e64b674bc9d76edb4cf1b8c98446b1d29a16b9df.tar.xz
linux-e64b674bc9d76edb4cf1b8c98446b1d29a16b9df.zip
software node: implement reference properties
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), { } }; Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/swnode.c49
1 files changed, 41 insertions, 8 deletions
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 3d422918a53d..604d7327bba7 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -246,6 +246,13 @@ static int property_entry_copy_data(struct property_entry *dst,
if (!src->is_inline && !src->length)
return -ENODATA;
+ /*
+ * Reference properties are never stored inline as
+ * they are too big.
+ */
+ if (src->type == DEV_PROP_REF && src->is_inline)
+ return -EINVAL;
+
if (src->length <= sizeof(dst->value)) {
dst_ptr = &dst->value;
dst->is_inline = true;
@@ -473,23 +480,49 @@ 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;
u32 nargs_prop_val;
int error;
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;
@@ -510,7 +543,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;
}