取消
显示结果 
搜索替代 
您的意思是: 
Highlighted
260 次查看
注册日期: ‎06-15-2019

zynq7020-linux系统下DMA驱动收发通道中断申请失败

各位前辈好:小弟的问题是这样:

vivado创建的dma收发测试,BD图如下:

 

20190926121309.png

 

通过petalinux创建工程,导入硬件信息。生成的设备树经过修改接收和发送通道后如下:

        dma@40400000 {

            #dma-cells = <0x1>;

            clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";

            clocks = <0x1 0xf 0x1 0xf 0x1 0xf 0x1 0xf>;

            compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a";

            interrupt-names = "mm2s_introut", "s2mm_introut";

            interrupt-parent = <0x4>;

            interrupts = <0x0 0x1d 0x4 0x0 0x1e 0x4>;

            reg = <0x40400000 0x10000>;

            xlnx,addrwidth = <0x20>;

            xlnx,include-sg;

            xlnx,sg-length-width = <0xe>;

 

            dma-channel@40400000 {

                compatible = "xlnx,axi-dma-mm2s-channel";

                dma-channels = <0x1>;

                interrupts = <0x0 0x1d 0x4>;

                xlnx,datawidth = <0x20>;

                xlnx,device-id = <0x0>;

            };

 

            dma-channel@40400030 {

                compatible = "xlnx,axi-dma-s2mm-channel";

                dma-channels = <0x1>;

                interrupts = <0x0 0x1e 0x4>;

                xlnx,datawidth = <0x20>;

                xlnx,device-id = <0x1>;

            };

        };

    };

驱动代码如下:

/*  axidmatest.c - The simplest kernel module.

 

* Copyright (C) 2013 - 2016 Xilinx, Inc

*

*   This program is free software; you can redistribute it and/or modify

*   it under the terms of the GNU General Public License as published by

*   the Free Software Foundation; either version 2 of the License, or

*   (at your option) any later version.

 

*   This program is distributed in the hope that it will be useful,

*   but WITHOUT ANY WARRANTY; without even the implied warranty of

*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

*   GNU General Public License for more details.

*

*   You should have received a copy of the GNU General Public License along

*   with this program. If not, see <http://www.gnu.org/licenses/>.

 

*/

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/module.h>

#include <linux/slab.h>

#include <linux/io.h>

#include <linux/interrupt.h>

 

#include <linux/of_address.h>

#include <linux/of_device.h>

#include <linux/of_platform.h>

 

 

/* Standard module information, edit as appropriate */

MODULE_LICENSE("GPL");

MODULE_AUTHOR

    ("Xilinx Inc.");

MODULE_DESCRIPTION

    ("axidmatest - loadable module template generated by petalinux-create -t modules");

#define DRIVER_NAME "axidmatest"

#define DRIVER_NAME1 "axidmatest1mm2s"

#define DRIVER_NAME2 "axidmatest2s2mm"

 

/* Simple example of how to receive command line parameters to your module.

   Delete if you don't need them */

unsigned myint = 0xdeadbeef;

char *mystr = "default";

 

module_param(myint, int, S_IRUGO);

module_param(mystr, charp, S_IRUGO);

 

struct axidmatest_local {

int irq;

unsigned long mem_start;

unsigned long mem_end;

void __iomem *base_addr;

};

 

static irqreturn_t axidmatest_irq_mm2s(int irq, void *lp)

{

printk("axidmatest_irq_mm2s interrupt\n");

return IRQ_HANDLED;

}

static irqreturn_t axidmatest_irq_s2mm(int irq, void *lp)

{

printk("axidmatest_irq_s2mm interrupt\n");

return IRQ_HANDLED;

}

 

//DMA 基地址

#define DMA_BASE_ADDR 0X40400000

//DMA MM2S控制寄存器

volatile unsigned int  * mm2s_cr;

#define MM2S_DMACR 0X00000000

//DMA MM2S状态控制寄存器

volatile unsigned int * mm2s_sr;

#define MM2S_DMASR 0X00000004

//DMA MM2S源地址低32位

volatile unsigned int * mm2s_sa;

#define MM2S_SA 0X00000018

//DMA MM2S传输长度(字节)

volatile unsigned int * mm2s_len;

#define MM2S_LENGTH 0X00000028

//DMA S2MM控制寄存器

volatile unsigned int  * s2mm_cr;

#define S2MM_DMACR 0X00000030

//DMA S2MM状态控制寄存器

volatile unsigned int  * s2mm_sr;

#define S2MM_DMASR 0X00000034

//DMA S2MM目标地址低32位

volatile unsigned int  * s2mm_da;

#define S2MM_DA 0X00000048

//DMA S2MM传输长度(字节)

volatile unsigned int  * s2mm_len;

#define S2MM_LENGTH 0X00000058

#define DMA_LENGTH 16384

dma_addr_t axidma_handle;

volatile unsigned int * axidma_addr;

 

/*申请一大块空间

//axidma_handle :  返回地址是物理地址,让dma设备使用

//axidma_addr   : 该地址供系统调用使用,比如*/

//axidma_addr = dma_alloc_coherent(NULL,DMA_LENGTH,&axidma_handle,GFP_KERNEL);

 

static int axidmatest_probe(struct platform_device *pdev)

{

struct resource *r_irq1; /* Interrupt resources */

struct resource *r_irq2; /* Interrupt resources */

struct resource *r_mem1; /* IO mem resources */

struct resource *r_mem2; /* IO mem resources */

struct device *dev = &pdev->dev;

struct axidmatest_local lp1;

struct axidmatest_local lp2;

 

int rc = 0;

 

printk(KERN_EMERG "axidmatest_probe Device Tree Probing\n"); // v

 

dev_info(dev, "Device Tree Probing\n");// v

/* Get iospace for the device */

r_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);

if (!r_mem1) {

dev_err(dev, "invalid address1\n");

return -ENODEV;

}

printk(KERN_EMERG "axidmatest_probe 1 \n");

r_mem2 = platform_get_resource(pdev, IORESOURCE_MEM, 0);

if (!r_mem2) {

dev_err(dev, "invalid address2\n");

return -ENODEV;

}

printk(KERN_EMERG "r_mem1 = %p  \n",r_mem1); // v

printk(KERN_EMERG "r_mem2 = %p \n",r_mem2); // v

 

 

/* Get IRQ for the device */

////////////////////////////////s2mm////////////////////////////////////////

r_irq1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

if (!r_irq1)

{

dev_info(dev, "no IRQ1 found\n");

return 0;

}

printk(KERN_EMERG "axidmatest_probe 8.1 \n");

 

lp1.irq = r_irq1->start;

printk(KERN_EMERG "lp1.irq = %d  \n",lp1.irq); // v

printk(KERN_EMERG "lp1.mem_start = %d  \n",lp1.mem_start);

printk(KERN_EMERG "lp1.mem_end = %d  \n",lp1.mem_end);

printk(KERN_EMERG "lp1.base_addr = %p  \n",lp1.base_addr);

rc = request_irq(lp1.irq, &axidmatest_irq_mm2s, 4, DRIVER_NAME1, &lp1);

if (rc)

{

dev_err(dev, "testmodule1: Could not allocate interrupt %d.\n",

lp1.irq);

goto error3;

}

printk(KERN_EMERG "axidmatest_probe 8.2 \n");

////////////////////////////////mm2s////////////////////////////////////////

r_irq2 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);

if (!r_irq2) {

dev_info(dev, "no IRQ2 found\n");

return 0;

}

printk(KERN_EMERG "axidmatest_probe 8.3 \n");

lp2.irq = r_irq1->start;

printk(KERN_EMERG "lp2.irq = %d  \n",lp2.irq);

printk(KERN_EMERG "lp2.mem_start = %d  \n",lp2.mem_start);

printk(KERN_EMERG "lp2.mem_end = %d  \n",lp2.mem_end);

printk(KERN_EMERG "lp2.base_addr = %p  \n",lp2.base_addr);

//rc = request_irq(lp2.irq, &axidmatest_irq_s2mm, 4, DRIVER_NAME2, &lp2);

rc = request_irq(0x1e, &axidmatest_irq_s2mm, 4, DRIVER_NAME2, &lp2);

if (rc) {

dev_err(dev, "testmodule2: Could not allocate interrupt %d.\n",

lp2.irq);

goto error3;

}

printk(KERN_EMERG "axidmatest_probe 8.4 \n");

 

return 0;

error3:

//free_irq(lp1->irq1, lp1);

//free_irq(lp1->irq2, lp1);

error2:

//release_mem_region(lp1->mem_start, lp1->mem_end - lp1->mem_start + 1);

//release_mem_region(lp1->mem_start, lp1->mem_end - lp2->mem_start + 1);

error1:

//kfree(lp1);

//kfree(lp2);

//dev_set_drvdata(dev, NULL);

return rc;

}

 

static int axidmatest_remove(struct platform_device *pdev)

{

struct device *dev = &pdev->dev;

struct axidmatest_local *lp = dev_get_drvdata(dev);

free_irq(lp->irq, lp);

iounmap(lp->base_addr);

release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);

//kfree(lp1);

dev_set_drvdata(dev, NULL);

return 0;

}

struct of_device_id

{

char name[32];

char type[32];

char compatible[128];

const void *data;

};

 

#define CONFIG_OF

#ifdef CONFIG_OF

static struct of_device_id axidmatest_of_match[] = {

{ .compatible = "xlnx,axi-dma-1.00.a", },

{ .compatible = "xlnx,axi-dma-7.1", },

{ .compatible = "xlnx,axi-dma-mm2s-channel", },

{ .compatible = "xlnx,axi-dma-s2mm-channel", },

{ /* end of list */ },

};

 

#endif

MODULE_DEVICE_TABLE(of, axidmatest_of_match);

static struct platform_driver axidmatest_driver = {

.driver = {

.name = DRIVER_NAME,

.owner = THIS_MODULE,

.of_match_table = axidmatest_of_match,

},

.probe = axidmatest_probe,

.remove = axidmatest_remove,

};

static int __init axidmatest_init(void)

{

printk("<1>Hello module world.\n");

printk("<1>Module parameters were (0x%08x) and \"%s\"\n", myint,

       mystr);

 

return platform_driver_register(&axidmatest_driver);

}

static void __exit axidmatest_exit(void)

{

platform_driver_unregister(&axidmatest_driver);

printk(KERN_ALERT "Goodbye module world.\n");

}

 

module_init(axidmatest_init);

module_exit(axidmatest_exit);

 

问题的现象:

第一个通道mm2s可以申请到中断,第二个s2mm却申请失败,启动信息如下图20190926121834.jpg

 

请问下,是否我的设备树设置的问题,还是驱动编写的问题呢?有什么思路或者建议呢? 非常感谢!!!

0 项奖励
4 条回复4
Highlighted
Xilinx Employee
Xilinx Employee
204 次查看
注册日期: ‎04-15-2011

回复: zynq7020-linux系统下DMA驱动收发通道中断申请失败

Hi,
你用的是什么版本的Petalinux?
你跑Petalinux自带的axidamtest会有同样的问题吗?
https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842337/DMA+Drivers+-+Soft+IPs

我看到你这里面有两个driver, 有点奇怪。
compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a";
-------------------------------------------------------------------------
Don't forget to reply, kudo, and accept as solution.
-------------------------------------------------------------------------
0 项奖励
Highlighted
201 次查看
注册日期: ‎06-15-2019

回复: zynq7020-linux系统下DMA驱动收发通道中断申请失败

petalinux2018.3 内核xlnx2015.1
0 项奖励
Highlighted
Xilinx Employee
Xilinx Employee
194 次查看
注册日期: ‎04-15-2011

回复: zynq7020-linux系统下DMA驱动收发通道中断申请失败

peking428@163.com 

如果你用2018.3 Petalinux去编译2015.1内核,那最直接看到的问题,是生成的dts版本与内核版本不匹配。

你能用2018.3内核试试吗?

另外,你的Vivado版本是多少?我们强烈建议Vivado,Petalinux,kernel版本一致。

-------------------------------------------------------------------------
Don't forget to reply, kudo, and accept as solution.
-------------------------------------------------------------------------
0 项奖励
Highlighted
180 次查看
注册日期: ‎06-15-2019

回复: zynq7020-linux系统下DMA驱动收发通道中断申请失败

感谢你的回复! 我只能用2015.1的内核版本,我们在这个版本上有移植特殊的软件,所以只能用这个版本了
0 项奖励