Warm tip: This article is reproduced from serverfault.com, please click

c-为什么对于返回IRQ_HANDLED的共享IRQ,Linux内核不会在第一个处理程序处停止?

(c - Why does the Linux kernel not stop at the first handler for a shared IRQ that returns IRQ_HANDLED?)

发布于 2020-12-01 15:38:13

我敢肯定有一个很好的理由,但是我看不出它是什么。__handle_irq_event_percpu内核内部遍历为特定IRQ行注册的所有处理程序,并对其进行调用。我不明白的是为什么在到达第一个处理程序返回时没有退出此循环IRQ_HANDLED这似乎是一个简单的性能改进,因此必须有一些我不理解的地方。

有人知道为什么吗?

Questioner
cmannett85
Viewed
0
Rachid K. 2020-12-10 16:57:54

在Linux源代码树中,__ handle_irq_event_percpu()位于kernel / irq / handle.c中

irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{
    irqreturn_t retval = IRQ_NONE;
    unsigned int irq = desc->irq_data.irq;
    struct irqaction *action;

    record_irq_time(desc);

    for_each_action_of_desc(desc, action) {
        irqreturn_t res;

        trace_irq_handler_entry(irq, action);
        res = action->handler(irq, action->dev_id);
        trace_irq_handler_exit(irq, action, res);

        if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pS enabled interrupts\n",
                  irq, action->handler))
            local_irq_disable();

        switch (res) {
        case IRQ_WAKE_THREAD:
            /*
             * Catch drivers which return WAKE_THREAD but
             * did not set up a thread function
             */
            if (unlikely(!action->thread_fn)) {
                warn_no_thread(irq, action);
                break;
            }

            __irq_wake_thread(desc, action);

            /* Fall through - to add to randomness */
        case IRQ_HANDLED:
            *flags |= action->flags;
            break;

        default:
            break;
        }

        retval |= res;
    }

    return retval;
}

for_each_action_of_desc(DESC,动作)在IRQ描述符的动作列表宏游记:

#define for_each_action_of_desc(desc, act)          \
    for (act = desc->action; act; act = act->next)
[...]
struct irq_desc {
    struct irq_common_data  irq_common_data;
    struct irq_data     irq_data;
    unsigned int __percpu   *kstat_irqs;
    irq_flow_handler_t  handle_irq;
    struct irqaction    *action;    /* IRQ action list */
[...]
struct irqaction {
    irq_handler_t       handler;
    void            *dev_id;
    void __percpu       *percpu_dev_id;
    struct irqaction    *next;
    irq_handler_t       thread_fn;
    struct task_struct  *thread;
    struct irqaction    *secondary;
    unsigned int        irq;
    unsigned int        flags;
    unsigned long       thread_flags;
    unsigned long       thread_mask;
    const char      *name;
    struct proc_dir_entry   *dir;
} ____cacheline_internodealigned_in_smp;

如果中断线由多个设备共享,则动作列表中有多个条目。因此,几个设备可能会同时进入中断状态因此,将为共享线路的所有设备调用该操作,以检查是否有事情要做。

注意