3.3.2 IPIPE对Linux中断使能与屏蔽的改造

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

        3.3 第一行之hard_local_irq_disable() 

                3.3.1 Linux中断的使能与屏蔽

                        3.3.1.1 中断使能与屏蔽的三重关卡
                        3.3.1.2 第一重关卡IMR
                        3.3.1.3 第二重关卡中断控制器的使能bit
                        3.3.1.4 第三重关卡CPU core异常掩码标志

                3.3.2 IPIPE对Linux中断使能与屏蔽的改造

                        3.3.2.1 第一重关卡IMR的改造
                        3.3.2.2 第二重关卡中断控制器的使能bit的改造
                        3.3.2.3 第三重关卡的改造

3.3.2 IPIPE对Linux中断使能与屏蔽的改造

3.3.2.1 第一重关卡IMR的改造

        如上文分析,设备的Interrupt Mask Register(IMR)是由各个设备的驱动自行控制的,IPIPE patch不会做任何修改。

        如果想把某个设备交给Head域的实时内核(例如Cobalt)来使用,那么需要使用RTDM来重写设备的驱动程序。内核打上了Xenomai3 patch之后,在drivers/xenomai/目录下有很多在RTDM框架下写好的驱动。以/drivers/xenomai/spi/spi-bcm2835.c为例,它依然是直接读写IMR寄存器来控制自身的中断。

static int do_transfer_irq(struct rtdm_spi_remote_slave *slave)
{
	struct spi_master_bcm2835 *spim = to_master_bcm2835(slave);
	int ret;
	u32 cs;
	
	cs = bcm2835_rd(spim, BCM2835_SPI_CS);

    ……

	/* Enable interrupts last, wait for transfer completion. */
	cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD;
	bcm2835_wr(spim, BCM2835_SPI_CS, cs);

    ……

	return 0;
}
3.3.2.2 第二重关卡中断控制器的使能bit的改造

        如上文分析,默认情况下,disable_irq工作在UNLAZY模式。但是IPIPE是无法在UNLAZY模式下工作的,必须设置为DISABLE_UNLAZY模式。这个修正是通过__fixup_irq_handler函数来完成的。

kernel/irq/chip.c:

irq_flow_handler_t
__fixup_irq_handler(struct irq_desc *desc, irq_flow_handler_t handle, int is_chained)
{
	……

	/*
	 * We don't cope well with lazy disabling simply because we
	 * neither track nor update the descriptor state bits, which
	 * is badly wrong.
	 */
	irq_settings_clr_and_set(desc, 0, _IRQ_DISABLE_UNLAZY);

    ……

	return handle;
}

        那么__fixup_irq_handler函数是在什么时机被调用呢?是在中断分配过程中,对中断描述符irq_desc直接进行修正。具体内核的中断子系统初始化的过程,以后再详细分析。

3.3.2.3 第三重关卡的改造

       如第一章的《1.2.1.2 虚拟中断标志Virtual interrupt flag》所阐述,为了保证头域中的out-of-band代码的实时性,根域中的in-band代码一定不能关闭CPU的物理中断。所以,运行在root域(根域)中的Linux只能管理和使用虚拟中断标志。当根域中的Linux调用local_irq_save/local_irq_disable/spin_lock_irqsave等函数关闭中断时,实际上是对虚拟中断标志进行关闭操作,并没有真正的关闭物理中断标志。此时,头域中的Cobalt依然能够接收物理中断,保证实时性。

       具体是怎么做到的呢?以local_irq_disable为例说明一下。

        local_irq_disable它最终调用的是arch_local_irq_disable,而arch_local_irq_disable定义在头文件<asm/irqflags.h>。在<asm/irqflags.h>,IPIPE patch为它多增加了一个头文件<asm/ipipe_hwirq.h>,正是这个新的头文件抢先定义了local_irq_disable最终调用的arch_local_irq_disable,把原先对DAIF寄存器的操作变成了对虚拟中断标志的操作ipipe_stall_root<kernel/ipipe/core.c>。来看一下它的代码。 

        它里面最核心的是第395行__set_bit(IPIPE_STALL_FLAG, &__ipipe_root_status),将虚拟中断标志位进行置位操作(stall操作),即关闭虚拟中断。

       既然Linux不再操作物理中断,那IPIPE是如何接手的呢?回顾一下咱们第3.3章节的主题,大家就能猜出来了。是的,IPIPE重新定义一套函数来操作物理中断标志位DAIF,前缀是hard_local_irq_xxx,同样是两对函数。

        这两对函数定义在<arch/arm64/include/asm/hwirq.h>,为简化分析,默认没有定义CONFIG_IPIPE_TRACE_IRQSOFF。

arch/arm64/include/asm/hwirq.h:
#define hard_local_irq_disable    hard_local_irq_disable_notrace
#define hard_local_irq_enable     hard_local_irq_enable_notrace
#define hard_local_irq_save       hard_local_irq_save_notrace
#define hard_local_irq_restore    hard_local_irq_restore_notrace

arch/arm64/include/asm/hwirq.h:
static inline void hard_local_irq_disable_notrace(void)
{
	__asm__ __volatile__("msr daifset, #2" : : : "memory", "cc");
}

static inline void hard_local_irq_enable_notrace(void)
{
	__asm__ __volatile__("msr daifclr, #2" : : : "memory", "cc");
}

#define hard_local_irq_restore_notrace(x)				\
	__asm__ __volatile__(						\
	"msr	daif, %0"	\
	:								\
	: "r" (x)							\
	: "memory", "cc")

static inline unsigned long hard_local_irq_save_notrace(void)
{
	unsigned long res;
	__asm__ __volatile__(
		"mrs	%0, daif\n"
		"msr daifset, #2"
		: "=r" (res) : : "memory", "cc");
	return res;
}

        最后,呼应一下第3.3章节的主题哈。原先start_kernel调用local_irq_disable是为了屏蔽物理中断的。因为local_irq_disable已经变成了对虚拟中断标志位的操作,所以需要替换为IPIPE自己定义的hard_local_irq_disable。

       说起来挺简单的,但是追寻背后的细节还是花费了不少功夫。接下来分析下一行初始化代码。

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值