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缓冲区,可以使用内核提供的已经考虑到一致性的API:

  1. /**
  2. * request_dma - 申请DMA通道
  3. * On certain platforms, we have to allocate an interrupt as well...
  4. */
  5. int request_dma(unsigned int chan, const char *device_id);
  6. /**
  7. * dma_alloc_coherent - allocate consistent memory for DMA
  8. * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  9. * @size: required memory size
  10. * @handle: bus-specific DMA address *
  11. * Allocate some memory for a device for performing DMA. This function
  12. * allocates pages, and will return the CPU-viewed address, and sets @handle
  13. * to be the device-viewed address.
  14. */
  15. void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag)
  16. //申请PCI设备的DMA缓冲区
  17. void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
  18. //释放DMA缓冲区
  19. void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle )
  20. //释放PCI设备的DMA缓冲区
  21. void pci_free_consistent()
  22. /**
  23. * free_dma - 释放DMA通道
  24. * On certain platforms, we have to free interrupt as well...
  25. */
  26. 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. int request_dma(unsigned int chan, const char *device_id);
  6. //映射流式DMA
  7. dma_addr_t dma_map_single(struct device *dev,void *buf, size_t size, enum dma_datadirection direction);
  8. //驱动获得DMA拥有权,通常驱动不该这么做
  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);
  10. //将DMA拥有权还给设备
  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. //去映射流式DMA
  13. dma_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. void free_dma(unsigned int chan);

Linux驱动技术(三) _DMA编程的更多相关文章

  1. Linux驱动技术(三) _DMA编程【转】

    转自:https://www.cnblogs.com/xiaojiang1025/archive/2017/02/11/6389194.html DMA即Direct Memory Access,是一 ...

  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. python高级特性:切片/迭代/列表生成式/生成器

    廖雪峰老师的教程上学来的,地址:python高级特性 下面以几个具体示例演示用法: 一.切片 1.1 利用切片实现trim def trim(s): while s[:1] == " &qu ...

  2. Linux kernel engineer--trace

    http://oliveryang.net/ https://github.com/yangoliver

  3. C#编程(七十一)---------- 自定义特性

    自定义特性 在说自定义之前,有必要先介绍一些基本的概念. 元数据:就是C#中封装的一些类,无法修改,类成员的特性被称为元数据中的注释 1.什么是特性? (1)属性和特性的区别 属性:属性是面向对象思想 ...

  4. 什么叫做GNU

    GNU就是GNU's Not Unix的缩写, GNU 的创始人Stallman 认为UNIX 虽然不是最 好的操作系统,但是至少不会太差,而他自信有能力把UNIX不足的地方加以改进,使它 成为一个优 ...

  5. No module named 'pandas._libs.tslib'

    用pip命令安装: pip install pandas python3的: pip3 install pandas

  6. 你的项目真的需要Session吗? redis保存session性能怎么样?

    在web开发中,Session这个东西一直都很重要,至少伴随我10年之久, 前一段时间发生一个性能问题,因为Redis session 问题,后来想想 其实我的项目session 是不需要的. 先看看 ...

  7. Android之官方导航栏之Toolbar(Toolbar+DrawerLayout+ViewPager+PagerSlidingTabStrip)

    通过前几篇文章,我们对Android的导航栏有了一定的了解认识,本次文章将对Toolbar进行综合应用,主要结合DrawerLayout.ViewPager.PagerSlidingTabStrip一 ...

  8. 从入门到精通Puppet的实践之路

    本文有感于<精通Puppet配置管理工具>在豆瓣上的某些差评而顺手写的书评. 半路出家   故事要从12年初说起.  某天,部门老大让我所在team的老大调研一下当下业界的配置管理工具.于 ...

  9. Android数据库大批量数据插入优化

    对比在android中批量插入数据的3中方式对比(各插入1W条数据所花费的时间): 1. 一个一个插入 public static boolean insert(SQLiteOpenHelper op ...

  10. Android——进程通信/ AIDL/Message相关知识总结贴

    Android多进程通信 http://www.apkbus.com/android-83462-1-1.html Android 跨进程通信(一) http://www.apkbus.com/and ...