summaryrefslogtreecommitdiff
path: root/i386/i386at
diff options
context:
space:
mode:
Diffstat (limited to 'i386/i386at')
-rw-r--r--i386/i386at/interrupt.S21
-rw-r--r--i386/i386at/ioapic.c18
-rw-r--r--i386/i386at/model_dep.c1
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