Linux内核相关论坛问题回复(1)

来源:互联网 发布:虚拟相机软件 编辑:程序博客网 时间:2024/05/16 01:33

http://bbs.csdn.net/topics/391048758?page=1#post-399361268
有人在论坛提了下面的问题,比较典型。

最近在调试SPI子系统时发现如下错误:[ 3777.005000] BUG: scheduling while atomic: spi0/25/0x00000002[ 3777.005000] Modules linked in: focal_fp_sensor(O) rtl8192cu(O) snd_soc_tiny4412_wm8960 snd_soc_wm8960 [last unloaded: focal_fp_sensor][ 3777.005000] [<c0015484>] (unwind_backtrace+0x0/0xf0) from [<c0058084>] (__schedule_bug+0x44/0x58)[ 3777.010000] [<c0058084>] (__schedule_bug+0x44/0x58) from [<c058b180>] (__schedule+0x760/0x830)[ 3777.020000] [<c058b180>] (__schedule+0x760/0x830) from [<c025343c>] (rpm_resume+0x12c/0x640)[ 3777.025000] [<c025343c>] (rpm_resume+0x12c/0x640) from [<c0253bb8>] (__pm_runtime_resume+0x48/0x60)[ 3777.035000] [<c0253bb8>] (__pm_runtime_resume+0x48/0x60) from [<c0219f18>] (pl330_alloc_chan_resources+0x1bc/0x1f0)[ 3777.045000] [<c0219f18>] (pl330_alloc_chan_resources+0x1bc/0x1f0) from [<c021898c>] (dma_chan_get+0x5c/0xfc)[ 3777.055000] [<c021898c>] (dma_chan_get+0x5c/0xfc) from [<c0219144>] (__dma_request_channel+0x110/0x1d4)[ 3777.065000] [<c0219144>] (__dma_request_channel+0x110/0x1d4) from [<c0027324>] (samsung_dmadev_request+0x40/0x4c)[ 3777.075000] [<c0027324>] (samsung_dmadev_request+0x40/0x4c) from [<c027a034>] (s3c64xx_spi_prepare_transfer+0x44/0x88)[ 3777.085000] [<c027a034>] (s3c64xx_spi_prepare_transfer+0x44/0x88) from [<c0277d08>] (spi_pump_messages+0xe8/0x160)[ 3777.095000] [<c0277d08>] (spi_pump_messages+0xe8/0x160) from [<c004b504>] (kthread_worker_fn+0x4c/0x164)[ 3777.105000] [<c004b504>] (kthread_worker_fn+0x4c/0x164) from [<c004b710>] (kthread+0x8c/0x98)[ 3777.115000] [<c004b710>] (kthread+0x8c/0x98) from [<c000f598>] (kernel_thread_exit+0x0/0x8)该错误是概率性的,并不是每次都出现,我google和百度发现类似问题的原因是如下:中断处理函数中调用了可以休眠的函数,如semaphore,mutex,sleep之类的可休眠的函数,而linux内核要求在中断处理的时候,不允许系统调度,不允许抢占,要等到中断处理完成才能做其他事情。因此,要充分考虑中断处理的时间,一定不能太久。但是我这边并不是在中断系统中,发了几天时间也没有找出原因来,我追踪源码最后到了pl330_request_channel里面的pm_runtime_get_sync(pl330->pinfo->dev); 这个RPM函数因为调用__schedule 而发生原子错误,由于这个错误时概率性事件,小弟百思不得其解,求大神们指点一二。我的子系统驱动函数应该没有问题,内核版本为三星平台3.5,开发板是用的友善之臂的。我通过修改内核源码是解决了这个问题,我的修改如下,我基本上是吧DMA的RPM唤醒机制屏蔽掉了。1.将pl330_probe函数里的pm_runtime_put(&adev->dev); 注释掉;2.将pl330_request_channel的pm_runtime_get_sync注释掉;3.将pl330_release_channel的pm_runtime_put(pl330->pinfo->dev);注释掉;这样修改之后不会出现上述问题,具体请看下面注释:static int s3c64xx_spi_prepare_transfer(struct spi_master *spi){struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);/* Acquire DMA channels */while (!acquire_dma(sdd))  //原先这里面有调用pm_runtime_  就把里面的注释了msleep(10);pm_runtime_get_sync(&sdd->pdev->dev);//但是为什么这里调用就不会出现原子错误呢???return 0;}static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi){struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);/* Free DMA channels */sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client);//原先这里面也有调用pm_runtime_  就把里面的注释了sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client);//原先这里面也有调用pm_runtime_  就把里面的注释了pm_runtime_put(&sdd->pdev->dev);return 0;}求大神指点!感激万分!!谢谢!!

以下是我的回复

网上说“中断处理函数中调用了可以休眠的函数,如semaphore,mutex,sleep之类的可休眠的函数”就会打印“[ 3777.005000] BUG: scheduling while atomic: spi0/25/0x00000002”这种log。这种说法有一定道理,但没有说到本质。我想你也找过打印上面log的地方,就在__schedule_bug()函数里。运行__schedule_bug()函数的条件是static inline void schedule_debug(struct task_struct *prev)if (unlikely(in_atomic_preempt_off() && !prev->exit_state))__schedule_bug(prev);}所以打印上面Log的条件是在preempt_disable的进程里,运行schedule()函数。也就是说某个进程已经不允许其他进程抢占,但在这个进程的某个函数里边却运行了schedule()试图放弃当前的进程执行权。你可以看一下“[ 3777.005000] BUG: scheduling while atomic: spi0/25/0x00000002”里边0x00000002代表的意思,其实就是preempt_count的值,这个值大于0表示当前进程不能被抢占。那可以找一下在哪里会增加preempt_count的值。我没有你的代码,所以看不到详细的内容。但我找了我本地的代码,可能是三星的spi驱动里边设置的spinlock函数。你可以找一下spinlock的实现,里边都有增加preempt_count。所以要避免出现上面的错误,必须要注意spinlock lock和spinlock unlock的地方。最好在schedule之前解spinlock锁,在schedule之后再打开。以避免出现上面的错误
0 0
原创粉丝点击