Configuring an IOAPIC for Serial Port interrupts [solved]

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Configuring an IOAPIC for Serial Port interrupts [solved]

Post 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.
Last edited by gerryg400 on Sat Jun 25, 2011 5:22 pm, edited 1 time in total.
If a trainstation is where trains stop, what is a workstation ?
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: Configuring an IOAPIC for Serial Port interrupts

Post 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?
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
kabure
Posts: 12
Joined: Tue Jul 20, 2010 9:43 pm

Re: Configuring an IOAPIC for Serial Port interrupts

Post 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.
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: Configuring an IOAPIC for Serial Port interrupts

Post 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.
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
kabure
Posts: 12
Joined: Tue Jul 20, 2010 9:43 pm

Re: Configuring an IOAPIC for Serial Port interrupts

Post 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.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Configuring an IOAPIC for Serial Port interrupts

Post 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: Configuring an IOAPIC for Serial Port interrupts

Post 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?
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Configuring an IOAPIC for Serial Port interrupts

Post 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
kabure
Posts: 12
Joined: Tue Jul 20, 2010 9:43 pm

Re: Configuring an IOAPIC for Serial Port interrupts

Post 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.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Configuring an IOAPIC for Serial Port interrupts [solved

Post 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.
If a trainstation is where trains stop, what is a workstation ?
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Configuring an IOAPIC for Serial Port interrupts [solved

Post 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.
If a trainstation is where trains stop, what is a workstation ?
Post Reply