diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-27 06:45:12 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-27 06:45:12 +0300 |
commit | 361b0d286afea0d867537536977a695b5557d133 (patch) | |
tree | a9a362c2f4b687435fc1b11f411f593f86d0467d /drivers/base | |
parent | 6e9f879684b46331f51d0c76ebee981c788417db (diff) | |
parent | 1afc14032e54a7e6c38304dc9a6bda1b6416f2b7 (diff) | |
download | linux-361b0d286afea0d867537536977a695b5557d133.tar.xz |
Merge tag 'devprop-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull device properties framework updates from Rafael Wysocki:
"Add support for printing fwnode names using a new conversion specifier
"%pfw" (Sakari Ailus), clean up the software node and
efi/apple-properties code in preparation for improved software node
reference properties handling (Dmitry Torokhov) and fix the struct
fwnode_operations description (Heikki Krogerus)"
* tag 'devprop-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (22 commits)
software node: simplify property_entry_read_string_array()
software node: unify PROPERTY_ENTRY_XXX macros
software node: remove property_entry_read_uNN_array functions
software node: get rid of property_set_pointer()
software node: clean up property_copy_string_array()
software node: mark internal macros with double underscores
efi/apple-properties: use PROPERTY_ENTRY_U8_ARRAY_LEN
software node: introduce PROPERTY_ENTRY_XXX_ARRAY_LEN()
software node: remove DEV_PROP_MAX
device property: Fix the description of struct fwnode_operations
lib/test_printf: Add tests for %pfw printk modifier
lib/vsprintf: Add %pfw conversion specifier for printing fwnode names
lib/vsprintf: OF nodes are first and foremost, struct device_nodes
lib/vsprintf: Make use of fwnode API to obtain node names and separators
lib/vsprintf: Add a note on re-using %pf or %pF
lib/vsprintf: Remove support for %pF and %pf in favour of %pS and %ps
device property: Add a function to obtain a node's prefix
device property: Add fwnode_get_name for returning the name of a node
device property: Add functions for accessing node's parents
device property: Move fwnode_get_parent() up
...
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/property.c | 83 | ||||
-rw-r--r-- | drivers/base/swnode.c | 258 |
2 files changed, 164 insertions, 177 deletions
diff --git a/drivers/base/property.c b/drivers/base/property.c index 81bd01ed4042..511f6d7acdfe 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -557,6 +557,42 @@ int device_add_properties(struct device *dev, EXPORT_SYMBOL_GPL(device_add_properties); /** + * fwnode_get_name - Return the name of a node + * @fwnode: The firmware node + * + * Returns a pointer to the node name. + */ +const char *fwnode_get_name(const struct fwnode_handle *fwnode) +{ + return fwnode_call_ptr_op(fwnode, get_name); +} + +/** + * fwnode_get_name_prefix - Return the prefix of node for printing purposes + * @fwnode: The firmware node + * + * Returns the prefix of a node, intended to be printed right before the node. + * The prefix works also as a separator between the nodes. + */ +const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode) +{ + return fwnode_call_ptr_op(fwnode, get_name_prefix); +} + +/** + * fwnode_get_parent - Return parent firwmare node + * @fwnode: Firmware whose parent is retrieved + * + * Return parent firmware node of the given node if possible or %NULL if no + * parent was available. + */ +struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode) +{ + return fwnode_call_ptr_op(fwnode, get_parent); +} +EXPORT_SYMBOL_GPL(fwnode_get_parent); + +/** * fwnode_get_next_parent - Iterate to the node's parent * @fwnode: Firmware whose parent is retrieved * @@ -578,17 +614,50 @@ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode) EXPORT_SYMBOL_GPL(fwnode_get_next_parent); /** - * fwnode_get_parent - Return parent firwmare node - * @fwnode: Firmware whose parent is retrieved + * fwnode_count_parents - Return the number of parents a node has + * @fwnode: The node the parents of which are to be counted * - * Return parent firmware node of the given node if possible or %NULL if no - * parent was available. + * Returns the number of parents a node has. */ -struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode) +unsigned int fwnode_count_parents(const struct fwnode_handle *fwnode) { - return fwnode_call_ptr_op(fwnode, get_parent); + struct fwnode_handle *__fwnode; + unsigned int count; + + __fwnode = fwnode_get_parent(fwnode); + + for (count = 0; __fwnode; count++) + __fwnode = fwnode_get_next_parent(__fwnode); + + return count; } -EXPORT_SYMBOL_GPL(fwnode_get_parent); +EXPORT_SYMBOL_GPL(fwnode_count_parents); + +/** + * fwnode_get_nth_parent - Return an nth parent of a node + * @fwnode: The node the parent of which is requested + * @depth: Distance of the parent from the node + * + * Returns the nth parent of a node. If there is no parent at the requested + * @depth, %NULL is returned. If @depth is 0, the functionality is equivalent to + * fwnode_handle_get(). For @depth == 1, it is fwnode_get_parent() and so on. + * + * The caller is responsible for calling fwnode_handle_put() for the returned + * node. + */ +struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode, + unsigned int depth) +{ + unsigned int i; + + fwnode_handle_get(fwnode); + + for (i = 0; i < depth && fwnode; i++) + fwnode = fwnode_get_next_parent(fwnode); + + return fwnode; +} +EXPORT_SYMBOL_GPL(fwnode_get_nth_parent); /** * fwnode_get_next_child_node - Return the next child node handle for a node diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index a1f3f0994f9f..d8d0dc0ca5ac 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -71,9 +71,9 @@ software_node_to_swnode(const struct software_node *node) return swnode; } -const struct software_node *to_software_node(struct fwnode_handle *fwnode) +const struct software_node *to_software_node(const struct fwnode_handle *fwnode) { - struct swnode *swnode = to_swnode(fwnode); + const struct swnode *swnode = to_swnode(fwnode); return swnode ? swnode->node : NULL; } @@ -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, @@ -187,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) @@ -265,49 +149,45 @@ 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, 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); @@ -322,13 +202,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) { @@ -337,29 +219,29 @@ 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; + const char * const *src_str = src->pointer; size_t nval = src->length / sizeof(*d); int i; 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); - 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); - return -ENOMEM; + return NULL; } } - dst->pointer.str = d; - return 0; + return d; } static int property_entry_copy_data(struct property_entry *dst, @@ -367,36 +249,35 @@ 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) 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; @@ -515,12 +396,47 @@ static int software_node_read_string_array(const struct fwnode_handle *fwnode, propname, val, nval); } +static const char * +software_node_get_name(const struct fwnode_handle *fwnode) +{ + const struct swnode *swnode = to_swnode(fwnode); + + if (!swnode) + return "(null)"; + + return kobject_name(&swnode->kobj); +} + +static const char * +software_node_get_name_prefix(const struct fwnode_handle *fwnode) +{ + struct fwnode_handle *parent; + const char *prefix; + + parent = fwnode_get_parent(fwnode); + if (!parent) + return ""; + + /* Figure out the prefix from the parents. */ + while (is_software_node(parent)) + parent = fwnode_get_next_parent(parent); + + prefix = fwnode_get_name_prefix(parent); + fwnode_handle_put(parent); + + /* Guess something if prefix was NULL. */ + return prefix ?: "/"; +} + static struct fwnode_handle * software_node_get_parent(const struct fwnode_handle *fwnode) { struct swnode *swnode = to_swnode(fwnode); - return swnode ? (swnode->parent ? &swnode->parent->fwnode : NULL) : NULL; + if (!swnode || !swnode->parent) + return NULL; + + return fwnode_handle_get(&swnode->parent->fwnode); } static struct fwnode_handle * @@ -612,6 +528,8 @@ static const struct fwnode_operations software_node_ops = { .property_present = software_node_property_present, .property_read_int_array = software_node_read_int_array, .property_read_string_array = software_node_read_string_array, + .get_name = software_node_get_name, + .get_name_prefix = software_node_get_name_prefix, .get_parent = software_node_get_parent, .get_next_child_node = software_node_get_next_child, .get_named_child_node = software_node_get_named_child_node, |