1
0
Fork 0

Device properties framework updates for 5.5-rc1

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).
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAl3dHU0SHHJqd0Byand5
 c29ja2kubmV0AAoJEILEb/54YlRx1JkP/j/YkE6VsMlXqL+3kMABXfVlAIZtkZ71
 YB13wtGHdz0hewvCFJDLZuJ3+axbR5Lk60tqX+lfG6GvWMtudZ+URkZ0KIUBhDXM
 uwVniqcWvlItMGo+cU7FLW1rKkRDCQ75x4GlKD1MivCG+PZXYqkH/ESQZgi3TdwD
 0rYGzUx4nBKzS9yJ6ZnBhSOGRq9sGGHgOr20LjYlAplcOMhE6PP+SQNCfKVk8DE8
 ZolavWpmD+nsV97qWGLpJOKWJXplCv+lWX8cQICvONRSWPHq6ehQ4HONnLDtPai3
 EcyGQ3LbuVMYKOWUVRYs2X+wvgmAz461Y+Du8FO1QzYuNMYzArRx2naD1LIIUT6Q
 UE8RRkN2YyqvVmSLlAYAJPH7GCP8mRZV2gHfmS7fF16jUpTOiDHKiZFjOgvSc/lp
 31DhBpWr64NgSOSpqi/bX6fSYVv9YGPOd0J8dPNsaGZbHZxJJ2cmZ092u6Rrx6VG
 x1qO2j2c2xC6Y+pEMCBCqjDUmhFD5P6O7qVky/9kyZv9AWyBlEpni7tdu8J6DqVG
 RUB0zq5jujfBoTtBFFpVxDiQYvctTs/T9te48DQkdCli0J/bUEEyNw5nX6HKnjZM
 jyrh93Th512W0JwbPWpJXn1JJMdxkNitwlLRwnhCSSTdcLZiHzDoYdf7taSemvX5
 ZJZYhPG5T6i5
 =VcCH
 -----END PGP SIGNATURE-----

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
  ...
alistair/sunxi64-5.5-dsi
Linus Torvalds 2019-11-26 19:45:12 -08:00
commit 361b0d286a
11 changed files with 413 additions and 292 deletions

View File

@ -98,8 +98,6 @@ Symbols/Function Pointers
%pS versatile_init+0x0/0x110
%ps versatile_init
%pF versatile_init+0x0/0x110
%pf versatile_init
%pSR versatile_init+0x9/0x110
(with __builtin_extract_return_addr() translation)
%pB prev_fn_of_versatile_init+0x88/0x88
@ -109,14 +107,6 @@ The ``S`` and ``s`` specifiers are used for printing a pointer in symbolic
format. They result in the symbol name with (S) or without (s)
offsets. If KALLSYMS are disabled then the symbol address is printed instead.
Note, that the ``F`` and ``f`` specifiers are identical to ``S`` (``s``)
and thus deprecated. We have ``F`` and ``f`` because on ia64, ppc64 and
parisc64 function pointers are indirect and, in fact, are function
descriptors, which require additional dereferencing before we can lookup
the symbol. As of now, ``S`` and ``s`` perform dereferencing on those
platforms (when needed), so ``F`` and ``f`` exist for compatibility
reasons only.
The ``B`` specifier results in the symbol name with offsets and should be
used when printing stack backtraces. The specifier takes into
consideration the effect of compiler optimisations which may occur
@ -440,6 +430,30 @@ Examples::
Passed by reference.
Fwnode handles
--------------
::
%pfw[fP]
For printing information on fwnode handles. The default is to print the full
node name, including the path. The modifiers are functionally equivalent to
%pOF above.
- f - full name of the node, including the path
- P - the name of the node including an address (if there is one)
Examples (ACPI)::
%pfwf \_SB.PCI0.CIO2.port@1.endpoint@0 - Full node name
%pfwP endpoint@0 - Node name
Examples (OF)::
%pfwf /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name
%pfwP endpoint - Node name
Time and date (struct rtc_time)
-------------------------------

View File

@ -1317,6 +1317,52 @@ acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
args_count, args);
}
static const char *acpi_fwnode_get_name(const struct fwnode_handle *fwnode)
{
const struct acpi_device *adev;
struct fwnode_handle *parent;
/* Is this the root node? */
parent = fwnode_get_parent(fwnode);
if (!parent)
return "\\";
fwnode_handle_put(parent);
if (is_acpi_data_node(fwnode)) {
const struct acpi_data_node *dn = to_acpi_data_node(fwnode);
return dn->name;
}
adev = to_acpi_device_node(fwnode);
if (WARN_ON(!adev))
return NULL;
return acpi_device_bid(adev);
}
static const char *
acpi_fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
{
struct fwnode_handle *parent;
/* Is this the root node? */
parent = fwnode_get_parent(fwnode);
if (!parent)
return "";
/* Is this 2nd node from the root? */
parent = fwnode_get_next_parent(parent);
if (!parent)
return "";
fwnode_handle_put(parent);
/* ACPI device or data node. */
return ".";
}
static struct fwnode_handle *
acpi_fwnode_get_parent(struct fwnode_handle *fwnode)
{
@ -1357,6 +1403,8 @@ acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
.get_parent = acpi_node_get_parent, \
.get_next_child_node = acpi_get_next_subnode, \
.get_named_child_node = acpi_fwnode_get_named_child_node, \
.get_name = acpi_fwnode_get_name, \
.get_name_prefix = acpi_fwnode_get_name_prefix, \
.get_reference_args = acpi_fwnode_get_reference_args, \
.graph_get_next_endpoint = \
acpi_graph_get_next_endpoint, \

View File

@ -556,6 +556,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

View File

@ -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,

View File

@ -53,7 +53,8 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
for (i = 0; i < dev_header->prop_count; i++) {
int remaining = dev_header->len - (ptr - (void *)dev_header);
u32 key_len, val_len;
u32 key_len, val_len, entry_len;
const u8 *entry_data;
char *key;
if (sizeof(key_len) > remaining)
@ -85,17 +86,14 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
ucs2_as_utf8(key, ptr + sizeof(key_len),
key_len - sizeof(key_len));
entry[i].name = key;
entry[i].length = val_len - sizeof(val_len);
entry[i].is_array = !!entry[i].length;
entry[i].type = DEV_PROP_U8;
entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len);
entry_data = ptr + key_len + sizeof(val_len);
entry_len = val_len - sizeof(val_len);
entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data,
entry_len);
if (dump_properties) {
dev_info(dev, "property: %s\n", entry[i].name);
dev_info(dev, "property: %s\n", key);
print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
16, 1, entry[i].pointer.u8_data,
entry[i].length, true);
16, 1, entry_data, entry_len, true);
}
ptr += key_len + val_len;

View File

@ -872,6 +872,20 @@ of_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
of_property_count_strings(node, propname);
}
static const char *of_fwnode_get_name(const struct fwnode_handle *fwnode)
{
return kbasename(to_of_node(fwnode)->full_name);
}
static const char *of_fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
{
/* Root needs no prefix here (its name is "/"). */
if (!to_of_node(fwnode)->parent)
return "";
return "/";
}
static struct fwnode_handle *
of_fwnode_get_parent(const struct fwnode_handle *fwnode)
{
@ -993,6 +1007,8 @@ const struct fwnode_operations of_fwnode_ops = {
.property_present = of_fwnode_property_present,
.property_read_int_array = of_fwnode_property_read_int_array,
.property_read_string_array = of_fwnode_property_read_string_array,
.get_name = of_fwnode_get_name,
.get_name_prefix = of_fwnode_get_name_prefix,
.get_parent = of_fwnode_get_parent,
.get_next_child_node = of_fwnode_get_next_child_node,
.get_named_child_node = of_fwnode_get_named_child_node,

View File

@ -49,13 +49,15 @@ struct fwnode_reference_args {
* struct fwnode_operations - Operations for fwnode interface
* @get: Get a reference to an fwnode.
* @put: Put a reference to an fwnode.
* @device_is_available: Return true if the device is available.
* @device_get_match_data: Return the device driver match data.
* @property_present: Return true if a property is present.
* @property_read_integer_array: Read an array of integer properties. Return
* zero on success, a negative error code
* otherwise.
* @property_read_int_array: Read an array of integer properties. Return zero on
* success, a negative error code otherwise.
* @property_read_string_array: Read an array of string properties. Return zero
* on success, a negative error code otherwise.
* @get_name: Return the name of an fwnode.
* @get_name_prefix: Get a prefix for a node (for printing purposes).
* @get_parent: Return the parent of an fwnode.
* @get_next_child_node: Return the next child node in an iteration.
* @get_named_child_node: Return a child node with a given name.
@ -82,6 +84,8 @@ struct fwnode_operations {
(*property_read_string_array)(const struct fwnode_handle *fwnode_handle,
const char *propname, const char **val,
size_t nval);
const char *(*get_name)(const struct fwnode_handle *fwnode);
const char *(*get_name_prefix)(const struct fwnode_handle *fwnode);
struct fwnode_handle *(*get_parent)(const struct fwnode_handle *fwnode);
struct fwnode_handle *
(*get_next_child_node)(const struct fwnode_handle *fwnode,

View File

@ -22,7 +22,6 @@ enum dev_prop_type {
DEV_PROP_U32,
DEV_PROP_U64,
DEV_PROP_STRING,
DEV_PROP_MAX,
};
enum dev_dma_attr {
@ -80,9 +79,14 @@ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
const char *name,
unsigned int index);
const char *fwnode_get_name(const struct fwnode_handle *fwnode);
const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_get_next_parent(
struct fwnode_handle *fwnode);
unsigned int fwnode_count_parents(const struct fwnode_handle *fwn);
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwn,
unsigned int depth);
struct fwnode_handle *fwnode_get_next_child_node(
const struct fwnode_handle *fwnode, struct fwnode_handle *child);
struct fwnode_handle *fwnode_get_next_available_child_node(
@ -234,13 +238,7 @@ struct property_entry {
bool is_array;
enum dev_prop_type type;
union {
union {
const u8 *u8_data;
const u16 *u16_data;
const u32 *u32_data;
const u64 *u64_data;
const char * const *str;
} pointer;
const void *pointer;
union {
u8 u8_data;
u16 u16_data;
@ -252,62 +250,63 @@ struct property_entry {
};
/*
* Note: the below four initializers for the anonymous union are carefully
* Note: the below initializers for the anonymous union are carefully
* crafted to avoid gcc-4.4.4's problems with initialization of anon unions
* and structs.
*/
#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _Type_, _val_) \
#define __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_) \
sizeof(((struct property_entry *)NULL)->value._elem_)
#define __PROPERTY_ENTRY_ARRAY_LEN(_name_, _elem_, _Type_, _val_, _len_)\
(struct property_entry) { \
.name = _name_, \
.length = ARRAY_SIZE(_val_) * sizeof(_type_), \
.length = (_len_) * __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_), \
.is_array = true, \
.type = DEV_PROP_##_Type_, \
{ .pointer = { ._type_##_data = _val_ } }, \
{ .pointer = _val_ }, \
}
#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, U8, _val_)
#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, U16, _val_)
#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, U32, _val_)
#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, U64, _val_)
#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_) \
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u16_data, U16, _val_, _len_)
#define PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, _len_) \
__PROPERTY_ENTRY_ARRAY_LEN(_name_, u32_data, U32, _val_, _len_)
#define PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, _len_) \
__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_STRING_ARRAY(_name_, _val_) \
(struct property_entry) { \
.name = _name_, \
.length = ARRAY_SIZE(_val_) * sizeof(const char *), \
.is_array = true, \
.type = DEV_PROP_STRING, \
{ .pointer = { .str = _val_ } }, \
#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \
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_ELEMENT(_name_, _elem_, _Type_, _val_) \
(struct property_entry) { \
.name = _name_, \
.length = __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_), \
.type = DEV_PROP_##_Type_, \
{ .value = { ._elem_ = _val_ } }, \
}
#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_) \
(struct property_entry) { \
.name = _name_, \
.length = sizeof(_type_), \
.type = DEV_PROP_##_Type_, \
{ .value = { ._type_##_data = _val_ } }, \
}
#define PROPERTY_ENTRY_U8(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_)
#define PROPERTY_ENTRY_U16(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_)
#define PROPERTY_ENTRY_U32(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_)
#define PROPERTY_ENTRY_U64(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_)
#define PROPERTY_ENTRY_STRING(_name_, _val_) \
(struct property_entry) { \
.name = _name_, \
.length = sizeof(const char *), \
.type = DEV_PROP_STRING, \
{ .value = { .str = _val_ } }, \
}
#define PROPERTY_ENTRY_U8(_name_, _val_) \
__PROPERTY_ENTRY_ELEMENT(_name_, u8_data, U8, _val_)
#define PROPERTY_ENTRY_U16(_name_, _val_) \
__PROPERTY_ENTRY_ELEMENT(_name_, u16_data, U16, _val_)
#define PROPERTY_ENTRY_U32(_name_, _val_) \
__PROPERTY_ENTRY_ELEMENT(_name_, u32_data, U32, _val_)
#define PROPERTY_ENTRY_U64(_name_, _val_) \
__PROPERTY_ENTRY_ELEMENT(_name_, u64_data, U64, _val_)
#define PROPERTY_ENTRY_STRING(_name_, _val_) \
__PROPERTY_ENTRY_ELEMENT(_name_, str, STRING, _val_)
#define PROPERTY_ENTRY_BOOL(_name_) \
(struct property_entry) { \
@ -418,7 +417,8 @@ struct software_node {
};
bool is_software_node(const struct fwnode_handle *fwnode);
const struct software_node *to_software_node(struct fwnode_handle *fwnode);
const struct software_node *
to_software_node(const struct fwnode_handle *fwnode);
struct fwnode_handle *software_node_fwnode(const struct software_node *node);
const struct software_node *

View File

@ -22,6 +22,8 @@
#include <linux/gfp.h>
#include <linux/mm.h>
#include <linux/property.h>
#include "../tools/testing/selftests/kselftest_module.h"
#define BUF_SIZE 256
@ -593,6 +595,35 @@ flags(void)
kfree(cmp_buffer);
}
static void __init fwnode_pointer(void)
{
const struct software_node softnodes[] = {
{ .name = "first", },
{ .name = "second", .parent = &softnodes[0], },
{ .name = "third", .parent = &softnodes[1], },
{ NULL /* Guardian */ }
};
const char * const full_name = "first/second/third";
const char * const full_name_second = "first/second";
const char * const second_name = "second";
const char * const third_name = "third";
int rval;
rval = software_node_register_nodes(softnodes);
if (rval) {
pr_warn("cannot register softnodes; rval %d\n", rval);
return;
}
test(full_name_second, "%pfw", software_node_fwnode(&softnodes[1]));
test(full_name, "%pfw", software_node_fwnode(&softnodes[2]));
test(full_name, "%pfwf", software_node_fwnode(&softnodes[2]));
test(second_name, "%pfwP", software_node_fwnode(&softnodes[1]));
test(third_name, "%pfwP", software_node_fwnode(&softnodes[2]));
software_node_unregister_nodes(softnodes);
}
static void __init
errptr(void)
{
@ -636,6 +667,7 @@ test_pointer(void)
netdev_features();
flags();
errptr();
fwnode_pointer();
}
static void __init selftest(void)

View File

@ -39,6 +39,7 @@
#include <net/addrconf.h>
#include <linux/siphash.h>
#include <linux/compiler.h>
#include <linux/property.h>
#ifdef CONFIG_BLOCK
#include <linux/blkdev.h>
#endif
@ -938,7 +939,7 @@ char *symbol_string(char *buf, char *end, void *ptr,
#ifdef CONFIG_KALLSYMS
if (*fmt == 'B')
sprint_backtrace(sym, value);
else if (*fmt != 'f' && *fmt != 's')
else if (*fmt != 's')
sprint_symbol(sym, value);
else
sprint_symbol_no_offset(sym, value);
@ -1892,32 +1893,25 @@ char *flags_string(char *buf, char *end, void *flags_ptr,
return format_flags(buf, end, flags, names);
}
static const char *device_node_name_for_depth(const struct device_node *np, int depth)
{
for ( ; np && depth; depth--)
np = np->parent;
return kbasename(np->full_name);
}
static noinline_for_stack
char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)
char *fwnode_full_name_string(struct fwnode_handle *fwnode, char *buf,
char *end)
{
int depth;
const struct device_node *parent = np->parent;
/* special case for root node */
if (!parent)
return string_nocheck(buf, end, "/", default_str_spec);
/* Loop starting from the root node to the current node. */
for (depth = fwnode_count_parents(fwnode); depth >= 0; depth--) {
struct fwnode_handle *__fwnode =
fwnode_get_nth_parent(fwnode, depth);
for (depth = 0; parent->parent; depth++)
parent = parent->parent;
for ( ; depth >= 0; depth--) {
buf = string_nocheck(buf, end, "/", default_str_spec);
buf = string(buf, end, device_node_name_for_depth(np, depth),
buf = string(buf, end, fwnode_get_name_prefix(__fwnode),
default_str_spec);
buf = string(buf, end, fwnode_get_name(__fwnode),
default_str_spec);
fwnode_handle_put(__fwnode);
}
return buf;
}
@ -1941,6 +1935,9 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
struct printf_spec str_spec = spec;
str_spec.field_width = -1;
if (fmt[0] != 'F')
return error_string(buf, end, "(%pO?)", spec);
if (!IS_ENABLED(CONFIG_OF))
return error_string(buf, end, "(%pOF?)", spec);
@ -1962,10 +1959,11 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
switch (*fmt) {
case 'f': /* full_name */
buf = device_node_gen_full_name(dn, buf, end);
buf = fwnode_full_name_string(of_fwnode_handle(dn), buf,
end);
break;
case 'n': /* name */
p = kbasename(of_node_full_name(dn));
p = fwnode_get_name(of_fwnode_handle(dn));
precision = str_spec.precision;
str_spec.precision = strchrnul(p, '@') - p;
buf = string(buf, end, p, str_spec);
@ -1975,7 +1973,7 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
buf = number(buf, end, (unsigned int)dn->phandle, num_spec);
break;
case 'P': /* path-spec */
p = kbasename(of_node_full_name(dn));
p = fwnode_get_name(of_fwnode_handle(dn));
if (!p[1])
p = "/";
buf = string(buf, end, p, str_spec);
@ -2013,15 +2011,34 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
return widen_string(buf, buf - buf_start, end, spec);
}
static char *kobject_string(char *buf, char *end, void *ptr,
struct printf_spec spec, const char *fmt)
static noinline_for_stack
char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode,
struct printf_spec spec, const char *fmt)
{
switch (fmt[1]) {
case 'F':
return device_node_string(buf, end, ptr, spec, fmt + 1);
struct printf_spec str_spec = spec;
char *buf_start = buf;
str_spec.field_width = -1;
if (*fmt != 'w')
return error_string(buf, end, "(%pf?)", spec);
if (check_pointer(&buf, end, fwnode, spec))
return buf;
fmt++;
switch (*fmt) {
case 'P': /* name */
buf = string(buf, end, fwnode_get_name(fwnode), str_spec);
break;
case 'f': /* full_name */
default:
buf = fwnode_full_name_string(fwnode, buf, end);
break;
}
return error_string(buf, end, "(%pO?)", spec);
return widen_string(buf, buf - buf_start, end, spec);
}
/*
@ -2036,9 +2053,9 @@ static char *kobject_string(char *buf, char *end, void *ptr,
*
* - 'S' For symbolic direct pointers (or function descriptors) with offset
* - 's' For symbolic direct pointers (or function descriptors) without offset
* - 'F' Same as 'S'
* - 'f' Same as 's'
* - '[FfSs]R' as above with __builtin_extract_return_addr() translation
* - '[Ss]R' as above with __builtin_extract_return_addr() translation
* - '[Ff]' %pf and %pF were obsoleted and later removed in favor of
* %ps and %pS. Be careful when re-using these specifiers.
* - 'B' For backtraced symbolic direct pointers with offset
* - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
* - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
@ -2128,6 +2145,10 @@ static char *kobject_string(char *buf, char *end, void *ptr,
* F device node flags
* c major compatible string
* C full compatible string
* - 'fw[fP]' For a firmware node (struct fwnode_handle) pointer
* Without an option prints the full name of the node
* f full name
* P node name, including a possible unit address
* - 'x' For printing the address. Equivalent to "%lx".
*
* ** When making changes please also update:
@ -2141,8 +2162,6 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
struct printf_spec spec)
{
switch (*fmt) {
case 'F':
case 'f':
case 'S':
case 's':
ptr = dereference_symbol_descriptor(ptr);
@ -2204,7 +2223,9 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
case 'G':
return flags_string(buf, end, ptr, spec, fmt);
case 'O':
return kobject_string(buf, end, ptr, spec, fmt);
return device_node_string(buf, end, ptr, spec, fmt + 1);
case 'f':
return fwnode_string(buf, end, ptr, spec, fmt + 1);
case 'x':
return pointer_string(buf, end, ptr, spec);
case 'e':
@ -2844,8 +2865,6 @@ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
/* Dereference of functions is still OK */
case 'S':
case 's':
case 'F':
case 'f':
case 'x':
case 'K':
case 'e':

View File

@ -6015,14 +6015,18 @@ sub process {
for (my $count = $linenr; $count <= $lc; $count++) {
my $specifier;
my $extension;
my $qualifier;
my $bad_specifier = "";
my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
$fmt =~ s/%%//g;
while ($fmt =~ /(\%[\*\d\.]*p(\w))/g) {
while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) {
$specifier = $1;
$extension = $2;
if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxt]/) {
$qualifier = $3;
if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxtf]/ ||
($extension eq "f" &&
defined $qualifier && $qualifier !~ /^w/)) {
$bad_specifier = $specifier;
last;
}
@ -6039,7 +6043,6 @@ sub process {
my $ext_type = "Invalid";
my $use = "";
if ($bad_specifier =~ /p[Ff]/) {
$ext_type = "Deprecated";
$use = " - use %pS instead";
$use =~ s/pS/ps/ if ($bad_specifier =~ /pf/);
}