Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use request_threaded_irq so that the interrupt handler is called while the threaded handler works?

I am trying to write a simple interrupt handler for a GPIO in the linux kernel. I use request_threaded_irq to get an interrupt context handler, and a threaded handler.

My problem is that the work done by the threaded handler has a big impact on the timing of the calls to the interrupt handler.

The code to setup the interrupt is:

gpio_request(93, "test")
gpio_direction_input(93);
gpio_request(33, "mirror");
gpio_direction_output(33, 1);

request_threaded_irq(gpio_to_irq(93),
        interrupt_handler,
        threaded_interrupt_handler,
        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_TIMER,
        "test", NULL);

Here, I am simply requesting gpio 93 to fire an interrupt on rising and falling edges. I also request gpio 33 to use as a mirror, see below.

(In my setup, I put a clock source on gpio 93).

The code of the interrupt handler is this:

static irqreturn_t interrupt_handler(int irq, void *data)
{
    int state = gpio_get_value(93);
    gpio_set_value(33, state);
    return IRQ_WAKE_THREAD;
}

Here, the interrupt handler is simply mirroring gpio 93 input value as an output value for gpio 33. This allows me to monitor the effective rate of the calls to interrupt_handler.

Lastly, the threaded handler:

static irqreturn_t threaded_interrupt_handler(int irq, void *data)
{
    /* doing msleep here is apparently problematic... */
    msleep(1);
    return IRQ_HANDLED;
}

In the threaded interrupt handler, calling msleep (or actually performing work) is problematic: by looking with a scope at the gpio output 33, I can see that the interrupt_handler callback rate changes drastically when the threaded_interrupt_handler sleeps or perform too much work.

How can I setup/use request_threaded_irq() so that the interrupt handler is always called "on-time" even if the threaded handler as some big work to do?

like image 220
Gilles Gregoire Avatar asked Nov 21 '14 16:11

Gilles Gregoire


1 Answers

I eventually understand what was happening. According to this answer on SO, the interrupt is masked while processing the interrupt and the threaded interrupt handler.

So it seems I misunderstood the point of request_threaded_irq: it should really be used so that the interrupt handling is in a task scheduled by the scheduler.

For my needs, what I really wanted was simply a wait_queue. I remove the threaded interrupt handler for my code and changed the interrupt handler to something like:

static wait_queue_head_t wq;

static irqreturn_t interrupt_handler(int irq, void *data)
{
    int state = gpio_get_value(93);
    gpio_set_value(33, state);
    wake_up_interruptible(&wq);
    return IRQ_HANDLED;
}

Now, the interrupt handler is called with a correct timing!

like image 60
Gilles Gregoire Avatar answered Nov 15 '22 09:11

Gilles Gregoire