Help us understand the problem. What is going on with this article?

ZynqMP で Linux の CMA 領域を devicetree の reserved-memory で指定した時のアライメントは 0x00400000(4MiB) 単位

Linux ではデバイスツリーで次のように reserved-memory(予約メモリ)空間を指定出来ます。

devicetree.dts
/ {
    #address-cells = <2>;
    #size-cells = <2>;
    image_buf0: image_buf@0 {
        compatible = "shared-dma-pool";
        reusable;
        reg = <0x0 0x6fc00000 0x0 0x00400000>;
        alignment = <0x0 0x1000>;
        label = "image_buf0";
    };
};

この時、resuable プロパティを付けることによって、予約したメモリ領域を CMA 領域として使うことが出来ます。例えば ZynqMP-FPGA-Linux で上記のデバイスツリーを追加して Linux Kernel を起動すると、次のようなログが出ます。

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
[    0.000000] Linux version 4.19.0-xlnx-v2019.1-zynqmp-fpga (ichiro@Jabberwock) (gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04)) #2 SMP Wed Jul 17 15:19:07 DST 2019
[    0.000000] Machine model: Avnet Ultra96 Rev1
[    0.000000] efi: Getting EFI parameters from FDT:
[    0.000000] efi: UEFI not found.
[    0.000000] Reserved memory: created CMA memory pool at 0x000000006fc00000, size 4 MiB
[    0.000000] OF: reserved mem: initialized node image_buf@0, compatible id shared-dma-pool
[    0.000000] cma: Reserved 256 MiB at 0x0000000070000000
   :
   :
   :

このログを見てわかるように、0x000000006fc00000 から 4MiB が CMA 領域として確保されています。

実はこの件に関して udmabuf に issue があげられました。

この issue によれば、次のようなデバイスツリーの設定だと、

devicetree.dts
    reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        rproc_0_reserved: rproc@3ed00000 {
            no-map;
            reg = <0x0 0x3ed00000 0x0 0x1000000>;
        };
        image_buf0: image_buf@0 {
            compatible = "shared-dma-pool";
            reusable;
            reg = <0x0 0x6fc00000 0x0 0x0100000>;
            alignment = <0x0 0x1000>; 
            label = "image_buf0";
        };
    };
    udmabuf@0 {
        compatible = "ikwzm,udmabuf-0.10.a";
        device-name = "udmabuf0";
        size = <0x0 0x0100000>;
        memory-region = <&image_buf0>;
    };

"incorrect alignment of CMA region" というエラーが出て CMA 領域の確保に失敗します。

[ 0.000000] Reserved memory: incorrect alignment of CMA region
[ 0.000000] cma: Reserved 256 MiB at 0x000000005fc00000
  :
  :
  :
[ 127.914295] udmabuf udmabuf@0: of_reserved_mem_device_init failed. return=-22
[ 127.921580] udmabuf udmabuf@0: driver installed.
[ 127.926204] udmabuf: probe of udmabuf@0 failed with error -22
[ 127.932553] udmabuf udmabuf.0: DMA mask not set
[ 127.937692] udmabuf udmabuf0: driver version = 1.4.5
[ 127.942653] udmabuf udmabuf0: major number = 240
[ 127.947439] udmabuf udmabuf0: minor number = 0
[ 127.952052] udmabuf udmabuf0: phys address = 0x000000005fd00000
[ 127.958140] udmabuf udmabuf0: buffer size = 1048576
[ 127.963274] udmabuf udmabuf0: dma device = udmabuf.0
[ 127.968582] udmabuf udmabuf0: dma coherent = 0
[ 127.973195] udmabuf udmabuf.0: driver installed.

そこで Linux Kernel のソースコードを見てみると、kernel/dma/contiguous.c に次のような記述がありました。

kernel/dma/contiguous.c
static int __init rmem_cma_setup(struct reserved_mem *rmem)
{
    phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
    phys_addr_t mask = align - 1;
    unsigned long node = rmem->fdt_node;
    struct cma *cma;
    int err;

    if (!of_get_flat_dt_prop(node, "reusable", NULL) ||
        of_get_flat_dt_prop(node, "no-map", NULL))
        return -EINVAL;

    if ((rmem->base & mask) || (rmem->size & mask)) {
        pr_err("Reserved memory: incorrect alignment of CMA region\n");
        return -EINVAL;
    }

    err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma);
    if (err) {
        pr_err("Reserved memory: unable to setup CMA region\n");
        return err;
    }
    /* Architecture specific contiguous memory fixup. */
    dma_contiguous_early_fixup(rmem->base, rmem->size);

    if (of_get_flat_dt_prop(node, "linux,cma-default", NULL))
        dma_contiguous_set_default(cma);

    rmem->ops = &rmem_cma_ops;
    rmem->priv = cma;

    pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n",
        &rmem->base, (unsigned long)rmem->size / SZ_1M);

    return 0;
}
RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);

align 変数でアライメント単位を設定してから、開始アドレス(rmem->base) と容量(rmem->size) がアライメント単位であるかどうかチェックしています。アライメント単位は MAX_ORDER 定数や pageblock_order 変数(or定数) によって算出されますが、ZynqMP-FPGA-Linux では 0x00400000 になります。

したがって、ZynqMP で Linux の CMA 領域を devicetree の reserved-memory で指定した時のアライメントは 0x00400000(4MiB) 単位であることがわかります。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした