Online Linux Driver Verification Service (alpha)

0037

RULE_ERROR

Making no delay when probing for IRQs

Summary

You should wait for some time between probe_irq_on()/probe_irq_off(...) calls.

Description

A driver sometimes needs to look up the IRQ that is acquired by the controlled device. However, PC-compatible machines make its identification non-trivial, since the number of an interrupt line depends on physical location of the device (on an index of the slot it occupies).

Performing such calculations is the purpose of Kernel IRQ probing mechanism, which is implemented by probe_irq_on()/probe_irq_off(...) functions. They should be used as follows:

  1. probe_irq_on() activates all non-occupied (which handler is NULL) interruptions, and the list of these interruptions is returned as a bitmap.

  2. Driver tells the device (using input-output ports) that he's about to activate an interrupt line.

  3. Delay is required, because it's necessary to wait for the reaction of the device to the request through input-output ports.

    If an activation of IRQ line, hadnler of which is NULL, is detected then the IRQ is deactivated at the OS level.

  4. probe_irq_off(...) function compares the list of the previously activated interruptions (returned by the recent probe_irq_on()) with the system list, in which one of the interruptions is deactivated (see 3). This function basically detects which IRQs have been deactivated, and thus which ones have received interrupts.

  5. Deactivated interruption is used by the controlled device.

Without a delay (p. 3) making additional iterations (one or more) of a loop usually used for detecting interrupt lines may be required, because the device will not have enough time to process an interrupt query, or the interrupt controller will not send information to the processor input on time. It's more convenient to make the delay by calling udelay(delay) function.

Therefore, you should wait for some time between probe_irq_on()/probe_irq_off(...) calls. There are two ways to do it:

  1. Call udelay(...). This is the most common way to make a delay.

  2. Use more powerful waiting procedure (e.g. put to the waiting queue and transmit the control to the planner).

Example

Sample correct usage:

int count = 0;
do {
    unsigned long mask;
    mask = probe_irq_on( );
    outb_p(0x10,short_base+2); /* interrupt queue to the device */
    outb_p(0x00,short_base);      
    outb_p(0xFF,short_base);      
    outb_p(0x00,short_base+2); 
    udelay(5); 
    short_irq = probe_irq_off(mask);
    if (short_irq = = 0) { 
        printk(KERN_INFO "short: no irq reported by probe\n");
        short_irq = -1;
    }
} while (short_irq < 0 && count++ < 5);
        if (short_irq < 0)
            printk("short: probe failed %i times, giving up\n", count);
        /* an interrupt line used by the controlling device is detected  */