summaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/Makefile6
-rw-r--r--drivers/of/address.c51
-rw-r--r--drivers/of/base.c328
-rw-r--r--drivers/of/device.c7
-rw-r--r--drivers/of/dynamic.c23
-rw-r--r--drivers/of/fdt.c40
-rw-r--r--drivers/of/irq.c14
-rw-r--r--drivers/of/kexec.c458
-rw-r--r--drivers/of/of_net.c88
-rw-r--r--drivers/of/of_reserved_mem.c6
-rw-r--r--drivers/of/overlay.c22
-rw-r--r--drivers/of/platform.c12
-rw-r--r--drivers/of/property.c118
-rw-r--r--drivers/of/unittest-data/Makefile48
-rw-r--r--drivers/of/unittest-data/overlay_base.dts90
-rw-r--r--drivers/of/unittest-data/overlay_common.dtsi91
-rw-r--r--drivers/of/unittest-data/static_base_1.dts4
-rw-r--r--drivers/of/unittest-data/static_base_2.dts4
-rw-r--r--drivers/of/unittest-data/testcases.dts23
-rw-r--r--drivers/of/unittest-data/testcases_common.dtsi19
-rw-r--r--drivers/of/unittest-data/tests-interrupts.dtsi11
21 files changed, 1062 insertions, 401 deletions
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 6e1e5212f058..c13b982084a3 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -14,4 +14,10 @@ obj-$(CONFIG_OF_RESOLVE) += resolver.o
obj-$(CONFIG_OF_OVERLAY) += overlay.o
obj-$(CONFIG_OF_NUMA) += of_numa.o
+ifdef CONFIG_KEXEC_FILE
+ifdef CONFIG_OF_FLATTREE
+obj-y += kexec.o
+endif
+endif
+
obj-$(CONFIG_OF_UNITTEST) += unittest-data/
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 73ddf2540f3f..aca94c348bd4 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -26,6 +26,7 @@ static struct of_bus *of_match_bus(struct device_node *np);
static int __of_address_to_resource(struct device_node *dev,
const __be32 *addrp, u64 size, unsigned int flags,
const char *name, struct resource *r);
+static bool of_mmio_is_nonposted(struct device_node *np);
/* Debug utility */
#ifdef DEBUG
@@ -116,9 +117,12 @@ static unsigned int of_bus_pci_get_flags(const __be32 *addr)
flags |= IORESOURCE_IO;
break;
case 0x02: /* 32 bits */
- case 0x03: /* 64 bits */
flags |= IORESOURCE_MEM;
break;
+
+ case 0x03: /* 64 bits */
+ flags |= IORESOURCE_MEM | IORESOURCE_MEM_64;
+ break;
}
if (w & 0x40000000)
flags |= IORESOURCE_PREFETCH;
@@ -847,6 +851,9 @@ static int __of_address_to_resource(struct device_node *dev,
return -EINVAL;
memset(r, 0, sizeof(struct resource));
+ if (of_mmio_is_nonposted(dev))
+ flags |= IORESOURCE_MEM_NONPOSTED;
+
r->start = taddr;
r->end = taddr + size - 1;
r->flags = flags;
@@ -857,6 +864,9 @@ static int __of_address_to_resource(struct device_node *dev,
/**
* of_address_to_resource - Translate device tree address and return as resource
+ * @dev: Caller's Device Node
+ * @index: Index into the array
+ * @r: Pointer to resource array
*
* Note that if your address is a PIO address, the conversion will fail if
* the physical address can't be internally converted to an IO token with
@@ -896,7 +906,10 @@ void __iomem *of_iomap(struct device_node *np, int index)
if (of_address_to_resource(np, index, &res))
return NULL;
- return ioremap(res.start, resource_size(&res));
+ if (res.flags & IORESOURCE_MEM_NONPOSTED)
+ return ioremap_np(res.start, resource_size(&res));
+ else
+ return ioremap(res.start, resource_size(&res));
}
EXPORT_SYMBOL(of_iomap);
@@ -928,7 +941,11 @@ void __iomem *of_io_request_and_map(struct device_node *np, int index,
if (!request_mem_region(res.start, resource_size(&res), name))
return IOMEM_ERR_PTR(-EBUSY);
- mem = ioremap(res.start, resource_size(&res));
+ if (res.flags & IORESOURCE_MEM_NONPOSTED)
+ mem = ioremap_np(res.start, resource_size(&res));
+ else
+ mem = ioremap(res.start, resource_size(&res));
+
if (!mem) {
release_mem_region(res.start, resource_size(&res));
return IOMEM_ERR_PTR(-ENOMEM);
@@ -1094,3 +1111,31 @@ bool of_dma_is_coherent(struct device_node *np)
return false;
}
EXPORT_SYMBOL_GPL(of_dma_is_coherent);
+
+/**
+ * of_mmio_is_nonposted - Check if device uses non-posted MMIO
+ * @np: device node
+ *
+ * Returns true if the "nonposted-mmio" property was found for
+ * the device's bus.
+ *
+ * This is currently only enabled on builds that support Apple ARM devices, as
+ * an optimization.
+ */
+static bool of_mmio_is_nonposted(struct device_node *np)
+{
+ struct device_node *parent;
+ bool nonposted;
+
+ if (!IS_ENABLED(CONFIG_ARCH_APPLE))
+ return false;
+
+ parent = of_get_parent(np);
+ if (!parent)
+ return false;
+
+ nonposted = of_property_read_bool(parent, "nonposted-mmio");
+
+ of_node_put(parent);
+ return nonposted;
+}
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 8a348f0d3c5e..48e941f99558 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -244,7 +244,7 @@ struct device_node *__of_find_all_nodes(struct device_node *prev)
* @prev: Previous node or NULL to start iteration
* of_node_put() will be called on it
*
- * Returns a node pointer with refcount incremented, use
+ * Return: A node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_all_nodes(struct device_node *prev)
@@ -305,7 +305,7 @@ bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id)
return (u32)phys_id == cpu;
}
-/**
+/*
* Checks if the given "prop_name" property holds the physical id of the
* core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not
* NULL, local thread number within the core is returned in it.
@@ -374,7 +374,7 @@ bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun,
* before booting secondary cores. This function uses arch_match_cpu_phys_id
* which can be overridden by architecture specific implementation.
*
- * Returns a node pointer for the logical cpu with refcount incremented, use
+ * Return: A node pointer for the logical cpu with refcount incremented, use
* of_node_put() on it when done. Returns NULL if not found.
*/
struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
@@ -394,8 +394,8 @@ EXPORT_SYMBOL(of_get_cpu_node);
*
* @cpu_node: Pointer to the device_node for CPU.
*
- * Returns the logical CPU number of the given CPU device_node.
- * Returns -ENODEV if the CPU is not found.
+ * Return: The logical CPU number of the given CPU device_node or -ENODEV if the
+ * CPU is not found.
*/
int of_cpu_node_to_id(struct device_node *cpu_node)
{
@@ -427,7 +427,7 @@ EXPORT_SYMBOL(of_cpu_node_to_id);
* bindings. This function check for both and returns the idle state node for
* the requested index.
*
- * In case an idle state node is found at @index, the refcount is incremented
+ * Return: An idle state node if found at @index. The refcount is incremented
* for it, so call of_node_put() on it when done. Returns NULL if not found.
*/
struct device_node *of_get_cpu_state_node(struct device_node *cpu_node,
@@ -561,7 +561,7 @@ int of_device_compatible_match(struct device_node *device,
* of_machine_is_compatible - Test root of device tree for a given compatible value
* @compat: compatible string to look for in root node's compatible property.
*
- * Returns a positive integer if the root node has the given value in its
+ * Return: A positive integer if the root node has the given value in its
* compatible property.
*/
int of_machine_is_compatible(const char *compat)
@@ -583,7 +583,7 @@ EXPORT_SYMBOL(of_machine_is_compatible);
*
* @device: Node to check for availability, with locks already held
*
- * Returns true if the status property is absent or set to "okay" or "ok",
+ * Return: True if the status property is absent or set to "okay" or "ok",
* false otherwise
*/
static bool __of_device_is_available(const struct device_node *device)
@@ -611,7 +611,7 @@ static bool __of_device_is_available(const struct device_node *device)
*
* @device: Node to check for availability
*
- * Returns true if the status property is absent or set to "okay" or "ok",
+ * Return: True if the status property is absent or set to "okay" or "ok",
* false otherwise
*/
bool of_device_is_available(const struct device_node *device)
@@ -632,7 +632,7 @@ EXPORT_SYMBOL(of_device_is_available);
*
* @device: Node to check for endianness
*
- * Returns true if the device has a "big-endian" property, or if the kernel
+ * Return: True if the device has a "big-endian" property, or if the kernel
* was compiled for BE *and* the device has a "native-endian" property.
* Returns false otherwise.
*
@@ -651,11 +651,11 @@ bool of_device_is_big_endian(const struct device_node *device)
EXPORT_SYMBOL(of_device_is_big_endian);
/**
- * of_get_parent - Get a node's parent if any
- * @node: Node to get parent
+ * of_get_parent - Get a node's parent if any
+ * @node: Node to get parent
*
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
+ * Return: A node pointer with refcount incremented, use
+ * of_node_put() on it when done.
*/
struct device_node *of_get_parent(const struct device_node *node)
{
@@ -673,15 +673,15 @@ struct device_node *of_get_parent(const struct device_node *node)
EXPORT_SYMBOL(of_get_parent);
/**
- * of_get_next_parent - Iterate to a node's parent
- * @node: Node to get parent of
+ * of_get_next_parent - Iterate to a node's parent
+ * @node: Node to get parent of
*
- * This is like of_get_parent() except that it drops the
- * refcount on the passed node, making it suitable for iterating
- * through a node's parents.
+ * This is like of_get_parent() except that it drops the
+ * refcount on the passed node, making it suitable for iterating
+ * through a node's parents.
*
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
+ * Return: A node pointer with refcount incremented, use
+ * of_node_put() on it when done.
*/
struct device_node *of_get_next_parent(struct device_node *node)
{
@@ -719,13 +719,13 @@ static struct device_node *__of_get_next_child(const struct device_node *node,
child = __of_get_next_child(parent, child))
/**
- * of_get_next_child - Iterate a node childs
- * @node: parent node
- * @prev: previous child of the parent node, or NULL to get first
+ * of_get_next_child - Iterate a node childs
+ * @node: parent node
+ * @prev: previous child of the parent node, or NULL to get first
*
- * Returns a node pointer with refcount incremented, use of_node_put() on
- * it when done. Returns NULL when prev is the last child. Decrements the
- * refcount of prev.
+ * Return: A node pointer with refcount incremented, use of_node_put() on
+ * it when done. Returns NULL when prev is the last child. Decrements the
+ * refcount of prev.
*/
struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev)
@@ -741,12 +741,12 @@ struct device_node *of_get_next_child(const struct device_node *node,
EXPORT_SYMBOL(of_get_next_child);
/**
- * of_get_next_available_child - Find the next available child node
- * @node: parent node
- * @prev: previous child of the parent node, or NULL to get first
+ * of_get_next_available_child - Find the next available child node
+ * @node: parent node
+ * @prev: previous child of the parent node, or NULL to get first
*
- * This function is like of_get_next_child(), except that it
- * automatically skips any disabled nodes (i.e. status = "disabled").
+ * This function is like of_get_next_child(), except that it
+ * automatically skips any disabled nodes (i.e. status = "disabled").
*/
struct device_node *of_get_next_available_child(const struct device_node *node,
struct device_node *prev)
@@ -772,12 +772,12 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
EXPORT_SYMBOL(of_get_next_available_child);
/**
- * of_get_next_cpu_node - Iterate on cpu nodes
- * @prev: previous child of the /cpus node, or NULL to get first
+ * of_get_next_cpu_node - Iterate on cpu nodes
+ * @prev: previous child of the /cpus node, or NULL to get first
*
- * Returns a cpu node pointer with refcount incremented, use of_node_put()
- * on it when done. Returns NULL when prev is the last child. Decrements
- * the refcount of prev.
+ * Return: A cpu node pointer with refcount incremented, use of_node_put()
+ * on it when done. Returns NULL when prev is the last child. Decrements
+ * the refcount of prev.
*/
struct device_node *of_get_next_cpu_node(struct device_node *prev)
{
@@ -816,7 +816,7 @@ EXPORT_SYMBOL(of_get_next_cpu_node);
* Lookup child node whose compatible property contains the given compatible
* string.
*
- * Returns a node pointer with refcount incremented, use of_node_put() on it
+ * Return: a node pointer with refcount incremented, use of_node_put() on it
* when done; or NULL if not found.
*/
struct device_node *of_get_compatible_child(const struct device_node *parent,
@@ -834,15 +834,15 @@ struct device_node *of_get_compatible_child(const struct device_node *parent,
EXPORT_SYMBOL(of_get_compatible_child);
/**
- * of_get_child_by_name - Find the child node by name for a given parent
- * @node: parent node
- * @name: child name to look for.
+ * of_get_child_by_name - Find the child node by name for a given parent
+ * @node: parent node
+ * @name: child name to look for.
*
- * This function looks for child node for given matching name
+ * This function looks for child node for given matching name
*
- * Returns a node pointer if found, with refcount incremented, use
- * of_node_put() on it when done.
- * Returns NULL if node is not found.
+ * Return: A node pointer if found, with refcount incremented, use
+ * of_node_put() on it when done.
+ * Returns NULL if node is not found.
*/
struct device_node *of_get_child_by_name(const struct device_node *node,
const char *name)
@@ -893,22 +893,22 @@ struct device_node *__of_find_node_by_full_path(struct device_node *node,
}
/**
- * of_find_node_opts_by_path - Find a node matching a full OF path
- * @path: Either the full path to match, or if the path does not
- * start with '/', the name of a property of the /aliases
- * node (an alias). In the case of an alias, the node
- * matching the alias' value will be returned.
- * @opts: Address of a pointer into which to store the start of
- * an options string appended to the end of the path with
- * a ':' separator.
- *
- * Valid paths:
- * /foo/bar Full path
- * foo Valid alias
- * foo/bar Valid alias + relative path
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
+ * of_find_node_opts_by_path - Find a node matching a full OF path
+ * @path: Either the full path to match, or if the path does not
+ * start with '/', the name of a property of the /aliases
+ * node (an alias). In the case of an alias, the node
+ * matching the alias' value will be returned.
+ * @opts: Address of a pointer into which to store the start of
+ * an options string appended to the end of the path with
+ * a ':' separator.
+ *
+ * Valid paths:
+ * * /foo/bar Full path
+ * * foo Valid alias
+ * * foo/bar Valid alias + relative path
+ *
+ * Return: A node pointer with refcount incremented, use
+ * of_node_put() on it when done.
*/
struct device_node *of_find_node_opts_by_path(const char *path, const char **opts)
{
@@ -958,15 +958,15 @@ struct device_node *of_find_node_opts_by_path(const char *path, const char **opt
EXPORT_SYMBOL(of_find_node_opts_by_path);
/**
- * of_find_node_by_name - Find a node by its "name" property
- * @from: The node to start searching from or NULL; the node
+ * of_find_node_by_name - Find a node by its "name" property
+ * @from: The node to start searching from or NULL; the node
* you pass will not be searched, only the next one
* will. Typically, you pass what the previous call
* returned. of_node_put() will be called on @from.
- * @name: The name string to match against
+ * @name: The name string to match against
*
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
+ * Return: A node pointer with refcount incremented, use
+ * of_node_put() on it when done.
*/
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)
@@ -985,16 +985,16 @@ struct device_node *of_find_node_by_name(struct device_node *from,
EXPORT_SYMBOL(of_find_node_by_name);
/**
- * of_find_node_by_type - Find a node by its "device_type" property
- * @from: The node to start searching from, or NULL to start searching
+ * of_find_node_by_type - Find a node by its "device_type" property
+ * @from: The node to start searching from, or NULL to start searching
* the entire device tree. The node you pass will not be
* searched, only the next one will; typically, you pass
* what the previous call returned. of_node_put() will be
* called on from for you.
- * @type: The type string to match against
+ * @type: The type string to match against
*
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
+ * Return: A node pointer with refcount incremented, use
+ * of_node_put() on it when done.
*/
struct device_node *of_find_node_by_type(struct device_node *from,
const char *type)
@@ -1013,18 +1013,18 @@ struct device_node *of_find_node_by_type(struct device_node *from,
EXPORT_SYMBOL(of_find_node_by_type);
/**
- * of_find_compatible_node - Find a node based on type and one of the
+ * of_find_compatible_node - Find a node based on type and one of the
* tokens in its "compatible" property
- * @from: The node to start searching from or NULL, the node
- * you pass will not be searched, only the next one
- * will; typically, you pass what the previous call
- * returned. of_node_put() will be called on it
- * @type: The type string to match "device_type" or NULL to ignore
- * @compatible: The string to match to one of the tokens in the device
- * "compatible" list.
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @type: The type string to match "device_type" or NULL to ignore
+ * @compatible: The string to match to one of the tokens in the device
+ * "compatible" list.
+ *
+ * Return: A node pointer with refcount incremented, use
+ * of_node_put() on it when done.
*/
struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compatible)
@@ -1044,16 +1044,16 @@ struct device_node *of_find_compatible_node(struct device_node *from,
EXPORT_SYMBOL(of_find_compatible_node);
/**
- * of_find_node_with_property - Find a node which has a property with
- * the given name.
- * @from: The node to start searching from or NULL, the node
- * you pass will not be searched, only the next one
- * will; typically, you pass what the previous call
- * returned. of_node_put() will be called on it
- * @prop_name: The name of the property to look for.
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
+ * of_find_node_with_property - Find a node which has a property with
+ * the given name.
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @prop_name: The name of the property to look for.
+ *
+ * Return: A node pointer with refcount incremented, use
+ * of_node_put() on it when done.
*/
struct device_node *of_find_node_with_property(struct device_node *from,
const char *prop_name)
@@ -1102,10 +1102,10 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
/**
* of_match_node - Tell if a device_node has a matching of_match structure
- * @matches: array of of device match structures to search in
- * @node: the of device structure to match against
+ * @matches: array of of device match structures to search in
+ * @node: the of device structure to match against
*
- * Low level utility function used by device matching.
+ * Low level utility function used by device matching.
*/
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct device_node *node)
@@ -1121,17 +1121,17 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches,
EXPORT_SYMBOL(of_match_node);
/**
- * of_find_matching_node_and_match - Find a node based on an of_device_id
- * match table.
- * @from: The node to start searching from or NULL, the node
- * you pass will not be searched, only the next one
- * will; typically, you pass what the previous call
- * returned. of_node_put() will be called on it
- * @matches: array of of device match structures to search in
- * @match Updated to point at the matches entry which matched
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
+ * of_find_matching_node_and_match - Find a node based on an of_device_id
+ * match table.
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @matches: array of of device match structures to search in
+ * @match: Updated to point at the matches entry which matched
+ *
+ * Return: A node pointer with refcount incremented, use
+ * of_node_put() on it when done.
*/
struct device_node *of_find_matching_node_and_match(struct device_node *from,
const struct of_device_id *matches,
@@ -1170,7 +1170,7 @@ EXPORT_SYMBOL(of_find_matching_node_and_match);
* It does this by stripping the manufacturer prefix (as delimited by a ',')
* from the first entry in the compatible list property.
*
- * This routine returns 0 on success, <0 on failure.
+ * Return: This routine returns 0 on success, <0 on failure.
*/
int of_modalias_node(struct device_node *node, char *modalias, int len)
{
@@ -1190,7 +1190,7 @@ EXPORT_SYMBOL_GPL(of_modalias_node);
* of_find_node_by_phandle - Find a node given a phandle
* @handle: phandle of the node to find
*
- * Returns a node pointer with refcount incremented, use
+ * Return: A node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_node_by_phandle(phandle handle)
@@ -1426,7 +1426,7 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
* @index: For properties holding a table of phandles, this is the index into
* the table
*
- * Returns the device_node pointer with refcount incremented. Use
+ * Return: The device_node pointer with refcount incremented. Use
* of_node_put() on it when done.
*/
struct device_node *of_parse_phandle(const struct device_node *np,
@@ -1460,21 +1460,21 @@ EXPORT_SYMBOL(of_parse_phandle);
* Caller is responsible to call of_node_put() on the returned out_args->np
* pointer.
*
- * Example:
+ * Example::
*
- * phandle1: node1 {
+ * phandle1: node1 {
* #list-cells = <2>;
- * }
+ * };
*
- * phandle2: node2 {
+ * phandle2: node2 {
* #list-cells = <1>;
- * }
+ * };
*
- * node3 {
+ * node3 {
* list = <&phandle1 1 2 &phandle2 3>;
- * }
+ * };
*
- * To get a device_node of the `node2' node you may call this:
+ * To get a device_node of the ``node2`` node you may call this:
* of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
*/
int of_parse_phandle_with_args(const struct device_node *np, const char *list_name,
@@ -1512,29 +1512,29 @@ EXPORT_SYMBOL(of_parse_phandle_with_args);
* Caller is responsible to call of_node_put() on the returned out_args->np
* pointer.
*
- * Example:
+ * Example::
*
- * phandle1: node1 {
- * #list-cells = <2>;
- * }
+ * phandle1: node1 {
+ * #list-cells = <2>;
+ * };
*
- * phandle2: node2 {
- * #list-cells = <1>;
- * }
+ * phandle2: node2 {
+ * #list-cells = <1>;
+ * };
*
- * phandle3: node3 {
- * #list-cells = <1>;
- * list-map = <0 &phandle2 3>,
- * <1 &phandle2 2>,
- * <2 &phandle1 5 1>;
- * list-map-mask = <0x3>;
- * };
+ * phandle3: node3 {
+ * #list-cells = <1>;
+ * list-map = <0 &phandle2 3>,
+ * <1 &phandle2 2>,
+ * <2 &phandle1 5 1>;
+ * list-map-mask = <0x3>;
+ * };
*
- * node4 {
- * list = <&phandle1 1 2 &phandle3 0>;
- * }
+ * node4 {
+ * list = <&phandle1 1 2 &phandle3 0>;
+ * };
*
- * To get a device_node of the `node2' node you may call this:
+ * To get a device_node of the ``node2`` node you may call this:
* of_parse_phandle_with_args(node4, "list", "list", 1, &args);
*/
int of_parse_phandle_with_args_map(const struct device_node *np,
@@ -1694,19 +1694,19 @@ EXPORT_SYMBOL(of_parse_phandle_with_args_map);
* Caller is responsible to call of_node_put() on the returned out_args->np
* pointer.
*
- * Example:
+ * Example::
*
- * phandle1: node1 {
- * }
+ * phandle1: node1 {
+ * };
*
- * phandle2: node2 {
- * }
+ * phandle2: node2 {
+ * };
*
- * node3 {
- * list = <&phandle1 0 2 &phandle2 2 3>;
- * }
+ * node3 {
+ * list = <&phandle1 0 2 &phandle2 2 3>;
+ * };
*
- * To get a device_node of the `node2' node you may call this:
+ * To get a device_node of the ``node2`` node you may call this:
* of_parse_phandle_with_fixed_args(node3, "list", 2, 1, &args);
*/
int of_parse_phandle_with_fixed_args(const struct device_node *np,
@@ -1726,7 +1726,7 @@ EXPORT_SYMBOL(of_parse_phandle_with_fixed_args);
* @list_name: property name that contains a list
* @cells_name: property name that specifies phandles' arguments count
*
- * Returns the number of phandle + argument tuples within a property. It
+ * Return: The number of phandle + argument tuples within a property. It
* is a typical pattern to encode a list of phandle and variable
* arguments into a single property. The number of arguments is encoded
* by a property in the phandle-target node. For example, a gpios
@@ -1774,6 +1774,8 @@ EXPORT_SYMBOL(of_count_phandle_with_args);
/**
* __of_add_property - Add a property to a node without lock operations
+ * @np: Caller's Device Node
+ * @prop: Property to add
*/
int __of_add_property(struct device_node *np, struct property *prop)
{
@@ -1795,6 +1797,8 @@ int __of_add_property(struct device_node *np, struct property *prop)
/**
* of_add_property - Add a property to a node
+ * @np: Caller's Device Node
+ * @prop: Property to add
*/
int of_add_property(struct device_node *np, struct property *prop)
{
@@ -1839,6 +1843,8 @@ int __of_remove_property(struct device_node *np, struct property *prop)
/**
* of_remove_property - Remove a property from a node.
+ * @np: Caller's Device Node
+ * @prop: Property to remove
*
* Note that we don't actually remove it, since we have given out
* who-knows-how-many pointers to the data using get-property.
@@ -1946,13 +1952,12 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np,
/**
* of_alias_scan - Scan all properties of the 'aliases' node
+ * @dt_alloc: An allocator that provides a virtual address to memory
+ * for storing the resulting tree
*
* The function scans all the properties of the 'aliases' node and populates
* the global lookup table with the properties. It returns the
* number of alias properties found, or an error code in case of failure.
- *
- * @dt_alloc: An allocator that provides a virtual address to memory
- * for storing the resulting tree
*/
void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
{
@@ -2021,7 +2026,9 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
* @stem: Alias stem of the given device_node
*
* The function travels the lookup table to get the alias id for the given
- * device_node and alias stem. It returns the alias id if found.
+ * device_node and alias stem.
+ *
+ * Return: The alias id if found.
*/
int of_alias_get_id(struct device_node *np, const char *stem)
{
@@ -2125,13 +2132,14 @@ EXPORT_SYMBOL_GPL(of_alias_get_highest_id);
/**
* of_console_check() - Test and setup console for DT setup
- * @dn - Pointer to device node
- * @name - Name to use for preferred console without index. ex. "ttyS"
- * @index - Index to use for preferred console.
+ * @dn: Pointer to device node
+ * @name: Name to use for preferred console without index. ex. "ttyS"
+ * @index: Index to use for preferred console.
*
* Check if the given device node matches the stdout-path property in the
- * /chosen node. If it does then register it as the preferred console and return
- * TRUE. Otherwise return FALSE.
+ * /chosen node. If it does then register it as the preferred console.
+ *
+ * Return: TRUE if console successfully setup. Otherwise return FALSE.
*/
bool of_console_check(struct device_node *dn, char *name, int index)
{
@@ -2147,12 +2155,12 @@ bool of_console_check(struct device_node *dn, char *name, int index)
EXPORT_SYMBOL_GPL(of_console_check);
/**
- * of_find_next_cache_node - Find a node's subsidiary cache
- * @np: node of type "cpu" or "cache"
+ * of_find_next_cache_node - Find a node's subsidiary cache
+ * @np: node of type "cpu" or "cache"
*
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done. Caller should hold a reference
- * to np.
+ * Return: A node pointer with refcount incremented, use
+ * of_node_put() on it when done. Caller should hold a reference
+ * to np.
*/
struct device_node *of_find_next_cache_node(const struct device_node *np)
{
@@ -2182,7 +2190,7 @@ struct device_node *of_find_next_cache_node(const struct device_node *np)
*
* @cpu: cpu number(logical index) for which the last cache level is needed
*
- * Returns the the level at which the last cache is present. It is exactly
+ * Return: The the level at which the last cache is present. It is exactly
* same as the total number of cache levels for the given logical cpu.
*/
int of_find_last_cache_level(unsigned int cpu)
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 6cb86de404f1..c5a9473a5fb1 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -53,7 +53,7 @@ int of_device_add(struct platform_device *ofdev)
}
/**
- * of_dma_configure - Setup DMA configuration
+ * of_dma_configure_id - Setup DMA configuration
* @dev: Device to apply DMA configuration
* @np: Pointer to OF node having DMA configuration
* @force_dma: Whether device is to be set up by of_dma_configure() even if
@@ -258,6 +258,9 @@ EXPORT_SYMBOL_GPL(of_device_request_module);
/**
* of_device_modalias - Fill buffer with newline terminated modalias string
+ * @dev: Calling device
+ * @str: Modalias string
+ * @len: Size of @str
*/
ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len)
{
@@ -275,6 +278,8 @@ EXPORT_SYMBOL_GPL(of_device_modalias);
/**
* of_device_uevent - Display OF related uevent information
+ * @dev: Device to apply DMA configuration
+ * @env: Kernel object's userspace event reference
*/
void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 9a824decf61f..cd3821a6444f 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -27,7 +27,7 @@ static struct device_node *kobj_to_device_node(struct kobject *kobj)
* @node: Node to inc refcount, NULL is supported to simplify writing of
* callers
*
- * Returns node.
+ * Return: The node with refcount incremented.
*/
struct device_node *of_node_get(struct device_node *node)
{
@@ -104,7 +104,8 @@ int of_reconfig_notify(unsigned long action, struct of_reconfig_data *p)
* @arg - argument of the of notifier
*
* Returns the new state of a device based on the notifier used.
- * Returns 0 on device going from enabled to disabled, 1 on device
+ *
+ * Return: 0 on device going from enabled to disabled, 1 on device
* going from disabled to enabled and -1 on no change.
*/
int of_reconfig_get_state_change(unsigned long action, struct of_reconfig_data *pr)
@@ -229,6 +230,7 @@ static void __of_attach_node(struct device_node *np)
/**
* of_attach_node() - Plug a device node into the tree and global list.
+ * @np: Pointer to the caller's Device Node
*/
int of_attach_node(struct device_node *np)
{
@@ -281,6 +283,7 @@ void __of_detach_node(struct device_node *np)
/**
* of_detach_node() - "Unplug" a node from the device tree.
+ * @np: Pointer to the caller's Device Node
*/
int of_detach_node(struct device_node *np)
{
@@ -318,7 +321,7 @@ static void property_list_free(struct property *prop_list)
/**
* of_node_release() - release a dynamically allocated node
- * @kref: kref element of the node to be released
+ * @kobj: kernel object of the node to be released
*
* In of_node_put() this function is passed to kref_put() as the destructor.
*/
@@ -372,7 +375,8 @@ void of_node_release(struct kobject *kobj)
* property structure and the property name & contents. The property's
* flags have the OF_DYNAMIC bit set so that we can differentiate between
* dynamically allocated properties and not.
- * Returns the newly allocated property or NULL on out of memory error.
+ *
+ * Return: The newly allocated property or NULL on out of memory error.
*/
struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
{
@@ -415,7 +419,7 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
* another node. The node data are dynamically allocated and all the node
* flags have the OF_DYNAMIC & OF_DETACHED bits set.
*
- * Returns the newly allocated node or NULL on out of memory error.
+ * Return: The newly allocated node or NULL on out of memory error.
*/
struct device_node *__of_node_dup(const struct device_node *np,
const char *full_name)
@@ -781,7 +785,8 @@ static int __of_changeset_apply(struct of_changeset *ocs)
* Any side-effects of live tree state changes are applied here on
* success, like creation/destruction of devices and side-effects
* like creation of sysfs properties and directories.
- * Returns 0 on success, a negative error value in case of an error.
+ *
+ * Return: 0 on success, a negative error value in case of an error.
* On error the partially applied effects are reverted.
*/
int of_changeset_apply(struct of_changeset *ocs)
@@ -875,7 +880,8 @@ static int __of_changeset_revert(struct of_changeset *ocs)
* was before the application.
* Any side-effects like creation/destruction of devices and
* removal of sysfs properties and directories are applied.
- * Returns 0 on success, a negative error value in case of an error.
+ *
+ * Return: 0 on success, a negative error value in case of an error.
*/
int of_changeset_revert(struct of_changeset *ocs)
{
@@ -903,7 +909,8 @@ EXPORT_SYMBOL_GPL(of_changeset_revert);
* + OF_RECONFIG_ADD_PROPERTY
* + OF_RECONFIG_REMOVE_PROPERTY,
* + OF_RECONFIG_UPDATE_PROPERTY
- * Returns 0 on success, a negative error value in case of an error.
+ *
+ * Return: 0 on success, a negative error value in case of an error.
*/
int of_changeset_action(struct of_changeset *ocs, unsigned long action,
struct device_node *np, struct property *prop)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index adb26aff481d..ba17a80b8c79 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -282,7 +282,7 @@ static void reverse_nodes(struct device_node *parent)
* @dad: Parent struct device_node
* @nodepp: The device_node tree created by the call
*
- * It returns the size of unflattened device tree or error code
+ * Return: The size of unflattened device tree or error code
*/
static int unflatten_dt_nodes(const void *blob,
void *mem,
@@ -351,11 +351,6 @@ static int unflatten_dt_nodes(const void *blob,
/**
* __unflatten_device_tree - create tree of device_nodes from flat blob
- *
- * unflattens a device-tree, creating the
- * tree of struct device_node. It also fills the "name" and "type"
- * pointers of the nodes so the normal device-tree walking functions
- * can be used.
* @blob: The blob to expand
* @dad: Parent device node
* @mynodes: The device_node tree created by the call
@@ -363,7 +358,11 @@ static int unflatten_dt_nodes(const void *blob,
* for the resulting tree
* @detached: if true set OF_DETACHED on @mynodes
*
- * Returns NULL on failure or the memory chunk containing the unflattened
+ * unflattens a device-tree, creating the tree of struct device_node. It also
+ * fills the "name" and "type" pointers of the nodes so the normal device-tree
+ * walking functions can be used.
+ *
+ * Return: NULL on failure or the memory chunk containing the unflattened
* device tree on success.
*/
void *__unflatten_device_tree(const void *blob,
@@ -452,7 +451,7 @@ static DEFINE_MUTEX(of_fdt_unflatten_mutex);
* pointers of the nodes so the normal device-tree walking functions
* can be used.
*
- * Returns NULL on failure or the memory chunk containing the unflattened
+ * Return: NULL on failure or the memory chunk containing the unflattened
* device tree on success.
*/
void *of_fdt_unflatten_tree(const unsigned long *blob,
@@ -480,7 +479,7 @@ void *initial_boot_params __ro_after_init;
static u32 of_fdt_crc32;
-/**
+/*
* __reserved_mem_reserve_reg() - reserve all memory described in 'reg' property
*/
static int __init __reserved_mem_reserve_reg(unsigned long node,
@@ -526,7 +525,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
return 0;
}
-/**
+/*
* __reserved_mem_check_root() - check if #size-cells, #address-cells provided
* in /reserved-memory matches the values supported by the current implementation,
* also check if ranges property has been provided
@@ -549,8 +548,8 @@ static int __init __reserved_mem_check_root(unsigned long node)
return 0;
}
-/**
- * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
+/*
+ * __fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
*/
static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
int depth, void *data)
@@ -660,6 +659,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
/**
* of_scan_flat_dt_subnodes - scan sub-nodes of a node call callback on each.
+ * @parent: parent node
* @it: callback function
* @data: context data pointer
*
@@ -699,7 +699,7 @@ int __init of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname)
return fdt_subnode_offset(initial_boot_params, node, uname);
}
-/**
+/*
* of_get_flat_dt_root - find the root node in the flat blob
*/
unsigned long __init of_get_flat_dt_root(void)
@@ -707,7 +707,7 @@ unsigned long __init of_get_flat_dt_root(void)
return 0;
}
-/**
+/*
* of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
*
* This function can be used within scan_flattened_dt callback to get
@@ -726,7 +726,7 @@ const void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
* @node: node to test
* @compat: compatible string to compare with compatible list.
*
- * On match, returns a non-zero value with smaller values returned for more
+ * Return: a non-zero value on match with smaller values returned for more
* specific compatible values.
*/
static int of_fdt_is_compatible(const void *blob,
@@ -761,7 +761,7 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
return of_fdt_is_compatible(initial_boot_params, node, compat);
}
-/**
+/*
* of_flat_dt_match - Return true if node matches a list of compatible values
*/
static int __init of_flat_dt_match(unsigned long node, const char *const *compat)
@@ -781,8 +781,8 @@ static int __init of_flat_dt_match(unsigned long node, const char *const *compat
return score;
}
-/**
- * of_get_flat_dt_prop - Given a node in the flat blob, return the phandle
+/*
+ * of_get_flat_dt_phandle - Given a node in the flat blob, return the phandle
*/
uint32_t __init of_get_flat_dt_phandle(unsigned long node)
{
@@ -957,7 +957,7 @@ int __init early_init_dt_scan_chosen_stdout(void)
}
#endif
-/**
+/*
* early_init_dt_scan_root - fetch the top level address and size cells
*/
int __init early_init_dt_scan_root(unsigned long node, const char *uname,
@@ -993,7 +993,7 @@ u64 __init dt_mem_next_cell(int s, const __be32 **cellp)
return of_read_number(p, s);
}
-/**
+/*
* early_init_dt_scan_memory - Look for and parse memory nodes
*/
int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 25d17b8a1a1a..352e14b007e7 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -48,7 +48,7 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
* of_irq_find_parent - Given a device node, find its interrupt parent node
* @child: pointer to device node
*
- * Returns a pointer to the interrupt parent node, or NULL if the interrupt
+ * Return: A pointer to the interrupt parent node, or NULL if the interrupt
* parent could not be determined.
*/
struct device_node *of_irq_find_parent(struct device_node *child)
@@ -81,14 +81,14 @@ EXPORT_SYMBOL_GPL(of_irq_find_parent);
* @addr: address specifier (start of "reg" property of the device) in be32 format
* @out_irq: structure of_phandle_args updated by this function
*
- * Returns 0 on success and a negative number on error
- *
* This function is a low-level interrupt tree walking function. It
* can be used to do a partial walk with synthetized reg and interrupts
* properties, for example when resolving PCI interrupts when no device
* node exist for the parent. It takes an interrupt specifier structure as
* input, walks the tree looking for any interrupt-map properties, translates
* the specifier for each map, and then returns the translated map.
+ *
+ * Return: 0 on success and a negative number on error
*/
int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
{
@@ -380,7 +380,7 @@ EXPORT_SYMBOL_GPL(of_irq_to_resource);
* @dev: pointer to device tree node
* @index: zero-based index of the IRQ
*
- * Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
+ * Return: Linux IRQ number on success, or 0 on the IRQ mapping failure, or
* -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
* of any other failure.
*/
@@ -407,7 +407,7 @@ EXPORT_SYMBOL_GPL(of_irq_get);
* @dev: pointer to device tree node
* @name: IRQ name
*
- * Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
+ * Return: Linux IRQ number on success, or 0 on the IRQ mapping failure, or
* -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
* of any other failure.
*/
@@ -447,7 +447,7 @@ int of_irq_count(struct device_node *dev)
* @res: array of resources to fill in
* @nr_irqs: the number of IRQs (and upper bound for num of @res elements)
*
- * Returns the size of the filled in table (up to @nr_irqs).
+ * Return: The size of the filled in table (up to @nr_irqs).
*/
int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
int nr_irqs)
@@ -602,7 +602,7 @@ static u32 __of_msi_map_id(struct device *dev, struct device_node **np,
* Walk up the device hierarchy looking for devices with a "msi-map"
* property. If found, apply the mapping to @id_in.
*
- * Returns the mapped MSI ID.
+ * Return: The mapped MSI ID.
*/
u32 of_msi_map_id(struct device *dev, struct device_node *msi_np, u32 id_in)
{
diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c
new file mode 100644
index 000000000000..f335d941a716
--- /dev/null
+++ b/drivers/of/kexec.c
@@ -0,0 +1,458 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 Arm Limited
+ *
+ * Based on arch/arm64/kernel/machine_kexec_file.c:
+ * Copyright (C) 2018 Linaro Limited
+ *
+ * And arch/powerpc/kexec/file_load.c:
+ * Copyright (C) 2016 IBM Corporation
+ */
+
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/memblock.h>
+#include <linux/libfdt.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/random.h>
+#include <linux/types.h>
+
+/* relevant device tree properties */
+#define FDT_PROP_KEXEC_ELFHDR "linux,elfcorehdr"
+#define FDT_PROP_MEM_RANGE "linux,usable-memory-range"
+#define FDT_PROP_INITRD_START "linux,initrd-start"
+#define FDT_PROP_INITRD_END "linux,initrd-end"
+#define FDT_PROP_BOOTARGS "bootargs"
+#define FDT_PROP_KASLR_SEED "kaslr-seed"
+#define FDT_PROP_RNG_SEED "rng-seed"
+#define RNG_SEED_SIZE 128
+
+/*
+ * Additional space needed for the FDT buffer so that we can add initrd,
+ * bootargs, kaslr-seed, rng-seed, useable-memory-range and elfcorehdr.
+ */
+#define FDT_EXTRA_SPACE 0x1000
+
+/**
+ * fdt_find_and_del_mem_rsv - delete memory reservation with given address and size
+ *
+ * @fdt: Flattened device tree for the current kernel.
+ * @start: Starting address of the reserved memory.
+ * @size: Size of the reserved memory.
+ *
+ * Return: 0 on success, or negative errno on error.
+ */
+static int fdt_find_and_del_mem_rsv(void *fdt, unsigned long start, unsigned long size)
+{
+ int i, ret, num_rsvs = fdt_num_mem_rsv(fdt);
+
+ for (i = 0; i < num_rsvs; i++) {
+ u64 rsv_start, rsv_size;
+
+ ret = fdt_get_mem_rsv(fdt, i, &rsv_start, &rsv_size);
+ if (ret) {
+ pr_err("Malformed device tree.\n");
+ return -EINVAL;
+ }
+
+ if (rsv_start == start && rsv_size == size) {
+ ret = fdt_del_mem_rsv(fdt, i);
+ if (ret) {
+ pr_err("Error deleting device tree reservation.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * get_addr_size_cells - Get address and size of root node
+ *
+ * @addr_cells: Return address of the root node
+ * @size_cells: Return size of the root node
+ *
+ * Return: 0 on success, or negative errno on error.
+ */
+static int get_addr_size_cells(int *addr_cells, int *size_cells)
+{
+ struct device_node *root;
+
+ root = of_find_node_by_path("/");
+ if (!root)
+ return -EINVAL;
+
+ *addr_cells = of_n_addr_cells(root);
+ *size_cells = of_n_size_cells(root);
+
+ of_node_put(root);
+
+ return 0;
+}
+
+/**
+ * do_get_kexec_buffer - Get address and size of device tree property
+ *
+ * @prop: Device tree property
+ * @len: Size of @prop
+ * @addr: Return address of the node
+ * @size: Return size of the node
+ *
+ * Return: 0 on success, or negative errno on error.
+ */
+static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
+ size_t *size)
+{
+ int ret, addr_cells, size_cells;
+
+ ret = get_addr_size_cells(&addr_cells, &size_cells);
+ if (ret)
+ return ret;
+
+ if (len < 4 * (addr_cells + size_cells))
+ return -ENOENT;
+
+ *addr = of_read_number(prop, addr_cells);
+ *size = of_read_number(prop + 4 * addr_cells, size_cells);
+
+ return 0;
+}
+
+/**
+ * ima_get_kexec_buffer - get IMA buffer from the previous kernel
+ * @addr: On successful return, set to point to the buffer contents.
+ * @size: On successful return, set to the buffer size.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int ima_get_kexec_buffer(void **addr, size_t *size)
+{
+ int ret, len;
+ unsigned long tmp_addr;
+ size_t tmp_size;
+ const void *prop;
+
+ if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC))
+ return -ENOTSUPP;
+
+ prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len);
+ if (!prop)
+ return -ENOENT;
+
+ ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size);
+ if (ret)
+ return ret;
+
+ *addr = __va(tmp_addr);
+ *size = tmp_size;
+
+ return 0;
+}
+
+/**
+ * ima_free_kexec_buffer - free memory used by the IMA buffer
+ */
+int ima_free_kexec_buffer(void)
+{
+ int ret;
+ unsigned long addr;
+ size_t size;
+ struct property *prop;
+
+ if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC))
+ return -ENOTSUPP;
+
+ prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL);
+ if (!prop)
+ return -ENOENT;
+
+ ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size);
+ if (ret)
+ return ret;
+
+ ret = of_remove_property(of_chosen, prop);
+ if (ret)
+ return ret;
+
+ return memblock_free(addr, size);
+
+}
+
+/**
+ * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
+ *
+ * @fdt: Flattened Device Tree to update
+ * @chosen_node: Offset to the chosen node in the device tree
+ *
+ * The IMA measurement buffer is of no use to a subsequent kernel, so we always
+ * remove it from the device tree.
+ */
+static void remove_ima_buffer(void *fdt, int chosen_node)
+{
+ int ret, len;
+ unsigned long addr;
+ size_t size;
+ const void *prop;
+
+ if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC))
+ return;
+
+ prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len);
+ if (!prop)
+ return;
+
+ ret = do_get_kexec_buffer(prop, len, &addr, &size);
+ fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer");
+ if (ret)
+ return;
+
+ ret = fdt_find_and_del_mem_rsv(fdt, addr, size);
+ if (!ret)
+ pr_debug("Removed old IMA buffer reservation.\n");
+}
+
+#ifdef CONFIG_IMA_KEXEC
+/**
+ * setup_ima_buffer - add IMA buffer information to the fdt
+ * @image: kexec image being loaded.
+ * @fdt: Flattened device tree for the next kernel.
+ * @chosen_node: Offset to the chosen node.
+ *
+ * Return: 0 on success, or negative errno on error.
+ */
+static int setup_ima_buffer(const struct kimage *image, void *fdt,
+ int chosen_node)
+{
+ int ret;
+
+ if (!image->ima_buffer_size)
+ return 0;
+
+ ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
+ "linux,ima-kexec-buffer",
+ image->ima_buffer_addr,
+ image->ima_buffer_size);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = fdt_add_mem_rsv(fdt, image->ima_buffer_addr,
+ image->ima_buffer_size);
+ if (ret)
+ return -EINVAL;
+
+ pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n",
+ image->ima_buffer_addr, image->ima_buffer_size);
+
+ return 0;
+}
+#else /* CONFIG_IMA_KEXEC */
+static inline int setup_ima_buffer(const struct kimage *image, void *fdt,
+ int chosen_node)
+{
+ return 0;
+}
+#endif /* CONFIG_IMA_KEXEC */
+
+/*
+ * of_kexec_alloc_and_setup_fdt - Alloc and setup a new Flattened Device Tree
+ *
+ * @image: kexec image being loaded.
+ * @initrd_load_addr: Address where the next initrd will be loaded.
+ * @initrd_len: Size of the next initrd, or 0 if there will be none.
+ * @cmdline: Command line for the next kernel, or NULL if there will
+ * be none.
+ * @extra_fdt_size: Additional size for the new FDT buffer.
+ *
+ * Return: fdt on success, or NULL errno on error.
+ */
+void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
+ unsigned long initrd_load_addr,
+ unsigned long initrd_len,
+ const char *cmdline, size_t extra_fdt_size)
+{
+ void *fdt;
+ int ret, chosen_node;
+ const void *prop;
+ size_t fdt_size;
+
+ fdt_size = fdt_totalsize(initial_boot_params) +
+ (cmdline ? strlen(cmdline) : 0) +
+ FDT_EXTRA_SPACE +
+ extra_fdt_size;
+ fdt = kvmalloc(fdt_size, GFP_KERNEL);
+ if (!fdt)
+ return NULL;
+
+ ret = fdt_open_into(initial_boot_params, fdt, fdt_size);
+ if (ret < 0) {
+ pr_err("Error %d setting up the new device tree.\n", ret);
+ goto out;
+ }
+
+ /* Remove memory reservation for the current device tree. */
+ ret = fdt_find_and_del_mem_rsv(fdt, __pa(initial_boot_params),
+ fdt_totalsize(initial_boot_params));
+ if (ret == -EINVAL) {
+ pr_err("Error removing memory reservation.\n");
+ goto out;
+ }
+
+ chosen_node = fdt_path_offset(fdt, "/chosen");
+ if (chosen_node == -FDT_ERR_NOTFOUND)
+ chosen_node = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"),
+ "chosen");
+ if (chosen_node < 0) {
+ ret = chosen_node;
+ goto out;
+ }
+
+ ret = fdt_delprop(fdt, chosen_node, FDT_PROP_KEXEC_ELFHDR);
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ goto out;
+ ret = fdt_delprop(fdt, chosen_node, FDT_PROP_MEM_RANGE);
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ goto out;
+
+ /* Did we boot using an initrd? */
+ prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", NULL);
+ if (prop) {
+ u64 tmp_start, tmp_end, tmp_size;
+
+ tmp_start = fdt64_to_cpu(*((const fdt64_t *) prop));
+
+ prop = fdt_getprop(fdt, chosen_node, "linux,initrd-end", NULL);
+ if (!prop) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ tmp_end = fdt64_to_cpu(*((const fdt64_t *) prop));
+
+ /*
+ * kexec reserves exact initrd size, while firmware may
+ * reserve a multiple of PAGE_SIZE, so check for both.
+ */
+ tmp_size = tmp_end - tmp_start;
+ ret = fdt_find_and_del_mem_rsv(fdt, tmp_start, tmp_size);
+ if (ret == -ENOENT)
+ ret = fdt_find_and_del_mem_rsv(fdt, tmp_start,
+ round_up(tmp_size, PAGE_SIZE));
+ if (ret == -EINVAL)
+ goto out;
+ }
+
+ /* add initrd-* */
+ if (initrd_load_addr) {
+ ret = fdt_setprop_u64(fdt, chosen_node, FDT_PROP_INITRD_START,
+ initrd_load_addr);
+ if (ret)
+ goto out;
+
+ ret = fdt_setprop_u64(fdt, chosen_node, FDT_PROP_INITRD_END,
+ initrd_load_addr + initrd_len);
+ if (ret)
+ goto out;
+
+ ret = fdt_add_mem_rsv(fdt, initrd_load_addr, initrd_len);
+ if (ret)
+ goto out;
+
+ } else {
+ ret = fdt_delprop(fdt, chosen_node, FDT_PROP_INITRD_START);
+ if (ret && (ret != -FDT_ERR_NOTFOUND))
+ goto out;
+
+ ret = fdt_delprop(fdt, chosen_node, FDT_PROP_INITRD_END);
+ if (ret && (ret != -FDT_ERR_NOTFOUND))
+ goto out;
+ }
+
+ if (image->type == KEXEC_TYPE_CRASH) {
+ /* add linux,elfcorehdr */
+ ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
+ FDT_PROP_KEXEC_ELFHDR,
+ image->elf_load_addr,
+ image->elf_headers_sz);
+ if (ret)
+ goto out;
+
+ /*
+ * Avoid elfcorehdr from being stomped on in kdump kernel by
+ * setting up memory reserve map.
+ */
+ ret = fdt_add_mem_rsv(fdt, image->elf_load_addr,
+ image->elf_headers_sz);
+ if (ret)
+ goto out;
+
+ /* add linux,usable-memory-range */
+ ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
+ FDT_PROP_MEM_RANGE,
+ crashk_res.start,
+ crashk_res.end - crashk_res.start + 1);
+ if (ret)
+ goto out;
+ }
+
+ /* add bootargs */
+ if (cmdline) {
+ ret = fdt_setprop_string(fdt, chosen_node, FDT_PROP_BOOTARGS, cmdline);
+ if (ret)
+ goto out;
+ } else {
+ ret = fdt_delprop(fdt, chosen_node, FDT_PROP_BOOTARGS);
+ if (ret && (ret != -FDT_ERR_NOTFOUND))
+ goto out;
+ }
+
+ /* add kaslr-seed */
+ ret = fdt_delprop(fdt, chosen_node, FDT_PROP_KASLR_SEED);
+ if (ret == -FDT_ERR_NOTFOUND)
+ ret = 0;
+ else if (ret)
+ goto out;
+
+ if (rng_is_initialized()) {
+ u64 seed = get_random_u64();
+
+ ret = fdt_setprop_u64(fdt, chosen_node, FDT_PROP_KASLR_SEED, seed);
+ if (ret)
+ goto out;
+ } else {
+ pr_notice("RNG is not initialised: omitting \"%s\" property\n",
+ FDT_PROP_KASLR_SEED);
+ }
+
+ /* add rng-seed */
+ if (rng_is_initialized()) {
+ void *rng_seed;
+
+ ret = fdt_setprop_placeholder(fdt, chosen_node, FDT_PROP_RNG_SEED,
+ RNG_SEED_SIZE, &rng_seed);
+ if (ret)
+ goto out;
+ get_random_bytes(rng_seed, RNG_SEED_SIZE);
+ } else {
+ pr_notice("RNG is not initialised: omitting \"%s\" property\n",
+ FDT_PROP_RNG_SEED);
+ }
+
+ ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0);
+ if (ret)
+ goto out;
+
+ remove_ima_buffer(fdt, chosen_node);
+ ret = setup_ima_buffer(image, fdt, fdt_path_offset(fdt, "/chosen"));
+
+out:
+ if (ret) {
+ kvfree(fdt);
+ fdt = NULL;
+ }
+
+ return fdt;
+}
diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
index 6e411821583e..dbac3a172a11 100644
--- a/drivers/of/of_net.c
+++ b/drivers/of/of_net.c
@@ -11,6 +11,7 @@
#include <linux/phy.h>
#include <linux/export.h>
#include <linux/device.h>
+#include <linux/nvmem-consumer.h>
/**
* of_get_phy_mode - Get phy mode for given device_node
@@ -45,40 +46,60 @@ int of_get_phy_mode(struct device_node *np, phy_interface_t *interface)
}
EXPORT_SYMBOL_GPL(of_get_phy_mode);
-static const void *of_get_mac_addr(struct device_node *np, const char *name)
+static int of_get_mac_addr(struct device_node *np, const char *name, u8 *addr)
{
struct property *pp = of_find_property(np, name, NULL);
- if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value))
- return pp->value;
- return NULL;
+ if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value)) {
+ memcpy(addr, pp->value, ETH_ALEN);
+ return 0;
+ }
+ return -ENODEV;
}
-static const void *of_get_mac_addr_nvmem(struct device_node *np)
+static int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr)
{
- int ret;
- const void *mac;
- u8 nvmem_mac[ETH_ALEN];
struct platform_device *pdev = of_find_device_by_node(np);
+ struct nvmem_cell *cell;
+ const void *mac;
+ size_t len;
+ int ret;
- if (!pdev)
- return ERR_PTR(-ENODEV);
-
- ret = nvmem_get_mac_address(&pdev->dev, &nvmem_mac);
- if (ret) {
+ /* Try lookup by device first, there might be a nvmem_cell_lookup
+ * associated with a given device.
+ */
+ if (pdev) {
+ ret = nvmem_get_mac_address(&pdev->dev, addr);
put_device(&pdev->dev);
- return ERR_PTR(ret);
+ return ret;
}
- mac = devm_kmemdup(&pdev->dev, nvmem_mac, ETH_ALEN, GFP_KERNEL);
- put_device(&pdev->dev);
- if (!mac)
- return ERR_PTR(-ENOMEM);
+ cell = of_nvmem_cell_get(np, "mac-address");
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ mac = nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
- return mac;
+ if (IS_ERR(mac))
+ return PTR_ERR(mac);
+
+ if (len != ETH_ALEN || !is_valid_ether_addr(mac)) {
+ kfree(mac);
+ return -EINVAL;
+ }
+
+ memcpy(addr, mac, ETH_ALEN);
+ kfree(mac);
+
+ return 0;
}
/**
+ * of_get_mac_address()
+ * @np: Caller's Device Node
+ * @addr: Pointer to a six-byte array for the result
+ *
* Search the device tree for the best MAC address to use. 'mac-address' is
* checked first, because that is supposed to contain to "most recent" MAC
* address. If that isn't set, then 'local-mac-address' is checked next,
@@ -98,24 +119,27 @@ static const void *of_get_mac_addr_nvmem(struct device_node *np)
* this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
* but is all zeros.
*
- * Return: Will be a valid pointer on success and ERR_PTR in case of error.
+ * Return: 0 on success and errno in case of error.
*/
-const void *of_get_mac_address(struct device_node *np)
+int of_get_mac_address(struct device_node *np, u8 *addr)
{
- const void *addr;
+ int ret;
+
+ if (!np)
+ return -ENODEV;
- addr = of_get_mac_addr(np, "mac-address");
- if (addr)
- return addr;
+ ret = of_get_mac_addr(np, "mac-address", addr);
+ if (!ret)
+ return 0;
- addr = of_get_mac_addr(np, "local-mac-address");
- if (addr)
- return addr;
+ ret = of_get_mac_addr(np, "local-mac-address", addr);
+ if (!ret)
+ return 0;
- addr = of_get_mac_addr(np, "address");
- if (addr)
- return addr;
+ ret = of_get_mac_addr(np, "address", addr);
+ if (!ret)
+ return 0;
- return of_get_mac_addr_nvmem(np);
+ return of_get_mac_addr_nvmem(np, addr);
}
EXPORT_SYMBOL(of_get_mac_address);
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index a7fbc5e37e19..15e2417974d6 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -45,7 +45,7 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
return memblock_reserve(base, size);
}
-/**
+/*
* fdt_reserved_mem_save_node() - save fdt node for second pass initialization
*/
void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
@@ -67,7 +67,7 @@ void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
return;
}
-/**
+/*
* __reserved_mem_alloc_size() - allocate reserved memory described by
* 'size', 'alignment' and 'alloc-ranges' properties.
*/
@@ -164,7 +164,7 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
static const struct of_device_id __rmem_of_table_sentinel
__used __section("__reservedmem_of_table_end");
-/**
+/*
* __reserved_mem_init_node() - call region specific reserved memory init code
*/
static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 23effe5e50ec..d80160cf34bb 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -140,7 +140,7 @@ int of_overlay_notifier_register(struct notifier_block *nb)
EXPORT_SYMBOL_GPL(of_overlay_notifier_register);
/**
- * of_overlay_notifier_register() - Unregister notifier for overlay operations
+ * of_overlay_notifier_unregister() - Unregister notifier for overlay operations
* @nb: Notifier block to unregister
*/
int of_overlay_notifier_unregister(struct notifier_block *nb)
@@ -298,7 +298,7 @@ err_free_target_path:
*
* Update of property in symbols node is not allowed.
*
- * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
+ * Return: 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
* invalid @overlay.
*/
static int add_changeset_property(struct overlay_changeset *ovcs,
@@ -403,7 +403,7 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
*
* NOTE_2: Multiple mods of created nodes not supported.
*
- * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
+ * Return: 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
* invalid @overlay.
*/
static int add_changeset_node(struct overlay_changeset *ovcs,
@@ -475,7 +475,7 @@ static int add_changeset_node(struct overlay_changeset *ovcs,
*
* Do not allow symbols node to have any children.
*
- * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
+ * Return: 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
* invalid @overlay_node.
*/
static int build_changeset_next_level(struct overlay_changeset *ovcs,
@@ -606,7 +606,7 @@ static int find_dup_cset_prop(struct overlay_changeset *ovcs,
* the same node or duplicate {add, delete, or update} properties entries
* for the same property.
*
- * Returns 0 on success, or -EINVAL if duplicate changeset entry found.
+ * Return: 0 on success, or -EINVAL if duplicate changeset entry found.
*/
static int changeset_dup_entry_check(struct overlay_changeset *ovcs)
{
@@ -630,7 +630,7 @@ static int changeset_dup_entry_check(struct overlay_changeset *ovcs)
* any portions of the changeset that were successfully created will remain
* in @ovcs->cset.
*
- * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
+ * Return: 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
* invalid overlay in @ovcs->fragments[].
*/
static int build_changeset(struct overlay_changeset *ovcs)
@@ -726,7 +726,7 @@ static struct device_node *find_target(struct device_node *info_node)
* the top level of @tree. The relevant top level nodes are the fragment
* nodes and the __symbols__ node. Any other top level node will be ignored.
*
- * Returns 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error
+ * Return: 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error
* detected in @tree, or -ENOSPC if idr_alloc() error.
*/
static int init_overlay_changeset(struct overlay_changeset *ovcs,
@@ -796,6 +796,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
if (!fragment->target) {
of_node_put(fragment->overlay);
ret = -EINVAL;
+ of_node_put(node);
goto err_free_fragments;
}
@@ -1023,7 +1024,6 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
struct device_node *overlay_root = NULL;
*ovcs_id = 0;
- ret = 0;
if (overlay_fdt_size < sizeof(struct fdt_header) ||
fdt_check_header(overlay_fdt)) {
@@ -1186,7 +1186,7 @@ static int overlay_removal_is_ok(struct overlay_changeset *remove_ovcs)
* If an error is returned by an overlay changeset post-remove notifier
* then no further overlay changeset post-remove notifier will be called.
*
- * Returns 0 on success, or a negative error number. *ovcs_id is set to
+ * Return: 0 on success, or a negative error number. *@ovcs_id is set to
* zero after reverting the changeset, even if a subsequent error occurs.
*/
int of_overlay_remove(int *ovcs_id)
@@ -1194,8 +1194,6 @@ int of_overlay_remove(int *ovcs_id)
struct overlay_changeset *ovcs;
int ret, ret_apply, ret_tmp;
- ret = 0;
-
if (devicetree_corrupt()) {
pr_err("suspect devicetree state, refuse to remove overlay\n");
ret = -EBUSY;
@@ -1264,7 +1262,7 @@ EXPORT_SYMBOL_GPL(of_overlay_remove);
*
* Removes all overlays from the system in the correct order.
*
- * Returns 0 on success, or a negative error number
+ * Return: 0 on success, or a negative error number
*/
int of_overlay_remove_all(void)
{
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 0da86209ddaa..25d448f5af91 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -44,7 +44,7 @@ static const struct of_device_id of_skipped_node_table[] = {
* Takes a reference to the embedded struct device which needs to be dropped
* after use.
*
- * Returns platform_device pointer, or NULL if not found
+ * Return: platform_device pointer, or NULL if not found
*/
struct platform_device *of_find_device_by_node(struct device_node *np)
{
@@ -160,7 +160,7 @@ EXPORT_SYMBOL(of_device_alloc);
* @platform_data: pointer to populate platform_data pointer with
* @parent: Linux device model parent device.
*
- * Returns pointer to created platform device, or NULL if a device was not
+ * Return: Pointer to created platform device, or NULL if a device was not
* registered. Unavailable devices will not get registered.
*/
static struct platform_device *of_platform_device_create_pdata(
@@ -204,7 +204,7 @@ err_clear_flag:
* @bus_id: name to assign device
* @parent: Linux device model parent device.
*
- * Returns pointer to created platform device, or NULL if a device was not
+ * Return: Pointer to created platform device, or NULL if a device was not
* registered. Unavailable devices will not get registered.
*/
struct platform_device *of_platform_device_create(struct device_node *np,
@@ -290,7 +290,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
}
#endif /* CONFIG_ARM_AMBA */
-/**
+/*
* of_dev_lookup() - Given a device node, lookup the preferred Linux name
*/
static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *lookup,
@@ -463,7 +463,7 @@ EXPORT_SYMBOL(of_platform_bus_probe);
* New board support should be using this function instead of
* of_platform_bus_probe().
*
- * Returns 0 on success, < 0 on failure.
+ * Return: 0 on success, < 0 on failure.
*/
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
@@ -607,7 +607,7 @@ static void devm_of_platform_populate_release(struct device *dev, void *res)
* Similar to of_platform_populate(), but will automatically call
* of_platform_depopulate() when the device is unbound from the bus.
*
- * Returns 0 on success, < 0 on failure.
+ * Return: 0 on success, < 0 on failure.
*/
int devm_of_platform_populate(struct device *dev)
{
diff --git a/drivers/of/property.c b/drivers/of/property.c
index 78427c85bef3..6c028632f425 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -61,9 +61,11 @@ EXPORT_SYMBOL(of_graph_is_present);
* @elem_size: size of the individual element
*
* Search for a property in a device node and count the number of elements of
- * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
- * property does not exist or its length does not match a multiple of elem_size
- * and -ENODATA if the property does not have a value.
+ * size elem_size in it.
+ *
+ * Return: The number of elements on sucess, -EINVAL if the property does not
+ * exist or its length does not match a multiple of elem_size and -ENODATA if
+ * the property does not have a value.
*/
int of_property_count_elems_of_size(const struct device_node *np,
const char *propname, int elem_size)
@@ -95,8 +97,9 @@ EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
* @len: if !=NULL, actual length is written to here
*
* Search for a property in a device node and valid the requested size.
- * Returns the property value on success, -EINVAL if the property does not
- * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
+ *
+ * Return: The property value on success, -EINVAL if the property does not
+ * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data is too small or too large.
*
*/
@@ -129,7 +132,9 @@ static void *of_find_property_value_of_size(const struct device_node *np,
* @out_value: pointer to return value, modified only if no error.
*
* Search for a property in a device node and read nth 32-bit value from
- * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * it.
+ *
+ * Return: 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
@@ -161,7 +166,9 @@ EXPORT_SYMBOL_GPL(of_property_read_u32_index);
* @out_value: pointer to return value, modified only if no error.
*
* Search for a property in a device node and read nth 64-bit value from
- * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * it.
+ *
+ * Return: 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
@@ -196,12 +203,14 @@ EXPORT_SYMBOL_GPL(of_property_read_u64_index);
* sz_min will be read.
*
* Search for a property in a device node and read 8-bit value(s) from
- * it. Returns number of elements read on success, -EINVAL if the property
- * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
- * if the property data is smaller than sz_min or longer than sz_max.
+ * it.
*
* dts entry of array should be like:
- * property = /bits/ 8 <0x50 0x60 0x70>;
+ * ``property = /bits/ 8 <0x50 0x60 0x70>;``
+ *
+ * Return: The number of elements read on success, -EINVAL if the property
+ * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
+ * if the property data is smaller than sz_min or longer than sz_max.
*
* The out_values is modified only if a valid u8 value can be decoded.
*/
@@ -244,12 +253,14 @@ EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
* sz_min will be read.
*
* Search for a property in a device node and read 16-bit value(s) from
- * it. Returns number of elements read on success, -EINVAL if the property
- * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
- * if the property data is smaller than sz_min or longer than sz_max.
+ * it.
*
* dts entry of array should be like:
- * property = /bits/ 16 <0x5000 0x6000 0x7000>;
+ * ``property = /bits/ 16 <0x5000 0x6000 0x7000>;``
+ *
+ * Return: The number of elements read on success, -EINVAL if the property
+ * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
+ * if the property data is smaller than sz_min or longer than sz_max.
*
* The out_values is modified only if a valid u16 value can be decoded.
*/
@@ -292,7 +303,9 @@ EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
* sz_min will be read.
*
* Search for a property in a device node and read 32-bit value(s) from
- * it. Returns number of elements read on success, -EINVAL if the property
+ * it.
+ *
+ * Return: The number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
@@ -331,7 +344,9 @@ EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array);
* @out_value: pointer to return value, modified only if return value is 0.
*
* Search for a property in a device node and read a 64-bit value from
- * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * it.
+ *
+ * Return: 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
@@ -366,7 +381,9 @@ EXPORT_SYMBOL_GPL(of_property_read_u64);
* sz_min will be read.
*
* Search for a property in a device node and read 64-bit value(s) from
- * it. Returns number of elements read on success, -EINVAL if the property
+ * it.
+ *
+ * Return: The number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
@@ -408,10 +425,11 @@ EXPORT_SYMBOL_GPL(of_property_read_variable_u64_array);
* return value is 0.
*
* Search for a property in a device tree node and retrieve a null
- * terminated string value (pointer to data, not a copy). Returns 0 on
- * success, -EINVAL if the property does not exist, -ENODATA if property
- * does not have a value, and -EILSEQ if the string is not null-terminated
- * within the length of the property data.
+ * terminated string value (pointer to data, not a copy).
+ *
+ * Return: 0 on success, -EINVAL if the property does not exist, -ENODATA if
+ * property does not have a value, and -EILSEQ if the string is not
+ * null-terminated within the length of the property data.
*
* The out_string pointer is modified only if a valid string can be decoded.
*/
@@ -775,7 +793,7 @@ EXPORT_SYMBOL(of_graph_get_remote_port_parent);
* @node: pointer to a local endpoint device_node
*
* Return: Remote port node associated with remote endpoint node linked
- * to @node. Use of_node_put() on it when done.
+ * to @node. Use of_node_put() on it when done.
*/
struct device_node *of_graph_get_remote_port(const struct device_node *node)
{
@@ -808,7 +826,7 @@ EXPORT_SYMBOL(of_graph_get_endpoint_count);
* @endpoint: identifier (value of reg property) of the endpoint node
*
* Return: Remote device node associated with remote endpoint node linked
- * to @node. Use of_node_put() on it when done.
+ * to @node. Use of_node_put() on it when done.
*/
struct device_node *of_graph_get_remote_node(const struct device_node *node,
u32 port, u32 endpoint)
@@ -1038,6 +1056,25 @@ static bool of_is_ancestor_of(struct device_node *test_ancestor,
return false;
}
+static struct device_node *of_get_compat_node(struct device_node *np)
+{
+ of_node_get(np);
+
+ while (np) {
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ np = NULL;
+ }
+
+ if (of_find_property(np, "compatible", NULL))
+ break;
+
+ np = of_get_next_parent(np);
+ }
+
+ return np;
+}
+
/**
* of_link_to_phandle - Add fwnode link to supplier from supplier phandle
* @con_np: consumer device tree node
@@ -1061,25 +1098,11 @@ static int of_link_to_phandle(struct device_node *con_np,
struct device *sup_dev;
struct device_node *tmp_np = sup_np;
- of_node_get(sup_np);
/*
* Find the device node that contains the supplier phandle. It may be
* @sup_np or it may be an ancestor of @sup_np.
*/
- while (sup_np) {
-
- /* Don't allow linking to a disabled supplier */
- if (!of_device_is_available(sup_np)) {
- of_node_put(sup_np);
- sup_np = NULL;
- }
-
- if (of_find_property(sup_np, "compatible", NULL))
- break;
-
- sup_np = of_get_next_parent(sup_np);
- }
-
+ sup_np = of_get_compat_node(sup_np);
if (!sup_np) {
pr_debug("Not linking %pOFP to %pOFP - No device\n",
con_np, tmp_np);
@@ -1225,6 +1248,8 @@ static struct device_node *parse_##fname(struct device_node *np, \
* @parse_prop.prop_name: Name of property holding a phandle value
* @parse_prop.index: For properties holding a list of phandles, this is the
* index into the list
+ * @optional: Describes whether a supplier is mandatory or not
+ * @node_not_dev: The consumer node containing the property is never a device.
*
* Returns:
* parse_prop() return values are
@@ -1236,6 +1261,7 @@ struct supplier_bindings {
struct device_node *(*parse_prop)(struct device_node *np,
const char *prop_name, int index);
bool optional;
+ bool node_not_dev;
};
DEFINE_SIMPLE_PROP(clocks, "clocks", "#clock-cells")
@@ -1260,6 +1286,7 @@ DEFINE_SIMPLE_PROP(pinctrl5, "pinctrl-5", NULL)
DEFINE_SIMPLE_PROP(pinctrl6, "pinctrl-6", NULL)
DEFINE_SIMPLE_PROP(pinctrl7, "pinctrl-7", NULL)
DEFINE_SIMPLE_PROP(pinctrl8, "pinctrl-8", NULL)
+DEFINE_SIMPLE_PROP(remote_endpoint, "remote-endpoint", NULL)
DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells")
@@ -1343,6 +1370,7 @@ static const struct supplier_bindings of_supplier_bindings[] = {
{ .parse_prop = parse_pinctrl6, },
{ .parse_prop = parse_pinctrl7, },
{ .parse_prop = parse_pinctrl8, },
+ { .parse_prop = parse_remote_endpoint, .node_not_dev = true, },
{ .parse_prop = parse_gpio_compat, },
{ .parse_prop = parse_interrupts, },
{ .parse_prop = parse_regulators, },
@@ -1353,7 +1381,6 @@ static const struct supplier_bindings of_supplier_bindings[] = {
/**
* of_link_property - Create device links to suppliers listed in a property
- * @dev: Consumer device
* @con_np: The consumer device tree node which contains the property
* @prop_name: Name of property to be parsed
*
@@ -1377,7 +1404,6 @@ static int of_link_property(struct device_node *con_np, const char *prop_name)
const struct supplier_bindings *s = of_supplier_bindings;
unsigned int i = 0;
bool matched = false;
- int ret = 0;
/* Do not stop at first failed link, link all available suppliers. */
while (!matched && s->parse_prop) {
@@ -1387,14 +1413,20 @@ static int of_link_property(struct device_node *con_np, const char *prop_name)
}
while ((phandle = s->parse_prop(con_np, prop_name, i))) {
+ struct device_node *con_dev_np;
+
+ con_dev_np = s->node_not_dev
+ ? of_get_compat_node(con_np)
+ : of_node_get(con_np);
matched = true;
i++;
- of_link_to_phandle(con_np, phandle);
+ of_link_to_phandle(con_dev_np, phandle);
of_node_put(phandle);
+ of_node_put(con_dev_np);
}
s++;
}
- return ret;
+ return 0;
}
static int of_fwnode_add_links(struct fwnode_handle *fwnode)
diff --git a/drivers/of/unittest-data/Makefile b/drivers/of/unittest-data/Makefile
index 009f4045c8e4..a5d2d9254b2c 100644
--- a/drivers/of/unittest-data/Makefile
+++ b/drivers/of/unittest-data/Makefile
@@ -38,3 +38,51 @@ DTC_FLAGS_testcases += -@
# suppress warnings about intentional errors
DTC_FLAGS_testcases += -Wno-interrupts_property
+
+# Apply overlays statically with fdtoverlay. This is a build time test that
+# the overlays can be applied successfully by fdtoverlay. This does not
+# guarantee that the overlays can be applied successfully at run time by
+# unittest, but it provides a bit of build time test coverage for those
+# who do not execute unittest.
+#
+# The overlays are applied on top of static_base_1.dtb and static_base_2.dtb to
+# create static_test_1.dtb and static_test_2.dtb. If fdtoverlay detects an
+# error than the kernel build will fail. static_test_1.dtb and
+# static_test_2.dtb are not consumed by unittest.
+#
+# Some unittest overlays deliberately contain errors that unittest checks for.
+# These overlays will cause fdtoverlay to fail, and are thus not included
+# in the static test:
+# overlay_bad_add_dup_node.dtbo \
+# overlay_bad_add_dup_prop.dtbo \
+# overlay_bad_phandle.dtbo \
+# overlay_bad_symbol.dtbo \
+
+apply_static_overlay_1 := overlay_0.dtbo \
+ overlay_1.dtbo \
+ overlay_2.dtbo \
+ overlay_3.dtbo \
+ overlay_4.dtbo \
+ overlay_5.dtbo \
+ overlay_6.dtbo \
+ overlay_7.dtbo \
+ overlay_8.dtbo \
+ overlay_9.dtbo \
+ overlay_10.dtbo \
+ overlay_11.dtbo \
+ overlay_12.dtbo \
+ overlay_13.dtbo \
+ overlay_15.dtbo \
+ overlay_gpio_01.dtbo \
+ overlay_gpio_02a.dtbo \
+ overlay_gpio_02b.dtbo \
+ overlay_gpio_03.dtbo \
+ overlay_gpio_04a.dtbo \
+ overlay_gpio_04b.dtbo
+
+apply_static_overlay_2 := overlay.dtbo
+
+static_test_1-dtbs := static_base_1.dtb $(apply_static_overlay_1)
+static_test_2-dtbs := static_base_2.dtb $(apply_static_overlay_2)
+
+dtb-$(CONFIG_OF_OVERLAY) += static_test_1.dtb static_test_2.dtb
diff --git a/drivers/of/unittest-data/overlay_base.dts b/drivers/of/unittest-data/overlay_base.dts
index 99ab9d12d00b..ab9014589c5d 100644
--- a/drivers/of/unittest-data/overlay_base.dts
+++ b/drivers/of/unittest-data/overlay_base.dts
@@ -2,92 +2,4 @@
/dts-v1/;
/plugin/;
-/*
- * Base device tree that overlays will be applied against.
- *
- * Do not add any properties in node "/".
- * Do not add any nodes other than "/testcase-data-2" in node "/".
- * Do not add anything that would result in dtc creating node "/__fixups__".
- * dtc will create nodes "/__symbols__" and "/__local_fixups__".
- */
-
-/ {
- testcase-data-2 {
- #address-cells = <1>;
- #size-cells = <1>;
-
- electric_1: substation@100 {
- compatible = "ot,big-volts-control";
- reg = < 0x00000100 0x100 >;
- status = "disabled";
-
- hvac_1: hvac-medium-1 {
- compatible = "ot,hvac-medium";
- heat-range = < 50 75 >;
- cool-range = < 60 80 >;
- };
-
- spin_ctrl_1: motor-1 {
- compatible = "ot,ferris-wheel-motor";
- spin = "clockwise";
- rpm_avail = < 50 >;
- };
-
- spin_ctrl_2: motor-8 {
- compatible = "ot,roller-coaster-motor";
- };
- };
-
- rides_1: fairway-1 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "ot,rides";
- status = "disabled";
- orientation = < 127 >;
-
- ride@100 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "ot,roller-coaster";
- reg = < 0x00000100 0x100 >;
- hvac-provider = < &hvac_1 >;
- hvac-thermostat = < 29 > ;
- hvac-zones = < 14 >;
- hvac-zone-names = "operator";
- spin-controller = < &spin_ctrl_2 5 &spin_ctrl_2 7 >;
- spin-controller-names = "track_1", "track_2";
- queues = < 2 >;
-
- track@30 {
- reg = < 0x00000030 0x10 >;
- };
-
- track@40 {
- reg = < 0x00000040 0x10 >;
- };
-
- };
- };
-
- lights_1: lights@30000 {
- compatible = "ot,work-lights";
- reg = < 0x00030000 0x1000 >;
- status = "disabled";
- };
-
- lights_2: lights@40000 {
- compatible = "ot,show-lights";
- reg = < 0x00040000 0x1000 >;
- status = "disabled";
- rate = < 13 138 >;
- };
-
- retail_1: vending@50000 {
- reg = < 0x00050000 0x1000 >;
- compatible = "ot,tickets";
- status = "disabled";
- };
-
- };
-};
-
+#include "overlay_common.dtsi"
diff --git a/drivers/of/unittest-data/overlay_common.dtsi b/drivers/of/unittest-data/overlay_common.dtsi
new file mode 100644
index 000000000000..08874a72556e
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_common.dtsi
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Base device tree that overlays will be applied against.
+ *
+ * Do not add any properties in node "/".
+ * Do not add any nodes other than "/testcase-data-2" in node "/".
+ * Do not add anything that would result in dtc creating node "/__fixups__".
+ * dtc will create nodes "/__symbols__" and "/__local_fixups__".
+ */
+
+/ {
+ testcase-data-2 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ electric_1: substation@100 {
+ compatible = "ot,big-volts-control";
+ reg = < 0x00000100 0x100 >;
+ status = "disabled";
+
+ hvac_1: hvac-medium-1 {
+ compatible = "ot,hvac-medium";
+ heat-range = < 50 75 >;
+ cool-range = < 60 80 >;
+ };
+
+ spin_ctrl_1: motor-1 {
+ compatible = "ot,ferris-wheel-motor";
+ spin = "clockwise";
+ rpm_avail = < 50 >;
+ };
+
+ spin_ctrl_2: motor-8 {
+ compatible = "ot,roller-coaster-motor";
+ };
+ };
+
+ rides_1: fairway-1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "ot,rides";
+ status = "disabled";
+ orientation = < 127 >;
+
+ ride@100 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "ot,roller-coaster";
+ reg = < 0x00000100 0x100 >;
+ hvac-provider = < &hvac_1 >;
+ hvac-thermostat = < 29 > ;
+ hvac-zones = < 14 >;
+ hvac-zone-names = "operator";
+ spin-controller = < &spin_ctrl_2 5 &spin_ctrl_2 7 >;
+ spin-controller-names = "track_1", "track_2";
+ queues = < 2 >;
+
+ track@30 {
+ reg = < 0x00000030 0x10 >;
+ };
+
+ track@40 {
+ reg = < 0x00000040 0x10 >;
+ };
+
+ };
+ };
+
+ lights_1: lights@30000 {
+ compatible = "ot,work-lights";
+ reg = < 0x00030000 0x1000 >;
+ status = "disabled";
+ };
+
+ lights_2: lights@40000 {
+ compatible = "ot,show-lights";
+ reg = < 0x00040000 0x1000 >;
+ status = "disabled";
+ rate = < 13 138 >;
+ };
+
+ retail_1: vending@50000 {
+ reg = < 0x00050000 0x1000 >;
+ compatible = "ot,tickets";
+ status = "disabled";
+ };
+
+ };
+};
+
diff --git a/drivers/of/unittest-data/static_base_1.dts b/drivers/of/unittest-data/static_base_1.dts
new file mode 100644
index 000000000000..10556cb3f01f
--- /dev/null
+++ b/drivers/of/unittest-data/static_base_1.dts
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+#include "testcases_common.dtsi"
diff --git a/drivers/of/unittest-data/static_base_2.dts b/drivers/of/unittest-data/static_base_2.dts
new file mode 100644
index 000000000000..b0ea9504d6f3
--- /dev/null
+++ b/drivers/of/unittest-data/static_base_2.dts
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+#include "overlay_common.dtsi"
diff --git a/drivers/of/unittest-data/testcases.dts b/drivers/of/unittest-data/testcases.dts
index a85b5e1c381a..61cdd3d5fccb 100644
--- a/drivers/of/unittest-data/testcases.dts
+++ b/drivers/of/unittest-data/testcases.dts
@@ -2,19 +2,20 @@
/dts-v1/;
/plugin/;
+#include "testcases_common.dtsi"
+
/ {
+ /*
+ * testcase data that intentionally results in an error is located here
+ * instead of in testcases_common.dtsi so that the static overlay apply
+ * tests will not include the error.
+ */
testcase-data {
- changeset {
- prop-update = "hello";
- prop-remove = "world";
- node-remove {
- };
+ testcase-device2 {
+ compatible = "testcase-device";
+ interrupt-parent = <&test_intc2>;
+ interrupts = <1>; /* invalid specifier - too short */
};
};
+
};
-#include "tests-phandle.dtsi"
-#include "tests-interrupts.dtsi"
-#include "tests-match.dtsi"
-#include "tests-address.dtsi"
-#include "tests-platform.dtsi"
-#include "tests-overlay.dtsi"
diff --git a/drivers/of/unittest-data/testcases_common.dtsi b/drivers/of/unittest-data/testcases_common.dtsi
new file mode 100644
index 000000000000..19292bbb4cbb
--- /dev/null
+++ b/drivers/of/unittest-data/testcases_common.dtsi
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+ testcase-data {
+ changeset {
+ prop-update = "hello";
+ prop-remove = "world";
+ node-remove {
+ };
+ };
+ };
+};
+
+#include "tests-phandle.dtsi"
+#include "tests-interrupts.dtsi"
+#include "tests-match.dtsi"
+#include "tests-address.dtsi"
+#include "tests-platform.dtsi"
+#include "tests-overlay.dtsi"
diff --git a/drivers/of/unittest-data/tests-interrupts.dtsi b/drivers/of/unittest-data/tests-interrupts.dtsi
index ec175e800725..9b60a549f502 100644
--- a/drivers/of/unittest-data/tests-interrupts.dtsi
+++ b/drivers/of/unittest-data/tests-interrupts.dtsi
@@ -62,11 +62,10 @@
interrupts = <1>;
};
- testcase-device2 {
- compatible = "testcase-device";
- interrupt-parent = <&test_intc2>;
- interrupts = <1>; /* invalid specifier - too short */
- };
+ /*
+ * testcase data that intentionally results in an error is
+ * located in testcases.dts instead of in this file so that the
+ * static overlay apply tests will not include the error.
+ */
};
-
};