提交 361b0d28 编写于 作者: L Linus Torvalds

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
  ...
...@@ -98,8 +98,6 @@ Symbols/Function Pointers ...@@ -98,8 +98,6 @@ Symbols/Function Pointers
%pS versatile_init+0x0/0x110 %pS versatile_init+0x0/0x110
%ps versatile_init %ps versatile_init
%pF versatile_init+0x0/0x110
%pf versatile_init
%pSR versatile_init+0x9/0x110 %pSR versatile_init+0x9/0x110
(with __builtin_extract_return_addr() translation) (with __builtin_extract_return_addr() translation)
%pB prev_fn_of_versatile_init+0x88/0x88 %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 ...@@ -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) format. They result in the symbol name with (S) or without (s)
offsets. If KALLSYMS are disabled then the symbol address is printed instead. 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 The ``B`` specifier results in the symbol name with offsets and should be
used when printing stack backtraces. The specifier takes into used when printing stack backtraces. The specifier takes into
consideration the effect of compiler optimisations which may occur consideration the effect of compiler optimisations which may occur
...@@ -440,6 +430,30 @@ Examples:: ...@@ -440,6 +430,30 @@ Examples::
Passed by reference. 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) Time and date (struct rtc_time)
------------------------------- -------------------------------
......
...@@ -1317,6 +1317,52 @@ acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, ...@@ -1317,6 +1317,52 @@ acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
args_count, args); 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 * static struct fwnode_handle *
acpi_fwnode_get_parent(struct fwnode_handle *fwnode) acpi_fwnode_get_parent(struct fwnode_handle *fwnode)
{ {
...@@ -1357,6 +1403,8 @@ acpi_fwnode_device_get_match_data(const 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_parent = acpi_node_get_parent, \
.get_next_child_node = acpi_get_next_subnode, \ .get_next_child_node = acpi_get_next_subnode, \
.get_named_child_node = acpi_fwnode_get_named_child_node, \ .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, \ .get_reference_args = acpi_fwnode_get_reference_args, \
.graph_get_next_endpoint = \ .graph_get_next_endpoint = \
acpi_graph_get_next_endpoint, \ acpi_graph_get_next_endpoint, \
......
...@@ -556,6 +556,42 @@ int device_add_properties(struct device *dev, ...@@ -556,6 +556,42 @@ int device_add_properties(struct device *dev,
} }
EXPORT_SYMBOL_GPL(device_add_properties); 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_get_next_parent - Iterate to the node's parent
* @fwnode: Firmware whose parent is retrieved * @fwnode: Firmware whose parent is retrieved
...@@ -578,17 +614,50 @@ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode) ...@@ -578,17 +614,50 @@ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode)
EXPORT_SYMBOL_GPL(fwnode_get_next_parent); EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
/** /**
* fwnode_get_parent - Return parent firwmare node * fwnode_count_parents - Return the number of parents a node has
* @fwnode: Firmware whose parent is retrieved * @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 * Returns the number of parents a node has.
* parent was available.
*/ */
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 * fwnode_get_next_child_node - Return the next child node handle for a node
......
...@@ -71,9 +71,9 @@ software_node_to_swnode(const struct software_node *node) ...@@ -71,9 +71,9 @@ software_node_to_swnode(const struct software_node *node)
return swnode; 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; return swnode ? swnode->node : NULL;
} }
...@@ -103,71 +103,15 @@ property_entry_get(const struct property_entry *prop, const char *name) ...@@ -103,71 +103,15 @@ property_entry_get(const struct property_entry *prop, const char *name)
return NULL; 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) static const void *property_get_pointer(const struct property_entry *prop)
{ {
switch (prop->type) { if (!prop->length)
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:
return NULL; return NULL;
}
if (prop->is_array)
return prop->pointer;
return &prop->value;
} }
static const void *property_entry_find(const struct property_entry *props, 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, ...@@ -187,66 +131,6 @@ static const void *property_entry_find(const struct property_entry *props,
return pointer; 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 static int
property_entry_count_elems_of_size(const struct property_entry *props, property_entry_count_elems_of_size(const struct property_entry *props,
const char *propname, size_t length) const char *propname, size_t length)
...@@ -265,49 +149,45 @@ static int property_entry_read_int_array(const struct property_entry *props, ...@@ -265,49 +149,45 @@ static int property_entry_read_int_array(const struct property_entry *props,
unsigned int elem_size, void *val, unsigned int elem_size, void *val,
size_t nval) size_t nval)
{ {
const void *pointer;
size_t length;
if (!val) if (!val)
return property_entry_count_elems_of_size(props, name, return property_entry_count_elems_of_size(props, name,
elem_size); 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, static int property_entry_read_string_array(const struct property_entry *props,
const char *propname, const char *propname,
const char **strings, size_t nval) const char **strings, size_t nval)
{ {
const struct property_entry *prop;
const void *pointer; const void *pointer;
size_t array_len, length; size_t length;
int array_len;
/* Find out the array length. */ /* Find out the array length. */
prop = property_entry_get(props, propname); array_len = property_entry_count_elems_of_size(props, propname,
if (!prop) sizeof(const char *));
return -EINVAL; if (array_len < 0)
return array_len;
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;
/* Return how many there are if strings is NULL. */ /* Return how many there are if strings is NULL. */
if (!strings) if (!strings)
return array_len; return array_len;
array_len = min(nval, array_len); array_len = min_t(size_t, nval, array_len);
length = array_len * sizeof(*strings); length = array_len * sizeof(*strings);
pointer = property_entry_find(props, propname, length); pointer = property_entry_find(props, propname, length);
...@@ -322,13 +202,15 @@ static int property_entry_read_string_array(const struct property_entry *props, ...@@ -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) static void property_entry_free_data(const struct property_entry *p)
{ {
const void *pointer = property_get_pointer(p); const void *pointer = property_get_pointer(p);
const char * const *src_str;
size_t i, nval; size_t i, nval;
if (p->is_array) { 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 *); nval = p->length / sizeof(const char *);
for (i = 0; i < nval; i++) for (i = 0; i < nval; i++)
kfree(p->pointer.str[i]); kfree(src_str[i]);
} }
kfree(pointer); kfree(pointer);
} else if (p->type == DEV_PROP_STRING) { } else if (p->type == DEV_PROP_STRING) {
...@@ -337,29 +219,29 @@ static void property_entry_free_data(const struct property_entry *p) ...@@ -337,29 +219,29 @@ static void property_entry_free_data(const struct property_entry *p)
kfree(p->name); kfree(p->name);
} }
static int property_copy_string_array(struct property_entry *dst, static const char * const *
const struct property_entry *src) property_copy_string_array(const struct property_entry *src)
{ {
const char **d; const char **d;
const char * const *src_str = src->pointer;
size_t nval = src->length / sizeof(*d); size_t nval = src->length / sizeof(*d);
int i; int i;
d = kcalloc(nval, sizeof(*d), GFP_KERNEL); d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
if (!d) if (!d)
return -ENOMEM; return NULL;
for (i = 0; i < nval; i++) { for (i = 0; i < nval; i++) {
d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL); d[i] = kstrdup(src_str[i], GFP_KERNEL);
if (!d[i] && src->pointer.str[i]) { if (!d[i] && src_str[i]) {
while (--i >= 0) while (--i >= 0)
kfree(d[i]); kfree(d[i]);
kfree(d); kfree(d);
return -ENOMEM; return NULL;
} }
} }
dst->pointer.str = d; return d;
return 0;
} }
static int property_entry_copy_data(struct property_entry *dst, static int property_entry_copy_data(struct property_entry *dst,
...@@ -367,36 +249,35 @@ 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 *pointer = property_get_pointer(src);
const void *new; const void *new;
int error;
if (src->is_array) { if (src->is_array) {
if (!src->length) if (!src->length)
return -ENODATA; return -ENODATA;
if (src->type == DEV_PROP_STRING) { if (src->type == DEV_PROP_STRING) {
error = property_copy_string_array(dst, src); new = property_copy_string_array(src);
if (error) if (!new)
return error; return -ENOMEM;
new = dst->pointer.str;
} else { } else {
new = kmemdup(pointer, src->length, GFP_KERNEL); new = kmemdup(pointer, src->length, GFP_KERNEL);
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
} }
dst->is_array = true;
dst->pointer = new;
} else if (src->type == DEV_PROP_STRING) { } else if (src->type == DEV_PROP_STRING) {
new = kstrdup(src->value.str, GFP_KERNEL); new = kstrdup(src->value.str, GFP_KERNEL);
if (!new && src->value.str) if (!new && src->value.str)
return -ENOMEM; return -ENOMEM;
dst->value.str = new;
} else { } else {
new = pointer; dst->value = src->value;
} }
dst->length = src->length; dst->length = src->length;
dst->is_array = src->is_array;
dst->type = src->type; dst->type = src->type;
property_set_pointer(dst, new);
dst->name = kstrdup(src->name, GFP_KERNEL); dst->name = kstrdup(src->name, GFP_KERNEL);
if (!dst->name) if (!dst->name)
goto out_free_data; goto out_free_data;
...@@ -515,12 +396,47 @@ static int software_node_read_string_array(const struct fwnode_handle *fwnode, ...@@ -515,12 +396,47 @@ static int software_node_read_string_array(const struct fwnode_handle *fwnode,
propname, val, nval); 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 * static struct fwnode_handle *
software_node_get_parent(const struct fwnode_handle *fwnode) software_node_get_parent(const struct fwnode_handle *fwnode)
{ {
struct swnode *swnode = to_swnode(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 * static struct fwnode_handle *
...@@ -612,6 +528,8 @@ static const struct fwnode_operations software_node_ops = { ...@@ -612,6 +528,8 @@ static const struct fwnode_operations software_node_ops = {
.property_present = software_node_property_present, .property_present = software_node_property_present,
.property_read_int_array = software_node_read_int_array, .property_read_int_array = software_node_read_int_array,
.property_read_string_array = software_node_read_string_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_parent = software_node_get_parent,
.get_next_child_node = software_node_get_next_child, .get_next_child_node = software_node_get_next_child,
.get_named_child_node = software_node_get_named_child_node, .get_named_child_node = software_node_get_named_child_node,
......
...@@ -53,7 +53,8 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, ...@@ -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++) { for (i = 0; i < dev_header->prop_count; i++) {
int remaining = dev_header->len - (ptr - (void *)dev_header); 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; char *key;
if (sizeof(key_len) > remaining) if (sizeof(key_len) > remaining)
...@@ -85,17 +86,14 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, ...@@ -85,17 +86,14 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
ucs2_as_utf8(key, ptr + sizeof(key_len), ucs2_as_utf8(key, ptr + sizeof(key_len),
key_len - sizeof(key_len)); key_len - sizeof(key_len));
entry[i].name = key; entry_data = ptr + key_len + sizeof(val_len);
entry[i].length = val_len - sizeof(val_len); entry_len = val_len - sizeof(val_len);
entry[i].is_array = !!entry[i].length; entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data,
entry[i].type = DEV_PROP_U8; entry_len);
entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len);
if (dump_properties) { 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, print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
16, 1, entry[i].pointer.u8_data, 16, 1, entry_data, entry_len, true);
entry[i].length, true);
} }
ptr += key_len + val_len; ptr += key_len + val_len;
......
...@@ -872,6 +872,20 @@ of_fwnode_property_read_string_array(const struct fwnode_handle *fwnode, ...@@ -872,6 +872,20 @@ of_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
of_property_count_strings(node, propname); 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 * static struct fwnode_handle *
of_fwnode_get_parent(const struct fwnode_handle *fwnode) of_fwnode_get_parent(const struct fwnode_handle *fwnode)
{ {
...@@ -993,6 +1007,8 @@ const struct fwnode_operations of_fwnode_ops = { ...@@ -993,6 +1007,8 @@ const struct fwnode_operations of_fwnode_ops = {
.property_present = of_fwnode_property_present, .property_present = of_fwnode_property_present,
.property_read_int_array = of_fwnode_property_read_int_array, .property_read_int_array = of_fwnode_property_read_int_array,
.property_read_string_array = of_fwnode_property_read_string_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_parent = of_fwnode_get_parent,
.get_next_child_node = of_fwnode_get_next_child_node, .get_next_child_node = of_fwnode_get_next_child_node,
.get_named_child_node = of_fwnode_get_named_child_node, .get_named_child_node = of_fwnode_get_named_child_node,
......
...@@ -49,13 +49,15 @@ struct fwnode_reference_args { ...@@ -49,13 +49,15 @@ struct fwnode_reference_args {
* struct fwnode_operations - Operations for fwnode interface * struct fwnode_operations - Operations for fwnode interface
* @get: Get a reference to an fwnode. * @get: Get a reference to an fwnode.
* @put: Put 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. * @device_get_match_data: Return the device driver match data.
* @property_present: Return true if a property is present. * @property_present: Return true if a property is present.
* @property_read_integer_array: Read an array of integer properties. Return * @property_read_int_array: Read an array of integer properties. Return zero on
* zero on success, a negative error code * success, a negative error code otherwise.
* otherwise.
* @property_read_string_array: Read an array of string properties. Return zero * @property_read_string_array: Read an array of string properties. Return zero
* on success, a negative error code otherwise. * 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_parent: Return the parent of an fwnode.
* @get_next_child_node: Return the next child node in an iteration. * @get_next_child_node: Return the next child node in an iteration.
* @get_named_child_node: Return a child node with a given name. * @get_named_child_node: Return a child node with a given name.
...@@ -82,6 +84,8 @@ struct fwnode_operations { ...@@ -82,6 +84,8 @@ struct fwnode_operations {
(*property_read_string_array)(const struct fwnode_handle *fwnode_handle, (*property_read_string_array)(const struct fwnode_handle *fwnode_handle,
const char *propname, const char **val, const char *propname, const char **val,
size_t nval); 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_parent)(const struct fwnode_handle *fwnode);
struct fwnode_handle * struct fwnode_handle *
(*get_next_child_node)(const struct fwnode_handle *fwnode, (*get_next_child_node)(const struct fwnode_handle *fwnode,
......
...@@ -22,7 +22,6 @@ enum dev_prop_type { ...@@ -22,7 +22,6 @@ enum dev_prop_type {
DEV_PROP_U32, DEV_PROP_U32,
DEV_PROP_U64, DEV_PROP_U64,
DEV_PROP_STRING, DEV_PROP_STRING,
DEV_PROP_MAX,
}; };
enum dev_dma_attr { enum dev_dma_attr {
...@@ -80,9 +79,14 @@ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode, ...@@ -80,9 +79,14 @@ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
const char *name, const char *name,
unsigned int index); 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_parent(const struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_get_next_parent( struct fwnode_handle *fwnode_get_next_parent(
struct fwnode_handle *fwnode); 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( struct fwnode_handle *fwnode_get_next_child_node(
const struct fwnode_handle *fwnode, struct fwnode_handle *child); const struct fwnode_handle *fwnode, struct fwnode_handle *child);
struct fwnode_handle *fwnode_get_next_available_child_node( struct fwnode_handle *fwnode_get_next_available_child_node(
...@@ -234,13 +238,7 @@ struct property_entry { ...@@ -234,13 +238,7 @@ struct property_entry {
bool is_array; bool is_array;
enum dev_prop_type type; enum dev_prop_type type;
union { union {
union { const void *pointer;
const u8 *u8_data;
const u16 *u16_data;
const u32 *u32_data;
const u64 *u64_data;
const char * const *str;
} pointer;
union { union {
u8 u8_data; u8 u8_data;
u16 u16_data; u16 u16_data;
...@@ -252,62 +250,63 @@ struct property_entry { ...@@ -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 * crafted to avoid gcc-4.4.4's problems with initialization of anon unions
* and structs. * 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) { \ (struct property_entry) { \
.name = _name_, \ .name = _name_, \
.length = ARRAY_SIZE(_val_) * sizeof(_type_), \ .length = (_len_) * __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_), \
.is_array = true, \ .is_array = true, \
.type = DEV_PROP_##_Type_, \ .type = DEV_PROP_##_Type_, \
{ .pointer = { ._type_##_data = _val_ } }, \ { .pointer = _val_ }, \
} }
#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \ #define PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, _len_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, U8, _val_) __PROPERTY_ENTRY_ARRAY_LEN(_name_, u8_data, U8, _val_, _len_)
#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \ #define PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, _len_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, U16, _val_) __PROPERTY_ENTRY_ARRAY_LEN(_name_, u16_data, U16, _val_, _len_)
#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \ #define PROPERTY_ENTRY_U32_ARRAY_LEN(_name_, _val_, _len_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, U32, _val_) __PROPERTY_ENTRY_ARRAY_LEN(_name_, u32_data, U32, _val_, _len_)
#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \ #define PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, _len_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, U64, _val_) __PROPERTY_ENTRY_ARRAY_LEN(_name_, u64_data, U64, _val_, _len_)
#define PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, _len_) \
#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \ __PROPERTY_ENTRY_ARRAY_LEN(_name_, str, STRING, _val_, _len_)
(struct property_entry) { \
.name = _name_, \ #define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
.length = ARRAY_SIZE(_val_) * sizeof(const char *), \ PROPERTY_ENTRY_U8_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
.is_array = true, \ #define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \
.type = DEV_PROP_STRING, \ PROPERTY_ENTRY_U16_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
{ .pointer = { .str = _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_) \
#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_) \ PROPERTY_ENTRY_U64_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
(struct property_entry) { \ #define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \
.name = _name_, \ PROPERTY_ENTRY_STRING_ARRAY_LEN(_name_, _val_, ARRAY_SIZE(_val_))
.length = sizeof(_type_), \
.type = DEV_PROP_##_Type_, \ #define __PROPERTY_ENTRY_ELEMENT(_name_, _elem_, _Type_, _val_) \
{ .value = { ._type_##_data = _val_ } }, \ (struct property_entry) { \
.name = _name_, \
.length = __PROPERTY_ENTRY_ELEMENT_SIZE(_elem_), \
.type = DEV_PROP_##_Type_, \
{ .value = { ._elem_ = _val_ } }, \
} }
#define PROPERTY_ENTRY_U8(_name_, _val_) \ #define PROPERTY_ENTRY_U8(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_) __PROPERTY_ENTRY_ELEMENT(_name_, u8_data, U8, _val_)
#define PROPERTY_ENTRY_U16(_name_, _val_) \ #define PROPERTY_ENTRY_U16(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_) __PROPERTY_ENTRY_ELEMENT(_name_, u16_data, U16, _val_)
#define PROPERTY_ENTRY_U32(_name_, _val_) \ #define PROPERTY_ENTRY_U32(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_) __PROPERTY_ENTRY_ELEMENT(_name_, u32_data, U32, _val_)
#define PROPERTY_ENTRY_U64(_name_, _val_) \ #define PROPERTY_ENTRY_U64(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_) __PROPERTY_ENTRY_ELEMENT(_name_, u64_data, U64, _val_)
#define PROPERTY_ENTRY_STRING(_name_, _val_) \
#define PROPERTY_ENTRY_STRING(_name_, _val_) \ __PROPERTY_ENTRY_ELEMENT(_name_, str, STRING, _val_)
(struct property_entry) { \
.name = _name_, \
.length = sizeof(const char *), \
.type = DEV_PROP_STRING, \
{ .value = { .str = _val_ } }, \
}
#define PROPERTY_ENTRY_BOOL(_name_) \ #define PROPERTY_ENTRY_BOOL(_name_) \
(struct property_entry) { \ (struct property_entry) { \
...@@ -418,7 +417,8 @@ struct software_node { ...@@ -418,7 +417,8 @@ struct software_node {
}; };
bool is_software_node(const struct fwnode_handle *fwnode); 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); struct fwnode_handle *software_node_fwnode(const struct software_node *node);
const struct software_node * const struct software_node *
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/property.h>
#include "../tools/testing/selftests/kselftest_module.h" #include "../tools/testing/selftests/kselftest_module.h"
#define BUF_SIZE 256 #define BUF_SIZE 256
...@@ -593,6 +595,35 @@ flags(void) ...@@ -593,6 +595,35 @@ flags(void)
kfree(cmp_buffer); 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 static void __init
errptr(void) errptr(void)
{ {
...@@ -636,6 +667,7 @@ test_pointer(void) ...@@ -636,6 +667,7 @@ test_pointer(void)
netdev_features(); netdev_features();
flags(); flags();
errptr(); errptr();
fwnode_pointer();
} }
static void __init selftest(void) static void __init selftest(void)
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <net/addrconf.h> #include <net/addrconf.h>
#include <linux/siphash.h> #include <linux/siphash.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/property.h>
#ifdef CONFIG_BLOCK #ifdef CONFIG_BLOCK
#include <linux/blkdev.h> #include <linux/blkdev.h>
#endif #endif
...@@ -938,7 +939,7 @@ char *symbol_string(char *buf, char *end, void *ptr, ...@@ -938,7 +939,7 @@ char *symbol_string(char *buf, char *end, void *ptr,
#ifdef CONFIG_KALLSYMS #ifdef CONFIG_KALLSYMS
if (*fmt == 'B') if (*fmt == 'B')
sprint_backtrace(sym, value); sprint_backtrace(sym, value);
else if (*fmt != 'f' && *fmt != 's') else if (*fmt != 's')
sprint_symbol(sym, value); sprint_symbol(sym, value);
else else
sprint_symbol_no_offset(sym, value); sprint_symbol_no_offset(sym, value);
...@@ -1892,32 +1893,25 @@ char *flags_string(char *buf, char *end, void *flags_ptr, ...@@ -1892,32 +1893,25 @@ char *flags_string(char *buf, char *end, void *flags_ptr,
return format_flags(buf, end, flags, names); 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 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; int depth;
const struct device_node *parent = np->parent;
/* special case for root node */
if (!parent)
return string_nocheck(buf, end, "/", default_str_spec);
for (depth = 0; parent->parent; depth++) /* Loop starting from the root node to the current node. */
parent = parent->parent; for (depth = fwnode_count_parents(fwnode); depth >= 0; depth--) {
struct fwnode_handle *__fwnode =
fwnode_get_nth_parent(fwnode, depth);
for ( ; depth >= 0; depth--) { buf = string(buf, end, fwnode_get_name_prefix(__fwnode),
buf = string_nocheck(buf, end, "/", default_str_spec);
buf = string(buf, end, device_node_name_for_depth(np, depth),
default_str_spec); default_str_spec);
buf = string(buf, end, fwnode_get_name(__fwnode),
default_str_spec);
fwnode_handle_put(__fwnode);
} }
return buf; return buf;
} }
...@@ -1941,6 +1935,9 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, ...@@ -1941,6 +1935,9 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
struct printf_spec str_spec = spec; struct printf_spec str_spec = spec;
str_spec.field_width = -1; str_spec.field_width = -1;
if (fmt[0] != 'F')
return error_string(buf, end, "(%pO?)", spec);
if (!IS_ENABLED(CONFIG_OF)) if (!IS_ENABLED(CONFIG_OF))
return error_string(buf, end, "(%pOF?)", spec); return error_string(buf, end, "(%pOF?)", spec);
...@@ -1962,10 +1959,11 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, ...@@ -1962,10 +1959,11 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
switch (*fmt) { switch (*fmt) {
case 'f': /* full_name */ 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; break;
case 'n': /* name */ case 'n': /* name */
p = kbasename(of_node_full_name(dn)); p = fwnode_get_name(of_fwnode_handle(dn));
precision = str_spec.precision; precision = str_spec.precision;
str_spec.precision = strchrnul(p, '@') - p; str_spec.precision = strchrnul(p, '@') - p;
buf = string(buf, end, p, str_spec); buf = string(buf, end, p, str_spec);
...@@ -1975,7 +1973,7 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, ...@@ -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); buf = number(buf, end, (unsigned int)dn->phandle, num_spec);
break; break;
case 'P': /* path-spec */ case 'P': /* path-spec */
p = kbasename(of_node_full_name(dn)); p = fwnode_get_name(of_fwnode_handle(dn));
if (!p[1]) if (!p[1])
p = "/"; p = "/";
buf = string(buf, end, p, str_spec); buf = string(buf, end, p, str_spec);
...@@ -2013,15 +2011,34 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, ...@@ -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); return widen_string(buf, buf - buf_start, end, spec);
} }
static char *kobject_string(char *buf, char *end, void *ptr, static noinline_for_stack
struct printf_spec spec, const char *fmt) char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode,
struct printf_spec spec, const char *fmt)
{ {
switch (fmt[1]) { struct printf_spec str_spec = spec;
case 'F': char *buf_start = buf;
return device_node_string(buf, end, ptr, spec, fmt + 1);
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, ...@@ -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) with offset
* - 's' For symbolic direct pointers (or function descriptors) without offset * - 's' For symbolic direct pointers (or function descriptors) without offset
* - 'F' Same as 'S' * - '[Ss]R' as above with __builtin_extract_return_addr() translation
* - 'f' Same as 's' * - '[Ff]' %pf and %pF were obsoleted and later removed in favor of
* - '[FfSs]R' as above with __builtin_extract_return_addr() translation * %ps and %pS. Be careful when re-using these specifiers.
* - 'B' For backtraced symbolic direct pointers with offset * - 'B' For backtraced symbolic direct pointers with offset
* - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
* - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] * - '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, ...@@ -2128,6 +2145,10 @@ static char *kobject_string(char *buf, char *end, void *ptr,
* F device node flags * F device node flags
* c major compatible string * c major compatible string
* C full 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". * - 'x' For printing the address. Equivalent to "%lx".
* *
* ** When making changes please also update: * ** When making changes please also update:
...@@ -2141,8 +2162,6 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, ...@@ -2141,8 +2162,6 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
struct printf_spec spec) struct printf_spec spec)
{ {
switch (*fmt) { switch (*fmt) {
case 'F':
case 'f':
case 'S': case 'S':
case 's': case 's':
ptr = dereference_symbol_descriptor(ptr); ptr = dereference_symbol_descriptor(ptr);
...@@ -2204,7 +2223,9 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, ...@@ -2204,7 +2223,9 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
case 'G': case 'G':
return flags_string(buf, end, ptr, spec, fmt); return flags_string(buf, end, ptr, spec, fmt);
case 'O': 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': case 'x':
return pointer_string(buf, end, ptr, spec); return pointer_string(buf, end, ptr, spec);
case 'e': case 'e':
...@@ -2844,8 +2865,6 @@ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args) ...@@ -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 */ /* Dereference of functions is still OK */
case 'S': case 'S':
case 's': case 's':
case 'F':
case 'f':
case 'x': case 'x':
case 'K': case 'K':
case 'e': case 'e':
......
...@@ -6015,14 +6015,18 @@ sub process { ...@@ -6015,14 +6015,18 @@ sub process {
for (my $count = $linenr; $count <= $lc; $count++) { for (my $count = $linenr; $count <= $lc; $count++) {
my $specifier; my $specifier;
my $extension; my $extension;
my $qualifier;
my $bad_specifier = ""; my $bad_specifier = "";
my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
$fmt =~ s/%%//g; $fmt =~ s/%%//g;
while ($fmt =~ /(\%[\*\d\.]*p(\w))/g) { while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) {
$specifier = $1; $specifier = $1;
$extension = $2; $extension = $2;
if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxt]/) { $qualifier = $3;
if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxtf]/ ||
($extension eq "f" &&
defined $qualifier && $qualifier !~ /^w/)) {
$bad_specifier = $specifier; $bad_specifier = $specifier;
last; last;
} }
...@@ -6039,7 +6043,6 @@ sub process { ...@@ -6039,7 +6043,6 @@ sub process {
my $ext_type = "Invalid"; my $ext_type = "Invalid";
my $use = ""; my $use = "";
if ($bad_specifier =~ /p[Ff]/) { if ($bad_specifier =~ /p[Ff]/) {
$ext_type = "Deprecated";
$use = " - use %pS instead"; $use = " - use %pS instead";
$use =~ s/pS/ps/ if ($bad_specifier =~ /pf/); $use =~ s/pS/ps/ if ($bad_specifier =~ /pf/);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册