Linux环境下DMA的研究与应用---饶兵兵(6)

2019-03-16 19:11

武汉科技大学本科毕业设计

在DMA engine遍历通道时会执行这个过滤函数,判断遍历到的通道是否满足用户的需要,该过滤函数只有在满足特定条件下才返回TRUE。

fn_param:过滤函数参数。 2、

释放DMA通道

当任务完成,我们在卸载相关的驱动程序时,我们需要将前面申请的通道释放,释放函数如下:

void dma_release_channel(struct dma_chan *chan) 3、

DMA 驱动操作

在DMA数据准备完成后就可以进入操作DMA设备阶段,调用DMA设备向DMA engine注册的各种类型的操作接口来操作DMA设备。这个阶段DMA设备驱动会将操作的数据填充到DMA硬件能够识别的操作描述符中。在填充的过程中,根据DMA硬件的能力可能需要多个描述符来完成一个DMA操作,这些操作都由DMA设备驱动来完成。操作完成返回一个异步传输描述符tx。如果操作失败则返回NULL。

dev->device_prep_dma_xxx(chan, …);

struct dma_async_tx_descriptor *(*device_prep_dma_xxx)( struct dma_chan *chan, …)

如果返回一个正确的异步传输描述符,就可以将DMA用户的回调函数(如果需要)设置到这个异步传输描述符上,则在这个描述符被完成后,将会调用这个回调函数。

4、

DMA操作回调

在获得了异步传输描述符后,就可以设置回调函数,设置到异步传输描述符(dma_async_tx_descriptor结构)的callback字段。回调函数由DMA使用者提供,其原型如下:

typedef void (*dma_async_tx_callback)(void *dma_async_param) dma_async_param也是由DMA使用者提供,设置到异步传输描述符的callback_param字段。

该回调函数在tasklet环境中被调用。因为DMA异步操作完成并不一定会产生中断,所以也并不是每一个异步传输操作都需要回调函数。反过来说,如果需要回调操作,就必须在DMA驱动操作中设置DMA_PREP_INTERRUPT宏,指示DMA驱动在本次操作后产生一个中断。

5、

DMA操作提交

DMA操作描述符准备后,需要提交给DMA硬件,提交的请求DMA硬件并不知道,只是将通道的pending计数增加,直到后面的发送pending完成。这个过程是调用DMA驱动提供的submit方法来完成的。Submit在DMA驱动初始化时填充到异步描述符的submit函数指针。其原型如下:

dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx)

22

武汉科技大学本科毕业设计

提交返回一个cookie值,这个值用户并不需要关心其内容和含义,只需要了解如果cookie为负值表示操作错误码。如果大于零则是一个DMA请求的cookie。

使用dma_submit_error(cookie)宏来判断cookie是否是失败。 6、

DMA通道发送pending的请求

将一个DMA通道上的pending的请求都提交到DMA硬件来操作。在IOAT驱动中,在提交DMA请求操作阶段,如果pending的请求过多,也会执行发送pending的操作。发送pending的操作DMA engine的函数接口来完成,实际是调用的DMA驱动注册的issue_pending接口。

void dma_async_issue_pending(struct dma_chan *chan) 7、 举类型值。

enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,

dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)

cookie是提交DMA请求操作返回的DMA请求cookie;last和used,正在执行的DMA请求,可以设置为NULL。可用dma_async_is_tx_complete检查DMA驱动内部状态,而不用返回驱动的内部状态值。

8、

DMA操作链

1、IOAT驱动硬件描述符链

IOAT驱动中,硬件描述符在驱动初始化阶段就已经分配,并将DMA描述符组成了描述符环,如下图所示。各种DMA操作循环利用这些描述符。在DMA硬件中,逐个处理DMA描述符,遇到需要触发中断的描述符,DMA硬件产生DMA中断用于提示操作完成。

DMA操作状态查询

一个DMA请求是否完成可以通过下面的接口查询,该接口返回DMA操作状态枚

RRRC/PPCovered by DMACOUNTPZZDescriptor being programedOwned by SW,must not be touched by HWOwned by HW,must not be touched by SWR = retiredC = Current descriptor being processedP = PendingZ = descriptor being modified (not yet pending)

图3.7 DMA硬件描述符环

23

武汉科技大学本科毕业设计

2、异步传输描述符依赖链

与硬件描述符环对应的,异步传输描述符也可以组织成链式操作。如下图所示,在异步传输中支持多个异步传输描述符之间形成一个依赖链。描述符链中的各个请求之间有严格的先后顺序依赖,只有在前一个请求完成后才会进行下一个请求。

Channel mChannel nnextparentnextparentnext

图3.8 异步描述符依赖链

在异步描述符结构中,parent字段指向本请求依赖的请求的异步传输描述符,next字段指向依赖本描述符的下一个异步传输描述符。从图中可以看出,异步描述符链可以跨越多个DMA通道,这样就可以把不同的DMA操作放到一个描述符链中进行。但如果同一个通道具有描述符链所要求的所有功能,最好是将描述符链放到同一个DMA通道中,(这样就不会阻塞通道中的与本描述符链不相关其他请求)。 描述符链需要考虑的问题:

1)同一个通道可以保证依赖关系,不用设置依赖链直接submit。如果在同一通道又存在上一级的依赖链时,为什么不能submit?而只能建立依赖关系放在依赖者后面?(这个问题是通过pending设置位来保证后面的请求可以下发,只要issue_pending就可以将chan上的所有请求下发)。issue_pending只会刷有pending标识的chan,参见ioat2_issue_pending函数,如果有一个依赖关系存在,在依赖没有完成前,pending不会被设置。

2)如果不在同一个通道,又要保证依赖关系,使用switch_channel。Switch channel的操作是在被依赖的chan上插入一个interrupt请求,将新的请求作为interrupt请求的后续依赖请求,只有在interrupt请求完成后才会提交新的请求到自己的chan上。

3.3.3 DMA engine与I/OAT DMA的接口

为了屏蔽各种不同DMA硬件差异,DMA engine将DMA的功能进行了抽象,提取了DMA需要实现的公共功能,而将具体硬件的差异隐藏在DMA硬件驱动中实现。DMA引擎提供给各种不同的DMA硬件驱动的注册和功能接口,DMA引擎通过调用DMA硬件驱动注册的功能函数来操作DMA硬件。

24

武汉科技大学本科毕业设计

1、 IOAT_DMA通道资源分配:

使能channel的中断标志,分配至多达256 个desc并做初始化, 返回分配的desc数:

ioat_dma_alloc_chan_resources(struct dma_chan *chan, struct dma_client *client) 具体完成:

1) 使能channel的错误中断、异常中止和错误发送completion信号(写硬件) 2) 清Channel Error Register

3) 分配至多256个desc,并添加到tmp_list链表 4) 把tmp_list链表添加到ioat_chan->free_desc链表中 5) 把ioat_chan通道中的desc连成环;

6) 分配并映射存放最后一次completion的desc的缓冲区(大小64bit),该地址为用于存放返回completion status

7) 设置返回用于存储writes the completion status的地址(把6得到的地址写硬件) 8) 使能清通道已完成desc的小任务

9) 启动channel,传输一个空的desc(没有数据与地址=0),用于设置通道的desc链表的首地址发给硬件(把描述符环首地址写到硬件中)

10) 返回分配的desc数 2、 释放通道中所有的描述符

static void ioat_dma_free_chan_resources(struct dma_chan *chan) 主要功能如下:

1) 禁止小任务,清除所有已待处理的descriptor 2) RESET 通道(写寄存器)

3) 遍历通道的free descriptor链表,删除表项,释放DMA 缓冲池缓冲区,重 新初始化descriptor链表

4) 释放完成completion status的 DMA 池 5) 清0

3、 IOAT DMA操作状态查询: 判断DMA请求cookie是否已经完成

static enum dma_status ioat_dma_is_complete(

struct dma_chan *chan,dma_cookie_t cookie, dma_cookie_t *done,dma_cookie_t *used)

4、 IOAT DMA 驱动操作:

从chan中获取一个空闲的desc,使用传输的参数做初始化后返回desc->tx。 static struct dma_async_tx_descriptor *ioat3_dma_prep_memcpy(

25

武汉科技大学本科毕业设计

struct dma_chan *chan, dma_addr_t dma_dest, dma_addr_t dma_src, size_t len,

unsigned long flags)

5、 IOAT DMA操作提交:

构建满足IOAT DMA硬件传送大小的desc描述符,若之前的desc量过大,需要拆分,则需要改写回调函数(只最后一个有),若通道上待处理的desc>=4个,马上启动第6步;

static dma_cookie_t ioat3_tx_submit(struct dma_async_tx_descriptor *tx) 1) 根据要传送的数据长度计算需要的desc数量,并做初始化; 2) 设置回调函数

3) new->tx_cnt = desc_count;//完成这次传输使用的desc数量,一个被分成多少个 4) 增加cookie

5) 增加ioat_chan->dmacount和pending数量

6) 通道上待处理的desc>=4个,马上启动第6步issue pending。 6、 IOAT DMA通道发送pending的请求:

写DMACOUNT寄存器: Number of Descriptors to Process,启动DMA channel处理描述符,清channel->pending=0;

static void ioat3_dma_memcpy_issue_pending(struct dma_chan *chan) 7、 IOAT DMA 定时器功能

个人认为定时器的应用是整个贯穿DMA驱动的亮点。它主要实现四个方面的作用: 1) 对used descriptors 资源的回收; 2) 错误的检查,并打印err info; 3) 重启dma channel,完成相关任务; 4) 对环的重塑,合理的利用资源; 函数如下:

static void ioat3_timer_event(unsigned long data) 8、 IOAT DMA tasklet事件

之所以引进这个概念,主要是为了利用软中断延时的功能,对于那些不是那么紧急的中断任务,我们可以将它们提出来,然后放在tasklet队列中,这样有助于提高 CPU的利用率,而在IOAT DMA 代码中主要应用于资源的回收和维护工作。

26


Linux环境下DMA的研究与应用---饶兵兵(6).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:2017-2018中小学教师素质提升计划范文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: