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

时间:2015-04-09 12:05:48

标签: kernel driver linux-device-driver

从工作队列调用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

1 个答案:

答案 0 :(得分:1)

Workqueue在启用了IRQ的进程上下文中运行。所以你应该在workqueue处理程序中执行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"

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

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