diff options
author | Richard Braun <rbraun@sceen.net> | 2017-06-03 17:42:53 +0200 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2017-06-03 17:42:53 +0200 |
commit | bcac7e2c417bdbc0c2eace0a693d29442a0db12c (patch) | |
tree | ac4c82d3927d0328d2bd471db0c073c4d88bf06f | |
parent | 04002b5583c6da62b60b9c2470b0853178358658 (diff) |
x86/{acpi,ioapic}: handle interrupt source overrides
-rw-r--r-- | arch/x86/machine/acpi.c | 67 | ||||
-rw-r--r-- | arch/x86/machine/ioapic.c | 121 | ||||
-rw-r--r-- | arch/x86/machine/ioapic.h | 12 | ||||
-rw-r--r-- | arch/x86/machine/pic.c | 2 | ||||
-rw-r--r-- | arch/x86/machine/pic.h | 10 | ||||
-rw-r--r-- | arch/x86/machine/trap.h | 5 |
6 files changed, 203 insertions, 14 deletions
diff --git a/arch/x86/machine/acpi.c b/arch/x86/machine/acpi.c index 1f7e5683..6d5e06e6 100644 --- a/arch/x86/machine/acpi.c +++ b/arch/x86/machine/acpi.c @@ -16,6 +16,7 @@ */ #include <assert.h> +#include <stdbool.h> #include <stddef.h> #include <stdint.h> #include <stdio.h> @@ -80,6 +81,7 @@ struct acpi_rsdt { */ #define ACPI_MADT_ENTRY_LAPIC 0 #define ACPI_MADT_ENTRY_IOAPIC 1 +#define ACPI_MADT_ENTRY_ISO 2 struct acpi_madt_entry_hdr { uint8_t type; @@ -103,11 +105,29 @@ struct acpi_madt_entry_ioapic { uint32_t base; } __packed; +#define ACPI_MADT_ISO_POL_DEFAULT 0x00 +#define ACPI_MADT_ISO_POL_HIGH 0x01 +#define ACPI_MADT_ISO_POL_LOW 0x03 +#define ACPI_MADT_ISO_POL_MASK 0x03 +#define ACPI_MADT_ISO_TRIG_DEFAULT 0x00 +#define ACPI_MADT_ISO_TRIG_EDGE 0x04 +#define ACPI_MADT_ISO_TRIG_LEVEL 0x0c +#define ACPI_MADT_ISO_TRIG_MASK 0x0c + +struct acpi_madt_entry_iso { + struct acpi_madt_entry_hdr header; + uint8_t bus; + uint8_t source; + uint32_t gsi; + int16_t flags; +} __packed; + union acpi_madt_entry { uint8_t type; struct acpi_madt_entry_hdr header; struct acpi_madt_entry_lapic lapic; struct acpi_madt_entry_ioapic ioapic; + struct acpi_madt_entry_iso iso; } __packed; #define ACPI_MADT_PC_COMPAT 0x1 @@ -487,6 +507,45 @@ acpi_load_ioapic(const struct acpi_madt_entry_ioapic *ioapic) } static void __init +acpi_load_iso(const struct acpi_madt_entry_iso *iso) +{ + bool active_high, edge_triggered; + + if (iso->bus != 0) { + printf("acpi: error: invalid interrupt source override bus\n"); + return; + } + + switch (iso->flags & ACPI_MADT_ISO_POL_MASK) { + case ACPI_MADT_ISO_POL_DEFAULT: + case ACPI_MADT_ISO_POL_HIGH: + active_high = true; + break; + case ACPI_MADT_ISO_POL_LOW: + active_high = false; + break; + default: + printf("acpi: error: invalid polarity\n"); + return; + } + + switch (iso->flags & ACPI_MADT_ISO_TRIG_MASK) { + case ACPI_MADT_ISO_TRIG_DEFAULT: + case ACPI_MADT_ISO_TRIG_EDGE: + edge_triggered = true; + break; + case ACPI_MADT_ISO_TRIG_LEVEL: + edge_triggered = false; + break; + default: + printf("acpi: error: invalid trigger mode\n"); + return; + } + + ioapic_override(iso->source, iso->gsi, active_high, edge_triggered); +} + +static void __init acpi_load_madt(void) { const struct acpi_sdth *table; @@ -501,10 +560,6 @@ acpi_load_madt(void) lapic_setup(madt->lapic_addr); is_bsp = 1; - /* - * TODO Handle interrupt overrides - */ - acpi_madt_foreach(madt, &iter) { switch (iter.entry->type) { case ACPI_MADT_ENTRY_LAPIC: @@ -512,6 +567,10 @@ acpi_load_madt(void) break; case ACPI_MADT_ENTRY_IOAPIC: acpi_load_ioapic(&iter.entry->ioapic); + break; + case ACPI_MADT_ENTRY_ISO: + acpi_load_iso(&iter.entry->iso); + break; } } diff --git a/arch/x86/machine/ioapic.c b/arch/x86/machine/ioapic.c index d48cc307..e49cb309 100644 --- a/arch/x86/machine/ioapic.c +++ b/arch/x86/machine/ioapic.c @@ -29,6 +29,7 @@ #include <machine/cpu.h> #include <machine/ioapic.h> #include <machine/lapic.h> +#include <machine/pic.h> #include <machine/trap.h> #include <vm/vm_kmem.h> @@ -40,6 +41,10 @@ #define IOAPIC_VERSION_MAXREDIR_MASK 0x00ff0000 #define IOAPIC_VERSION_MAXREDIR_SHIFT 16 +#define IOAPIC_ENTLOW_FIXED_DEST 0x00000 +#define IOAPIC_ENTLOW_PHYS_DELIVERY 0x00000 +#define IOAPIC_ENTLOW_ACTIVE_LOW 0x02000 +#define IOAPIC_ENTLOW_LEVEL 0x08000 #define IOAPIC_ENTLOW_INTRMASK 0x10000 #define IOAPIC_MAX_ENTRIES 24 @@ -55,6 +60,16 @@ struct ioapic_map { uint32_t win; }; +/* + * Interrupt source override descriptor. + */ +struct ioapic_iso { + uint8_t source; + uint32_t gsi; + bool active_high; + bool edge_triggered; +}; + struct ioapic { struct spinlock lock; unsigned int id; @@ -67,6 +82,51 @@ struct ioapic { static unsigned int ioapic_nr_devs; +static struct ioapic_iso ioapic_isos[PIC_MAX_INTR + 1]; +static unsigned int ioapic_nr_isos; + +static void +ioapic_iso_init(struct ioapic_iso *iso, uint8_t source, uint32_t gsi, + bool active_high, bool edge_triggered) +{ + iso->source = source; + iso->gsi = gsi; + iso->active_high = active_high; + iso->edge_triggered = edge_triggered; +} + +static struct ioapic_iso * __init +ioapic_alloc_iso(void) +{ + struct ioapic_iso *iso; + + if (ioapic_nr_isos >= ARRAY_SIZE(ioapic_isos)) { + printf("ioapic: error: too many interrupt overrides\n"); + return NULL; + } + + iso = &ioapic_isos[ioapic_nr_isos]; + ioapic_nr_isos++; + return iso; +} + +static struct ioapic_iso * +ioapic_lookup_iso(unsigned int intr) +{ + struct ioapic_iso *iso; + unsigned int i; + + for (i = 0; i < ioapic_nr_isos; i++) { + iso = &ioapic_isos[i]; + + if (intr == iso->source) { + return iso; + } + } + + return NULL; +} + static uint32_t ioapic_read(struct ioapic *ioapic, uint8_t reg) { @@ -161,18 +221,52 @@ ioapic_compute_id(const struct ioapic *ioapic, unsigned int intr) } static void +ioapic_compute_entry(uint32_t *highp, uint32_t *lowp, + unsigned int apic_id, unsigned int intr, + bool active_high, bool edge_triggered) +{ + assert(apic_id < 16); + assert(intr < (TRAP_NR_VECTORS - TRAP_INTR_FIRST)); + + *highp = apic_id << 24; + *lowp = (!edge_triggered ? IOAPIC_ENTLOW_LEVEL : 0) + | (!active_high ? IOAPIC_ENTLOW_ACTIVE_LOW : 0) + | IOAPIC_ENTLOW_PHYS_DELIVERY + | IOAPIC_ENTLOW_FIXED_DEST + | (TRAP_INTR_FIRST + intr); +} + +static void ioapic_enable(void *priv, unsigned int intr, unsigned int cpu) { + bool active_high, edge_triggered; + const struct ioapic_iso *iso; + uint32_t high, low, gsi; struct ioapic *ioapic; unsigned long flags; unsigned int id; + iso = ioapic_lookup_iso(intr); + + /* XXX These are defaults that should work with architectural devices */ + if (iso == NULL) { + active_high = true; + edge_triggered = true; + gsi = intr; + } else { + active_high = iso->active_high; + edge_triggered = iso->edge_triggered; + gsi = iso->gsi; + } + ioapic = priv; - id = ioapic_compute_id(ioapic, intr); + id = ioapic_compute_id(ioapic, gsi); + ioapic_compute_entry(&high, &low, cpu_apic_id(cpu), intr, + active_high, edge_triggered); spinlock_lock_intr_save(&ioapic->lock, &flags); - ioapic_write_entry_high(ioapic, id, cpu_apic_id(cpu) << 24); - ioapic_write_entry_low(ioapic, id, TRAP_INTR_FIRST + intr); + ioapic_write_entry_high(ioapic, id, high); + ioapic_write_entry_low(ioapic, id, low); spinlock_unlock_intr_restore(&ioapic->lock, flags); } @@ -207,6 +301,13 @@ static const struct intr_ops ioapic_ops = { }; void __init +ioapic_setup(void) +{ + ioapic_nr_devs = 0; + ioapic_nr_isos = 0; +} + +void __init ioapic_register(unsigned int apic_id, uintptr_t addr, unsigned int intr_base) { struct ioapic *ioapic; @@ -216,3 +317,17 @@ ioapic_register(unsigned int apic_id, uintptr_t addr, unsigned int intr_base) ioapic->first_intr, ioapic->last_intr); } +void __init +ioapic_override(uint8_t source, uint32_t gsi, + bool active_high, bool edge_triggered) +{ + struct ioapic_iso *iso; + + iso = ioapic_alloc_iso(); + + if (iso == NULL) { + return; + } + + ioapic_iso_init(iso, source, gsi, active_high, edge_triggered); +} diff --git a/arch/x86/machine/ioapic.h b/arch/x86/machine/ioapic.h index d508904e..b9a702d3 100644 --- a/arch/x86/machine/ioapic.h +++ b/arch/x86/machine/ioapic.h @@ -18,12 +18,24 @@ #ifndef _KERN_IOAPIC_H #define _KERN_IOAPIC_H +#include <stdbool.h> #include <stdint.h> /* + * Initialize the ioapic module. + */ +void ioapic_setup(void); + +/* * Register an I/O APIC controller. */ void ioapic_register(unsigned int apic_id, uintptr_t addr, unsigned int gsi_base); +/* + * Report an interrupt source override. + */ +void ioapic_override(uint8_t source, uint32_t gsi, + bool active_high, bool edge_triggered); + #endif /* _KERN_IOAPIC_H */ diff --git a/arch/x86/machine/pic.c b/arch/x86/machine/pic.c index ab30ac20..8ef57538 100644 --- a/arch/x86/machine/pic.c +++ b/arch/x86/machine/pic.c @@ -51,8 +51,6 @@ */ #define PIC_SLAVE_INTR 2 #define PIC_SPURIOUS_INTR 7 -#define PIC_NR_INTRS 8 -#define PIC_MAX_INTR ((PIC_NR_INTRS * 2) - 1) static unsigned int pic_nr_slave_intrs; diff --git a/arch/x86/machine/pic.h b/arch/x86/machine/pic.h index e49d336e..89833d00 100644 --- a/arch/x86/machine/pic.h +++ b/arch/x86/machine/pic.h @@ -18,7 +18,15 @@ #ifndef _X86_PIC_H #define _X86_PIC_H -#include <machine/trap.h> +/* + * Interrupts per PIC. + */ +#define PIC_NR_INTRS 8 + +/* + * Maximum global interrupt number. + */ +#define PIC_MAX_INTR ((PIC_NR_INTRS * 2) - 1) /* * Initialize the pic module. diff --git a/arch/x86/machine/trap.h b/arch/x86/machine/trap.h index 7bda9cf3..e4d5912b 100644 --- a/arch/x86/machine/trap.h +++ b/arch/x86/machine/trap.h @@ -61,10 +61,7 @@ #define TRAP_LAPIC_ERROR 254 #define TRAP_LAPIC_SPURIOUS 255 -/* - * Vector identifying an unhandled trap. - */ -#define TRAP_DEFAULT 256 +#define TRAP_NR_VECTORS 256 #ifndef __ASSEMBLER__ |