Linux DMA子系统驱动开发

嵌入式技术

1332人已加入

描述

1.概述

DMA(Direct Memory Access)是计算机系统中除了CPU之外可以主动访问计算机系统内存的硬件部件,DMA的主要功能搬移内存数据而不用通过CPU核。

有些CPU会设计通用DMA设备给各外设使用,例如嵌入式CPU的一些低速外设,自身没有设计DMA,为了数据传输的高效,则需要借用通用DMA设备。

对于大多数的高速外设,因其业务特性,是会自己实现相应的DMA组件的,以追求业务最佳性能。

针对通用DMA设备,Linux系统中提供了统一的DMA驱动框架——DMA子系统。

2. DMA类型

DMA从不同的角度可以进行不同的分类:

2.1 DMA mapping方式分类

从DMA mapping方式可以分为2类:

Coherent DMA(一致性DMA)

Coherent DMA访问内存地址时不过cache,是cache-coherence设备,采用Consistent mapping的API进行内存申请;

Streaming DMA(流式DMA)

Streaming DMA在访问内存地址时经过cache,是non-coherence设备,通常采用streaming mapping的API进行内存申请,在单次DMA传输时进行map,在传输完成后进行unmap;

2.2 DMA工作方式分类

从DMA工作方式可以分为2类:

Block DMA

硬件DMA设计为一次访问操作需要连续内存地址空间;

Scatter-Gather DMA

硬件DMA设计为一次访问操作可以访问多个离散的、不连续的内存地址空间,并将不连续地址空间的进行数据组合;

两种类型的DMA明显差异是软件配置给DMA的地址格式不同,Block DMA只需要在寄存器中实现地址寄存器数据长度寄存器即可;但Scatter-Gather DMA需要采用描述符表的方式,描述符表中每一个条目是各离散地址和数据长度,寄存器只需要实现描述符表的基址寄存器。

3. Linux DMA子系统

3.1 DMA子系统框架

DMA子系统是一个相对比较简单的子系统,整个框架比较薄,Linux下DMA子系统的框架图见下图蓝色部分:

Linux

Linux DMA子系统主要有有5部分组成:

dmaengine:

是DMA子系统的核心,为DMA Device Driver提供DMA设备注册的API,为DMA调用者(Device Driver)提供屏蔽DMA设备实现细节的统一接口API;

virt-dma:

为DMA子系统提供虚拟DMA channel的支持;

of-dma:

为DMA子系统提供设备树描述DMA信息传入的支持;

DMA Device Driver:

为DMA设备的驱动程序;

dmatest:

提供dmatest模块测试DMA memcpy, memset, XOR和RAID6 P+Q操作各种长度和各种偏移量进入源和目标缓冲区;

3.2 DMA子系统重要API

此处主要介绍DMA系统为上、下游提供的API,dma-mapping的API此处不做介绍。

3.2.1 Register API

1)dma_async_device_register

将DMA设备驱动注册到dma子系统;

int dma_async_device_register(struct dma_device *device)

2)dma_async_device_unregister

将DMA设备驱动从dma子系统注销;

void dma_async_device_unregister(struct dma_device *device)

3.2.2 DMA调用者(Device Driver)API

1)dma_request_chan

查找并返回与设备关联的设备名为name的DMA通道,这种关联是通过设备树描述实现的。

通过该接口申请的channel是独占的,直到使用dma_release_channel()释放为止。

struct dma_chan *dma_request_chan(struct device *dev, const char *name)

2)dmaengine_slave_config

传递指定的信息给DMA驱动,这些信息大部分已经集成在struct dma_slave_config中赋值;

如果需要传递更多的信息,可以将struct dma_slave_config内嵌到DMA设备的指定结构体中,这种就可以传递更多参数了

int dmaengine_slave_config(struct dma_chan *chan, struct dma_slave_config *config)

3)dmaengine_prep_slave_sg

以散列表的形式传输数据,在调用dmaengine_prep_slave_sg()之前需要使用散列表的映射,并且必须在DMA操作完成之前不能释放。如果需要同步,请调用dma_sync_*_for_*();

struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
      struct dma_chan *chan, struct scatterlist *sgl,
      unsigned int sg_len, enum dma_data_direction direction,
      unsigned long flags);

4)dmaengine_submit

把描述符添加到挂起的队列中来;

dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)

5)dma_async_issue_pending

激活挂起队列中的事务,一旦一个事务完成,队列中的下一个事务就开启,如果设置了回调,还会调用回调以通知完成;

void dma_async_issue_pending(struct dma_chan *chan)

审核编辑:黄飞

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分