ARM GIC介紹

一、GIC介紹

GIC(Generic Interrupt Controller)ARM公司提供的一個通用的中斷控制器,目前有4個版本GICv1 ~ GICv4GICv1已棄用;GICv2最多支持8個ARM Core;GICv3/GICv4支持更多的ARM Core)。

GIC的核心功能:對SOC中外設的中斷源的管理,并提供給軟件,配置以及控制這些中斷源。當對應的中斷源有效時,GIC根據(jù)中斷源配置,決定是否將該中斷信號發(fā)給CPU。如果有多個中斷源有效,那么GIC還會進行仲裁,選擇最高優(yōu)先級中斷,發(fā)送給CPU。當CPU接收到GIC發(fā)送的中斷,通過讀取GIC的寄存器,可以知道中斷的來源,從而做對應的處理。當CPU處理完中斷后,會配置GIC寄存器,表示該中斷已處理完畢。GIC接收到信息后,就將該中斷源取消,避免又重新發(fā)送該中斷給CPU,以及允許中斷搶占。

二、GIC IP

對于不同的GIC版本,ARM公司設計了對應的GIC IP。

1)GIC-400:支持GICv2版本。

2)GIC-500:支持GICv3版本。

3)GIC-600:支持GICv3版本。

4)GIC-700:支持GICv3/GICv4.1版本。

CPUGIC之間兼容性見下圖:

image.png

三、GIC框架

GICv3架構(gòu)包括:

1、Distributor

DistributorSPI外設中斷分發(fā)器,外設經(jīng)特定硬件中斷線連接到Distributor。Distributor判斷SPI中斷的優(yōu)先級,決定優(yōu)先處理哪個中斷,使用中斷重映射表決定中斷的目的PE,同時維護中斷的active/pending/acknowledged狀態(tài)。

2、Redistributor

Redistributor:管理SGI/PPI/LPI中斷,決定他們的優(yōu)先級,觸發(fā)方式,控制他們的狀態(tài),以及enable/disable特定中斷。

3、CPU interface

CPU interface:傳輸中斷給Core。每個Redistributor連接一個CPU interface,它負責打開和關(guān)閉PE的中斷處理能力,acknowledge中斷,為PE維護一個中斷優(yōu)先級掩碼(只響應更高優(yōu)先級中斷),定義中斷搶占策略,執(zhí)行中斷降級。

4、ITS

ITS(Interrupt Translation Service):接收LPI消息中斷,根據(jù)消息攜帶的event iddevice id,翻譯得到物理中斷線以及目標PEITSdevice之間通過系統(tǒng)總線連接,device采用內(nèi)存地址的形式發(fā)一個中斷消息給ITS

5、 PE

PE(Process element)處理器單元,中斷的最終接收者和處理者。

image.png

GICv2GICv3少了RedistributorITS等功能。

image.png

GICv4GICv3的功能基本相同,增加了直接注入虛擬中斷的能力。

四、GIC中斷類型

GIC中斷類型包括:

1、 SGI(Software Generated Interrupt)

軟中斷,主要用于核間通信,通過寫SGI寄存器產(chǎn)生。

2、PPI(Private Peripheral Interrupt)

私有外設中斷,為某個核的私有中斷。例(arch/arm64/boot/dts/rockchip/rk3399.dtsi):

        # RK3399小核CortexA53 pmu PPI中斷
        pmu_a53 {
                compatible = "arm,cortex-a53-pmu";
                interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW &ppi_cluster0>;
        };

        # RK3399大核CortexA72 pmu PPI中斷
        pmu_a72 {
                compatible = "arm,cortex-a72-pmu";
                interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW &ppi_cluster1>;
        };
        ...
        # ARMV8 timer PPI中斷
        timer {
                compatible = "arm,armv8-timer";
                interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW 0>,
                             <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW 0>,
                             <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW 0>,
                             <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW 0>;
                arm,no-tick-in-suspend;
        };

3、SPI(Shared Peripheral Interrupt)

共享外設中斷,外設中斷可以發(fā)送到任何一個連接的core。例(arch/arm64/boot/dts/rockchip/rk3399.dtsi):

        # RK3399 uart SPI中斷
        uart0: serial@ff180000 {
                compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
                reg = <0x0 0xff180000 0x0 0x100>;
                clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
                clock-names = "baudclk", "apb_pclk";
                interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH 0>;
                reg-shift = <2>;
                reg-io-width = <4>;
                pinctrl-names = "default";
                pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
                status = "disabled";
        };

4、 LPI(Locality-specific Peripheral Interrupt)

特定區(qū)域外設中斷。只在GICv3GICv4上支持。

不同中斷類型的INITD范圍如下:

image.png

image.png

注:目前Linux內(nèi)核驅(qū)動中,使用的是IRQ中斷,沒有使用FIQ中斷,同時禁止IRQ中斷嵌套。

五、GIC中斷觸發(fā)方式

GIC中斷觸發(fā)方式包括:

1、edge-triggered interrupt

邊沿觸發(fā)中斷。支持的中斷類型有:SGI/PPI/SPI/LPI。

2、 level-sensitive interrupt

電平觸發(fā)中斷。支持的中斷類型有:PPI/SPI。

注:GICv2/v3 SPI中斷只支持上升沿或高電平觸發(fā)。

代碼如下:

drivers/irqchip/irq-gic-v3.c

static int gic_set_type(struct irq_data *d, unsigned int type)
{
        unsigned int irq = gic_irq(d);
        void (*rwp_wait)(void);
        void __iomem *base;

        /* Interrupt configuration for SGIs can't be changed */
        if (irq < 16)
                return -EINVAL;

        ## GICv3 SPI只支持高電平和上升沿觸發(fā)中斷
        /* SPIs have restrictions on the supported types */
        if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
                         type != IRQ_TYPE_EDGE_RISING)
                return -EINVAL;
        ...
}

drivers/irqchip/irq-gic.c

static int gic_set_type(struct irq_data *d, unsigned int type)
{
        void __iomem *base = gic_dist_base(d);
        unsigned int gicirq = gic_irq(d);

        /* Interrupt configuration for SGIs can't be changed */
        if (gicirq < 16)
                return -EINVAL;

        ## GICv2 SPI只支持高電平和上升沿觸發(fā)中斷
        /* SPIs have restrictions on the supported types */
        if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
                            type != IRQ_TYPE_EDGE_RISING)
                return -EINVAL;
        ...
}

六、GIC中斷狀態(tài)

GIC中斷狀態(tài)包括:

1、 Inactive

該中斷源當前無效,未發(fā)生中斷。

2、 Pending

已產(chǎn)生中斷,未被PE響應。

3、 Active

該中斷源已經(jīng)發(fā)生并且已被PE響應。

4、 Active and pending

這個中斷已被響應,再一次的中斷正在被pending。

GIC中斷處理狀態(tài)機如下:

image.png

七、GIC中斷周期

GIC中斷處理基于GIC中斷生命周期,中斷生命周期為描述中斷處理過程,包括:

1、Generate interrupt

外設或軟件產(chǎn)生一個中斷。

2、Distribute

IRI(Interrupt Router Interface)實現(xiàn)中斷分組、中斷優(yōu)先級控制、并控制中斷轉(zhuǎn)發(fā)到CPU接口。PPI/SGI是各個Core獨有的中斷,不參與目的Core仲裁。SPI是所有Core共享的,根據(jù)配置決定中斷發(fā)往的Core。最后選擇優(yōu)先級最高的中斷發(fā)給CPU interface。寄存器用GICD_做前綴。

3、Deliver

CPU接口將中斷發(fā)給PE。將GICD發(fā)送的中斷信息,通過IRQ、FIRQ引腳傳輸給Core。寄存器使用GICC_做前綴。

4、Activate

PE通過讀取GICC_IAR寄存器識別中斷,設置最高優(yōu)先級的SGI/PPI/SPI中斷為激活狀態(tài)。

5、Priority drop

PE通過配置GICC_EOIR寄存器,實現(xiàn)優(yōu)先級重置。

6、Deactivation

PE通過配置GICC_DIR寄存器,使該中斷無效。

中斷生命周期流程如下:

image.png

參考:

https://developer.arm.com/documentation/ka002107/1-0

IHI0048B_b_gic_architecture_specification.pdf

IHI0069H_gic_architecture_specification.pdf

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容