内核中与驱动相关的内存操作之十七(DMA)

1.DMA的宏观理论:

    DMA,即Direct Memory Access,直接内存访问.主要是考虑到RAM和外设之间拷贝大量数据时提升性能的一种硬件策略.数据交互,需要一个数据的源地址和目的地址,类似memcpy()函数.DMA也不能例外,它也必须提供源、目的寄存器,只不过其内部是靠硬件实现的从而达到更高效的数据交互目的而已.这里可以假想DMA是一种数据传输过程中的"桥梁",DMA的源寄存器存放的就是我们要拷贝的数据的开始位置地址,DMA的目的寄存器存放的我们要拷贝数据的目的地址.这样硬件DMA就帮助我们高效完成了数据的传输.

    下面是DMA操作相关的伪代码:

static void DmaCpy(char *src,char *dest)
{
	DmaSrcReg = src;
	DmaDestReg = dest;
	CfgDmaRegs();
}
    比如,我们通过DMA来播放音频文档,其中音频数据源存放在数组ArrayWav,我们要实现播放就需要把这音频数组里面的音频数据丢到IISFIFO里面去.如下:

static void PlayWav(char *wav)
{
    ... ...;
    DmaCpy(wav,iisfiforegs);
    ... ...;
}
    由于DMA是硬件实现的,而且不占用CPU资源,因此,其效率是很高的.一般CPU都提供了几路DMA通道,例如S3C2440就提供了四路DMA Channel.


2.内核中DMA相关:

    DMA属于系统级别的资源,它只是提供一种设备I/O和RAM的硬件数据交互的手段,这里需求注意的是,它不属于类似字符设备、块设备、网络设备这样的外设.这样的外设一般都有一定的功能暴露给用户空间去操作,而DMA都是在默默无闻在内核空间协助完成外设到RAM的数据交互.它相当于CPU的一个助手,它是因为CPU本身的性能而存在,而不是因为用户的功能而存在的.

    也就是说,DMA本身不会有像网卡、串口一样有"常规驱动",它的存在,只是给需要用到DMA传输数据的外设提供了一种更高效的手段而已.当然,具体的外设驱动可以选择不用DMA的.

    

    2-1.DMA和Cache的一致性:

    如果驱动编程中需要用到DMA进行数据交互的话,必须注意DMA和Cache的一致性问题.Cache,即CPU内置的缓存,其功能类似外设RAM,但是Cache被CPU访问更快,它缓存的是最近CPU访问过的指令或数据.DMA传输数据的过程中CPU是不知道的,如果DMA的目的地址和Cache有重叠的时候,Cache里面的数据内容发生变化了,而CPU并不知道,它还是把Cache里面的数据当作RAM中的数据.这样一来,同样一个数据,可能即存在于Cache中,也可能存在于主存RAM中.如果二者并不形成同步逻辑的话,将会引发驱动无法使用.


    2-2.DMA缓冲:

    内存中与外设交互数据的一块区域叫做"DMA缓冲区",即具有DMA能力的内存区域.比如ISA设备,其最前16M的内存区域是具有DMA能力的.DMA缓冲区是内核中实现DMA数据传输有着重要的地位--无论是通过DMA发数据还是通过DMA收数据,DMA缓冲都是必须的"中转环节".

    

    2-2-1.通过DMA往外发数据的流程:

    我们需要通过DMA往外传输数据的时候,大体流程如下:

申请DMA缓冲区
-->
把目标数据(可以是用户空间的数据通过mmap映射下来的)存放到DMA缓冲区
-->
把目标DMA缓冲区的地址转换为设备在总线上的地址
-->
把设备的总线地址告诉DMA,并开启DMA控制器使能.DMA控制器便开始自动传输
-->
DMA传输完毕后,发出一个中断告诉CPU.

    2-2-2.通过DMA接收数据的流程:

    设备到主控的数据通过DMA传输过程(同步):

1. 当一个进程调用 read, 驱动方法分配一个 DMA 缓冲并引导硬件来传输它的数据到那个缓冲. 这个进程被置为睡眠.

2. 硬件写数据到这个 DMA 缓冲并且在它完成时引发一个中断.

3. 中断处理获得输入数据, 确认中断, 并且唤醒进程, 它现在可以读数据了.
    此机制只用到了单一的DMA缓冲.

    设备到主控的数据通过DMA传输过程(异步):

1. 硬件引发一个中断来宣告新数据已经到达.

2. 中断处理分配一个DMA缓冲并且告知硬件在哪里传输数据.

3. 外设写数据到缓冲并且引发另一个中断当完成时.

4. 处理者分派新数据, 唤醒任何相关的进程, 并且负责杂务.

    此机制用到了DMA缓冲队列.

    例如网卡常常期望见到一个在内存中和处理器共享的环形缓冲(常常被称为一个 DMA 的缓冲); 每个到来的报文被放置在环中下一个可用的缓冲, 并且发出一个中断. 驱动接着传递网络本文到内核其他部分并且在环中放置一个新 DMA 缓冲.

    在所有这些情况中的处理的步骤都强调,有效的 DMA 处理依赖中断报告.虽然可能实现 DMA 使用一个轮询驱动,它不可能有意义,因为一个轮询驱动可能浪费 DMA 提供的性能益处超过更容易的处理器驱动的I/O.


    2-3.分配DMA缓存:

    当我们在驱动中需要用到DMA来实现DMA数据的传输时,可以通过函数kmalloc()或get_free_pages()并设置GFP_DMA标志来获取一块具有DMA能力的内存缓冲区.更可读更明了的API如下:

static unsigned long dma_mem_alloc(int size)
{
	int order = get_order(size);
	return __get_dma_pages(GFP_KERNEL, order);
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值