Re: [PATCH v5 09/12] Driver core: Unified interface for firmware node properties

Grant Likely
2014-10-18T14:55:24Z

On Fri, 17 Oct 2014 14:14:53 +0200
, "Rafael J. Wysocki" <rjw@rjwysocki.net>
wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> Add new generic routines are provided for retrieving properties from
> device description objects in the platform firmware in case there are
> no struct device objects for them (either those objects have not been
> created yet or they do not exist at all).
>
> The following functions are provided:
>
> fwnode_property_present()
> fwnode_property_read_u8()
> fwnode_property_read_u16()
> fwnode_property_read_u32()
> fwnode_property_read_u64()
> fwnode_property_read_string()
> fwnode_property_read_u8_array()
> fwnode_property_read_u16_array()
> fwnode_property_read_u32_array()
> fwnode_property_read_u64_array()
> fwnode_property_read_string_array()
>
> in analogy with the corresponding functions for struct device added
> previously. For all of them, the first argument is a pointer to struct
> fwnode_handle (new type) that allows a device description object
> (depending on what platform firmware interface is in use) to be
> obtained.
>
> Add a new macro device_for_each_child_node() for iterating over the
> children of the device description object associated with a given
> device and a new function device_get_child_node_count() returning the
> number of a given device's child nodes.
>
> The interface covers both ACPI and Device Trees.

This is all *so much* better. I'm a lot happier.

I was about to make the comment that the implementation for
device_property_read_*() should merely be wrappers around
fwnode_property_read_*(), but when when I actually looked at it, I saw
this:

In patch 2:
int device_property_read_u8(struct device *dev, const char *propname, u8 *val)
{
if (IS_ENABLED(CONFIG_OF) && dev->of_node)
return of_property_read_u8(dev->of_node, propname, val);

return acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
DEV_PROP_U8, val);
}

And in this patch:
int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
u8 *val)
{
if (is_of_node(fwnode))
return of_property_read_u8(of_node(fwnode), propname, val);
else if (is_acpi_node(fwnode))
return acpi_dev_prop_read(acpi_node(fwnode), propname,
DEV_PROP_U8, val);

return -ENXIO;
}

Making the device_property functions wrappers around fwnode_property_*
wouldn't actually be great since it would need to decode the fwnode
pointer twice.

I do still think the functions above should be macro generated, just in
terms of keeping the line count down, and I would suggest merging patches #2
and #9.

Something like:

#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type(dev->of_node, propname, val); \
return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, \
__devprop_type, val); \
} \
int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val); \
return -ENXIO; \
}

define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);

That significantly reduces the code size for these things.

Also, can the non-array versions be implemented as a wrapper around the
array versions? That also will reduce the sheer number of lines of code
a lot.

Maybe this:

#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type##_array(struct device *dev, \
const char *propname, __type *val, \
size_t nval) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type##_array(dev->of_node, \
propname, val, nval); \
return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname, \
__devprop_type, val, nval); \
} \
static inline int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
return device_property_read_##__type##_array(dev, propname, val, 1) \
} \
int fwnode_property_read_##__type##_array(struct fwnode_handle *fwnode, \
const char *propname, __type *val, \
size_t nval) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val, nval); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val, nval); \
return -ENXIO; \
} \
static inline int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
return fwnode_property_read_##__type##_array(fwnode, propname, val, 1) \
}
define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);

g.

>
> Suggested-by: Grant Likely <grant.likely@linaro.org>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
> drivers/acpi/scan.c | 21 ++
> drivers/base/property.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++
> include/acpi/acpi_bus.h | 12 +
> include/linux/acpi.h | 21 ++
> include/linux/of.h | 22 ++
> include/linux/property.h | 48 ++++++
> 6 files changed, 497 insertions(+)
>
> Index: linux-pm/include/linux/property.h
> ===================================================================
> --- linux-pm.orig/include/linux/property.h
> +++ linux-pm/include/linux/property.h
> @@ -44,4 +44,52 @@ int device_property_read_u64_array(struc
> int device_property_read_string_array(struct device *dev, const char *propname,
> char **val, size_t nval);
>
> +enum fwnode_type {
> + FWNODE_INVALID = 0,
> + FWNODE_OF,
> + FWNODE_ACPI,
> +};
> +
> +struct fwnode_handle {
> + enum fwnode_type type;
> +};
> +
> +bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
> +int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
> + u8 *val);
> +int fwnode_property_read_u16(struct fwnode_handle *fwnode, const char *propname,
> + u16 *val);
> +int fwnode_property_read_u32(struct fwnode_handle *fwnode, const char *propname,
> + u32 *val);
> +int fwnode_property_read_u64(struct fwnode_handle *fwnode, const char *propname,
> + u64 *val);
> +int fwnode_property_read_string(struct fwnode_handle *fwnode,
> + const char *propname, const char **val);
> +int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
> + const char *propname, u8 *val,
> + size_t nval);
> +int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
> + const char *propname, u16 *val,
> + size_t nval);
> +int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
> + const char *propname, u32 *val,
> + size_t nval);
> +int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
> + const char *propname, u64 *val,
> + size_t nval);
> +int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
> + const char *propname, char **val,
> + size_t nval);
> +
> +struct fwnode_handle *device_get_next_child_node(struct device *dev,
> + struct fwnode_handle *child);
> +
> +#define device_for_each_child_node(dev, child) \
> + for (child = device_get_next_child_node(dev, NULL); child; \
> + child = device_get_next_child_node(dev, child))
> +
> +void fwnode_handle_put(struct fwnode_handle *fwnode);
> +
> +unsigned int device_get_child_node_count(struct device *dev);
> +
> #endif /* _LINUX_PROPERTY_H_ */
> Index: linux-pm/include/acpi/acpi_bus.h
> ===================================================================
> --- linux-pm.orig/include/acpi/acpi_bus.h
> +++ linux-pm/include/acpi/acpi_bus.h
> @@ -27,6 +27,7 @@
> #define __ACPI_BUS_H__
>
> #include <linux/device.h>
> +#include <linux/property.h>
>
> /* TBD: Make dynamic */
> #define ACPI_MAX_HANDLES 10
> @@ -348,6 +349,7 @@ struct acpi_device_data {
> struct acpi_device {
> int device_type;
> acpi_handle handle; /* no handle for fixed hardware */
> + struct fwnode_handle fwnode;
> struct acpi_device *parent;
> struct list_head children;
> struct list_head node;
> @@ -372,6 +374,16 @@ struct acpi_device {
> void (*remove)(struct acpi_device *);
> };
>
> +static inline bool is_acpi_node(struct fwnode_handle *fwnode)
> +{
> + return fwnode && fwnode->type == FWNODE_ACPI;
> +}
> +
> +static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
> +{
> + return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
> +}
> +
> static inline void *acpi_driver_data(struct acpi_device *d)
> {
> return d->driver_data;
> Index: linux-pm/include/linux/acpi.h
> ===================================================================
> --- linux-pm.orig/include/linux/acpi.h
> +++ linux-pm/include/linux/acpi.h
> @@ -439,6 +439,18 @@ int acpi_device_modalias(struct device *
> #define ACPI_COMPANION_SET(dev, adev) do { } while (0)
> #define ACPI_HANDLE(dev) (NULL)
>
> +struct fwnode_handle;
> +
> +static inline bool is_acpi_node(struct fwnode_handle *fwnode)
> +{
> + return false;
> +}
> +
> +static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
> +{
> + return NULL;
> +}
> +
> static inline const char *acpi_dev_name(struct acpi_device *adev)
> {
> return NULL;
> @@ -681,6 +693,9 @@ int acpi_dev_prop_read(struct acpi_devic
> int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
> enum dev_prop_type proptype, void *val,
> size_t nval);
> +
> +struct acpi_device *acpi_get_next_child(struct device *dev,
> + struct acpi_device *child);
> #else
> static inline int acpi_dev_get_property(struct acpi_device *adev,
> const char *name, acpi_object_type type,
> @@ -724,6 +739,12 @@ static inline int acpi_dev_prop_read_arr
> return -ENXIO;
> }
>
> +static inline struct acpi_device *acpi_get_next_child(struct device *dev,
> + struct acpi_device *child)
> +{
> + return NULL;
> +}
> +
> #endif
>
> #endif /*_LINUX_ACPI_H*/
> Index: linux-pm/include/linux/of.h
> ===================================================================
> --- linux-pm.orig/include/linux/of.h
> +++ linux-pm/include/linux/of.h
> @@ -50,6 +50,7 @@ struct device_node {
> const char *type;
> phandle phandle;
> const char *full_name;
> + struct fwnode_handle fwnode;
>
> struct property *properties;
> struct property *deadprops; /* removed properties */
> @@ -80,6 +81,7 @@ extern struct kobj_type of_node_ktype;
> static inline void of_node_init(struct device_node *node)
> {
> kobject_init(&node->kobj, &of_node_ktype);
> + node->fwnode.type = FWNODE_OF;
> }
>
> /* true when node is initialized */
> @@ -115,6 +117,16 @@ extern struct device_node *of_aliases;
> extern struct device_node *of_stdout;
> extern raw_spinlock_t devtree_lock;
>
> +static inline bool is_of_node(struct fwnode_handle *fwnode)
> +{
> + return fwnode && fwnode->type == FWNODE_OF;
> +}
> +
> +static inline struct device_node *of_node(struct fwnode_handle *fwnode)
> +{
> + return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL;
> +}
> +
> static inline bool of_have_populated_dt(void)
> {
> return of_allnodes != NULL;
> @@ -365,6 +377,16 @@ bool of_console_check(struct device_node
>
> #else /* CONFIG_OF */
>
> +static inline bool is_of_node(struct fwnode_handle *fwnode)
> +{
> + return false;
> +}
> +
> +static inline struct device_node *of_node(struct fwnode_handle *fwnode)
> +{
> + return NULL;
> +}
> +
> static inline const char* of_node_full_name(const struct device_node *np)
> {
> return "<no-node>";
> Index: linux-pm/drivers/base/property.c
> ===================================================================
> --- linux-pm.orig/drivers/base/property.c
> +++ linux-pm/drivers/base/property.c
> @@ -156,6 +156,166 @@ int device_property_read_string(struct d
> }
> EXPORT_SYMBOL_GPL(device_property_read_string);
>
> +/**
> + * fwnode_property_present - check if a property of a firmware node is present
> + * @fwnode: Firmware node whose property to check
> + * @propname: Name of the property
> + */
> +bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
> +{
> + if (is_of_node(fwnode))
> + return of_property_read_bool(of_node(fwnode), propname);
> + else if (is_acpi_node(fwnode))
> + return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
> +
> + return false;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_present);
> +
> +/**
> + * fwnode_property_read_u8 - return a u8 property of a firmware node
> + * @fwnode: Firmware node to get the property of
> + * @propname: Name of the property
> + * @val: The value is stored here
> + *
> + * Read property @propname from the given firmware node and store the value into
> + * @val if found. The value is checked to be of type u8.
> + *
> + * Return: %0 if the property was found (success),
> + * %-EINVAL if given arguments are not valid,
> + * %-ENODATA if the property does not have a value,
> + * %-EPROTO or %-EILSEQ if the property type is not u8,
> + * %-EOVERFLOW if the property value is out of bounds of u8,
> + * %-ENXIO if no suitable firmware interface is present.
> + */
> +int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
> + u8 *val)
> +{
> + if (is_of_node(fwnode))
> + return of_property_read_u8(of_node(fwnode), propname, val);
> + else if (is_acpi_node(fwnode))
> + return acpi_dev_prop_read(acpi_node(fwnode), propname,
> + DEV_PROP_U8, val);
> +
> + return -ENXIO;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_read_u8);
> +
> +/**
> + * fwnode_property_read_u16 - return a u16 property of a firmware node
> + * @fwnode: Firmware node to get the property of
> + * @propname: Name of the property
> + * @val: The value is stored here
> + *
> + * Read property @propname from the given firmware node and store the value into
> + * @val if found. The value is checked to be of type u16.
> + *
> + * Return: %0 if the property was found (success),
> + * %-EINVAL if given arguments are not valid,
> + * %-ENODATA if the property does not have a value,
> + * %-EPROTO or %-EILSEQ if the property type is not u16,
> + * %-EOVERFLOW if the property value is out of bounds of u16,
> + * %-ENXIO if no suitable firmware interface is present.
> + */
> +int fwnode_property_read_u16(struct fwnode_handle *fwnode, const char *propname,
> + u16 *val)
> +{
> + if (is_of_node(fwnode))
> + return of_property_read_u16(of_node(fwnode), propname, val);
> + else if (is_acpi_node(fwnode))
> + return acpi_dev_prop_read(acpi_node(fwnode), propname,
> + DEV_PROP_U16, val);
> +
> + return -ENXIO;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_read_u16);
> +
> +/**
> + * fwnode_property_read_u32 - return a u32 property of a firmware node
> + * @fwnode: Firmware node to get the property of
> + * @propname: Name of the property
> + * @val: The value is stored here
> + *
> + * Read property @propname from the given firmware node and store the value into
> + * @val if found. The value is checked to be of type u32.
> + *
> + * Return: %0 if the property was found (success),
> + * %-EINVAL if given arguments are not valid,
> + * %-ENODATA if the property does not have a value,
> + * %-EPROTO or %-EILSEQ if the property type is not u32,
> + * %-EOVERFLOW if the property value is out of bounds of u32,
> + * %-ENXIO if no suitable firmware interface is present.
> + */
> +int fwnode_property_read_u32(struct fwnode_handle *fwnode, const char *propname,
> + u32 *val)
> +{
> + if (is_of_node(fwnode))
> + return of_property_read_u32(of_node(fwnode), propname, val);
> + else if (is_acpi_node(fwnode))
> + return acpi_dev_prop_read(acpi_node(fwnode), propname,
> + DEV_PROP_U32, val);
> +
> + return -ENXIO;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_read_u32);
> +
> +/**
> + * fwnode_property_read_u64 - return a u64 property of a firmware node
> + * @fwnode: Firmware node to get the property of
> + * @propname: Name of the property
> + * @val: The value is stored here
> + *
> + * Read property @propname from the given firmware node and store the value into
> + * @val if found. The value is checked to be of type u64.
> + *
> + * Return: %0 if the property was found (success),
> + * %-EINVAL if given arguments are not valid,
> + * %-ENODATA if the property does not have a value,
> + * %-EPROTO or %-EILSEQ if the property type is not u64,
> + * %-EOVERFLOW if the property value is out of bounds of u64,
> + * %-ENXIO if no suitable firmware interface is present.
> + */
> +int fwnode_property_read_u64(struct fwnode_handle *fwnode, const char *propname,
> + u64 *val)
> +{
> + if (is_of_node(fwnode))
> + return of_property_read_u64(of_node(fwnode), propname, val);
> + else if (is_acpi_node(fwnode))
> + return acpi_dev_prop_read(acpi_node(fwnode), propname,
> + DEV_PROP_U64, val);
> +
> + return -ENXIO;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_read_u64);
> +
> +/**
> + * fwnode_property_read_string - return a string property of a firmware node
> + * @fwnode: Firmware node to get the property of
> + * @propname: Name of the property
> + * @val: The value is stored here
> + *
> + * Read property @propname from the given firmware node and store the value into
> + * @val if found. The value is checked to be a string.
> + *
> + * Return: %0 if the property was found (success),
> + * %-EINVAL if given arguments are not valid,
> + * %-ENODATA if the property does not have a value,
> + * %-EPROTO or %-EILSEQ if the property is not a string,
> + * %-ENXIO if no suitable firmware interface is present.
> + */
> +int fwnode_property_read_string(struct fwnode_handle *fwnode,
> + const char *propname, const char **val)
> +{
> + if (is_of_node(fwnode))
> + return of_property_read_string(of_node(fwnode), propname, val);
> + else if (is_acpi_node(fwnode))
> + return acpi_dev_prop_read(acpi_node(fwnode), propname,
> + DEV_PROP_STRING, val);
> +
> + return -ENXIO;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_read_string);
> +
> #define of_dev_prop_read_array(node, propname, type, val, nval) \
> (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
> : of_property_count_elems_of_size((node), (propname), sizeof(type))
> @@ -299,3 +459,216 @@ int device_property_read_string_array(st
> DEV_PROP_STRING, val, nval);
> }
> EXPORT_SYMBOL_GPL(device_property_read_string_array);
> +
> +/**
> + * fwnode_property_read_u8_array - return a u8 array property of firmware node
> + * @fwnode: Firmware node to get the property of
> + * @propname: Name of the property
> + * @val: The values are stored here
> + * @nval: Size of the @val array
> + *
> + * Read an array of u8 properties with @propname from @fwnode and stores them to
> + * @val if found.
> + *
> + * Return: %0 if the property was found (success),
> + * %-EINVAL if given arguments are not valid,
> + * %-ENODATA if the property does not have a value,
> + * %-EPROTO if the property is not an array of numbers,
> + * %-EOVERFLOW if the size of the property is not as expected,
> + * %-ENXIO if no suitable firmware interface is present.
> + */
> +int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
> + const char *propname, u8 *val, size_t nval)
> +{
> + if (is_of_node(fwnode))
> + return of_dev_prop_read_array(of_node(fwnode), propname,
> + u8, val, nval);
> + else if (is_acpi_node(fwnode))
> + return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
> + DEV_PROP_U8, val, nval);
> +
> + return -ENXIO;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
> +
> +/**
> + * fwnode_property_read_u16_array - return a u16 array property of firmware node
> + * @fwnode: Firmware node to get the property of
> + * @propname: Name of the property
> + * @val: The values are stored here
> + * @nval: Size of the @val array
> + *
> + * Read an array of u16 properties with @propname from @fwnode and store them to
> + * @val if found.
> + *
> + * Return: %0 if the property was found (success),
> + * %-EINVAL if given arguments are not valid,
> + * %-ENODATA if the property does not have a value,
> + * %-EPROTO if the property is not an array of numbers,
> + * %-EOVERFLOW if the size of the property is not as expected,
> + * %-ENXIO if no suitable firmware interface is present.
> + */
> +int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
> + const char *propname, u16 *val, size_t nval)
> +{
> + if (is_of_node(fwnode))
> + return of_dev_prop_read_array(of_node(fwnode), propname,
> + u16, val, nval);
> + else if (is_acpi_node(fwnode))
> + return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
> + DEV_PROP_U16, val, nval);
> +
> + return -ENXIO;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
> +
> +/**
> + * fwnode_property_read_u32_array - return a u32 array property of firmware node
> + * @fwnode: Firmware node to get the property of
> + * @propname: Name of the property
> + * @val: The values are stored here
> + * @nval: Size of the @val array
> + *
> + * Read an array of u32 properties with @propname from @fwnode store them to
> + * @val if found.
> + *
> + * Return: %0 if the property was found (success),
> + * %-EINVAL if given arguments are not valid,
> + * %-ENODATA if the property does not have a value,
> + * %-EPROTO if the property is not an array of numbers,
> + * %-EOVERFLOW if the size of the property is not as expected,
> + * %-ENXIO if no suitable firmware interface is present.
> + */
> +int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
> + const char *propname, u32 *val, size_t nval)
> +{
> + if (is_of_node(fwnode))
> + return of_dev_prop_read_array(of_node(fwnode), propname,
> + u32, val, nval);
> + else if (is_acpi_node(fwnode))
> + return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
> + DEV_PROP_U32, val, nval);
> +
> + return -ENXIO;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
> +
> +/**
> + * fwnode_property_read_u64_array - return a u64 array property firmware node
> + * @fwnode: Firmware node to get the property of
> + * @propname: Name of the property
> + * @val: The values are stored here
> + * @nval: Size of the @val array
> + *
> + * Read an array of u64 properties with @propname from @fwnode and store them to
> + * @val if found.
> + *
> + * Return: %0 if the property was found (success),
> + * %-EINVAL if given arguments are not valid,
> + * %-ENODATA if the property does not have a value,
> + * %-EPROTO if the property is not an array of numbers,
> + * %-EOVERFLOW if the size of the property is not as expected,
> + * %-ENXIO if no suitable firmware interface is present.
> + */
> +int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
> + const char *propname, u64 *val, size_t nval)
> +{
> + if (is_of_node(fwnode))
> + return of_dev_prop_read_array(of_node(fwnode), propname,
> + u64, val, nval);
> + else if (is_acpi_node(fwnode))
> + return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
> + DEV_PROP_U64, val, nval);
> +
> + return -ENXIO;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
> +
> +/**
> + * fwnode_property_read_string_array - return string array property of a node
> + * @fwnode: Firmware node to get the property of
> + * @propname: Name of the property
> + * @val: The values are stored here
> + * @nval: Size of the @val array
> + *
> + * Read an string list property @propname from the given firmware node and store
> + * them to @val if found.
> + *
> + * Return: %0 if the property was found (success),
> + * %-EINVAL if given arguments are not valid,
> + * %-ENODATA if the property does not have a value,
> + * %-EPROTO if the property is not an array of strings,
> + * %-EOVERFLOW if the size of the property is not as expected,
> + * %-ENXIO if no suitable firmware interface is present.
> + */
> +int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
> + const char *propname, char **val,
> + size_t nval)
> +{
> + if (is_of_node(fwnode))
> + return of_property_read_string_array(of_node(fwnode), propname,
> + val, nval);
> + else if (is_acpi_node(fwnode))
> + return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
> + DEV_PROP_STRING, val, nval);
> +
> + return -ENXIO;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
> +
> +
> +/**
> + * device_get_next_child_node - Return the next child node handle for a device
> + * @dev: Device to find the next child node for.
> + * @child: Handle to one of the device's child nodes or a null handle.
> + */
> +struct fwnode_handle *device_get_next_child_node(struct device *dev,
> + struct fwnode_handle *child)
> +{
> + if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
> + struct device_node *node;
> +
> + node = of_get_next_available_child(dev->of_node, of_node(child));
> + if (node)
> + return &node->fwnode;
> + } else if (ACPI_COMPANION(dev)) {
> + struct acpi_device *node;
> +
> + node = acpi_get_next_child(dev, acpi_node(child));
> + if (node)
> + return &node->fwnode;
> + }
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(device_get_next_child_node);
> +
> +/**
> + * fwnode_handle_put - Drop reference to a device node
> + * @fwnode: Pointer to the device node to drop the reference to.
> + *
> + * This has to be used when terminating device_for_each_child_node() iteration
> + * with break or return to prevent stale device node references from being left
> + * behind.
> + */
> +void fwnode_handle_put(struct fwnode_handle *fwnode)
> +{
> + if (is_of_node(fwnode))
> + of_node_put(of_node(fwnode));
> +}
> +EXPORT_SYMBOL_GPL(fwnode_handle_put);
> +
> +/**
> + * device_get_child_node_count - return the number of child nodes for device
> + * @dev: Device to cound the child nodes for
> + */
> +unsigned int device_get_child_node_count(struct device *dev)
> +{
> + struct fwnode_handle *child;
> + unsigned int count = 0;
> +
> + device_for_each_child_node(dev, child)
> + count++;
> +
> + return count;
> +}
> +EXPORT_SYMBOL_GPL(device_get_child_node_count);
> Index: linux-pm/drivers/acpi/scan.c
> ===================================================================
> --- linux-pm.orig/drivers/acpi/scan.c
> +++ linux-pm/drivers/acpi/scan.c
> @@ -1342,6 +1342,26 @@ int acpi_device_add(struct acpi_device *
> return result;
> }
>
> +struct acpi_device *acpi_get_next_child(struct device *dev,
> + struct acpi_device *child)
> +{
> + struct acpi_device *adev = ACPI_COMPANION(dev);
> + struct list_head *head, *next;
> +
> + if (!adev)
> + return NULL;
> +
> + head = &adev->children;
> + if (list_empty(head))
> + return NULL;
> +
> + if (!child)
> + return list_first_entry(head, struct acpi_device, node);
> +
> + next = child->node.next;
> + return next == head ? NULL : list_entry(next, struct acpi_device, node);
> +}
> +
> /* --------------------------------------------------------------------------
> Driver Management
> -------------------------------------------------------------------------- */
> @@ -1961,6 +1981,7 @@ void acpi_init_device_object(struct acpi
> device->device_type = type;
> device->handle = handle;
> device->parent = acpi_bus_get_parent(handle);
> + device->fwnode.type = FWNODE_ACPI;
> acpi_set_device_status(device, sta);
> acpi_device_get_busid(device);
> acpi_set_pnp_ids(handle, &device->pnp, type);
>