linux驱动中断注册与注销带来的段错误
错误描述:
今天写了个重力传感器的驱动,按照通常的中断申请与注册流程,insmod时安静,运行测试程序正常,rmmod安静。但是..... 当我再次insmod时,报了一堆的oops错误,从错误描述中看根本找不出是我写的哪个函数有错,从此以后就再也不能insmod了,rmmod却报资源忙,这下是进也不是退也不是,每次到了这里就得断电重启,这bug,卡了我整整一天。
1 root@nufront ~$ insmod mc3xxx.ko 2 [ 199.970066] mc3xxx: request irq sucssce! irq = 105 3 [ 200.064055] input: mc3xxx as /devices/virtual/input/input1 4 root@nufront ~$ [ 200.314850] mc3xxx: entern extint_irq_handler 5 6 root@nufront ~$ 7 root@nufront ~$ 8 root@nufront ~$ 9 root@nufront ~$ 10 root@nufront ~$ rmmod mc3xxx.ko 11 root@nufront ~$ insmod mc3xxx.ko 12 [ 230.449460] Unable to handle kernel paging request at virtual address bf001e01 13 [ 230.456598] pgd = cf80c000 14 [ 230.459287] [bf001e01] *pgd=0f590811, *pte=00000000, *ppte=00000000 15 [ 230.465539] Internal error: Oops - BUG: 7 [#1] PREEMPT SMP ARM 16 [ 230.471351] Modules linked in: mc3xxx(O+) [last unloaded: mc3xxx] 17 [ 230.477435] CPU: 0 PID: 2562 Comm: insmod Tainted: G O 4.4.0-xil1 18 [ 230.486975] Hardware name: Xilinx Zynq Platform 19 [ 230.491492] task: c8213ac0 ti: cf8cc000 task.ti: cf8cc000 20 [ 230.496878] PC is at strnlen+0x10/0x28 21 [ 230.500607] LR is at string+0x30/0xcc 22 [ 230.504254] pc : [<c01dd6d8>] lr : [<c01de8e4>] psr: a0000093 23 [ 230.504254] sp : cf8cdc20 ip : 00000073 fp : cf8cdc50 24 [ 230.515707] r10: c0626f80 r9 : 00000002 r8 : c0514663 25 [ 230.520916] r7 : bf001e01 r6 : 0000ffff r5 : c0627360 r4 : c0626fc2 26 [ 230.527426] r3 : bf001e01 r2 : bf001e01 r1 : fffffffe r0 : bf001e01 27 [ 230.533937] Flags: NzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user 28 [ 230.541141] Control: 18c5387d Table: 0f80c04a DAC: 00000055 29 [ 230.546869] Process insmod (pid: 2562, stack limit = 0xcf8cc210) 30 [ 230.552858] Stack: (0xcf8cdc20 to 0xcf8ce000) 31 [ 230.557205] dc20: ff0a0004 cf8cdd0c c0626fc2 cf8cdd10 c0627360 c01e0144 c06264 32 [ 230.565363] dc40: ffffffff ffff0008 ffffffff 000003e0 ff0a0004 ffffffff fffff0 33 [ 230.573521] dc60: ffffffff 00000000 00000069 00000000 00000000 00000000 00000c 34 [ 230.581681] dc80: 00000000 c005411c 00000069 00000002 cf8cdcc0 c0057628 cf8cd8 35 [ 230.589840] dca0: cf8cdca8 cf8cdcac 00000000 60000093 c8109f00 c0054464 cd50e0 36 [ 230.597999] dcc0: 00000069 ce97e380 c8109f00 cd50e5e0 60000013 c0054480 c0514c 37 [ 230.606158] dce0: 00000001 c008c67c c051462c cf8cdcfc cf723a00 c00569e4 c05149 38 [ 230.614317] dd00: 00000002 bf008e01 00000002 bf001e01 d7bac450 00000002 00000c 39 [ 230.622476] dd20: 00000069 cf723a00 cd50e580 00000000 c8109f00 00000002 000000 40 [ 230.630636] dd40: c8109f00 d7baca7c ffffffed bf008f8c cd4f5600 00000500 bf0088 41 [ 230.638796] dd60: bf008e01 c8109f00 bf008514 cd4f5600 cd4f5620 ffffffed bf0088 42 [ 230.646954] dd80: 00000001 c032c068 cd4f5620 00000000 bf008f8c 00000008 bf0098 43 [ 230.655113] dda0: 00000000 cd4f5620 cd4f5654 bf008f8c 00000000 c0271814 bf0084 44 [ 230.663273] ddc0: 00000000 c02700e8 c80ef75c c8406b34 bf008f8c cf7ae980 c06164 45 [ 230.671432] dde0: bf008e01 cf8cc020 00000000 bf008f8c 00000000 00000000 c05f48 46 [ 230.679591] de00: c0616494 bf00b000 bf008f70 c032c628 c05f4e50 bf00b000 000004 47 [ 230.687749] de20: ff0a0004 00000000 00000001 00000001 c80b5000 00000001 000000 48 [ 230.695909] de40: d7da5e60 d7da5e80 00000000 c0091404 c05f4e44 d7da5e60 000000 49 [ 230.704068] de60: 00000000 00000000 d7da5e60 c0092ff4 d7da5e60 bf009080 cf8cc0 50 [ 230.712228] de80: ce97e1c0 bf0090c8 00000500 c008c934 bf009080 0000003e bf0090 51 [ 230.720386] dea0: 00000001 c00773b8 bf00908c 00007fff 00000000 c0074c74 000004 52 [ 230.728546] dec0: bf00922c 000000b1 e0940674 000a7008 6e72656b 00006c65 000000 53 [ 230.736703] dee0: 00000000 00000000 00000000 00000000 00000000 00000000 000000 54 [ 230.744862] df00: 00000000 00000000 00000000 00000000 00000000 00000000 000000 55 [ 230.753023] df20: 00000000 c056e410 00000000 00005198 e0942198 00000000 000ac8 56 [ 230.761183] df40: cf8cc000 00000000 00000000 c00776dc e093d000 00005198 e09407 57 [ 230.769341] df60: e0941af4 00002248 00002668 00000000 00000000 00000000 00000f 58 [ 230.777501] df80: 00000016 00000013 00000011 00000000 00005198 bea85e14 bea850 59 [ 230.785661] dfa0: c000ec44 c000eaa0 00005198 bea85e14 000a7018 00005198 000a79 60 root@nufront ~$ rm mc3xxx.ko 61 root@nufront ~$ lsmod 62 Module Size Used by 63 mc3xxx 14935 1 64 root@nufront ~$ rmmod mc3xxx 65 rmmod: can't unload 'mc3xxx': Device or resource busy 66 root@nufront ~$ reboot -f 67 [ 508.527520] max_wdt_notify_sys: feed watchdog
发现问题:
后来,我尝试着先不注册中断,这样就能随意地加载卸载,逐渐地缩小目标范围,最终锁定“嫌疑犯”: request_irq() / free_irq() 。 只要注释了这一对“夫妇”,程序就乖乖地听我的话了。
于是乎,确定时这里面传参的问题了,又在网上几经周折,终于知道原因了:这个gpio是与其他gpio等共享52号中断线的(xilinx zynq-7z030二合一芯片),所以得以共享中断方式注册,而且最后一个参数必不可少,他就是通过这最后一个参数区分具体是谁触发的。
改正后代码:
static irqreturn_t extint_irq_handler(int irq, void *dev) { struct i2c_client *client = container_of(mc3xxx_device.parent, struct i2c_client, dev); struct mc3xxx_data *data; data = i2c_get_clientdata(client); if (&data->input_dev->dev == dev) { udelay(100);
i2c_smbus_read_byte_data(client, 0x03); GSE_ERR("entern extint_irq_handler \n"); } return IRQ_HANDLED; } probe() { ....... /* add by xxg for surpport extern interrupt triger */ np = of_find_compatible_node(NULL, NULL, "mcube,mc3xxx"); if(NULL == np){ printk(KERN_DEBUG "not fund device node mc3xxx \n"); goto erro_node_find ; } #if !(DTS_HAVE_INT) data->gpio = of_get_named_gpio(np, "gpio_int", 0); if (data->gpio < 0) { printk(KERN_DEBUG "get gpio failed \n"); goto erro_node_find ; } if(gpio_is_valid(data->gpio)){//判断是不是一个可用的gpio号 ret = gpio_request_one(data->gpio, GPIOF_IN, "mc3xxx");//将这个gpio的引脚复用功能设置成中断功能 if(ret){ printk(KERN_DEBUG "get gpio failed \n"); goto erro_get_gpio; } GSE_ERR("get gpio sucssce! gpio = %d \n", data->gpio); data->irq = gpio_to_irq(data->gpio);//为gpio申请一个软中断号 } else { goto erro_get_gpio; } #endif #if DTS_HAVE_INT data->irq = of_irq_get(np, 0); #endif if (data->irq < 0) { printk(KERN_DEBUG "gpio to irq failed \n"); goto erro_get_gpio ; } ret = request_irq(data->irq, extint_irq_handler, IRQF_TRIGGER_FALLING | IRQF_SHARED , data->input_dev->name , &data->input_dev->dev);//将申请到的软中断号注册进内核(绑定回调函数) if(ret){ printk(KERN_DEBUG "requst irq failled \n"); goto erro_get_irq ; } GSE_ERR("request irq sucssce! irq = %d \n", data->irq); ...... } static int mc3xxx_remove(struct i2c_client *client) { struct mc3xxx_data *data = i2c_get_clientdata(client); destroy_workqueue(data->mc3xxx_wq); free_irq(data->irq, &data->input_dev->dev ); gpio_free(data->gpio); hrtimer_cancel(&data->timer); input_unregister_device(data->input_dev); misc_deregister(&mc3xxx_device); sysfs_remove_group(&data->input_dev->dev.kobj, &mc3xxx_group); kfree(data); return 0; }