DMA驱动框架流程编写

本文深入探讨Linux设备驱动中的DMA驱动技术,讲解DMA驱动的基本原理及一致性DMA的处理流程,通过实例阐述如何编写DMA驱动框架。
摘要由CSDN通过智能技术生成

本文主要是针对Xilinx DMA驱动流程框架编写
DMA驱动一致性和流式的基本认识
一致性DMA与流式DMA主要是内存的申请方式和访问控制权限不一样
一致性DMA内存申请:
void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);


流式DMA内存申请:
dma_addr_t dma_map_single(struct device *dev, void *buffer, size_t size, enum dma_data_direction direction); 
 如果映射成功,返回的是总线地址,否则返回NULL.最后一个参数DMA的方向,可能取DMA_TO_DEVICE, DMA_FORM_DEVICE, DMA_BIDIRECTIONAL和DMA_NONE


一致性申请的内存区域DMA和CPU能够同时访问,所以可以认为一致性是同步的
流式申请的内存区域DMA和CPU不能同时访问,DMA释放之后CPU才能访问,所以认为是异步的


初始化DMA
(1)dma_cap_zero(mask);
宏定义如下
#define dma_cap_zero(mask) __dma_cap_zero(&(mask))
static inline void __dma_cap_zero(dma_cap_mask_t *dstp)
{
bitmap_zero(dstp->bits, DMA_TX_TYPE_END);
}
将mask清零;
(2)dma_cap_set(DMA_SLAVE | DMA_PRIVATE, mask);
设置mask,DMA传输通道类型
   direction = DMA_DEV_TO_MEM;//DMA传输方向
match = (direction & 0xFF) | XILINX_DMA_IP_DMA;//DMA匹配类型(外设ID)
(3)DMA通道申请
dma_request_channel(mask, axi_adc_filter, &match);
static bool axi_adc_filter(struct dma_chan *chan, void *param)


一致性内存申请
dma_alloc_coherent(rx_dev->dev,AXI_XADC_BUFF_SIZE,&(axi_xadc_dev->dma_dsts),GFP_ATOMIC); 
流式内存映射
axi_xadc_dev->dma_dsts = dma_map_single(rx_dev->dev,axi_xadc_dev->dsts,AXI_XADC_BUFF_SIZE,
DMA_DEV_TO_MEM); 
     一致性内存:设备和CPU能同时访问这块内存,无需担心cache的影响;
流式:DMA必须释放内存之后,CPU才能访问这块内存
设备申请AXI_XADC_BUFF_SIZE字节大小的一致性内存;函数返回两个参数,一个是申请的虚拟内存的首地址;另一个是内存的物理地址保存在axi_xadc_dev->dma_dsts给DMA操作;GFP_ATOMIC为申请的内存flags。
通道的配置
config.coalesc = 1;中断级联门限
config.delay = 0;延时
rx_dev->device_control(axi_xadc_dev->rx_chan, DMA_SLAVE_CONFIG, (unsigned long) &config);
驱动接口函数为:
xilinx_dma_device_control(struct dma_chan *dchan,enum dma_ctrl_cmd cmd, 
unsigned long arg)
     DMA_SLAVE_CONFIG:DMA从配置命令字
     Config:配置参数
获取BD描述符
dmaengine_prep_slave_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
                    enum dma_transfer_direction dir, unsigned long flags)
{
struct scatterlist sg;
sg_init_table(&sg, 1);初始化sg数组
sg_dma_address(&sg) = buf;dma地址
sg_dma_len(&sg) = len;dma数据长度


return chan->device->device_prep_slave_sg(chan, &sg, 1,
 dir, flags, NULL);
}
本文直接调用驱动接口函数
sg_init_table(&axi_xadc_dev->rx_sg, AXI_XADC_BUF_COUNT);
sg_dma_address(&axi_xadc_dev->rx_sg) = axi_xadc_dev->dma_dsts;
sg_dma_len(&axi_xadc_dev->rx_sg) = AXI_XADC_BUFF_SIZE;
device_prep_slave_sg(axi_xadc_dev->rx_chan,
&axi_xadc_dev->rx_sg,
AXI_XADC_BUF_COUNT,
DMA_DEV_TO_MEM,
axi_xadc_dev->flags, NULL);


钩子挂接函数接口为:
static struct dma_async_tx_descriptor * xilinx_dma_prep_slave_sg(
struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
enum dma_transfer_direction direction, unsigned long flags, void *context)
参数说明:struct dma_chan *dchan:DMA通道
 struct scatterlist *sgl:sg数组首地址,头指针
 unsigned int sg_len:sg数组表项个数
 enum dma_transfer_direction direction:枚举类型,传输方向
 unsigned long flags:传输响应标志
{
struct xilinx_dma_desc_hw *hw;
struct xilinx_dma_transfer *t;
<
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值