为什么要建设应急管理网站,检测软件定制,短网址生成器是什么意思,江西企业网站建设电话为什么要实现自定义AXI DMA驱动
ZYNQ 的 AXI DMA 在 Direct Register DMA #xff08;即 Simple DMA#xff09;模式下可以通过 AXIS 总线的 tlast 提前结束传输#xff0c;同时还可以在 BUFFLEN 寄存器中读取到实际传输的字节数#xff0c;但是通过 Linux 的 DMA 驱动框架…为什么要实现自定义AXI DMA驱动
ZYNQ 的 AXI DMA 在 Direct Register DMA 即 Simple DMA模式下可以通过 AXIS 总线的 tlast 提前结束传输同时还可以在 BUFFLEN 寄存器中读取到实际传输的字节数但是通过 Linux 的 DMA 驱动框架控制 AXI DMA 时无法获取实际传输的字节数因此这里便基于字符设备驱动框架实现一个 AXI DMA 的驱动只支持 Simple 模式。
AXI DMA IP配置 设备树修改
在顶层设备树根节点中加入如下节点 axi_dma_test0: dma_test0{compatible user_axi_dma; /* 用于设备树与驱动进行匹配 */status okay; /* 状态 */interrupt-names mm2s_introut, s2mm_introut; /* 中断名称 */interrupt-parent intc; /* 中断控制器 */interrupts 0 29 4 0 30 4; /* mm2s中断类型、中断号、触发方式s2mm中断类型、中断号、触发方式需要结合Vivado的配置 */reg 0x40400000 0x10000; /* 控制寄存器 */buffer-max 512; /* 收发缓冲区大小不能超过DMA最大传输字节数 */};在顶层设备树中引用axi_dma_0节点并加入如下内容
axi_dma_0 {compatible unused-xlnx-axi-dma-driver; /* 修改compatible属性不使用赛灵思的AXI DMA驱动 */
};
Linux驱动代码
#include linux/init.h
#include linux/kernel.h
#include linux/module.h
#include linux/fs.h
#include linux/cdev.h
#include linux/slab.h
#include linux/device.h
#include linux/uaccess.h
#include linux/io.h
#include linux/poll.h
#include linux/ioport.h
#include linux/miscdevice.h
#include linux/delay.h
#include linux/interrupt.h
#include linux/dma-mapping.h
#include linux/skbuff.h
#include linux/platform_device.h
#include linux/of.h
#include linux/of_address.h
#include linux/of_irq.h#define USER_AXI_DMA_MAX_MINORS 10#define XAXIDMA_CR_OFFSET 0x00000000 /* Channel control */
#define XAXIDMA_SR_OFFSET 0x00000004 /* Status */
#define XAXIDMA_SRCADDR_OFFSET 0x00000018 /* Simple mode source address pointer */
#define XAXIDMA_DESTADDR_OFFSET 0x00000018 /* Simple mode destination address pointer */
#define XAXIDMA_SRCADDR_MSB_OFFSET 0x0000001C /* Simple mode source address pointer */
#define XAXIDMA_BUFFLEN_OFFSET 0x00000028 /* Tail descriptor pointer */#define XAXIDMA_CR_RUNSTOP_MASK 0x00000001 /* Start/stop DMA channel */
#define XAXIDMA_CR_RESET_MASK 0x00000004 /* Reset DMA engine */
#define XAXIDMA_CR_KEYHOLE_MASK 0x00000008 /* Keyhole feature */
#define XAXIDMA_CR_CYCLIC_MASK 0x00000010 /* Cyclic Mode */#define XAXIDMA_IRQ_IOC_MASK 0x00001000 /* Completion intr */
#define XAXIDMA_IRQ_DELAY_MASK 0x00002000 /* Delay interrupt */
#define XAXIDMA_IRQ_ERROR_MASK 0x00004000 /* Error interrupt */
#define XAXIDMA_IRQ_ALL_MASK 0x00007000 /* All interrupts */struct user_axi_dma {//cdev对象struct cdev cdev;//次设备号unsigned long minor;//设备IDdev_t devt;//打开标志atomic_t open_flag;//mm2s等待队列uint32_t mm2s_result;struct wait_queue_head mm2s_wq;//s2mm等待队列struct wait_queue_head s2mm_wq;//s2mm skbuffstruct sk_buff_head s2mm_skbuff;//MM2S的中断号int mm2s_irq;//S2MM的中断号int s2mm_irq;//MM2S中断名称char mm2s_irq_name[32];//S2MM中断名称char s2mm_irq_name[32];//IO内存虚拟地址void __iomem *base_addr;//mm2s bufferuint8_t *mm2s_buffer;dma_addr_t mm2s_phy;//s2mm bufferuint8_t *s2mm_buffer;dma_addr_t s2mm_phy;//DMA缓冲区最大大小uint32_t buffer_max;
};//起始设备号
static dev_t user_axi_dma_major;
//class对象
static struct class *user_axi_dma_class;
//IAD用于管理次设备号
static DEFINE_IDA(user_axi_dma_ida);static void mm2s_transfer(struct user_axi_dma *user_axi_dma, dma_addr_t mm2s_buffer, uint32_t length)
{uint32_t cr_reg;iowrite32(mm2s_buffer, user_axi_dma-base_addr 0x00000000 XAXIDMA_SRCADDR_OFFSET);cr_reg ioread32(user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);iowrite32(cr_reg | XAXIDMA_CR_RUNSTOP_MASK, user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);iowrite32(length, user_axi_dma-base_addr 0x00000000 XAXIDMA_BUFFLEN_OFFSET);
}static void s2mm_transfer(struct user_axi_dma *user_axi_dma, dma_addr_t s2mm_buffer, u32 length)
{uint32_t cr_reg;iowrite32(s2mm_buffer, user_axi_dma-base_addr 0x00000030 XAXIDMA_DESTADDR_OFFSET);cr_reg ioread32(user_axi_dma-base_addr 0x00000030 XAXIDMA_CR_OFFSET);iowrite32(cr_reg | XAXIDMA_CR_RUNSTOP_MASK, user_axi_dma-base_addr 0x00000030 XAXIDMA_CR_OFFSET);iowrite32(length, user_axi_dma-base_addr 0x00000030 XAXIDMA_BUFFLEN_OFFSET);
}static irqreturn_t mm2s_interrupt(int irq, void *d)
{int count;uint32_t irq_status;uint32_t mm2s_cr;uint32_t s2mm_cr;uint32_t mm2s_bufflen;struct user_axi_dma *user_axi_dma d;//读取待处理的中断irq_status ioread32(user_axi_dma-base_addr 0x00000000 XAXIDMA_SR_OFFSET) XAXIDMA_IRQ_ALL_MASK;//确认待处理的中断iowrite32(irq_status XAXIDMA_IRQ_ALL_MASK, user_axi_dma-base_addr 0x00000000 XAXIDMA_SR_OFFSET);//mm2s出错if((irq_status XAXIDMA_IRQ_ERROR_MASK)) {//复位DMA控制器iowrite32(XAXIDMA_CR_RESET_MASK, user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);//等待复位完成for(count 0; count 2000; count){mm2s_cr ioread32(user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);s2mm_cr ioread32(user_axi_dma-base_addr 0x00000030 XAXIDMA_CR_OFFSET);if(((mm2s_cr XAXIDMA_CR_RESET_MASK) 0) ((s2mm_cr XAXIDMA_CR_RESET_MASK) 0))break;}//传输结果为0xFFFFFFFF表示失败user_axi_dma-mm2s_result 0xFFFFFFFF;}else{//获取DMA实际发送长度mm2s_bufflen ioread32(user_axi_dma-base_addr 0x00000000 XAXIDMA_BUFFLEN_OFFSET);//传输结果成功为传输长度失败为0xFFFFFFFFuser_axi_dma-mm2s_result (mm2s_bufflen 0) ? mm2s_bufflen : 0xFFFFFFFF;}//通过等待队列唤醒正在进行写操作的线程wake_up_interruptible(user_axi_dma-mm2s_wq);return IRQ_HANDLED;
}static irqreturn_t s2mm_interrupt(int irq, void *d)
{int count;uint32_t irq_status;uint32_t mm2s_cr;uint32_t s2mm_cr;uint32_t s2mm_bufflen;struct sk_buff *skb;struct user_axi_dma *user_axi_dma d;//读取待处理的中断irq_status ioread32(user_axi_dma-base_addr 0x00000030 XAXIDMA_SR_OFFSET) XAXIDMA_IRQ_ALL_MASK;//确认待处理的中断iowrite32(irq_status XAXIDMA_IRQ_ALL_MASK, user_axi_dma-base_addr 0x00000030 XAXIDMA_SR_OFFSET);//s2mm出错if((irq_status XAXIDMA_IRQ_ERROR_MASK)) {//复位DMA控制器iowrite32(XAXIDMA_CR_RESET_MASK, user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);//等待复位完成for(count 0; count 2000; count){mm2s_cr ioread32(user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);s2mm_cr ioread32(user_axi_dma-base_addr 0x00000030 XAXIDMA_CR_OFFSET);if(((mm2s_cr XAXIDMA_CR_RESET_MASK) 0) ((s2mm_cr XAXIDMA_CR_RESET_MASK) 0))break;}}else{//获取DMA实际接收长度s2mm_bufflen ioread32(user_axi_dma-base_addr 0x00000030 XAXIDMA_BUFFLEN_OFFSET);if(s2mm_bufflen 0)return IRQ_HANDLED;//确保skbuff中最大包含8个skb避免内存消耗过大while(skb_queue_len(user_axi_dma-s2mm_skbuff) 8){skb skb_dequeue(user_axi_dma-s2mm_skbuff);kfree_skb(skb);}//分配skbskb alloc_skb(s2mm_bufflen, GFP_ATOMIC);if(!skb)return IRQ_HANDLED;//将数据拷贝到skpmemcpy(skb_put(skb, s2mm_bufflen), user_axi_dma-s2mm_buffer, s2mm_bufflen);//将skp添加到skp队列skb_queue_tail(user_axi_dma-s2mm_skbuff, skb);//通过等待队列唤醒正在进行读操作的线程wake_up_interruptible(user_axi_dma-s2mm_wq);}//重新启动DMA接收s2mm_transfer(user_axi_dma, user_axi_dma-s2mm_phy, user_axi_dma-buffer_max);return IRQ_HANDLED;
}static int user_axi_dma_open(struct inode *inode, struct file *p_file)
{int result;int count;uint32_t mm2s_cr;uint32_t s2mm_cr;struct sk_buff *skb;struct user_axi_dma *user_axi_dma container_of(inode-i_cdev, struct user_axi_dma, cdev);unsigned long irqflags IRQF_SHARED | IRQF_ONESHOT;//若已经被打开则返回busyif(!atomic_dec_and_test(user_axi_dma-open_flag)){atomic_inc(user_axi_dma-open_flag);return -EBUSY;}//设置文件私有数据p_file-private_data user_axi_dma;//复位skbuffwhile(!skb_queue_empty(user_axi_dma-s2mm_skbuff)){skb skb_dequeue(user_axi_dma-s2mm_skbuff);kfree_skb(skb);}//复位DMA控制器iowrite32(XAXIDMA_CR_RESET_MASK, user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);//等待复位完成for(count 0; count 200; count){mm2s_cr ioread32(user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);s2mm_cr ioread32(user_axi_dma-base_addr 0x00000030 XAXIDMA_CR_OFFSET);if(((mm2s_cr XAXIDMA_CR_RESET_MASK) 0) ((s2mm_cr XAXIDMA_CR_RESET_MASK) 0))break;msleep_interruptible(1);}if(count 200){atomic_inc(user_axi_dma-open_flag);printk(reset dma failed\r\n);return result;}//注册中断snprintf(user_axi_dma-mm2s_irq_name, sizeof(user_axi_dma-mm2s_irq_name), axi-dma%ld-mm2s, user_axi_dma-minor);result request_threaded_irq(user_axi_dma-mm2s_irq, NULL, mm2s_interrupt, irqflags, user_axi_dma-mm2s_irq_name, user_axi_dma);if(result 0){atomic_inc(user_axi_dma-open_flag);printk(request mm2s_irq failed\r\n);return result;}snprintf(user_axi_dma-s2mm_irq_name, sizeof(user_axi_dma-s2mm_irq_name), axi-dma%ld-s2mm, user_axi_dma-minor);result request_threaded_irq(user_axi_dma-s2mm_irq, NULL, s2mm_interrupt, irqflags, user_axi_dma-s2mm_irq_name, user_axi_dma);if(result 0){free_irq(user_axi_dma-mm2s_irq, user_axi_dma);atomic_inc(user_axi_dma-open_flag);printk(request s2mm_irq failed\r\n);return result;}//使能DMA mm2s中断mm2s_cr ioread32(user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);iowrite32(mm2s_cr | XAXIDMA_IRQ_ALL_MASK, user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);//使能DMA s2mm中断s2mm_cr ioread32(user_axi_dma-base_addr 0x00000030 XAXIDMA_CR_OFFSET);iowrite32(s2mm_cr | XAXIDMA_IRQ_ALL_MASK, user_axi_dma-base_addr 0x00000030 XAXIDMA_CR_OFFSET);//启动DMA接收s2mm_transfer(user_axi_dma, user_axi_dma-s2mm_phy, user_axi_dma-buffer_max);return 0;
}static int user_axi_dma_release(struct inode *inode, struct file *p_file)
{int count;uint32_t mm2s_cr;uint32_t s2mm_cr;struct user_axi_dma *user_axi_dma p_file-private_data;//复位DMA控制器iowrite32(XAXIDMA_CR_RESET_MASK, user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);//等待复位完成for(count 0; count 200; count){mm2s_cr ioread32(user_axi_dma-base_addr 0x00000000 XAXIDMA_CR_OFFSET);s2mm_cr ioread32(user_axi_dma-base_addr 0x00000030 XAXIDMA_CR_OFFSET);if(((mm2s_cr XAXIDMA_CR_RESET_MASK) 0) ((s2mm_cr XAXIDMA_CR_RESET_MASK) 0))break;msleep_interruptible(1);}//注销中断free_irq(user_axi_dma-s2mm_irq, user_axi_dma);free_irq(user_axi_dma-mm2s_irq, user_axi_dma);//恢复原子变量的值atomic_set(user_axi_dma-open_flag, 1);return 0;
}static ssize_t user_axi_dma_read(struct file *p_file, char __user *buf, size_t len, loff_t *pos)
{struct sk_buff *skb;struct user_axi_dma *user_axi_dma p_file-private_data;if(skb_queue_empty(user_axi_dma-s2mm_skbuff)){if(p_file-f_flags O_NONBLOCK)return -EAGAIN;if(wait_event_interruptible(user_axi_dma-s2mm_wq, !skb_queue_empty(user_axi_dma-s2mm_skbuff)))return -ERESTARTSYS;}skb skb_dequeue(user_axi_dma-s2mm_skbuff);if(!skb) {printk(read failed, s2mm_skbuff is empty.\n);return -EAGAIN;}len (len skb-len) ? skb-len : len;if(copy_to_user(buf, skb-data, len)){printk(Failed to copy data to user.\n);kfree_skb(skb);return -EFAULT;}kfree_skb(skb);return len;
}static ssize_t user_axi_dma_write(struct file *p_file, const char __user *buf, size_t len, loff_t *pos)
{int result;struct user_axi_dma *user_axi_dma p_file-private_data;//单次传输不能超过FIFO大小len (len user_axi_dma-buffer_max) ? user_axi_dma-buffer_max : len;//将数据拷贝到发送DMA缓冲区if(copy_from_user(user_axi_dma-mm2s_buffer, buf, len) 0){printk(copy to mm2s_buffer failed\r\n);return -EFAULT;}//复位传输结果user_axi_dma-mm2s_result 0;//启动DMA接收mm2s_transfer(user_axi_dma, user_axi_dma-mm2s_phy, user_axi_dma-buffer_max);//等待传输完成result wait_event_interruptible_timeout(user_axi_dma-mm2s_wq, user_axi_dma-mm2s_result, 100);if(result 0){printk(mm2s_transfer timeout\r\n);return -ETIMEDOUT;}else if(result 0){printk(mm2s_transfer break\r\n);return result;}return len;
}static unsigned int user_axi_dma_poll(struct file *p_file, poll_table *wait)
{unsigned int mask 0;struct user_axi_dma *user_axi_dma p_file-private_data;poll_wait(p_file, user_axi_dma-s2mm_wq, wait);if (!skb_queue_empty(user_axi_dma-s2mm_skbuff))mask | POLLIN | POLLRDNORM;return mask;
}static long user_axi_dma_ioctl(struct file *p_file, unsigned int cmd, unsigned long arg)
{struct user_axi_dma *user_axi_dma p_file-private_data;return 0;
}static const struct file_operations user_axi_dma_fops {.owner THIS_MODULE,.open user_axi_dma_open,.release user_axi_dma_release,.read user_axi_dma_read,.write user_axi_dma_write,.poll user_axi_dma_poll,.unlocked_ioctl user_axi_dma_ioctl,
};//设备和驱动匹配成功执行
static int user_axi_dma_probe(struct platform_device *pdev)
{int result;struct device *device;struct user_axi_dma *user_axi_dma;char device_driver_name[128];printk(%s\r\n, __FUNCTION__);//设置SPI设备的DMA寻址范围不然dma_alloc会执行失败pdev-dev.coherent_dma_mask DMA_BIT_MASK(32);//分配设备句柄采用devm_xxx函数申请资源后续可自动释放user_axi_dma devm_kzalloc(pdev-dev, sizeof(struct user_axi_dma), GFP_KERNEL);if (!user_axi_dma){printk(alloc memory failed\r\n);return -ENOMEM;}memset(user_axi_dma, 0, sizeof(struct user_axi_dma));//设置原子变量为1表示未执行open操作atomic_set(user_axi_dma-open_flag, 1);//初始化等待队列user_axi_dma-mm2s_result 0;init_waitqueue_head(user_axi_dma-mm2s_wq);init_waitqueue_head(user_axi_dma-s2mm_wq);//初始化skbuffskb_queue_head_init(user_axi_dma-s2mm_skbuff);//获取缓冲区最大大小result of_property_read_u32_index(pdev-dev.of_node, buffer-max, 0, user_axi_dma-buffer_max);if(result 0){printk(get \buffer-max\ parameter failed\r\n);return result;}//分配mm2s_buffer缓冲帧user_axi_dma-mm2s_buffer dma_alloc_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-mm2s_phy, GFP_KERNEL);if(!user_axi_dma-mm2s_buffer){printk(alloc mm2s_buffer failed\r\n);return -ENOMEM;}memset(user_axi_dma-mm2s_buffer, 0x00, user_axi_dma-buffer_max);//分配s2mm_buffer缓冲帧user_axi_dma-s2mm_buffer dma_alloc_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-s2mm_phy, GFP_KERNEL);if(!user_axi_dma-s2mm_buffer){dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-mm2s_buffer, user_axi_dma-mm2s_phy);printk(alloc s2mm_buffer failed\r\n);return -ENOMEM;}memset(user_axi_dma-s2mm_buffer, 0x00, user_axi_dma-buffer_max);//映射寄存器资源user_axi_dma-base_addr devm_platform_ioremap_resource(pdev, 0);if (IS_ERR(user_axi_dma-base_addr)){dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-s2mm_buffer, user_axi_dma-s2mm_phy);dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-mm2s_buffer, user_axi_dma-mm2s_phy);printk(ioremap reg failed.\n);return PTR_ERR(user_axi_dma-base_addr);}//获取中断号user_axi_dma-mm2s_irq of_irq_get(pdev-dev.of_node, 0);if(user_axi_dma-mm2s_irq 0){dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-s2mm_buffer, user_axi_dma-s2mm_phy);dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-mm2s_buffer, user_axi_dma-mm2s_phy);printk(irq mm2s_irq failed);return user_axi_dma-mm2s_irq;}printk(mm2s_irq:%d\r\n, user_axi_dma-mm2s_irq);user_axi_dma-s2mm_irq of_irq_get(pdev-dev.of_node, 1);if(user_axi_dma-s2mm_irq 0){dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-s2mm_buffer, user_axi_dma-s2mm_phy);dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-mm2s_buffer, user_axi_dma-mm2s_phy);printk(irq s2mm_irq failed);return user_axi_dma-s2mm_irq;}printk(s2mm_irq:%d\r\n, user_axi_dma-s2mm_irq);//分配设备IDresult ida_simple_get(user_axi_dma_ida, 0, USER_AXI_DMA_MAX_MINORS, GFP_KERNEL);if(result 0){dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-s2mm_buffer, user_axi_dma-s2mm_phy);dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-mm2s_buffer, user_axi_dma-mm2s_phy);printk(Not able to get minor id for device.\n);return result;}//合成设备号user_axi_dma-minor result;user_axi_dma-devt MKDEV(MAJOR(user_axi_dma_major), user_axi_dma-minor);//初始化CDEV对象cdev_init(user_axi_dma-cdev, user_axi_dma_fops);user_axi_dma-cdev.owner THIS_MODULE;//向系统添加CDEV对象result cdev_add(user_axi_dma-cdev, user_axi_dma-devt, 1);if(result 0){ida_simple_remove(user_axi_dma_ida, user_axi_dma-minor);dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-s2mm_buffer, user_axi_dma-s2mm_phy);dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-mm2s_buffer, user_axi_dma-mm2s_phy);printk(chardev registration failed.\n);return result;}printk(device major %d, device minor %d, device file name user_axi_dma%ld\r\n,MAJOR(user_axi_dma-devt), MINOR(user_axi_dma-devt), user_axi_dma-minor);//创建设备文件snprintf(device_driver_name, sizeof(device_driver_name), user_axi_dma%ld, user_axi_dma-minor);device device_create(user_axi_dma_class, NULL, user_axi_dma-devt, NULL, device_driver_name);if(IS_ERR(device)){cdev_del(user_axi_dma-cdev);ida_simple_remove(user_axi_dma_ida, user_axi_dma-minor);dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-s2mm_buffer, user_axi_dma-s2mm_phy);dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-mm2s_buffer, user_axi_dma-mm2s_phy);printk(device create failed);return PTR_ERR(device);}//设置平台设备的驱动私有数据dev_set_drvdata(pdev-dev, user_axi_dma);return 0;
}//设备或驱动卸载时执行
static int user_axi_dma_remove(struct platform_device *pdev)
{struct sk_buff *skb;struct user_axi_dma *user_axi_dma dev_get_drvdata(pdev-dev);printk(%s\r\n, __FUNCTION__);if(!user_axi_dma)return 0;//删除设备文件device_destroy(user_axi_dma_class, user_axi_dma-devt);//从内核删除cdev对象cdev_del(user_axi_dma-cdev);//释放设备IDida_simple_remove(user_axi_dma_ida, user_axi_dma-minor);//释放DMA缓冲区dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-s2mm_buffer, user_axi_dma-s2mm_phy);dma_free_wc(pdev-dev, user_axi_dma-buffer_max, user_axi_dma-mm2s_buffer, user_axi_dma-mm2s_phy);//复位skbuffwhile(!skb_queue_empty(user_axi_dma-s2mm_skbuff)){skb skb_dequeue(user_axi_dma-s2mm_skbuff);kfree_skb(skb);}return 0;
}//匹配列表用于设备树和平台驱动匹配
static const struct of_device_id user_axi_dma_of_match[] {{ .compatible user_axi_dma },{ /* Sentinel */ }
};
//平台驱动
struct platform_driver user_axi_dma_drv {.driver {.name user_axi_dma, //平台驱动名称.owner THIS_MODULE,.pm NULL,.of_match_table user_axi_dma_of_match,},.probe user_axi_dma_probe, //设备和驱动匹配成功执行.remove user_axi_dma_remove, //设备或驱动卸载时执行
};static int __init plt_drv_init(void)
{int result;printk(%s\r\n, __FUNCTION__);//根据次设备号起始值动态注册字符设备号result alloc_chrdev_region(user_axi_dma_major, 0, USER_AXI_DMA_MAX_MINORS, char-driver-template);if(result 0){printk(alloc chrdev failed\r\n);return result;}printk(first device major %d, minor %d\r\n, MAJOR(user_axi_dma_major), MINOR(user_axi_dma_major));//创建class对象user_axi_dma_class class_create(THIS_MODULE, led,class);if(IS_ERR(user_axi_dma_class)){unregister_chrdev_region(user_axi_dma_major, USER_AXI_DMA_MAX_MINORS);printk(class create failed);return PTR_ERR(user_axi_dma_class);}//注册平台驱动result platform_driver_register(user_axi_dma_drv);if(result 0){class_destroy(user_axi_dma_class);unregister_chrdev_region(user_axi_dma_major, USER_AXI_DMA_MAX_MINORS);printk(add cdev failed\r\n);return result;}return 0;
}static void __exit plt_drv_exit(void)
{printk(%s\r\n, __FUNCTION__);//注销平台驱动platform_driver_unregister(user_axi_dma_drv);//销毁class对象class_destroy(user_axi_dma_class);//注销字符设备号unregister_chrdev_region(user_axi_dma_major, USER_AXI_DMA_MAX_MINORS);
}module_init(plt_drv_init);
module_exit(plt_drv_exit);MODULE_LICENSE(GPL);
MODULE_AUTHOR(csdn);
MODULE_DESCRIPTION(axi_dma_driver);AXI DMA驱动测试程序
#include stdio.h
#include stdint.h
#include string.h
#include unistd.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include sys/ioctl.h
#include pthread.hstatic int amp_fd;static uint8_t wbuffer[512];
static uint8_t rbuffer[512*2];
static volatile ssize_t read_total 0, write_total 0;
static volatile int cnt 0;void *echo_thread(void *arg)
{int32_t result;ssize_t write_size, read_size;int32_t magic 0;while(1){//填充数据magic;for(int i0; isizeof(wbuffer); i)wbuffer[i] (uint8_t)(magic i);//发送数据result write(amp_fd, wbuffer, sizeof(wbuffer));if(result ! sizeof(wbuffer)){printf(write failed\r\n);continue;}write_size result;write_total write_size;//读取数据memset(rbuffer, 0, sizeof(rbuffer));result read(amp_fd, rbuffer, sizeof(rbuffer));if(result ! write_size){printf(read failed\r\n);continue;}read_size result;read_total read_size;//校验数据是否一致for(int i0; isizeof(wbuffer); i){if(wbuffer[i] ! rbuffer[i]){printf(check out failed\r\n);break;}}cnt;}
}int main(int argc, char *argv[])
{int err;pthread_t thread;char *rpmsg_dev/dev/rpmsg0;if(argc 1)rpmsg_dev argv[1];printf(amp test\r\n);amp_fd open(rpmsg_dev, O_RDWR);if(amp_fd 0){perror(error);return -1;}err pthread_create(thread, NULL, echo_thread, NULL);if(err ! 0){printf(create thread failed, error code %d\r\n, err);return -1;}err pthread_detach(thread);if(err ! 0){printf(thread detach failed, error code %d\r\n, err);return -1;}while(1){sleep(1);printf(read speed %fMB/s\r\n, read_total/1.0f/1024.0f/1024.0f);read_total 0;printf(write speed %fMB/s\r\n, write_total/1.0f/1024.0f/1024.0f);write_total 0;printf(echo count %d\r\n, cnt);cnt 0;}
}