Linux的IRQ中斷子系統(tǒng)分析
本文以Linux中斷子系統(tǒng)架構為視角,旨在提供一個對Linux中斷系統(tǒng)的全局認識,不涉及具體實現(xiàn)細節(jié)。
一、Linux中斷子系統(tǒng)架構
在Linux中斷子系統(tǒng)(generic irq)出現(xiàn)之前,內核使用__do_IRQ處理所有的中斷,這意味著__do_IRQ中要處理各種類型的中斷,這會導致軟件的復雜性增加,層次不分明,而且代碼的可重用性也不好。通用中斷子系統(tǒng)的原型最初出現(xiàn)于ARM體系中,一開始內核的開發(fā)者們把3種中斷類型區(qū)分出來(電平中斷、邊緣中斷、簡易中斷),后來又針對某些需要回應eoi(end of interrupt)的中斷控制器,加入了fast eoi type,針對smp加入了per cpu type。把這些不同的中斷類型抽象出來后,成為了中斷子系統(tǒng)的流控層。要使所有的體系架構都可以重用這部分的代碼,中斷控制器也被進一步地封裝起來,形成了中斷子系統(tǒng)中的芯片級硬件封裝層。
二、芯片級硬件封裝層
中斷系統(tǒng)與CPU硬件關系密切,linux系統(tǒng)為了兼容各種型號的CPU,提供了對于各種CPU的特性及其中斷控制器的底層封裝,這樣就可以把底層的硬件實現(xiàn)盡可能地隱藏起來,使得驅動程序的開發(fā)人員不用關注底層的實現(xiàn)。該部分主要工作是:
- 實現(xiàn)不同CPU的中斷入口,初始化中斷向量表,該部分通常由匯編實現(xiàn)。
- 對中斷控制器實現(xiàn)軟件抽象(struct irq_chip),源碼路徑如:” arch/arm/plat-s3c24xx/irq.c”
該部分初始化過程中,系統(tǒng)根據(jù)設備使用的中斷控制器的類型,實現(xiàn)irq_chip結構中的接口,并把該irq_chip實例注冊到irq_desc.irq_data.chip字段中,這樣各個irq和中斷控制器就進行了關聯(lián),只要知道irq編號,即可得到對應到irq_desc結構,進而可以通過chip指針訪問中斷控制器。 其初始化流程如下圖所示:
三、中斷流控層
由linux內核提供,所謂中斷流控是指合理并正確地處理連續(xù)發(fā)生的中斷,比如一個中斷在處理中,同一個中斷再次到達時如何處理,何時應該屏蔽中斷,何時打開中斷,何時回應中斷控制器等一系列的操作。該層實現(xiàn)了與體系和硬件無關的中斷流控處理操作,它針對不同的中斷電氣類型(level,edge......),實現(xiàn)了對應的標準中斷流控處理函數(shù),在這些處理函數(shù)中,最終會把中斷控制權傳遞到驅動程序注冊中斷時傳入的處理函數(shù)或者是中斷線程中。
目前的通用中斷子系統(tǒng)實現(xiàn)了以下這些標準流控回調函數(shù),這些函數(shù)都定義在:”kernel/irq/chip.c”中,
handle_simple_irq 用于簡易流控處理;
handle_level_irq 用于電平觸發(fā)中斷的流控處理;
handle_edge_irq 用于邊沿觸發(fā)中斷的流控處理;
handle_fasteoi_irq 用于需要響應eoi的中斷控制器;
handle_percpu_irq 用于只在單一cpu響應的中斷;
handle_nested_irq 用于處理使用線程的嵌套中斷;
以下這個序列圖展示了整個通用中斷子系統(tǒng)的中斷響應過程,flow_handle一欄就是中斷流控層的生命周期:
四、中斷驅動接口層
由linux內核提供,驅動程序的開發(fā)者通常只會使用到這一層提供的這些接口即可完成驅動程序的開發(fā)工作,其他的細節(jié)都由另外幾個軟件層較好地“隱藏”起來了,驅動程序開發(fā)者無需再關注底層的實現(xiàn)。該部分向驅動程序提供的一系列的編程,用于向系統(tǒng)申請/釋放中斷,打開/關閉中斷,設置中斷類型和中斷喚醒系統(tǒng)的特性等操作。常用的一些接口如:
- l request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
用來向Linux申請中斷。
irq是要申請的硬件中斷號。
handler是向系統(tǒng)注冊的中斷處理函數(shù)。
irqflags是中斷處理的屬性,一般用來指定相應的中斷流控。
devname設置中斷名稱,通常是在cat /proc/interrupts中可以看到此名稱。
dev_id在中斷共享時會用到,一般設置為這個設備的設備結構體或者NULL。
- enable_irq(unsigned int irq)
用來打開中斷。
- disable_irq(unsigned int irq)
用來關閉中斷。
- irq_set_chip(irq, *chip)
設置中斷控制器
- irq_set_handler(irq,handle)
設置中斷流控
中斷子系統(tǒng)內部定義了幾個重要的數(shù)據(jù)結構,這些數(shù)據(jù)結構的各個字段控制或影響著中斷子系統(tǒng)和各個irq的行為和實現(xiàn)方式。例如:irq_desc,irq_chip,irq_data,irqaction,等等。其中 irq_desc[NR_IRQS]數(shù)組是linux內核中用于維護IRQ資源的管理單元,它記錄了某IRQ號對應的流控處理函數(shù),中斷控制器、中斷服務程序、IRQ自身的屬性、資源等,是內核中斷子系統(tǒng)的一個核心數(shù)組,中斷驅動接口“request_irq()”就是通過修改該數(shù)組以實現(xiàn)中斷的注冊。
五、中斷驅動程序設計
有了前幾層所做的貢獻,使得我們進行l(wèi)inux中斷驅動設計變得異常簡單。一般情況下,我們只需要使用”request_irq”函數(shù)向內核注冊相應的中斷號及其中斷服務程序,然后調用“enable_irq”“disable_irq”開開或關閉中斷即可。其流程如下圖所示:
六、中斷服務程序設計
當CPU收到中斷,就會執(zhí)行相應中斷服務程序,我們知道CPU在執(zhí)行中斷服務程序時是不能執(zhí)行其他程序的,甚至此時CPU不能響應某些優(yōu)先級比它低的中斷,如果CPU一直長時間執(zhí)行某個中斷服務程序,勢必影響系統(tǒng)的響應速度,降低了系統(tǒng)性能。為此Linux中斷子系統(tǒng)將中斷分為了中斷上文和中斷下文,中斷上文用來執(zhí)行一些緊迫的程序,中斷下文用來執(zhí)行一些不緊急的可延后執(zhí)行的程序。Linux提供了三種機制來處理中斷下文:Soft irq(軟中斷)、Tasklet、work_queue(工作隊列)。
Ø 軟中斷
Ø Tasklet
Ø Work_queue