本文主要是针对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;
<
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;
<