4.2.1 通过DTS传递物理中断号给Linux

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客 

4.2.1 通过DTS传递物理中断号给Linux

参考《GICv3_Software_Overview_Official_Release_B》,下表描述了GIC V3支持的INTID(硬件中断号)的范围。

SGI (Software Generated Interrupt):软件触发的中断。Linux内核可以通过写GICD_SGIR寄存器来触发一个中断事件,用于CPU core之间的通信。

PPI (Private Peripheral Interrupt):私有外设中断。这是每个核心私有的中断。PPI会送达到指定的CPU上,应用场景有CPU本地时钟。

SPI (Shared Peripheral Interrupt):软件触发的中断。软件可以通过写GICD_SGIR寄存器来触发一个中断事件,一般用于核间通信。

LPI (Locality-specific Peripheral Interrupt):LPI是GICv3中的新特性,是基于消息的中断。当前GIC V3驱动irq-gic-v3.c的参数gicv3_nolpi默认为0,所以默认是默认支持LPI的。

SOC芯片在设计的时候,不同设备会分配到自己固定的硬件中断号,一般在手册里都会说明。这些硬件中断号如何告知内核呢?通过open firmware device tree,经常简称device tree。设备树通常以 .dts(Device Tree Source)文件的形式编写,这是一种人类可读的文本格式。.dts 文件会被编译成二进制的 .dtb(Device Tree Blob)文件,供内核在启动时使用。

以dts中的timer设备为例,说明一下硬件中断号是如何传入Linux中的。

/dts-v1/;

/ {
    ......

    timer {
        compatible = "arm,armv8-timer";
        interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_HIGH)>,
                     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_HIGH)>,
                     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_HIGH)>,
                     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_HIGH)>;
    };

    ......
};

interrupts 属性定义了定时器产生的中断。每个中断由三个字段组成:

  • 第一个字段是中断类型,0代表GIC_SPI,1代表GIC_PPI

 

  • 第二个字段是中断号。这个中断号并不是GIC中的硬件中断号,而是PPI或SPI各自范围的逻辑编号。对于PPI来说,范围是0~15;对于SPI来说,范围是0~987。例子中有四个PPI中断号:中断号13 (0x0d)、中断号14 (0x0e)、中断号11 (0x0b)、中断号10 (0x0a)。
  • 第三个字段是中断的属性,包括2个字节。低字节是中断的触发类型,在这个例子中,中断是高电平触发。高字节表示中断的目标 CPU 掩码,例如GIC_CPU_MASK_SIMPLE(8)可以表示所有 8 个 CPU 都可以接收这个中断。

 dts里面的中断号,是如何传递到Linux中呢?Linux根据dts中的timer节点来创建设备时,需要计算出真实的hwirq。以GIC IRQ V3来说,使用gic_irq_domain_translate函数,根据中断类型进行转换。对于PPI,要加上16;对于SPI,要加上32.

最后一个问题,对于timer设备来说,四个中断最终使用哪个中断?根据compatible = "arm,armv8-timer",确认匹配的驱动程序为drivers/clocksource/arm_arch_timer.c。四个中断的定义在include/clocksource/arm_arch_timer.h。 

drivers/clocksource/arm_arch_timer.c
TIMER_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);

include/clocksource/arm_arch_timer.h
enum arch_timer_ppi_nr {
    ARCH_TIMER_PHYS_SECURE_PPI,   // 对应timer中的PPI 13
    ARCH_TIMER_PHYS_NONSECURE_PPI, //对应timer中的PPI 14
    ARCH_TIMER_VIRT_PPI,          //对应timer中的PPI 11
    ARCH_TIMER_HYP_PPI,           //对应timer中的PPI 10
    ARCH_TIMER_MAX_TIMER_PPI      // 用于边界检查
};

以我用的QEMU virt为例,arch_timer_of_init调用arch_timer_select_ppi()选择了ARCH_TIMER_VIRT_PPI,对应timer中的PPI 11。根据上面的分析,针对PPI中断,Linux会加上偏移量16,最终得到hwirq 27!

通过cat /proc/interrupts来验证一下,arch_timer的硬件中断号hwirq确实是27!

注意看图上的第一列,显示的是Linux中断号。arch_timer的硬件中断号hwirq 27对应Linux的中断号为3,二者是怎么映射的,下一章继续分析。

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值