3.4.3 __ipipe_init_early之初始化root domain

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

3.4.3 __ipipe_init_early之初始化root domain

       如下图所示,红框里面的函数当前都是空的,本章还是分析蓝框中的代码片段。

第295行,变量ipd指向了ipipe_root即ipd代表root domain。

第305行,root domain的名字被命名为“Linux”。

第306行,初始化ipd->context_offset变量,详细分析见《3.4.1.1 IPIPE基础数据结构》。

第307行,调用init_stage(ipd)对root domain进行初始化。此函数只要3行,直接在代码里面进行注释如下:

linux/kernel/ipipe/core.c:
static void init_stage(struct ipipe_domain *ipd)
{
//对ipipe_irqdesc irqs[IPIPE_NR_IRQS]数组进行清零操作。
//此数据结构的意义具体见《3.4.1.2 IPIPE对Linux中断号的改造》
	memset(&ipd->irqs, 0, sizeof(ipd->irqs));

    //对互斥量进行初始化
	mutex_init(&ipd->mutex);

//(1) 调用__ipipe_ipis_alloc()完成所有IPI中断的分配
//(2) 调用hook_internal_ipi设置IPIPE_CRITICAL_IPI
	__ipipe_hook_critical_ipi(ipd);
}

arch/arm64/kernel/ipipe.c:
void __ipipe_hook_critical_ipi(struct ipipe_domain *ipd)
{
	__ipipe_ipis_alloc();
	hook_internal_ipi(ipd, IPIPE_CRITICAL_IPI, __ipipe_do_critical_sync);
}

       init_stage最后调用的函数__ipipe_hook_critical_ipi(ipd),里面做了两件事情,需要展开说一下。

  • 调用__ipipe_ipis_alloc()完成所有IPI中断的分配
arch/arm64/kernel/smp.c:
void __ipipe_ipis_alloc(void)
{
	unsigned int virq, ipi;
	static bool done;

	if (done)
		return;

	/*
	 * We have to get virtual IRQs in the range
	 * [ IPIPE_IPI_BASE..IPIPE_IPI_BASE + NR_IPI + IPIPE_OOB_IPI_NR - 1 ],
	 * otherwise something is wrong (likely someone would have
	 * allocated virqs before we do, and this would break our
	 * fixed numbering scheme for IPIs).
	 */
	for (ipi = 0; ipi < NR_IPI + IPIPE_OOB_IPI_NR; ipi++) {
		virq = ipipe_alloc_virq();
		WARN_ON_ONCE(virq != IPIPE_IPI_BASE + ipi);
	}

	done = true;
}

        根据《3.4.1.2 IPIPE对Linux中断号的改造》的分析,NR_IPI等于7,IPIPE_OOB_IPI_NR等于3,所以for循环调用ipipe_alloc_virq()函数10次,共申请10个virtual interrupt编号。关于virtual interrupt,之前已经总结过了,它的总数量就是IPIPE_NR_VIRQS(64)。为了管理virtual interrupt,IPIPE定义了全局变量 __ipipe_virtual_irq_map,通过位图来标记是否virtual interrupt是否被占用。 

       ipipe_alloc_virq()函数的本质,就是在变量__ipipe_virtual_irq_map的64个bit中,找到第一个为0的bit位(ffz就是find first zero)即空闲的bit位,然后把此bit位设置为1即占用此bit位。从__ipipe_virtual_irq_map中找到的bit位存到变量ipos,必须再加上IPIPE_VIRQ_BASE(1024),才能得到最终的virtual interrupt的编号。

    回到__ipipe_ipis_alloc,它for循环调用ipipe_alloc_virq()函数10次,得到的10个virq是1024~1033. 注意这个范围哦,下一步的IPIPE_CRITICAL_IPI是1031,就在这个范围内!

linux/kernel/ipipe/core.c:
// 共64 bit位,通过位图来标记是否VIRQ是否被占用
static unsigned long __ipipe_virtual_irq_map;

unsigned int ipipe_alloc_virq(void)
{
	unsigned long flags, irq = 0;
	int ipos;

	raw_spin_lock_irqsave(&__ipipe_lock, flags);

	if (__ipipe_virtual_irq_map != ~0) {
		ipos = ffz(__ipipe_virtual_irq_map);
		set_bit(ipos, &__ipipe_virtual_irq_map);
		irq = ipos + IPIPE_VIRQ_BASE;
	}

	raw_spin_unlock_irqrestore(&__ipipe_lock, flags);

	return irq;
}
EXPORT_SYMBOL_GPL(ipipe_alloc_virq);
  • 调用hook_internal_ipi设置IPIPE_CRITICAL_IPI

        IPIPE_CRITICAL_IPI是OOB IPI之一,它对应的virq编号是1031。上一步已经把1031分配出来了,hook_internal_ipi就是来设置IPIPE_CRITICAL_IPI对应的中断处理程序为__ipipe_do_critical_sync()!具体这个函数的用处,后面的章节再分析。

arch/arm64/kernel/ipipe.c:
static inline void
hook_internal_ipi(struct ipipe_domain *ipd, int virq,
		  void (*handler)(unsigned int irq, void *cookie))
{
	ipd->irqs[virq].ackfn = NULL;
	ipd->irqs[virq].handler = handler;
	ipd->irqs[virq].cookie = NULL;
	/* Immediately handle in the current domain but *never* pass */
	ipd->irqs[virq].control = IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK;
}

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值