bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 4/4 gnumach] apic: Add extended feature registers for local ap


From: Damien Zammit
Subject: [PATCH v3 4/4 gnumach] apic: Add extended feature registers for local apic unit
Date: Sat, 21 Dec 2024 23:55:40 +0000

Add workaround for broken systems that advertise 8 bit APIC ids
but only match IPIs on 4 bits of the APIC id.
---
 i386/i386/apic.c              | 28 +++++++++++++++++++++++++++-
 i386/i386/apic.h              | 15 ++++++++++++++-
 i386/i386/cpu_number.h        |  3 +++
 i386/i386/cpuboot.S           |  1 +
 i386/i386/mp_desc.c           |  2 +-
 i386/i386at/acpi_parse_apic.c |  5 ++++-
 i386/i386at/ioapic.c          |  8 ++++++--
 7 files changed, 56 insertions(+), 6 deletions(-)

diff --git a/i386/i386/apic.c b/i386/i386/apic.c
index e0941c6a..77d555b5 100644
--- a/i386/i386/apic.c
+++ b/i386/i386/apic.c
@@ -46,6 +46,13 @@ int cpu_id_lut[UINT8_MAX + 1] = {0};
 
 ApicInfo apic_data;
 
+/* xAPIC: This is supposed to be an 8 bit mask.  On some platforms it needs to 
be a
+ * lower 4 bit mask because the chipset only matches on 4 bits of the id when 
doing IPIs.
+ * The cpuid accessor and lapic may report full 8 bit id so always & with this 
mask when
+ * reading the APIC id.  Increases to 8 bits if no workaround is required.
+*/
+uint8_t apic_id_mask = 0xf;
+
 /*
  * apic_data_init: initialize the apic_data structures to preliminary values.
  * Reserve memory to the lapic list dynamic vector.
@@ -206,7 +213,7 @@ apic_get_current_cpu(void)
     eax = 1;
     ecx = 0;
     cpuid(eax, ebx, ecx, edx);
-    return (ebx >> 24);
+    return (ebx >> 24) & apic_id_mask;
 }
 
 
@@ -322,6 +329,25 @@ lapic_disable(void)
     lapic->spurious_vector.r &= ~LAPIC_ENABLE;
 }
 
+void
+fix_apic_id_mask(void)
+{
+    if (lapic->version.r & APIC_VERSION_HAS_EXT_APIC_SPACE) {
+        /* Extended registers beyond 0x3f0 are present */
+        if (lapic->extended_feature.r & APIC_EXT_FEATURE_HAS_8BITID) {
+            /* 8 bit APIC ids are supported on this local APIC */
+            if (!(lapic->extended_control.r & APIC_EXT_CTRL_ENABLE_8BITID)) {
+                printf("WARNING: Only 4 bit APIC ids\n");
+                apic_id_mask = 0xf;
+                return;
+            }
+        }
+    }
+
+    printf("8 bit APIC ids\n");
+    apic_id_mask = 0xff;
+}
+
 void
 lapic_setup(void)
 {
diff --git a/i386/i386/apic.h b/i386/i386/apic.h
index cb700c44..a7dab2a2 100644
--- a/i386/i386/apic.h
+++ b/i386/i386/apic.h
@@ -189,8 +189,20 @@ typedef struct ApicLocalUnit {
         ApicReg reserved3d;              /* 0x3d0 */
         ApicReg divider_config;          /* 0x3e0 */
         ApicReg reserved3f;              /* 0x3f0 */
+        ApicReg extended_feature;        /* 0x400  Present if version extended 
apic space bit is set */
+        ApicReg extended_control;        /* 0x410 */
+        ApicReg specific_eoi;            /* 0x420 */
 } ApicLocalUnit;
 
+#define APIC_VERSION_HAS_EXT_APIC_SPACE        (1 << 31)
+#define APIC_VERSION_HAS_DIRECTED_EOI  (1 << 24)
+
+#define APIC_EXT_FEATURE_HAS_SEOI      (1 << 1)
+#define APIC_EXT_FEATURE_HAS_8BITID    (1 << 2)
+
+#define APIC_EXT_CTRL_ENABLE_SEOI      (1 << 1)
+#define APIC_EXT_CTRL_ENABLE_8BITID    (1 << 2)
+
 typedef struct IoApicData {
         uint8_t  apic_id;
         uint8_t  ngsis;
@@ -244,6 +256,7 @@ int apic_get_total_gsis(void);
 void picdisable(void);
 void lapic_eoi(void);
 void ioapic_irq_eoi(int pin);
+void fix_apic_id_mask(void);
 void lapic_setup(void);
 void lapic_disable(void);
 void lapic_enable(void);
@@ -261,6 +274,7 @@ extern void intnull(int unit);
 extern volatile ApicLocalUnit* lapic;
 extern int cpu_id_lut[];
 extern uint32_t *hpet_addr;
+extern uint8_t apic_id_mask;
 
 #endif
 
@@ -292,7 +306,6 @@ extern uint32_t *hpet_addr;
 #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                          64 /* Max 32 GSIs on each of two 
IOAPICs */
 #define IOAPIC_FIXED                   0
diff --git a/i386/i386/cpu_number.h b/i386/i386/cpu_number.h
index 547e0498..0c0ec189 100644
--- a/i386/i386/cpu_number.h
+++ b/i386/i386/cpu_number.h
@@ -46,6 +46,7 @@
        movl    %cs:lapic, reg          ;\
        movl    %cs:APIC_ID(reg), reg   ;\
        shrl    $24, reg                ;\
+       andl    %cs:apic_id_mask, reg   ;\
        movl    %cs:CX(cpu_id_lut, reg), reg    ;\
 
 /* Fast version, requires a stack */
@@ -60,6 +61,7 @@
        movl    $1, %eax        ;\
        cpuid                   ;\
        shrl    $24, %ebx       ;\
+       andl    %cs:apic_id_mask, %ebx  ;\
        movl    %cs:CX(cpu_id_lut, %ebx), %esi  ;\
        popl    %edx            ;\
        popl    %ecx            ;\
@@ -79,6 +81,7 @@
        movl    $1, %eax        ;\
        cpuid                   ;\
        shrl    $24, %ebx       ;\
+       andl    %cs:apic_id_mask, %ebx  ;\
        movl    %cs:CX(cpu_id_lut, %ebx), %esi  ;\
        popq    %rdx            ;\
        popq    %rcx            ;\
diff --git a/i386/i386/cpuboot.S b/i386/i386/cpuboot.S
index 76ed907d..2bfd1e5d 100644
--- a/i386/i386/cpuboot.S
+++ b/i386/i386/cpuboot.S
@@ -170,6 +170,7 @@ apboot_jmp_offset:
        movl    $1, %eax
        cpuid
        shrl    $24, %ebx
+       andl    %cs:apic_id_mask, %ebx
        movl    %cs:CX(cpu_id_lut, %ebx), %ebp
 
        /* Copy first gdt descriptor and gdt to cpu-th area */
diff --git a/i386/i386/mp_desc.c b/i386/i386/mp_desc.c
index f6ee11f5..ab3bb4e9 100644
--- a/i386/i386/mp_desc.c
+++ b/i386/i386/mp_desc.c
@@ -316,7 +316,7 @@ start_other_cpus(void)
        /* This is set once for all APs to use */
        pmap_make_temporary_mapping();
 
-       smp_startup_cpus(apic_get_cpu_apic_id(0), apboot_addr);
+       smp_startup_cpus(apic_get_current_cpu(), apboot_addr);
 
        for (cpu = 1; cpu < ncpus; cpu++) {
                machine_slot[cpu].running = FALSE;
diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c
index ae92ee2e..bac5d04d 100644
--- a/i386/i386at/acpi_parse_apic.c
+++ b/i386/i386at/acpi_parse_apic.c
@@ -378,7 +378,7 @@ acpi_apic_add_lapic(struct acpi_apic_lapic *lapic_entry)
     /* If cpu flag is correct */
     if (lapic_entry->flags & (ACPI_LAPIC_FLAG_ENABLED | 
ACPI_LAPIC_FLAG_CAPABLE)) {
         /* Add cpu to processors' list. */
-        apic_add_cpu(lapic_entry->apic_id);
+        apic_add_cpu(lapic_entry->apic_id & apic_id_mask);
     }
 
 }
@@ -541,6 +541,9 @@ acpi_apic_setup(struct acpi_apic *apic)
         return ACPI_NO_LAPIC;
 
     apic_lapic_init(lapic_unit);
+
+    fix_apic_id_mask();
+
     acpi_apic_parse_table(apic);
 
     ncpus = apic_get_numcpus();
diff --git a/i386/i386at/ioapic.c b/i386/i386at/ioapic.c
index 845d1249..5dd2de2e 100644
--- a/i386/i386at/ioapic.c
+++ b/i386/i386at/ioapic.c
@@ -366,7 +366,7 @@ void
 ioapic_configure(void)
 {
     /* Assume first IO APIC maps to GSI base 0 */
-    int gsi, apic = 0, bsp = 0, pin;
+    int gsi, apic = 0, pin;
     IrqOverrideData *irq_over;
     int timer_gsi;
     int version = ioapic_version(apic);
@@ -387,7 +387,11 @@ ioapic_configure(void)
     entry.both.delvmode = IOAPIC_FIXED;
     entry.both.destmode = IOAPIC_PHYSICAL;
     entry.both.mask = IOAPIC_MASK_DISABLED;
-    entry.both.dest = apic_get_cpu_apic_id(bsp);
+    /* This does not use apic_id_mask because
+     * the IOAPIC seems to use what is actually set
+     * in lapic's apic_id register.
+     */
+    entry.both.dest = lapic->apic_id.r >> 24;
 
     for (pin = 0; pin < 16; pin++) {
         gsi = pin;
-- 
2.45.2





reply via email to

[Prev in Thread] Current Thread [Next in Thread]