3.3_第一行之hard_local_irq_disable
3.3 第一行之hard_local_irq_disable
3.3.1 Linux中断的使能与屏蔽
3.3.1.1 中断使能与屏蔽的三重关卡
本章的主题是hard_local_irq_disable(),它是对中断的关闭操作。为了彻底搞清楚中断关闭的机制,这里先对Linux使能与屏蔽中断的API做详细的分析,然后再分析IPIPE做了哪些针对性地改造。这里分析的范围已经超过了hard_local_irq_disable()。如果只关心hard_local_irq_disable(),可以只看第三重关卡的分析与改造。
硬件控制器的物理中断发生后,到执行中断处理程序IRQ Handler,这中间要经历3重关卡。
3.3.1.2 第一重关卡IMR
第一重关卡指的是硬件控制器自身的中断屏蔽寄存器IMR(Interrupt Mask Register)。以SPI控制器为例,SPI_IMR[4]为0时代表RX FIFO FULL中断被屏蔽,为1时代表RX FIFO FULL中断被使能。在driver/spi/spi-rockchip.c驱动中,由驱动自行根据需要来管理中断屏蔽位。例如使能RX FIFO FULL中断,则调用:
writel_relaxed(INT_RF_FULL, rs->regs + ROCKCHIP_SPI_IMR);
其寄存器定义如下:
3.3.1.3 第二重关卡中断控制器的使能bit
第二重关卡指的是中断控制器的使能bit。以GIC V3为例,每个中断号都有一个enable bit,可以通过GICD_ISENABLER寄存器来set-enable使能中断,通过GICD_ICENABLER寄存器来clear-enable屏蔽中断。在kernel/irq/manage.c,定义了如下接口:
//关闭中断,在非中断处理程序中使用,会等待中断处理程序完成
void disable_irq(unsigned int irq) //关闭中断:在中断处理程序中使用,不会等待,避免自己等待自己造成死锁
void disable_irq_nosync(unsigned int irq) //使能中断
void enable_irq(unsigned int irq)
以disable_irq为例,来追踪一下是如何修改中断控制器的使能bit的。
disable_irq <kernel/irq/manage.c>-> __disable_irq_nosync <kernel/irq/manage.c>-> __disable_irq <kernel/irq/manage.c>-> irq_disable <kernel/irq/chip.c>-> __irq_disable <kernel/irq/chip.c>
其中最后一级的调用__irq_disable,它开始了一顿让人迷惑的操作,下面展开说一下。
第1行,第一个入参struct irq_desc *desc是指向中断描述符的指针,为方便讨论,以下简称中断描述符。第二个入参mask涉及到内核的一个精巧的设计。先看一下这个参数是如何传递下来的。
kernel/irq/chip.c:void irq_disable(st