Chinaunix首页 | 论坛 | 博客
  • 博客访问: 22210
  • 博文数量: 7
  • 博客积分: 190
  • 博客等级: 入伍新兵
  • 技术积分: 100
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-11 11:02
文章分类
文章存档

2012年(7)

我的朋友

分类: C/C++

2012-06-11 22:35:24

/**

* async_memcpy - attempt to copy memory with a dma engine.

* @dest: destination page

* @src: src page

* @dest_offset: offset into 'dest' to start transaction

* @src_offset: offset into 'src' to start transaction

* @len: length in bytes

* @submit: submission / completion modifiers

*

* honored flags: ASYNC_TX_ACK

*/

首先关注一下入参,类似memcpy的用法,目的page,源page

注意,如果你要copy的数据,不满一个4k页面,就需要指定长度,目的偏移和源地址偏移

需要copy的长度,

唯一和一般memcpy操作不同的是最后一个异步提交管理结构体

struct dma_async_tx_descriptor *

async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,

            unsigned int src_offset, size_t len,

            struct async_submit_ctl *submit)

{

       struct dma_chan *chan = async_tx_find_channel(submit, DMA_MEMCPY,

                                                     &dest, 1, &src, 1, len);

       struct dma_device *device = chan ? chan->device : NULL;

       struct dma_async_tx_descriptor *tx = NULL;

       if (device && is_dma_copy_aligned(device, src_offset, dest_offset, len)) {

               dma_addr_t dma_dest, dma_src;

               unsigned long dma_prep_flags = 0;

               if (submit->cb_fn)

                       dma_prep_flags |= DMA_PREP_INTERRUPT;

               if (submit->flags & ASYNC_TX_FENCE)

                       dma_prep_flags |= DMA_PREP_FENCE;

/* 如果设置了回调,或者FENCE标志,则需要设置不同的标志位 */

               dma_dest = dma_map_page(device->dev, dest, dest_offset, len,

                                       DMA_FROM_DEVICE);

               dma_src = dma_map_page(device->dev, src, src_offset, len,

                                      DMA_TO_DEVICE);

               tx = device->device_prep_dma_memcpy(chan, dma_dest, dma_src,

                                                   len, dma_prep_flags);

       }

       if (tx) {

               pr_debug("%s: (async) len: %zu\n", __func__, len);

               async_tx_submit(chan, tx, submit);

       } else {

               void *dest_buf, *src_buf;

               pr_debug("%s: (sync) len: %zu\n", __func__, len);

               /* wait for any prerequisite operations */

               async_tx_quiesce(&submit->depend_tx);

               dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset;

               src_buf = kmap_atomic(src, KM_USER1) + src_offset;

               memcpy(dest_buf, src_buf, len);

               kunmap_atomic(dest_buf, KM_USER0);

               kunmap_atomic(src_buf, KM_USER1);

               async_tx_sync_epilog(submit);

       }

       return tx;

}

首先注意一下,整个大的流程分成2部分,在接口中首先尝试获取dma驱动注册的设备,如果设备不存在,则使用同步方式也就是用cpu来进行搬运

换句话说,这个时候的async_memcpy和memcpy没有区别。分水岭就在判断tx是否为空上

最开始的时候,先通过async_tx_find_channel查找dma通道,注意这里是抽象概念,原来我们提到过,cpu厂商会提供几个硬件加速的能力

抽象成了通道,而有的厂商通过设置不同的寄存器,可以让通道完成不一样的功能。也有的厂商会写死通道能力,比如0号通道提供xor能力,其他的

通道提供内存加速能力,这些都要去看cpu手册。

然后通过通道找设备,如果设备在的话,注意这里有个判断is_dma_copy_aligned 地址是否对齐。也就是说使用的时候,如果cpu要求对其,则需要小心对齐问题,不然就不会用DMA搬运,而还是cpu搬运。

这里可以看到async_xxx接口屏蔽了cpu的能力,让上层应用,这里主要指的是raid,不需要关注cpu是否有DMA能力。只需要调用async接口就可以

应用处理可以简单很多。

dma_map_page起到的作用是,将应用给的地址,映射到dma设备可以看见的地址。

device_prep_dma_memcpy是调用dma驱动的接口,目的是做一些驱动内部的DMA准备,分配一些资源等等。这个和cpu有关,不一样的cpu,就有不一样的DMA加速驱动,内部实现机制也不同,有的是用中断,有的是发送消息等等,这里让驱动自己去准备。

当一切都正常后,这个接口返回一个dma_async_tx_descriptor,描述符

通过intel在内核中的驱动,Dma_v2.c,我们可以看到这个描述符tx,通常在一个DMA驱动的管理结构体的内部,通过这个tx,驱动可以找到内部管理结构。

当我们判断出tx不是空的时候,最后调用async_tx_submit来提交

菊子曰 这就是啦!
阅读(1791) | 评论(0) | 转发(0) |
0

上一篇:linux 2.6.32 Async_tx代码分析 三

下一篇:没有了

给主人留下些什么吧!~~