天天看点

kernel first 内核优先1. 什么是内核优先2. ACPI for the Armv8 RAS Extensions 1.03. 中断知识

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 }