Linux – IRQ handler: There is a problem with Flags mismatch irq

IRQ handler: There is a problem with Flags mismatch irq… here is a solution to the problem.

IRQ handler: There is a problem with Flags mismatch irq

I’m implementing an interrupt handling module using threaded IRQ.
I’m facing this error :

1983.150961] Shut down eMMC app module init.
[ 1983.151115] genirq: Flags mismatch irq 49. 00000004 (eMMC_power_shutdown_irq_
handler) vs. 00000004 (xuartps)
fio@uz3cg-dgw:~$ (edited) 

The flag I chose is #define IRQF_TRIGGER_HIGH 0x00000004 and assigned to IRQ number 49 in this case.

Here is my code :

static int __init shutdownemmc_module_init(void)
{
    printk("Shut down eMMC app module init. ");
    if (request_threaded_irq( IRQ_NO,                       //IRQ number
                            (void *) emmc_irq_handler,      //IRQ handler (Top half)
                            emmc_interrupt_thread_fn,       //IRQ Thread handler (Bottom half). When the handler function returns IRQ_WAKE_THREAD
                            IRQF_TRIGGER_HIGH,                    //Handler will be called in raising edge
                            "eMMC_power_shutdown_irq_handler",    //used to identify the device name using this IRQ
                            (void *) (emmc_irq_handler)))    device id for shared IRQ
    {
        pr_err("Cannot register IRQ ");
        pr_err(" EIO %d , EINVAL %d\n", EIO, EINVAL);
        return 0;
    }
    pr_info("Interrupt handler... Done!!! \n");
    return 0;
}

Can someone explain what the flag mismatch irq issue is and how can I fix it?
Thank you
Ann

Solution

Because “xuartps” has requested the IRQ number, no sharing has been requested.

Excerpt from __setup_irq():in “kernel/irq/manage.c”

        /*
         * If nobody did set the configuration before, inherit
         * the one provided by the requester.
         */
        if (irqd_trigger_type_was_set(&desc->irq_data)) {
            oldtype = irqd_get_trigger_type(&desc->irq_data);
        } else {
            oldtype = new->flags & IRQF_TRIGGER_MASK;
            irqd_set_trigger_type(&desc->irq_data, oldtype);
        }

if (!( (old->flags & new->flags) & IRQF_SHARED) ||
            (oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||
            ((old->flags ^ new->flags) & IRQF_ONESHOT))
            goto mismatch;

In the above, old is an existing handler set by “xuartps”. new is a new handler set by your code. In order to share an IRQ, one of the above conditions is that both the old and new handlers need to request the IRQ using the IRQF_SHARED flag. However, if the underlying interrupt should be shareable, the driver should only set the IRQF_SHARED; For example, if all PCI interrupts are shareable, the driver for the PCI device should request an interrupt with IRQF_SHARED set.

mismatch:
    if (!( new->flags & IRQF_PROBE_SHARED)) {
        pr_err("Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n",
               irq, new->flags, new->name, old->flags, old->name);
#ifdef CONFIG_DEBUG_SHIRQ
        dump_stack();
#endif
    }
    ret = -EBUSY;

Above is where the “Flags mismatch” message is printed to the kernel log.

If you do not want the IRQ to have already been requested, check that you are requesting the correct IRQ.

Related Problems and Solutions