dma-buf 由浅入深(一) —— 最简单的 dma-buf 驱动程序
dma-buf 由浅入深(二) —— kmap / vmap
dma-buf 由浅入深(三) —— map attachment
dma-buf 由浅入深(四) —— mmap
dma-buf 由浅入深(五) —— File
dma-buf 由浅入深(六) —— begin / end cpu_access
dma-buf 由浅入深(七) —— alloc page 版本
dma-buf 由浅入深(八) —— ION 简化版


前言

最近因为工作内容发生了变化,导致《最简单的DRM驱动程序》系列文章暂停了更新,但我仍然会坚持把它写完。由于在后面讲解 DRM 驱动程序的过程中,会不可避免的介绍到 dma-buf,因此这里将该模块单独提取出来,形成一个系列文章,为后续讲解 DRM PRIME 打下基础。

如果你和我一样,是一位从事Android多媒体底层开发的工程师,那么你对 dma-buf 这个词语一定不会陌生,因为不管是 Video、Camera 还是 Display、GPU,它们的buffer都来自于ION,而 ION 正是基于 dma-buf 实现的。

假如你对 dma-buf 的理解并不深刻,又期望找个时间来彻底公关一下,那么很高兴,这几篇文章一定能让你对 dma-buf 有个更深入、更透彻的理解。

历史

dma-buf 最初的原型为 shrbuf,由 Marek Szyprowski (Samsung)于2011年8月2日首次提出,他实现了 “Buffer Sharing” 的概念验证(Proof-of-Concept),并在三星平台的 V4L2 驱动中实现了 camera 与 display 的 buffer 共享问题。该 patch 发表后,在内核社区引起了巨大反响,因为当时关于 buffer 共享问题很早就开始讨论了,但是由于内核没有现成的框架支持,导致各个厂商实现的驱动五花八门,此时急需要一个统一的框架来解决 buffer 共享问题。

  • LWN: Buffer sharing proof-of-concept
  • LWN: Sharing buffers between devices

于是 Sumit Semwal (Linaro) 基于 Marek Szyprowski 的 patch 重构了一套新的框架,也就是我们今天看到的 dma-buf 核心代码,它经历了社区开发人员给出的重重考验,并最终于 2012 年 2 月 merge 到了 Linux-3.3 主线版本中,这也是 dma-buf 的第一个正式版本。此后 dma-buf 被广泛应用于内核多媒体驱动开发中,尤其在 V4L2、DRM 子系统中得到了充分应用。

  • LWN: DMA buffer sharing in 3.3
  • Patch: dma-buf: Documentation for buffer sharing framework
  • Patch: dma-buf: Introduce dma buffer sharing mechanism
  • 第一个使用 dma-buf 的 DRM 分支: drm-prime-dmabuf

概念

dma-buf 的出现就是为了解决各个驱动之间 buffer 共享的问题,因此它本质上是 buffer 与 file 的结合,即 dma-buf 既是块物理 buffer,又是个 linux file。buffer 是内容,file 是媒介,只有通过 file 这个媒介才能实现同一 buffer 在不同驱动之间的流转。

一个典型的 dma-buf 应用框图如下:

通常,我们将分配 buffer 的模块称为 exporter,将使用该 buffer 的模块称为 importeruser。但在本系列文章中,importer 特指内核空间的使用者,user 特指用户空间的使用者。

有的人习惯将 exporter 说成是生产者,importer 说成是消费者,我个人认为这样的说法并不严谨。举例来说,Android 系统中,graphic buffer 都是由 ION 来分配的,GPU 负责填充该 buffer,DPU 负责显示该 buffer。那么在这里,ION 则是 exporter,GPU 和 DPU 则都是 importer。但是从生产者/消费者模型来讲,GPU 则是生产者,DPU 是消费者,因此不能片面的认为 exporter 就是生产者。

最简单的 dma-buf 驱动程序

如下代码演示了如何编写一个最简单的 dma-buf 驱动程序,我将其称为 dummy 驱动,因为它什么事情也不做。注意:该代码已经是精简的不能再精简了,少一行代码都不行!

exporter-dummy.c

#include <linux/dma-buf.h>
#include <linux/module.h>static struct sg_table *exporter_map_dma_buf(struct dma_buf_attachment *attachment,enum dma_data_direction dir)
{return NULL;
}static void exporter_unmap_dma_buf(struct dma_buf_attachment *attachment,struct sg_table *table,enum dma_data_direction dir)
{}static void exporter_release(struct dma_buf *dmabuf)
{}static void *exporter_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num)
{return NULL;
}static void *exporter_kmap(struct dma_buf *dmabuf, unsigned long page_num)
{return NULL;
}static int exporter_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
{return -ENODEV;
}static const struct dma_buf_ops exp_dmabuf_ops = {.map_dma_buf = exporter_map_dma_buf,.unmap_dma_buf = exporter_unmap_dma_buf,.release = exporter_release,.map_atomic = exporter_kmap_atomic,.map = exporter_kmap,.mmap = exporter_mmap,
};static int __init exporter_init(void)
{DEFINE_DMA_BUF_EXPORT_INFO(exp_info);struct dma_buf *dmabuf;exp_info.ops = &exp_dmabuf_ops;exp_info.size = PAGE_SIZE;exp_info.flags = O_CLOEXEC;exp_info.priv = "null";dmabuf = dma_buf_export(&exp_info);return 0;
}module_init(exporter_init);

从上面的代码来看,要实现一个 dma-buf exporter驱动,需要执行3个步骤:

  1. dma_buf_ops
  2. DEFINE_DMA_BUF_EXPORT_INFO
  3. dma_buf_export()

注意: 其中 dma_buf_ops 的回调接口中,如下接口又是必须要实现的,缺少任何一个都将导致 dma_buf_export() 函数调用失败!

  • map_dma_buf
  • unmap_dma_buf
  • map
  • map_atomic
  • mmap
  • release

从 linux-4.19 开始,map_atomic 接口被废弃,map 和 mmap 接口不再被强制要求。

  • dma-buf: make map_atomic and map function pointers optional
  • dma-buf: remove kmap_atomic interface
  • dma-buf: Remove requirement for ops->map() from dma_buf_export
  • dma-buf: Make mmap callback actually optional

开发环境

内核源码 4.14.143
示例源码 hexiaolong2008-GitHub/sample-code/dma-buf/01
开发平台 Ubuntu14.04/16.04
运行平台 my-qemu 仿真环境

编译

dma-buf 的核心代码由 CONFIG_DMA_SHARED_BUFFER 宏来控制是否参与编译,而该 config 并不是一个显式的菜单项,我们无法直接在 menuconfig 菜单中找到它,因此我这里就直接简单粗暴的修改 Kconfig 文件,设置 default y 来实现 dma-buf.c 的强制编译:

linux-4.14.43/drivers/base/Kconfig:

config DMA_SHARED_BUFFERbooldefault y

或者你也可以通过 menuconfig 菜单选择那些依赖 dma-buf 的设备驱动,如 DRM VGEM。

然后编译 exporter_dummy.ko 文件,并打包到 my-qemu 环境中。

运行

在 my-qemu 仿真环境中执行如下命令:

# insmod /lib/modules/4.14.143/kernel/drivers/dma-buf/exporter-dummy.ko
# lsmod
exporter_dummy 16384 1 - Live 0x7f000000

通过如下命令来查看 dma-buf 的相关信息:

# cat /sys/kernel/debug/dma_buf/bufinfo
Dma-buf Objects:
size        flags       mode        count       exp_name
00004096    00000000    00000005    00000001    exporter_dummyAttached Devices:
Total 0 devices attachedTotal 1 objects, 4096 bytes

运行截图:

在实际运行的过程中,细心的小伙伴可能会发现,该 exporter_dummy.ko 只能被 insmod,无法被 rmmod。关于该问题的原因,我将在《dma-buf 由浅入深(五)—— File》中为大家解答。

总结

  1. dma-buf 本质上是 buffer + file 的结合。
  2. 编写 dma-buf 驱动的三个步骤:
    (1)dma_buf_ops
    (2)DEFINE_DMA_BUF_EXPORT_INFO
    (3)dma_buf_export()

通过本篇我们学习了如何编写一个最简单的 dma-buf 驱动程序。但是该驱动什么事情也做不了,因为它的 dma_buf_ops 回调函数都是空的。从下一篇起,我们将一步步实现 dma_buf_ops 的回调函数,让大家一步步的掌握 dma-buf 的使用技巧。

参考资料

敬叶:Linux DMA-BUF

下一篇:《dma-buf 由浅入深(二)—— kmap / vmap》
文章汇总:《DRM(Direct Rendering Manager)学习简介》

dma-buf 由浅入深(一) —— 最简单的 dma-buf 驱动程序相关推荐

  1. 基于设备树的TQ2440 DMA学习(2)—— 简单的DMA传输

    作者 彭东林 pengdonglin137@163.com 平台 TQ2440 Linux-4.9 概述 上一篇博客分析了DMA控制器的寄存器,循序渐进,下面我们直接操作DMA控制器的寄存器实现一个m ...

  2. axi dma 寄存器配置_「STM32」DMA采集单通道,简单数据分析

    什么是DMA DMA,Direct Memory Access,直接内存访问,是一种不经过CPU而直接从内存存取数据的数据交换模式.在DMA模式下,CPU只需要向DMA控制器下达指令,传输数据由DMA ...

  3. PYNQ开发板使用-使用DMA进行数据搬移(Simple DMA transfer 模式)

    该篇是学习使用PYNQ开发板,实际上是对ZYNQ PL端AXI_CDMA 核的应用.实验步骤参照官网的教程,一步一步地做,但是由于在硬件资源布置方面与官方教程稍有出入,所以在SDK的源码里也进行了修改 ...

  4. 【嵌入式12】DMA通信原理及编程实验,DMA方式向上位机连续发送数据

    本文介绍DMS通信原理,STM32采用串口DMA方式,用115200bps或更高速率向上位机连续发送数据. 一.DMA介绍 什么是DMA? DMA介绍 DMA传输方式 DMA传输参数 DMA数据传输的 ...

  5. filter hid_如何构造一个简单的USB过滤驱动程序

    本文分三部分来介绍如何构造一个简单的USB过滤驱动程序,包括"基本原理"."程序的实现"."使用INF安装".此文的目的在于希望读者了解基本 ...

  6. 2021-08-16Zynq linux系统下的AXI DMA驱动与应用程序简单Demo实现

    在参考网友(天使之猜)的例程(https://blog.csdn.net/hello_jinjin/article/details/102058119)中遇到了一些问题,导致内核崩溃. 在英勇无比的网 ...

  7. Linux驱动程序教程:如何编写简单的Linux设备驱动程序

    翻译来自: https://www.apriorit.com/dev-blog/195-simple-driver-for-linux-os 代码下载 此Linux设备驱动程序教程将为您提供有关如何为 ...

  8. 使用Linux编写最简单的hello world驱动程序

    1.前言 我们在学习C语言或着其他语言的时候第一个程序都是打印hello world,所以我们今天学习驱动程序的开发也是使用hello world作为我们的第一个程序. 在开始编程之前我们需要我们需要 ...

  9. Altera Scatter-Gather DMA (SG-DMA)的简单使用

    文章来源:http://www.cnblogs.com/scnutiger/archive/2010/02/06/1664980.html 在Quartus7.2之后的版本中,除了原有的基于avalo ...

  10. DMA简单理解和分享

    一.DMA基本概念 直接存储器访问(Direct Memory Access),简称DMA.DMA是CPU一个用于数据从一个地址空间到另一地址空间"搬运"(拷贝)的组件,数据拷贝过 ...

最新文章

  1. 语义网所谓的“本体”的具体例子是什么?人工智能
  2. TOP (100) PERCENT
  3. Xamarin iOS教程之页面控件
  4. 小波的秘密10_图像处理应用:图像增强
  5. 链路层 ---《TCP/IP协议》卷一
  6. OCA第2部分中的Java难题
  7. python的起源和发展_Python入门第一课——Python的起源、发展与前景!
  8. Spring AOP底层实现原理(动态代理)
  9. Linux 查看CPU信息
  10. android xml 多行注释,C#中的XML多行注释 - 我做错了什么?
  11. linux版本信息i686,Linux下如何查看版本信息
  12. SpringCloud之高可用的分布式配置中心(Spring Cloud Config)(七)
  13. Linux:cpufreq
  14. 计算机多媒体应用软件有超媒体特点吗,《多媒体技术与应用》(本)阶段练习一...
  15. 嵌入式开发辅助工具_JPG图片转HEX工具
  16. 神奇的数字之回文数c语言,奇妙的数字
  17. PLC中如何区分源型漏型
  18. 局域网入侵教程_黑客常用Linux 入侵工具:可获取目标浏览图片的EtterCap
  19. excel转置怎么操作_技能篇:Excel数据处理小技巧
  20. ckfinder java 配置_JAVA里使用CKEditor和CKFinder的配置

热门文章

  1. SEO真的可以刷关键词排名吗?
  2. STM32F0官网固件库
  3. 02.07Center Alignment居中对齐
  4. 内存缓存(from memory cache)和硬盘缓存(from disk cache) 的区别
  5. PHP函数implode()与explode()的用法
  6. 双11增速超天猫 京东已成进口产品首选中国平台
  7. 阿里在职7年高级测试工程师整理出的软件测试自学指南
  8. 关于Socket通信中SOCK_STREAM和SOCK_DGRAM区别
  9. hcip笔记(GRE,MGRE的介绍与配置)
  10. MySQL 5.7.31安装Can‘t change dir to ‘……‘问题解决