天天看點

Linux的IRQ中斷子系統分析

本文以linux中斷子系統架構為視角,旨在提供一個對linux中斷系統的全局認識,不涉及具體實作細節。

一、linux中斷子系統架構

在linux中斷子系統(generic irq)出現之前,核心使用__do_irq處理所有的中斷,這意味着__do_irq中要處理各種類型的中斷,這會導緻軟體的複雜性增加,層次不分明,而且代碼的可重用性也不好。通用中斷子系統的原型最初出現于arm體系中,一開始核心的開發者們把3種中斷類型區分出來(電平中斷、邊緣中斷、簡易中斷),後來又針對某些需要回應eoi(end of interrupt)的中斷控制器,加入了fast eoi type,針對smp加入了per cpu type。把這些不同的中斷類型抽象出來後,成為了中斷子系統的流控層。要使所有的體系架構都可以重用這部分的代碼,中斷控制器也被進一步地封裝起來,形成了中斷子系統中的晶片級硬體封裝層。

Linux的IRQ中斷子系統分析

二、晶片級硬體封裝層

中斷系統與cpu硬體關系密切,linux系統為了相容各種型号的cpu,提供了對于各種cpu的特性及其中斷控制器的底層封裝,這樣就可以把底層的硬體實作盡可能地隐藏起來,使得驅動程式的開發人員不用關注底層的實作。該部分主要工作是:

實作不同cpu的中斷入口,初始化中斷向量表,該部分通常由彙編實作。

對中斷控制器實作軟體抽象(struct irq_chip),源碼路徑如:” arch/arm/plat-s3c24xx/irq.c”

該部分初始化過程中,系統根據裝置使用的中斷控制器的類型,實作irq_chip結構中的接口,并把該irq_chip執行個體注冊到irq_desc.irq_data.chip字段中,這樣各個irq和中斷控制器就進行了關聯,隻要知道irq編号,即可得到對應到irq_desc結構,進而可以通過chip指針通路中斷控制器。 其初始化流程如下圖所示:

Linux的IRQ中斷子系統分析

三、中斷流控層

由linux核心提供,所謂中斷流控是指合理并正确地處理連續發生的中斷,比如一個中斷在進行中,同一個中斷再次到達時如何處理,何時應該屏蔽中斷,何時打開中斷,何時回應中斷控制器等一系列的操作。該層實作了與體系和硬體無關的中斷流控處理操作,它針對不同的中斷電氣類型(level,edge......),實作了對應的标準中斷流控處理函數,在這些處理函數中,最終會把中斷控制權傳遞到驅動程式注冊中斷時傳入的處理函數或者是中斷線程中。

目前的通用中斷子系統實作了以下這些标準流控回調函數,這些函數都定義在:”kernel/irq/chip.c”中,

handle_simple_irq 用于簡易流控處理;

handle_level_irq 用于電平觸發中斷的流控處理;

handle_edge_irq 用于邊沿觸發中斷的流控處理;

handle_fasteoi_irq 用于需要響應eoi的中斷控制器;

handle_percpu_irq 用于隻在單一cpu響應的中斷;

handle_nested_irq 用于處理使用線程的嵌套中斷;

以下這個序列圖展示了整個通用中斷子系統的中斷響應過程,flow_handle一欄就是中斷流控層的生命周期:

四、中斷驅動接口層

由linux核心提供,驅動程式的開發者通常隻會使用到這一層提供的這些接口即可完成驅動程式的開發工作,其他的細節都由另外幾個軟體層較好地“隐藏”起來了,驅動程式開發者無需再關注底層的實作。該部分向驅動程式提供的一系列的程式設計,用于向系統申請/釋放中斷,打開/關閉中斷,設定中斷類型和中斷喚醒系統的特性等操作。常用的一些接口如:

l request_irq(unsigned int irq, irq_handler_t handler,

unsigned long irqflags, const char *devname, void *dev_id)

用來向linux申請中斷。

irq是要申請的硬體中斷号。

handler是向系統注冊的中斷處理函數。

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)

設定中斷流控

中斷子系統内部定義了幾個重要的資料結構,這些資料結構的各個字段控制或影響着中斷子系統和各個irq的行為和實作方式。例如:irq_desc,irq_chip,irq_data,irqaction,等等。其中 irq_desc[nr_irqs]數組是linux核心中用于維護irq資源的管理單元,它記錄了某irq号對應的流控處理函數,中斷控制器、中斷服務程式、irq自身的屬性、資源等,是核心中斷子系統的一個核心數組,中斷驅動接口“request_irq()”就是通過修改該數組以實作中斷的注冊。

五、中斷驅動程式設計

有了前幾層所做的貢獻,使得我們進行linux中斷驅動設計變得異常簡單。一般情況下,我們隻需要使用”request_irq”函數向核心注冊相應的中斷号及其中斷服務程式,然後調用“enable_irq”“disable_irq”開開或關閉中斷即可。其流程如下圖所示:

六、中斷服務程式設計

當cpu收到中斷,就會執行相應中斷服務程式,我們知道cpu在執行中斷服務程式時是不能執行其他程式的,甚至此時cpu不能響應某些優先級比它低的中斷,如果cpu一直長時間執行某個中斷服務程式,勢必影響系統的響應速度,降低了系統性能。為此linux中斷子系統将中斷分為了中斷上文和中斷下文,中斷上文用來執行一些緊迫的程式,中斷下文用來執行一些不緊急的可延後執行的程式。linux提供了三種機制來進行中斷下文:soft irq(軟中斷)、tasklet、work_queue(工作隊列)。

Ø 軟中斷

Ø tasklet

Ø work_queue

本文作者:佚名

來源:51cto

繼續閱讀