歡迎光臨
每天分享高質量文章

一次觸摸屏中斷除錯引發的深入探究

首先非常感謝陳莉君老師的賞識,題目名字也是陳老師幫忙起的。      

      大家好,我叫張昺華,中間那個字和“餅”字一個讀音,嘿嘿,相信不少人都不認識我的第二個字吧,這是我一個很聰明的表哥(當時他只有9歲)從新華字典里取名的,光明正大的意思,希望我一生光明磊落。當時的技術不發達,加上這個字太特殊了,導致基本上大考都沒我名字,就連戶口本都是手寫的……因為這個字也讓我很容易上課被點名,因為太特別了,老師們總是喜歡叫上一叫……可是現在技術發達了,照樣經常遇到很多人不認識這個字就會隨便輸入,比如說張鍋華,張口華,張日華…有次在醫院拿藥,竟然有人把我的名字輸入成了張菊花(淚奔…),不過可能因為它的特殊性吧,讓我交到了非常多的好朋友,高中的230,大學的社聯公關部,啟明星支教隊,電氣2班,科創的小伙伴兒們以及現在公司里的很多朋友……

2014年我畢業於廣東省惠州學院,我從小酷愛理科,當看到陳莉君老師在《Linux內核之旅》上發的學生在課堂上用課本劇的方式來詮釋技術時,想到了自己初中的時候老師就是這樣鍛煉我們的,很喜歡那樣的學習氛圍,自己大學時和小伙伴們一起創立了科技創新協會,目的就是可以一群人在研究技術,一起做有意思的東西,一起分享技術帶給我們的快樂,也希望中國有更多的人熱愛技術,喜歡一起研究、分享技術,然後可以一起用我們的技術來做一些好玩的東西,可以為這個社會創造一些東西來改善人們的生活。

 

如下為本人原創,在解決問題的過程中的一點心得(要感謝公司的權哥與泉哥的鼎力支持),如果有描述不准確的地方還請各位指出,非常感謝

 

Linux內核版本:linux-4.9.18

曾有一次除錯觸摸屏的時候遇到如下的問題

 

/startup/modules#

 [  233.370296] irq 44: nobody cared (try booting with the”irqpoll” option)

[ 233.376983] CPU: 0 PID: 0 Comm: swapper Tainted:G          O    4.9.18 #8

[ 233.383912] Hardware name: Broadcom Cygnus SoC

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

[ 233.396103] [] (show_stack) from [](__report_bad_irq+0x24/0xa4)

[ 233.403821]

[](__report_bad_irq) from [] (note_interrupt+0x1c8/0x274)

[ 233.412052]

[](note_interrupt) from [] (handle_irq_event_percpu+0x44/0x50)

[ 233.420715]

[](handle_irq_event_percpu) from [] (handle_irq_event+0x28/0x3c)

[ 233.429550]

[](handle_irq_event) from [] (handle_simple_irq+0x70/0x78)

[  233.437868]

[](handle_simple_irq) from [] (generic_handle_irq+0x18/0x28)

[ 233.446366]

[](generic_handle_irq) from [](iproc_gpio_irq_handler+0xd0/0x11c)

[ 233.455376]

[](iproc_gpio_irq_handler) from [] (generic_handle_irq+0x18/0x28)

[ 233.464297]

[](generic_handle_irq) from [] (__handle_domain_irq+0x80/0xa4)

[ 233.472959]

[](__handle_domain_irq) from [] (gic_handle_irq+0x50/0x84)

[ 233.481275] [] (gic_handle_irq) from [](__irq_svc+0x6c/0x90)

[ 233.488723] Exception stack(0xc0901f60 to 0xc0901fa8)

[ 233.493754] 1f60: c0112900 c0717028 c0901fb8 00000000 c093af4c 0000000000000335 c0826220

[ 233.501896] 1f80: 00000001 414fc091 df9eab80 00000000 c0900038 c0901fb0c010843c c0108440

[ 233.510034] 1fa0: 60000013 ffffffff

[ 233.513514] [] (__irq_svc) from [](arch_cpu_idle+0x2c/0x38)

[ 233.520887] [] (arch_cpu_idle) from [](cpu_startup_entry+0x50/0xc0)

[ 233.528956] [] (cpu_startup_entry) from [](start_kernel+0x414/0x4b0)

[ 233.537097] handlers:

[ 233.539363]

[]irq_default_primary_handler threaded [] synaptics_rmi4_irq[synaptics_dsx]

[  233.549300]Disabling IRQ#44

 

 

首先我們順著錯誤跟蹤linux內核來看下

kernel/irq/spurious.c

因此有提示的log信息可以看出,是走的else的分支,

bad_action_ret(action_ret)傳回為0

通過此函式的dump_stack的信息,可以追溯到呼叫者

 

drivers/pinctrl/bcm/pinctrl-iproc-gpio.c

kernel/irq/chip.c

handle_level_irq

===> handle_irq_event  (kernel/irq/handle.c)

===>handle_irq_event_percpu  (kernel/irq/handle.c)

===>__handle_irq_event_percpu  (kernel/irq/handle.c)

 

根據log,我們可以在下圖看到note_interrupt,即說明noirqdebug=0

Kernel/irq/handle.c

因為上面我們已經分析過bad_action_ret(action_ret)傳回為0

因此在note_interrupt函式裡面只會從如下分支進去

Kernel/irq/spurious.c

從上圖可以看出,如果想出現那樣的錯誤,必須滿足條件

desc->irqs_unhandled > 99900為真

如要要滿足如上條件的話,那麼只有如下地方會讓irqs_unhandled++

Kernel/irq/spurious.c                 

通過上圖,我們可以看到,必須滿足條件:

action_ret == IRQ_NONE為真

再繼續看回如下圖,action_ret就是retval

res即為action_ret

而 action->handler的回呼函式是:

request_threaded_irq執行緒化註冊中斷的第2個引數

kernel/irq/manage.c

因為handlerNULL,所以handler = irq_default_primary_handler

action_ret= IRQ_WAKE_THREAD

Kernel/irq/spurious.c

經過如上圖,我們可以發現action_ret = IRQ_NONE

那麼我們接下來看看到底是怎麼被呼叫到這裡的,一個中斷的產生又是怎樣的?

首先handle_level_irq這個函式是在這裡註冊到kernel中的

drivers/pinctrl/bcm/pinctrl-iproc-gpio.c

static intiproc_gpio_probe(struct platform_device *pdev)

===>gpiochip_irqchip_add

Include/linux/gpio/driver.h

typedef    void(*irq_flow_handler_t)(struct irq_desc *desc);

這裡即gpiochip->irq_handler = handle_level_irq

 

struct irqaction *action;

一個中斷開始的時候

arch/arm/kernel/entry-armv.S

這裡有一個全域性的handle_arch_irq

這個全域性的handle_arch_irq會在如下地方被賦值

arch/arm/kernel/setup.c

void __init setup_arch(char**cmdline_p)

===> handle_arch_irq被賦值

那麼接下來我們就要找到mdesc->handle_irq又是在哪裡被賦值了呢?

 

drivers/irqchip/irq-gic.c

這裡有這樣的函式set_handle_irq

接下來我們看下這個函式的實現就知道了

arch/arm/kernel/irq.c

那麼這個set_handle_irq又是在哪裡被呼叫的呢?

針對內核版本Linux-4.9.18

drivers/irqchip/irq-gic.c

gic_of_init

===>__gic_init_bases

===>set_handle_irq

Include/linux/irqchip.h

Include/linux/of.h

Include/linux/of.h

因此我們得出一個結論:

handle_arch_irq = gic_handle_irq

一個中斷開始後,從entry-armv.S中進入

handle_domain_irq

===> __handle_domain_irq

===>generic_handle_irq

===>generic_handle_irq_desc

這裡的desc->handle_irq其實就是handle_level_irq

這裡是如何轉換過去的呢?

drivers/pinctrl/bcm/pinctrl-iproc-gpio.c

gpiochip_set_chained_irqchip

===>irq_set_chained_handler_and_data

===> __irq_do_set_handler

Kernel/irq/chip.c

回歸到最初的問題,之前我們分析出如下的結論:

如果想出現log那樣的錯誤,必須滿足條件

desc->irqs_unhandled > 99900為真

如要要滿足如上條件的話,那麼只有讓irqs_unhandled++

那麼滿足這個條件就必須action_ret== IRQ_NONE

#defineSPURIOUS_DEFERRED      0x80000000

如下圖:

也就是必須要滿足handled !=desc->threads_handled_last為假

這裡handled= threads_handled

desc->threads_handled_last會在如下位置設置為SPURIOUS_DEFERRED

再看下圖

 

Kernel/irq/manage.c

Irq_thread

這裡會一直將threads_handled++ ,這裡handled =threads_handled

直到滿足handled !=desc->threads_handled_last為假

 

那麼為什麼這個threads_handled會一直++呢?

因為這裡:

上圖是正確的修改,如果gpiochip_irqchip_add的第四個引數是handle_simple_irq的話,

那麼就會出現threads_handled會一直++的情況,從而產生本文最開頭的錯誤

[ 233.370296] irq44: nobody cared (try booting with the “irqpoll” option)

[ 233.549300] DisablingIRQ #44

這裡我們就要對handle_simple_irq 與handle_level_irq做個分析了,具體的分析大家可以網上看蝸窩的資料以及csdn上很多對這塊有詳細的描述,我這裡簡單敘述下我個人的理解

首先上代碼:

大家可以看出來,handle_simple_irq做的事情很簡單,而handle_level_irq卻做了這個動作

mask_ack_irq(desc);因為是電平中斷,如果不做mask中斷的動作的話,會因為中斷電平一直是有效電平導致中斷控制器會源源不斷地給cpu發中斷

而handle_simple_irq就是非常簡單的處理中斷,沒有mask中斷,原本代碼是寫的handle_simple_irq,而觸摸屏的中斷是設置為執行緒化的,並且為電平觸發方式,那麼如果沒有mask該中斷,那麼當一次執行緒化中斷處理函式還未執行完成的時候,又會有源源不斷地中斷一直進來,那麼就會出現threads_handled會一直++的情況,從而產生本文最開頭的錯誤

到此這個問題就已經分析完了

 

 

如下只是個小記錄:

這個函式的作用是檢查是否有中斷嵌套

【作者】張昺華

【新浪微博】張昺華–sky

【博客園】 http://www.cnblogs.com/sky-heaven/

【知乎】 http://www.zhihu.com/people/zhang-bing-hua

【我的作品旋轉倒立擺】 http://v.youku.com/v_show/id_XODM5NDAzNjQw.html?spm=a2hzp.8253869.0.0&from;=y1.7-2

【我的作品自平衡自動循跡車】 http://v.youku.com/v_show/id_XODM5MzYyNTIw.html?spm=a2hzp.8253869.0.0&from;=y1.7-2

 

 

參考:

http://www.wowotech.net/irq_subsystem/request_threaded_irq.html

http://www.wowotech.net/linux_kenrel/interrupt_descriptor.html

https://blog.csdn.net/tiantao2012/article/details/78062621

https://blog.csdn.net/tiantao2012/article/details/78094691

https://blog.csdn.net/zhao2272062978/article/details/70599978

https://blog.csdn.net/droidphone/article/details/7467436

https://blog.csdn.net/droidphone/article/details/7445825

https://blog.csdn.net/droidphone/article/category/1118447

https://blog.csdn.net/phenix_lord/article/details/45116259

https://blog.csdn.net/phenix_lord/article/details/45116595

https://blog.csdn.net/phenix_lord/article/details/45116689

 

赞(0)

分享創造快樂