diff options
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/address.c | 44 |
1 files changed, 18 insertions, 26 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c index 5ce69d026584..99c1b8058559 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -930,47 +930,39 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz 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 @@ -978,7 +970,7 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz * 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(%llx) to CPU address failed node(%pOF)\n", dmaaddr, np); |