kernel first 內核優先

1. 什麼是內核優先

RAS錯誤上報整體方案有兩個:固件優先和內核優先。
固件優先:所有錯誤先報到固件, 固件處理做第一手處理,然後再報給OS或者帶外。
內核優先:所有錯誤先報給內核。

方案 優點 缺點
固件優先 可以上報到帶外,方便錯誤統一搜集,更容易規避硬件的缺陷,更安全 1)一般的錯誤恢復在固件做不了,需要再報給OS,增加了上報的通道,且該通道很容易成爲瓶頸; 2) 固件不支持多任務,只能一個主核來處理,對主核依賴比較重。
內核優先 可以多核處理,且能快速分配給對應驅動做故障恢復。 錯誤蒐集只能在帶內做,不能報給帶外。

ARM64的內核優先方案還不成熟,方案還不完整,arm的人正在推。

2. ACPI for the Armv8 RAS Extensions 1.0

ARM定義的一個規範,做爲支持kernel first的開始,後面要把它推到ACPI規範,並圍繞這個規範,在linux內核做
想關的支持。

https://static.docs.arm.com/den0085/a/DEN0085_RAS_ACPI_1.0_BETA_1.pdf

已經推了個RFC的patchset在linux內核做支持:
[PATCH RFC 0/4] ARM Error Source Table Support

這個規範其實就定義了一個ACPI表格,即AEST(Arm Error Source Table)。 把芯片node(節點)的RAS信息上報報給kernel,
這些信息包括interrupt和interface(寄存器)。 node的粒度是芯片定義,可以多個模塊報一個node,也可以一個模塊報一個node。
每node裏面包含一個interface,多個interrupts,每個interface可以有多個寄存器組組成,但地址要是連續的。
中斷處理函數裏需要查詢interface下的寄存器。

支持三種Node type:
• 0 processor error node
• 1 memory error node
• 2 vendor defined error node

支持兩種Interrupt type:
• 0x0 – Fault Handling Interrupt (ERI)
• 0x1 – Error Recovery Interrupt (FHI)

支持兩種Interface type:
• 0x0 – System Register
• 0x1 – Memory mapped

如果要把中斷上報給EL3,就必須使用SPI或者PPI中斷。
參考RAS規範章節4.9 Error recovery and fault handling signaling
原話是這樣說的:

To allow it to be delivered to firmware as a high priority group 0
interrupt, error recovery and fault handling interrupts must be signaled as either Shared Peripheral Interrupts
(SPIs) or Private Peripheral Interrupts (PPIs).

如果不上報EL3,就沒這個要求,理論上可以使用消息中斷,但AEST的patch是把中斷限定在SPI範圍。

3. 中斷知識

GSI: Software Generated Interrupt
SPI: Shared Peripheral Interrupt
PPI: Private Peripheral Interrupt
LPI: Locality-specific Peripheral Interrupt
GSIV: Global System Interrupts, ACPI裏的概念,

IRQ: Interrupt ReQuest
http://guojing.me/linux-kernel-architecture/posts/irq-and-interrupt/

FIQ和IRQ的區別
https://blog.csdn.net/dasheng_604/article/details/5976460
FIQ比IRQ更快:FIQ模式有更多的banked寄存器,並有更高的優先級。

arch_arm_ras_report_error()是用來處理核上的,或者接口類型爲系統寄存器的。
正常的都是aest_proc()調用的。

GIC規範中定義了4類中斷類型:SGI(0-15), PPI(16-31), SPI(32-1029)和LPI(8192-~)。

http://joyxu.github.io/2018/10/18/ARM-GIC-Linux-Kernel%E6%8E%A5%E5%8F%A3%E5%88%86%E6%9E%90-%E4%B8%80/

SPI中斷可以報給EL3,也可以報給EL1,是通過GIC的寄存器組GICD_IGROUPR完成的,該寄存器的在內核
的GIC驅動也有配置,但該寄存器一般被設計爲安全寄存器,內核配置不了。 內核代碼對應如下:
drivers/irqchip/irq-gic-v3.c

 579 static void __init gic_dist_init(void)
 580 {
 581         unsigned int i;
 582         u64 affinity;
 583         void __iomem *base = gic_data.dist_base;
 584
 585         /* Disable the distributor */
 586         writel_relaxed(0, base + GICD_CTLR);
 587         gic_dist_wait_for_rwp();
 588
 589         /*
 590          * Configure SPIs as non-secure Group-1. This will only matter
 591          * if the GIC only has a single security state. This will not
 592          * do the right thing if the kernel is running in secure mode,
 593          * but that's not the intended use case anyway.
 594          */
 595         for (i = 32; i < gic_data.irq_nr; i += 32)
 596                 writel_relaxed(~0, base + GICD_IGROUPR + i / 8);
 597
 598         gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp);
 599
 600         /* Enable distributor with ARE, Group1 */
 601         writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
 602                        base + GICD_CTLR);
 603
 604         /*
 605          * Set all global interrupts to the boot CPU only. ARE must be
 606          * enabled.
 607          */
 608         affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
 609         for (i = 32; i < gic_data.irq_nr; i++)
 610                 gic_write_irouter(affinity, base + GICD_IROUTER + i * 8);
 611 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章