From 6bca5c2873ef4cfccd8d2ebeedad29c9d5a6ec7f Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Mon, 29 Jan 2024 10:06:57 +0000 Subject: Support up to two IOAPICs with up to 32 GSIs on each Previously, only IOAPIC[0] was supported. Now this supports up to two IOAPICs. Message-ID: <20240129100652.1262126-1-damien@zamaudio.com> --- i386/i386/apic.c | 13 +++++++ i386/i386/apic.h | 6 ++- i386/i386/locore.S | 43 +++++++++++++++++++++ i386/i386at/acpi_parse_apic.c | 3 ++ i386/i386at/int_init.c | 6 ++- i386/i386at/ioapic.c | 89 ++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 153 insertions(+), 7 deletions(-) diff --git a/i386/i386/apic.c b/i386/i386/apic.c index 3a51f506..0cf7c37c 100644 --- a/i386/i386/apic.c +++ b/i386/i386/apic.c @@ -179,6 +179,19 @@ apic_get_num_ioapics(void) return apic_data.nioapics; } +/* apic_get_total_gsis: returns the total number of GSIs in the system. */ +int +apic_get_total_gsis(void) +{ + int id; + int gsis = 0; + + for (id = 0; id < apic_get_num_ioapics(); id++) + gsis += apic_get_ioapic(id)->ngsis; + + return gsis; +} + /* * apic_get_current_cpu: returns the apic_id of current cpu. */ diff --git a/i386/i386/apic.h b/i386/i386/apic.h index e870dcf8..b8fff2af 100644 --- a/i386/i386/apic.h +++ b/i386/i386/apic.h @@ -193,6 +193,7 @@ typedef struct ApicLocalUnit { typedef struct IoApicData { uint8_t apic_id; + uint8_t ngsis; uint32_t addr; uint32_t gsi_base; ApicIoUnit *ioapic; @@ -239,6 +240,7 @@ int apic_get_current_cpu(void); void apic_print_info(void); int apic_refit_cpulist(void); void apic_generate_cpu_id_lut(void); +int apic_get_total_gsis(void); void picdisable(void); void lapic_eoi(void); void ioapic_irq_eoi(int pin); @@ -257,6 +259,8 @@ extern int cpu_id_lut[]; #define APIC_IO_UNIT_ID 0x00 #define APIC_IO_VERSION 0x01 +# define APIC_IO_VERSION_SHIFT 0 +# define APIC_IO_ENTRIES_SHIFT 16 #define APIC_IO_REDIR_LOW(int_pin) (0x10+(int_pin)*2) #define APIC_IO_REDIR_HIGH(int_pin) (0x11+(int_pin)*2) @@ -283,7 +287,7 @@ extern int cpu_id_lut[]; #define LAPIC_TIMER_BASEDIV 0x100000 #define LAPIC_HAS_DIRECTED_EOI 0x1000000 -#define NINTR 24 +#define NINTR 64 /* Max 32 GSIs on each of two IOAPICs */ #define IOAPIC_FIXED 0 #define IOAPIC_PHYSICAL 0 #define IOAPIC_LOGICAL 1 diff --git a/i386/i386/locore.S b/i386/i386/locore.S index df41722d..378297ff 100644 --- a/i386/i386/locore.S +++ b/i386/i386/locore.S @@ -694,6 +694,49 @@ INTERRUPT(20) INTERRUPT(21) INTERRUPT(22) INTERRUPT(23) +/* Possibly 8 more GSIs */ +INTERRUPT(24) +INTERRUPT(25) +INTERRUPT(26) +INTERRUPT(27) +INTERRUPT(28) +INTERRUPT(29) +INTERRUPT(30) +INTERRUPT(31) +/* ... APIC IOAPIC #2 */ +INTERRUPT(32) +INTERRUPT(33) +INTERRUPT(34) +INTERRUPT(35) +INTERRUPT(36) +INTERRUPT(37) +INTERRUPT(38) +INTERRUPT(39) +INTERRUPT(40) +INTERRUPT(41) +INTERRUPT(42) +INTERRUPT(43) +INTERRUPT(44) +INTERRUPT(45) +INTERRUPT(46) +INTERRUPT(47) +INTERRUPT(48) +INTERRUPT(49) +INTERRUPT(50) +INTERRUPT(51) +INTERRUPT(52) +INTERRUPT(53) +INTERRUPT(54) +INTERRUPT(55) +/* Possibly 8 more GSIs */ +INTERRUPT(56) +INTERRUPT(57) +INTERRUPT(58) +INTERRUPT(59) +INTERRUPT(60) +INTERRUPT(61) +INTERRUPT(62) +INTERRUPT(63) #endif #if NCPUS > 1 INTERRUPT(CALL_AST_CHECK) diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c index 9cd861ed..1aef53ed 100644 --- a/i386/i386at/acpi_parse_apic.c +++ b/i386/i386at/acpi_parse_apic.c @@ -331,6 +331,9 @@ acpi_apic_add_ioapic(struct acpi_apic_ioapic *ioapic_entry) io_apic.ioapic = (ApicIoUnit *)kmem_map_aligned_table(ioapic_entry->addr, sizeof(ApicIoUnit), VM_PROT_READ | VM_PROT_WRITE); + io_apic.ioapic->select.r = APIC_IO_VERSION; + io_apic.ngsis = ((io_apic.ioapic->window.r >> APIC_IO_ENTRIES_SHIFT) & 0xff) + 1; + /* Insert IOAPIC in the list. */ apic_add_ioapic(io_apic); } diff --git a/i386/i386at/int_init.c b/i386/i386at/int_init.c index d55d7a48..262bef1b 100644 --- a/i386/i386at/int_init.c +++ b/i386/i386at/int_init.c @@ -24,6 +24,10 @@ #include #include #include +#include +#ifdef APIC +#include +#endif /* defined in locore.S */ extern vm_offset_t int_entry_table[]; @@ -37,7 +41,7 @@ int_fill(struct real_gate *myidt) int nirq = 16; #else int base = IOAPIC_INT_BASE; - int nirq = 24; + int nirq = NINTR; #endif for (i = 0; i < nirq; i++) { diff --git a/i386/i386at/ioapic.c b/i386/i386at/ioapic.c index fb73eab7..270362c3 100644 --- a/i386/i386at/ioapic.c +++ b/i386/i386at/ioapic.c @@ -46,7 +46,13 @@ int spl_init = 0; def_simple_lock_irq_data(static, ioapic_lock) /* Lock for non-atomic window accesses to ioapic */ int iunit[NINTR] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23}; + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + /* 2nd IOAPIC */ + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63 }; interrupt_handler_fn ivect[NINTR] = { /* 00 */ (interrupt_handler_fn)hardclock, @@ -77,6 +83,49 @@ interrupt_handler_fn ivect[NINTR] = { /* 21 */ intnull, /* PIRQF */ /* 22 */ intnull, /* PIRQG */ /* 23 */ intnull, /* PIRQH */ + + /* 24 */ intnull, + /* 25 */ intnull, + /* 26 */ intnull, + /* 27 */ intnull, + /* 28 */ intnull, + /* 29 */ intnull, + /* 30 */ intnull, + /* 31 */ intnull, + + /* 32 */ intnull, + /* 33 */ intnull, + /* 34 */ intnull, + /* 35 */ intnull, + /* 36 */ intnull, + /* 37 */ intnull, + /* 38 */ intnull, + /* 39 */ intnull, + /* 40 */ intnull, + /* 41 */ intnull, + /* 42 */ intnull, + /* 43 */ intnull, + /* 44 */ intnull, + /* 45 */ intnull, + /* 46 */ intnull, + /* 47 */ intnull, + /* 48 */ intnull, + /* 49 */ intnull, + /* 50 */ intnull, + /* 51 */ intnull, + /* 52 */ intnull, + /* 53 */ intnull, + /* 54 */ intnull, + /* 55 */ intnull, + + /* 56 */ intnull, + /* 57 */ intnull, + /* 58 */ intnull, + /* 59 */ intnull, + /* 60 */ intnull, + /* 61 */ intnull, + /* 62 */ intnull, + /* 63 */ intnull, }; void @@ -155,7 +204,13 @@ ioapic_toggle_entry(int apic, int pin, int mask) static int ioapic_version(int apic) { - return ioapic_read(apic, APIC_IO_VERSION) & 0xff; + return (ioapic_read(apic, APIC_IO_VERSION) >> APIC_IO_VERSION_SHIFT) & 0xff; +} + +static int +ioapic_gsis(int apic) +{ + return ((ioapic_read(apic, APIC_IO_VERSION) >> APIC_IO_ENTRIES_SHIFT) & 0xff) + 1; } static void timer_expiry_callback(void *arg) @@ -315,6 +370,8 @@ ioapic_configure(void) IrqOverrideData *irq_over; int timer_gsi; int version = ioapic_version(apic); + int ngsis = ioapic_gsis(apic); + int ngsis2 = 0; if (version >= 0x20) { has_irq_specific_eoi = 1; @@ -362,7 +419,7 @@ ioapic_configure(void) } } - for (pin = 16; pin < 24; pin++) { + for (pin = 16; pin < ngsis; pin++) { gsi = pin; /* PCI IRQs PIRQ A-H */ @@ -376,8 +433,30 @@ ioapic_configure(void) ioapic_write_entry(apic, pin, entry.both); } + printf("IOAPIC 0 configured with GSI 0-%d\n", ngsis - 1); + + /* Second IOAPIC */ + if (apic_get_num_ioapics() > 1) { + apic = 1; + ngsis2 = ioapic_gsis(apic); + + for (pin = 0; pin < ngsis2; pin++) { + gsi = pin + ngsis; + + /* Defaults */ + entry.both.trigger = IOAPIC_LEVEL_TRIGGERED; + entry.both.polarity = IOAPIC_ACTIVE_LOW; + + if ((irq_over = acpi_get_irq_override(pin + ngsis))) { + gsi = override_irq(irq_over, &entry); + } + entry.both.vector = IOAPIC_INT_BASE + gsi; + ioapic_write_entry(apic, pin, entry.both); + } + + printf("IOAPIC 1 configured with GSI %d-%d\n", ngsis, ngsis + ngsis2 - 1); + } + /* Start the IO APIC receiving interrupts */ lapic_enable(); - - printf("IOAPIC 0 configured\n"); } -- cgit v1.2.3