1. 从硬件中断号到Linux IRQ:GIC驱动的初始化核心
上一篇文章我们聊了Linux中断子系统的整体框架,知道了它分为硬件无关的通用层、硬件相关层和硬件层。今天,咱们就深入到硬件相关层最核心的部分——GIC驱动的初始化。这就像你要用电脑,得先给主板通电、装好操作系统一样,GIC驱动就是让CPU能“认识”并管理所有硬件中断的那个“操作系统安装程序”。
我刚开始接触这块的时候,总觉得GIC驱动初始化代码又长又复杂,看得一头雾水。后来发现,只要抓住一条主线就清晰了:它的核心任务就是建立硬件中断世界和Linux软件世界之间的“翻译官”体系。这个“翻译官”在Linux里叫 irq_domain。
简单来说,硬件设备(比如你的网卡、UART串口)都有自己的“身份证号”,叫硬件中断号(HW interrupt ID)。这个号是GIC控制器硬件规定的,比如RK3568芯片上,UART3的中断硬件号可能是119。但Linux内核自己有一套独立的“户口本”来管理中断,它给每个需要处理的中断分配一个虚拟中断号(Linux IRQ number)。GIC驱动初始化时,最关键的一步就是创建一个irq_domain,并告诉它如何把“硬件身份证号”翻译成“Linux户口号”。
我们来看一下实际驱动代码里是怎么做的。以Linux内核中GICv3的驱动(drivers/irqchip/irq-gic-v3.c)为例,初始化的入口通常是gic_of_init或gic_init_bases。这里面我挑几个最关键的步骤给你拆解:
第一步:映射寄存器地址。 驱动首先从设备树(Device Tree)里拿到GIC控制器的“家庭住址”,也就是reg属性里描述的Distributor和Redistributor的物理内存地址,然后通过ioremap把这些地址映射到内核的虚拟地址空间。这样,软件才能通过读写内存的方式来配置GIC这个硬件。
dist_base = of_iomap(node, 0); // 映射GIC Distributor寄存器区域
if (!dist_base) {
pr_err("无法映射GIC Distributor寄存器\n");
return -ENXIO;
}
第二步:创建irq_domain。 这是灵魂操作。内核会调用irq_domain_create_tree来创建一个irq_domain结构体,并关联一组操作函数集(gic_irq_domain_ops)。这组函数里最重要的两个是:
translate: 负责解析设备树里描述的中断信息,提取出硬件中断号和触发类型(比如上升沿、高电平)。map: 负责完成硬件中断号到Linux IRQ的绑定,并且设置好这个Linux IRQ对应的中断描述符(struct irq_desc)里的关键函数指针。
第三步:设置CPU的中断处理入口。 通过set_handle_irq(gic_handle_irq),告诉CPU:“以后所有外部中断来了,都先统一跑到gic_handle_irq这个函数来报到!” 这个函数是中断从硬件进入软件世界的总闸口。
第四步:初始化GIC硬件本身。 调用gic_dist_i

1150

被折叠的 条评论
为什么被折叠?



