DMA即Direct Memory Access,是一种允许外设直接存取内存数据而没有CPU参与的技术,当外设对于该块内存的读写完成之后,DMAC通过中断通知CPU,这种技术多用于对数据量和数据传输速度都有很高要求的外设控制,比如显示设备等。

DMA和Cache一致性

我们知道,为了提高系统运行效率,现代的CPU都采用多级缓存结构,其中就包括使用多级Cache技术来缓存内存中的数据来缓解CPU和内存速度差异问题。在这种前提下,显而易见,如果DMA内存的数据已经被Cache缓存了,而外设又修改了其中的数据,这就会造成Cache数据和内存数据不匹配的问题,即DMA与Cache的一致性问题。为了解决这个问题,最简单的办法就是禁掉对DMA内存的Cache功能,显然,这会导致性能的降低

虚拟地址 VS 物理地址 VS 总线地址

在有MMU的计算机中,CPU看到的是虚拟地址,发给MMU后转换成物理地址,虚拟地址再经过相应的电路转换成总线地址,就是外设看到的地址。所以,DMA外设看到的地址其实是总线地址。Linux内核提供了相应的API来实现三种地址间的转换:

//虚拟->物理
virt_to_phys()
//物理->虚拟
ioremap()//虚拟->总线
virt_to_bus()
//总线->虚拟
bus_to_virt()

DMA地址掩码

DMA外设并不一定能在所有的内存地址上执行DMA操作,此时应该使用DMA地址掩码

int dma_set_mask(struct device *dev,u64 mask);

比如一个只能访问24位地址的DMA外设,就使用dma_set_mask(dev,0xffffff)

编程流程

下面是在内核程序中使用DMA内存的流程:

一致性DMA

如果在驱动中使用DMA缓冲区,可以使用内核提供的已经考虑到一致性的API:

/*** request_dma - 申请DMA通道* On certain platforms, we have to allocate an interrupt as well...*/
int request_dma(unsigned int chan, const char *device_id);/*** dma_alloc_coherent - allocate consistent memory for DMA* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices* @size: required memory size* @handle: bus-specific DMA address ** Allocate some memory for a device for performing DMA.  This function* allocates pages, and will return the CPU-viewed address, and sets @handle* to be the device-viewed address.*/
void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag)//申请PCI设备的DMA缓冲区
void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)//释放DMA缓冲区
void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle )//释放PCI设备的DMA缓冲区
void pci_free_consistent()/*** free_dma - 释放DMA通道* On certain platforms, we have to free interrupt as well...*/
void free_dma(unsigned int chan); 

流式DMA

如果使用应用层的缓冲区建立的DMA申请而不是驱动中的缓冲区,可能仅仅使用kmalloc等函数进行申请,那么就需要使用流式DMA缓冲区,此外,还要解决Cache一致性的问题。


/*** request_dma - 申请DMA通道* On certain platforms, we have to allocate an interrupt as well...*/
int request_dma(unsigned int chan, const char *device_id);//映射流式DMA
dma_addr_t dma_map_single(struct device *dev,void *buf, size_t size, enum dma_datadirection direction);//驱动获得DMA拥有权,通常驱动不该这么做
void dma_sync_single_for_cpu(struct device *dev,dma_addr_t dma_handle_t bus_addr,size_t size, enum dma_data_direction direction);//将DMA拥有权还给设备
void dma_sync_single_for_device(struct device *dev,dma_addr_t dma_handle_t bus_addr,size_t size, enum dma_data_direction direction);//去映射流式DMA
dma_addr_t dma_unmap_single(struct device *dev,void *buf, size_t size, enum dma_datadirection direction);/*** free_dma - 释放DMA通道* On certain platforms, we have to free interrupt as well...*/
void free_dma(unsigned int chan); 

Linux驱动技术(三) _DMA编程相关推荐

  1. Android应用程序访问linux驱动第三步:实现并向系统注册Service

    在学习Android应用程序访问linux驱动时,原博主在第一.二步写得具体详细,但我学到第三步实现并向系统注册Service时,发觉内迷惑和发现几处错误,这里我将我的理解和修改记录下来和大家分享.希 ...

  2. 详解Linux驱动技术(五) _设备阻塞/非阻塞读写

    在Linux驱动程序编写过程中,设备阻塞/非阻塞读写是一种非常重要的技术.它可以实现高效的数据传输和事件处理,提高系统的性能和响应速度.在本文中,我们将深入探讨Linux驱动技术(五) _设备阻塞/非 ...

  3. linux 模块化编译,手把手教Linux驱动1-模块化编程 module

    大家好,从本篇起,一口君将手把手教大家如何来学习Linux驱动,预计会有20篇关于驱动初级部分知识点.本专题会一直更新,有任何疑问,可以留言或者加我微信. Linux的开发者,遍布世界各地,他们相互之 ...

  4. 手把手教Linux驱动1-模块化编程

    大家好,从本篇起,一口君将手把手教大家如何来学习Linux驱动,预计会有20篇关于驱动初级部分知识点.本专题会一直更新,有任何疑问,可以留言或者加我微信. 什么是模块化编程? Linux的开发者,遍布 ...

  5. Linux 驱动开发 三:字符设备驱动框架

    一.参考 (3条消息) Linux 字符设备驱动结构(一)-- cdev 结构体.设备号相关知识解析_知秋一叶-CSDN博客 (3条消息) linux设备驱动框架_不忘初心-CSDN博客_linux设 ...

  6. Linux 驱动开发 三十五:Linux 内核时钟管理

    参考: linux时间管理,时钟中断,系统节拍_u010936265的博客-CSDN博客_系统节拍时钟中断 Linux内核时钟系统和定时器实现_anonymalias的专栏-CSDN博客_linux内 ...

  7. linux服务器开发三(网络编程)

    转载自:http://www.cnblogs.com/zfc2201/archive/2017/05/04/6804990.html 作者:水之原 网络基础 协议的概念 什么是协议 从应用的角度出发, ...

  8. Linux 驱动开发 三十四:Linux 内核定时器原理

    参考文档: <Cortex -A7 MPCore Technical Reference Manual> 中 Chapter 9:Generic Timer. <ARM ® Arch ...

  9. Linux驱动技术(六) _内核中断

    在硬件上,中断源可以通过中断控制器向CPU提交中断,进而引发中断处理程序的执行,不过这种硬件中断体系每一种CPU都不一样,而Linux作为操作系统,需要同时支持这些中断体系,如此一来,Linux中就提 ...

最新文章

  1. 皮一皮:别人都那么努力,你还有什么理由不努力...
  2. WPF DatePicker 默认显示当前时间
  3. JavaScript入门(part2)--JS书写方式及注释
  4. 牙齿间隙变大怎么办_牙齿之间的间隙越来越大怎么办?
  5. git ignore 怎么添加和删除_Git删除已追踪文件,上传大文件到Github
  6. ie浏览器怎么取消代理浏览器_微软和IE渐行渐远,IE浏览器终将成为回忆
  7. 乐pad平板电脑_2020年双十一高性价比平板电脑推荐(包含苹果ipad,安卓华为,微软surface)...
  8. 《HTML5移动Web开发实战》—— 1.6 在移动网站中使用HTML5
  9. LINQ to SQL之使用Lambda Expression批量删除数据
  10. flash json php,php - codeigniter数组json和flashdata - 堆栈内存溢出
  11. paip.c++ bcb string 转换操作大总结.
  12. qt 定义一个长度的数组_6.8 C++字符数组
  13. flush和evit
  14. Aspose.word Java实现html转word,word转html
  15. Zynga公布2020年第四季度及全年财务业绩
  16. 笔记本损耗60 计算机提示,笔记本电池损耗60%多怎么处理!
  17. Tomcat服务器日志输出格式设置
  18. 真假金士顿U盘大拆解
  19. 【开发工具】【memtester】内存测试工具(memtester)的使用
  20. 装好虚拟机后,打开系统有黑屏的一些解决策略

热门文章

  1. 3d max 安装和导入rvt模型失败
  2. nosql数据库学习总结
  3. 一次Rootkit实施失败记(图解)
  4. DirectX9 SDK 下载、安装、VC++开发环境配置、跑通第一个例子
  5. Hadoop 故障整理
  6. Delphi控制Excel输出上标示例
  7. Java CPU占用率高分析
  8. javaweb之Java基础加强
  9. 如何通过阅读英文网站提高英文水平
  10. css圆角矩形及去掉空格属性