【T113 S3】【spi驱动】【DMA 连续内存分配】【dma_alloc_coherent】【失败】
-
项目需要用到spi和FPGA通讯,使用dma物理内存和虚拟内存地址映射,供应用程序直接调用内存。
驱动代码通过了编译,并且在imx6ull上可以跑通,运行在T113上,加载驱动就会报错,报错内容提示:dma物理内存申请失败,没有找到原因。
请大佬提供思路,并留下联系方式,如果能解决,愿意发红包。# insmod fsfpgain.ko [ 1525.955277] fsfpgain_probe [ 1525.958904] fsfpgain major=243, minor=0 [ 1525.965357] *device:0xc4abe400,device:0xbf00237c [ 1525.971775] fsfpgaindev.nd name:fsfpgain@0 [ 1525.972340] fsfpgaindev request cs&irq gpio ok [ 1525.983232] irq_gpio_spi_handler run [ 1525.987790] fsfpgaindev request_threaded_irq ok [ 1525.992980] spi_setup ret:0 [ 1525.996247] fsfpgain probe ok [ 1525.999671] fsfpgain Debug:005 [ 1526.003191] rxvadr:0x0 padr:0x0 [ 1526.006846] rxvadr:0xbf002394 padr:0xbf002398 [ 1526.011832] txvadr:0x0 padr:0x0 [ 1526.015456] 8<--- cut here --- [ 1526.018909] Unable to handle kernel NULL pointer dereference at virtual address 00000008 [ 1526.028004] pgd = 37cc6d18 [ 1526.031038] [00000008] *pgd=44a83835, *pte=00000000, *ppte=00000000 [ 1526.038098] Internal error: Oops: 17 [#1] PREEMPT SMP ARM [ 1526.044155] Modules linked in: fsfpgain(+) [ 1526.048758] CPU: 0 PID: 5484 Comm: insmod Not tainted 5.4.61 #16 [ 1526.055495] Hardware name: Generic DT based system [ 1526.060875] PC is at memcpy+0x48/0x330 [ 1526.065092] LR is at dma_alloc_coherent.constprop.5+0x34/0x68 [fsfpgain] [ 1526.072608] pc : [<c06375a8>] lr : [<bf0009cc>] psr: 20030013 [ 1526.079635] sp : c4b83a14 ip : 00000000 fp : bf00138f [ 1526.085493] r10: c65b4c00 r9 : bf002308 r8 : 00000001 [ 1526.091352] r7 : 00000cc1 r6 : bf002398 r5 : 00000040 r4 : 00000000 [ 1526.098673] r3 : ae70a2b7 r2 : 000001f0 r1 : 00000008 r0 : c4b83a30 [ 1526.105995] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 1526.113999] Control: 10c5387d Table: 44a4406a DAC: 00000051 [ 1526.120444] Process insmod (pid: 5484, stack limit = 0x95a75581) [ 1526.127181] Stack: (0xc4b83a14 to 0xc4b84000) [ 1526.132067] 3a00: 00000040 bf002398 00000cc1 [ 1526.141247] 3a20: 00000001 c4b83a30 00000000 bf0009cc c709d900 c70b9e80 c0b03cc0 00000000 [ 1526.150427] 3a40: 00000000 00000000 c0b02d00 c0142494 c76b7dc0 00000000 00000000 c088c885 [ 1526.159608] 3a60: 00000001 c0a3fd80 00010001 c4b83b10 c4b83a70 c4b83a70 c70b9e80 00000000 [ 1526.168787] 3a80: 00000000 00000000 c76b7d80 c709d914 00000000 00000001 00000000 00000001 [ 1526.177967] 3aa0: c76b13ac 00000000 00000000 00000020 00000000 00000002 00000000 c4b83abc [ 1526.187148] 3ac0: c4b83abc ae70a2b7 00000000 c70b9e80 00000000 c4b83bcb 00000006 00000010 [ 1526.196329] 3ae0: c4b83b0c c0647f68 00002e38 00000000 c4b83b10 ffffffff 00000000 00000000 [ 1526.205510] 3b00: 00000001 00000000 c0b03bc8 31383332 00003031 ae70a2b7 c086923d c0888e4c [ 1526.214690] 3b20: c7061d40 ae70a2b7 c4b82000 c4b83bb4 c4b83bcb c4b83bb8 ffffffff c08476e4 [ 1526.223870] 3b40: c4b83b64 c4b83bd1 c4b83bb8 c064a374 00000609 ffff0a10 c0b03bc8 00000001 [ 1526.233052] 3b60: 0007b36e 00000600 ffff0a10 ae70a2b7 00000001 c0b03bc8 c0b6d248 c060ef5c [ 1526.242233] 3b80: c4b83b90 c0636820 c0b03bc8 c0636868 8dcd23b7 ae70a2b7 c0b80ae4 00000060 [ 1526.251414] 3ba0: 000026d1 c03bdba0 c4b83bb8 c0636820 c0b03bc8 c0636868 8dcd2cda ae70a2b7 [ 1526.260595] 3bc0: c0b80ae4 00000060 000026d1 c03bdba0 c0b80ae4 00000001 20030093 c0b0bc5c [ 1526.269776] 3be0: 20030093 c0652c74 c0b0bc5c 00000000 c0b67a40 c014e67c c0b67534 00000000 [ 1526.278957] 3c00: 00000000 c06531a8 c0b67530 c0155e24 00000400 c0b0bc5c 00000187 00000000 [ 1526.288137] 3c20: 60030013 60030013 00000187 00000000 c086922c c0851b4e 00000001 c0a39428 [ 1526.297314] 3c40: c76b142c c018bf3c c0a3942c 00000014 60030013 c01572d8 00000001 c01574cc [ 1526.306495] 3c60: bf00153a c4b83cbc 000000eb 00000001 c643fa3c c0b03bc8 bf002300 00000000 [ 1526.315673] 3c80: 00000000 00000001 bf002308 c65b4c00 bf00138f c0157518 bf00153a c4b83cbc [ 1526.324850] 3ca0: 00000040 bf002398 00000cc1 ae70a2b7 bf002300 bf002300 bf002300 00000000 [ 1526.334027] 3cc0: 00000000 bf000880 bf00147d bf002308 c0895157 bf002100 00000007 bf002000 [ 1526.343204] 3ce0: c65b4c00 00000000 bf002010 c0b8134c 00000007 00000000 c4b83f38 c041f0a4 [ 1526.352381] 3d00: c65b4c00 00000000 c0b81350 c03d1e8c c65b4c00 bf002010 bf002010 c03d250c [ 1526.361558] 3d20: 00000000 c4bc7064 00000848 c03d2320 bf002010 c65b4c00 ae70a2b7 00000000 [ 1526.370734] 3d40: c65b4c00 bf002010 c03d250c 00000000 c4bc7064 c03d24f4 00000000 c65b4c00 [ 1526.379912] 3d60: bf002010 c03d25b8 c65b4c00 c0b03bc8 bf002010 c03d0400 c738d6bc c738d6a8 [ 1526.389089] 3d80: c657fab4 ae70a2b7 c738d6bc bf002010 00000000 c49bcc80 c0b3e520 c03d131c [ 1526.398266] 3da0: bf0015e1 00000001 00000000 bf002010 c0b65000 c0b03bc8 bf005000 c03d2d98 [ 1526.407444] 3dc0: ffffe000 c0b65000 c0b03bc8 bf005010 ffffe000 c0102f60 c086922c c0a428e0 [ 1526.416621] 3de0: c7002200 60040013 00000cc0 c01897b0 c4b83e18 00000000 c4b83f38 c01d3e60 [ 1526.425798] 3e00: 00000000 c7002200 00000cc0 c01897b0 c4b82000 c01d4254 c08b1b2c bf002100 [ 1526.434975] 3e20: 00000001 ae70a2b7 bf002100 00000001 c4bc7180 c4bc7040 00000001 c01897ec [ 1526.444152] 3e40: bf002100 00000001 bf002100 00000001 bf002148 c0188430 bf00210c 00007fff [ 1526.453329] 3e60: bf002100 c0185b18 c4bc7064 c96a4300 c4bc7048 00000124 01c8d008 00000000 [ 1526.462505] 3e80: 00000000 00000000 00000cc0 ae70a2b7 bf000000 c499f700 00000000 00000000 [ 1526.471681] 3ea0: 00000000 00000000 00000000 00000000 6e72656b 00006c65 00000000 00000000 [ 1526.480855] 3ec0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 1526.490030] 3ee0: 00000000 00000000 00000000 ae70a2b7 7fffffff 00000000 c0b03bc8 01c8d008 [ 1526.499207] 3f00: 00000003 c0101228 c4b82000 0000017b 00000000 c0188af0 7fffffff 00000000 [ 1526.508383] 3f20: 00000003 c01d56f8 00000001 c9677000 0002d328 00000000 c9677e44 c96782c0 [ 1526.517560] 3f40: c9677000 0002d328 c96a3ab8 c9698682 c96991e0 00003000 000033c0 00001de8 [ 1526.526737] 3f60: 000035a5 00000000 00000000 00000000 00001dd8 00000034 00000035 0000001e [ 1526.535914] 3f80: 00000000 00000019 00000000 ae70a2b7 0000002d 01c8d008 bec2df27 bec2de24 [ 1526.545091] 3fa0: 0000017b c0101000 01c8d008 bec2df27 00000003 01c8d008 00000000 bec2df27 [ 1526.554268] 3fc0: 01c8d008 bec2df27 bec2de24 0000017b bec2df27 00000000 b6fb8000 00000000 [ 1526.563446] 3fe0: bec2dc88 bec2dc78 00026fb8 b6f14242 80040030 00000003 00000000 00000000 [ 1526.572635] [<c06375a8>] (memcpy) from [<bf0009cc>] (dma_alloc_coherent.constprop.5+0x34/0x68 [fsfpgain]) [ 1526.583386] [<bf0009cc>] (dma_alloc_coherent.constprop.5 [fsfpgain]) from [<bf000880>] (fsfpgain_probe+0x290/0x3a8 [fsfpgain]) [ 1526.596181] [<bf000880>] (fsfpgain_probe [fsfpgain]) from [<c041f0a4>] (spi_drv_probe+0x78/0xa0) [ 1526.606051] [<c041f0a4>] (spi_drv_probe) from [<c03d1e8c>] (really_probe+0x168/0x394) [ 1526.614844] [<c03d1e8c>] (really_probe) from [<c03d2320>] (driver_probe_device+0x10c/0x154) [ 1526.624237] [<c03d2320>] (driver_probe_device) from [<c03d24f4>] (device_driver_attach+0x44/0x5c) [ 1526.634196] [<c03d24f4>] (device_driver_attach) from [<c03d25b8>] (__driver_attach+0xac/0xb8) [ 1526.643780] [<c03d25b8>] (__driver_attach) from [<c03d0400>] (bus_for_each_dev+0x64/0xa0) [ 1526.652981] [<c03d0400>] (bus_for_each_dev) from [<c03d131c>] (bus_add_driver+0xdc/0x1bc) [ 1526.662172] [<c03d131c>] (bus_add_driver) from [<c03d2d98>] (driver_register+0xb0/0xf8) [ 1526.671169] [<c03d2d98>] (driver_register) from [<bf005010>] (fsfpgain_init+0x10/0x1000 [fsfpgain]) [ 1526.681332] [<bf005010>] (fsfpgain_init [fsfpgain]) from [<c0102f60>] (do_one_initcall+0x70/0x194) [ 1526.691390] [<c0102f60>] (do_one_initcall) from [<c01897ec>] (do_init_module+0x54/0x1dc) [ 1526.700476] [<c01897ec>] (do_init_module) from [<c0188430>] (load_module+0x18f4/0x1dd4) [ 1526.709459] [<c0188430>] (load_module) from [<c0188af0>] (sys_finit_module+0x94/0xb4) [ 1526.718251] [<c0188af0>] (sys_finit_module) from [<c0101000>] (ret_fast_syscall+0x0/0x54) [ 1526.727424] Exception stack(0xc4b83fa8 to 0xc4b83ff0) [ 1526.733092] 3fa0: 01c8d008 bec2df27 00000003 01c8d008 00000000 bec2df27 [ 1526.742269] 3fc0: 01c8d008 bec2df27 bec2de24 0000017b bec2df27 00000000 b6fb8000 00000000 [ 1526.751443] 3fe0: bec2dc88 bec2dc78 00026fb8 b6f14242 [ 1526.757112] Code: ba000002 f5d1f03c f5d1f05c f5d1f07c (e8b151f8) [ 1526.764119] ---[ end trace c5b41e868c50cbd3 ]--- Segmentation fault
驱动入库程序如下:
#include "fsfpgain.h" static int fsfpgain_open(struct inode *inode, struct file *filp) { if (atomic_dec_and_test(&valid))//原子操作 唯一应用打开驱动 { return 0; } atomic_inc(&valid); return -EBUSY; } static int fsfpgain_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off) { } static long fsfpgain_ioctl(struct file *file, uint32_t cmd, unsigned long arg) { } static int fsfpgain_mmap(struct file *filp, struct vm_area_struct *vma) { return ret; } static int fsfpgain_release(struct inode *inode, struct file *filp) { valid.counter =1;//open函数访问,原子锁初始化 return 0; } static void init_p_buf_cut(void) { } static void spi_fpga_recv(struct buffer_cut *_p, int _no) { } static irqreturn_t irq_gpio_spi_handler(int irq, void *dev_id) { } static irqreturn_t irq_gpio_spi_thread_func(int irq, void *data) { } static const struct file_operations fsfpgain_fops = { .owner = THIS_MODULE, .open = fsfpgain_open, .read = fsfpgain_read, .release= fsfpgain_release, .unlocked_ioctl = fsfpgain_ioctl, .mmap = fsfpgain_mmap, }; static int fsfpgain_probe(struct spi_device *spi) { int ret = 0; valid.counter =1;//open函数访问,原子锁初始化 //valid = ATOMIC_INIT(1); printk("fsfpgain_probe\r\n"); fsfpgaindev.major = 0; if(fsfpgaindev.major) { fsfpgaindev.devid = MKDEV(fsfpgaindev.major, 0); ret = register_chrdev_region(fsfpgaindev.devid, FSFPGAIN_CNT, FSFPGAIN_NAME); }else{ ret = alloc_chrdev_region(&fsfpgaindev.devid, 0, FSFPGAIN_CNT, FSFPGAIN_NAME); fsfpgaindev.major = MAJOR(fsfpgaindev.devid); fsfpgaindev.minor = MINOR(fsfpgaindev.devid); } if(ret < 0) { printk("fsfpgain chrdev_region err!\r\n"); goto fail_devid; } printk("fsfpgain major=%d, minor=%d\r\n", fsfpgaindev.major, fsfpgaindev.minor); fsfpgaindev.cdev.owner = THIS_MODULE; /* 2、注册设备 */ cdev_init(&fsfpgaindev.cdev, &fsfpgain_fops); ret = cdev_add(&fsfpgaindev.cdev, fsfpgaindev.devid, FSFPGAIN_CNT); if(0 > ret) { goto fail_cdev; } /* 3、创建类 */ fsfpgaindev.class = class_create(THIS_MODULE, FSFPGAIN_NAME); if(IS_ERR(fsfpgaindev.class)) { ret = PTR_ERR(fsfpgaindev.device); goto fail_class; } /* 4、创建设备 */ fsfpgaindev.device = device_create(fsfpgaindev.class, NULL, fsfpgaindev.devid, NULL, FSFPGAIN_NAME); if(IS_ERR(fsfpgaindev.device)){ ret = PTR_ERR(fsfpgaindev.device); goto fail_device; } printk("*device:0x%x,device:0x%x\r\n",fsfpgaindev.device,&fsfpgaindev.device); //get nd //fsfpgaindev.nd = of_get_parent(spi->dev.of_node); fsfpgaindev.nd = spi->dev.of_node; if(NULL == fsfpgaindev.nd){ printk("fsfpgaindev.nd get error\r\n"); goto fail_gpio; }else{ printk("fsfpgaindev.nd name:%s", fsfpgaindev.nd->full_name); } fsfpgaindev.cs_gpio = of_get_named_gpio(fsfpgaindev.nd, "cs-gpio", 0); fsfpgaindev.irq_gpio = of_get_named_gpio(fsfpgaindev.nd, "irq-gpio", 0); if (fsfpgaindev.cs_gpio < 0) { printk("fsfpgaindev.cs_gpio get error\r\n"); goto fail_gpio; /* code */ } if (fsfpgaindev.irq_gpio < 0) { printk("fsfpgaindev.irq_gpio get error\r\n"); goto fail_gpio; /* code */ } //注册gpio gpio_request(fsfpgaindev.cs_gpio, "cs_gpio"); gpio_request(fsfpgaindev.irq_gpio, "irq_gpio"); printk("fsfpgaindev request cs&irq gpio ok\r\n"); //set gpio ret = gpio_direction_output(fsfpgaindev.cs_gpio, 1); ret = gpio_direction_input(fsfpgaindev.irq_gpio); //get irq num fsfpgaindev.irq_num = gpio_to_irq(fsfpgaindev.irq_gpio); //注册中断 线程化 //ret = request_irq(fsfpgaindev.irq_num, irq_gpio_spi_handler, IRQF_TRIGGER_FALLING, "irq_gpio", &fsfpgaindev); ret = request_threaded_irq(fsfpgaindev.irq_num, irq_gpio_spi_handler,irq_gpio_spi_thread_func,IRQF_TRIGGER_RISING, "irq_gpio", &fsfpgaindev); if(0 > ret) { printk("request_irq error\r\n"); goto fail_irq; } printk("fsfpgaindev request_threaded_irq ok\r\n"); //init spi spi->mode = SPI_MODE_1; ret = spi_setup(spi); printk("spi_setup ret:%d\r\n",ret); //set privete fsfpgaindev.private_data = spi; fsfpgaindev.b_workflag = 0;//初始化工作状态为不工作 fsfpgaindev.send_data_len = 0;//初始化spi收发数据长度为0 fsfpgaindev.recv_buf_no = 0; fsfpgaindev.read_buf_no = 0; fsfpgaindev.copy_recv_buf_no = 0; printk("fsfpgain probe ok\r\n"); memset(&fsfpgaindev,0,sizeof(fsfpgaindev)); printk("fsfpgain Debug:005\r\n"); printk("rxvadr:0x%lx padr:0x%x\r\n",(long)fsfpgaindev.rxbuf.v_adr,fsfpgaindev.rxbuf.p_adr); printk("rxvadr:0x%lx padr:0x%x\r\n",(long)&fsfpgaindev.rxbuf.v_adr,&fsfpgaindev.rxbuf.p_adr); printk("txvadr:0x%lx padr:0x%x\r\n",(long)fsfpgaindev.txbuf.v_adr,fsfpgaindev.txbuf.p_adr); fsfpgaindev.rxbuf.v_adr = dma_alloc_coherent(NULL,64,&fsfpgaindev.rxbuf.p_adr,GFP_KERNEL|GFP_DMA); fsfpgaindev.txbuf.v_adr = dma_alloc_coherent(NULL,32,&fsfpgaindev.txbuf.p_adr,GFP_KERNEL|GFP_DMA); if((0x00000000 != fsfpgaindev.rxbuf.v_adr) & (0x00000000 != fsfpgaindev.txbuf.v_adr)) { printk("dma_alloc_coherent ok\r\n"); printk("rxvadr:0x%lx padr:0x%x\r\n",(long)fsfpgaindev.rxbuf.v_adr,fsfpgaindev.rxbuf.p_adr); printk("txvadr:0x%lx padr:0x%x\r\n",(long)fsfpgaindev.txbuf.v_adr,fsfpgaindev.txbuf.p_adr); } else{ printk("dma_alloc_coherent return NULL\r\n"); return -1; }//申请大内存 return ret; fail_irq: gpio_free(fsfpgaindev.cs_gpio); gpio_free(fsfpgaindev.irq_gpio); fail_gpio: fail_device: device_destroy(fsfpgaindev.class, fsfpgaindev.devid); fail_class: class_destroy(fsfpgaindev.class); fail_cdev: cdev_del(&fsfpgaindev.cdev); fail_devid: unregister_chrdev_region(fsfpgaindev.devid,FSFPGAIN_CNT); printk("fsfpgain probe error\r\n"); return ret; } static int fsfpgain_remove(struct spi_device *spi) { int ret = 0; //free irq free_irq(fsfpgaindev.irq_num, &fsfpgaindev); //gpio reset gpio_direction_output(fsfpgaindev.cs_gpio, 0); gpio_direction_output(fsfpgaindev.irq_gpio, 0); //gpio free gpio_free(fsfpgaindev.cs_gpio); gpio_free(fsfpgaindev.irq_gpio); cdev_del(&fsfpgaindev.cdev); unregister_chrdev_region(fsfpgaindev.devid,FSFPGAIN_CNT); device_destroy(fsfpgaindev.class, fsfpgaindev.devid); class_destroy(fsfpgaindev.class); printk("fsfpgain_remove\r\n"); return ret; } //传统匹配 struct spi_device_id fsfpgain_id[] = { {"fsfpgain", 0}, {} }; //设备树匹配 static const struct of_device_id fsfpgain_of_match[] = { { .compatible = "fsfpgain",}, {} }; struct spi_driver fsfpgain = { .probe = fsfpgain_probe, .remove = fsfpgain_remove, .id_table = fsfpgain_id, .driver = { .name = "fsfpgain", .owner = THIS_MODULE, .of_match_table = fsfpgain_of_match, }, }; //入口函数 static int __init fsfpgain_init(void) { int ret = 0; //申请大内存 //of_dma_configure(); //struct device *dev = fsfpgain.dev; ret = spi_register_driver(&fsfpgain); printk("fsfpgain_init spi_register_driver return:%d\r\n", ret); return ret; } //出口函数 static void __exit fsfpgain_exit(void) { //释放大内存 printk("rxvadr:0x%lx padr:0x%x\r\n",(long)fsfpgaindev.rxbuf.v_adr,fsfpgaindev.rxbuf.p_adr); printk("txvadr:0x%lx padr:0x%x\r\n",(long)fsfpgaindev.txbuf.v_adr,fsfpgaindev.txbuf.p_adr); dma_free_coherent(NULL,DMAC_MAX_TRF_SIZE*DMA_RECV_MAX_NUM,fsfpgaindev.rxbuf.v_adr, fsfpgaindev.rxbuf.p_adr); dma_free_coherent(NULL,DMAC_MAX_TRF_SIZE*DMA_RECV_MAX_NUM,fsfpgaindev.txbuf.v_adr, fsfpgaindev.txbuf.p_adr); printk("rxvadr:0x%lx padr:0x%x\r\n",(long)fsfpgaindev.rxbuf.v_adr,fsfpgaindev.rxbuf.p_adr); printk("txvadr:0x%lx padr:0x%x\r\n",(long)fsfpgaindev.txbuf.v_adr,fsfpgaindev.txbuf.p_adr); spi_unregister_driver(&fsfpgain); printk("fsfpgain_exit\r\n"); } module_init(fsfpgain_init); module_exit(fsfpgain_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("fsml"); MODULE_DESCRIPTION("fsfpgain t113 module"); MODULE_VERSION("v2.0.0.0");
头文件如下:
#ifndef ___FSFPGAIN_H #define ___FSFPGAIN_H #include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/gpio.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/of_gpio.h> #include <linux/semaphore.h> #include <linux/timer.h> #include <linux/spi/spi.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/atomic.h> #include <linux/irq.h> //#include <linux/irqreturn.h> #include <linux/of_irq.h> #include <asm/mach/map.h> #include <asm/uaccess.h> #include <asm/io.h> //#define _DEBUG //#define _DEBUGWZG #define DMAC_CNLL_MAX_NUM 16 #define DMAC_ONE_TR_NUM 3200 //3000 #define DMAC_MAX_TRF_SIZE DMAC_CNLL_MAX_NUM*DMAC_ONE_TR_NUM #define DMA_RECV_MAX_NUM 10//环形缓冲器大小 #define NEXT_BUF(x) (((x+1) < DMA_RECV_MAX_NUM) ? (x+1) : 0) #define FSFPGAIN_CNT 1 #define FSFPGAIN_NAME "fsfpgain@0" struct mem_addr{ char* v_adr; dma_addr_t p_adr; }; //环形缓冲器,分块保存每个dma头物理地址 struct buffer_cut{ unsigned int recv_num; unsigned int last_buf_len;//最后一块内存的长度 dma_addr_t pr_buf_fpga[DMA_RECV_MAX_NUM][DMAC_CNLL_MAX_NUM]; dma_addr_t pt_buf_fpga[DMA_RECV_MAX_NUM][DMAC_CNLL_MAX_NUM]; }; struct fsfpgain_dev { int major; int minor; dev_t devid; struct cdev cdev; struct class *class; struct device *device; struct spi_device *private_data; int cs_gpio; //io1 20片选引脚 int irq_gpio;//io1 30中断引脚 int irq_num; //中断号 struct device_node *nd;//设备树节点 struct mem_addr rxbuf; struct mem_addr txbuf; struct spi_message m; struct spi_transfer t; int spi_len;//spi dma 单次长度 bool b_workflag;//工作状态 bool b_printk;//调试打印状态 unsigned int send_data_len;//与fpga通讯一次交换数据的长度 struct semaphore spi_sema;//信号量 表示环形缓冲区内的可读数据量 int recv_buf_no;//接收到的数据块号码 int copy_recv_buf_no;//被复制的“接收到的数据块号码”防止被中断修改数据 int read_buf_no;//可读取的数据块号码 //struct tasklet_struct tasklet;//中断下半部 }; //_p 环形缓冲器指针数组结构体 _no环形缓冲器编号 //完成一次从fpga读取数据 static void spi_fpga_recv(struct buffer_cut *_p, int _no); /*调用一次dma spi传输,启动dma要求长度是32的倍数 **0 == _len % 32 */ //static int spi_dma_recv(void *_ptx,void *_prx, unsigned int _len); //中断上半部,使用中断线程化,上半部可有可无,非必须 static irqreturn_t irq_gpio_spi_handler(int irq, void *dev_id); /*初始化缓冲器指针数组结构体 **驱动被板载ioctl设置fpga传输长度后,就可以把环形缓冲器每次传输的头地址设置好 **后期使用不再计算 */ static void init_p_buf_cut(void); //中断下半部处理,调用一次spi收发函数 //没有使用dma接收完成中断,使用imx自带的dma驱动,将其放入线程,不影响板载程序调用,待测试效果 static irqreturn_t irq_gpio_spi_thread_func(int irq, void *data); static struct fsfpgain_dev fsfpgaindev; static struct buffer_cut buf_cut; static atomic_t valid;//原子操作 唯一应用打开驱动 irq_handler_t (*handler)(int, void*); #endif
-
参考 G2D 驱动做下修改
lichee/linux-5.4/drivers/char/sunxi_g2d/g2d_rcq/g2d.c
void *g2d_malloc(__u32 bytes_num, __u32 *phy_addr) { void *address = NULL; #if defined(CONFIG_ION) u32 actual_bytes; if (bytes_num != 0) { actual_bytes = G2D_BYTE_ALIGN(bytes_num); address = dma_alloc_coherent(para.dev, actual_bytes, (dma_addr_t *) phy_addr, GFP_KERNEL); if (address) { return address; } G2D_ERR_MSG("dma_alloc_coherent fail, size=0x%x\n", bytes_num); return NULL; } G2D_ERR_MSG("size is zero\n"); #else unsigned int map_size = 0; struct page *page; if (bytes_num != 0) { map_size = PAGE_ALIGN(bytes_num); page = alloc_pages(GFP_KERNEL, get_order(map_size)); if (page != NULL) { address = page_address(page); if (address == NULL) { free_pages((unsigned long)(page), get_order(map_size)); G2D_ERR_MSG("page_address fail!\n"); return NULL; } *phy_addr = virt_to_phys(address); return address; } G2D_ERR_MSG("alloc_pages fail!\n"); return NULL; } G2D_ERR_MSG("size is zero\n"); #endif return NULL; }
目前看到 dma_alloc_coherent(NULL, xxx...) 的第一个参数是NULL,正常来说应该分配设备而不是NULL。
-
@awwwwa 谢谢老师,我尝试一下,我之前也看到过这个地方的问题,也有说第一个参数可以为NULL,我也传入过spidev->dev,现象一样,我测试下您发的驱动参考。
-
@awwwwa 在 【T113 S3】【spi驱动】【DMA 连续内存分配】【dma_alloc_coherent】【失败】 中说:
参考 G2D 驱动做下修改
lichee/linux-5.4/drivers/char/sunxi_g2d/g2d_rcq/g2d.c
void *g2d_malloc(__u32 bytes_num, __u32 *phy_addr) { void *address = NULL; #if defined(CONFIG_ION) u32 actual_bytes; if (bytes_num != 0) { actual_bytes = G2D_BYTE_ALIGN(bytes_num); address = dma_alloc_coherent(para.dev, actual_bytes, (dma_addr_t *) phy_addr, GFP_KERNEL); if (address) { return address; } G2D_ERR_MSG("dma_alloc_coherent fail, size=0x%x\n", bytes_num); return NULL; } G2D_ERR_MSG("size is zero\n"); #else unsigned int map_size = 0; struct page *page; if (bytes_num != 0) { map_size = PAGE_ALIGN(bytes_num); page = alloc_pages(GFP_KERNEL, get_order(map_size)); if (page != NULL) { address = page_address(page); if (address == NULL) { free_pages((unsigned long)(page), get_order(map_size)); G2D_ERR_MSG("page_address fail!\n"); return NULL; } *phy_addr = virt_to_phys(address); return address; } G2D_ERR_MSG("alloc_pages fail!\n"); return NULL; } G2D_ERR_MSG("size is zero\n"); #endif return NULL; }
目前看到 dma_alloc_coherent(NULL, xxx...) 的第一个参数是NULL,正常来说应该分配设备而不是NULL。
我尝试了把fsfpgaindev.device作为参数传进去,还是不行。报错是一样的。
fsfpgaindev.rxbuf.v_adr = dma_alloc_coherent(fsfpgaindev.device,64,&fsfpgaindev.rxbuf.p_adr,GFP_KERNEL|GFP_DMA); fsfpgaindev.txbuf.v_adr = dma_alloc_coherent(fsfpgaindev.device,32,&fsfpgaindev.txbuf.p_adr,GFP_KERNEL|GFP_DMA);
-
这里的memset的作用是什么
-
#include "fsfpgain.h" static int fsfpgain_open(struct inode *inode, struct file *filp) { if (atomic_dec_and_test(&valid)) // 原子操作 唯一应用打开驱动 { return 0; } atomic_inc(&valid); return -EBUSY; } static int fsfpgain_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off) {} static long fsfpgain_ioctl(struct file *file, uint32_t cmd, unsigned long arg) { } static int fsfpgain_mmap(struct file *filp, struct vm_area_struct *vma) { return 0; } static int fsfpgain_release(struct inode *inode, struct file *filp) { valid.counter = 1; // open函数访问,原子锁初始化 return 0; } static void init_p_buf_cut(void) {} static void spi_fpga_recv(struct buffer_cut *_p, int _no) {} static irqreturn_t irq_gpio_spi_handler(int irq, void *dev_id) {} static irqreturn_t irq_gpio_spi_thread_func(int irq, void *data) {} static const struct file_operations fsfpgain_fops = { .owner = THIS_MODULE, .open = fsfpgain_open, .read = fsfpgain_read, .release = fsfpgain_release, .unlocked_ioctl = fsfpgain_ioctl, .mmap = fsfpgain_mmap, }; static int fsfpgain_probe(struct spi_device *spi) { int ret = 0; valid.counter = 1; // open函数访问,原子锁初始化 // valid = ATOMIC_INIT(1); printk("fsfpgain_probe\r\n"); fsfpgaindev.major = 0; if (fsfpgaindev.major) { fsfpgaindev.devid = MKDEV(fsfpgaindev.major, 0); ret = register_chrdev_region(fsfpgaindev.devid, FSFPGAIN_CNT, FSFPGAIN_NAME); } else { ret = alloc_chrdev_region(&fsfpgaindev.devid, 0, FSFPGAIN_CNT, FSFPGAIN_NAME); fsfpgaindev.major = MAJOR(fsfpgaindev.devid); fsfpgaindev.minor = MINOR(fsfpgaindev.devid); } if (ret < 0) { printk("fsfpgain chrdev_region err!\r\n"); goto fail_devid; } printk("fsfpgain major=%d, minor=%d\r\n", fsfpgaindev.major, fsfpgaindev.minor); fsfpgaindev.cdev.owner = THIS_MODULE; /* 2、注册设备 */ cdev_init(&fsfpgaindev.cdev, &fsfpgain_fops); ret = cdev_add(&fsfpgaindev.cdev, fsfpgaindev.devid, FSFPGAIN_CNT); if (0 > ret) { goto fail_cdev; } /* 3、创建类 */ fsfpgaindev.class = class_create(THIS_MODULE, FSFPGAIN_NAME); if (IS_ERR(fsfpgaindev.class)) { ret = PTR_ERR(fsfpgaindev.device); goto fail_class; } /* 4、创建设备 */ fsfpgaindev.device = device_create(fsfpgaindev.class, NULL, fsfpgaindev.devid, NULL, FSFPGAIN_NAME); if (IS_ERR(fsfpgaindev.device)) { ret = PTR_ERR(fsfpgaindev.device); goto fail_device; } printk("*device:0x%x,device:0x%x\r\n", fsfpgaindev.device, &fsfpgaindev.device); // get nd // fsfpgaindev.nd = of_get_parent(spi->dev.of_node); fsfpgaindev.nd = spi->dev.of_node; if (NULL == fsfpgaindev.nd) { printk("fsfpgaindev.nd get error\r\n"); goto fail_gpio; } else { printk("fsfpgaindev.nd name:%s", fsfpgaindev.nd->full_name); } fsfpgaindev.cs_gpio = of_get_named_gpio(fsfpgaindev.nd, "cs-gpio", 0); fsfpgaindev.irq_gpio = of_get_named_gpio(fsfpgaindev.nd, "irq-gpio", 0); if (fsfpgaindev.cs_gpio < 0) { printk("fsfpgaindev.cs_gpio get error\r\n"); goto fail_gpio; /* code */ } if (fsfpgaindev.irq_gpio < 0) { printk("fsfpgaindev.irq_gpio get error\r\n"); goto fail_gpio; /* code */ } // 注册gpio gpio_request(fsfpgaindev.cs_gpio, "cs_gpio"); gpio_request(fsfpgaindev.irq_gpio, "irq_gpio"); printk("fsfpgaindev request cs&irq gpio ok\r\n"); // set gpio ret = gpio_direction_output(fsfpgaindev.cs_gpio, 1); ret = gpio_direction_input(fsfpgaindev.irq_gpio); // // get irq num // fsfpgaindev.irq_num = gpio_to_irq(fsfpgaindev.irq_gpio); // // 注册中断 线程化 // // ret = request_irq(fsfpgaindev.irq_num, irq_gpio_spi_handler, // // IRQF_TRIGGER_FALLING, "irq_gpio", &fsfpgaindev); // ret = request_threaded_irq(fsfpgaindev.irq_num, irq_gpio_spi_handler, // irq_gpio_spi_thread_func, IRQF_TRIGGER_RISING, // "irq_gpio", &fsfpgaindev); // if (0 > ret) { // printk("request_irq error\r\n"); // goto fail_irq; // } // printk("fsfpgaindev request_threaded_irq ok\r\n"); // init spi spi->mode = SPI_MODE_1; ret = spi_setup(spi); printk("spi_setup ret:%d\r\n", ret); // set privete fsfpgaindev.private_data = spi; fsfpgaindev.b_workflag = 0; // 初始化工作状态为不工作 fsfpgaindev.send_data_len = 0; // 初始化spi收发数据长度为0 fsfpgaindev.recv_buf_no = 0; fsfpgaindev.read_buf_no = 0; fsfpgaindev.copy_recv_buf_no = 0; printk("fsfpgain probe ok\r\n"); printk("fsfpgain Debug:005\r\n"); printk("rxvadr:0x%lx padr:0x%x\r\n", (long)fsfpgaindev.rxbuf.v_adr, fsfpgaindev.rxbuf.p_adr); printk("rxvadr:0x%lx padr:0x%x\r\n", (long)&fsfpgaindev.rxbuf.v_adr, &fsfpgaindev.rxbuf.p_adr); printk("txvadr:0x%lx padr:0x%x\r\n", (long)fsfpgaindev.txbuf.v_adr, fsfpgaindev.txbuf.p_adr); // 设置DMA掩码 if ((dma_set_coherent_mask(&spi->dev, DMA_BIT_MASK(32))) != 0) { dev_err(&spi->dev, "Failed to set 32-bit DMA mask\n"); return -ENODEV; } fsfpgaindev.rxbuf.v_adr = dma_alloc_coherent(&spi->dev, 64, &fsfpgaindev.rxbuf.p_adr, GFP_KERNEL); fsfpgaindev.txbuf.v_adr = dma_alloc_coherent(&spi->dev, 32, &fsfpgaindev.txbuf.p_adr, GFP_KERNEL); if ((0x00000000 != fsfpgaindev.rxbuf.v_adr) & (0x00000000 != fsfpgaindev.txbuf.v_adr)) { printk("dma_alloc_coherent ok\r\n"); printk("rxvadr:0x%lx padr:0x%x\r\n", (long)fsfpgaindev.rxbuf.v_adr, fsfpgaindev.rxbuf.p_adr); printk("txvadr:0x%lx padr:0x%x\r\n", (long)fsfpgaindev.txbuf.v_adr, fsfpgaindev.txbuf.p_adr); } else { printk("dma_alloc_coherent return NULL\r\n"); return -1; } // 申请大内存 return ret; fail_irq: gpio_free(fsfpgaindev.cs_gpio); gpio_free(fsfpgaindev.irq_gpio); fail_gpio: fail_device: device_destroy(fsfpgaindev.class, fsfpgaindev.devid); fail_class: class_destroy(fsfpgaindev.class); fail_cdev: cdev_del(&fsfpgaindev.cdev); fail_devid: unregister_chrdev_region(fsfpgaindev.devid, FSFPGAIN_CNT); printk("fsfpgain probe error\r\n"); return ret; } static int fsfpgain_remove(struct spi_device *spi) { int ret = 0; // free irq free_irq(fsfpgaindev.irq_num, &fsfpgaindev); // gpio reset gpio_direction_output(fsfpgaindev.cs_gpio, 0); gpio_direction_output(fsfpgaindev.irq_gpio, 0); // gpio free gpio_free(fsfpgaindev.cs_gpio); gpio_free(fsfpgaindev.irq_gpio); cdev_del(&fsfpgaindev.cdev); unregister_chrdev_region(fsfpgaindev.devid, FSFPGAIN_CNT); device_destroy(fsfpgaindev.class, fsfpgaindev.devid); class_destroy(fsfpgaindev.class); printk("fsfpgain_remove\r\n"); return ret; } // 传统匹配 struct spi_device_id fsfpgain_id[] = {{"fsfpgain", 0}, {}}; // 设备树匹配 static const struct of_device_id fsfpgain_of_match[] = { { .compatible = "fsfpgain", }, {}}; struct spi_driver fsfpgain = { .probe = fsfpgain_probe, .remove = fsfpgain_remove, .id_table = fsfpgain_id, .driver = { .name = "fsfpgain", .owner = THIS_MODULE, .of_match_table = fsfpgain_of_match, }, }; // 入口函数 static int __init fsfpgain_init(void) { int ret = 0; ret = spi_register_driver(&fsfpgain); printk("fsfpgain_init spi_register_driver return:%d\r\n", ret); return ret; } // 出口函数 static void __exit fsfpgain_exit(void) { // 释放大内存 printk("rxvadr:0x%lx padr:0x%x\r\n", (long)fsfpgaindev.rxbuf.v_adr, fsfpgaindev.rxbuf.p_adr); printk("txvadr:0x%lx padr:0x%x\r\n", (long)fsfpgaindev.txbuf.v_adr, fsfpgaindev.txbuf.p_adr); dma_free_coherent(NULL, DMAC_MAX_TRF_SIZE * DMA_RECV_MAX_NUM, fsfpgaindev.rxbuf.v_adr, fsfpgaindev.rxbuf.p_adr); dma_free_coherent(NULL, DMAC_MAX_TRF_SIZE * DMA_RECV_MAX_NUM, fsfpgaindev.txbuf.v_adr, fsfpgaindev.txbuf.p_adr); printk("rxvadr:0x%lx padr:0x%x\r\n", (long)fsfpgaindev.rxbuf.v_adr, fsfpgaindev.rxbuf.p_adr); printk("txvadr:0x%lx padr:0x%x\r\n", (long)fsfpgaindev.txbuf.v_adr, fsfpgaindev.txbuf.p_adr); spi_unregister_driver(&fsfpgain); printk("fsfpgain_exit\r\n"); } module_init(fsfpgain_init); module_exit(fsfpgain_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("fsml"); MODULE_DESCRIPTION("fsfpgain t113 module"); MODULE_VERSION("v2.0.0.0");
问题:
- 没有设置设备,丢了一个NULL进去,这个操作在Linux 5.4 内核中是不允许的
- 没有设置 DMA MASK,4.14之前内核可以,之后的不行
- memset把之前设置的参数全部清空了,不知道有什么作用
-
@awwwwa 老师,问题解决了!非常感谢,我的电话:13643323722,您可以加我微信或者留下电话,我添加您。
-
@awwwwa memset是个错误,尝试解决问题时遗留下来的。
-
@awwwwa 老师你好,这个驱动还有个问题:中断只能响应40us以上的高电平才会执行中断,但是我的驱动里面中断函数里面是上升沿触发。我看教程是通过设备树来设置,是因为我是驱动程序里面设置,没有成功吗?还是有其他因素呢?
中断注册部分代码是:ret = request_threaded_irq(fsfpgaindev.irq_num, irq_gpio_spi_handler,irq_gpio_spi_thread_func,IRQF_TRIGGER_RISING, "irq_gpio", &fsfpgaindev); if(0 > ret) { printk("request_irq error\r\n"); goto fail_irq; } else { printk("fsfpgain irq_num:%d\n",fsfpgaindev.irq_num); }
Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号