4.8 IPIPE中断流动的标识
4.8.1 传入__ipipe_dispatch_irq的flags
include/linux/ipipe.h:
#define IPIPE_IRQF_NOACK 0x1
#define IPIPE_IRQF_NOSYNC 0x2
void __ipipe_dispatch_irq(unsigned int irq, int flags);
传入__ipipe_dispatch_irq的flags,有三种可能性:0、1、2.
第一,传入0
在gic_handle_irq读到物理中断号irqnr后,如果是PPI/SPI/LPI中断,则调用 ipipe_handle_domain_irq。
ipipe_handle_domain_irq->__ipipe_grab_irq->__ipipe_dispatch_irq(irq, 0)总是向__ipipe_dispatch_irq传递flags=0。


第二,传入1(IPIPE_IRQF_NOACK)
IPIPE_IRQF_NOACK,代表在__ipipe_dispatch_irq中不需要执行ipd->irqs[irq].ackfn(desc)。ackfn在《4.4.2 timer中断的应答(__ipipe_dispatch_irq上半部)》有完整的阐述。

为什么flags设置了IPIPE_IRQF_NOACK,需要执行第1510行:IPIPE_WARN_ONCE(chained_irq)?
根据注释,chained中断绝大部分都有一个有效的ackfn(acknowledge handler),应该不要在chained中断处理过程中向__ipipe_dispatch_irq传入IPIPE_IRQF_NOACK。
什么时候可以合理的传入IPIPE_IRQF_NOACK?有两种情况:
- 调用__ipipe_grab_ipi处理SGI中断不需要调用ackfn
在gic_handle_irq读到物理中断号irqnr后,如果是SGI中断,则调用 ipipe_handle_multi_ipi。
ipipe_handle_multi_ipi-> __ipipe_grab_ipi-> __ipipe_dispatch_irq(irq, IPIPE_IRQF_NOACK)总是向__ipipe_dispatch_irq传递flags=IPIPE_IRQF_NOACK。


- ipipe_raise_irq,是软件模拟的中断,不需要ackfn
在没有硬件中断发生的情况下,可以直接调用__ipipe_dispatch_irq(irq, IPIPE_IRQF_NOACK)传入一个virq中断号,模拟一个中断的发生。

第三,传入2(IPIPE_IRQF_NOSYNC)
IPIPE_IRQF_NOSYNC 完全是服务于chained中断。参考《4.7 chained中断如何流动》。
4.8.2 Interrupt control bits
Interrupt control bits指的是如下标识位,服务于struct ipipe_domain的成员unsigned long control。
include/linux/ipipe_domain.h:
/* Interrupt control bits */
#define IPIPE_HANDLE_FLAG 0
#define IPIPE_STICKY_FLAG 1
#define IPIPE_LOCK_FLAG 2
#define IPIPE_HANDLE_MASK (1 << IPIPE_HANDLE_FLAG)
#define IPIPE_STICKY_MASK (1 << IPIPE_STICKY_FLAG)
#define IPIPE_LOCK_MASK (1 << IPIPE_LOCK_FLAG)
struct ipipe_domain {
int context_offset;
struct ipipe_irqdesc {
unsigned long control;
ipipe_irq_ackfn_t ackfn;
ipipe_irq_handler_t handler;
void *cookie;
} ____cacheline_aligned irqs[IPIPE_NR_IRQS];
const char *name;
struct mutex mutex;
};
第一种,IPIPE_HANDLE_MASK
IPIPE_HANDLE_MASK的意义就是代表是否在domain中已经注册了handler!在ipipe_request_irq会对control进行赋值IPIPE_HANDLE_MASK,ipipe_free_irq会对control赋值0。
在__ipipe_dispatch_irq中总是通过检查ipd->irqs[irq].control是否设置了IPIPE_HANDLE_MASK来判断是否注册了handler。

第二种,IPIPE_STICKY_MASK
根据注释,IPIPE_STICKY_MASK 代表立刻在当前域进行处理。

在IPIPE代码中,只有一个中断设置了此标识:head domain和root domain初始化过程中,都会调用init_stage->__ipipe_hook_critical_ipi->hook_internal_ipi为各自的中断IPIPE_CRITICAL_IPI设置相同的中断处理函数__ipipe_do_critical_sync。

所以,这个IPIPE_CRITICAL_IPI发生时,在__ipipe_dispatch_irq中会被记录到__ipipe_current_domain的interrupt log中。
第三种,IPIPE_LOCK_MASK
IPIPE_LOCK_MASK没有被__ipipe_dispatch_irq直接使用,是在__ipipe_dispatch_irq ->__ipipe_set_irq_pending间接使用。
在__ipipe_set_irq_pending,如果发现某个中断设置了IPIPE_LOCK_MASK,则把中断记录到irqheld_map中(interrupt held log)。

从gic_mask_irq ->ipipe_lock_irq->__ipipe_lock_irq调用过程中的细节可知,IPIPE_LOCK_MASK仅对root domain生效。__ipipe_lock_irq不仅会设置IPIPE_LOCK_MASK,还会把interrupt pend log中的中断标志位挪到interrupt held log中。__ipipe_unlock_irq是__ipipe_lock_irq的反向操作。

至此,已经完成第四章所有的内容!
在第四章分析过不同的场景下,走到__ipipe_dispatch_irq里面的逻辑:
- IPI 中断如何复用:《3.5.1 __ipipe_init()之IPIPE_CRITICAL_IPI》
- 同时在Head domain和Root domain注册的中断:《4.4 timer中断从Xenomai流向Linux》
- 仅在head domain注册的设备中断:《4.5 仅在head domain注册的设备中断处理流程》
- 仅在root domain注册的设备中断:《4.6 仅在root domain注册的设备中断》
- chained中断如何流动:《4.7 chained中断如何流动》
- 在IPIPE中涉及到的逻辑判断的标志位:《4.8 IPIPE中断流动的标识》
第一次感觉把__ipipe_dispatch_irq完完全全的看懂了,看透了!
41

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



