{"id":13643666,"url":"https://github.com/ikwzm/udmabuf","last_synced_at":"2026-01-18T14:24:12.861Z","repository":{"id":44585218,"uuid":"39002616","full_name":"ikwzm/udmabuf","owner":"ikwzm","description":"User space mappable dma buffer device driver for Linux.","archived":false,"fork":false,"pushed_at":"2025-12-13T10:17:41.000Z","size":691,"stargazers_count":657,"open_issues_count":38,"forks_count":183,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-12-22T20:06:13.669Z","etag":null,"topics":["device-driver","dma-buffer","fpga-soc-linux","linux-drivers"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ikwzm.png","metadata":{"files":{"readme":"Readme.ja.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2015-07-13T09:17:35.000Z","updated_at":"2025-12-13T10:17:15.000Z","dependencies_parsed_at":"2023-11-21T07:53:51.273Z","dependency_job_id":"4e93e161-a101-4e33-8053-56438d49c562","html_url":"https://github.com/ikwzm/udmabuf","commit_stats":null,"previous_names":[],"tags_count":93,"template":false,"template_full_name":null,"purl":"pkg:github/ikwzm/udmabuf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikwzm%2Fudmabuf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikwzm%2Fudmabuf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikwzm%2Fudmabuf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikwzm%2Fudmabuf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ikwzm","download_url":"https://codeload.github.com/ikwzm/udmabuf/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikwzm%2Fudmabuf/sbom","scorecard":{"id":483905,"data":{"date":"2025-08-11","repo":{"name":"github.com/ikwzm/udmabuf","commit":"e969832d944b6e97c4ee61b0f4c867592c3dc1f9"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 2/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":3,"reason":"0 commit(s) and 4 issue activity found in the last 90 days -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: BSD 2-Clause \"Simplified\" License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 4 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-19T17:19:23.528Z","repository_id":44585218,"created_at":"2025-08-19T17:19:23.528Z","updated_at":"2025-08-19T17:19:23.528Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28537546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T13:04:05.990Z","status":"ssl_error","status_checked_at":"2026-01-18T13:01:44.092Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["device-driver","dma-buffer","fpga-soc-linux","linux-drivers"],"created_at":"2024-08-02T01:01:51.009Z","updated_at":"2026-01-18T14:24:12.820Z","avatar_url":"https://github.com/ikwzm.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"u-dma-buf(User space mappable DMA Buffer)\n==================================================================================\n\n\n\n# はじめに\n\n\n\n## u-dma-bufとは\n\n\nu-dma-buf はLinux のカーネル空間に連続したメモリ領域をDMAバッファとして確保し、ユーザー空間からアクセス可能にするためのデバイスドライバです。主にUIO(User space I/O)を使ってユーザー空間でデバイスドライバを動かす場合のDMAバッファを提供します。\n\nユーザー空間でu-dma-bufで確保したDMAバッファを利用する際は、デバイスファイル(/dev/udmabuf0など)をopen()して、mmap()でユーザー空間にマッピングするか、read()またはwrite()で行います。\n\nopenする際にO_SYNCフラグをセットすることによりCPUキャッシュを無効にすることが出来ます。また、CPUキャッシュを有効にした状態で、CPUキャッシュのフラッシュとインヴァリディエートを行うことが出来ます(ARMアーキテクチャのみ)。\n\n/sys/class/u-dma-buf/udmabuf0/phys_addr を読むことにより、DMAバッファの物理空間上のアドレスを知ることが出来ます。\n\nu-dma-bufのDMAバッファの大きさやデバイスのマイナー番号は、デバイスドライバのロード時(insmodによるロードなど)に指定できます。またプラットフォームによってはデバイスツリーに記述しておくこともできます。\n\n\n## 構成\n\n\n\n![図1 構成](./u-dma-buf-1.jpg \"図1 構成\")\n\n図1 構成\n\n\u003cbr /\u003e\n\n\n\n\n## 対応プラットフォーム\n\n\n* OS : Linux Kernel Version 3.6 - 3.8, 3.18, 4.4, 4.8, 4.12, 4.14, 4.19, 5.0 - 5.10\n(私が動作を確認したのは3.18, 4.4, 4.8, 4.12, 4.14, 4.19, 5.4, 5.10 です).\n* CPU: ARM Cortex-A9 (Xilinx ZYNQ / Altera CycloneV SoC)\n* CPU: ARM64 Cortex-A53 (Xilinx ZYNQ UltraScale+ MPSoC)\n* CPU: x86(64bit) ただし検証が不十分です。皆さんからの結果を期待しています。また、現時点では以下の機能に制限があります。\n\n  * O_SYNCフラグによるCPUキャッシュの制御が出来ません。常にCPUキャッシュは有効です。\n  * sync_for_cpu、sync_for_deviceによる手動でのCPUキャッシュの制御が出来ません。\n  * デバイスツリーによる各種設定が出来ません。\n\n\n## 注意: udmabuf から u-dma-buf へ\n\n### u-dma-buf の前身\n\nu-dma-buf の前身は udmabuf です。\"udmabuf\" から \"u-dma-buf\" にカーネルモジュール名を変更しました。これは Linux Kernel 5.x から \"udmabuf\" と同じ名前の別のカーネルモジュールが追加されたため、名前の重複をさけるのが目的です。\n\n### udmabuf から u-dma-buf への変更点\n\n| Categoly            | udmabuf                | u-dma-buf               |\n|:--------------------|:-----------------------|:------------------------|\n| module name         | udmabuf.ko             | u-dma-buf.ko            |\n| source file         | udmabuf.c              | u-dma-buf.c             |\n| sys class name      | /sys/class/udmabuf/    | /sys/class/u-dma-buf/   |\n| DT compatible prop. | \"ikwzm,udmabuf-0.10.a\" | \"ikwzm,u-dma-buf\"       |\n\n\n# 使い方\n\n\n\n## コンパイル\n\n\n次のようなMakefileを用意しています。\n\n\n```Makefile:Makefile\nHOST_ARCH       ?= $(shell uname -m | sed -e s/arm.*/arm/ -e s/aarch64.*/arm64/)\nARCH            ?= $(shell uname -m | sed -e s/arm.*/arm/ -e s/aarch64.*/arm64/)\n\nifdef KERNEL_SRC\n  KERNEL_SRC_DIR  := $(KERNEL_SRC)\nelse\n  KERNEL_SRC_DIR  ?= /lib/modules/$(shell uname -r)/build\nendif\n\nifeq ($(ARCH), arm)\n ifneq ($(HOST_ARCH), arm)\n   CROSS_COMPILE  ?= arm-linux-gnueabihf-\n endif\nendif\nifeq ($(ARCH), arm64)\n ifneq ($(HOST_ARCH), arm64)\n   CROSS_COMPILE  ?= aarch64-linux-gnu-\n endif\nendif\n\nu-dma-buf-obj           := u-dma-buf.o\nobj-$(CONFIG_U_DMA_BUF) += $(u-dma-buf-obj)\n\nifndef UDMABUF_MAKE_TARGET\n  KERNEL_VERSION_LT_5 ?= $(shell awk '/^VERSION/{print int($$3) \u003c 5}' $(KERNEL_SRC_DIR)/Makefile)\n  ifeq ($(KERNEL_VERSION_LT_5), 1)\n    UDMABUF_MAKE_TARGET ?= modules\n  else\n    UDMABUF_MAKE_TARGET ?= u-dma-buf.ko\n  endif\nendif\n\nall:\n\t$(MAKE) -C $(KERNEL_SRC_DIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) obj-m=$(u-dma-buf-obj) $(UDMABUF_MAKE_TARGET)\n\nmodules_install:\n\t$(MAKE) -C $(KERNEL_SRC_DIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) obj-m=$(u-dma-buf-obj) modules_install\n\nclean:\n\t$(MAKE) -C $(KERNEL_SRC_DIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) clean\n\n```\n\n\n\n\n\n## インストール\n\n\ninsmod でu-dma-bufのカーネルドライバをロードします。この際に引数を渡すことによりDMAバッファを確保してデバイスドライバを作成します。insmod の引数で作成できるDMAバッファは udmabuf0/1/2/3/4/5/6/7の最大８つです。\n\n\n```console\nzynq$ insmod u-dma-buf.ko udmabuf0=1048576\nu-dma-buf udmabuf0: driver installed\nu-dma-buf udmabuf0: major number   = 248\nu-dma-buf udmabuf0: minor number   = 0\nu-dma-buf udmabuf0: phys address   = 0x1e900000\nu-dma-buf udmabuf0: buffer size    = 1048576\nu-dma-buf udmabuf0: dma coherent = 0\nzynq$ ls -la /dev/udmabuf0\ncrw------- 1 root root 248, 0 Dec  1 09:34 /dev/udmabuf0\n```\n\n\nパーミッションがrootのみ読み書き可能になっています。ロード時にパーミッションを変更したい場合は、/etc/udev/rules.d/99-u-dma-buf.rules というファイルを作成し、以下の内容を書いておきます。\n\n\n```rules:99-u-dma-buf.rules\nKERNEL==\"udmabuf[0-9]*\", GROUP=\"root\", MODE=\"0666\"\n```\n\n\n\n\nアンインストールするには rmmod を使います。\n\n\n```console\nzynq$ rmmod u-dma-buf\nu-dma-buf udmabuf0: driver uninstalled\n```\n\n\n\n\n\n## Debian パッケージによるインストール\n\n\n以下のURL に u-dma-buf を Debian パッケージ化するリポジトリを用意しています。詳細は以下の URL を参照してください。\n\n*  https://github.com/ikwzm/u-dma-buf-kmod-dpkg\n\n\n\n\n## デバイスツリーによる設定\n\n\nu-dma-bufはinsmod の引数でDMAバッファを用意する以外に、Linuxのカーネルが起動時に読み込むdevicetreeファイルによってDMAバッファを用意する方法があります。devicetreeファイルに次のようなエントリを追加しておけば、insmod でロードする際に自動的にDMAバッファを確保してデバイスドライバを作成します。\n\n\n```devicetree:devicetree.dts\n\t\tudmabuf@0x00 {\n\t\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\t\tdevice-name = \"udmabuf0\";\n\t\t\tminor-number = \u003c0\u003e;\n\t\t\tsize = \u003c0x00100000\u003e;\n\t\t};\n\n```\n\n\n\n\n\n```console\nzynq$ insmod u-dma-buf.ko\nu-dma-buf udmabuf0: driver installed\nu-dma-buf udmabuf0: major number   = 248\nu-dma-buf udmabuf0: minor number   = 0\nu-dma-buf udmabuf0: phys address   = 0x1e900000\nu-dma-buf udmabuf0: buffer size    = 1048576\nu-dma-buf udmabuf0: dma coherent  = 0\nzynq$ ls -la /dev/udmabuf0\ncrw------- 1 root root 248, 0 Dec  1 09:34 /dev/udmabuf0\n```\n\n\n\n\nデバイスツリーでは以下のプロパティを設定することができます。\n\n  *  compatible\n  *  size\n  *  minor-number\n  *  device-name\n  *  sync-mode\n  *  sync-always\n  *  sync-offset\n  *  sync-size\n  *  sync-direction\n  *  dma-coherent\n  *  dma-mask\n  *  memory-region\n\n\n\n\n### compatible\n\n\ncompatible プロパティはデバイスツリーをロードした際に対応するデバイスドライバを指定します。compatible プロパティは必須です。compatible プロパティには必ず \"ikwzm,u-dma-buf\" を指定してください。\n\n\n\n\n### size\n\n\nsize プロパティはDMAバッファの容量をバイト数で指定します。size プロパティは必須です。\n\n\n```devicetree:devicetree.dts\n\t\tudmabuf@0x00 {\n\t\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\t\tsize = \u003c0x00100000\u003e;\n\t\t};\n\n```\n\nバッファの容量に 4GiB 以上を指定したいときは、次のように 64bit の値を指定します。\n64bit の値は 上位 32bit、下位 32bit の順に二つ並べて表現します。\n\n```devicetree:devicetree.dts\n\t\tudmabuf@0x00 {\n\t\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\t\tsize = \u003c0x01 0x00000000\u003e;  // size = 0x1_0000_0000\n\t\t};\n\n```\n\n### minor-number\n\n\nminor-number プロパティはu-dma-bufのマイナー番号を指定します。マイナー番号は0から255までつけることができます。ただし、insmodの引数の方が優先され、マイナー番号がかち合うとdevicetreeで指定した方が失敗します。\n\nminor-number プロパティは省略可能です。minor-number プロパティが省略された場合、空いているマイナー番号が割り当てられます。\n\n\n```devicetree:devicetree.dts\n\t\tudmabuf@0x00 {\n\t\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\t\tminor-number = \u003c0\u003e;\n\t\t\tsize = \u003c0x00100000\u003e;\n\t\t};\n\n```\n\n\n\n\n\n### device-name\n\n\ndevice-name プロパティはデバイス名を指定します。\n\ndevice-name プロパティは省略可能です。デバイス名は次のように決まります。\n\n1. device-name プロパティが指定されていた場合は、 device-name。\n2. device-name プロパティが省略されていて、かつminor-number プロパティが指定されていた場合は、sprintf(\"udmabuf%d\", minor-number)。\n3. device-name プロパティが省略されていて、かつminor-number プロパティも省略されていた場合は、devicetree のエントリー名(例ではudmabuf@0x00)。\n\n\n```devicetree:devicetree.dts\n\t\tudmabuf@0x00 {\n\t\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\t\tdevice-name = \"udmabuf0\";\n\t\t\tsize = \u003c0x00100000\u003e;\n\t\t};\n\n```\n\n\n\n### sync-mode\n\n\nsync-mode プロパティはu-dma-bufをopenする際にO_SYNCを指定した場合の動作を指定します。\n\n* sync-mode=\u003c1\u003e:  open 時にO_SYNCフラグが設定された場合または sync-always プロパティが設定されていた場合、CPUキャッシュを無効にします。O_SYNCフラグが設定されなかった場合、CPUキャッシュは有効です。\n* sync-mode=\u003c2\u003e: open 時に O_SYNCフラグが設定された場合または sync-always プロパティが設定されていた場合、CPUがDMAバッファに書き込む際、ライトコンバインします。ライトコンバインとは、基本的にはCPUキャッシュは無効ですが、複数の書き込みをまとめて行うことで若干性能が向上します。O_SYNCフラグが設定されなかった場合、CPUキャッシュは有効です。\n* sync-mode=\u003c3\u003e: open 時にO_SYNCフラグが設定された場合または sync-always プロパティが設定されていた場合、DMAコヒーレンシモードにします。O_SYNCフラグが設定されなかった場合、CPUキャッシュは有効です。\n\nsync-mode プロパティは省略可能です。sync-mode プロパティが省略された場合は \u003c1\u003e に設定されます。\n\n\n```devicetree:devicetree.dts\n\t\tudmabuf@0x00 {\n\t\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\t\tsize = \u003c0x00100000\u003e;\n\t\t\tsync-mode = \u003c2\u003e;\n\t\t};\n\n```\n\n\nO_SYNCおよびキャッシュの設定に関しては次の節で説明します。\n\n\n### sync-always\n\n\nsync-always プロパティを設定した時、 u-dma-buf を open する際に O_SYNC の指定に関わらず常に sync-mode プロパティで指定された動作することを指定します。\n\n\n```devicetree:devicetree.dts\n\t\tudmabuf@0x00 {\n\t\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\t\tsize = \u003c0x00100000\u003e;\n\t\t\tsync-mode = \u003c2\u003e;\n\t\t\tsync-always;\n\t\t};\n\n```\n\n\nO_SYNCおよびキャッシュの設定に関しては次の節で説明します。\n\n\n### sync-offset\n\n\nsync-offset プロパティは u-dma-buf のキャッシュ制御を手動で行う際のバッファの範囲の先頭を指定します。\n\nsync-offset プロパティは省略可能です。sync-offset プロパティが省略された場合は\u003c0\u003e になります。\n\n手動でキャッシュを制御する方法は次の節で説明します。\n\n\n### sync-size\n\n\nsync-size プロパティは  u-dma-buf  のキャッシュ制御を手動で行う際のバッファの範囲のサイズを指定します。\n\nsync-size プロパティは省略可能です。sync-size プロパティが省略された場合は、size プロパティと同じ値になります。\n\n手動でキャッシュを制御する方法は次の節で説明します。\n\n\n### sync-direction\n\n\nsync-direction プロパティは u-dma-buf のキャッシュ制御を手動で行う際のDMAの方向を指定します。\n\n* sync-direction=\u003c0\u003e: DMA_BIDIRECTIONALを指定します。\n* sync-direction=\u003c1\u003e: DMA_TO_DEVICEを指定します。\n* sync-direction=\u003c2\u003e: DMA_FROM_DEVICEを指定します。\n\nsync-direction プロパティは省略可能です。sync-direction プロパティが省略された場合は\u003c0\u003eに設定されます。\n\n\n```devicetree:devicetree.dts\n\t\tudmabuf@0x00 {\n\t\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\t\tsize = \u003c0x00100000\u003e;\n\t\t\tsync-offset = \u003c0x00010000\u003e;\n\t\t\tsync-size = \u003c0x000F0000\u003e;\n\t\t\tsync-direction = \u003c2\u003e;\n\t\t};\n\n```\n\n\n手動でキャッシュを制御する方法は次の節で説明します。\n\n\n### dma-coherent\n\n\ndma-coherent プロパティを設定した時、DMAバッファとCPUキャッシュのコヒーレンシはハードウェアで保証できることを示します。\n\ndma-coherent プロパティは省略可能です。dma-cohernet プロパティが省略された場合、DMAバッファとCPUキャッシュのコヒーレンシはハードウェアで保証できないことを示します。\n\n\n```devicetree:devicetree.dts\n\t\tudmabuf@0x00 {\n\t\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\t\tsize = \u003c0x00100000\u003e;\n\t\t\tdma-coherent;\n\t\t};\n\n```\n\n\n手動でキャッシュを制御する方法は次の節で説明します。\n\n### dma-mask\n\n** 注意事項: dma-mask の値はシステムに依存します。dma-mask の意味をよく理解して設定してください。 **\n\n```devicetree:devicetree.dts\n\t\tudmabuf@0x00 {\n\t\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\t\tsize = \u003c0x00100000\u003e;\n\t\t\tdma-mask = \u003c64\u003e;\n\t\t};\n```\n\n### memory-region\n\n\nLinux はデバイスツリーで reserved-memory(予約メモリ)領域を指定することができます。Linux のカーネルは reserved-memory で指定された物理メモリ空間を通常のメモリアロケーションの対象外にします。この reserved-memory 領域にアクセスするためには /dev/mem 等の汎用メモリアクセスドライバを使うか、デバイスツリーでデバイスドライバに紐付ける必要があります。\n\nmemory-region プロパティによってreserved-memory で確保したメモリ領域 u-dma-buf に紐付けることができます。\n\n\n```devicetree:devicetree.dts\n\treserved-memory {\n\t\t#address-cells = \u003c1\u003e;\n\t\t#size-cells = \u003c1\u003e;\n\t\tranges;\n\t\timage_buf0: image_buf@0 {\n\t\t\tcompatible = \"shared-dma-pool\";\n\t\t\treusable;\n\t\t\treg = \u003c0x3C000000 0x04000000\u003e; \n\t\t\tlabel = \"image_buf0\";\n\t\t};\n\t};\n\tudmabuf@0 {\n\t\tcompatible = \"ikwzm,u-dma-buf\";\n\t\tdevice-name = \"udmabuf0\";\n\t\tsize = \u003c0x04000000\u003e; // 64MiB\n\t\tmemory-region = \u003c\u0026image_buf0\u003e;\n\t};\n```\n\n\n上の例では image_buf0 として 0x3C000000 〜 0x3FFFFFFF の64Mbyte を reserved-memory として確保しています。この image_buf0 に compatible プロパティに \"shared-dma-pool\" を、そして reusable プロパティを指定します。これらのプロパティの指定によって、この reserved-memory の領域を CMA がアロケートする領域とします。また、アドレスとサイズのアライメントに注意する必要があります。\n\nudmabuf@0 に上記の image_buf0 を memory-region プロパティで紐付けしています。この紐付けによって udmabuf@0 は image_buf0 で指定した CMA 領域から物理メモリを確保します。\n\nmemory-region プロパティは省略可能です。memory-region プロパティが省略された場合、Linux カーネルに確保された CMA 領域から DMA バッファを確保します。\n\n\n## デバイスファイル\n\n\nu-dma-bufをinsmodでカーネルにロードすると、次のようなデバイスファイルが作成されます。\\\u003cdevice-name\\\u003eには、前節で説明したデバイス名が入ります。\n\n  * /dev/\\\u003cdevice-name\\\u003e\n  * /sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/phys_addr\n  * /sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/size\n  * /sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_mode\n  * /sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_offset\n  * /sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_size\n  * /sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_direction\n  * /sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_owner\n  * /sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_for_cpu\n  * /sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_for_device\n  * /sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/dma_coherent\n\n\n### /dev/\\\u003cdevice-name\\\u003e\n\n\n/dev/\\\u003cdevice-name\\\u003eはmmap()を使って、ユーザー空間にマッピングするか、read()、write()を使ってバッファにアクセスする際に使用します。\n\n\n```C:u-dma-buf_test.c\n    if ((fd  = open(\"/dev/udmabuf0\", O_RDWR)) != -1) {\n        buf = mmap(NULL, buf_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);\n        /* ここでbufに読み書きする処理を行う */\n        close(fd);\n    }\n\n```\n\n\nまた、ddコマンド等でにデバイスファイルを指定することにより、shellから直接リードライトすることも出来ます。\n\n\n```console\nzynq$ dd if=/dev/urandom of=/dev/udmabuf0 bs=4096 count=1024\n1024+0 records in\n1024+0 records out\n4194304 bytes (4.2 MB) copied, 3.07516 s, 1.4 MB/s\n```\n\n\n```console\nzynq$dd if=/dev/udmabuf4 of=random.bin\n8192+0 records in\n8192+0 records out\n4194304 bytes (4.2 MB) copied, 0.173866 s, 24.1 MB/s\n```\n\n\n\n\n\n### phys_addr\n\n\n/sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/phys_addr はDMAバッファの物理アドレスが読めます。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    unsigned long  phys_addr;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/phys_addr\", O_RDONLY)) != -1) {\n        read(fd, attr, 1024);\n        sscanf(attr, \"%x\", \u0026phys_addr);\n        close(fd);\n    }\n\n```\n\n\n\n\n\n### size\n\n\n/sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/size はDMAバッファのサイズが読めます。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    unsigned int   buf_size;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/size\", O_RDONLY)) != -1) {\n        read(fd, attr, 1024);\n        sscanf(attr, \"%d\", \u0026buf_size);\n        close(fd);\n    }\n\n```\n\n\n\n\n\n### sync_mode\n\n\n/sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_mode はu-dma-bufをopenする際にO_SYNCを指定した場合の動作を指定します。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_mode = 2;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/sync_mode\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_mode);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n\nO_SYNCおよびキャッシュの設定に関しては次の節で説明します。\n\n\n\n\n### sync_offset\n\n\n/sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_offset は u-dma-bufのキャッシュ制御を手動で行う際のバッファの範囲の先頭を指定します。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_offset = 0x00000000;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/sync_offset\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_offset);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n\n手動でキャッシュを制御する方法は次の節で説明します。\n\n\n\n\n### sync_size\n\n\n/sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_size は u-dma-bufのキャッシュ制御を手動で行う際のバッファの範囲のサイズを指定します。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_size = 1024;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/sync_size\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_size);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n\n手動でキャッシュを制御する方法は次の節で説明します。\n\n\n\n\n### sync_direction\n\n\n/sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_direction は u-dma-bufのキャッシュ制御を手動で行う際のDMAの方向を指定します。\n\n0: DMA_BIDIRECTIONALを指定します。\n\n1: DMA_TO_DEVICEを指定します。\n\n2: DMA_FROM_DEVICEを指定します。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_direction = 1;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/sync_direction\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_direction);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n\n手動でキャッシュを制御する方法は次の節で説明します。\n\n\n\n\n### dma_coherent\n\n\n/sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/dma_coherent は DMAバッファとCPUキャッシュのコヒーレンシをハードウェアで保証できるか否かを読み取ることができます。デバイスツリーで dma-coherent プロパティでハードウェアで保証できるか否かを指定することができますが、このデバイスファイルは読み取り専用です。\n\nこの値が1の時は、DMAバッファとCPUキャッシュのコヒーレンシはハードウェアで保証できることを示します。この値が0の時は、DMAバッファとCPUキャッシュのコヒーレンシはハードウェアで保証できないことを示します。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    int dma_coherent;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/dma_coherent\", O_RDONLY)) != -1) {\n        read(fd, attr, 1024);\n        sscanf(attr, \"%x\", \u0026dma_coherent);\n        close(fd);\n    }\n\n```\n\n\n\n\n\n\n\n### sync_owner\n\n\n/sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_owner は u-dma-bufのキャッシュ制御を手動で行った際に、現在のバッファのオーナーがCPUかDEVICEを読み取ります。バッファのオーナーが CPU の場合は 0 が読めます。バッファのオーナーが DEVICE の場合は 1 が読めます。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    int sync_owner;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/sync_owner\", O_RDONLY)) != -1) {\n        read(fd, attr, 1024);\n        sscanf(attr, \"%x\", \u0026sync_owner);\n        close(fd);\n    }\n\n```\n\n\n手動でキャッシュを制御する方法は次の節で説明します。\n\n\n\n\n### sync_for_cpu\n\n\n/sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_for_cpu はu-dma-bufのキャッシュ制御を手動で行う際、このデバイスファイルに0以外の値を書き込むことでバッファのオーナーをCPUにします。このデバイスファイルは書き込みオンリーです。\n\nこのデバイスファイルに 1 を書いた場合、sync_directionが2(=DMA_FROM_DEVICE)または0(=DMA_BIDIRECTIONAL)だった時、sync_offsetとsync_size で指定された領域のCPUキャッシュが無効化されます。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_for_cpu = 1;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/sync_for_cpu\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_for_cpu);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n\n\n\nこの sync_for_cpu デバイスファイルに書き込む値には、次のように、 sync_offset、sync_size および sync_direction を含める事が出来ます。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_offset     = 0;\n    unsigned long  sync_size        = 0x10000;\n    unsigned int   sync_direction = 0;\n    unsigned long  sync_for_cpu    = 1;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/sync_for_cpu\", O_WRONLY)) != -1) {\n        sprintf(attr, \"0x%08X%08X\", (sync_offset \u0026 0xFFFFFFFF), (sync_size \u0026 0xFFFFFFF0) | (sync_direction \u003c\u003c 2) | sync_for_cpu);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n\nこの sync_for_cpu デバイスファイルに含まれた sync_offset、sync_size、sync_direction は一時的なものであり、デバイスファイルの sync_offset、sync_size、sync_direction の値には影響を与えません。\n\n\n\n手動でキャッシュを制御する方法は次の節で説明します。\n\n\n### sync_for_device\n\n\n/sys/class/u-dma-buf/\\\u003cdevice-name\\\u003e/sync_for_deviceはu-dma-bufのキャッシュ制御を手動で行う際、このデバイスドライバに0以外の値を書き込むことでバッファのオーナーをDEVICEにします。このデバイスファイルは書き込みオンリーです。\n\nこのデバイスファイルに 1 を書いた場合、sync_directionが1(=DMA_TO_DEVICE)または0(=DMA_BIDIRECTIONAL)だった時、sync_offsetとsync_size で指定された領域のCPUキャッシュがフラッシュされます。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_for_device = 1;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/sync_for_device\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_for_device);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n\n\n\nこの sync_for_device デバイスファイルに書き込む値には、次のように、 sync_offset、sync_size および sync_direction を含める事が出来ます。\n\n\n```C:u-dma-buf_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_offset     = 0;\n    unsigned long  sync_size        = 0x10000;\n    unsigned int   sync_direction  = 0;\n    unsigned long  sync_for_device = 1;\n    if ((fd  = open(\"/sys/class/u-dma-buf/udmabuf0/sync_for_device\", O_WRONLY)) != -1) {\n        sprintf(attr, \"0x%08X%08X\", (sync_offset \u0026 0xFFFFFFFF), (sync_size \u0026 0xFFFFFFF0) | (sync_direction \u003c\u003c 2) | sync_for_device);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n\nこの sync_for_device デバイスファイルに含まれた sync_offset、sync_size、sync_direction は一時的なものであり、デバイスファイルの sync_offset、sync_size、sync_direction の値には影響を与えません。\n\n\n\n手動でキャッシュを制御する方法は次の節で説明します。\n\n\n## /dev/u-dma-buf-mgr による u-dma-buf の作成と削除\n\nu-dma-buf v2.1以降、 /dev/u-dma-buf-mgr デバイスドライバーが追加されました。 u-dma-buf は\n/dev/u-dma-buf-mgr に文字列としてコマンドを書き込むことにより作成/削除されます。\n\n### u-dma-buf の作成\n\nu-dma-bufは、次のように文字列 \"create \u003cdevice-name\u003e \u003csize\u003e\"を /dev/u-dma-buf-mgr に書き込むことで作成できます。\n\\\u003cdevice-name\\\u003e には、生成される u-dma-buf のデバイス名を指定します。\n\\\u003csize\\\u003e には、割り当てるバッファのサイズを指定します。\n\n```console\nzynq$ sudo echo \"create udmabuf8 0x10000\" \u003e /dev/u-dma-buf-mgr\n[   58.790695] u-dma-buf-mgr : create udmabuf8 65536\n[   58.798637] u-dma-buf udmabuf8: driver version = 2.1.0\n[   58.804114] u-dma-buf udmabuf8: major number   = 245\n[   58.809000] u-dma-buf udmabuf8: minor number   = 0\n[   58.815628] u-dma-buf udmabuf8: phys address   = 0x1f050000\n[   58.822041] u-dma-buf udmabuf8: buffer size    = 65536\n[   58.827098] u-dma-buf udmabuf8: dma device     = u-dma-buf.0.auto\n[   58.834918] u-dma-buf udmabuf8: dma coherent   = 0\n[   58.839632] u-dma-buf u-dma-buf.0.auto: driver installed.\n```\n\n### u-dma-buf の削除\n\nu-dma-bufは、次のように文字列 \"delete \u003cdevice-name\u003e\" を /dev/u-dma-buf-mgr に書き込むことで削除できます。\n\\\u003cdevice-name\\\u003e には、作成コマンドで指定された \\\u003cdevice-name\\\u003e を指定します。\n\n```console\nzynq$ sudo echo \"delete udmabuf8\" \u003e /dev/u-dma-buf-mgr\n[  179.089702] u-dma-buf-mgr : delete udmabuf8\n[  179.094212] u-dma-buf u-dma-buf.0.auto: driver removed.\n```\n\n# DMAバッファとCPUキャッシュのコヒーレンシ\n\n\nCPUは通常キャッシュを通じてメインメモリ上のDMAバッファにアクセスしますが、アクセラレータは直接メインメモリ上のDMAバッファにアクセスします。その際、問題になるのはCPUのキャッシュとメインメモリとのコヒーレンシ(内容の一貫性)です。\n\n\n\n\n## ハードウェアでコヒーレンシを保証できる場合\n\n\nハードウェアでコヒーレンシを保証できる場合、CPUキャッシュを有効にしても問題はありません。例えばZYNQにはACP(Accelerator Coherency Port)があり、アクセラレータ側がこのPortを通じてメインメモリにアクセスする場合は、ハードウェアによってCPUキャッシュとメインメモリとのコヒーレンシが保証できます。\n\nハードウェアでコヒーレンシを保証できる場合は、CPUキャッシュを有効にすることでCPUからのアクセスを高速に行うことができます。CPUキャッシュを有効にする場合は、O_SYNCフラグを設定せずにu-dma-bufをopen してください。\n\n\n```C:u-dma-buf_test.c\n    /* CPUキャッシュを有効にする場合はO_SYNCをつけずにopen する */\n    if ((fd  = open(\"/dev/udmabuf0\", O_RDWR)) != -1) {\n        buf = mmap(NULL, buf_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);\n        /* ここでbufに読み書きする処理を行う */\n        close(fd);\n    }\n\n```\n\n\n\n\nハードウェアでコヒーレンシを保証できる場合は、次の項で説明するようなCPUキャッシュを手動で制御する必要はありません。\n\n\n\nデバイスツリーで dma-coherent プロパティを設定した場合、ハードウェアでコヒーレンシを保証できることを指定します。dma-coherent プロパティを設定した場合、後述の「CPUキャッシュを有効にしたまま手動でCPUキャッシュを制御する方法」で説明したキャッシュの制御が行われません。\n\n\n\n\n## ハードウェアでコヒーレンシを保証できない場合\n\n\nハードウェアでコヒーレンシを保証できない場合、別の方法でコヒーレンシを保証しなければなりません。u-dma-bufでは、CPUキャッシュを無効にする方法と、CPUキャッシュを有効にしたまま手動でCPUキャッシュをフラッシュ/無効化する方法を用意しています。\n\n\n\n\n### CPUキャッシュを無効にする方法\n\n\nCPUキャッシュを無効にする場合は、u-dma-bufをopenする際にO_SYNCフラグを設定します。\n\n\n```C:u-dma-buf_test.c\n    /* CPUキャッシュを無効にする場合はO_SYNCをつけてopen する */\n    if ((fd  = open(\"/dev/udmabuf0\", O_RDWR | O_SYNC)) != -1) {\n        buf = mmap(NULL, buf_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);\n        /* ここでbufに読み書きする処理を行う */\n        close(fd);\n    }\n\n```\n\n\nO_SYNCフラグを設定した場合のキャッシュの振る舞いはsync_modeで設定します。sync_modeには次の値が設定できます。\n\n* sync_mode=0:  常にCPUキャッシュが有効。つまりO_SYNCフラグの有無にかかわらず常にCPUキャッシュは有効になります。\n* sync_mode=1: O_SYNCフラグが設定された場合、CPUキャッシュを無効にします。O_SYNCフラグが設定されなかった場合、CPUキャッシュは有効です。\n* sync_mode=2: O_SYNCフラグが設定された場合、CPUがDMAバッファに書き込む際、ライトコンバインします。ライトコンバインとは、基本的にはCPUキャッシュは無効ですが、複数の書き込みをまとめて行うことで若干性能が向上します。O_SYNCフラグが設定されなかった場合、CPUキャッシュは有効です。\n* sync_mode=3: O_SYNCフラグが設定された場合、DMAコヒーレンシモードにします。といっても、DMAコヒーレンシモードに関してはまだよく分かっていません。O_SYNCフラグが設定されなかった場合、CPUキャッシュは有効です。\n* sync_mode=4:  常にCPUキャッシュが有効。つまりO_SYNCフラグの有無にかかわらず常にCPUキャッシュは有効になります。\n* sync_mode=5: O_SYNCフラグの有無にかかわらずCPUキャッシュを無効にします。\n* sync_mode=6: O_SYNCフラグの有無にかかわらず、CPUがDMAバッファに書き込む際、ライトコンバインします。\n* sync_mode=7: O_SYNCフラグの有無にかかわらず、DMAコヒーレンシモードにします。\n\n\n\n参考までに、CPUキャッシュを有効/無効にした場合の次のようなプログラムを実行した際の処理時間を示します。\n\n\n```C:u-dma-buf_test.c\nint check_buf(unsigned char* buf, unsigned int size)\n{\n    int m = 256;\n    int n = 10;\n    int i, k;\n    int error_count = 0;\n    while(--n \u003e 0) {\n      for(i = 0; i \u003c size; i = i + m) {\n        m = (i+256 \u003c size) ? 256 : (size-i);\n        for(k = 0; k \u003c m; k++) {\n          buf[i+k] = (k \u0026 0xFF);\n        }\n        for(k = 0; k \u003c m; k++) {\n          if (buf[i+k] != (k \u0026 0xFF)) {\n            error_count++;\n          }\n        }\n      }\n    }\n    return error_count;\n}\nint clear_buf(unsigned char* buf, unsigned int size)\n{\n    int n = 100;\n    int error_count = 0;\n    while(--n \u003e 0) {\n      memset((void*)buf, 0, size);\n    }\n    return error_count;\n}\n\n```\n\n\n表-1　checkbufの測定結果\n\n\u003ctable border=\"2\"\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\" rowspan=\"2\"\u003esync_mode\u003c/td\u003e\n    \u003ctd align=\"center\" rowspan=\"2\"\u003eO_SYNC\u003c/td\u003e\n    \u003ctd align=\"center\" colspan=\"3\"\u003eDMAバッファのサイズ\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e1MByte\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e5MByte\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e10MByte\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e0\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.437[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e2.171[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e4.340[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.437[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e2.171[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e4.340[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e1\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.434[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e2.179[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e4.337[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e2.283[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e11.414[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e22.830[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e2\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.434[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e2.169[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e4.337[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e1.616[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e8.262[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e16.562[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e3\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.434[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e2.169[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e4.337[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e1.600[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e8.391[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e16.587[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e4\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.437[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e2.171[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e4.337[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.437[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e2.171[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e4.337[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e5\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e2.283[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e11.414[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e22.809[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e2.283[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e11.414[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e22.840[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e6\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e1.655[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e8.391[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e16.587[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e1.655[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e8.391[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e16.587[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e7\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e1.655[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e8.391[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e16.587[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e1.655[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e8.391[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e16.587[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n表-2　clearbufの測定結果\n\n\u003ctable border=\"2\"\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\" rowspan=\"2\"\u003esync_mode\u003c/td\u003e\n    \u003ctd align=\"center\" rowspan=\"2\"\u003eO_SYNC\u003c/td\u003e\n    \u003ctd align=\"center\" colspan=\"3\"\u003eDMAバッファのサイズ\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e1MByte\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e5MByte\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e10MByte\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e0\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.067[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.359[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.713[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.067[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.362[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.716[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e1\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.067[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.362[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.718[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.912[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e4.563[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e9.126[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e2\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.068[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.360[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.721[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.063[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.310[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.620[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e3\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.068[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.361[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.715[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.062[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.310[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.620[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e4\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.068[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.360[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.718[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.067[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.360[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.710[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e5\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.913[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e4.562[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e9.126[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.913[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e4.562[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e9.126[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e6\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.062[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.310[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.618[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.062[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.310[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.619[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd rowspan=\"2\"\u003e7\u003c/td\u003e\n    \u003ctd\u003e無\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.062[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.310[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.620[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e有\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.062[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.310[sec]\u003c/td\u003e\n    \u003ctd align=\"right\"\u003e0.621[sec]\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\n**注意事項: ARM64 で `O_SYNC` を使う場合**\n\nv2.1.1 以前では、udmabuf は ARM64 で sync_mode = 1（noncached）の時、 ```pgprot_writecombine()``` を使用していました。その理由は、 ```pgprot_noncached()``` を使用すると udmabuf_test.c の memset() でバスエラーが発生したためです。\n\nしかしながら、https://github.com/ikwzm/udmabuf/pull/28 で報告されているように、ARM64 で ```pgprot_writecombine()``` を使用すると、キャッシュの一貫性に問題があることがわかりました。\n\nしたがって、v2.1.2 以降、sync_mode = 1の場合は ```pgprot_noncached()``` を使用するように変更されました。 これは、キャッシュの一貫性の問題を理解するのが非常に難しくデバッグが難しいためです。キャッシュの一貫性の問題を心配するのではなく、バスエラーを起したほうが簡単だと判断しました。\n\nこの変更により、ARM64 で `O_SYNC` フラグによるキャッシュ制御を行う場合は注意が必要になります。おそらく、memset() を使用することはできません。\n\n問題が発生した場合、キャッシュの一貫性はハードウェアによって維持するか、後述のCPUキャッシュを有効にしたまま手動でキャッシュを制御する方法を使用してください。\n\n### CPUキャッシュを有効にしたまま手動でCPUキャッシュを制御する方法\n\n\nCPUキャッシュを有効にする場合は、O_SYNCフラグを設定せずにu-dma-bufをopen します。\n\n\n```C:u-dma-buf_test.c\n    /* CPUキャッシュを有効にする場合はO_SYNCをつけずにopen する */\n    if ((fd  = open(\"/dev/udmabuf0\", O_RDWR)) != -1) {\n        buf = mmap(NULL, buf_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);\n        /* ここでbufに読み書きする処理を行う */\n        close(fd);\n    }\n\n```\n\n\n\n\nアクセラレーターと共有するバッファの範囲をsync_offsetとsync_sizeで指定します。sync_offsetはmmap()で確保した先頭アドレスからのオフセット値を指定します。sync_sizeは共有するバッファの大きさをバイト数で指定します。\n\nアクセラレータがバッファからデータを読むだけの場合は、sync_direction に1(=DMA_TO_DEVICE)を指定します。\n\nアクセラレータがバッファにデータを書き込むだけの場合は、sync_direction に2(=DMA_FROM_DEVICE)を指定します。\n\nアクセラレータがバッファにデータを読み書き両方行う場合は、sync_direction に0(=DMA_BIDIRECTIONAL)を指定します。\n\n\n\n以上の設定の後、CPUがバッファにアクセスする前に sync_for_cpu に1を書いてバッファのオーナーをCPUにします。dma-coherent プロパティが設定されていない場合、sync_direction が2か0の時、sync_offsetとsync_sizeで指定された範囲のCPUキャッシュを無効化(Invalidiate)します。一度この操作を行ってバッファのオーナーをCPUにした後は、アクセラレーターがバッファをアクセスしないようにしなければなりません。dma-coherent プロパティが設定されている場合、キャッシュの無効化(Invalidiate)は行われません。\n\n\n\nアクセラレータがバッファにアクセスする前にsync_for_deviceに1を書いてバッファのオーナーをデバイスにします。dma-coherentプロパティが設定されていない場合、sync_directionが1か0の時、sync_offsetとsync_sizeで指定された範囲のCPUキャッシュをフラッシュします。一度この操作を行ってバッファのオーナーをアクセラレーターにした後は、CPUがこのバッファをアクセスしてはいけません。dma-coherent プロパティが設定されている場合、キャッシュのフラッシュは行われません。\n\n\n# Python から u-dma-buf を使う例\n\n\nプログラミング言語Python には NumPy という拡張モジュールが提供されています。この節ではu-dma-buf でカーネル内に確保した DMA バッファを NumPy の memmap でマッピングして ndarray と同じような操作をする方法について説明します。\n\n\n## Udmabuf クラス\n\n\nここでは  u-dma-buf を Python から使うための Udmabuf クラスを定義している udmabuf.py について説明します。\n\n\n\nUdmabuf クラスを定義する前に、numpy をインポートします。\n\n\n```python:udmabuf.py\nimport numpy as np\n\n```\n\n\n\n\nUdmabuf クラスを定義します。初期化時にデバイス名を指定します。\n\n\n```python:udmabuf.py\nclass Udmabuf:\n    \"\"\"A simple u-dma-buf class\"\"\"\n    def __init__(self, name):\n        self.name           = name\n        self.device_name    = '/dev/%s'                 % self.name\n        self.class_path     = '/sys/class/u-dma-buf/%s' % self.name\n        self.phys_addr      = self.get_value('phys_addr', 16)\n        self.buf_size       = self.get_value('size')\n        self.sync_offset    = None\n        self.sync_size      = None\n        self.sync_direction = None\n\n```\n\n\n\n\nUdmabuf クラスにカーネル内に確保した DMA バッファを NumPy の memmap でマッピングする memmap メソッドを定義します。\n\n\n```python:udmabuf.py\n    def memmap(self, dtype, shape):\n        self.item_size = np.dtype(dtype).itemsize\n        self.array     = np.memmap(self.device_name, dtype=dtype, mode='r+', shape=shape)\n        return self.array\n```\n\n\n\n\nUdmabuf クラスにデバイスファイルから数値を読む get_value メソッドと数値を書き込む set_value メソッドを定義します。\n\n\n```python:udmabuf.py\n    def get_value(self, name, radix=10):\n        value = None\n        for line in open(self.class_path + '/' + name):\n            value = int(line, radix)\n            break\n        return value\n    def set_value(self, name, value):\n        f = open(self.class_path + '/' + name, 'w')\n        f.write(str(value))\n        f.close\n\n```\n\n\n\n\nUdmabuf クラスにキャッシュを制御するメソッド群を定義します。\n\n\n```python:udmabuf.py\n    def set_sync_area(self, direction=None, offset=None, size=None):\n        if offset is None:\n            self.sync_offset    = self.get_value('sync_offset')\n        else:\n            self.set_value('sync_offset', offset)\n            self.sync_offset    = offset\n        if size   is None:\n            self.sync_size      = self.get_value('sync_size')\n        else:\n            self.set_value('sync_size', size)\n            self.sync_size      = size\n        if direction is None:\n            self.sync_direction = self.get_value('sync_direction')\n        else:\n            self.set_value('sync_direction', direction)\n            self.sync_direction = direction\n    def set_sync_to_device(self, offset=None, size=None):\n        self.set_sync_area(1, offset, size)\n    def set_sync_to_cpu(self, offset=None, size=None):\n        self.set_sync_area(2, offset, size)\n    def set_sync_to_bidirectional(self, offset=None, size=None):\n        self.set_sync_area(3, offset, size)\n    def sync_for_cpu(self):\n        self.set_value('sync_for_cpu', 1)\n    def sync_for_device(self):\n        self.set_value('sync_for_device', 1)\n\n```\n\n\n\n## udmabuf_test.py\n\n\n次に Python+NumPy による簡単なテストをするスクリプトを示します。\n\n\n```python:udmabuf_test.py\nfrom udmabuf import Udmabuf\nimport numpy as np\nimport time\ndef test_1(a):\n    for i in range (0,9):\n        a *= 0\n        a += 0x31\nif __name__ == '__main__':\n    udmabuf      = Udmabuf('udmabuf0')\n    test_dtype   = np.uint8\n    test_size    = udmabuf.buf_size/(np.dtype(test_dtype).itemsize)\n    udmabuf.memmap(dtype=test_dtype, shape=(test_size))\n    comparison   = np.zeros(test_size, dtype=test_dtype)\n    print (\"test_size  : %d\" % test_size)\n    start        = time.time()\n    test_1(udmabuf.mem_map)\n    elapsed_time = time.time() - start\n    print (\"udmabuf0   : elapsed_time:{0}\".format(elapsed_time)) + \"[sec]\"\n    start        = time.time()\n    test_1(comparison)\n    elapsed_time = time.time() - start\n    print (\"comparison : elapsed_time:{0}\".format(elapsed_time)) + \"[sec]\"\n    if np.array_equal(udmabuf.mem_map, comparison):\n        print (\"udmabuf0 == comparison : OK\")\n    else:\n        print (\"udmabuf0 != comparison : NG\")\n\n```\n\n\n\n\n\n## 実行結果\n\n\nu-dma-buf をインストールします。今回の例では udmabuf0 として 8MByte のバッファを確保しています。\n\n\n```console\nzynq# insmod u-dma-buf.ko udmabuf0=8388608\n[34654.622746] u-dma-buf udmabuf0: driver installed\n[34654.627153] u-dma-buf udmabuf0: major number   = 237\n[34654.631889] u-dma-buf udmabuf0: minor number   = 0\n[34654.636685] u-dma-buf udmabuf0: phys address   = 0x1f300000\n[34654.642002] u-dma-buf udmabuf0: buffer size    = 8388608\n[34654.642002] u-dma-buf udmabuf0: dma-coherent  = 0\n\n```\n\n\n\n\n前節のスクリプトを実行すると次のような結果が得られました。\n\n\n```console\nzynq# python udmabuf_test.py\ntest_size  : 8388608\nudmabuf0   : elapsed_time:1.53304982185[sec]\ncomparison : elapsed_time:1.536673069[sec]\nudmabuf0 == comparison : OK\n```\n\n\n\n\nudmabuf0(カーネル内に確保したバッファ領域)に対する操作と、ndarray で同じ操作を行った場合(comparison)の実行時間はほぼ同じでした。すなわち udmabuf0 も CPU キャッシュが有効に働いていると思われます。\n\nこのスクリプトを実行した後で、udmabuf0 の内容を確認しました。\n\n\n```console\nzynq# dd if=/dev/udmabuf0 of=udmabuf0.bin bs=8388608\n1+0 records in\n1+0 records out\n8388608 bytes (8.4 MB) copied, 0.151531 s, 55.4 MB/s\nshell# \nshell# od -t x1 udmabuf0.bin\n0000000 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31\n*\n40000000\n```\n\n\n\n\nスクリプト実行後も、実行した結果がバッファに残っていることが確認できました。念のため、NumPy でも読めることを確認しましょう。\n\n\n\n\n```console\nzynq# python\nPython 2.7.9 (default, Aug 13 2016, 17:56:53)\n[GCC 4.9.2] on linux2\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n\u003e\u003e\u003e import numpy as np\n\u003e\u003e\u003e a = np.memmap('/dev/udmabuf0', dtype=np.uint8, mode='r+', shape=(8388608))\n\u003e\u003e\u003e a\nmemmap([49, 49, 49, ..., 49, 49, 49], dtype=uint8)\n\u003e\u003e\u003e a.itemsize\n1\n\u003e\u003e\u003e a.size\n8388608\n\u003e\u003e\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fikwzm%2Fudmabuf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fikwzm%2Fudmabuf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fikwzm%2Fudmabuf/lists"}