summaryrefslogtreecommitdiff
path: root/i386
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2024-01-29 10:06:57 +0000
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2024-01-29 20:02:21 +0100
commit6bca5c2873ef4cfccd8d2ebeedad29c9d5a6ec7f (patch)
tree8ddfc5b93af6151d26df9aa63205bde37ee9f065 /i386
parentf8d0f98e80b3d7d9b24fa077818113fb0f4b3970 (diff)
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>
Diffstat (limited to 'i386')
-rw-r--r--i386/i386/apic.c13
-rw-r--r--i386/i386/apic.h6
-rw-r--r--i386/i386/locore.S43
-rw-r--r--i386/i386at/acpi_parse_apic.c3
-rw-r--r--i386/i386at/int_init.c6
-rw-r--r--i386/i386at/ioapic.c89
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 <i386at/idt.h>
#include <i386at/int_init.h>
#include <i386/mp_desc.h>
+#include <kern/printf.h>
+#ifdef APIC
+#include <i386/apic.h>
+#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");
}