转自:https://www.cnblogs.com/xiaojiang1025/archive/2017/02/11/6389194.html

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. Linux驱动技术(三) _DMA编程

    DMA即Direct Memory Access,是一种允许外设直接存取内存数据而没有CPU参与的技术,当外设对于该块内存的读写完成之后,DMAC通过中断通知CPU,这种技术多用于对数据量和数据传输速 ...

  2. 手把手教Linux驱动1-模块化编程,玩转module

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

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

    网络基础 协议的概念 什么是协议 从应用的角度出发,协议可理解为"规则",是数据传输和数据的解释的规则. 假设,A.B双方欲传输文件.规定: 第一次,传输文件名,接收方接收到文件名 ...

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

    等待队列是内核中实现进程调度的一个十分重要的数据结构,其任务是维护一个链表,链表中每一个节点都是一个PCB(进程控制块),内核会将PCB挂在等待队列中的所有进程都调度为睡眠状态,直到某个唤醒的条件发生 ...

  5. Linux驱动技术(八) _并发控制技术

    为了实现对临界资源的有效管理,应用层的程序有原子变量,条件变量,信号量来控制并发,同样的问题也存在与驱动开发中,比如一个驱动同时被多个应用层程序调用,此时驱动中的全局变量会同时属于多个应用层进程的进程 ...

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

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

  7. Linux驱动技术(五) _设备阻塞/非阻塞读写【转】

    转自:http://www.cnblogs.com/xiaojiang1025/p/6377925.html 等待队列是内核中实现进程调度的一个十分重要的数据结构,其任务是维护一个链表,链表中每一个节 ...

  8. Linux驱动技术(一) _内存申请

    先上基础,下图是Linux的内存映射模型,其中体现了Linux内存映射的几个特点: 每一个进程都有自己的进程空间,进程空间的0-3G是用户空间,3G-4G是内核空间 每个进程的用户空间不在同一个物理内 ...

  9. Linux驱动技术(四) _异步通知技术

    异步通知的全称是"信号驱动的异步IO",通过"信号"的方式,放期望获取的资源可用时,驱动会主动通知指定的应用程序,和应用层的"信号"相对应, ...

随机推荐

  1. 批量导入导出站点权限site permissions

    批量导入站点权限   cls $Web = Get-SPWeb "http://16.178.115.14:91/" Get-Content c:\export\account.t ...

  2. emwin之CHECKBOX控件的通知代码的响应规则

    @2018-08-28 [小记] 在 case WM_INIT_DIALOG: 中使用 CHECKBOX_SetState()函数改变了复选框状态,就会产生 WM_NOTIFICATION_VALUE ...

  3. 【转】#pragma pack(push,1)与#pragma pack(1)的区别

    这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n)             作用:C编译器将按照n个字节对 ...

  4. HDU 1069 Monkey and Banana / ZOJ 1093 Monkey and Banana (最长路径)

    HDU 1069 Monkey and Banana / ZOJ 1093 Monkey and Banana (最长路径) Description A group of researchers ar ...

  5. 收藏:SQL Server 数据库改名

    SQL SERVER 2005以前通常使用sp_renameDB存储过程. EXEC sp_renameDB 'oldDB','newDB'   或者:数据库先分离,然后再附加也可以改名. SQL S ...

  6. XML模块(二十四)

    xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代, 大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统 ...

  7. word中批量修改图片大小的两个方法

    前言: 对于把ppt的内容拷贝到word中: 对ppt的一页进行复制,然后粘贴到word中 如果要的是ppt运行过程中的内容,在qq运行的情况下,按Ctrl+Alt+A截屏,按勾,然后可以直接粘贴到w ...

  8. Pentaho data integration(kettle) 在Mac上启动不了

    环境 MacOS Mojave (10.14.1) Pentaho Data Integration 8.2 Java 8 现象 从官方下载下来最新的安装包,解压之后,双击Data Integrati ...

  9. CPU密集型和I/O密集型区别

    CPU密集型 一些进程绝大多数时间在计算上,称为计算密集型(CPU密集型)computer-bound.一些大量循环的代码(例如:图片处理.视频编码.人工智能等)就是CPU密集型. I/O密集型 有一 ...

  10. 如何解决win7系统无法运行cmd命令提示符

    如何解决win7系统无法运行cmd命令提示符   CMD命令可以帮助我们很快的执行所需要的程序命令,可以查询系统中很多的信息和解决系统很多的故障,对我们来说非常方便,但是最近有用户反馈自己win7电脑 ...