Pregunta

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

  • at time T, a hardware IRQ is enabled
  • between time T and T + "around" 15ms, the IRQ callback can be reached if the IRQ is triggered. I say around because I'm not using an RT kernel and if it's 14 or 16ms, it's fine. In the IRQ callback, I need to write down get cpu_clock(0) and call wake_up_interruptible. The timeout needs to be killed. The whole process needs to be started again within 5ms.
  • if by T + "around" 15ms, the IRQ has not been triggered, I need to execute some other code. The IRQ should be disabled then. The whole process needs to be started again within 5ms.

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?

¿Fue útil?

Solución

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top