Linux內核相關論壇問題回覆(1)

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之後再打開。
以避免出現上面的錯誤
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章