Search code examples
linux-kernelinterruptioctl

Handling interrupt in character device


I am trying to correctly register interrupt in kernel for user interface.

Surprisingly, I did not find many examples in kernel for that.

irq handler



    static irqreturn_t irq_handler(int irq, void *dev_id)
    {
       struct el_irq_dev *el_irq = &el_irq_devices[0];
        printk("irq in\n");
    
        spin_lock(&el->my_lock,flags);

        clear_interrupt() 

        some_buffer[buf_wr] = ch;
        el_irq->buf_wr++;
        if (el_irqbuf_wr >= 16)
            el_irqbuf_wr = 0;


         spin_unlock(&el->my_lock,flags);
         wake_up_interruptible(&el->pollw);



    return IRQ_HANDLED;
}

ioctl for waiting on interrupts

    static long el_device_ioctl( struct file *filp, 
             unsigned int ioctl_num, 
             unsigned long ioctl_param)
    {
        struct el_irq_dev *el_irq = &el_irq_devices[0];
    switch (ioctl_num) {
    case IOCTL_WAIT_IRQ:      // <<<---- using ioctl (no poll) to wait on interrupt
        wait_event_interruptible(el_irq->pollw, &el_irq->buf_wr != &el_irq->buf_rd) ;
        spin_lock(&el_irq->my_lock);
        if (el_irq->buf_wr != &el_irq->buf_rd)
        {
            my_value=some_buffer[el_irq->buf_rd];
            el_irq->buf_rd++;
            if (el_irq->buf_rd >= 16)
                el_irq->buf_rd = 0;
        }
         
        spin_unlock(&el_irq->my_lock);
        copy_to_user(ioctl_param,&my_value,sizeof(my_value));

    default:
            break;
        }
        return 0;
    }

My question is:

  1. Should we put the clear of interrupts (clear_interrupt() ) in fpga in the interrupt before or after the wake_up ? Can we event put the clearing interrupt in the userspace handler (IOCTL_WAIT_IRQ) instead of clearing the interrupt in the interrupt handler ?
  2. As you can see in the code, I am using cyclic buffer in order to handle cases where the userspace handler is missing interrupts. Is that really required or can we assume that there are no misses ? In other words, Is it reasnoble to assume that there should never be missed interrupts ? so that the ioctl call should never see more than 1 waiting interrupt ? If yes - maybe I don't need buffer mechanism between the interrupt handler and the ioctl handler.

Thank you, Ran


Solution

  • Short answer.

    1. It seems reasonable to me to clear interrupts in the user-space handler. It makes some sense to do it as late as possible, after all work has been done, as long as you check again after clearing that there is really no work left to do (some more work might have arrived just before clearing).
    2. The user-space handler might indeed miss interrupts, e.g. if several arrive between calls to IOCTL_WAIT_IRQ. Interrupts might also get "missed" in some sense though if several pieces of work arrive before interrupts are cleared. The stack (hardware and software) should be designed so that this is not a problem. An interrupt should just signal that there is work to be done, and the user-space handler should be able to just do all outstanding work before returning.
    3. You should probably be using spin_lock_irqsave() in your IOCtl code[1].

    [1] http://www.makelinux.net/ldd3/chp-5-sect-5