记录一次驱动调试过程

在开发板Exynos4412上用4个led:LED2~5来模拟4bit数实验:

seg_led_drv.c

问题:

        在卸载模块时,虽然没有崩溃,但是内核打印如下警告:

[ 3494.595000] WARNING: CPU: 2 PID: 1277 at drivers/gpio/gpiolib.c:1556 gpiod_free+0xc0/0xe8() //问题出现在内核文件gpiolib.c下gpiod_free+0xc0(第1556行)

[ 3494.595000] Modules linked in: seg_led_drv(O-) [last unloaded: seg_led_drv]

[ 3494.595000] CPU: 2 PID: 1277 Comm: rmmod Tainted: G W O 3.14.0 #8

[ 3494.595000] [] (unwind_backtrace) from [] (show_stack+0x10/0x14)

[ 3494.595000] [] (show_stack) from [] (dump_stack+0x64/0xb4)

[ 3494.595000] [] (dump_stack) from [] (warn_slowpath_common+0x68/0x88)

[ 3494.595000] [] (warn_slowpath_common) from [] (warn_slowpath_null+0x1c/0x24)

[ 3494.595000] [] (warn_slowpath_null) from [] (gpiod_free+0xc0/0xe8)

[ 3494.595000] [] (gpiod_free) from [] (free_gpio+0xf4/0x14c [seg_led_drv]) //驱动程序中seg_remove()下的free_gpio()函数调用了内核中的gpiod_free()函数

[ 3494.595000] [] (free_gpio [seg_led_drv]) from [] (seg_remove+0x2c/0x68 [seg_led_drv])

[ 3494.595000] [] (seg_remove [seg_led_drv]) from [] (platform_drv_remove+0x14/0x18)

[ 3494.685000] [] (platform_drv_remove) from [] (__device_release_driver+0x58/0xb4)

[ 3494.685000] [] (__device_release_driver) from [] (driver_detach+0xac/0xb0)

[ 3494.685000] [] (driver_detach) from [] (bus_remove_driver+0x4c/0x90)

[ 3494.685000] [] (bus_remove_driver) from [] (SyS_delete_module+0x124/0x180)

[ 3494.685000] [] (SyS_delete_module) from [] (ret_fast_syscall+0x0/0x30)

[ 3494.685000] ---[ end trace d371ea0a334f660f ]---

分析过程:

从打印信息可以看出:

1、当卸载驱动模块时,seg_remove中的释放gpio的操作(free_gpio ())出现了问题

2、问题根源在内核文件gpiolib.c的第1556行,查看该文件下包含1556行的函数,

1525 static void gpiod_free(struct gpio_desc *desc)
1526 {
1527     unsigned long       flags;
1528     struct gpio_chip    *chip;
1529 
1530     might_sleep();
1531 
1532     if (!desc) {
1533         WARN_ON(extra_checks);
1534         return;
1535     }
1536 
1537     gpiod_unexport(desc);
1538 
1539     spin_lock_irqsave(&gpio_lock, flags);
1540 
1541     chip = desc->chip;
1542     if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
1543         if (chip->free) {
1544             spin_unlock_irqrestore(&gpio_lock, flags);
1545             might_sleep_if(chip->can_sleep);
1546             chip->free(chip, gpio_chip_hwgpio(desc));
1547             spin_lock_irqsave(&gpio_lock, flags);
1548         }
1549         desc_set_label(desc, NULL);
1550         module_put(desc->chip->owner);
1551         clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
1552         clear_bit(FLAG_REQUESTED, &desc->flags);
1553         clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
1554         clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
1555     } else
1556         WARN_ON(extra_checks);
1557 
1558     spin_unlock_irqrestore(&gpio_lock, flags);
1559 }

1549~1554行:释放gpio

1556行:警告

该函数选择执行了else分支下的代码(即第1556行代码),而没有执行else上面(1549~1554行)的代码,也就是没有执行释放gpio的操作,

说明第1542行if条件为假,desc下的chip为空或者desc对象下的标志flags的第FLAG_REQUESTED(即0)位为0都会导致if条件为假,通过以下方法来鉴别是哪种原因导致的:

在执行释放gpio的操作之前,查看desc下的chip和flags信息,因此在free_gpio函数中添加检测代码(106~121行,参照内核中gpiod_free()函数中的代码来写)

//前提:将内核文件gpiolib.c中的struct gpio_desc结构体复制到当前驱动中,否则,编译不通过

105 void free_gpio(struct seg_dev *sdev){                                                                                 
106     struct gpio_desc *desc = NULL;
107     struct gpio_chip *chip = NULL;
108     unsigned long flag;
109     int test;
110 
111     desc = gpio_to_desc(sdev->led2_gpio);
112     flag = desc->flags;
113     chip = desc->chip;
114     test = test_bit(FLAG_REQUESTED,&flag);
115 
116     printk("#######################################\n");
117     printk("desc = %p \t size = %u\n",desc,sizeof(struct gpio_desc));
118     printk("flag = %#x\n",flag);
119     printk("chip = %p \t size = %u\n",chip,sizeof(struct gpio_chip));
120     printk("free = %p \t test = %d\n",chip->free,test);
121     printk("#######################################\n");
122 
123     printk("%s \t %d\n",__FUNCTION__,__LINE__);
124     printk("gpio2:%d\n",sdev->led2_gpio);
125     printk("gpio3:%d\n",sdev->led3_gpio);
126     printk("gpio4:%d\n",sdev->led4_gpio);
127     printk("gpio5:%d\nafter:\n",sdev->led5_gpio);
128 
129     gpio_free(sdev->led2_gpio);
130     gpio_free(sdev->led3_gpio);
131     gpio_free(sdev->led4_gpio);
132     gpio_free(sdev->led5_gpio);
133     printk("gpio2:%d\n",sdev->led2_gpio);
134     printk("gpio3:%d\n",sdev->led3_gpio);
135     printk("gpio4:%d\n",sdev->led4_gpio);
136     printk("gpio5:%d\n",sdev->led5_gpio);
137 }

这部分代码在卸载驱动模块时会被执行,在执行命令rmmod seg_led_drv后打印如下

[root@farsightmydrv]#rmmod seg_led_drv

[ 1384.605000] #######################################

[ 1384.610000] desc = c061bc88        size = 8

[ 1384.615000] flag = 0x2

[ 1384.615000] chip = c05c4e14        size = 100

[ 1384.620000] free = (null)        test = 0

[ 1384.625000] #######################################

//...

[ 1384.645000] WARNING: CPU: 2 PID: 1265 at drivers/gpio/gpiolib.c:1556 gpiod_free+0xc0/0xe8()

//...

由此可知:导致if条件为假的原因是desc对象下的标志flags的第FLAG_REQUESTED(即第0bit)位为0,该标志意味着,在执行gpio_free之前,该gpio的状态是没有被申请,

难道是申请gpio的操作gpio_request()无效吗?通过以下方法来鉴定:

在申请gpio的操作之前和之后查看desc下的flags信息,因此在init_gpio函数中添加检测代码(147~150行,178~188行,192~202行,参照内核中gpiod_request()()函数中的代码来写)

141 void init_gpio(struct seg_dev *sdev,struct device_node *pnod){
142     int ret = 0;
143     unsigned int *value = NULL;
144     u32 arr[3] = {0};
145     char *p = NULL;
146 
147     struct gpio_desc *desc = NULL;
148     struct gpio_chip *chip = NULL;
149     unsigned long flag;
150     int test;
151 
152     printk("%s \t %d\n",__FUNCTION__,__LINE__);
153     value = (int *)pnod->properties->next->value;
154     printk("node name:%s\n",pnod->name);
155     printk("property name:%s\n",pnod->properties->name);
156     printk("next property name:%s\n",pnod->properties->next->name);
157     printk("next property value[0]:%#x\n",value[0]);    //打印节点属性值(方式一)
158     printk("next property value[1]:%#x\n",value[1]);
159     printk("next property value[2]:%#x\n",value[2]);   
160 
161     of_property_read_u32_array(pnod,"led2-gpio",arr,3);
162     printk("arr0:%#x \t arr1:%#x \t arr2:%#x\n",arr[0],arr[1],arr[2]);    //打印节点属性值(方式二)
163 
164     p = (char*)arr;
165     for(;ret<12;ret++){
166         printk("%x\n",p[ret]);    //打印节点属性值(方式三)
167     }
168     /*获取gpio标号*/
169     sdev->led2_gpio = of_get_named_gpio(pnod,"led2-gpio",0);
170     printk("gpio2:%d\n",sdev->led2_gpio);
171     sdev->led3_gpio = of_get_named_gpio(pnod,"led3-gpio",0);
172     printk("gpio3:%d\n",sdev->led3_gpio);
173     sdev->led4_gpio = of_get_named_gpio(pnod,"led4-gpio",0);
174     printk("gpio4:%d\n",sdev->led4_gpio);
175     sdev->led5_gpio = of_get_named_gpio(pnod,"led5-gpio",0);
176     printk("gpio5:%d\n",sdev->led5_gpio);
177 
178     desc = gpio_to_desc(sdev->led2_gpio);
179     flag = desc->flags;
180     chip = desc->chip;
181     test = test_bit(FLAG_REQUESTED,(volatile unsigned long *)&flag);
182 
183     printk("#######################################\n");
184     printk("desc = %p \t size = %u\n",desc,sizeof(struct gpio_desc));
185     printk("flag = %#x\n",flag);
186     printk("chip = %p \t size = %u\n",chip,sizeof(struct gpio_chip));
187     printk("free = %p \t test = %d\n",chip->free,test);
188     printk("#######################################\n");
189     /*申请使用gpio*/
190     ret = gpio_request(sdev->led2_gpio,"led2_gpio");    
191     
192     desc = gpio_to_desc(sdev->led2_gpio);
193     flag = desc->flags;
194     chip = desc->chip;
195     test = test_bit(FLAG_REQUESTED,&flag);
196 
197     printk("#######################################\n");
198     printk("desc = %p \t size = %u\n",desc,sizeof(struct gpio_desc));
199     printk("flag = %#x\n",flag);
200     printk("chip = %p \t size = %u\n",chip,sizeof(struct gpio_chip));
201     printk("free = %p \t test = %d\n",chip->free,test);
202     printk("#######################################\n");
203     
204     ret = gpio_request(sdev->led3_gpio,"led3_gpio");
205     if(ret < 0 )
206         goto free_gpio2;
207     ret = gpio_request(sdev->led4_gpio,"led4_gpio");
208     if(ret < 0 )
209         goto free_gpio3;
210     ret = gpio_request(sdev->led5_gpio,"led5_gpio");
211     if(ret < 0 )
212         goto free_gpio4;
213     /*设置gpio为输出功能*/
214     gpio_direction_output(sdev->led2_gpio, 0);
215     gpio_direction_output(sdev->led3_gpio, 0);
216     gpio_direction_output(sdev->led4_gpio, 0);
217     gpio_direction_output(sdev->led5_gpio, 0);
218 
219 free_gpio4:
220     gpio_free(sdev->led4_gpio);
221 free_gpio3:
222     gpio_free(sdev->led3_gpio);
223 free_gpio2:
224     gpio_free(sdev->led2_gpio);                                                                                       
225 }

183~188:在申请gpio之前查看desc的信息

197~202:在申请gpio之后查看desc的信息

这部分代码在载入驱动模块时会被调用,执行命令insmod seg_led_drv.ko后打印如下:

[root@farsightmydrv]#insmod seg_led_drv.ko

//...

[ 3989.660000] #######################################

[ 3989.665000] desc = c061bc88        size = 8

[ 3989.670000] flag = 0x2

[ 3989.670000] chip = c05c4e14        size = 100

[ 3989.675000] free = (null)        test = 0

[ 3989.680000] #######################################

[ 3989.685000] #######################################

[ 3989.690000] desc = c061bc88 size = 8

[ 3989.695000] flag = 0x3

[ 3989.695000] chip = c05c4e14 size = 100

[ 3989.700000] free = (null)        test = 1

[ 3989.705000] #######################################

由此可见,申请gpio的操作是有效的,那么可以推断:在init_gpio()下的gpio_request与seg_remove()下的free_gpio之间,存在一个释放gpio的操作,

也就是说,在卸载驱动模块之前,gpio已经被释放了,因此,需要找到这个释放操作,

经查,在init_gpio()下,有一个条件操作:当gpio_request失败时执行goto。而goto下的操作就是执行gpio_free

此时,恍然大悟,goto操作是没有被隔离的,是必定被执行的,

因此,解决办法就是,在goto操作之前加上return

再次编译后运行,警告解除!

总结:写代码要仔细、仔细、再仔细

                                                                                ----新手小白,时刻期待大神的指教----

  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值