[PATCH 4/8] dm: Introduce xxx_get_dma_range()

Peter Robinson pbrobinson at gmail.com
Thu Dec 10 18:03:09 CET 2020


Hi Nicolas,


On Thu, Nov 19, 2020 at 5:50 PM Nicolas Saenz Julienne
<nsaenzjulienne at suse.de> wrote:
>
> Add the follwing 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.

I'm seeing issues with this patch, with the just posted v2 as well
(it's not arrived in my inbox as yet). I get the following linking
error when building across a number of devices such as Jetson boards
like jetson-tk1, p3450-0000, as well as puma-rk3399, marsboard, udoo,
udoo_neo. The error is:

  /usr/bin/arm-linux-gnu-ld.bfd  -pie --gc-sections -Bstatic
--no-dynamic-linker -Ttext 0x87800000 -o u-boot -T u-boot.lds
arch/arm/cpu/armv7/start.o --start-group  arch/arm/cpu/built-in.o
arch/arm/cpu/armv7/built-in.o  arch/arm/lib/built-in.o
arch/arm/mach-imx/built-in.o  board/udoo/neo/built-in.o
cmd/built-in.o  common/built-in.o  disk/built-in.o  drivers/built-in.o
 drivers/dma/built-in.o  drivers/gpio/built-in.o
drivers/i2c/built-in.o  drivers/net/built-in.o
drivers/net/phy/built-in.o  drivers/power/built-in.o
drivers/power/battery/built-in.o  drivers/power/domain/built-in.o
drivers/power/fuel_gauge/built-in.o  drivers/power/mfd/built-in.o
drivers/power/pmic/built-in.o  drivers/power/regulator/built-in.o
drivers/serial/built-in.o  drivers/spi/built-in.o
drivers/usb/cdns3/built-in.o  drivers/usb/common/built-in.o
drivers/usb/dwc3/built-in.o  drivers/usb/emul/built-in.o
drivers/usb/eth/built-in.o  drivers/usb/host/built-in.o
drivers/usb/mtu3/built-in.o  drivers/usb/musb-new/built-in.o
drivers/usb/musb/built-in.o  drivers/usb/phy/built-in.o
drivers/usb/ulpi/built-in.o  env/built-in.o  fs/built-in.o
lib/built-in.o  net/built-in.o --end-group arch/arm/lib/eabi_compat.o
arch/arm/lib/lib.a -Map u-boot.map;  true
/usr/bin/arm-linux-gnu-ld.bfd: drivers/built-in.o: in function
`dev_get_dma_range':
/home/perobins/fedora/packages/uboot-tools/u-boot-2021.01-rc3/include/dm/read.h:1025:
undefined reference to `ofnode_get_dma_range'
make[1]: *** [/home/perobins/fedora/packages/uboot-tools/u-boot-2021.01-rc3/Makefile:1757:
u-boot] Error 1
make[1]: Leaving directory
'/home/perobins/fedora/packages/uboot-tools/u-boot-2021.01-rc3/builds/udoo_neo'

Peter

> Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne at suse.de>
> ---
>  common/fdt_support.c   | 72 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/core/of_addr.c | 68 +++++++++++++++++++++++++++++++++++++++
>  drivers/core/ofnode.c  |  9 ++++++
>  drivers/core/read.c    |  5 +++
>  include/dm/of_addr.h   | 17 ++++++++++
>  include/dm/ofnode.h    | 16 ++++++++++
>  include/dm/read.h      |  6 ++++
>  include/fdt_support.h  | 14 ++++++++
>  8 files changed, 207 insertions(+)
>
> diff --git a/common/fdt_support.c b/common/fdt_support.c
> index 5ae75df3c6..78dc7906bd 100644
> --- a/common/fdt_support.c
> +++ b/common/fdt_support.c
> @@ -1342,6 +1342,78 @@ 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;
> +       const fdt32_t *ranges;
> +       int na, ns, pna, pns;
> +       int parent = node;
> +       u64 cpu_addr;
> +       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 */
> +       of_match_bus(blob, 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;
> +       }
> +
> +       of_match_bus(blob, parent)->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_addr = fdt_read_number(ranges + na, pna);
> +       *cpu = fdt_translate_dma_address(blob, node, (const fdt32_t*)&cpu_addr);
> +       *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..8457e04a25 100644
> --- a/drivers/core/of_addr.c
> +++ b/drivers/core/of_addr.c
> @@ -325,6 +325,74 @@ 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;
> +       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;
> +       }
> +
> +       /* Get the address sizes both for the bus and its parent */
> +       of_match_bus(dev)->count_cells(dev, &na, &ns);
> +       if (!OF_CHECK_COUNTS(na, ns)) {
> +               printf("Bad cell count for %s\n", of_node_full_name(dev));
> +               return -EINVAL;
> +               goto out;
> +       }
> +
> +       of_match_bus(parent)->count_cells(parent, &pna, &pns);
> +       if (!OF_CHECK_COUNTS(pna, pns)) {
> +               printf("Bad cell count for %s\n", of_node_full_name(parent));
> +               return -EINVAL;
> +               goto out;
> +       }
> +
> +       *bus = of_read_number(ranges, na);
> +       *cpu = of_translate_dma_address(dev, of_read_number(ranges + na, pna));
> +       *size = of_read_number(ranges + na + pna, ns);
> +out:
> +       return ret;
> +}
> +
> +
>  static int __of_address_to_resource(const struct device_node *dev,
>                 const __be32 *addrp, u64 size, unsigned int flags,
>                 const char *name, struct resource *r)
> diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
> index a68076bf35..15470d4875 100644
> --- a/drivers/core/ofnode.c
> +++ b/drivers/core/ofnode.c
> @@ -911,6 +911,15 @@ u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
>                 return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
>  }
>
> +int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
> +{
> +       if (ofnode_is_np(node))
> +               return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
> +       else
> +               return fdt_get_dma_range(gd->fdt_blob, ofnode_to_offset(node),
> +                                        cpu, bus, size);
> +}
> +
>  int ofnode_device_is_compatible(ofnode node, const char *compat)
>  {
>         if (ofnode_is_np(node))
> diff --git a/drivers/core/read.c b/drivers/core/read.c
> index 076125824c..b835e82be9 100644
> --- a/drivers/core/read.c
> +++ b/drivers/core/read.c
> @@ -338,6 +338,11 @@ u64 dev_translate_dma_address(const struct udevice *dev, const fdt32_t *in_addr)
>         return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
>  }
>
> +u64 dev_translate_cpu_address(const struct udevice *dev, const fdt32_t *in_addr)
> +{
> +       return ofnode_translate_cpu_address(dev_ofnode(dev), in_addr);
> +}
> +
>  int dev_read_alias_highest_id(const char *stem)
>  {
>         if (of_live_active())
> diff --git a/include/dm/of_addr.h b/include/dm/of_addr.h
> index 3fa1ffce81..ee21d5cf4f 100644
> --- a/include/dm/of_addr.h
> +++ b/include/dm/of_addr.h
> @@ -44,6 +44,23 @@ u64 of_translate_address(const struct device_node *no, const __be32 *in_addr);
>   */
>  u64 of_translate_dma_address(const struct device_node *no, const __be32 *in_addr);
>
> +
> +/**
> + * of_get_dma_range() - get dma-ranges for a specific DT node
> + *
> + * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
> + * cpu->bus address translations
> + *
> + * @param blob         Pointer to device tree blob
> + * @param node_offset  Node DT offset
> + * @param cpu          Pointer to variable storing the range's cpu address
> + * @param bus          Pointer to variable storing the range's bus address
> + * @param size         Pointer to variable storing the range's size
> + * @return translated DMA address or OF_BAD_ADDR on error
> + */
> +int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
> +                    dma_addr_t *bus, u64 *size);
> +
>  /**
>   * of_get_address() - obtain an address from a node
>   *
> diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
> index ced7f6ffb2..dc3dd84d9f 100644
> --- a/include/dm/ofnode.h
> +++ b/include/dm/ofnode.h
> @@ -939,6 +939,22 @@ u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr);
>   */
>  u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr);
>
> +/**
> + * ofnode_get_dma_range() - get dma-ranges for a specific DT node
> + *
> + * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
> + * cpu->bus address translations
> + *
> + * @param blob         Pointer to device tree blob
> + * @param node_offset  Node DT offset
> + * @param cpu          Pointer to variable storing the range's cpu address
> + * @param bus          Pointer to variable storing the range's bus address
> + * @param size         Pointer to variable storing the range's size
> + * @return translated DMA address or OF_BAD_ADDR on error
> + */
> +int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus,
> +                        u64 *size);
> +
>  /**
>   * ofnode_device_is_compatible() - check if the node is compatible with compat
>   *
> diff --git a/include/dm/read.h b/include/dm/read.h
> index 0585eb1228..9e1f3f5f12 100644
> --- a/include/dm/read.h
> +++ b/include/dm/read.h
> @@ -1004,6 +1004,12 @@ static inline u64 dev_translate_dma_address(const struct udevice *dev,
>         return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
>  }
>
> +static inline u64 dev_get_dma_range(const struct udevice *dev, phys_addr_t *cpu,
> +                                   dma_addr_t *bus, u64 *size)
> +{
> +       return ofnode_get_dma_range(dev_ofnode(dev), cpu, bus, size);
> +}
> +
>  static inline int dev_read_alias_highest_id(const char *stem)
>  {
>         if (!CONFIG_IS_ENABLED(OF_LIBFDT))
> diff --git a/include/fdt_support.h b/include/fdt_support.h
> index dbbac0fb6a..46eb1dbbb2 100644
> --- a/include/fdt_support.h
> +++ b/include/fdt_support.h
> @@ -260,6 +260,20 @@ u64 fdt_translate_address(const void *blob, int node_offset,
>  u64 fdt_translate_dma_address(const void *blob, int node_offset,
>                               const __be32 *in_addr);
>
> +/**
> + * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
> + * cpu->bus address translations
> + *
> + * @param blob         Pointer to device tree blob
> + * @param node_offset  Node DT offset
> + * @param cpu          Pointer to variable storing the range's cpu address
> + * @param bus          Pointer to variable storing the range's bus address
> + * @param size         Pointer to variable storing the range's size
> + * @return translated DMA address or OF_BAD_ADDR on error
> + */
> +int fdt_get_dma_range(const void *blob, int node_offset, phys_addr_t *cpu,
> +                     dma_addr_t *bus, u64 *size);
> +
>  int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
>                                         phys_addr_t compat_off);
>  int fdt_alloc_phandle(void *blob);
> --
> 2.29.2
>


More information about the U-Boot mailing list