Page 1 of 1

Configuring an IOAPIC for Serial Port interrupts [solved]

Posted: Fri Jun 24, 2011 12:51 am
by gerryg400
I use a serial port (in vmware) to output logging information while my O/S boots. I just noticed today that I had configured the IOAPIC to be in level-triggered mode for interrupt 4, (the ISA serial chip interrupt) so I corrected it to edge-triggered and I stoppped getting interrupts.

I did a bit of research and now I'm really unsure what the setting is supposed to be. ISA has edge-triggered interrupts but the 16550 INTR pin seems to be a wire-OR of the currently pending interrupts. That would make it level-triggered.

Does anyone know how this works ?

Btw, haven't tried any of this on real hardware. I'll do that tonight.

Re: Configuring an IOAPIC for Serial Port interrupts

Posted: Sat Jun 25, 2011 12:30 am
by Chandra
gerryg400 wrote:I use a serial port (in vmware) to output logging information while my O/S boots. I just noticed today that I had configured the IOAPIC to be in level-triggered mode for interrupt 4, (the ISA serial chip interrupt) so I corrected it to edge-triggered and I stoppped getting interrupts.
Hey, that seems a good news for me. Is it possible to change a specific IRQ to level triggered with the PIC? I don't use IOAPIC and I need level triggered IRQs with PIC. I know how to program the controller to generate level triggered IRQs but the bottomline is that all the IRQs generated from that controller turn out to be level triggerred.Any ideas?

Re: Configuring an IOAPIC for Serial Port interrupts

Posted: Sat Jun 25, 2011 1:10 am
by kabure
Chandra wrote:Is it possible to change a specific IRQ to level triggered with the PIC?
There is, kinda, but it's chipset-specific. I'm looking at the Intel ICH10 spec, and there are two extra registers, ELCR1 and ELCR2, which allow most interrupts to be individually set to either edge- or level-triggered mode using just the PIC. I don't know if non-Intel chipsets have anything related, and it's certainly not going to be a portable method.

Re: Configuring an IOAPIC for Serial Port interrupts

Posted: Sat Jun 25, 2011 1:25 am
by Chandra
kabure wrote:
Chandra wrote:Is it possible to change a specific IRQ to level triggered with the PIC?
There is, kinda, but it's chipset-specific. I'm looking at the Intel ICH10 spec, and there are two extra registers, ELCR1 and ELCR2, which allow most interrupts to be individually set to either edge- or level-triggered mode using just the PIC. I don't know if non-Intel chipsets have anything related, and it's certainly not going to be a portable method.
That was exactly what I was looking for. Could you please link to the specification? I'm currently using all the slave IRQs as level triggered because I need to share an IRQ from the slave controller. That specification might come handy.

And yes, everything is specific to Intel Chipsets, if matters.

Re: Configuring an IOAPIC for Serial Port interrupts

Posted: Sat Jun 25, 2011 5:34 am
by kabure
Chandra wrote:That was exactly what I was looking for. Could you please link to the specification? I'm currently using all the slave IRQs as level triggered because I need to share an IRQ from the slave controller. That specification might come handy.

And yes, everything is specific to Intel Chipsets, if matters.
Well, here's the ICH10 spec. These registers should be in any Intel chipset you look at--just google "Intel <chipset here, particularly the I/O controller hub or whichever chip handles all the devices>". Just look under the 8259 interrupt controller section under the LPC bridge registers section.

Re: Configuring an IOAPIC for Serial Port interrupts

Posted: Sat Jun 25, 2011 7:41 am
by Brendan
Hi,
gerryg400 wrote:I use a serial port (in vmware) to output logging information while my O/S boots. I just noticed today that I had configured the IOAPIC to be in level-triggered mode for interrupt 4, (the ISA serial chip interrupt) so I corrected it to edge-triggered and I stoppped getting interrupts.
That should work as long as you get the polarity right - e.g. "edge triggered, active high" (or triggered on the rising edge) and not "edge triggered, active low" (or triggered on the falling edge).
gerryg400 wrote:I did a bit of research and now I'm really unsure what the setting is supposed to be. ISA has edge-triggered interrupts but the 16550 INTR pin seems to be a wire-OR of the currently pending interrupts. That would make it level-triggered.
Inside the 16550 the interrupt sources are ORed together. If there were no internal interrupts and one occurs, then this produces a rising edge on the 16550's INTR line, and the PIC detects the rising edge and sends an IRQ to the CPU. If there were internal interrupts and another one occurs, then this doesn't change the state of the 16550's INTR line, and the PIC doesn't waste it's time attempting to send a second/unnecessary IRQ to the CPU.

When the IRQ handler starts, it checks all of the interrupt sources in the 16550 and handles all of them in a loop until there are no interrupt sources left. When there's 2 16550's sharing the same interrupt line, then the IRQ handler has to check all of the interrupt sources in all 16550 chips in a loop (and be careful with race conditions - e.g. in case an interrupt occurs in one 16550 that you've already checked while you're handling an interrupt in the other).
kabure wrote:
Chandra wrote:Is it possible to change a specific IRQ to level triggered with the PIC?
There is, kinda, but it's chipset-specific. I'm looking at the Intel ICH10 spec, and there are two extra registers, ELCR1 and ELCR2, which allow most interrupts to be individually set to either edge- or level-triggered mode using just the PIC. I don't know if non-Intel chipsets have anything related, and it's certainly not going to be a portable method.
ELCR1 and ELCR2 are standard (since EISA?). All ISA IRQs should be configured as "edge triggered" and all PCI IRQs (and EISA IRQs?) should be configured as "level triggered". The firmware/BIOS should've already done this, and the only sane reason for an OS to touch ELCR1 and ELCR2 is if the OS has changed the way PCI IRQs are routed to the PIC chip/s.
Chandra wrote:I'm currently using all the slave IRQs as level triggered because I need to share an IRQ from the slave controller.
You're doing it wrong.

You need to tell the PICs (and IO APICs) what type of interrupt signal the hardware generates. Telling the PIC the wrong thing (e.g. that ISA IRQs are level triggered) doesn't magically cause hardware to be redesigned to conform to whatever you told the PIC.


Cheers,

Brendan

Re: Configuring an IOAPIC for Serial Port interrupts

Posted: Sat Jun 25, 2011 9:01 am
by Chandra
Brendan wrote:You need to tell the PICs (and IO APICs) what type of interrupt signal the hardware generates. Telling the PIC the wrong thing (e.g. that ISA IRQs are level triggered) doesn't magically cause hardware to be redesigned to conform to whatever you told the PIC.
Thanks alot. That's the most sensible thing to hear. If I understood you properly the PIC is to be programmed depending upon the IRQ generated by the devices, right? So, does that mean level triggered and edge triggered directly complies with the hardware device itself?

Re: Configuring an IOAPIC for Serial Port interrupts

Posted: Sat Jun 25, 2011 9:37 am
by Brendan
Hi,
Chandra wrote:
Brendan wrote:You need to tell the PICs (and IO APICs) what type of interrupt signal the hardware generates. Telling the PIC the wrong thing (e.g. that ISA IRQs are level triggered) doesn't magically cause hardware to be redesigned to conform to whatever you told the PIC.
Thanks alot. That's the most sensible thing to hear. If I understood you properly the PIC is to be programmed depending upon the IRQ generated by the devices, right? So, does that mean level triggered and edge triggered directly complies with the hardware device itself?
To be more correct, I should've said "You need to tell the PICs (and IO APICs) what type of interrupt signal is delivered to the PIC or APIC's inputs."

It's possible to have "glue logic" in-between the device and the PIC or APIC. For example, imagine a device that generates a "level triggered, active high" signal. Nothing says that this signal can't be used as the input to an inverter and the output of the inverter connected to the APIC, so that the APIC must be programmed as "level triggered, active low". In the same way glue logic can convert "edge triggered" into "level triggered" (e.g. a latch), or convert "level triggered" into "edge triggered".

The only thing you can really rely on is established conventions. The established conventions for PIC chips are "all IRQs appear as edge triggered active high at the PIC input", where the ELCRs are "glue logic" that make PCI interrupts look edge triggered when they originally weren't. Of course in modern systems (where the ELCRs and the PICs and any other glue logic is built into a single chip where corners can be cut) you can't even assume that is actually what is happening in reality - you can only assume that is how it behaves from software's perspective (regardless of what happens in reality).

The established conventions for IO APICs is "do what the MP spec tables and/or the ACPI spec tables tells you to". Chipset/motherboard designers can do whatever they like with any IRQ lines they want, as long as the MP spec tables and/or the ACPI spec tables correctly tell the OS how to configure the IO APIC/s to suit.


Cheers,

Brendan

Re: Configuring an IOAPIC for Serial Port interrupts

Posted: Sat Jun 25, 2011 3:13 pm
by kabure
Brendan wrote:ELCR1 and ELCR2 are standard (since EISA?). All ISA IRQs should be configured as "edge triggered" and all PCI IRQs (and EISA IRQs?) should be configured as "level triggered". The firmware/BIOS should've already done this, and the only sane reason for an OS to touch ELCR1 and ELCR2 is if the OS has changed the way PCI IRQs are routed to the PIC chip/s.
Ah, ok, thanks. I was wondering about those.

Re: Configuring an IOAPIC for Serial Port interrupts [solved

Posted: Sat Jun 25, 2011 5:43 pm
by gerryg400
Thanks for the help everyone. After Brendan confirmed that the IOAPIC should be programmed to edge-triggered/rising-edge I set the IOAPIC like that and went looking for the real bug. In the end it turned out to be the order that I was setting up the serial interrupts.
This...

Code: Select all

    /* Enable all intr types in the UART */
    outportb(IER, 0x0f);

    /* Create and install an interrupt object */
    serial_intr = intr_create(kserial_handler, NULL, 0);
    intr_install(serial_intr, 0x77);

    /* Enable the hardware for intr4 */
    ioapic_map_intr(0x77, 0, 0, 4);
    ioapic_unmask_intr(4);

    txing = 0;
should have been this...

Code: Select all

    /* Create and install an interrupt object */
    serial_intr = intr_create(kserial_handler, NULL, 0);
    intr_install(serial_intr, 0x77);

    /* Enable the hardware for intr4 */
    ioapic_map_intr(0x77, 0, 0, 4);
    ioapic_unmask_intr(4);

    /* Enable all intr types in the UART */
    outportb(IER, 0x0f);
    txing = 0;
It was quite stupid really. I just wasn't ready when the first edge-triggered interrupt came. I never noticed the bug before because I had the IOAPIC set to level-triggered ints.

Re: Configuring an IOAPIC for Serial Port interrupts [solved

Posted: Sun Jun 26, 2011 4:54 am
by gerryg400
Berkus, I do need to look at that flag. It's an ugly boolean that currently has 3 possible values. Not a problem today but must be fixed. Added to my TODO list.