卷一 内核源代码分析 第二章 异常 2.2.1 cortex A9多核处理器的中断控制器GIC---2.2.2 Mt6577的中断体系 图书试读版-请勿转载
生活随笔
收集整理的這篇文章主要介紹了
卷一 内核源代码分析 第二章 异常 2.2.1 cortex A9多核处理器的中断控制器GIC---2.2.2 Mt6577的中断体系 图书试读版-请勿转载
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
作者 crosskernel@gmail.com
2.2.1cortex A9多核處理器的中斷控制器GIC
對于多核處理器來說,中斷有著新的使命---處理器間通信,在CA9以前,每種SOC的中斷控制器是自己實現的,但是到了CA9 SMP以后,中斷控制器成為了ARM規范的一部分,各家的處理器都遵循arm 中斷控制器GIC規范:《IHI0048A_gic_architecture_spec》。其中原因在于,對于非SMP的架構,中斷控制器就是控制中斷的功能,完成中斷的記錄、ack、屏蔽等功能即可,各家廠商愛怎么玩就怎么玩。但是到了SMP結構下,除了ack、記錄、屏蔽之外,中斷控制器還面臨如下問題:
? 中斷分發給哪顆處理器
? 處理器間通信如何實現--處理器通信本質上就是一種中斷
? 處理器局部中斷
ARM提供的中斷控制器GIC,就是解決以上問題,根據GIC規范,中斷安排如下。參見《IHI0048A_gic_architecture_spec》的“Figure 2-1 GIC logical partitioning into Distributor and CPU interfaces”
? 32-1019 SPI ? 全局中斷,可指定分發到不同的處理器
? 16-31 PPP ? ?處理器局部中斷,處理器局部可見
? 0-15 SGI ? ? 軟件產生中斷,由cpu寫ICDSGIR產生,可指定分發到不同的處理器
而GIC本身分成兩份
? GIC的DIST部分,這部分是所有CPU公用的
? 每個CPU自己CPU interface部分, 這部分控制寄存器地址,只能被CPU局部可見,ARM推薦各SOC廠商將該地址實現為相同位置。
以上概念在GIC描述結構,struct gic_chip_data得到體現:?
struct gic_chip_data {
unsigned int irq_offset; ? //中斷號的偏移量
void __percpu __iomem **dist_base; //記錄每顆CPU訪問GIC Dist的基地址
void __percpu __iomem **cpu_base; //記錄每顆CPU訪問GIC CPU interface的基地址,每顆處理器看到同樣的地方,但是訪問的卻是不同的寄存器
? ? …
unsigned int gic_irqs;
};
2.2.2 Mt6577的中斷體系
MTK與Android是絕配。在智能機時代, MTK盡管開始走了段彎路,但是很快撥亂反正。MTK的智能機時代策略,與其功能機時代如出一轍,這與其市場定位有關。
MTK手機處理器的技術路線,不追求最快,但一定會在市場需要的準時出現;不追求最強,但一定能流暢運行最新版本的Android系統與應用。
MTK的公板,從器件選型、電路板設計到Android系統實現,MTK親力親為幾乎做好了所有技術上的工作。MTK的參考設計總是能做到與大陸手機產業鏈完美匹配,著力支持手機供應鏈中最常用、供貨最有保障器件和外設,而同一種功能器件和外設,進行多家驗證,以確保整機商供應鏈的安全。由此,良性循環,華南的IC、模具、LCD、SMT等產業鏈以MTK馬首是瞻,總是自覺的將自己產品與MTK公板的兼容性作為其重要工作。
? 本節分析MT6577的中斷體系。Mt6577的Datasheet不是個公開的文檔,況且該文檔里也并沒有清晰的闡述其中斷體系的結構。 但是通過U8836d公開的代碼卻可以完整的分析出mt6577的中斷架構。Mt6577的中斷體系的最高層依然遵循GIC規范,可參見ARM公司release相關技術文件。Mt6577中的實現可參見u8836d公開的代碼中的文件:
//“U8836D\mediatek\platform\mt6577\kernel\core\include\mach\mt6577_irq.c”?
//16個軟件中斷
#define NR_GIC_SGI ? ? ? ? ? ? ?16
//16個處理器局部中斷,在mt6577其實只使用了5個,從第27號開始
#define NR_GIC_PPI ? ? ? ? ? ? ?16
//128個全局中斷
#define MT6577_NR_SPI ? ? ? ? ? (128)
#define NR_MT6577_IRQ_LINE ? ? ?(NR_GIC_SGI + NR_GIC_PPI + MT6577_NR_SPI)?
//全局中斷從第32號開始
#define GIC_PRIVATE_SIGNALS ? ? 32?
//處理器局部中斷的起始號
#define GIC_PPI_OFFSET ? ? ? ? ?(27)
//如下定義了5個處理器局部中斷
#define GIC_PPI_GLOBAL_TIMER ? ?(GIC_PPI_OFFSET + 0)
#define GIC_PPI_LEGACY_FIQ ? ? ?(GIC_PPI_OFFSET + 1)
#define GIC_PPI_PRIVATE_TIMER ? (GIC_PPI_OFFSET + 2)
#define GIC_PPI_WATCHDOG_TIMER ?(GIC_PPI_OFFSET + 3)
#define GIC_PPI_LEGACY_IRQ ? ? ?(GIC_PPI_OFFSET + 4)
然后從32號中斷開始定義了104個全局中斷
#define MT6577_L2CCINTR_IRQ_ID ? ? ? ? ? ? ?(GIC_PRIVATE_SIGNALS + 0)
…
#define MT6577_USB0_IRQ_ID ? ? ? ? ? ? ? ? ?(GIC_PRIVATE_SIGNALS + 8)
#define MT6577_USB1_IRQ_ID ? ? ? ? ? ? ? ? ?(GIC_PRIVATE_SIGNALS + 9)
…
#define MT6577_EINT_IRQ_ID ? ? ? ? ? ? ? ? ?(GIC_PRIVATE_SIGNALS + 96)
…
#define MT6577_EINT_DIRECT7_IRQ_ID ? ? ? ? ?(GIC_PRIVATE_SIGNALS + 104)
以上中斷體系的實現是通過GIC的配置來完成,而GIC的配置在初始化過程中完成。GIC初始化包括DIST的初始化,和每顆CPU自己interface的初始化。DIST初始化由CPU0完成,然后CPU0再完成自己備份的interface初始化。在CPU1起來之后再完成CPU1的相關interface初始化。
CPU0的工作:
void __init mt_init_irq(void)
{ ? …
//DIST的初始化
mt_gic_dist_init();
//CPU0的interface初始化
? ? mt_gic_cpu_init();
}
static void mt_gic_dist_init(void)
{
? ? unsigned int i;
u32 cpumask = 1 << smp_processor_id();
? ? cpumask |= cpumask << 8;
? ? cpumask |= cpumask << 16;
? ? writel(0, GIC_DIST_BASE + GIC_DIST_CTRL);
? ? /*
? ? ?從32號開始, 設置SPI中斷電平觸發,N-N模式。GIC從GIC_DIST_CONFIG --0xC00開始是中斷分發寄存器ICDICFR,每個SPI對應2位。
? ? ?*/
? ? for (i = 32; i < (MT6577_NR_SPI + 32); i += 16) {
? ? ? ? writel(0, GIC_DIST_BASE + GIC_DIST_CONFIG + i * 4 / 16);
? ? }
? ? /*
? ? ? 所有SPI分發給CPU0。這部代碼只有CPU0才能執行到。GIC從GIC_DIST_TARGET --0x800開始是中斷分發寄存器,長度根據支持的SPI不同而不同,每個中斷對應8位,哪一位置1,該中斷發到哪顆處理器。Cpumask每8位的最低位都置1,所以從32號中斷開始,SPI都分發CPU0。
? ? ?*/
? ? for (i = 32; i < (MT6577_NR_SPI + 32); i += 4) {
? ? ? ? writel(cpumask, GIC_DIST_BASE + GIC_DIST_TARGET + i * 4 / 4);
? ? }
? ? /*
GIC從GIC_DIST_PRI --0x400開始是中斷優先級寄存器,長度根據支持的SPI不同而不同,每個中斷對應8位,這里把所有SPI優先級都設置為相同優先級。
*/
? ? for (i = 32; i < NR_MT6577_IRQ_LINE; i += 4) {
? ? ? ? writel(0xA0A0A0A0, GIC_DIST_BASE + GIC_DIST_PRI + i * 4 / 4);
? ? }
? ? /*
? ? GIC從GIC_DIST_ENABLE_CLEAR --0x180開始是中斷屏蔽寄存器ICDICER,長度根據支持的SPI不同而不同,每個中斷對應1位,置1屏蔽該中斷。
? ? */
? ? for (i = 32; i < NR_MT6577_IRQ_LINE; i += 32) {
? ? ? ? writel(0xFFFFFFFF, GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);?
? ? }
? ? /*
? ? ?把掛到linux中斷描述數組里去,每個中斷一個“struct irq_desc”,以前是個數組,現在可選成radix樹。每個中斷一個“struct irq_desc”,記錄兩個中斷處理的關鍵數據結構“struct irq_chip”和 irq_flow_handler_t。前者用來對付中斷控制器,在mt6577上是“struct irq_chip mt_irq_chip”,后者是中斷處理程序,分成“void handle_level_irq(unsigned int irq, struct irq_desc *desc)”—用來對付電平觸發,和“void
handle_edge_irq(unsigned int irq, struct irq_desc *desc)”—用來對付邊沿觸發。
? ? ?*/
? ? for (i = GIC_PPI_OFFSET; i < NR_MT6577_IRQ_LINE; i++) {
? ? ? ? irq_set_chip_and_handler(i, &mt_irq_chip, handle_level_irq);
? ? ? ? set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
? ? }
#ifdef CONFIG_FIQ_DEBUGGER
? ? irq_set_chip_and_handler(FIQ_DBG_SGI, &mt_irq_chip, handle_level_irq);
? ? set_irq_flags(FIQ_DBG_SGI, IRQF_VALID | IRQF_PROBE);
#endif
? ? /*
? ? ?GIC從GIC_ICDISR --0x80開始是中斷屏蔽寄存器ICDISR,長度根據支持的SPI不同而不同,每個中斷對應1位,置0表示該中斷是安全中斷,置1表示該中斷是非安全中斷,這里全置1
? ? ?*/
? ? for (i = 32; i < NR_IRQS; i += 32)
? ? {
? ? ? ? writel(0xFFFFFFFF, GIC_ICDISR + 4 * (i / 32));
? ? }
? ? /*
? ? ?ICDDCR位于0x,中斷總開關,打開
? ? ?*/
? ? writel(3, GIC_DIST_BASE + GIC_DIST_CTRL);
}
//該函數在每顆CPU被激活時得到執行
static void mt_gic_cpu_init(void)
{
? ? int i;
? ? /*
? ? ?關閉PPI,打開SGI。PPI需要用到時調用“void mt_enable_ppi(int irq)”打開,在u8836d系統里只有local timer是PPI中斷在其初始化時將自己對應使能位打開,SGI必須全打開,SGI用來做處理器間中斷的基礎。
? ? ?*/
? ? writel(0xffff0000, GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR);
? ? writel(0x0000ffff, GIC_DIST_BASE + GIC_DIST_ENABLE_SET);
? ? /* 設置PPI SGI中斷優先級為0x80*/
? ? for (i = 0; i < 32; i += 4)
? ? ? ? writel(0x80808080, GIC_DIST_BASE + GIC_DIST_PRI + i * 4 / 4);
? ? /*設置PPI SGI中斷優先為非secure中斷*/
? ? writel(0xFFFFFFFF, GIC_ICDISR);
? ?
/*操作自己的CPU INTERFACE的ICCPMR寄存器,只有優先級高于0xF0的中斷才會送入本處理器*/
? ? writel(0xF0, GIC_CPU_BASE + GIC_CPU_PRIMASK);
/*操作自己的CPU INTERFACE的ICCICR寄存器,做如下設置:
? 允許向本處理器送secure中斷
? 允許向本處理器送非secure中斷
? 把secure中斷送到本處理器的FIQ中斷線
? 中斷搶占通過secure binary point register判斷
? 一個ICCIAR的secure讀,導致非secure最高優先級pending中斷的ack
/
? ? writel(0x1F, GIC_CPU_BASE + GIC_CPU_CTRL);
? ? dsb();
}
值得注意的是mt6577全局中斷的實現,又分為兩種。
? 對于集成在SOC里的外設,直接對應一個全局中斷,如“MT6577_USB1_IRQ_ID”,在其驅動初始時直接將其中斷處理函數注冊到內核的中斷處理里數組中:“request_irq(nIrq, musbfsh->isr, IRQF_TRIGGER_LOW, dev_name(dev), musbfsh)”
? 而對于位于SCO之外的外設,則通過MT6577_EINT_IRQ_ID 進行轉發:
Mt6577在內核里準備了一個外設中斷處理函數的數組:
typedef struct?
{
? ? void (*eint_func[EINT_MAX_CHANNEL])(void);
? ? unsigned int eint_auto_umask[EINT_MAX_CHANNEL];
} eint_func;
這些外設通過“void mt65xx_eint_registration(…)”注冊自己的中斷函數。
比如觸屏控制器gt813,“mediatek\custom\out\huaqin77_cu_ics2\kernel\touchpanel\ Gt813_driver.c”通過該函數注冊自己的中斷處理函數: ?
mt65xx_eint_registration(…, tpd_eint_interrupt_handler, 1);?
當這些SOC外外設中斷發生以后,mt6577將在GIC的MT6577_EINT_IRQ_ID上產生中斷,從而觸發其中斷處理函數“static irqreturn_t mt65xx_eint_isr(int irq, void *dev_id)”。在該函數里將檢查“eint_func”數組,進一步觸發對應的的處理函數。
總結
以上是生活随笔為你收集整理的卷一 内核源代码分析 第二章 异常 2.2.1 cortex A9多核处理器的中断控制器GIC---2.2.2 Mt6577的中断体系 图书试读版-请勿转载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第8章 降维
- 下一篇: webMethods入门简介