Linux驱动技术(三) _DMA编程

简介:

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来实现三种地址间的转换:

 
 
  1. //虚拟->物理 
  2. virt_to_phys() 
  3. //物理->虚拟 
  4. ioremap() 
  5. //虚拟->总线 
  6. virt_to_bus() 
  7. //总线->虚拟 
  8. bus_to_virt()  

DMA地址掩码

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

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

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

编程流程

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

在内核程序中使用DMA内存的流程

一致性DMA

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

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

流式DMA

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

 
 
  1. /** 
  2.  * request_dma - 申请DMA通道 
  3.  * On certain platforms, we have to allocate an interrupt as well... 
  4.  */ 
  5.  
  6. int request_dma(unsigned int chan, const char *device_id);//映射流式 
  7. DMAdma_addr_t dma_map_single(struct device *dev,void *buf, size_t size, enum dma_datadirection direction);//驱动获得DMA拥有权,通常驱动不该这么做 
  8.  
  9. 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拥有权还给设备 
  10.  
  11. 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);//去映射流式 
  12.  
  13. DMAdma_addr_t dma_unmap_single(struct device *dev,void *buf, size_t size, enum dma_datadirection direction); 
  14. /** 
  15.  * free_dma - 释放DMA通道 
  16.  * On certain platforms, we have to free interrupt as well... 
  17.  */ 
  18.  
  19. void free_dma(unsigned int chan);   




本文作者:佚名
来源:51CTO
目录
相关文章
|
1月前
|
算法 Linux C++
【Linux系统编程】解析获取和设置文件信息与权限的Linux系统调用
【Linux系统编程】解析获取和设置文件信息与权限的Linux系统调用
29 0
|
1月前
|
算法 Linux C++
【Linux系统编程】深入解析Linux中read函数的错误场景
【Linux系统编程】深入解析Linux中read函数的错误场景
205 0
|
1月前
|
Linux API C语言
【Linux系统编程】深入理解Linux 组ID和附属组ID的查询与设置
【Linux系统编程】深入理解Linux 组ID和附属组ID的查询与设置
34 0
【Linux系统编程】深入理解Linux 组ID和附属组ID的查询与设置
|
1月前
|
Linux 数据安全/隐私保护 虚拟化
Linux技术基础(1)——操作系统的安装
本文是龙蜥操作系统(Anolis OS) 8.4 的安装指南,用户可以从[龙蜥社区下载页面](https://openanolis.cn/download)获取ISO镜像。安装方法包括物理机的光驱和USB闪存方式,以及虚拟机中的VMware Workstation Pro设置。安装过程涉及选择语言、配置安装目标、选择软件集合和内核,设置Root密码及创建新用户。安装完成后,可通过文本模式或图形化界面验证系统版本,如Anolis OS 8.4,标志着安装成功。
|
1月前
|
Linux API 调度
Linux系统驱动跟裸机驱动的区别
Linux系统驱动跟裸机驱动的区别
29 0
|
1月前
|
存储 缓存 Linux
【Shell 命令集合 磁盘维护 】Linux 设置和查看硬盘驱动器参数 hdparm命令使用教程
【Shell 命令集合 磁盘维护 】Linux 设置和查看硬盘驱动器参数 hdparm命令使用教程
36 0
|
1月前
|
存储 Linux API
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用(三)
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用
31 1
|
1月前
|
存储 算法 Linux
【Linux系统编程】深入理解Linux目录扫描函数:scandir目录函数(按条件扫描目录
【Linux系统编程】深入理解Linux目录扫描函数:scandir目录函数(按条件扫描目录
39 0
|
1月前
|
存储 算法 Linux
【Linux系统编程】Linux 文件系统探究:深入理解 struct dirent、DIR 和 struct stat结构
【Linux系统编程】Linux 文件系统探究:深入理解 struct dirent、DIR 和 struct stat结构
45 0
|
1天前
|
消息中间件 关系型数据库 MySQL
Linux:开源之魅与编程之道
Linux:开源之魅与编程之道
9 1