diff options
Diffstat (limited to 'i386/i386at')
-rw-r--r-- | i386/i386at/interrupt.S | 21 | ||||
-rw-r--r-- | i386/i386at/ioapic.c | 18 | ||||
-rw-r--r-- | i386/i386at/model_dep.c | 1 |
3 files changed, 34 insertions, 6 deletions
diff --git a/i386/i386at/interrupt.S b/i386/i386at/interrupt.S index 77424b43..164b0939 100644 --- a/i386/i386at/interrupt.S +++ b/i386/i386at/interrupt.S @@ -61,6 +61,11 @@ ENTRY(interrupt) je _call_local_ast #endif + movb EXT(irqinfo)(,%ecx,2),%al /* look up irq_info[irq].trigger */ + testb $1,%al /* was this a level triggered interrupt? */ + jnz _call_handler /* yes: handle before eoi */ + +_eoi: #ifndef APIC movl $1,%eax shll %cl,%eax /* get corresponding IRQ mask */ @@ -102,6 +107,12 @@ ENTRY(interrupt) call EXT(ioapic_irq_eoi) /* ioapic irq specific EOI */ #endif + movl S_IRQ,%ecx /* restore irq number */ + movb EXT(irqinfo)(,%ecx,2),%al /* look up irq_info[irq].trigger */ + testb $1,%al /* was this a level triggered interrupt? */ + jnz _completed /* yes: we are done */ + +_call_handler: movl S_IPL,%eax movl %eax,4(%esp) /* previous ipl as 2nd arg */ @@ -113,11 +124,15 @@ ENTRY(interrupt) movl S_IRQ,%eax /* copy irq number */ - shll $2,%eax /* irq * 4 */ - movl EXT(iunit)(%eax),%edx /* get device unit number */ + movl EXT(iunit)(,%eax,4),%edx /* get device unit number */ movl %edx,(%esp) /* unit number as 1st arg */ - call *EXT(ivect)(%eax) /* call interrupt handler */ + call *EXT(ivect)(,%eax,4) /* call interrupt handler */ + + movl S_IRQ,%ecx /* restore irq number */ + movb EXT(irqinfo)(,%ecx,2),%al /* look up irq_info[irq].trigger */ + testb $1,%al /* was this a level triggered interrupt? */ + jnz _eoi /* yes: eoi */ _completed: movl S_IPL,%eax /* restore previous ipl */ diff --git a/i386/i386at/ioapic.c b/i386/i386at/ioapic.c index d0724f76..e38e4d6b 100644 --- a/i386/i386at/ioapic.c +++ b/i386/i386at/ioapic.c @@ -128,6 +128,8 @@ interrupt_handler_fn ivect[NINTR] = { /* 63 */ intnull, }; +struct irqinfo irqinfo[NINTR]; + void picdisable(void) { @@ -293,6 +295,7 @@ ioapic_toggle(int pin, int mask) void ioapic_irq_eoi(int pin) { + /* FIXME: multiple ioapics (not always zero) */ int apic = 0; union ioapic_route_entry_union oldentry, entry; @@ -302,6 +305,7 @@ ioapic_irq_eoi(int pin) spl_t s = simple_lock_irq(&ioapic_lock); if (!has_irq_specific_eoi) { + // XXX Linux conditions on trigger mode: if (irqinfo[pin].trigger) { /* Workaround for old IOAPICs with no specific EOI */ /* Mask the pin and change to edge triggered */ @@ -313,11 +317,10 @@ ioapic_irq_eoi(int pin) /* Restore level entry */ ioapic_write_entry(apic, pin, oldentry.both); + //} } else { volatile ApicIoUnit *ioapic = apic_get_ioapic(apic)->ioapic; - - ioapic_read_entry(apic, pin, &entry.both); - ioapic->eoi.r = entry.both.vector; + ioapic->eoi.r = irqinfo[pin].vector; } simple_unlock_irq(s, &ioapic_lock); @@ -407,6 +410,9 @@ ioapic_configure(void) entry.both.vector = IOAPIC_INT_BASE + gsi; ioapic_write_entry(apic, pin, entry.both); + irqinfo[pin].vector = entry.both.vector; + irqinfo[pin].trigger = entry.both.trigger; + /* Set initial state to masked */ mask_irq(pin); @@ -441,6 +447,9 @@ ioapic_configure(void) entry.both.vector = IOAPIC_INT_BASE + gsi; ioapic_write_entry(apic, pin, entry.both); + irqinfo[pin].vector = entry.both.vector; + irqinfo[pin].trigger = entry.both.trigger; + /* Set initial state to masked */ mask_irq(pin); } @@ -465,6 +474,9 @@ ioapic_configure(void) entry.both.vector = IOAPIC_INT_BASE + gsi; ioapic_write_entry(apic, pin, entry.both); + irqinfo[pin + ngsis].vector = entry.both.vector; + irqinfo[pin + ngsis].trigger = entry.both.trigger; + /* Set initial state to masked */ mask_irq(pin + ngsis); } diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c index 42dadeb8..071c23fa 100644 --- a/i386/i386at/model_dep.c +++ b/i386/i386at/model_dep.c @@ -173,6 +173,7 @@ void machine_init(void) #if (NCPUS > 1) smp_init(); #endif + init_irqs(); #if defined(APIC) ioapic_configure(); #endif |