summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2021-04-05 15:29:16 +1000
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2021-04-05 12:00:25 +0200
commit697d9a014506df49976251b2cc449bbe2a806d9a (patch)
treeb4c75a44d6973de42193cdd20989a62557b8c15e
parent417f458488e4802cc3f2658c1b241a5e0053df46 (diff)
ioapic: Use irq specific EOI properly when detected
Message-Id: <20210405052916.174771-5-damien@zamaudio.com>
-rw-r--r--i386/i386/apic.h4
-rw-r--r--i386/i386at/ioapic.c30
2 files changed, 26 insertions, 8 deletions
diff --git a/i386/i386/apic.h b/i386/i386/apic.h
index d63dbfcc..add1b8cf 100644
--- a/i386/i386/apic.h
+++ b/i386/i386/apic.h
@@ -35,6 +35,8 @@ typedef struct ApicReg {
typedef struct ApicIoUnit {
ApicReg select;
ApicReg window;
+ ApicReg unused[2];
+ ApicReg eoi; /* write the vector you wish to EOI to this reg */
} ApicIoUnit;
struct ioapic_route_entry {
@@ -175,6 +177,7 @@ extern inline void unmask_irq (unsigned int irq_nr);
#define LAPIC_ENABLE 0x100
#define LAPIC_FOCUS 0x200
#define LAPIC_NMI 0x400
+#define LAPIC_ENABLE_DIRECTED_EOI 0x1000
#define LAPIC_DISABLE 0x10000
#define LAPIC_TIMER_PERIODIC 0x20000
#define LAPIC_TIMER_DIVIDE_2 0
@@ -182,6 +185,7 @@ extern inline void unmask_irq (unsigned int irq_nr);
#define LAPIC_TIMER_DIVIDE_8 2
#define LAPIC_TIMER_DIVIDE_16 3
#define LAPIC_TIMER_BASEDIV 0x100000
+#define LAPIC_HAS_DIRECTED_EOI 0x1000000
#define NINTR 24
#define IOAPIC_FIXED 0
diff --git a/i386/i386at/ioapic.c b/i386/i386at/ioapic.c
index 38d1b43c..30ae30e1 100644
--- a/i386/i386at/ioapic.c
+++ b/i386/i386at/ioapic.c
@@ -31,6 +31,7 @@
#include <mach/machine.h>
#include <kern/printf.h>
+static int has_irq_specific_eoi = 1; /* FIXME: Assume all machines have this */
static int timer_gsi;
int timer_pin;
@@ -244,16 +245,23 @@ ioapic_irq_eoi(int pin)
int apic = 0;
union ioapic_route_entry_union oldentry, entry;
- /* Workaround for old IOAPICs with no specific EOI */
+ if (!has_irq_specific_eoi) {
+ /* Workaround for old IOAPICs with no specific EOI */
- /* Mask the pin and change to edge triggered */
- oldentry.both = entry.both = ioapic_read_entry(apic, pin);
- entry.both.mask = IOAPIC_MASK_DISABLED;
- entry.both.trigger = IOAPIC_EDGE_TRIGGERED;
- ioapic_write_entry(apic, pin, entry.both);
+ /* Mask the pin and change to edge triggered */
+ oldentry.both = entry.both = ioapic_read_entry(apic, pin);
+ entry.both.mask = IOAPIC_MASK_DISABLED;
+ entry.both.trigger = IOAPIC_EDGE_TRIGGERED;
+ ioapic_write_entry(apic, pin, entry.both);
+
+ /* Restore level entry */
+ ioapic_write_entry(apic, pin, oldentry.both);
+ } else {
+ volatile ApicIoUnit *ioapic = apic_get_ioapic(apic)->ioapic;
- /* Restore level entry */
- ioapic_write_entry(apic, pin, oldentry.both);
+ entry.both = ioapic_read_entry(apic, pin);
+ ioapic->eoi.r = entry.both.vector;
+ }
}
void
@@ -382,6 +390,12 @@ ioapic_configure(void)
/* Enable IOAPIC processor focus */
lapic->spurious_vector.r |= LAPIC_FOCUS;
+ /* Enable directed EOI if applicable */
+ if (has_irq_specific_eoi || lapic->version.r & LAPIC_HAS_DIRECTED_EOI) {
+ has_irq_specific_eoi = 1;
+ lapic->spurious_vector.r |= LAPIC_ENABLE_DIRECTED_EOI;
+ }
+
/* Enable IOAPIC interrupts */
lapic->spurious_vector.r |= LAPIC_ENABLE;