gregoiregentil
gregoiregentil

Reputation: 1889

Linux kernel driver: IRQ triggered or timeout

In a linux kernel driver, I would like to repeat indefinitely the following sequence:

Therefore, by T + "around" 20ms, in worst case, the whole process needs to be started again.

Note that if the IRQ is physically triggered at 18ms, too bad, "I missed the train". I will catch another hardware trigger at the next sequence.

While testing, I was doing something along the following pseudo-code:

INIT_DELAYED_WORK(&priv->work, driver_work);
INIT_DELAYED_WORK(&priv->timeout, driver_timeout);
request_irq(priv->irq, driver_interrupt, IRQF_TRIGGER_RISING, "my_irq", priv);

then:

queue_delayed_work(priv->workq, &priv->work, 0ms);

static void driver_work(struct work_struct *work) {
    queue_delayed_work(priv->workq, &priv->timeout, 15ms);
    priv->interruptCalled = 0;
    enable_irq(priv->irq);
}

Then:

static irqreturn_t driver_interrupt(int irq, void *_priv) {
    disable_irq_nosync(priv->irq);
    priv->interruptCalled = 1;
    cancel_delayed_work(&priv->timeout);
    priv->stamp = cpu_clock(0);
    wake_up_interruptible(&driver_wait);
    queue_delayed_work(priv->workq, &priv->work, 5ms);
    return IRQ_HANDLED;

}

And:

static void driver_timeout(struct work_struct *work) {
    if (priv->interruptCalled == 0) {
        disable_irq_nosync(priv->irq);
        //Do other small cleanup
        queue_delayed_work(priv->workq, &priv->work, 5ms);
    }
}

I'm trying to write a robust but simple driver. Is this a proper implementation? How can I improve this implementation?

Upvotes: 3

Views: 2059

Answers (1)

gregoiregentil
gregoiregentil

Reputation: 1889

Answering my own question: the problem is that queue_delayed_work is based on jiffies. Or 5ms is not possible as HZ=100 (1 jiffy = 10ms). HR timer brought a good solution.

Upvotes: 1

Related Questions