DMA子是CPU中实现数据传输的一种方式,CPU配置好DMA控制器之后发起数据传输,CPU本身不参与数据传输的动作中去。

DMA种类:
分为外设DMA和DMA控制器。其中外设DMA实现的为特定的外设与内存之间的数据传输,一般是外设向RAM单向传输数据。而DMA控制器则可以实现任意外设与内存之间的数据传输。此时外设跟CPU控制器之间通过流控制信号来保证传输通道的正常运行。

DMA传输的数据宽度不固定。

还可以实现任意长度的burst 操作。burst是DMA控制地址总线自行改变。

DMA也支持分散集合模式,即内存中数据并非连续,而是分配在多个块中,块大小也不一样,这时候DMA可以根据Scatter Gather Descriptors来进行DMA数据传输。

Descriptors是一个单向列表,描述了每块数据的位置和大小还有其他配置。DMA自行解析Descriptors的内容进行数据传输并寻找小一个链表节点,

如果Descriptor 链表是一个循环链接,则传输被叫做环形传输(Cyclic Transfers)。

linux实现了DMA框架,叫做DMA Engine,内核驱动开发者必须按照固定的流程编码才能正确的使用DMA。DMA
Engine提供出来了Slave API供其它内核调用。这些API实现了复杂的scatter gather
传输模式,通过这些API实现DMA传输的驱动被叫做DMA client.

DMA中调用API的顺序为:

DMA通道申请

DMA client的第一步就是要申请DMA 通道,有的DMA client 可能需要申请特殊的通道,而有的DMA client可以申请任意可用的通道。通道申请的API为dma_request_channel 或者他的某一变形API。

struct dma_chan *dma_request_channel(dma_cap_mask_t mask, dma_filter_fn filter_fn, void *filter_param);

其中dma_cap_mask_t是根据dma_cap_sets指定的DMA传输类型。
如:

    dma_cap_mask_t mask;

    dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY,mask);
dma_chan1 = dma_request_channel(mask,0,NULL);

而传输类型具体列为:

enum dma_transaction_type {
DMA_MEMCPY,
DMA_XOR,
DMA_PQ,
DMA_XOR_VAL,
DMA_PQ_VAL,
DMA_MEMSET,
DMA_INTERRUPT,
DMA_SG,
DMA_PRIVATE,
DMA_ASYNC_TX,
DMA_SLAVE,
DMA_CYCLIC,
DMA_INTERLEAVE,
/* last transaction type for creation of the capabilities mask */
DMA_TX_TYPE_END,
};

配置DMA通道

dmaengine_slave_config
static inline int dmaengine_slave_config(struct dma_chan *chan,struct dma_slave_config *config)

获取一个传输描述符

dmaengine_prep_slave_single()

提交传输到挂起队列

dmaengine_submit

发起传输申请

dmaengine_issue_pending调用会从第一个描述符开始进行传输。如果DMA client 驱动有回调函数的话,会在传输完成后执行。

一个简单的DMA传输案例:

#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/moduleparam.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <linux/fs.h>
#include <linux/gfp.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/kdev_t.h>
#include <linux/proc_fs.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/mempool.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <asm/types.h>
#include <asm/io.h>
#include <asm/dma-mapping.h> #define DEST_ADDRESS 0x73800000
#define SRC_ADDRESS 0x10400000 static volatile struct completion comp1;
static volatile struct dma_chan *dma_chan1; static int device_mmap(struct file *file,struct vm_area_struct* vma)
{
int size;
printk("mmap fpga\n");
size=vma->vm_end - vma->vm_start;
if(remap_pfn_range(vma,vma->vm_start,DEST_ADDRESS>>PAGE_SHIFT,0x800000,vma->vm_page_prot))
return -EAGAIN;
return 0;
}
static void dma_complete_func(void *completion)
{
complete(completion);
} struct dma_async_tx_descriptor *tx1 = NULL; static int device_ioctl(struct inode *inode,struct file *file,int num,int param)
{
struct dma_device *dma_dev;
enum dma_ctrl_flags flags;
dma_cookie_t cookie;
dma_dev = dma_chan1->device;
flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SKIP_SRC_UNMAP;
tx1 = dma_dev->device_prep_dma_memcpy(dma_chan1, DEST_ADDRESS,
SRC_ADDRESS+0x40000*param, 0x40000, flags);
if (!tx1) {
printk("Failed to prepare DMA memcpy\n");
return -1;
}
init_completion(&comp1);
tx1->callback = dma_complete_func;
tx1->callback_param = &comp1; cookie = tx1->tx_submit(tx1);
if (dma_submit_error(cookie)) {
printk("Failed to do DMA tx_submit\n");
return -1;
} dma_async_issue_pending(dma_chan1); wait_for_completion(&comp1);
} static struct file_operations fpga_fops =
{
.owner = THIS_MODULE,
.mmap = device_mmap,
.ioctl = device_ioctl,
}; static int __init hello_init (void)
{
dev_t fpga_dev;
struct cdev *fpga_cdev;
struct device *dev;
dma_addr_t dm;
dma_cap_mask_t mask; dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY,mask);
dma_chan1 = dma_request_channel(mask,0,NULL); if(dma_chan1 == 0)
{
printk("fpga:failed to request DMA channel\n");
} if(register_chrdev_region(MKDEV(200,0),1,"fpga"))
{
printk (KERN_INFO "alloc chrdev error.\n");
return -1;
} fpga_cdev=cdev_alloc();
if(!fpga_cdev)
{
printk (KERN_INFO "cdev alloc error.\n");
return -1;
}
fpga_cdev->ops = &fpga_fops;
fpga_cdev->owner = THIS_MODULE; if(cdev_add(fpga_cdev,MKDEV(200,0),1))
{
printk (KERN_INFO "cdev add error.\n");
return -1;
}
printk("fpga driver loaded\n"); return 0; } late_initcall(hello_init);
MODULE_LICENSE("GPL");

dma子系统 dmac的更多相关文章

  1. DMA(直接存储器存取)

    DMA(Direct Memory Access) DMA(Direct Memory Access)即直接存储器存取,是一种快速传送数据的机制. 工作原理 DMA是指外部设备不通过CPU而直接与系统 ...

  2. (转)DMA(Direct Memory Access)

    DMA(Direct Memory Access) DMA(Direct Memory Access)即直接存储器存取,是一种快速传送数据的机制. 工作原理 DMA是指外部设备不通过CPU而直接与系统 ...

  3. 【转】scatterlist && DMA

    原文:scatterlist && DMA DMA是一种无须CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制.使用DMA可以是系统CPU从实际的IO数据传输过程中摆脱出 ...

  4. 如何在WDM中使用xp系统的DMA用来处理数据

    最近做了一款pci的视频采集卡(H264压缩),由于数据传输量比较大,所有想采用dma来传输数据,刚开始感觉很简单,后来感觉还是困难重重. DMA 验证监控直接内存访问 (DMA) 的使用.随着 Wi ...

  5. 基于设备树的TQ2440 DMA学习(1)—— 芯片手册

    作者 彭东林pengdonglin137@163.com 平台 TQ2440内核Linux4.9 概述 一直想抽时间学习一下DMA驱动,今天就以S3C2440为例,这款芯片的DMA控制器足够简单,也比 ...

  6. linux驱动(续)

    网络通信 --> IO多路复用之select.poll.epoll详解 IO多路复用之select.poll.epoll详解      目前支持I/O多路复用的系统调用有 select,psel ...

  7. windbg命令详解

      DLL 该扩展仅在内核模式下使用,即使它是在Ext.dll中的. Windows NT 4.0 Ext.dll Windows 2000 Ext.dll Windows XP和之后 Ext.dll ...

  8. 深入理解CMA【转】

    转自:https://www.csdn.net/article/a/2016-07-07/15839383 摘要:连续内存分配(简称CMA) 是一种用于申请大量的,并且物理上连续的内存块的方法,在LW ...

  9. stm32DMA

    源和目标地址必须按数据传输宽度对齐 支持循环的缓冲器管理 可编程的数据传输数目:最大为65536 每一个通道都有一组寄存器 DMA_CPARx.DMA_CMARx是没有差别的,它们都可以存放外设的地址 ...

随机推荐

  1. Java并发编程(七)-- ThreadLocal

    提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...

  2. 如何查看linux版本信息

    查看系统信息 [root@root]# hostnamectl Static hostname: root Icon name: computer-desktop Chassis: desktop M ...

  3. Ios项目添加Pods

    一.概要 iOS开发时,项目中会引用许多第三方库,CocoaPods(https://github.com/CocoaPods/CocoaPods)可以用来方便的统一管理这些第三方库. 二.安装 由于 ...

  4. 将两个DataTable合并成一个DataTable

    转载自 http://blog.csdn.net/wangxiaojia42121/article/details/53330464 谢谢 //两个结构一样的DT合并DataTable DataTab ...

  5. JS_高程5.引用类型(3)Array类型-检测数组

    1. instanceof操作符(ECMAScript3) 对于一个网页,或者是一个全局作用域而言,使用instanceof操作符来检测数组就可以得到满意的结果. 语法:if(value instan ...

  6. TDG今日成立!

    大家好我们是来自土1603-3的佟天宇.杨子浩.吴强.周泊辰(从左到右) 我们的团队名称是  TDG队 我们的口号是:“Legends Never Die!” 队员简介: 佟天宇 个性:儒雅随和 特长 ...

  7. How to do conditional auto-wiring in Spring?

    ou can implement simple factory bean to do the conditional wiring. Such factory bean can contain com ...

  8. 使用linux kernel代码编译perf工具

    环境:Qemu + ARMv8 perf是一款综合性分析工具,大到系统全局性性能,再小到进程线程级别,甚至到函数及汇编级别. 在内核源码目录下执行编译脚本: #!/bin/bash cross_com ...

  9. iOS10 11跳转系统设置等的URL收集

    Settings App-Prefs:root Settings -> About App-Prefs:root=General&path=About Settings -> Ac ...

  10. Spark2.3(四十二):Spark Streaming和Spark Structured Streaming更新broadcast总结(二)

    本次此时是在SPARK2,3 structured streaming下测试,不过这种方案,在spark2.2 structured streaming下应该也可行(请自行测试).以下是我测试结果: ...