acpi: Use X2APIC entries, if there are only X2APIC entries in MADT.
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 29 May 2018 13:42:15 +0000 (21:42 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 29 May 2018 13:49:05 +0000 (21:49 +0800)
sys/platform/pc64/acpica/acpi_madt.c

index 7459e96..6721fb1 100644 (file)
@@ -77,6 +77,8 @@ static int                    madt_ioapic_probe(struct ioapic_enumerator *);
 
 static vm_paddr_t              madt_phyaddr;
 
+static boolean_t               madt_use_x2apic = FALSE;
+
 u_int                          cpu_id_to_acpi_id[NAPICID];
 
 static void
@@ -178,6 +180,14 @@ madt_iterate_entries(ACPI_TABLE_MADT *madt, madt_iter_t func, void *arg)
                        }
                        break;
 
+               case ACPI_MADT_TYPE_LOCAL_X2APIC:
+                       if (ent->Length < sizeof(ACPI_MADT_LOCAL_X2APIC)) {
+                               kprintf("madt_iterate_entries: invalid MADT "
+                                       "x2apic entry len %d\n", ent->Length);
+                               error = EINVAL;
+                       }
+                       break;
+
                case ACPI_MADT_TYPE_IO_APIC:
                        if (ent->Length < sizeof(ACPI_MADT_IO_APIC)) {
                                kprintf("madt_iterate_entries: invalid MADT "
@@ -294,11 +304,40 @@ madt_lapic_pass2_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
        return 0;
 }
 
+static int
+madt_x2apic_pass2_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
+{
+       const ACPI_MADT_LOCAL_X2APIC *x2apic_ent;
+       struct madt_lapic_pass2_cbarg *arg = xarg;
+
+       if (ent->Type != ACPI_MADT_TYPE_LOCAL_X2APIC)
+               return 0;
+
+       x2apic_ent = (const ACPI_MADT_LOCAL_X2APIC *)ent;
+       if (x2apic_ent->LapicFlags & ACPI_MADT_ENABLED) {
+               int cpu;
+
+               if (x2apic_ent->LocalApicId == arg->bsp_apic_id) {
+                       cpu = 0;
+                       arg->bsp_found = 1;
+               } else {
+                       cpu = arg->cpu;
+                       arg->cpu++;
+               }
+               MADT_VPRINTF("cpu id %d, acpi uid %u, apic id %d\n",
+                   cpu, x2apic_ent->Uid, x2apic_ent->LocalApicId);
+               lapic_set_cpuid(cpu, x2apic_ent->LocalApicId);
+               CPUID_TO_ACPIID(cpu) = x2apic_ent->Uid;
+       }
+       return 0;
+}
+
 static int
 madt_lapic_pass2(int bsp_apic_id)
 {
        ACPI_TABLE_MADT *madt;
        struct madt_lapic_pass2_cbarg arg;
+       madt_iter_t func;
        int error;
 
        MADT_VPRINTF("BSP apic id %d\n", bsp_apic_id);
@@ -312,7 +351,11 @@ madt_lapic_pass2(int bsp_apic_id)
        arg.cpu = 1;
        arg.bsp_apic_id = bsp_apic_id;
 
-       error = madt_iterate_entries(madt, madt_lapic_pass2_callback, &arg);
+       if (madt_use_x2apic)
+               func = madt_x2apic_pass2_callback;
+       else
+               func = madt_lapic_pass2_callback;
+       error = madt_iterate_entries(madt, func, &arg);
        if (error)
                panic("madt_iterate_entries(pass2) failed");
 
@@ -325,7 +368,8 @@ madt_lapic_pass2(int bsp_apic_id)
 }
 
 struct madt_lapic_probe_cbarg {
-       int             cpu_count;
+       int             x2apic_count;
+       int             lapic_count;
        vm_paddr_t      lapic_addr;
 };
 
@@ -339,7 +383,7 @@ madt_lapic_probe_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
 
                lapic_ent = (const ACPI_MADT_LOCAL_APIC *)ent;
                if (lapic_ent->LapicFlags & ACPI_MADT_ENABLED) {
-                       arg->cpu_count++;
+                       arg->lapic_count++;
                        if (lapic_ent->Id == APICID_MAX) {
                                kprintf("madt_lapic_probe: "
                                    "invalid LAPIC apic id %d\n",
@@ -347,6 +391,19 @@ madt_lapic_probe_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
                                return EINVAL;
                        }
                }
+       } else if (ent->Type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
+               const ACPI_MADT_LOCAL_X2APIC *x2apic_ent;
+
+               x2apic_ent = (const ACPI_MADT_LOCAL_X2APIC *)ent;
+               if (x2apic_ent->LapicFlags & ACPI_MADT_ENABLED) {
+                       if (x2apic_ent->LocalApicId < APICID_MAX) {
+                               /*
+                                * XXX we only support APIC ID 0~254 at
+                                * the moment.
+                                */
+                               arg->x2apic_count++;
+                       }
+               }
        } else if (ent->Type == ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE) {
                const ACPI_MADT_LOCAL_APIC_OVERRIDE *lapic_addr_ent;
 
@@ -381,11 +438,32 @@ madt_lapic_probe(struct lapic_enumerator *e)
 
        error = madt_iterate_entries(madt, madt_lapic_probe_callback, &arg);
        if (!error) {
-               if (arg.cpu_count == 0) {
+               if (arg.lapic_count == 0 && arg.x2apic_count == 0) {
                        kprintf("madt_lapic_probe: no CPU is found\n");
                        error = EOPNOTSUPP;
+               } else if (arg.lapic_count == 0) {
+                       /*
+                        * ACPI 5.1 says that LOCAL_X2APIC entry should
+                        * be used only if APIC ID > 255.  While ACPI 6.2
+                        * removes that constraint, which means that
+                        * LOCAL_X2APIC entry could be used for any APIC
+                        * ID.
+                        *
+                        * XXX
+                        * In DragonFlyBSD, we don't support APIC ID >=
+                        * 255, so LOCAL_X2APIC entries should be ignored,
+                        * if LOCAL_X2APIC entries are mixed with
+                        * LOCAL_APIC entries.  LOCAL_X2APIC entries are
+                        * used, iff only LOCAL_X2APIC entries exist.
+                        */
+                       madt_use_x2apic = TRUE;
+                       kprintf("MADT: use X2APIC entries\n");
                }
+
                if (arg.lapic_addr == 0) {
+                       /*
+                        * XXX x2apic mode.
+                        */
                        kprintf("madt_lapic_probe: zero LAPIC address\n");
                        error = EOPNOTSUPP;
                }