On 10/12/2020 10:42, Nicolas Saenz Julienne wrote:
> Add the following functions to get a specific device's DMA ranges:
>  - dev_get_dma_range()
>  - ofnode_get_dma_range()
>  - of_get_dma_range()
>  - fdt_get_dma_range()
> They are specially useful in oder to be able validate a physical address
> space range into a bus's and to convert addresses from and to address
> spaces.
> 
> Signed-off-by: Nicolas Saenz Julienne <nsaenzjulie...@suse.de>
> 
> ---
> Changes since v1:
>  - Fix wrong arguments in of_get_dma_range()'s call to 
> of_translate_dma_address()
>  - Fix build in SPL/TPL and no LIBFDT supprt
>  - Add missing declaration in 'core/read.c'
>  - Address Matthias' comments
> 
>  common/fdt_support.c   | 73 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/core/of_addr.c | 71 ++++++++++++++++++++++++++++++++++++++++
>  drivers/core/ofnode.c  |  9 ++++++
>  drivers/core/read.c    |  9 ++++++
>  include/dm/of_addr.h   | 17 ++++++++++
>  include/dm/ofnode.h    | 16 +++++++++
>  include/dm/read.h      | 21 ++++++++++++
>  include/fdt_support.h  | 14 ++++++++
>  8 files changed, 230 insertions(+)
> 
> diff --git a/common/fdt_support.c b/common/fdt_support.c
> index 5ae75df3c6..4bcd6720d2 100644
> --- a/common/fdt_support.c
> +++ b/common/fdt_support.c
> @@ -1342,6 +1342,79 @@ u64 fdt_translate_dma_address(const void *blob, int 
> node_offset,
>       return __of_translate_address(blob, node_offset, in_addr, "dma-ranges");
>  }
>  
> +int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu,
> +                   dma_addr_t *bus, u64 *size)
> +{
> +     bool found_dma_ranges = false;
> +     struct of_bus *bus_node;
> +     const fdt32_t *ranges;
> +     int na, ns, pna, pns;
> +     int parent = node;
> +     int ret = 0;
> +     int len;
> +
> +     /* Find the closest dma-ranges property */
> +     while (parent >= 0) {
> +             ranges = fdt_getprop(blob, parent, "dma-ranges", &len);
> +
> +             /* Ignore empty ranges, they imply no translation required */
> +             if (ranges && len > 0)
> +                     break;
> +
> +             /* Once we find 'dma-ranges', then a missing one is an error */
> +             if (found_dma_ranges && !ranges) {
> +                     ret = -ENODEV;
> +                     goto out;
> +             }
> +
> +             if (ranges)
> +                     found_dma_ranges = true;
> +
> +             parent = fdt_parent_offset(blob, parent);
> +     }
> +
> +     if (!ranges || parent < 0) {
> +             debug("no dma-ranges found for node %s\n",
> +                   fdt_get_name(blob, node, NULL));
> +             ret = -ENODEV;
> +             goto out;
> +     }
> +
> +     /* switch to that node */
> +     node = parent;
> +     parent = fdt_parent_offset(blob, node);
> +     if (parent < 0) {
> +             printf("Found dma-ranges in root node, shoudln't happen\n");
> +             ret = -EINVAL;
> +             goto out;
> +     }
> +
> +     /* Get the address sizes both for the bus and its parent */
> +     bus_node = of_match_bus(blob, node);
> +     bus_node->count_cells(blob, node, &na, &ns);
> +     if (!OF_CHECK_COUNTS(na, ns)) {
> +             printf("%s: Bad cell count for %s\n", __FUNCTION__,
> +                    fdt_get_name(blob, node, NULL));
> +             return -EINVAL;
> +             goto out;
> +     }
> +
> +     bus_node = of_match_bus(blob, parent);
> +     bus_node->count_cells(blob, parent, &pna, &pns);
> +     if (!OF_CHECK_COUNTS(pna, pns)) {
> +             printf("%s: Bad cell count for %s\n", __FUNCTION__,
> +                    fdt_get_name(blob, parent, NULL));
> +             return -EINVAL;
> +             goto out;
> +     }
> +
> +     *bus = fdt_read_number(ranges, na);
> +     *cpu = fdt_translate_dma_address(blob, node, ranges + na);
> +     *size = fdt_read_number(ranges + na + pna, ns);
> +out:
> +     return ret;
> +}
> +
>  /**
>   * fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
>   * who's reg property matches a physical cpu address
> diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c
> index ca34d84922..b1d6165b0a 100644
> --- a/drivers/core/of_addr.c
> +++ b/drivers/core/of_addr.c
> @@ -325,6 +325,77 @@ u64 of_translate_dma_address(const struct device_node 
> *dev, const __be32 *in_add
>       return __of_translate_address(dev, in_addr, "dma-ranges");
>  }
>  
> +int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
> +                  dma_addr_t *bus, u64 *size)
> +{
> +     bool found_dma_ranges = false;
> +     struct device_node *parent;
> +     struct of_bus *bus_node;
> +     int na, ns, pna, pns;
> +     const __be32 *ranges;
> +     int ret = 0;
> +     int len;
> +
> +     /* Find the closest dma-ranges property */
> +     while (dev) {
> +             ranges = of_get_property(dev, "dma-ranges", &len);
> +
> +             /* Ignore empty ranges, they imply no translation required */
> +             if (ranges && len > 0)
> +                     break;
> +
> +             /* Once we find 'dma-ranges', then a missing one is an error */
> +             if (found_dma_ranges && !ranges) {
> +                     ret = -ENODEV;
> +                     goto out;
> +             }
> +
> +             if (ranges)
> +                     found_dma_ranges = true;
> +
> +             dev = of_get_parent(dev);
> +     }
> +
> +     if (!dev || !ranges) {
> +             debug("no dma-ranges found for node %s\n",
> +                   of_node_full_name(dev));
> +             ret = -ENODEV;
> +             goto out;
> +     }
> +
> +     /* switch to that node */
> +     parent = of_get_parent(dev);
> +     if (!parent) {
> +             printf("Found dma-ranges in root node, shoudln't happen\n");
> +             ret = -EINVAL;
> +             goto out;
> +     }
> +

Although the function is a dummy, we should put of_node_put() here, to be in
sync with the rest of the code.

Regards,
Matthias

Reply via email to