在开发板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
再次编译后运行,警告解除!
总结:写代码要仔细、仔细、再仔细
----新手小白,时刻期待大神的指教----