中斷子系統

在kernel發生中斷後,會跳轉到彙編代碼entry-armv.S中__irq_svc處,進而調用handle_arch_irq,每個中斷控制器的drivver會使用如下:
handle_arch_irq = gic_handle_irq
將自己的中斷入口處理函數賦值給這個指針,這裏是gic的入口函數,從而進入GIC驅動,進行後續的中斷處理

http://blog.csdn.net/yimu13/article/details/6803957
http://bbs.chinaunix.net/thread-3566316-1-1.html
http://blog.csdn.net/droidphone/article/details/7467436 Linux中斷(interrupt)子系統之二:arch相關的硬件封裝層
http://blog.chinaunix.net/uid-23046336-id-3279553.html 解密ARM based Linux內核中斷處理框架
http://blog.csdn.net/hanchaoman/article/details/7099142 kernel 中斷詳解
http://blog.csdn.net/droidphone/article/details/7445825
http://www.bubuko.com/infodetail-1033486.html
http://www.cnblogs.com/pengdonglin137/p/6349209.html#_lab2_3_2
http://www.cnblogs.com/wmx-learn/p/5360269.html 老的do_asm方式的中斷,基本流程可以借鑑
http://blog.sina.com.cn/s/blog_95268f5001013ve7.html gpio中斷的例子
http://blog.csdn.net/laviolette/article/details/51577604 共享中斷

以上圖爲例:
ARM CPU 對外的連接只有 2 箇中斷,一個是 IRQ ,一個是 FIQ ,相對應的處理模式分別是一般中斷( IRQ )處理模式和快速中斷( FIQ )處理模式。所以 GIC 最後要把中斷彙集成 2 條線,與 CPU 對接。一個core只能連接一箇中斷控制器(即一個core只能同時處理一個任務),但是一箇中斷控制器可以連多個core(即中斷控制器可以下發中斷任務給多個core)
arm的中斷控制器以gic爲例,作爲 ARM 系統中通用中斷控制器的是 GIC(Generic Interrupt Controller) ,目前有四個版本,V1~V4(V2最多支持8個ARM core,V3/V4支持更多的ARM core,主要用於ARM64系統結構)。目前在ARM官方網站只能下載到Version 2的GIC architecture specification。其中GIC-500最多支持128個 cpu core,它要求ARM core必須是ARMV8指令集的(例如Cortex-A57),符合GIC architecture specification version 3。
中斷控制器用於收集中斷,它可以支持的中斷狀態寄存器的bit位代表它支持多少位中斷輸入,我們這裏暫且是4個32位的中斷中斷狀態寄存器,即共有4 x 32 = 128箇中斷輸入接口。
每一箇中斷接口又可以級聯更多的中斷源,如圖中bit 0,即0號硬件中斷外邊連了128個gpio pin,每個pin都支持中斷髮生。但是這些pin是共享中斷控制器這一層的0號中斷接口。當gpio的任何一個pin發生中斷時,都會觸發中斷控制器的狀態寄存器的bit0置位,表示發生了gpio中斷,然後去通知core去執行中斷程序。
那這128個gpio pin共享一個硬件中斷是如何區分哪一個pin的中斷髮生?在gpio這一級又有它自己的中斷狀態寄存器,128個pin也就有4個狀態寄存器,供128個bit,每個bit的置位表示一個gpio中斷的發生。
所以一箇中斷髮生時,會先查詢中斷控制器的狀態寄存器,看是哪一個中斷源發生了中斷,然後在看這個中斷源上是否級聯了下一級中斷源(例如GPIO共享一個硬件中斷入口),如果有就繼續查詢,如果沒有,就直接處理當前的中斷
當外設發生中斷時,首先進入中斷控制器,讓中斷控制器進行裁決,然後在去觸發連着的cpu的中斷接口。

在linux kernel中,對於每一個外設的IRQ都用struct irq_desc來描述,我們稱之中斷描述符(struct irq_desc)。linux kernel中會有一個數據結構保存了關於所有IRQ的中斷描述符信息,我們稱之中斷描述符DB(上圖中紅色框圖內)。當發生中斷後,首先獲取觸發中斷的HW interupt ID,然後通過irq domain翻譯成IRQ nuber,然後通過IRQ number就可以獲取對應的中斷描述符。調用中斷描述符中的highlevel irq-events handler來進行中斷處理就OK了

在軟件的角度:
中斷系統分爲2個層面:

1,core
2,core外部的中斷控制器

       local_irq_disable()、local_irq_enable()    -------------->對應的是core內部的中斷,就是core接不接受你這個中斷進來,或者要不要響應
disable_irq()、enable_irq()---------------------------->對應的是連接core的外部中斷控制器的中斷

在內核中,透過irq_chip 結構體來描述中斷控制器。該結構體內部封裝了中斷mask、unmask、ack 等成員函數
local_irq_disable()、local_irq_enable() 常用來做數據的保護和互斥
gic是arm core常用的中斷控制器:
只要有這幾個中斷類型
SGI(Software-generated interrupt),PPI(Private peripheral interrupt )、SPI(Shared peripheral interrupt)
顧名思義SGI爲軟件可以觸發的中斷,經常用於各個core之間的通信,PPI爲每個core的私有外設中斷,SPI爲各個core公用的中斷
SGI:0~15
PPI:16-31
SPI:32~1019

對於root GIC
hwirq_base = 16;
gic_irqs = 系統支持的所有的中斷數目-16。之所以減去16主要是因爲root GIC的0~15號HW interrupt 是for IPI的,因此要去掉。也正因爲如此hwirq_base從16開始

一般前32(0-31)個我們不去使用,我們從32開始映射我們的中斷狀態寄存器,加入我們有32*4個寄存器,那麼我們就會抽象出(32~(32+32*4))的中斷號,用於軟件上使用。
中斷的核心過程,首先是我們提前按照這個中斷號去註冊我們的中斷執行函數;
然後當硬件中斷髮生後,軟件層面去獲取這個發生的硬件中斷號(是否有映射),然後和註冊的中斷號去匹配,匹配成功後然後去執行該中斷號綁定的中斷函數。

中斷控制器的描述:struct irq_chip
中斷號的描述:struct irq_desc

關於HW interrupt ID映射到IRQ number上 這事,在過去系統只有一個interrupt controller的時候還是很簡單的,中斷控制器上實際的HW interrupt line的編號可以直接變成IRQ number。例如我們大家都熟悉的SOC內嵌的interrupt controller,這種controller多半有中斷狀態寄存器,這個寄存器可能有64個bit(也可能更多),每個bit就是一個IRQ number,可以直接進行映射。這時候,GPIO的中斷在中斷控制器的狀態寄存器中只有一個bit,因此所有的GPIO中斷只有一個IRQ number,在該通用GPIO中斷的irq handler中進行deduplex,將各個具體的GPIO中斷映射到其相應的IRQ number上
問題1:我們如何知道這個硬件中斷的系統中斷號是多少?是線性排列的還是動態獲取的?
2:爲什麼root gic在映射系統中斷號的時候要從16開始而不是32開始

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章