f07e572f64
bcm2708: boot tested on RPi B+ v1.2 bcm2709: boot tested on RPi 3B v1.2 and RPi 4B v1.1 4G bcm2710: boot tested on RPi 3B v1.2 bcm2711: boot tested on RPi 4B v1.1 4G Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
108 lines
3.2 KiB
Diff
108 lines
3.2 KiB
Diff
From 7631cb95056f03136c9e0a35484e8bebe7b52650 Mon Sep 17 00:00:00 2001
|
|
From: Robin Murphy <robin.murphy@arm.com>
|
|
Date: Wed, 3 Jul 2019 18:42:20 +0100
|
|
Subject: [PATCH] of: Make of_dma_get_range() work on bus nodes
|
|
|
|
commit 951d48855d86e72e0d6de73440fe09d363168064 upstream.
|
|
|
|
Since the "dma-ranges" property is only valid for a node representing a
|
|
bus, of_dma_get_range() currently assumes the node passed in is a leaf
|
|
representing a device, and starts the walk from its parent. In cases
|
|
like PCI host controllers on typical FDT systems, however, where the PCI
|
|
endpoints are probed dynamically the initial leaf node represents the
|
|
'bus' itself, and this logic means we fail to consider any "dma-ranges"
|
|
describing the host bridge itself. Rework the logic such that
|
|
of_dma_get_range() also works correctly starting from a bus node
|
|
containing "dma-ranges".
|
|
|
|
While this does mean "dma-ranges" could incorrectly be in a device leaf
|
|
node, there isn't really any way in this function to ensure that a leaf
|
|
node is or isn't a bus node.
|
|
|
|
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
|
|
[robh: Allow for the bus child node to still be passed in]
|
|
Signed-off-by: Rob Herring <robh@kernel.org>
|
|
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
|
|
Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
|
|
Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
|
|
---
|
|
drivers/of/address.c | 44 ++++++++++++++++++--------------------------
|
|
1 file changed, 18 insertions(+), 26 deletions(-)
|
|
|
|
--- a/drivers/of/address.c
|
|
+++ b/drivers/of/address.c
|
|
@@ -940,47 +940,39 @@ int of_dma_get_range(struct device_node
|
|
const __be32 *ranges = NULL;
|
|
int len, naddr, nsize, pna;
|
|
int ret = 0;
|
|
+ bool found_dma_ranges = false;
|
|
u64 dmaaddr;
|
|
|
|
- if (!node)
|
|
- return -EINVAL;
|
|
-
|
|
- while (1) {
|
|
- struct device_node *parent;
|
|
-
|
|
- naddr = of_n_addr_cells(node);
|
|
- nsize = of_n_size_cells(node);
|
|
-
|
|
- parent = __of_get_dma_parent(node);
|
|
- of_node_put(node);
|
|
-
|
|
- node = parent;
|
|
- if (!node)
|
|
- break;
|
|
-
|
|
+ while (node) {
|
|
ranges = of_get_property(node, "dma-ranges", &len);
|
|
|
|
/* Ignore empty ranges, they imply no translation required */
|
|
if (ranges && len > 0)
|
|
break;
|
|
|
|
- /*
|
|
- * At least empty ranges has to be defined for parent node if
|
|
- * DMA is supported
|
|
- */
|
|
- if (!ranges)
|
|
- break;
|
|
+ /* Once we find 'dma-ranges', then a missing one is an error */
|
|
+ if (found_dma_ranges && !ranges) {
|
|
+ ret = -ENODEV;
|
|
+ goto out;
|
|
+ }
|
|
+ found_dma_ranges = true;
|
|
+
|
|
+ node = of_get_next_dma_parent(node);
|
|
}
|
|
|
|
- if (!ranges) {
|
|
+ if (!node || !ranges) {
|
|
pr_debug("no dma-ranges found for node(%pOF)\n", np);
|
|
ret = -ENODEV;
|
|
goto out;
|
|
}
|
|
|
|
- len /= sizeof(u32);
|
|
-
|
|
+ naddr = of_bus_n_addr_cells(node);
|
|
+ nsize = of_bus_n_size_cells(node);
|
|
pna = of_n_addr_cells(node);
|
|
+ if ((len / sizeof(__be32)) % (pna + naddr + nsize)) {
|
|
+ ret = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
|
|
/* dma-ranges format:
|
|
* DMA addr : naddr cells
|
|
@@ -988,7 +980,7 @@ int of_dma_get_range(struct device_node
|
|
* size : nsize cells
|
|
*/
|
|
dmaaddr = of_read_number(ranges, naddr);
|
|
- *paddr = of_translate_dma_address(np, ranges);
|
|
+ *paddr = of_translate_dma_address(node, ranges + naddr);
|
|
if (*paddr == OF_BAD_ADDR) {
|
|
pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n",
|
|
dma_addr, np);
|