The reason it doesn't work is that the interrupt controllers are set up
to be edge-sensitive, and the controller won't notice a new interrupt
even if it has been acknowledged if the irq line doesn't go down in
between the ack and the new interrupt.
So with two serial cards sharing the same interrupt:
- card 2 asserts irq. Controller reacts, tells the CPU about it
- CPU acks the interrupt, masks the irq, and starts the interrupt.
- card 1 hasn't posted anything, so the interrupt routine skips it and
goes on to handle card 2 (correctly).
- card 1 asserts irq just before the interrupt routine reads the status
from card 2. irq line stays asserted.
- irq handler reads status from card 2, de-asserting card 2's irq.
- the interrupt controller never notices the pending interrupt, as the
irq line never went down.
- if the shared interrupt handler now doesn't go back to check card 1,
we'll never get any more interrupts on that irq because the irq
controller has decided that although the irq line is asserted, it
won't react to it.
Anyway, it's easy enough to program the irq controller to do
level-triggered interrupts, but the problem with this is that some of
the hardware doesn't like that. Notably, the timer irq is often
connected to a square wave generator, so if we have level-triggered
interrupts, we will get timer interrupts 50% of the time rather than
just once per timer tick.
On EISA and PCI machines, you can program the controller to do
level/egde triggering on a per-irq basis, so you can program those
interrupts that you expect to share as level-triggered, and program the
timer irq to be edge-triggered.
Linus