Skip to content

Commit

Permalink
software node: implement reference properties
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dmitry Torokhov authored and Rafael J. Wysocki committed Dec 3, 2019
1 parent 996b083 commit e64b674
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 24 deletions.
49 changes: 41 additions & 8 deletions drivers/base/swnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down
57 changes: 41 additions & 16 deletions include/linux/property.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum dev_prop_type {
DEV_PROP_U32,
DEV_PROP_U64,
DEV_PROP_STRING,
DEV_PROP_REF,
};

enum dev_dma_attr {
Expand Down Expand Up @@ -223,6 +224,20 @@ static inline int fwnode_property_count_u64(const struct fwnode_handle *fwnode,
return fwnode_property_read_u64_array(fwnode, propname, NULL, 0);
}

struct software_node;

/**
* struct software_node_ref_args - Reference property with additional arguments
* @node: Reference to a software node
* @nargs: Number of elements in @args array
* @args: Integer arguments
*/
struct software_node_ref_args {
const struct software_node *node;
unsigned int nargs;
u64 args[NR_FWNODE_REFERENCE_ARGS];
};

/**
* struct property_entry - "Built-in" device property representation.
* @name: Name of the property.
Expand Down Expand Up @@ -258,14 +273,20 @@ struct property_entry {
#define __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_) \
sizeof(((struct property_entry *)NULL)->value._elem_[0])

#define __PROPERTY_ENTRY_ARRAY_LEN(_name_, _elem_, _Type_, _val_, _len_)\
#define __PROPERTY_ENTRY_ARRAY_ELSIZE_LEN(_name_, _elsize_, _Type_, \
_val_, _len_) \
(struct property_entry) { \
.name = _name_, \
.length = (_len_) * __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_), \
.length = (_len_) * (_elsize_), \
.type = DEV_PROP_##_Type_, \
{ .pointer = _val_ }, \
}

#define __PROPERTY_ENTRY_ARRAY_LEN(_name_, _elem_, _Type_, _val_, _len_)\
__PROPERTY_ENTRY_ARRAY_ELSIZE_LEN(_name_, \
__PROPERTY_ENTRY_ELEMENT_SIZE(_elem_), \
_Type_, _val_, _len_)

#define PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, _len_) \
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u8_data, U8, _val_, _len_)
#define PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, _len_) \
Expand All @@ -276,6 +297,10 @@ struct property_entry {
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u64_data, U64, _val_, _len_)
#define PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, _len_) \
__PROPERTY_ENTRY_ARRAY_LEN(_name_, str, STRING, _val_, _len_)
#define PROPERTY_ENTRY_REF_ARRAY_LEN(_name_, _val_, _len_) \
__PROPERTY_ENTRY_ARRAY_ELSIZE_LEN(_name_, \
sizeof(struct software_node_ref_args), \
REF, _val_, _len_)

#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
Expand All @@ -287,6 +312,8 @@ struct property_entry {
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_REF_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_REF_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))

#define __PROPERTY_ENTRY_ELEMENT(_name_, _elem_, _Type_, _val_) \
(struct property_entry) { \
Expand Down Expand Up @@ -314,6 +341,18 @@ struct property_entry {
.is_inline = true, \
}

#define PROPERTY_ENTRY_REF(_name_, _ref_, ...) \
(struct property_entry) { \
.name = _name_, \
.length = sizeof(struct software_node_ref_args), \
.type = DEV_PROP_REF, \
{ .pointer = &(const struct software_node_ref_args) { \
.node = _ref_, \
.nargs = ARRAY_SIZE(((u64[]){ 0, ##__VA_ARGS__ })) - 1, \
.args = { __VA_ARGS__ }, \
} }, \
}

struct property_entry *
property_entries_dup(const struct property_entry *properties);

Expand Down Expand Up @@ -377,20 +416,6 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
/* -------------------------------------------------------------------------- */
/* Software fwnode support - when HW description is incomplete or missing */

struct software_node;

/**
* struct software_node_ref_args - Reference with additional arguments
* @node: Reference to a software node
* @nargs: Number of elements in @args array
* @args: Integer arguments
*/
struct software_node_ref_args {
const struct software_node *node;
unsigned int nargs;
u64 args[NR_FWNODE_REFERENCE_ARGS];
};

/**
* struct software_node_reference - Named software node reference property
* @name: Name of the property
Expand Down

0 comments on commit e64b674

Please sign in to comment.