The HyperNews Linux KHG Discussion Pages

## Interrupt sharing 101

  Forum: Device Drivers
  Re: Interrupt Sharing ? (Frieder Löffler)
  Re: Interrupt sharing - How to do with Network Drivers? (Frieder Löffler)
  Keywords: Interrupt sharing, PCI, Plug%0Aamp;Play
  Date: Wed, 28 Aug 1996 16:48:01 GMT
  From: Christophe Beauregard <chrisb@truespectra.com>

I guess this would be a handy thing to have in the knowledge base... The key thing to sharing an interrupt is to make sure that you have separate context information for each instance of the driver. That is, no static global variables. For most network drivers you just use the ``struct device* dev'' for the context. Pass this to request_irq() as the last argument:
    request_irq( irq, interrupt_handler, SA_SHIRQ, "MyDevice",
                 dev );
Note that the SA_INTERRUPT flag is significant here, since you can't share an IRQ if one driver uses fast interrupts and the other uses slow interrupts. This is a bug, IMHO, since long chains of interrupt handlers may alter the timing such that processing is no longer ``fast''. A better behaviour would be to just implicitly change to slow interrupts when more than one device is on the IRQ (and change back when the device is released down to one fast handler, of course). Then your interrupt handler looks something like this:
    static void interrupt_handler( int irq, void* dev_id, ...) {
        struct device* dev = (struct device*) dev_id;
        if( dev == NULL ) {
            ASSERT( 0 ); /* stupid programmer error.  Either
                         we passed a NULL dev to request_irq
                         or someone screwed up irq.c */
        }
        /* query the device to see if it caused the interrupt */
        if( !(inb(something)&something_else) ) {
            /* nope, not us - normally we'd call this a spurious
            interrupt, but it might belong to another device. */
            return;
        }
        /* now, using the dev structure, service the interrupt */
        ...
        /* tell the hardware device we're done (IMPORTANT)
        If this isn't done, the device will continue to hold
        the IRQ line high, and we go into a nasty interrupt
        loop.  Some devices might do this implicitly in the
        interrupt processing (i.e. by emptying a buffer) */
        outb(something, something);
    }
Because you have a separate ``struct device*'' for each instance of the card, multiple cards can share the same IRQ. Of course, they can also share the IRQ with other card, assuming they all Do The Right Thing. You can usually modify an existing device to do shared IRQs by simply finding the part of the code where it spews out a spurious interrupt message and replacing that with a `return' statement, adding SA_SHIRQ to the request_irq call, and removing references to irq2dev_map[]. I've had no problems doing this for drivers including drivers/char/psaux.c, drivers/net/tulip.c, drivers/scsi/aicxxx7.c and most of the MCA drivers. c.