3.5_第三行之__ipipe_init()

第三行之__ipipe_init()

3.5.1 __ipipe_init()之IPIPE_CRITICAL_IPI

在这里插入图片描述

__ipipe_init()最核心的就是__ipipe_enable_pipeline(),接下来对其展开分析!__ipipe_enable_pipeline()又可以分成两大部分来分析。本小节分析第一部分:ipipe_critical_enter和ipipe_critical_exit。

在这里插入图片描述

第一步:ipipe_send_ipi(IPIPE_CRITICAL_IPI, allbutself);

传入的ipi号是IPIPE_CRITICAL_IPI,它的定义是IPIPE_IPI_BASE + NR_IPI,它的值是virtual interrupt编号1031。在函数ipipe_send_ipi中减掉IPIPE_IPI_BASE得到7,存入ipinr并传递给函数smp_cross_call.

在这里插入图片描述

传入的cpumask是allbutself,它在ipipe_critical_enter中被初始化,除了bootup的CPU core 0,其它所有online CPU cores对应的bit位被置位1.

第二步:smp_cross_call(&cpumask, ipinr);

在这里插入图片描述

如果传入的ipinr小于7即0~6,说明是Linux的原生IPI,需要复用SGI0,变量sgi等于0。此时需要把ipinr记录到per cpu变量ipi_messages,方便其它CPU Core接收到SGI0中断时,从per cpu变量ipi_messages读出正确的ipinr的数值。

在当前的例子中,传入的ipinr等于7,所以在第862行sgi等于1。这就印证了《3.4.1.2 IPIPE对Linux中断号的改造》里面的分析,3个OOB IPI使用SGI1/2/3.

第三步:__smp_cross_call(target, sgi);

函数指针__smp_cross_call是在gic_init_bases-> gic_smp_init中初始化的,指向函数gic_raise_softirq。

drivers/irqchip/irq-gic-v3.c:
static void gic_smp_init(void)
{
	set_smp_cross_call(gic_raise_softirq);
	cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
				  "irqchip/arm/gicv3:starting",
				  gic_starting_cpu, NULL);
}

arch/arm64/kernel/smp.c:
void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
{
	__smp_cross_call = fn;
}

第四步:set_smp_cross_call(gic_raise_softirq);

GIC V3中断控制器,最终通过写SYS_ICC_SGI1R_EL1寄存器像其它CPU Cores发生SGI 1中断。

gic_raise_softirq
->gic_send_sgi
    ->gic_write_sgi1r
        ->write_sysreg_s(val, SYS_ICC_SGI1R_EL1)

第五步:gic_handle_irq

SGI 1中断发生后,根据《2.3.5 irq_handler》的分析,GIC V3中断控制器调用gic_handle_irq来处理中断。因为是IPI中断,所以调用ipipe_handle_multi_ipi来处理。

在这里插入图片描述

第六步:ipipe_handle_multi_ipi(irqnr, regs)

只调用了一个函数__ipipe_grab_ipi(irq, regs)。
在这里插入图片描述

第七步:__ipipe_grab_ipi(irq, regs);
在这里插入图片描述

如果sgi为非0,则说明是OOB IPI。在当前分析的上下文中,因为sgi传入的是1,所以irq最终等于1031,就是IPIPE_CRITICAL_IPI。所以,在这一步已经还原出需要响应的virtual interrupt编号。

如果sgi编号为0,则说明是Linux原生IPI,从per cpu变量ipi_messages还原出Linux原生IPI编号06,再加上IPIPE_IPI_BASE,变成10241030。对照第二步,就搞清楚了Linux原生IPI是如何复用SGI0了。

第八步:__ipipe_dispatch_irq

实时内核的注册是在start_kernel->rest_init中,是在_ipipe_init()之后才调用的。所以此时实时内核并没有注册,即ipipe_head_domain其实就等于ipipe_root_domain。在此背景下,virtual interrupt编号1031就会被__ipipe_set_irq_pending记录到interrupt log。

最后层层调用__ipipe_sync_pipeline ->__ipipe_do_sync_pipeline ->__ipipe_sync_stage->__ipipe_do_sync_stage,通过__ipipe_next_irq进行interrupt log回放。找到virtual interrupt编号1031,执行它的中断处理程序。根据《3.4.3 __ipipe_init_early之初始化root domain》,IPIPE_CRITICAL_IPI(1031)对应的中断处理程序初始化为__ipipe_do_critical_sync()。也就是说,除了CPU Core 0,其它online的CPU cores都开始执行__ipipe_do_critical_sync()。

在这里插入图片描述

第九步:_ipipe_do_critical_sync()

除了CPU Core 0,其它online的CPU cores都开始执行__ipipe_do_critical_sync()。这些CPU core都把自身的cpu编号在__ipipe_cpu_sync_map中进行置位,以此来通知CPU Core 0:老大,我已顺利收到IPIPE_CRITICAL_IPI(1031),并开始执行__ipipe_do_critical_sync()。

在这里插入图片描述

而CPU Core 0在ipipe_critical_enter中,不断检查__ipipe_cpu_sync_map的值,只要所有CPU cores对应的bit已经置位了,则说明:兄弟们都收到通知并开始执行了。

在这里插入图片描述

第十步,ipipe_critical_exit

其它online的CPU cores执行完__ipipe_do_critical_sync(),会最终把自身的cpu编号在__ipipe_cpu_sync_map中进行清空,以此来通知CPU Core 0:老大,我已顺利完成任务。
在这里插入图片描述

而CPU Core 0在ipipe_critical_exit中,不断检查__ipipe_cpu_sync_map,确定兄弟们都完成了任务,则最终退出循环,代表整个IPIPE_CRITICAL_IPI处理完美结束。
在这里插入图片描述

3.5.2 __ipipe_init()之完成中断处理程序设置

在这里插入图片描述

__ipipe_init()最核心的就是__ipipe_enable_pipeline(),接下来对其展开分析!__ipipe_enable_pipeline()又可以分成两大部分来分析。本小节分析第二部分:完成中断处理程序的设置。

在这里插入图片描述

借用在《3.4.1.2》中总结的中断号映射图,关注一下root domain的中断号,在0~1033范围内,其中只有IPIPE_CRITICAL_IPI(1031)已经分配且设置了中断处理程序_ipipe_do_critical_sync()。其它的中断号怎么办?

在这里插入图片描述

1. XIRQS(0~1023)

通过调用ipipe_request_irq,把XIRQS(01023)的中断处理程序全部设置成:__ipipe_do_IRQ。也就是说,中断号01023到达root domain后,全部都要经过__ipipe_do_IRQ,然后才对接到Linux中断子系统。具体的处理流程,在后面的章节分析。

在这里,分析一下ipipe_request_irq的要点。除了刚才提到的中断处理程序handler之外,还有一个控制标志control设置为IPIPE_HANDLE_MASK,代表此中断已经设置了handler!

在这里插入图片描述

2. VIRQS(1024~1033)

在函数__ipipe_ipis_request中,调用ipipe_request_irq把VIRQS(1024~1033)的中断处理程序全部设置成__ipipe_do_IPI,当然除了1031之外。

在这里插入图片描述

3. VIRQS(1034~1035)

这两个VIRQS(1034~1035),比较特殊哈,在《3.4.4 __ipipe_init_early之再论虚拟中断》已经详细解释过了,这里不再重复。

总之,在__ipipe_init()中,root domain所有的中断都已经分配了中断处理程序,用一副图总结如下。

在这里插入图片描述

至于head domain是如何初始化的,中断是如何在head domain和root domain中流动的,下一章会一一阐述!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值