Re: A question concerning time outs and possible lost interrupts

MOLNAR Ingo (mingo@chiara.csoma.elte.hu)
Mon, 14 Sep 1998 03:02:08 +0200 (CEST)


On Sun, 13 Sep 1998, Linus Torvalds wrote:

> Does anybody on the kernel list know how the BIOS makes its decisions
> about how to mark interrupts edge vs level-triggered? It would be
> informative to know, because maybe we should override it (but without
> knowing what the BIOS does I feel very nervous indeed about overriding
> it).

my understanding is this: the 'raw' PCI irq lines coming out of PCI cards
directly are called PIRQ0-3. These are both connected to the 'PCI IRQ
steering circuit' and optionally, to the IO-APIC's higher pins.

if it's connected to the IO-APIC, then it's OK, i have not seen any
mptable that gets this case wrong. The case we are worried about is when
the 'raw' PCI IRQ lines are not connected to the IO-APIC. This usually
happens if some cheaper IO-APIC part is used, which has only 16 incoming
lines, or if someone has set the wrong BIOS switch. (eg. my BX board BIOS
has a flag that says 'no IOAPIC', which might be useful for some older
SMP-capable OSs. The flag is misleading because there _is_ an IOAPIC, it's
just not being fed with PCI lines directly)

so, if the raw PCI line is only connected to the 'steering logic', then
the issue is more delicate. This is a PCI chipset specific thing,
unfortunately. Usually, a 'good' BIOS does something like this:

Type Polarity Trigger Bus ID IRQ APIC ID pin

INT active-hi edge 4 1 8 1
INT active-hi edge 4 0 8 2
INT active-hi edge 4 3 8 3
INT active-hi edge 4 4 8 4
INT active-hi level 4 5 8 5
INT active-hi edge 4 6 8 6
INT active-hi edge 4 7 8 7
INT active-hi edge 4 8 8 8
INT active-hi level 4 9 8 9
INT active-hi level 4 10 8 10

eg. IRQ 5, 9 and 10 are PCI devices, 'embedded' into ISA IRQ space.

'bad' BIOSes mark such PCI IRQ lines as 'edge'. PCI cards are inherently
level triggered, the output of the 'steering logic' is _always_ low-active
and level-triggered.

the reason i think why some 'bad' BIOSes mark all IRQs as 'edge' is that
this way it's possible to share a PCI and an ISA device. The ISA device's
signal is fed to whatever IRQ line it corresponds to, and the PIRQ line is
routed according to a PCI-chipset specific routing table. (4 entry one)
This way someone with a soundcard and an (inactive) VGA card on IRQ9 can
still play games.

[to make things even more complex, the 'old' PC interrupt controller seems
to be extended in newer PCI chipsets as well, it has an 'Edge/Level
Control Register'. (the old PIC could be set edge/level too, but only as a
global setting. The ELCR is per-IRQ line). But the ELCR has no function if
the IRQ signals are fed to the IO-APIC. It's just there to add to the
confusion ;)]

so, according to my reading, it's safe to set _all_ PCI device interrupts
to level-triggered in the IO-APIC. Since edges are only detected on a
rising signal, the IO-APIC detected level triggered interrupts even when
it has it's sense logic set to edge-trigggered, due to a wrong mptable.

this would also explain why interrupts are lost. (instead of getting two
edges, it might be possible to get only one, like you described)

Since the mptable itself does not necessarily tell wether a given IRQ line
is in fact a PCI one, there is no immediate (mp-table based) workaround.
There are several other options to more or less safely detect this:

- we can read the PIRQ routing table. Pros: it's easy to do. Cons: this
is PCI chipset dependent. (although it seems to be a very standard
register even present in the Neptune chipset, but still, i dont know
wether this can be considered an 'architectural feature'.) Also, an
inactive but PIRQ-routed PCI device (say a PCI video card sitting on
IRQ9) shuts up an IRQ line that might be perfectly usable for an ISA
device.

- if a PCI driver sets up an IRQ line, we can switch it to
level-triggered. Pros: it's only done for active devices, so one can
reuse even an allocated PIRQ-routed IRQ line for an ISA device, and
also this only depends on the PCI configuration space, which is
architectural. Cons: this does not cover the detection phase.

it would be nice to first try your suggested quick io_apic.c hack, i'd do
something like this:

io_apic.c, line 570:

if (!IO_APIC_IRQ(irq))
continue;

+ if (irq == 12) {
+ entry.trigger = 1;
+ entry.polarity = 1;
+ }
entry.vector = assign_irq_vector(irq);

(if the NCR is on IRQ12) If this really fixes the bug, then we can further
see how to work around this mess ...

-- mingo

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/faq.html