kernel 提供了一个命令行参数threadirqs,这个参数会让irq 中断强制运行在thread context,这个时候不管用户是否
设置中断线程化,都强制让中线运行在线程上下文中.
static int __init setup_forced_irqthreads(char *arg)
{
force_irqthreads = true;
return 0;
}
early_param("threadirqs", setup_forced_irqthreads);
当命令行加threadirqs时,则setup_forced_irqthreads等于true
当调用request_threaded_irq->__setup_irq 申请中断时
static int
__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
struct irqaction *old, **old_ptr;
unsigned long flags, thread_mask = 0;
int ret, nested, shared = 0;
#检查是否中断中嵌套中中断,从这里看kernel是支持中断嵌套的
nested = irq_settings_is_nested_thread(desc);
if (nested) {
if (!new->thread_fn) {
ret = -EINVAL;
goto out_mput;
}
/*
* Replace the primary handler which was provided from
* the driver for non nested interrupt handling by the
* dummy function which warns when called.
*/
new->handler = irq_nested_primary_handler;
} else {
#这里检查是否强制中断线程化
if (irq_settings_can_thread(desc)) {
ret = irq_setup_forced_threading(new);
if (ret)
goto out_mput;
}
}
}
一般我们都不设置_IRQ_NOTHREAD,所以if (irq_settings_can_thread(desc)) 返回true 进入到irq_setup_forced_threading
static inline bool irq_settings_can_thread(struct irq_desc *desc)
{
return !(desc->status_use_accessors & _IRQ_NOTHREAD);
}
static int irq_setup_forced_threading(struct irqaction *new)
{
#可以看到如果没有通过命令行设置force_irqthreads 为ture的话,这里就返回了
if (!force_irqthreads)
return 0;
if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT))
return 0;
/* Deal with the primary handler */
set_bit(IRQTF_FORCED_THREAD, &new->thread_flags);
new->thread_fn = new->handler;
#设置中断线程化的话,需要让中断线程返回IRQ_WAKE_THREAD,这样就会调用原本中断的callback函数new->handler
new->handler = irq_default_primary_handler;
return 0;
}
这个函数将在中断环境中执行,而用户设置的真正的中断回调函数却在线程上线文中执行
static irqreturn_t irq_default_primary_handler(int irq, void *dev_id)
{
return IRQ_WAKE_THREAD;
}