0

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

ransh
  • 1,589
  • 4
  • 30
  • 56

1 Answers1

1

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

michaeljt
  • 1,106
  • 8
  • 17
  • Thanks for the detailed answer. Is it reasnable to assume that there should never be missed interrupts ? i.e. the ioctl should never see more than 1 waiting interrupt ? If yes - maybe I don't need buffer mechanism between the interrupt handler and the ioctl – ransh Jan 20 '17 at 08:55
  • Not quite sure what you mean by "missed interrupts" here. The simplest thing is to make the IOCtl handler (don't worry about my capitals, there are several variants) return as soon as there has been at least one interrupt since the last clear_interrupts(). But the user-space handler should assume that there may have been several interrupts since the last time it the IOCtl returned, and there should be a way for the user-space handler to find out about all work which those interrupts were reporting. – michaeljt Jan 20 '17 at 09:17
  • so I assume that the buffer mechanism which I used in this example(some_buffer), is quite essential. – ransh Jan 20 '17 at 09:22
  • If that is the only way of providing user-space with all the work then yes. In your code, you assign "ch" to the current buffer slot, but I can't see where you get "ch" from or exactly what it is (I presume you just left it out of the sketch code). A lot of hardware would implement a buffer like some_buffer internally that the final handler (in this case the user-space one) could read directly. In that case some_buffer would not be needed. If this hardware does not do that then you should really make sure that you clear interrupts as fast as possible to avoid missing work. Did that help? – michaeljt Jan 20 '17 at 09:39
  • yes, it helped a lot ! I also marked this as a solution. I also now start to think that I really don't need this buffer, because HW takes cares to that. as long as I don't clear interrupt in fpga, I expect that the fpga buffer will not get filled more than expected. So there shouldn't be any real problem probably - if - the userspace handler (which waits on the ioctl) is fast enough to copy the buffer and clear the interrupt, Right ? – ransh Jan 20 '17 at 15:14
  • I would expect the internal FPGA buffer to fill up at the same speed whether or not you clear interrupts. If your interrupt handling code, whether kernel or user-space, can not read the data faster than it arrives there will probably be a buffer overflow (not the C language type) and data lost. That just happens when data arrives faster than you can handle it. But if you are reading it character by character then I assume it is not arriving that fast. I also assume that the data will remain in the FPGA buffer until your handler reads it, regardless of how many interrupts happened. – michaeljt Jan 20 '17 at 15:21