2
votes

I was working on a project where I was doing some action based on the keyboard interrupt received. So I registered for the keyboard interrupt and mark the interrupt as shared. But my program wasnt working as it should. To debug the issue, I wrote a small program that just registers for the keyboard interrupt and outputs some message to kernel when interrupt from keyboard is received. But I found out a lot of interrupts from keyboard are missed when interrupt rate is high. For example, in the sample code below, I register for the interrupt and output message to kernel when 'a' is pressed. From the counter value, the total number of interrupts are less than the actual number of interrupts geenrated by keyboard. I found this out by echoing the keypress to a terminal and counting the number of a's echoed to the terminal. So for example if there are 350 echoed a's on the terminal, the count will only be around 300-320. Same goes for higher number of interrupts. The larger the number of interrupts, the more interrupts are missed but the percentage of interrupts missed seems to be nearly equal in all cases. Can someone please explain what is the reason for this behaviour? Thanks in advance. Below is source code.

#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <asm/io.h>

/*
 The keyboard ISR
*/
irq_handler_t irq_handler (int irq, void *dev_id, struct pt_regs *regs)    
{
    static int count = 0;
static unsigned char scancode;

scancode = inb (0x60);

if (0x1E == scancode)
{
            count++;
    printk ("\nKeyboard key 'a' pressed !");
}

return (irq_handler_t) IRQ_HANDLED;
}

/*
 Register IRQ handler
*/
int init_module ()
{
return request_irq (1, (irq_handler_t) irq_handler, IRQF_SHARED, "kbd_irq_handler", (void *)(irq_handler));
}


MODULE_LICENSE ("GPL");
3
Maybe using printk in an interrupt handler is not such a good idea ...too honest for this site

3 Answers

1
votes

Can you try using workqueues as bottom half because if irq handler[Top] is taking time to complete in that case interrupts can be missed.

Its better to use workqueue for doing non time critical processing.

You code should be like

    static unsigned char scancode;
    irq_handler_t irq_handler (int irq, void *dev_id, struct pt_regs *regs)    
    {

       scancode = inb (0x60);

       schedule_delayed_work(work_struct);//in this function pointer is passed
       return (irq_handler_t) IRQ_HANDLED;
    }

    func()
    {
       if (0x1E == scancode)
       {
              count++;
              printk ("\nKeyboard key 'a' pressed !");
       }
    }

Also you can check the keyboard controller data sheet for minimum time interval between interrupts from hardware perspective and then check the interrupt execution time to see interrupt handler execution time should be less than than hw interrupt generation time.

Or you can also maintain event buffer after considering timing,system load.

0
votes

From here:

The logging code already tries to mitigate this problem by detecting and suppressing streams of identical messages.

Using printk for stream of identical messages - bad idea.

0
votes

I've seen exactly this problem in a different driver that missed interrupts. My driver is using a fast IRQ handler that just dispatches jobs to a bottom-half work-queue.

What I found is that when the IRQ handler is executing, the kernel may not register new interrupts for the same handler. I did not see a consistent behavior on this however. It was hit and miss.

I've debugged this by making the IRQ handler take a really long time (>= 10s) and issuing interrupts at one second interval. Out of 10 or more interrupts issued when the IRQ handler was executing, only 7 or 8 were registered.

My stop-gap solution was to add a watch-dog to the device firmware to reissue an interrupt if it sees not-serviced buffers on host but I'm looking for a better and deterministic solution.