ARM GIC 系列文章學習(轉)


原文來自:駿的世界

ARM GIC(一) cortex-A 處理器中斷簡介

對於ARM的處理器,中斷給處理器提供了觸覺,使處理器能夠感知到外界的變化,從而實時的處理。本系列博文,是以ARM cortex-A系列處理器,來介紹ARM的soc中,中斷的處理。

ARM cortex-A系列處理器,提供了4個管腳給soc,實現外界中斷的傳遞。分別是:

  • nIRQ: 物理普通中斷
  • nFIQ: 物理快速中斷
  • nVIRQ: 虛擬普通中斷
  • nVFIQ: 虛擬快速中斷

如下圖所示:

img

其中虛擬中斷,是為了實現虛擬化而加入的,在這個系列中,不討論虛擬中斷,只介紹物理中斷的相關知識。

在arm的soc系統中,會有多個外設,均有可能會產生中斷發送給arm cpu,等待cpu處理。

而arm cpu對中斷,只提供了2根信號,一個nIRQ,一個是nFIQ。因此就需要有一個中斷控制器來作為中間的橋接,收集soc的所有中斷信號,然后仲裁選擇合適的中斷,再發送給CPU,等待CPU處理。

如下圖所示:

img

這中間的橋接器件,就是arm公司推出大名鼎鼎的GIC,general interrupt controller。

GIC其實是一個架構,版本歷經了GICv1(已棄用),GICv2,GICv3,GICv4。對於不同的GIC版本,arm公司設計了對應的GIC IP。

  • GIC400,支持GICv2架構版本。
  • GIC500,支持GICv3架構版本。
  • GIC600,支持GICv3架構版本。

GIC的核心功能:對soc中外設的中斷源的管理,並且提供給軟件,配置以及控制這些中斷源。

當對應的中斷源有效時,GIC根據該中斷源的配置,決定是否將該中斷信號,發送給CPU。如果有多個中斷源有效,那么GIC還會進行仲裁,選擇最高優先級中斷,發送給CPU。

當CPU接受到GIC發送的中斷,通過讀取GIC的寄存器,就可以知道,中斷的來源來自於哪里,從而可以做相應的處理。

當CPU處理完中斷之后,會告訴GIC(通過訪問GIC的寄存器),該中斷處理完畢。GIC接受到該信息后,就將該中斷源取消,避免又重新發送該中斷給cpu以及允許中斷搶占。

之后,會先介紹下GICv2的相關知識,然后介紹目前主流使用的GICv3。

ARM GIC(二)中斷術語

ARM在GIC中,對於中斷,定義了如下的一些術語。

中斷狀態

對於每一個中斷而言,有以下4個狀態:

  • inactive:中斷處於無效狀態

  • pending:中斷處於有效狀態,但是cpu沒有響應該中斷

  • active:cpu在響應該中斷

  • active and pending:cpu在響應該中斷,但是該中斷源又發送中斷過來

以下是中斷狀態的轉移圖。至於圖中的轉移條件,在GIC架構文檔中,有介紹。

img

中斷觸發方式

中斷觸發方式,包含以下兩種方式:

  • edge-triggered:邊沿觸發,當中斷源產生一個邊沿,中斷有效
  • level-sensitive:電平觸發,當中斷源為指定電平,中斷有效

中斷類型

中斷類型分為以下幾類:

  • PPI:(private peripheral interrupt),私有外設中斷,該中斷來源於外設,但是該中斷只對指定的core有效。
  • SPI:(shared peripheral interrupt),共享外設中斷,該中斷來源於外設,但是該中斷可以對所有的core有效。
  • SGI:(software-generated interrupt),軟中斷,軟件產生的中斷,用於給其他的core發送中斷信號
  • virtual interrupt:虛擬中斷,用於支持虛擬機

中斷優先級

因為soc中,中斷有很多,為了方便對中斷的管理,對每個中斷,附加了中斷優先級。在中斷仲裁時,高優先級的中斷,會優於低優先級的中斷,發送給cpu處理。

當cpu在響應低優先級中斷時,如果此時來了高優先級中斷,那么高優先級中斷會搶占低優先級中斷,而被處理器響應。

中斷號

為了方便對中斷的管理,GIC為每個中斷,分配了一個中斷號,也就是interrupt ID。對於中斷號,GIC也進行了分配:

  • ID0-ID15:分配給SGI,軟中斷
  • ID16-ID31:分配給PPI,私有外設中斷
  • ID32-ID1019分配給SPI,共享外設中斷
  • 其他

在具體的arm的cpu中,對於PPI,又進行了詳細的分配。這個,就得看arm cpu的TRM了。

中斷生命周期

一個中斷,是有生命周期的。以下是流程圖:

Start=>start: Start,中斷開始
generate=>operation: generate,中斷源產生中斷,發送給GIC
deliver=>operation: deliver,GIC將中斷發送給cpu
activate=>operation: Activate,cpu響應該中斷
deactivate=>operation: Deactivate,cpu響應完中斷,告訴GIC,中斷處理完畢,GIC更新該中斷狀態
end=>end: End,中斷結束
Start->generate->deliver->activate->deactivate->end

banking

banking(不知翻譯成啥比較合適)功能,包括以下兩個:

中斷banking

對於PPI和SGI,GIC可以有多個中斷對應於同一個中斷號。比如在soc中,有多個外設的中斷,共享同一個中斷號。

寄存器banking

對於同一個GIC寄存器地址,在不同的情況下,訪問的是不同的寄存器。例如在secure和non-secure狀態下,訪問同一個GIC寄存器,其實是訪問的不同的GIC的寄存器。

具體,更多的信息,得看GIC spec以及arm spec。

ARM GIC(三) GICv2架構

ARM的cpu,特別是cortex-A系列的CPU,目前都是多core的cpu,因此對於多core的cpu的中斷管理,就不能像單core那樣簡單去管理,由此arm定義了GICv2架構,來支持多核cpu的中斷管理。

GICv2架構

GICv2,支持最大8個core。其框圖如下圖所示:

img

在GICv2中,GIC由兩個大模塊組成:

  • distributor:實現中斷分發,對於PPI,SGI是各個core獨有的中斷,不參與目的core的仲裁,SPI,是所有core共享的,根據配置決定中斷發往的core。最后選擇最高優先級中斷發送給cpu interface。寄存器使用 GICD_ 作為前綴。一個GIC中,只有一個GICD。

  • cpu interface:將GICD發送的中斷信息,通過IRQ,FIQ管腳,傳輸給core。寄存器使用 GICC_ 作為前綴。每一個core,有一個cpu interface。

  • virtual cpu interface:將GICD發送的虛擬中斷信息,通過VIRQ,VFIQ管腳,傳輸給core。每一個core,有一個virtual cpu interface。而在這virtual cpu interface中,又包含以下兩個組件:

    • virtual interface control:寄存器使用 GICH_ 作為前綴
    • virtual cpu interface:寄存器使用 GICV_ 作為前綴

圖中的virtual interface,是用於支持虛擬中斷,本系列不討論虛擬中斷。

GICv2支持中斷旁路模式,也就是GIC外部的FIQ,IRQ直接接到core的FIQ,IRQ上,相當於GIC是不使能的。也就是CFGSDISABLE是有效的,將GIC給無效掉。

GICv2,定義了自己的一些寄存器,這些寄存器,都是使用memory-mapped的方式去訪問的,也就是在soc中,會留有一片空間,給GIC。cpu通過訪問這部分空間,來對GIC進行操作。

寄存器,分為以下:

  • GICD_*: distributor的寄存器
  • GICH_*: 虛擬interface的控制寄存器
  • GICV_*:虛擬interface的控制寄存器
  • GICC_*: 虛擬cpu interface的寄存器

中斷分組

givc2,將中斷,分成了group0和group1。使用寄存器GICD_IGROUPRn來對每個中斷,設置組。

img

  • group0:安全中斷,由nFIQ驅動
  • group1:非安全中斷,由nIRQ驅動

中斷號

GICv2,支持最大1020個中斷。其中斷號分配如下:

中斷號 分配 中斷來源 寄存器
ID0-ID7 非安全軟中斷 軟件 GICD_SGIR
ID8-ID15 安全軟中斷 軟件 GICD_SGIR
ID16-ID31 私有中斷 外設 no
ID32-ID1019 共享中斷 外設 no

GIC結構

GIC主要包括以下兩個組件:distributor、cpu interface。

distributor

中斷分發器,用來收集所有的中斷來源,並且為每個中斷源設置中斷優先級,中斷分組,中斷目的core。當有中斷產生時,將當前最高優先級中斷,發送給對應的cpu interface。

distributor對中斷提供以下的功能:

  • 全局中斷使能
  • 每個中斷的使能
  • 中斷的優先級
  • 中斷的分組
  • 中斷的目的core
  • 中斷觸發方式
  • 對於SGI中斷,傳輸中斷到指定的core
  • 每個中斷的狀態管理
  • 提供軟件,可以修改中斷的pending狀態

cpu interface

cpu interface,將GICD發送的中斷信息,通過IRQ,FIQ管腳,發送給連接到該cpu接口的core。

cpu interface提供了一下的功能:

  • 將中斷請求發送給cpu
  • 對中斷進行認可(acknowledging an interrupt)
  • 中斷完成識別(indicating completion of an interrupt)
  • 設置中斷優先級屏蔽
  • 定義中斷搶占策略
  • 決定當前處於pending狀態最高優先級中斷

中斷認可

中斷認可,是指cpu響應該中斷。此時中斷狀態從pending狀態,變為active狀態。通過訪問GICC_IAR寄存器,來對中斷進行認可。

  • GICC_IAR: 認可group0的中斷
  • GICC_AIAR:認可group1的中斷

中斷完成

中斷完成,是指cpu處理完中斷。此時中斷狀態從active狀態,變為inactive狀態。GIC中,對中斷完成,定義了以下兩個stage:

  • 優先級重置(priority drop):將當前中斷屏蔽的最高優先級進行重置,以便能夠響應低優先級中斷。group0中斷,通過寫GICC_EOIR寄存器,來實現優先級重置,group1中斷,通過寫 GICC_AEOIR 寄存器,來實現優先級重置。
  • 中斷無效(interrupt deactivation):將中斷的狀態,設置為inactive狀態。通過寫 GICC_DIR 寄存器,來實現中斷無效。

這里為什么要對中斷完成,定義2個stage,其實是有考慮的。對於中斷來說,我們是希望中斷處理程序越短越好,但是有些中斷處理程序,就是比較長,在這種情況下,就會使其他中斷得到相應,從而影響實時性。

比如當前cpu在響應優先級為4的中斷A,但是這個中斷A的中斷處理程序比較長,此時如果有優先級為5的中斷B到來,(優先級越小,優先級越高)那么cpu是不會響應這個中斷的。

在軟件上,會將中斷處理程序分為兩部分,分為上半部分,和下半部分。在上半部分,完成中斷最緊急的任務,然后就可以通知GIC,降低當前的中斷處理優先級,以便其他中斷能夠得到響應。在下半部分,處理該中斷的其他事情。

在這種機制下,低優先級的中斷,不用等待高優先級的中斷,完全執行完中斷處理程序后,就可以被cpu所響應,提高實時性。

為了實現上述機制,就將中斷完成分成了2步。還是剛剛的例子,cpu在響應優先級為4的中斷A,當中斷A的上半部分完成后,通知GIC,優先級重置(drop priority),GIC將當前的最高優先級中斷重置,重置到響應中斷A之前的優先級,比如優先級6,那么此時優先級為5的中斷B,就可以被cpu響應。最后中斷A的下半部分完成后,通知GIC,將該中斷A的狀態,設置為inactive狀態,此時中斷A就真正的完成了。

當然,也可以不將中斷完成分成2步(就1步)。通過控制 GICC_CTLR寄存器的EOImode比特,來決定是否將中斷完成分成2步。

bypass功能

GICv2支持bypass功能,這樣GIC就不起作用了,core的中斷管腳,直接由soc的其他部門信號驅動。

如下圖所示,通過控制 GICC_CLTR 寄存器的一些比特位,來實現bypass功能。不過這個功能一般不使用,不然何必要在arm的soc中,加入GIC呢?

img

中斷處理流程

中斷處理流程,包含了以下幾步:

  • GIC決定每個中斷的使能狀態,不使能的中斷,是不能發送中斷的
  • 如果某個中斷的中斷源有效,GIC將該中斷的狀態設置為pending狀態,然后判斷該中斷的目標core
  • 對於每一個core,GIC將當前處於pending狀態的優先級最高的中斷,發送給該core的cpu interface
  • cpu interface接收GIC發送的中斷請求,判斷優先級是否滿足要求,如果滿足,就將中斷通過nFIQ或nIRQ管腳,發送給core。
  • core響應該中斷,通過讀取 GICC_IAR 寄存器,來認可該中斷。讀取該寄存器,如果是軟中斷,返回源處理器ID,否則返回中斷號。
  • 當core認可該中斷后,GIC將該中斷的狀態,修改為active狀態
  • 當core完成該中斷后,通過寫 EOIR (end of interrupt register)來實現優先級重置,寫 GICC_DIR 寄存器,來無效該中斷

中斷使能和禁止

通過設置GICD_ISENABLERn寄存器,來使中斷使能,通過設置GICD_ICENABLERn寄存器,來使中斷禁止。

這兩個寄存器,都是bit有效的寄存器,也就是一個bit,關聯一個中斷。

比如對於GICD_ISENABLER寄存器,描述如下:

img

中斷pending

通過設置GICD_ISPENDRn或GICD_ICPENDRn寄存器,可以讀取和修改中斷的pending狀態。這兩個寄存器,也是bit有效的寄存器,一個bit,關聯一個中斷。

中斷active

通過設置GICD_ISACTIVERn或GICD_ICACTIVERn寄存器,可以讀取和修改中斷的active狀態。這兩個寄存器,也是bit有效的寄存器,一個bit,關聯一個中斷。

產生軟中斷

通過寫 GICD_SGIR 寄存器,來產生軟中斷。軟中斷,可以指定產生中斷,發往執行的core,也可以發送多個core。

對於軟中斷,這個是軟件產生的中斷。比如軟件,想給執行自己的core,發送一個中斷,就可以通過軟中斷來產生。或者軟件,想起其他的core,發送一個中斷,也可以通過軟中斷來產生。

寄存器如下:

img

TargetListFileter

對於TargetListFileter:決定distributor將軟中斷,如何發送給cpu interface。

img

  • 0b00:按照CPUTargetList的指定,來發送軟中斷
  • 0b01:按照CPUTargetList的指定,來發送軟中斷,但是不能發送給自己
  • 0b10:軟中斷,只能發送給自己

CPUTargetList

描述如下:

img

對於多core的系統,會給每個core一個編號。GICv2支持最多8個core,因此core的編號就是0-7,剛好8個bit,可以表示。

這樣的CPUTargetList,就和8個cpu相對應。第0bit,表示core0,第7bit,表示core7。

如果想給core1,core2,core7發送軟中斷,那么此時這個位域要填入0x84。

NSATT

描述如下:

img

這個用來支持安全擴展,在GICv2中,將中斷進行了分組

  • group0:安全中斷
  • group1:非安全中斷

這個bit,用來表示發送的軟中斷,是安全中斷,還是非安全中斷。而且這個bit,只有core處於安全狀態的時候,才能寫。如果core是處於非安全狀態,那么這個bit被忽略,也就是只能發非安全的軟中斷。

SGIINTID

發送的軟中斷的中斷號。

中斷優先級

GICv2,支持最小16個,最大256個中斷優先級,如下圖所示:

img

如果實現的中斷優先級小於256個,那么最低的幾個bit,是為0的。

通過設置GICD_IPRIORITYRn寄存器,來設置中斷的優先級。這個寄存器是字節有效的,也就是一個字節,對應一個中斷的優先級。優先級數值越小,那么這個中斷的優先級越高。

高優先級的中斷,是可以搶占低優先級的中斷。

GIC使用例子

下圖是GIC的使用例子:

img

外部的中斷,連接到GIC。由distributor進行中斷分組。中斷請求,由distributor發送給cpu interface,cpu interface再發送給處理器。

對於支持安全擴展,其應用如下:

img

安全中斷,處於group0,非安全中斷處於group1。

GIC寄存器

GIC寄存器,分為兩部分,一部分是distributor的寄存器,另一部分是cpu interface的寄存器。

兩部分的寄存器,均是通過memory-mapped的方式來訪問。

下圖是distributor的寄存器:

img

下圖是cpu interface的寄存器:

img

總結

以上就是GICv2的介紹,更多的內容,需要查看GICv2的文檔。

GICv2比較簡單,最多只能支持8個core,超過了8個core,那么就不能使用GICv2了。不過這也不是大問題,對於手機的arm處理器來說,最多也就8個core。但是對於服務器,桌面級的arm處理器,那么就可能會超過8個core,此時GICv2就不適用了,所以ARM后面又加入GICv3,v4架構。

GICv2的寄存器,都是通過memory-mapped的方式訪問。但是中斷在一個soc系統中,是經常會產生的,那么處理器就會經常的讀取GIC的寄存器,而使用memory-mapped的方式去訪問,就會影響中斷響應速度。在之后的GICv3,v3中,就加入了使用系統寄存器來進行訪問,加快中斷處理。

GICv2只是一個GIC的架構,其實現的對應的IP是GIC400。

ARM GIC(四) GICv3架構基礎

GICv3架構是GICv2架構的升級版,增加了很多東西。變化在於以下:

  • 使用屬性層次(affinity hierarchies),來對core進行標識,使GIC支持更多的core
  • 將cpu interface獨立出來,用戶可以將其設計在core內部
  • 增加redistributor組件,用來連接distributor和cpu interface
  • 增加了LPI,使用ITS來解析
  • 對於cpu interface的寄存器,增加系統寄存器訪問方式

GICv3結構

下圖是GICv3的架構。

img**
**

包含了以下的組件:

  • distributor:SPI中斷的管理,將中斷發送給redistributor
  • redistributor:PPI,SGI,LPI中斷的管理,將中斷發送給cpu interface
  • cpu interface:傳輸中斷給core
  • ITS:用來解析LPI中斷

其中,cpu interface是實現在core內部的,distributor,redistributor,ITS是實現在GIC內部的。

cpu interface和GIC的redistributor通信,通過AXI-Stream協議,來實現通信。

屬性層次

GICv3的一大變化,是對core的標識。對core不在使用單一數字來表示,而是使用屬性層次來標識,和arm core,使用MPIDR_EL1系統寄存器來標識core一致。

每個core,根據屬性層次的不同,使用不同的標號來識別。如下圖所示,是一個4層結構,那么對於一個core來說,就可以用 xxx.xxx.xxx.xxx 來識別。

這種標識方式,和ARMv8架構的使用MPIDR_EL1寄存器,來標識core是一樣的。

img

每個core,連接一個cpu interface,而cpu interface會連接GIC中的一個redistributor。redistributor的標識和core的標識一樣。

img

中斷分組

GICv3,將中斷分成了2個大組,group0和group1。

  • group0:提供給EL3使用

  • group1:又分為2組,分別給安全中斷和非安全中斷使用

    如下圖所示:

img

以下是IRQ,FIQ與組的對應關系。

img

中斷生命周期

中斷生命周期,如下圖所示:

img

  • generate:外設發起一個中斷

  • distribute:distributor對收到的中斷源進行仲裁,然后發送給對應的cpu interface

  • deliver:cpu interface將中斷發送給core

  • activate:core通過讀取 GICC_IAR 寄存器,來對中斷進行認可

  • priority drop: core通過寫 GICC_EOIR 寄存器,來實現優先級重置

  • deactivation:core通過寫 GICC_DIR 寄存器,來無效該中斷

    這個中斷生命周期,和GICv2的中斷生命周期是一樣的。

中斷流程

下圖是GIC的中斷流程,中斷分成2類:

  • 一類是中斷要通過distributor,比如SPI中斷
  • 一類是中斷不通過distributor,比如LPI中斷

img

中斷要通過distributor的中斷流程

  • 外設發起中斷,發送給distributor

  • distributor將該中斷,分發給合適的re-distributor

  • re-distributor將中斷信息,發送給cpu interface。

  • cpu interface產生合適的中斷異常給處理器

  • 處理器接收該異常,並且軟件處理該中斷

    LPI中斷的中斷流程

  • 外設發起中斷,發送給ITS

  • ITS分析中斷,決定將來發送的re-distributor

  • ITS將中斷發送給合適的re-distributor

  • re-distributor將中斷信息,發送給cpu interface。

  • cpu interface產生合適的中斷異常給處理器

  • 處理器接收該異常,並且軟件處理該中斷

中斷處理

中斷處理,分為邊沿觸發處理和電平觸發處理

邊沿觸發處理

img

外部邊沿中斷到達,中斷狀態被置為pending狀態。

軟件讀取IAR寄存器值,表示PE認可該中斷,中斷狀態被置為active狀態

軟件中斷處理完畢后,寫EOIR寄存器,表示優先級重置。過一段時間后,寫DIR寄存器,中斷狀態被置為idle狀態。

電平觸發處理

img

外部高電平中斷到達,中斷狀態置為pending狀態。

軟件讀取IAR寄存器,表示PE認可該中斷。但中斷依然為高,中斷狀態進入pending and active狀態。

軟件中斷處理完畢后,寫EOIR寄存器,表示優先級重置。過一段時間后,寫DIR寄存器,中斷狀態被置為idle狀態。

寄存器

GICv3中,多了很多寄存器。而且對寄存器,提供了2種訪問方式,一種是memory-mapped的訪問,一種是系統寄存器訪問:

memory-mapped訪問的寄存器:

  • GICC: cpu interface寄存器

  • GICD: distributor寄存器

  • GICH: virtual interface控制寄存器,在hypervisor模式訪問

  • GICR: redistributor寄存器

  • GICV: virtual cpu interface寄存器

  • GITS: ITS寄存器

    系統寄存器訪問的寄存器:

  • ICC: 物理 cpu interface 系統寄存器

  • ICV: 虛擬 cpu interface 系統寄存器

  • ICH: 虛擬 cpu interface 控制系統寄存器

    下圖是GICv3中,各個寄存器,所在的位置。

img

對於系統寄存器訪問方式的GIC寄存器,是實現在core內部的。而memory-mapped訪問方式的GIC寄存器,是在GIC內部的。

GICv3架構中,沒有強制,系統寄存器訪問方式的寄存器,是不能通過memory-mapped方式訪問的。也就是ICC, ICV, ICH寄存器,也是可以實現在GIC內部,通過memory-mapped方式去訪問。但是一般的實現中,是沒有這樣的實現的。

下圖是ICC的系統寄存器,和memory-mepped方式寄存器的對應關系的一部分,更多的就要查看GICv3的spec。

img

那么,問題來了,GICv3中,為什么選擇將cpu interface,從GIC中抽離,實現在core內部?為什么要將cpu interface的寄存器,增加系統寄存器訪問方式,實現在core的內部?這樣做,是有什么好處?

我認為,GICv3的上述安排,第一是為了軟件編寫能夠簡單,通用,第二是為了讓中斷響應能夠更快。

首先要先了解,在GIC的寄存器中,哪一些寄存器,是會頻繁被core所訪問的,哪一些寄存器,是不會頻繁被core所訪問的。毫無疑問,cpu interface的寄存器,是會頻繁被core所訪問的,因為core需要訪問cpu interface的寄存器,來認可中斷,來中斷完成,來無效中斷。而其他的寄存器,是配置中斷的,只有在core需要去配置中斷的時候,才用訪問得到。有了這個認識,那么理解之后我所講述的,就比較容易了。

在GICv2中,cpu interface的寄存器,是實現在GIC內部的,因此當core收到一個中斷時,會通過axi總線(假設memory總線是axi總線),去訪問cpu interface的寄存器。而中斷在一個soc系統中,是會頻繁的產生的,這就意味着,core會頻繁的去訪問GIC的寄存器,這樣會占用axi總線的帶寬,總而會影響中斷的實時響應。而且core通過axi總線去訪問cpu interface寄存器,延遲,也比較大。

在GICv3中,將cpu interface從GIC中抽離出來,實現在core內部,而不實現在GIC中。core對cpu interface的訪問,通過系統寄存器方式訪問,也就是使用msr,mrs訪問,那么core對cpu interface的寄存器訪問,就加速了,而且還不占用axi總線帶寬。這樣core對中斷的處理,就加速了。

cpu interface與GIC之間,是通過專用的AXI-stream總線,來傳輸信息的,這樣也不會占用AXI總線的帶寬。

GICv3架構的內容,比較多,我這邊會拆成幾個部分。

下一部分,會介紹GIC stream協議。也就是cpu interface與GIC之間的通信。

ARM GIC(五)GICv3架構-GIC stream協議

GIC stream協議,是基於AXI-stream協議。用於GIC的IRI組件(interrupt routing infrastructure),和cpu interface之間,傳輸信息。

distributor,redistributor和ITS,統稱為IRI組件。

GIC stream協議,包含以下2個接口:

  • 下行AXI-stream接口:用於IRI向cpu interface傳遞信息,連接
  • 上行AXI-stream接口:用於cpu interface向IRI傳遞信息

如下圖所示:

img

接口信號

接口信號,包含下行接口信號,和上行接口信號。無論是上行還是下行,都是基於AXI-stream協議,通過data信號,來傳輸數據,data信號的位寬,也是固定的,為16bit。

下行接口信號

下行接口信號如下表所示,接口協議是基於AXI-stream協議。

img

上行接口信號

上行接口信號如下表所示,接口協議是基於AXI-stream協議。

img

IRI與cpu interface通過GIC stream協議傳輸信息,傳輸的信息,是以包為單位。包,分為兩類包:

  • 命令包,分為redistributor命令包,cpu interface命令包
  • 響應包,分為redistributor響應包,cpu interface響應包

AXI-stream協議,每次傳輸2個字節,多次傳輸,組成一個包。不同的包,大小不是一樣的,比如有的是16個字節,有的是8個字節。包傳輸的第一個16bit數據,表示包的類型。

如果一個組件,發送命令包,那么另一個,需要回應響應包。

redistributor命令包

下圖是下行redistributor命令包。

img

redistributor響應包

下圖是上行redistributor響應包。

img

cpu interface命令包

下圖是cpu interface命令包。

img

cpu interface響應包

下圖是cpu interface響應包。

img

例子

以下是cpu interface的activate命令包,格式如下:

img

這個activate命令,由cpu interface發送給IRI,表示認可中斷,中斷號,由包中的INTID字域來表示。

IRI在收到cpu interface的activate命令后,會回發activate acknowledge響應包。表示,IRI接收到cpu interface的activate命令。

其格式,如下所示:

img

包在傳輸的過程中,先發第一個數據的低16bit數據,再發第一個數據的高16bit數據,如果還有下一個數據,按照上述流程發送。所以,命令的類型,是最先發送的。

包傳輸流程

中斷發送

如下圖,redistributor,要發送一個中斷給cpu。包的傳輸的流程,如下:

img

  • redistributor給cpu interface發送set命令,發送中斷X請求,cpu interface接收到該命令后,如果該中斷X符合當前優先級要求,CPU interface通過IRQ/FIQ給cpu發送中斷。
  • CPU響應CPU interface發送的中斷,於是去讀取ICC_IAR寄存器,表示認可該中斷,得到中斷號。之后cpu interface給redistributor發送activate響應。然后把IRQ/FIQ給取消掉。

中斷取消

CPU在讀取ICC_IAR寄存器前,redistributor取消中斷。包的傳輸流程,如下:

img

  • redistributor給cpu interface發送set命令,cpu interface接收到該命令后,通過IRQ/FIQ給cpu發送中斷。
  • redistributor給cpu interface發送clear命令,清除該中斷,cpu interface將IRQ/FIQ拉低。然后回release響應。
  • cpu interface給redistributor,回clear acknowledge響應。
  • 如果此時,cpu讀取IAR寄存器,CPU會獲取到一個假的中斷號。

兩個中斷

redistributor給cpu interface發送兩個中斷。包的傳輸流程,如下圖所示:

img

  • redistributor,首先發送set x命令,發送中斷x。cpu interface接收該命令,將IRQ/FIQ拉高,向CPU發送中斷請求。
  • cpu讀取ICC_IAR寄存器,認可該中斷x,開始處理該中斷x。cpu interface給redistributor回activate x響應。
  • 之后,redistributor給CPU interface發送set y命令,發送中斷y。在cpu interface中,如果y的優先級符合要求,那么IRQ/FIQ會一直有效。等待CPU處理。

中斷搶占

redistributor給cpu interface發送2個中斷,第二個中斷搶占第一個中斷。包的流程如下:

img

  • redistributor,首先發送set x命令,發送中斷x。cpu interface接收該命令,將IRQ/FIQ拉高,向CPU發送中斷請求。
  • 在cpu讀取ICC_IAR寄存器之前,redistributor,又給cpu interface發送了set y命令,發送中斷y。並且y的優先級比x高。
  • cpu interface給redistributor回release x響應,表示cpu interface暫時不處理中斷x,中斷x,將來重新發送。
  • CPU讀取ICC_IAR寄存器,認可中斷y。cpu interface給redistributor回activate y響應。

電源斷電

GIC給CPU發送中斷,使CPU斷電。

img

這個,就比較復雜了。就不解析了。

電源上電

redistributor,請求將CPU和cpu interface上電。

img

這個也比較復雜,這里不解析。

總結

GICv3中,IRI與cpu interface之間,是通過包,來傳輸信息。傳輸的接口協議,使用AXI-stream。通過包的各種組合,來實現GIC的中斷操作與中斷管理。

之后,會介紹GICv3中,引入的一種新的中斷類型,消息中斷。

ARM GIC(六)GICv3架構-LPI

在GICv3中,引入了一種新的中斷類型。message based interrupts,消息中斷。

消息中斷

外設,不在通過專用中斷線,向GIC發送中斷,而是寫GIC的寄存器,來發送中斷。

img

這樣的一個好處是,可以減少中斷線的個數。

為了支持消息中斷,GICv3,增加了LPI,來支持消息中斷。並且為他分配了特別多的中斷號,從8192開始,移植到16777216。

LPI,locality-specific peripheral interrupts。spec中,用了一章,來介紹這個LPI。

LPI介紹

LPI是一種基於消息的邊沿中斷。也就是,中斷信息,不在通過中斷線,進行傳遞,而是通過memory。GIC內部,提供一個寄存器,當外設往這個地址,寫入數據時,就往GIC發送了一個中斷。

在soc系統中,外設想要發送中斷給GIC,是需要一根中斷線的。如果現在一個外設,需要增加一個中斷,那么就要增加一根中斷線,然后連接到GIC。這樣,就需要修改設計。而引入了LPI之后,當外設需要增加中斷,只需要使用LPI方式,傳輸中斷即可,不需要修改soc設計。

引入了LPI之后,GICv3中,還加入了ITS組件,interrupt translation service。ITS將接收到的LPI中斷,進行解析,然后發送到對應的redistributor,再由redistributor將中斷信息,發送給cpu interface。

以下是帶LPI的框圖。外設,通過寫 GITS_TRANSLATER 寄存器,來傳遞消息中斷。

img

LPI,和SPI,PPI,SGI有些差別,LPI的中斷的配置,以及中斷的狀態,是保存在memory的表中,而不是保存在GIC的寄存器中的。

  • GICR_PROPBASER:保存LPI中斷配置表的基地址
  • GICR_PENDBASER: 保存LPI中斷狀態表的基地址

這里,就涉及到兩個表:

LPI中斷配置表

該表,保存在memory中。基地址,由GICR_PROPBASER寄存器決定。

img

該寄存器描述如下:

img

其中的Physical_Address字段,指定了LPI中斷配置表的基地址。

對於LPI配置表,每個LPI中斷,占用1個字節,指定了該中斷的使能和中斷優先級。

img

當外部發送LPI中斷給redistributor,redistributor首先要查該表,也就是要訪問memory來獲取LPI中斷的配置。為了加速這過程,redistributor中可以配置cache,用來緩存LPI中斷的配置信息。

因為有了cache,所以LPI中斷的配置信息,就有了2份拷貝,一份在memory中,一份在redistributor的cache中。如果軟件修改了memory中的LPI中斷的配置信息,需要將redistributor中的cache信息給無效掉。

LPI中斷狀態表

該表,處於memory中,保存了LPI中斷的狀態,是否pending狀態。

LPI中斷的狀態,不是保存在寄存器中,而是保存在memory中的pending表中。該狀態表,由redistributor來進行更改。而該table的基地址,是由軟件來設置的。

軟件通過設置 GICR_PENDBASER 寄存器來設置。

img

該寄存器,設置LPI狀態表的基地址,該狀態表的memory的屬性,如shareability,cache屬性等。

img

每個LPI中斷,占用一個bit空間

  • 0: 該LPI中斷,沒有處於pending狀態
  • 1: 該LPI中斷,處於pending狀態

該狀態表,由redistributor來設置。軟件如果修改該表,會引發unpredictable行為。

LPI的實現方式

為了實現LPI,GICv3定義了以下兩種方法來實現:

  • 使用ITS,將外設發送到eventID,轉換成LPI 中斷號
  • forwarding方式,直接訪問redistributor的寄存器GICR_SERLPIR,直接發送LPI中斷

forwarding方式

這種方式,比較簡單,主要由下面幾個寄存器來實現:

  • GICR_SERLPIR

  • GICR_CLRLPIR

  • GICR_INVLPIR

  • GICR_INVALLR

  • GICR_SYNCR

    其GIC框圖如下所示:

img

GICR_SERLPIR,將指定的LPI中斷,設置為pending狀態。

img

GICR_INVLPIR,將指定的LPI中斷,清除pending狀態。寄存器內容和GICR_SERLPIR一致。

img**
**

GICR_INVLPIR,將緩存中,指定LPI的緩存給無效掉,使GIC重新從memory中載入LPI的配置。

img

GICR_INVALLR,將緩存中,所有LPI的緩存給無效掉,使GIC重新從memory中,載入LPI中斷的配置。

img

GICR_SYNCR,對redistributor的操作是否完成。

img

寄存器,只有第0bit是有效的。如果為0,表示當前對redistributor的操作是完成的,如果為1,那么是沒有完成的。

img

使用ITS方式

理解了forwarding方式,那么理解ITS方式,就要容易了。forwarding方式,是直接得到了LPI的中斷號。

但是對於ITS方式,是不知道LPI的中斷號的。需要將外設發送的DeviceID,eventID,通過一系列查表,得到LPI的中斷號以及該中斷對應的target redistributor,然后將LPI中斷,發送給對應的redistributor。

下圖是帶有ITS的GIC框圖:

img

外設,通過寫GITS_TRANSLATER寄存器,發起LPI中斷。寫操作,給ITS提供2個信息:

  • EventID:值保存在GITS_TRANSLATER寄存器中,表示外設發送中斷的事件類型
  • DeviceID:表示哪一個外設發起LPI中斷。該值的傳遞,是實現自定義,例如,可以使用AXI的user信號來傳遞。

ITS將DeviceID和eventID,通過一系列查表,得到LPI中斷號,再使用LPI中斷號查表,得到該中斷的目標cpu。

ITS將LPI中斷號,LPI中斷對應的目標cpu,發送給對應的redistributor。redistributor再將該中斷信息,發送給CPU。

ITS

ITS是一個組件,用來提供給外設,發送LPI中斷的,然后將LPI中斷,發送給redistributor。

ITS處理流程

ITS使用三類表格,實現LPI的轉換和映射:

  • device table: 映射deviceID到中斷轉換表
  • interrupt translation table:映射EventID到INTID。以及INTID屬於的collection組
  • collection table:映射collection到redistributor

img

當外設往GITS_TRANSLATER寄存器中寫數據后,ITS做如下操作:

  • 使用DeviceID,從設備表(device table)中選擇索引為DeviceID的表項。從該表項中,得到中斷映射表的位置
  • 使用EventID,從中斷映射表中選擇索引為EventID的表項。得到中斷號,以及中斷所屬的collection號
  • 使用collection號,從collection表格中,選擇索引為collection號的表項。得到redistributor的映射信息
  • 根據collection表項的映射信息,將中斷信息,發送給對應的redistributor

以上是物理LPI中斷的ITS流程。虛擬LPI中斷的ITS流程與之類似。以下是處理流程圖:

img

ITS命令

ITS操作,會涉及到很多表,而這些表的創建,維護是通過ITS命令,來實現的。雖然這些表,是在內存中的,但是GICv3和GICv4,不支持直接訪問這些表,而是要通過ITS命令,來配置這些表。

ITS的操作,是通過命令,來控制的。外部通過發送命令給ITS,ITS然后去執行命令,每個命令,占32字節。

ITS有command隊列,命令寫在這個隊列里面。ITS會自動的按照隊列順序,一一執行。

img

每個命令占32個字節。

命令,存放在內存中,GITS_CBASE,保存命令的首地址。GITS_CREADR,是由ITS控制,表示下一個命令的地址。GITS_CWRITER,是下一個待寫命令的地址。軟件往GITS_CWRITER地址處,寫入命令,之后ITS就會執行這個命令。

ITS提供的命令,有很多,可以查閱GIC手冊獲取更多。

以下是CLEAR命令。

img

ITS table

ITS包括很多個表,這些表均處於 non-secure區域。

GITS_BASER ,指定ITS表的基地址和大小。軟件,在使用ITS之前,必須要配置。

img

其中的Physical_Address字段,就指定了表的基地址所在位置。

以下是各個表的基地址,對應的寄存器。

img

總結

GICv3中,引入了消息中斷,並且為之,支持了LPI。分配了大量的中斷號,用於LPI。對於LPI的實現,有2種方式,一種是訪問redistributor提供的寄存器,一種是使用ITS。

不過對於手機arm cpu來說,其實是不需要LPI的,因為現有的中斷,已經符合要求,加入了LPI,讓GIC更復雜,讓軟件操作,也更復雜。但是對於服務器arm cpu,這個,就需要了,因為這個可以和PCIE相連,實現消息中斷。個人感覺,這個LPI中斷,是為arm服務器cpu,所使用的。

對於提供的GIC IP來說,比如GIC600,是有配置選項,決定,是否是否支持LPI中斷,以及是否需要ITS。

ARM GIC(七)GICv3架構-power控制

從GIC3開始,cpu interface放到了PE中,因此cpu interface和PE是同一個power domain。而屬於GIC的其他組件,如redistributor,distributor,是另外一個power domain。因此就有如下一種情況,PE和cpu interface的電源給斷掉了,而GIC的電源並沒有斷掉。此時GIC給cpu interface發送數據,cpu interface是不會響應的。

在這種情況下,GIC提供了power管理功能。

GICR_WAKER寄存器

GIC中,提供了如下的 GICR_WAKER 寄存器,來支持power功能。

img

其寄存器描述如下:

img

斷電cpu interface和PE

在cpu interface和PE要斷電之前,軟件要保證,通知redistributor,cpu interface和PE要進入low-power狀態。軟件,要往GICR_WAKER寄存器的ProcessorSleep字段,寫入1,表示PE要進入到low-power狀態。cpu interface之后將自己置為low-power狀態之后,就將ChildrenAseep字段,設置為1。

當GICR_WAKER.ChildrenAsleep為1之后,redistributor,不會在將中斷,發送給cpu interface,distributor,在中斷仲裁時,也不會考慮該PE。

喚醒cpu interface和PE

當GIC要喚醒cpu interface和PE時,也是操作這個 GICR_WAKER寄存器。

將processorsleep,寫入0,然后去喚醒該cpu,最后讀取childrenasleep,判斷PE是否喚醒成功,

img

此條目發表在ARM分類目錄,貼了GIC標簽。將固定鏈接加入收藏夾。

ARM GIC(八)總結

GIC,是arm為了實現復雜的中斷控制,而定義的一套架構。版本也歷經了多個變化,從最初的GICv1到現在最新的GICv4。每一個新的版本,都增加了一些新的功能。

img

目前最新的GIC-600 IP,支持GICv4。

不過從GICv3開始,架構就和之前的架構,變化就比較大了。

變化一:cpu interface

下圖是GICv2架構,cpu interface是實現在GIC內部,而且GIC的寄存器,都是memory-mapped方式訪問。

img

下圖是GICv3架構,cpu interface從GIC內部剝離,實現在PE的內部。並且將cpu interface的寄存器,提供了系統寄存器訪問方式,從而實現中斷的快速響應。

img

變化二:core的標識

GICv3中,對於core的標識,使用了屬性層次的方式,來進行標識,從而可以支持更多的core。

img

而GICv2中,支持最大8個core。

變化三:消息中斷

GICv3中,加入了LPI中斷類型,來實現消息中斷。並且提供了ITS,來實現中斷的轉換。

變化四:SGI處理

對於SGI的處理,有如下的變化。

img

總結

GICv3/v4,架構,比GICv2架構,增加了很多的特性,從而支持更復雜的中斷管理,支持更多的cpu。

自此,本系列博文到此就要結束了,基本上,除了虛擬中斷的相關內容,我將GIC的內容都進行了介紹。希望大家看完這系列博文,能夠對GIC有所認識。當初,自己也是看了很多的文檔,外加上代碼,才對這個理解的。

后面,如果我有去了解過虛擬中斷,會在寫一系列博文,來介紹虛擬中斷。

ARM GIC(九) GICv3的中斷分組

GICv3架構中,對中斷進行了分組。分成了以下三個組:

  • group0,用於EL3處理的中斷

  • secure group1:用於secure EL1處理的中斷

  • non-secure group1:用於non-secure的EL2和non-secure的EL1。

    對於redistributor的set命令,帶有Mod和Grp參數。

img

Mod與Grp共同表示,中斷所屬的組。其組合如下圖所示:

img

對於每一組中斷,有一個系統寄存器,來控制該組中斷是否有效。

  • ICC_IGRPEN0_EL1:針對group0的中斷
  • ICC_IGRPEN1_EL1:針對group1的中斷,該寄存器分為non-secure和secure訪問,不同的secure下,是訪問當前secure下的寄存器

而每個中斷的分組,由以下兩個寄存器來決定:

  • GICR_IGROUPR : interrupt group registers

  • GICR_IGRPMODR :interrupt group modifier registers

    每個中斷,占寄存器中的1個bit,使用中斷號進行索引。

當GIC給cpu interface通過set命令發送中斷,cpu能夠響應該組中斷,會回發activate命令,認可該中斷。

如果cpu不能響應該組中斷,會回發release響應。如下圖所示:

img

GIC給cpu interface通過set命令發送中斷,中斷號為93,優先級為0x40,Mod和Grp均為1,表示non-secure的group1。

cpu interface不能響應該中斷,回發release響應。

ARM GIC(十) GICv3軟中斷

軟中斷(software generated interrupts),用來多個核之間的通信(inter-processor communication)。軟件通過寫SGI寄存器來產生。

  • 軟件寫ICC_SGI1R_EL1產生對應當前secure狀態的group1軟中斷

  • 軟件寫ICC_ASGI1R_EL1產生secure狀態的group1軟中斷

  • 軟件寫ICC_SGI0R_EL1產生secure狀態的group0軟中斷

    這三個寄存器的位域是一樣的,如下圖:

img

  • Aff3.Aff2.Aff1:表示軟中斷目的CPU的屬性層次。
  • TargetList:表示要發給哪些CPU。
  • INTID:表示軟中斷號
  • IRM:軟中斷發送,是按照屬性層次發送,還是發起其他所有的cpu
  • RS:range selector,和TargetList結合,表示發送哪些CPU

例如,IRM為0,INTID為1,Aff3.Aff2.Aff1為0.0.0,TargetList為0xf,RS為0,就表示,軟中斷發送給屬性層次為0.0.0.[0-3]的cpu。

GICv3對軟中斷的中斷號,進行了規定,只能是0-15。

img

cpu interface SGI命令

軟件寫SGI寄存器后,cpu interface會通過GIC stream接口,發送SGI命令。

img

  • SGT:表示寫的哪一個SGI寄存器

    0b00: ICC_SGI0R_EL1

    0b01: ICC_SGI1R_EL1

    0b10: ICC_ASGI1R_EL1

    0b11: Reserved

  • NS: 當前的secure狀態,0表示secure,1表示non-secure

  • IRM: SGI寄存器的IRM bit

  • A3V: aff3是否有效,如果有效,需要發送A3數據。

  • RSV: range selector域是否有效

  • SGInum: 軟中斷中斷號

  • A3,A2,A1: 對應Aff3.Aff2.Aff1

  • TargetList: 對應SGI寄存器中的TargetList

  • Range Selecto: 對應SGI寄存器中的RS域

比如,往ICC_SGI0R_EL1寄存器寫0xffffef_ffffffff,那么cpu interface會發送如下波形:

img

A3V

GICv3中,使用屬性層次對CPU進行編號,屬性層次最多有4層,最高層為Aff3,這一層可以通過cpu interface系統寄存器來控制,是否使能。

img

ICC_CTLR_EL3和ICC_CTLR_EL1的A3V表示cpu interface是否支持Aff3,而GICD_TYPER.A3V表示GIC ip是否支持Aff3。

關於range selector的理解。

GICv3的spec對range selector的解釋如下:

img

GIC3中,使用屬性層次,來對CPU進行標識,這樣可以精確的將中斷發送指定的cpu。屬性層次最高有4層,為aff3.aff2.aff1.aff0。每一個屬性層次,用8bit來表示。如下圖所示:

img

SGI中斷,是可以同時發送給多個cpu的中斷,通過TargetList來表示要發送給哪一些CPU。而TargetList只有16個bit,也就是只能發送給16個cpu,但是Aff0最多可以表示256個cpu,那怎么發送給其他的cpu的了?

這個時候range selector就派上用場了,RS域共4個bit,可以表示16個范圍,16×16=256,剛好表示256個cpu。所以spec里面,說TargetList[n]表示的aff0的值為RS*16 + n。

比如要給65-68號CPU發送軟中斷,首先判斷這些cpu屬於的range,為5,那么給這些CPU發送軟中斷,RS為5,TargetList為0x1E。

GIC的SGI認可響應

當GIC收到cpu interface發的SGI命令,需要回SGI認可響應。

img

此條目發表在ARM分類目錄,貼了GIC標簽。將固定鏈接加入收藏夾。

ARM GIC(十一) GICv3架構-two secure state

Arm 技術

GICv3中,引入了支持2種安全狀態(secure state),也就是對於中斷,根據secure狀態,分為安全中斷和非安全中斷。當然也可以只支持一種安全狀態。。

這里的2種安全狀態和1種安全狀態,主要是影響中斷分組,所使用IRQ和FIQ管腳的映射,以及GIC中的寄存器訪問。

中斷線的映射

當GIC架構,使用GICv3后,中斷的傳遞,和GICv2有所區別。

GICv3中,將cpu interface從GIC中抽離,放入到了cpu中,cpu interface通過GIC stream接口,與GIC進行通信。

當GIC要發送中斷,GIC通過GIC stream接口,給cpu interface發送中斷命令,cpu interface收到中斷命令后,根據中斷線映射配置,決定是通過IRQ還是FIQ管腳,向cpu發送中斷。

而中斷線映射配置,要根據中斷的分組以及當前cpu所處的EL以及seucre狀態,來決定。

2種安全狀態中斷線映射

當GIC支持2種安全狀態,EL3是AArch64和AArch32,映射情況不同

EL3是AArch64

當EL3是AArch64時,映射如下:
1.png

◾對於group0中斷,中斷線均映射到FIQ

◾對於group1安全中斷,secure EL1或EL0,中斷線映射到IRQ,其他EL映射到FIQ

◾對於group1非安全中斷,secure EL1或EL0以及EL3,中斷線映射到FIQ,其他EL映射到IRQ

EL3是AArch32

當EL3是AArch32時,映射如下:
2.png

◾對於group0中斷,中斷線均映射到FIQ

◾對於group1安全中斷,secure EL0和EL3,中斷線映射到IRQ,其余EL映射到FIQ

◾對於group1非安全中斷,secure EL0和EL3,中斷線映射到FIQ,其余EL映射到IRQ

1種安全狀態中斷線映射

映射如下:
3.png

◾group0中斷線,直接映射到FIQ

◾group1中斷線,直接映射到IRQ

GICD寄存器

在GICD中的GICR_CTLR寄存器的DS bit,表示是否支持2種安全模式。

該bit描述如下,如果0,表示支持2種安全狀態,為1,表示不支持。

4.png

支持2種安全模式下GICD_CTLR

在支持2種安全模式下,GICD中寄存器會進行備份成2份,一份提供給secure訪問,。一份提供給non-secure訪問。

比如對於GICD_CTLR寄存器,secure訪問,寄存器描述如下:
5.png

而如果是non-secure訪問,其寄存器描述如下:
6.png

支持1種安全模式下GICD_CTLR

在1種安全模式下,寄存器描述如下,此時不論是non-secure訪問,還是secure訪問,都訪問的同一個寄存器。
7.png

系列其他篇

ARM GIC(十二) 中斷bypass

在GICv2架構中,GIC與core之間,是直接通過irq,fiq管腳,傳遞中斷信號。但是在GICv3架構中,GIC通過GIC stream接口向cpu interface傳遞中斷信息,然后由cpu interface向core傳遞中斷信息,而且,cpu interface被設計在了core當中。

GICv3支持中斷bypass功能,以下是我畫的一個框圖:

img

對於core而言,中斷有2種(不考慮虛擬中斷),分別是IRQ和FIQ。

在ICC_SRE_ELx寄存器,有DFB和DIB bit,分別控制FIQ,IRQ是否bypass。

img

對於DIB bit的描述:

img

對於DFB bit的描述:

img

這2個bit,復位值都是0,表示系統在復位后,中斷bypass功能是開啟的,此時外部的中斷信號,是直接輸入到core中的。

當軟件,關閉中斷bypass后,此時,才是由cpu interface給core發送中斷,而忽略掉外部發送的中斷。

在GICv3架構描述中,提到了中斷bypass功能,會受到下面幾個配置的影響:

一個是,是否運行系統寄存器訪問icc寄存器,也就是ICC_CTLR.SRE bit是否為高,如果允許系統寄存器訪問icc寄存器,那么中斷bypass功能是禁止的。

一個是,ICC_SRE寄存器,由當前設計中支持的最高EL級的ICC_SRE寄存器的DFB和DIB bit來控制。

img

最后一個,就是中斷分組使能,也就是ICC_IGPREN0_EL1和ICC_IGRPEN1_EL1的enable bit。

如果需要開啟中斷bypass功能,那么需要將中斷分組使能給關掉。

img

以下是FIQ中斷bypass的偽代碼:

img

IRQ的處理,和FIQ是一致的。

ARM GIC(十三) 波形為例,介紹GIC600與cpu interface通信

以下以GIC600與cpu interface之間傳遞的包,來說明,他們之間是如何通信的。這里以波形進行介紹。這樣比較直觀。

downstream control命令包

GIC600發送downstream control命令包給cpu interface。命令包的數據為0。

img

downstream control包格式如下:

img

解釋如下:

img

從表中可以解析,GIC600告訴cpu interface做如下配置:

  • VL設置為0,表示vINTID位寬是16bit
  • PL設置為0,表示pINTID位寬是16bit
  • RSS設置為1,表示SGI的aff0,支持0-15
  • DS設置為0,表示支持兩種secure模式

cpu interface接收到該命令包后,回一個downstream control acknowledge響應包。包格式如下:

img

upstream control命令包,設置PMR

cpu interface給GIC600發送upstream control命令包,數據為f8。設置PMR。

img

該包的格式如下:

img

對於f8,解析如下:

img

cpu interface告訴GIC600,當前的ICC_PMR_EL1值設置為f8,也就是將來優先級比這個低的,GIC600就不要發送中斷給cpu interface。

GIC600收到upstream control命令包后,回upstream control acknowledge包,格式如下:

img

upstream control命令包,設置group enable

cpu interface給GIC600發送upstream control命令包,數據為1。設置group enable。

img

對於數據1,解析如下:

img

cpu interface告訴GIC600,將grou0的中斷使能,group1的secure和non-secure中斷不使能。

GIC600收到upstream control命令包后,回upstream control acknowledge包,格式如下:

img

set命令包,發送中斷

GIC600發送set命令包給cpu interface。數據為20。

img

set命令包格式如下:

img

GIC600向cpu interface發送了一個中斷:

  • Grp為0,Mod為0,表示中斷屬於group0中斷組

  • ID length為0,表示INTID位寬為16bit

  • Priority為0x48,表示中斷優先級

  • INTID為0x20,表示中斷號為32(SPI中斷從32開始)

cpu interface收到該set命令后,發現不能處理該中斷,因此發送release響應包,並且INTID指定剛剛GIC600發送的中斷號。

img

該release響應包的各個參數解釋如下:

img

GIC600收到cpu interface的release響應包后,知道之前發送的中斷,不能得到cpu interface的響應,在之后,會重新發送該中斷。

這里為什么cpu interface不能處理該中斷,而是要回release響應包。原因在於中斷優先級不符合要求。

對於ICC_PMR_EL1寄存器,GICv3 spec描述如下:

img

對於中斷,GIC架構,最多使用8個bit,來表示中斷優先級。當然8個bit可以全用,也可以只用一部分,所以架構提供了5種配置方式。設計可以根據自己的需要,選擇一種配置即可。

對於使用的bit不一樣,對應的中斷優先級值不一樣。比如對於使用5個bit,那么就是[7:3],共32種中斷優先級。這個選擇多少個bit,是硬件決定好了,軟件是不能更改的。

軟件可以設置這個寄存器,來表示,符合要求的優先級,可以被cpu響應。優先級值越小,表示優先級越高。

假設這個時候,軟件往這個寄存器寫了8,表示優先級高於8的,都不能被core響應。

假設設計,使用[7:3],表示中斷優先級。

此時,發送了優先級為0x48的中斷,按照[7:3]bit,進行選擇,得到中斷優先級為9,高於設置的8,因此這個中斷不能被core響應,所以cpu interface直接給GIC600回release響應。

set命令包,發送中斷

GIC600發送set命令包給cpu interface。數據為21。

img

GIC600向cpu interface發送了一個中斷:

  • Grp為0,Mod為0,表示中斷屬於group0中斷組
  • ID length為0,表示INTID位寬為16bit
  • Priority為0x38,表示中斷優先級
  • INTID為0x21,表示中斷號為33

cpu interface接收到set命令包,將中斷發送給core,core響應中斷,讀取icc_iar寄存器,表示對該中斷認可。中斷被core認可后,cpu interface就會給GIC600回activate命令包,表示core認可了該中斷。GIC600就可以把該中斷狀態,更新為active或者active and pending狀態。

img

activate就命令包格式如下:

img

各個域解析如下:

img

deactivate命令包,無效中斷

core在處理完中斷后,會寫ICC_EOIR0_EL1或者ICC_EOIR1_EL1寄存器,來無效中斷,cpu interface接受core的這個寫操作,會向GIC600發送deactivate命令包,表示core對中斷處理完畢。

img

deactivate命令包,格式如下;

img

各個域解析如下:

img

GIC600收到cpu interfae發送的deactivate命令后,將自己內部對該中斷維護的狀態,修改為pending 或者 inactive。

ARM GIC(十四)GICv3架構-power控制詳解

在帶有GICv3的soc架構中,其框圖如下所示:

img

GICv3中的redistributor與core中的cpu interface通過AXI-Stream進行通信。

connection

當core上電之后,需要將core中cpu interface與GIC中的redistributor進行connect,這樣將來GIC才可以將中斷發送給core。

connection的流程如下所示:

img

描述如下:

  • 執行在core的程序,將GICR_WAKER.ProcessorSleep位給置低,表示要connect redistributor
  • redistributor在完成connect之后,將GICR_WAKER.ChildrenAsleep位給置低,表示connect完成
  • 執行在core的程序,查詢GICR_WAKER.ChildAsleep位是否為0,如果不是,表示redistributor還沒有完成connect操作,就繼續查詢
  • 如果查詢到0,表示connect完成,接着做之后的初始化工作

其匯編代碼如下:

img

波形如下:

首先寫GICR_WAKER寄存器,將ProcessorSleep位給置低。

img

然后讀取GICR_WAKER寄存器,判斷ChildAsleep位是否為0。在波形中,有讀取到0,表示connect成功。

connect成功后,GIC600會給cpu interface發送downstream包,設置vINTID,pINTID,RSS,DS這幾個域。

img

downstream包,對於identifier為0,length為1的解釋如下:

img

disconnection

當core下電之后,需要將core中cpu interface與GIC中的redistributor進行disconnect,這樣將來GIC才不會將中斷發送給core。

disconnection的流程如下所示:

img

描述如下:

  • 執行在core的程序,先將cpu interface的中斷組使能給disable

  • 執行在core的程序,將GICR_WAKER.ProcessorSleep位給置高,表示要disconnect redistributor

  • redistributor給cpu interface發送 Quiesce包

  • cpu interface清掉內部所有pending的中斷

  • 清除完畢后,cpu interface回發Quiesce Acknowledge包給redistibutor

  • redistributor收到cpu interface回發的響應之后,將GICR_WAKER.ChildrenAsleep位給置高,表示disconnect完成

  • 執行在core的程序,查詢GICR_WAKER.ChildAsleep位是否為1,如果不是,表示redistributor還沒有完成connect操作,就繼續查詢

  • 如果查詢到1,表示disconnect完成

    其匯編代碼如下:

img

其波形如下:

首先寫GICR_WAKER寄存器,將ProcessorSleep位給置高,表示要disconect。

img

然后讀取GICR_WAKER寄存器,判斷ChildAsleep位是否為0。在波形中,有讀取到0,表示disconnect不成功,需要再次讀取判斷。

img

GIC600給cpu interface發送Quiesce包。

img

cpu interface收到該命令包,完成內部的操作后,回發quiesce acknowledge響應包。

img

至此,完成了disconnect操作,此時再讀取GICR_WAKER寄存器,ChildAsleep位就為1了。

img

中斷喚醒core

當core下電之后,GIC就不再會給core發送中斷。如果此時有一個中斷是喚醒core的,那么其處理流程應該如何了?

在GICv3,為每一個redistributor,提供了WakeRequest輸出信號。當GICR_WAKER的ProcessorSleep為1,此時外部有喚醒該core的中斷請求,那么WakeRequest信號會被置高。

WakeRequest信號,會被連接到SCP或者PMU,也就是下圖中的紅色連線。當SCP或者PMU接收到WakeReqeust請求,就會將對應core給上電,然后core再connect redistributor,GIC在將中斷發送給該core,core再響應中斷。

img


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM