我们可以从工作队列中调用 enable_irq() 吗?

can we call enable_irq() from workqueues?

从工作队列调用 enable_irq() 有任何副作用吗?当通过工作队列完成此操作时,我看到报告了异常。

static void mmxx_irq_worker(struct work_struct *work)
{
    struct mmxx_data *mma = container_of(work, struct mmxx_data, accel_work);

    if (unlikely(read_and_report_abs(mmxx) != 0))
        dev_err(&mmxx_i2c_client->dev, "read_and_report failed\n");

    enable_irq(mmxx->irq);
}
[ 2029.755981] Exception stack(0xd51fbe70 to 0xd51fbeb8)
[ 2029.761718] be60: c09cee10 600b0113 00000001 00000000
[ 2029.771057] be80: c09cedc0 00000001 000002bf d508bb4c 000002d6 c09b3ac0 fffffffe d51fbec4
[ 2029.780426] bea0: d51fbec8 d51fbeb8 c00b6458 c06e5b28 400b0113 ffffffff
[ 2029.787841] r6:ffffffff r5:400b0113 r4:c06e5b28 r3:c00b6458
[ 2029.795379] [<c06e5b04>] (_raw_spin_unlock_irqrestore+0x0/0x50) from [<c00b6458>] (__irq_put_desc_unlock+0x1c/0x40)
[ 2029.807189] [<c00b643c>] (__irq_put_desc_unlock+0x0/0x40) from [<c00b7c2c>] (enable_irq+0x54/0x7c)
[ 2029.817352] r5:000001e5 r4:c09cedc0
[ 2029.821990] [<c00b7bd8>] (enable_irq+0x0/0x7c) from [<c0357394>] (mmxx_irq_worker+0x1b8/0x238)
[ 2029.832061] r5:c0a1d8b4 r4:c0abb340
[ 2029.836700] [<c03571dc>] (mmxx_irq_worker+0x0/0x238) from [<c0063e70>] (process_one_work+0x134/0x4ac)
[ 2029.847442] [<c0063d3c>] (process_one_work+0x0/0x4ac) from [<c0064374>] (worker_thread+0x18c/0x3d8)
[ 2029.857757] [<c00641e8>] (worker_thread+0x0/0x3d8) from [<c0068df8>] (kthread+0x90/0x9c)
[ 2029.866790] [<c0068d68>] (kthread+0x0/0x9c) from [<c004c9f4>] (do_exit+0x0/0x81c)
[ 2029.875366] r6:c004c9f4 r5:c0068d68 r4:d699dec4

工作队列在启用 IRQ 的进程上下文中 运行。所以你应该在工作队列处理程序中做enable_irq(),除非你之前禁用了这个IRQ。

但是你也不应该得到那个错误。可能 mmxx->irq 号码错误或未请求。注意回溯中的这一行:

(__irq_put_desc_unlock) from (enable_irq)

它发生在 enable_irq() 函数中:

void enable_irq(unsigned int irq)
{
    unsigned long flags;
    struct irq_desc *desc = irq_get_desc_buslock(irq, &flags,
                                                 IRQ_GET_DESC_CHECK_GLOBAL);

    if (!desc)
        return;
    if (WARN(!desc->irq_data.chip,
             KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq))
        goto out;

    __enable_irq(desc, irq);

out:
    irq_put_desc_busunlock(desc, flags);
}

其中 irq_put_desc_busunlock() 基本上是 __irq_put_desc_unlock()。 现在你可以看到这条链被执行的唯一方式是当你的 desc->irq_data.chipNULL 时。您还应该在回溯中观察这样的输出:

"enable_irq before setup/request_irq: irq %u\n"

从这里我会说你传递给 enable_irq()mmxx->irq 号码是错误的(0?)或者之前没有请求这个 IRQ。尝试检查 mmxx->irq 中的确切值,并确保在第一次调用工作队列处理程序之前已请求它。

无论如何,从您的代码中删除 enable_irq() 行应该可以解决问题(因为您可能真的不需要这样做)。