dma子系统 dmac
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的更多相关文章
- DMA(直接存储器存取)
DMA(Direct Memory Access) DMA(Direct Memory Access)即直接存储器存取,是一种快速传送数据的机制. 工作原理 DMA是指外部设备不通过CPU而直接与系统 ...
- (转)DMA(Direct Memory Access)
DMA(Direct Memory Access) DMA(Direct Memory Access)即直接存储器存取,是一种快速传送数据的机制. 工作原理 DMA是指外部设备不通过CPU而直接与系统 ...
- 【转】scatterlist && DMA
原文:scatterlist && DMA DMA是一种无须CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制.使用DMA可以是系统CPU从实际的IO数据传输过程中摆脱出 ...
- 如何在WDM中使用xp系统的DMA用来处理数据
最近做了一款pci的视频采集卡(H264压缩),由于数据传输量比较大,所有想采用dma来传输数据,刚开始感觉很简单,后来感觉还是困难重重. DMA 验证监控直接内存访问 (DMA) 的使用.随着 Wi ...
- 基于设备树的TQ2440 DMA学习(1)—— 芯片手册
作者 彭东林pengdonglin137@163.com 平台 TQ2440内核Linux4.9 概述 一直想抽时间学习一下DMA驱动,今天就以S3C2440为例,这款芯片的DMA控制器足够简单,也比 ...
- linux驱动(续)
网络通信 --> IO多路复用之select.poll.epoll详解 IO多路复用之select.poll.epoll详解 目前支持I/O多路复用的系统调用有 select,psel ...
- windbg命令详解
DLL 该扩展仅在内核模式下使用,即使它是在Ext.dll中的. Windows NT 4.0 Ext.dll Windows 2000 Ext.dll Windows XP和之后 Ext.dll ...
- 深入理解CMA【转】
转自:https://www.csdn.net/article/a/2016-07-07/15839383 摘要:连续内存分配(简称CMA) 是一种用于申请大量的,并且物理上连续的内存块的方法,在LW ...
- stm32DMA
源和目标地址必须按数据传输宽度对齐 支持循环的缓冲器管理 可编程的数据传输数目:最大为65536 每一个通道都有一组寄存器 DMA_CPARx.DMA_CMARx是没有差别的,它们都可以存放外设的地址 ...
随机推荐
- 常用的Lambda表达式
Java 8 引入Lambda表达式,对于Java开发人员来说是一大福利,简化了代码,提高了开发效率. 本文主要讲解日常开发中使用频率比较高的几类Lambda表达式. 集合 Lambda表达式的引入 ...
- 2186 ACM 水题 int 向下取整
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2186 扩展: #include <cstdio> 使用floor函数.floor(x)返回的是 ...
- git https 请求报错 504
git https 请求报错 504 原因可能是因为设置了代理,ubuntu/deepin 系统可以检查 /etc/profile ~/.bashrc 内有没有设置 https 的代理. 有的话,去掉 ...
- js权威指南笔记
//如setTimeout的delay参数为0毫秒,那么指定的函数不会立即执行.只会把它放到队列中,等到前面处于等待状态的事件处理 //程序全部执行完成后,再调用它. function invoke( ...
- JSP(7)—EL和JSTL
一.EL表达式: 1.简介:EL全称为Expression Language,原本是JSTL1.0为方便存储数据所定义的语言,当时只能在JSTL标签中 使用,到了JSTL2.0之后,EL已经成为正式纳 ...
- Servlet(11)—客户端跳转和服务端跳转
客户端跳转: 1.链接跳转:< a href="">< /a > 2.表单提交< form>< /form> 3.Response. ...
- MUI学习04-开关按钮
HTML代码如下: <div class="mui-switch"> <div class="mui-switch-handle">&l ...
- 利用百度OCR实现验证码自动识别
在爬取网站的时候都遇到过验证码,那么我们有什么方法让程序自动的识别验证码呢?其实网上已有很多打码平台,但是这些都是需要money.但对于仅仅爬取点数据而接入打码平台实属浪费.所以百度免费ocr正好可以 ...
- python测试开发django-56.模板渲染markdown语法+代码高亮
前言 上一篇已经实现在xadmin后台编辑markdown语法的文档,编辑完成之后发布博客,在前端html能把markdown语法显示出来. 主要思路是先从数据库把markdown的代码读出来,导入m ...
- SharePoint 修改用户属性User Name
前言 最近,碰到一个奇怪的事情,在SharePoint里的用户,如果显示方式显示为登录名(Account)的方式,显示为空.如下图: 1.经过查找,发现是因为用户属性 User name为空造成的,如 ...