6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

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) 単位であることがわかります。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?