disable_irq/enable_irq使用不匹配

2022-05-08 16:44:57 浏览数 (1)

最近在一次稳定性测试中,发现Kernel Log中出现了如下的Warring,如下:

代码语言:javascript复制
WARNING: CPU: 4 PID: 2956 at /space/builder/repo/sprdroid6.0_trunk_k318_dev/kernel/kernel/irq/manage.c:444 __enable_irq 0x50/0x94()
Unbalanced enable for IRQ 227

Call trace:
c4 [<ffffffc00008b480>] dump_backtrace 0x0/0x164
c4 [<ffffffc00008b600>] show_stack 0x1c/0x28
c4 [<ffffffc0009ceefc>] dump_stack 0x74/0xb8
c4 [<ffffffc0000bb340>] warn_slowpath_common 0x98/0xc0
c4 [<ffffffc0000bb3dc>] warn_slowpath_fmt 0x74/0x88
c4 [<ffffffc00010eb50>] __enable_irq 0x4c/0x94
c4 [<ffffffc00010ebd8>] enable_irq 0x40/0x80
c4 [<ffffffc000630a38>] spidev_ioctl 0x6e4/0xbc0
c4 [<ffffffc0002016f0>] do_vfs_ioctl 0x374/0x5b8
c4 [<ffffffc0002019c0>] SyS_ioctl 0x8c/0xa4
c4 ---[ end trace 3e8cbdaab32a5c30 ]---

根据Kernel log的提示,在内核源码中找到出错的地方:

代码语言:javascript复制
<kernel/irq/manage.c>
--------------------------------------------------------
void __enable_irq(struct irq_desc *desc, unsigned int irq)
{
    switch (desc->depth) {
    case 0:
 err_out:
        WARN(1, KERN_WARNING "Unbalanced enable for IRQ %dn", irq);
        break;
    case 1: {
        if (desc->istate & IRQS_SUSPENDED)
            goto err_out;
        /* Prevent probing on this irq: */
        irq_settings_set_noprobe(desc);
        irq_enable(desc);
        check_irq_resend(desc, irq);
        /* fall-through */
    }
    default:
        desc->depth--;
    }
}

可以看到当desc->depth等于0的时候,就会出现上述的log。

而出现此问题的原因是什么? 或者是谁导致出现了这种情况?

通过栈调用关系可以看出,应用程序通过ioctl命令去操作底层的指纹识别的过程出现的。 SyS_ioct->do_vfs_ioctl->spidev_ioctl->enable_irq->__enable_irq

从调用关系看,最后调用__enable_irq的时候desc->depth=0,出现了“Unbalanced enable for IRQ”, 而根据字面意思是“使能不匹配的IRQ”。

根据提示猜想,是不是enable_irq需要与disable_irq成对的匹配调用。

基于此猜想,可以通过disable_irq与enable_irq的源代码验证猜想。

先看disable_irq的代码:

代码语言:javascript复制
<kernel/irq/manage.c>
---------------------------------------------------------------------
void __disable_irq(struct irq_desc *desc, unsigned int irq)
{
    if (!desc->depth  )
        irq_disable(desc);
}

从代码可以看出disable_irq的时候,对desc->depth做 操作。

代码语言:javascript复制
<kernel/irq/manage.c>
---------------------------------------------------------------------
void __enable_irq(struct irq_desc *desc, unsigned int irq)
{
    switch (desc->depth) {
    case 0:
 err_out:
        WARN(1, KERN_WARNING "Unbalanced enable for IRQ %dn", irq);
        break;
    case 1: {
        if (desc->istate & IRQS_SUSPENDED)
            goto err_out;
        /* Prevent probing on this irq: */
        irq_settings_set_noprobe(desc);
        irq_enable(desc);
        check_irq_resend(desc, irq);
        /* fall-through */
    }
    default:
        desc->depth--;
    }
}

而__enable_irq代码是对desc->depth做–操作了。

根据一个做 操作,一个做–操作。可以得出disable_irq与enable_irq需要成对的使用。

而出现上述的原因就是在没有调用disable_irq的前提下,直接调用enable_irq,那时候desc->depth等于0,这时候enable_irq就会出现Warring, 也就是说这次的enable_irq没有起作用的。

假设驱动中先disable_irq,这时候desc->depth 了, desc->depth就等于1, 而这时候再次enable_irq就会走进case 1的分支中去。 然后desc->depth–了,最后desc->depth等于0

所以根据分析,出现上述的原因就是enable_irq与disable_irq在驱动中没有匹配使用导致的。

0 人点赞