[gic]-ARM gic总结

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.

扫描二维码关注公众号,回复: 11439199 查看本文章

当有中断进来时,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()

猜你喜欢

转载自blog.csdn.net/weixin_42135087/article/details/107202458
GIC