首页 > 其他分享 >DMA Engine框架(二)

DMA Engine框架(二)

时间:2024-04-01 10:33:55浏览次数:81  
标签:Engine DMA struct 框架 dma driver controller cookie device

参考资料: Linux内核4.14版本——DMA Engine框架分析(3)_dma controller驱动_dma_cookie_status-CSDN博客 linux内核之dmaengine_dmaengine 总线地址-CSDN博客   

struct dma_device:

struct dma_device{
         struct kref ref;
         unsigned int chancnt;
         unsigned int privatecnt;
         struct list_head channels;            // 链表头,保存着dmac支持的通道
         struct list_head global_node;
         struct dma_filter filter;
         dma_cap_mask_t  cap_mask;                // dmac支持的能力
         enum dma_desc_metadata_mode desc_metadata_modes;
         unsigned short max_xor;
         unsigned short max_pq;
         enum dmaengine_alignment copy_align;
         enum dmaengine_alignment xor_align;
         enum dmaengine_alignment pq_align;
         enum dmaengine_alignment fill_align;
         #define DMA_HAS_PQ_CONTINUE (1 << 15)

         int dev_id;
         struct device *dev;
         struct module *owner;
         struct ida chan_ida;
         struct mutex chan_mutex;        /* to protect chan_ida */

         u32 src_addr_widths;            // dmac支持哪些源地址位宽
         u32 dst_addr_widths;            // dmac支持哪些目的地址位宽
         u32 directions;                // dmac支持的传输方向,DMA_MEM_TO_MEM、DMA_MEM_TO_DEV、DMA_DEV_TO_MEM、DMA_DEV_TO_DEV四种
         u32 min_burst;
         u32 max_burst;
         u32 max_sg_burst;
         bool descriptor_reuse;
         enum dma_residue_granularity residue_granularity;

         int (*device_alloc_chan_resources)(struct dma_chan *chan);        // client驱动调用dma_request_channel时会调用此函数,分配通道资源
         void (*device_free_chan_resources)(struct dma_chan *chan);        // client驱动释放dam_release_channel时将会调用该函数,释放通道资源

         struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)(        
                 struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
                 size_t len, unsigned long flags);                        // dmac内存传输拷贝函数
... ...
         struct dma_async_tx_descriptor *(*device_prep_slave_sg)(
                 struct dma_chan *chan, struct scatterlist *sgl,
                 unsigned int sg_len, enum dma_transfer_direction direction,
                 unsigned long flags, void *context);                    // dmac散列表传输的函数
         struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
                 struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
                 size_t period_len, enum dma_transfer_direction direction,
                 unsigned long flags);                                    // cyclic传输
... ...
         void (*device_caps)(struct dma_chan *chan,
                             struct dma_slave_caps *caps);
         int (*device_config)(struct dma_chan *chan,
                              struct dma_slave_config *config);        // 配置dmac通道,dmaengine_slave_config时回调
         int (*device_pause)(struct dma_chan *chan);                    // 暂停dmac通道的传输,dmaengine_pause时回调
         int (*device_resume)(struct dma_chan *chan);                    // 恢复dmac通道的传输,dmaengine_resume时回调
         int (*device_terminate_all)(struct dma_chan *chan);            // 停止dmac通道中所有的传输(包括pending和正在进行的传输),dmaengine_terminate_all时回调
         void (*device_synchronize)(struct dma_chan *chan);

         enum dma_status (*device_tx_status)(struct dma_chan *chan,
                                             dma_cookie_t cookie,
                                             struct dma_tx_state *txstate);        // 获取dmac通道传输状态
         // 从pending queue中取走第一个传输描述符并启动传输,当传输完成后将会移到列表中下一个传输描述符,可以在中断上下文中使用。dma_async_issue_pending时回调
         void (*device_issue_pending)(struct dma_chan *chan);  
         void (*device_release)(struct dma_device *dev);               // dmac释放
};
device_prep_dma_xxx,同理,client driver通过dmaengine_prep_xxx API获取传输描述符的时候,damengine则会直接回调dma controller driver相应的device_prep_dma_xxx接口。至于要在这些回调函数中做什么事情,dma controller driver自己决定就是了。 device_config,client driver调用dmaengine_slave_config配置dma channel的时候,dmaengine会调用该回调函数,交给dma controller driver处理。 device_pause/device_resume/device_terminate_all,同理,client driver调用dmaengine_pause、dmaengine_resume、dmaengine_terminate_xxx等API的时候,dmaengine会调用相应的回调函数。 device_issue_pending,client driver调用dma_async_issue_pending启动传输的时候,会调用调用该回调函数。  

struct dma_chan:

struct dma_chan {
        struct dma_device *device;        // 指向该channel所在的dmac
        dma_cookie_t cookie;            // client driver以该channel为操作对象获取传输描述符时,dma controller driver返回给client的最后一个cookie
        dma_cookie_t completed_cookie;    // 在这个channel上最后一次完成的传输的cookie。dma controller driver可以在传输完成时调用辅助函数
 
        /* sysfs */
        int chan_id;
        struct dma_chan_dev *dev;
 
        struct list_head device_node;            // 链表node,用于将该channel添加到dma_device的channel列表中
        struct dma_chan_percpu __percpu *local;
        int client_count;
        int table_count;
 
        /* DMA router */
        struct dma_router *router;
        void *route_data;
 
        void *private;
}
 

struct virt_dma_chan:

struct virt_dma_desc {
        struct dma_async_tx_descriptor tx;          // 传输描述符,用于描述一次dma传输
        /* protected by vc.lock */
        struct list_head node;
};
 
struct virt_dma_chan {
        struct dma_chan chan;                        // 一个struct dma_chan类型的变量,用于和client driver打交道(屏蔽物理channel和虚拟channel的差异)
        struct tasklet_struct task;                    // tasklet,用于等待该虚拟channel上传输的完成(由于是虚拟channel,传输完成与否只能由软件判断)
        void (*desc_free)(struct virt_dma_desc *);        
 
        spinlock_t lock;
 
        /* protected by vc.lock */
        struct list_head desc_allocated;        // 保存不同状态下的虚拟channel描述符
        struct list_head desc_submitted;
        struct list_head desc_issued;
        struct list_head desc_completed;
 
        struct virt_dma_desc *cyclic;
};
  damengine直接向dma controller driver提供的API并不多(大部分的逻辑交互都位于struct dma_device结构的回调函数中),主要包括: 1、struct dma_device变量的注册和注销接口
/* include/linux/dmaengine.h */
int dma_async_device_register(struct dma_device *device);
void dma_async_device_unregister(struct dma_device *device);
dma controller driver准备好struct dma_device变量后,可以调用dma_async_device_register将它(controller)注册到kernel中。该接口会对device指针进行一系列的检查,
            然后对其做进一步的初始化,最后会放在一个名称为dma_device_list的全局链表上,以便后面使用。
dma_async_device_unregister,注销接口。

 

2、cookie有关的辅助接口

位于“drivers/dma/dmaengine.h”中,包括
static inline void dma_cookie_init(struct dma_chan *chan)
static inline dma_cookie_t dma_cookie_assign(struct dma_async_tx_descriptor *tx)
static inline void dma_cookie_complete(struct dma_async_tx_descriptor *tx)
static inline enum dma_status dma_cookie_status(struct dma_chan *chan,
                dma_cookie_t cookie, struct dma_tx_state *state)
由于cookie有关的操作,有很多共性,dmaengine就提供了一些通用实现:
void dma_cookie_init,初始化dma channel中的cookie、completed_cookie字段。
dma_cookie_assign,为指针的传输描述(tx)分配一个cookie。
dma_cookie_complete,当某一个传输(tx)完成的时候,可以调用该接口,更新该传输所对应channel的completed_cookie字段。
dma_cookie_status,获取指定channel(chan)上指定cookie的传输状态。

 

3、依赖处理接口
void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
由前面的描述可知,client可以同时提交多个具有依赖关系的dma传输。因此当某个传输结束的时候,dma controller driver需要检查是否有依赖该传输的传输,如果有,则传输之。这个检查并传输的过程,可以借助该接口进行(dma controller driver只需调用即可,省很多事)   4、device tree有关的辅助接口
extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma);
extern struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec, struct of_dma *ofdma);
上面两个接口可用于将client device node中有关dma的字段解析出来,并获取对应的dma channel。  

编写一个dma controller driver的方法和步骤:

编写一个dma controller driver的基本步骤包括(不考虑虚拟channel的情况): 1、定义一个struct dma_device变量,并根据实际的硬件情况,填充其中的关键字段。 2、根据controller支持的channel个数,为每个channel定义一个struct dma_chan变量,进行必要的初始化后,将每个channel都添加到struct dma_device变量的channels链表中。 3、根据硬件特性,实现struct dma_device变量中必要的回调函数(device_alloc_chan_resources/device_free_chan_resources、device_prep_dma_xxx、device_config、device_issue_pending等等)。 4、调用dma_async_device_register将struct dma_device变量注册到kernel中。 5、当client driver申请dma channel时(例如通过device tree中的dma节点获取),dmaengine core会调用dma controller driver的device_alloc_chan_resources函数,controller driver需要在这个接口中奖该channel的资源准备好。 6、当client driver配置某个dma channel时,dmaengine core会调用dma controller driver的device_config函数,controller driver需要在这个函数中将client想配置的内容准备好,以便进行后续的传输。 7、client driver开始一个传输之前,会把传输的信息通过dmaengine_prep_slave_xxx接口交给controller driver,controller driver需要在对应的device_prep_dma_xxx回调中,将这些要传输的内容准备好,并返回给client driver一个传输描述符。 8、然后,client driver会调用dmaengine_submit将该传输提交给controller driver,此时dmaengine会调用controller driver为每个传输描述符所提供的tx_submit回调函数,controller driver需要在这个函数中将描述符挂到该channel对应的传输队列中。 10、client driver开始传输时,会调用dma_async_issue_pending,controller driver需要在对应的回调函数(device_issue_pending)中,依次将队列上所有的传输请求提交给硬件。              

标签:Engine,DMA,struct,框架,dma,driver,controller,cookie,device
From: https://www.cnblogs.com/lethe1203/p/18107899

相关文章

  • DMA pool
    在Linux内核中,用于管理DMA内存池的相关函数通常包含在内核的DMAAPI中。以下是一些常见的DMA内存池管理函数:structdma_pool*dma_pool_create(constchar*name,structdevice*dev,size_tsize,size_talign,size_tallocation);功能:创建一个新的DMA内存池。参数:name:......
  • DMA cache一致性二
    参考资料:宋宝华:那些年你误会的LinuxDMA(关于LinuxDMAZONE和API最透彻的一篇)-CSDN博客https://blog.csdn.net/waterhawk/article/details/50723677https://www.linuxidc.com/Linux/2012-09/69591p2.htm注:本节有一些个人理解,如有误请谅解 dma_alloc_coherent与dma_alloc_wr......
  • Postfix + Dovecot IMAP 服务器的终极指南,完整支持 SPF、DKIM 和 DMARC,以及多域名设
    邮件服务器配置指南本指南将带您完成Postfix+DovecotIMAP服务器的设置,支持SPF、DKIM和DMARC,还将提供多域名配置的额外指导。在本指南中,domain.com将作为您的根域名,mail.domain.com将作为您邮件服务器的主机名。0x01添加DNS记录在您的域名下添加如下DNS记录:mailI......
  • 【前端】layui前端框架学习笔记
    【前端目录贴】参考视频:LayUI参考笔记:https://blog.csdn.net/qq_61313896/category_12432291.html1.介绍官网:http://layui.apixx.net/index.html国人16年开发的框架,拿来即用,门槛低…2.LayUi的安装及使用Layui是一套开源的WebUI组件库,采用自身轻量级模块......
  • 嵌入式软件通用框架
    前言一个好的软件架构,能让代码逻辑更好的理解是如何运行的。在最开始写代码的时候,我总是一股脑的从头写道尾,想到什么功能就写上去。如今工作这么久了,重新审视一下自己的以前的代码和现在的在公司里写的代码,既可以发现:以前的代码很多功能上会出现相关干扰的风险。常用三种架构应......
  • 基于Springboot框架高校学校自习室教室座位预约系统设计与实现(安装部署+源码+文档)
     博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书、P......
  • 【QT+QGIS跨平台编译】045:【netcdf3+Qt跨平台编译】(一套代码、一套框架,跨平台编译)
    点击查看专栏目录文章目录一、NetCDF3介绍二、文件下载三、文件分析四、pro文件五、编译实践一、NetCDF3介绍  NetCDF(NetworkCommonDataForm)是一种用于存储科学数据的文件格式和库。NetCDF3是NetCDF的旧版本,通常指的是NetCDF版本3.x。  以下是......
  • 解析两大Java框架:Spring与Spring Boot的区别
    Spring框架基本介绍Spring是一个开源的Java平台,它最初是为了解决企业级应用开发的复杂性而创建的。作为一个全面的编程和配置模型,Spring提供了一个框架,让开发者可以构建轻量级、松耦合的应用。SpringBoot基本介绍SpringBoot是基于Spring的一个框架,设计理念是简化新Sp......
  • 云计算应用管理(ENGINEER)
    01.如何对磁盘进行分区?答案:fdisk硬盘设备常用于划分MBR分区模式常用交互指令:m列出指令帮助,p查看现有的分区表,n新建分区,d删除分区,q放弃更改并退出,w保存更改并退出最大支持容量为2.2TB的磁盘须创。parted硬盘设备可以创建MBR或者GPT分区模式常用交互指令:mktable......
  • UnrealEngine UnityBuild模式编译第三方代码问题
    UnrealEngine默认开了UnityBuild模式,把多个代码文件合并到一个较大的cpp文件进行编译。这样是为了减少总编译任务数,尽量避免单个编译任务代码内容太少导致在切换任务上消耗太多时间,尤其分布式编译情况下,任务切换成本更高。UnityBuild参考日志1>[22/102]Compile[x64]Module.......