baron · 3月25日 · 四川

[gic]-ARM gicv2和gicv3的中断模型总结

快速连接

👉👉👉【精选】ARMv8/ARMv9架构入门到精通-目录 👈👈👈


 title=

GICV2

1、gicv2的中断模型

在SOC中,中断产生后,怎么讲信息发送给CPU的呢,如下图所示,画了一个简要说明:
在这里插入图片描述
ARM CORE只有4根线用于接受中断,nIRQ、nFIQ、nvIRQ、nvFIQ. 未enable hypevisor时,我们只看nIRQ、nFIQ就可以了;
SOC中的所有中断都接到gic上,然后gic再输出nIRQ、nFIQ、nvIRQ、nvFIQ四根信号给ARM core;
ARM CORE在收到中断信号后,会通过AXI总线去读写GIC的寄存器(软件上是通过memory-map的方式去读写),继而获取是哪个中断号产生的中断。

当一个device需要使用中断,该device会输出一个中断信号线,该中断线会接到gic上,gic中的cpu interface组件中的GICC_IAR寄存器就会跟着发生变化, 例如:
指纹模组产生了一个中断,该中断线接到了gic上,gic收到该中断后,相应的GICC_IAR寄存器就会发送变化。 这些都是由ASIC来设计的,例如我们由一个指纹中断,中断号是59,所谓的该中断号是59,其实就是该引脚产生中断信号后,相应的GICC_IAR寄存器会被写入59数值。

2、gicv2寄存器

(1)、Distributor register

在这里插入图片描述在这里插入图片描述

(2)、CPU interface register

在这里插入图片描述

3、中断处理的过程

在中断产生后,ARM Core接收到IRQ或FIQ信号会跳转到ARM的IRQ/FIQ异步异常向量表.
该向量表是在linux kernel开机初始化时设置,在该向量表的处理中,会跳转到gicv2的hander函数:gic_handle_irq()

static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
    u32 irqstat, irqnr;
    struct gic_chip_data *gic = &gic_data[0];
    void __iomem *cpu_base = gic_data_cpu_base(gic);

    do {
        irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
        irqnr = irqstat & GICC_IAR_INT_ID_MASK;

        if (likely(irqnr > 15 && irqnr < 1021)) {
            if (static_key_true(&supports_deactivate))
                writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
            handle_domain_irq(gic->domain, irqnr, regs);
            continue;
        }
        if (irqnr < 16) {
            writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
            if (static_key_true(&supports_deactivate))
                writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE);
#ifdef CONFIG_SMP
            /*
             * Ensure any shared data written by the CPU sending
             * the IPI is read after we've read the ACK register
             * on the GIC.
             *
             * Pairs with the write barrier in gic_raise_softirq
             */
            smp_rmb();
            handle_IPI(irqnr, regs);
#endif
            continue;
        }
        break;
    } while (1);
}

我们剖析一下这段代码:
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
irqnr = irqstat & GICC_IAR_INT_ID_MASK;
GIC_CPU_INTACK是0X0C,对应gicv2文档中的GICC_IAR,也就是读取gic中的物理中断号

if (likely(irqnr > 15 && irqnr < 1021)) 如果是PPI/SPI中断,则执行handle_domain_irq()

if (irqnr < 16)如果是SGI中断,则会执行后面的handle_IPI()

GICV3

1、gicv3的中断模型

在这里插入图片描述
在gicv3中,发生了很大的变化,原gicv2组件中的cpu interface移到了ARM Core中,
ARM Core通过系统寄存器的方式访问cpu interface寄存器(msr/mrs指令),不再是memory-map方式了。
当然了,访问destributor/redestributor还是通过memory-map方式.
gic同ARM Core的接口,也变成了AXI stream.

当有中断进来时,gic组件会通过AXI Stream传输信息给cpu interface,cpu interface仲裁后,再将FIQ/IRQ信号发送给真正的ARM CORE.

2、gicv3的寄存器

gicv3有组件中:detributor、redetributor、its再gicv3中, cpu interface挪到了ARM Core中
gicv3的寄存器有两种访问方式:一类是通过memory-map方式访问、一类是通过系统寄存器方式访问;

  • GICD 开头的寄存器是detributor寄存器,只能通过memory-map方式
  • GICR 开头的寄存器是redetributor寄存器,只能通过memory-map方式
  • GITS 开头的寄存器是its寄存器,只能通过memory-map方式
  • GICC 开头的寄存器是cpu interface寄存器,可以通过memory-map方式
  • ICC 开头的寄存器是cpu interface寄存器,可以通过系统寄存器方式访问 —— 对于cpu
    interface寄存器,我们一般采取这种访问

在这里插入图片描述

3、中断处理的过程

在中断产生后,ARM Core接收到IRQ或FIQ信号会跳转到ARM的IRQ/FIQ异步异常向量表.
该向量表是在linux kernel开机初始化时设置,在该向量表的处理中,会跳转到gicv2的hander函数:gic_handle_irq()

static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
    u32 irqnr;

    do {
        irqnr = gic_read_iar();

        if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
            int err;

            if (static_key_true(&supports_deactivate))
                gic_write_eoir(irqnr);

            err = handle_domain_irq(gic_data.domain, irqnr, regs);
            if (err) {
                WARN_ONCE(true, "Unexpected interrupt received!\n");
                if (static_key_true(&supports_deactivate)) {
                    if (irqnr < 8192)
                        gic_write_dir(irqnr);
                } else {
                    gic_write_eoir(irqnr);
                }
            }
            continue;
        }
        if (irqnr < 16) {
            gic_write_eoir(irqnr);
            if (static_key_true(&supports_deactivate))
                gic_write_dir(irqnr);
#ifdef CONFIG_SMP
            /*
             * Unlike GICv2, we don't need an smp_rmb() here.
             * The control dependency from gic_read_iar to
             * the ISB in gic_write_eoir is enough to ensure
             * that any shared data read by handle_IPI will
             * be read after the ACK.
             */
            handle_IPI(irqnr, regs);
#else
            WARN_ONCE(true, "Unexpected SGI received!\n");
#endif
            continue;
        }
    } while (irqnr != ICC_IAR1_EL1_SPURIOUS);
}

我们剖析一下这段代码:
irqnr = gic_read_iar() 使用mrs指令读取cpu interface寄存器中的ICC_IAR_EL1寄存器,该寄存器记录着物理中断号;
if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) 如果是PPI、SPI、LPI中断
if (irqnr < 16)如果是SGI中断,则会执行后面的handle_IPI()


关注"Arm精选"公众号,备注进ARM交流讨论区。
图片1.png

推荐阅读
关注数
9437
内容数
191
以易懂、渐进、有序的方式,深入探讨ARMv8/ARMv9架构的核心概念。我们将从基础知识开始,逐步深入,覆盖最新的架构,不再纠缠于过时技术。本系列内容包含但不限于ARM基础、SOC芯片基础、Trustzone、gic、异常和中断、AMBA、Cache、MMU等内容,并将持续更新。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息