吐血整理 | 肝翻 Linux 中斷所有知識點
時間:2021-09-06 15:20:10
手機看文章
掃描二維碼
隨時隨地手機看文章
[導讀]Linux中斷管理機制GIC硬件原理GIC,GenericInterruptController。是ARM公司提供的一個通用的中斷控制器。主要作用為:接受硬件中斷信號,并經(jīng)過一定處理后,分發(fā)給對應的CPU進行處理。當前GIC有四個版本,GICv1~v4,本文主要介紹GICv3控制...
Linux 中斷管理機制
GIC 硬件原理
GIC,Generic Interrupt Controller。是ARM公司提供的一個通用的中斷控制器。主要作用為:接受硬件中斷信號,并經(jīng)過一定處理后,分發(fā)給對應的CPU進行處理。當前GIC 有四個版本,GIC v1~v4, 本文主要介紹GIC v3控制器。GIC v3中斷類別
GICv3定義了以下中斷類型:- SGI (Software Generated Interrupt):軟件觸發(fā)的中斷。軟件可以通過寫 GICD_SGIR 寄存器來觸發(fā)一個中斷事件,一般用于核間通信,內核中的 IPI:inter-processor interrupts 就是基于 SGI。
- PPI (Private Peripheral Interrupt):私有外設中斷。這是每個核心私有的中斷。PPI會送達到指定的CPU上,應用場景有CPU本地時鐘。
- SPI (Shared Peripheral Interrupt):公用的外部設備中斷,也定義為共享中斷。中斷產生后,可以分發(fā)到某一個CPU上。比如按鍵觸發(fā)一個中斷,手機觸摸屏觸發(fā)的中斷。
- LPI (Locality-specific Peripheral Interrupt):LPI 是 GICv3 中的新特性,它們在很多方面與其他類型的中斷不同。LPI 始終是基于消息的中斷,它們的配置保存在表中而不是寄存器。比如 PCIe 的 MSI/MSI-x 中斷。
中斷類型 | 硬件中斷號 |
---|---|
SGI | 0-15 |
PPI | 16-31 |
SPI | 32-1019 |
reserved | ...... |
LPI | 8192-MAX |
GIC v3 組成
GICv3 控制器由以下三部分組成:- Distributor:SPI 中斷的管理,將中斷發(fā)送給 Redistributor
- 打開或關閉每個中斷。Distributor對中斷的控制分成兩個級別。一個是全局中斷的控制(GIC_DIST_CTRL)。一旦關閉了全局的中斷,那么任何的中斷源產生的中斷事件都不會被傳遞到 CPU interface。另外一個級別是對針對各個中斷源進行控制(GIC_DIST_ENABLE_CLEAR),關閉某一個中斷源會導致該中斷事件不會分發(fā)到 CPU interface,但不影響其他中斷源產生中斷事件的分發(fā)。
- 控制將當前優(yōu)先級最高的中斷事件分發(fā)到一個或者一組 CPU interface。當一個中斷事件分發(fā)到多個 CPU interface 的時候,GIC 的內部邏輯應該保證只 assert 一個CPU。
- 優(yōu)先級控制。
- interrupt屬性設定。設置每個外設中斷的觸發(fā)方式:電平觸發(fā)、邊緣觸發(fā);
- interrupt group的設定。設置每個中斷的 Group,其中 Group0 用于安全中斷,支持 FIQ 和 IRQ,Group1 用于非安全中斷,只支持 IRQ;
- Redistributor:SGI,PPI,LPI 中斷的管理,將中斷發(fā)送給 CPU interface
- 啟用和禁用 SGI 和 PPI。
- 設置 SGI 和 PPI 的優(yōu)先級。
- 將每個 PPI 設置為電平觸發(fā)或邊緣觸發(fā)。
- 將每個 SGI 和 PPI 分配給中斷組。
- 控制 SGI 和 PPI 的狀態(tài)。
- 內存中數(shù)據(jù)結構的基址控制,支持 LPI 的相關中斷屬性和掛起狀態(tài)。
- 電源管理支持。
- CPU interface:傳輸中斷給 Core
- 打開或關閉 CPU interface 向連接的 CPU assert 中斷事件。對于 ARM,CPU interface 和 CPU 之間的中斷信號線是 nIRQCPU 和 nFIQCPU。如果關閉了中斷,即便是 Distributor 分發(fā)了一個中斷事件到 CPU interface,也不會 assert 指定的 nIRQ 或者 nFIQ 通知 Core。
- 中斷的確認。Core 會向 CPU interface 應答中斷(應答當前優(yōu)先級最高的那個中斷),中斷一旦被應答,Distributor 就會把該中斷的狀態(tài)從 pending 修改成 active 或者 pending and active(這是和該中斷源的信號有關,例如如果是電平中斷并且保持了該 asserted 電平,那么就是 pending and active)。ack 了中斷之后,CPU interface 就會 deassert nIRQCPU 和 nFIQCPU 信號線。
- 中斷處理完畢的通知。當 interrupt handler 處理完了一個中斷的時候,會向寫 CPU interface 的寄存器通知 GIC CPU 已經(jīng)處理完該中斷。做這個動作一方面是通知 Distributor 將中斷狀態(tài)修改為 deactive,另外一方面,CPU interface 會 priority drop,從而允許其他的 pending 的中斷向 CPU 提交。
- 為 CPU 設置中斷優(yōu)先級掩碼。通過 priority mask,可以 mask 掉一些優(yōu)先級比較低的中斷,這些中斷不會通知到 CPU。
- 設置 CPU 的中斷搶占(preemption)策略。
- 在多個中斷事件同時到來的時候,選擇一個優(yōu)先級最高的通知 CPU。
中斷路由
GICv3 使用 hierarchy 來標識一個具體的 core, 如下圖是一個四層的結構(aarch64): 用 ... 的形式組成一個 PE 的路由。每一個 core 的 affnity 值可以通過 MPDIR_EL1 寄存器獲取, 每一個 affinity 占用8bit。配置對應 core 的 MPIDR 值,可以將中斷路由到該 core 上。各個 affinity 的定義是根據(jù) SOC 自己的定義,比如:.?..
...
中斷親和性的設置的通用函數(shù)為 irq_set_affinity,后面會做詳細介紹。中斷狀態(tài)機
中斷處理的狀態(tài)機如下圖:- Inactive:無中斷狀態(tài),即沒有 Pending 也沒有 Active。
- Pending:硬件或軟件觸發(fā)了中斷,該中斷事件已經(jīng)通過硬件信號通知到 GIC,等待 GIC 分配的那個 CPU 進行處理,在電平觸發(fā)模式下,產生中斷的同時保持 Pending 狀態(tài)。
- Active:CPU 已經(jīng)應答(acknowledge)了該中斷請求,并且正在處理中。
- Active and pending:當一個中斷源處于 Active 狀態(tài)的時候,同一中斷源又觸發(fā)了中斷,進入 pending 狀態(tài)。
中斷處理流程
- 外設發(fā)起中斷,發(fā)送給 Distributor
- Distributor 將該中斷,分發(fā)給合適的 Redistributor
- Redistributor 將中斷信息,發(fā)送給 CPU interface
- CPU interface 產生合適的中斷異常給處理器
- 處理器接收該異常,并且軟件處理該中斷
GIC 驅動
這里主要分析 linux kernel 中 GIC v3 中斷控制器的代碼(drivers/irqchip/irq-gic-v3.c)。設備樹
先來看下一個中斷控制器的設備樹信息:gic:?interrupt-controller@51a00000?{
????????compatible?=?"arm,gic-v3";
????????reg?=?<0x0?0x51a00000?0?0x10000>,?/*?GIC?Dist?*/
??????????????<0x0?0x51b00000?0?0xC0000>,?/*?GICR?*/
??????????????<0x0?0x52000000?0?0x2000>,??/*?GICC?*/
??????????????<0x0?0x52010000?0?0x1000>,??/*?GICH?*/
??????????????<0x0?0x52020000?0?0x20000>;?/*?GICV?*/
????????#interrupt-cells?=?<3>;
????????interrupt-controller;
????????interrupts?=?9
????????????????(GIC_CPU_MASK_SIMPLE(6)?|?IRQ_TYPE_LEVEL_HIGH)>;
????????interrupt-parent?=?<