1 : ID 分配
gic控制器最多支持 1020 个中断源, 支持多少,是soc 芯片设计时确定下来的
如 Altera cyclone 平台支持 256个中断源
SPI 外设中断 (Shared Peripheral Interrupt) 32 ~ 1019
先看一下中断控制器的初始化
main.c
❶ /* 源头 : uboot最终会跳入这个坑里,唯有源头活水来,uboot现在都die了 */
void start_kernel(void)
{
❷:irq.c
init_IRQ();
{
❸:irqchip.c
/* 如果支持Device-Tree ,machine_desc 下面会详细说明*/
if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq)
irqchip_init();
{
❹ : irq.c
of_irq_init();
{
❺irq-gic.c
/* 中断控制器开始初始化,到这里才init,坑太深!*/
gic_of_init()
}
}
else
machine_desc->init_irq();
}
}
好,下面先看一下这个函数
/*
它是怎么被调用的,下面会说,这里先看它的实现
*/
static void __exception_irq_entry gic_handle_irq(struct pt_regs * regs)
{
/*
irqnr : GIC控制器支持中断源的数目.最大为1020.
SOC在芯片设计阶段,是怎么确定下来的呢?
irqstat : GIC中断控制器中 中断确认寄存器的值,会取出它的低10位的值.
*/
u32 irqstat, irqnr;
/*
GIC描述结构
struct gic_chip_data {
union gic_base dist_base; 中断分发器的地址空间.
union gic_base cpu_base; cpu interface的基地址.
struct irq_domain * domain; 对应的irq_domain数据结构.
unsigned int gic_irqs; GIC支持的IRQ的数目,在gic_init_base中读取对应的寄存器后会为他赋值.
};
*/
struct gic_chip_data *gic = &gic_data[0];
/*
在初始化中断控制器的时候已经赋值了,
资源在初始化阶段被初始化并赋值给对应的结构体成员,到用的时候直接从该结构体中取出,常见且经典的做法.
gic_of_init(....)
{
void __iomem * cpu_base;
....
cpu_base = of_iomap(node,0); 底层使用 ioremap()来映射实现
....
gic_init_bases(gic_cnt,-1,dist_base,cpu_base,percpu_offset,node);
{
....
gic->cpu_base.common_base = dist_base; //在这里赋值了.
}
}
*/
void __iomem * cpu_base = gic_data_cpu_base(gic);
/*
下面是一个 do while()循环, 164 mo ISR会一直中断风暴来了,哈哈!
*/
do {
/*
上面说过了,这里读取寄存器赋值
Interrupt Acknowledge Register
GICC_IAR RO 0x0000003FF 只读 中断ID (硬件中断id)
*/
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
/*
bit[9:0] : 发生中断的硬件中断号,
Qualcomm 的linux kernel 维护者,姐,看到了吧,是从中断控制器中获取的硬件中断ID
*/
irqnr = irqstat & GICC_IAR_INT_ID_MASK;
/*
硬件中断号 15 ~ 1020,它是PPI 或者 SPI类型的中断.
*/
if (likely(irqnr > 15 && irqnr < 1021)) {
/*
硬件中断号传入进去了,会找到对应的软件中断号,
现在 还没有进入中断上下文
颠覆OS的革命技术 Interrupt 现在开始 闪亮登场了 . 哈哈!
*/
handle_domain_irq(gic->domain, irqnr, regs);
/*
神来之笔!
*/
continue;
}
/*
SGI中断,用于多核之间通讯.暂不分析.
*/
if (irqnr < 16) {
....
}
break;
} while (1);
}