pc: acpi: x2APIC support for MADT table and _MAT method

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
This commit is contained in:
Igor Mammedov 2016-10-19 14:05:31 +02:00 committed by Eduardo Habkost
parent a3ae21ec3f
commit e2c9593945
3 changed files with 76 additions and 23 deletions

View File

@ -531,6 +531,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
apic->flags = cpu_to_le32(1); apic->flags = cpu_to_le32(1);
break; break;
} }
case ACPI_APIC_LOCAL_X2APIC: {
AcpiMadtProcessorX2Apic *apic = (void *)madt_buf->data;
apic->flags = cpu_to_le32(1);
break;
}
default: default:
assert(0); assert(0);
} }

View File

@ -340,24 +340,38 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm,
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
CPUArchIdList *apic_ids, GArray *entry) CPUArchIdList *apic_ids, GArray *entry)
{ {
int apic_id; uint32_t apic_id = apic_ids->cpus[uid].arch_id;
AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic);
apic_id = apic_ids->cpus[uid].arch_id; /* ACPI spec says that LAPIC entry for non present
apic->type = ACPI_APIC_PROCESSOR; * CPU may be omitted from MADT or it must be marked
apic->length = sizeof(*apic); * as disabled. However omitting non present CPU from
apic->processor_id = uid; * MADT breaks hotplug on linux. So possible CPUs
apic->local_apic_id = apic_id; * should be put in MADT but kept disabled.
if (apic_ids->cpus[uid].cpu != NULL) { */
apic->flags = cpu_to_le32(1); if (apic_id < 255) {
AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic);
apic->type = ACPI_APIC_PROCESSOR;
apic->length = sizeof(*apic);
apic->processor_id = uid;
apic->local_apic_id = apic_id;
if (apic_ids->cpus[uid].cpu != NULL) {
apic->flags = cpu_to_le32(1);
} else {
apic->flags = cpu_to_le32(0);
}
} else { } else {
/* ACPI spec says that LAPIC entry for non present AcpiMadtProcessorX2Apic *apic = acpi_data_push(entry, sizeof *apic);
* CPU may be omitted from MADT or it must be marked
* as disabled. However omitting non present CPU from apic->type = ACPI_APIC_LOCAL_X2APIC;
* MADT breaks hotplug on linux. So possible CPUs apic->length = sizeof(*apic);
* should be put in MADT but kept disabled. apic->uid = cpu_to_le32(uid);
*/ apic->x2apic_id = cpu_to_le32(apic_id);
apic->flags = cpu_to_le32(0); if (apic_ids->cpus[uid].cpu != NULL) {
apic->flags = cpu_to_le32(1);
} else {
apic->flags = cpu_to_le32(0);
}
} }
} }
@ -369,11 +383,11 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms)
int madt_start = table_data->len; int madt_start = table_data->len;
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(pcms->acpi_dev); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(pcms->acpi_dev);
AcpiDeviceIf *adev = ACPI_DEVICE_IF(pcms->acpi_dev); AcpiDeviceIf *adev = ACPI_DEVICE_IF(pcms->acpi_dev);
bool x2apic_mode = false;
AcpiMultipleApicTable *madt; AcpiMultipleApicTable *madt;
AcpiMadtIoApic *io_apic; AcpiMadtIoApic *io_apic;
AcpiMadtIntsrcovr *intsrcovr; AcpiMadtIntsrcovr *intsrcovr;
AcpiMadtLocalNmi *local_nmi;
int i; int i;
madt = acpi_data_push(table_data, sizeof *madt); madt = acpi_data_push(table_data, sizeof *madt);
@ -382,6 +396,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms)
for (i = 0; i < apic_ids->len; i++) { for (i = 0; i < apic_ids->len; i++) {
adevc->madt_cpu(adev, i, apic_ids, table_data); adevc->madt_cpu(adev, i, apic_ids, table_data);
if (apic_ids->cpus[i].arch_id > 254) {
x2apic_mode = true;
}
} }
g_free(apic_ids); g_free(apic_ids);
@ -414,12 +431,25 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms)
intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */ intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */
} }
local_nmi = acpi_data_push(table_data, sizeof *local_nmi); if (x2apic_mode) {
local_nmi->type = ACPI_APIC_LOCAL_NMI; AcpiMadtLocalX2ApicNmi *local_nmi;
local_nmi->length = sizeof(*local_nmi);
local_nmi->processor_id = 0xff; /* all processors */ local_nmi = acpi_data_push(table_data, sizeof *local_nmi);
local_nmi->flags = cpu_to_le16(0); local_nmi->type = ACPI_APIC_LOCAL_X2APIC_NMI;
local_nmi->lint = 1; /* ACPI_LINT1 */ local_nmi->length = sizeof(*local_nmi);
local_nmi->uid = 0xFFFFFFFF; /* all processors */
local_nmi->flags = cpu_to_le16(0);
local_nmi->lint = 1; /* ACPI_LINT1 */
} else {
AcpiMadtLocalNmi *local_nmi;
local_nmi = acpi_data_push(table_data, sizeof *local_nmi);
local_nmi->type = ACPI_APIC_LOCAL_NMI;
local_nmi->length = sizeof(*local_nmi);
local_nmi->processor_id = 0xff; /* all processors */
local_nmi->flags = cpu_to_le16(0);
local_nmi->lint = 1; /* ACPI_LINT1 */
}
build_header(linker, table_data, build_header(linker, table_data,
(void *)(table_data->data + madt_start), "APIC", (void *)(table_data->data + madt_start), "APIC",

View File

@ -343,6 +343,24 @@ struct AcpiMadtLocalNmi {
} QEMU_PACKED; } QEMU_PACKED;
typedef struct AcpiMadtLocalNmi AcpiMadtLocalNmi; typedef struct AcpiMadtLocalNmi AcpiMadtLocalNmi;
struct AcpiMadtProcessorX2Apic {
ACPI_SUB_HEADER_DEF
uint16_t reserved;
uint32_t x2apic_id; /* Processor's local x2APIC ID */
uint32_t flags;
uint32_t uid; /* Processor object _UID */
} QEMU_PACKED;
typedef struct AcpiMadtProcessorX2Apic AcpiMadtProcessorX2Apic;
struct AcpiMadtLocalX2ApicNmi {
ACPI_SUB_HEADER_DEF
uint16_t flags; /* MPS INTI flags */
uint32_t uid; /* Processor object _UID */
uint8_t lint; /* Local APIC LINT# */
uint8_t reserved[3]; /* Local APIC LINT# */
} QEMU_PACKED;
typedef struct AcpiMadtLocalX2ApicNmi AcpiMadtLocalX2ApicNmi;
struct AcpiMadtGenericInterrupt { struct AcpiMadtGenericInterrupt {
ACPI_SUB_HEADER_DEF ACPI_SUB_HEADER_DEF
uint16_t reserved; uint16_t reserved;