pc: use new CPU hotplug interface since 2.7 machine type
For compatibility reasons PC/Q35 will start with legacy CPU hotplug interface by default but with new CPU hotplug AML code since 2.7 machine type. That way legacy firmware that doesn't use QEMU generated ACPI tables will be able to continue using legacy CPU hotplug interface. While new machine type, with firmware supporting QEMU provided ACPI tables, will generate new CPU hotplug AML, which will switch to new CPU hotplug interface when guest OS executes its _INI method on ACPI tables loading. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
76623d00ae
commit
679dd1a957
|
@ -373,6 +373,15 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||||
aml_append(field, aml_named_field(CPU_DATA, 32));
|
aml_append(field, aml_named_field(CPU_DATA, 32));
|
||||||
aml_append(cpu_ctrl_dev, field);
|
aml_append(cpu_ctrl_dev, field);
|
||||||
|
|
||||||
|
if (opts.has_legacy_cphp) {
|
||||||
|
method = aml_method("_INI", 0, AML_SERIALIZED);
|
||||||
|
/* switch off legacy CPU hotplug HW and use new one,
|
||||||
|
* on reboot system is in new mode and writing 0
|
||||||
|
* in CPU_SELECTOR selects BSP, which is NOP at
|
||||||
|
* the time _INI is called */
|
||||||
|
aml_append(method, aml_store(zero, aml_name(CPU_SELECTOR)));
|
||||||
|
aml_append(cpu_ctrl_dev, method);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
aml_append(sb_scope, cpu_ctrl_dev);
|
aml_append(sb_scope, cpu_ctrl_dev);
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,15 @@ static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size)
|
||||||
static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data,
|
static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data,
|
||||||
unsigned int size)
|
unsigned int size)
|
||||||
{
|
{
|
||||||
/* TODO: implement VCPU removal on guest signal that CPU can be removed */
|
/* firmware never used to write in CPU present bitmap so use
|
||||||
|
this fact as means to switch QEMU into modern CPU hotplug
|
||||||
|
mode by writing 0 at the beginning of legacy CPU bitmap
|
||||||
|
*/
|
||||||
|
if (addr == 0 && data == 0) {
|
||||||
|
AcpiCpuHotplug *cpus = opaque;
|
||||||
|
object_property_set_bool(cpus->device, false, "cpu-hotplug-legacy",
|
||||||
|
&error_abort);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps AcpiCpuHotplug_ops = {
|
static const MemoryRegionOps AcpiCpuHotplug_ops = {
|
||||||
|
@ -83,6 +91,17 @@ void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
|
||||||
memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops,
|
memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops,
|
||||||
gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN);
|
gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN);
|
||||||
memory_region_add_subregion(parent, base, &gpe_cpu->io);
|
memory_region_add_subregion(parent, base, &gpe_cpu->io);
|
||||||
|
gpe_cpu->device = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_switch_to_modern_cphp(AcpiCpuHotplug *gpe_cpu,
|
||||||
|
CPUHotplugState *cpuhp_state,
|
||||||
|
uint16_t io_port)
|
||||||
|
{
|
||||||
|
MemoryRegion *parent = pci_address_space_io(PCI_DEVICE(gpe_cpu->device));
|
||||||
|
|
||||||
|
memory_region_del_subregion(parent, &gpe_cpu->io);
|
||||||
|
cpu_hotplug_hw_init(parent, gpe_cpu->device, cpuhp_state, io_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine,
|
void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine,
|
||||||
|
|
|
@ -189,6 +189,33 @@ static const VMStateDescription vmstate_tco_io_state = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool vmstate_test_use_cpuhp(void *opaque)
|
||||||
|
{
|
||||||
|
ICH9LPCPMRegs *s = opaque;
|
||||||
|
return !s->cpu_hotplug_legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vmstate_cpuhp_pre_load(void *opaque)
|
||||||
|
{
|
||||||
|
ICH9LPCPMRegs *s = opaque;
|
||||||
|
Object *obj = OBJECT(s->gpe_cpu.device);
|
||||||
|
object_property_set_bool(obj, false, "cpu-hotplug-legacy", &error_abort);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_cpuhp_state = {
|
||||||
|
.name = "ich9_pm/cpuhp",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.needed = vmstate_test_use_cpuhp,
|
||||||
|
.pre_load = vmstate_cpuhp_pre_load,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_CPU_HOTPLUG(cpuhp_state, ICH9LPCPMRegs),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_ich9_pm = {
|
const VMStateDescription vmstate_ich9_pm = {
|
||||||
.name = "ich9_pm",
|
.name = "ich9_pm",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
|
@ -209,6 +236,7 @@ const VMStateDescription vmstate_ich9_pm = {
|
||||||
.subsections = (const VMStateDescription*[]) {
|
.subsections = (const VMStateDescription*[]) {
|
||||||
&vmstate_memhp_state,
|
&vmstate_memhp_state,
|
||||||
&vmstate_tco_io_state,
|
&vmstate_tco_io_state,
|
||||||
|
&vmstate_cpuhp_state,
|
||||||
NULL
|
NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -318,6 +346,11 @@ static void ich9_pm_set_cpu_hotplug_legacy(Object *obj, bool value,
|
||||||
{
|
{
|
||||||
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
||||||
|
|
||||||
|
assert(!value);
|
||||||
|
if (s->pm.cpu_hotplug_legacy && value == false) {
|
||||||
|
acpi_switch_to_modern_cphp(&s->pm.gpe_cpu, &s->pm.cpuhp_state,
|
||||||
|
ICH9_CPU_HOTPLUG_IO_BASE);
|
||||||
|
}
|
||||||
s->pm.cpu_hotplug_legacy = value;
|
s->pm.cpu_hotplug_legacy = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -276,6 +276,32 @@ static const VMStateDescription vmstate_memhp_state = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool vmstate_test_use_cpuhp(void *opaque)
|
||||||
|
{
|
||||||
|
PIIX4PMState *s = opaque;
|
||||||
|
return !s->cpu_hotplug_legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vmstate_cpuhp_pre_load(void *opaque)
|
||||||
|
{
|
||||||
|
Object *obj = OBJECT(opaque);
|
||||||
|
object_property_set_bool(obj, false, "cpu-hotplug-legacy", &error_abort);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_cpuhp_state = {
|
||||||
|
.name = "piix4_pm/cpuhp",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.needed = vmstate_test_use_cpuhp,
|
||||||
|
.pre_load = vmstate_cpuhp_pre_load,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_CPU_HOTPLUG(cpuhp_state, PIIX4PMState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* qemu-kvm 1.2 uses version 3 but advertised as 2
|
/* qemu-kvm 1.2 uses version 3 but advertised as 2
|
||||||
* To support incoming qemu-kvm 1.2 migration, change version_id
|
* To support incoming qemu-kvm 1.2 migration, change version_id
|
||||||
* and minimum_version_id to 2 below (which breaks migration from
|
* and minimum_version_id to 2 below (which breaks migration from
|
||||||
|
@ -310,6 +336,7 @@ static const VMStateDescription vmstate_acpi = {
|
||||||
},
|
},
|
||||||
.subsections = (const VMStateDescription*[]) {
|
.subsections = (const VMStateDescription*[]) {
|
||||||
&vmstate_memhp_state,
|
&vmstate_memhp_state,
|
||||||
|
&vmstate_cpuhp_state,
|
||||||
NULL
|
NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -585,6 +612,11 @@ static void piix4_set_cpu_hotplug_legacy(Object *obj, bool value, Error **errp)
|
||||||
{
|
{
|
||||||
PIIX4PMState *s = PIIX4_PM(obj);
|
PIIX4PMState *s = PIIX4_PM(obj);
|
||||||
|
|
||||||
|
assert(!value);
|
||||||
|
if (s->cpu_hotplug_legacy && value == false) {
|
||||||
|
acpi_switch_to_modern_cphp(&s->gpe_cpu, &s->cpuhp_state,
|
||||||
|
PIIX4_CPU_HOTPLUG_IO_BASE);
|
||||||
|
}
|
||||||
s->cpu_hotplug_legacy = value;
|
s->cpu_hotplug_legacy = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "hw/timer/hpet.h"
|
#include "hw/timer/hpet.h"
|
||||||
#include "hw/acpi/acpi-defs.h"
|
#include "hw/acpi/acpi-defs.h"
|
||||||
#include "hw/acpi/acpi.h"
|
#include "hw/acpi/acpi.h"
|
||||||
|
#include "hw/acpi/cpu.h"
|
||||||
#include "hw/nvram/fw_cfg.h"
|
#include "hw/nvram/fw_cfg.h"
|
||||||
#include "hw/acpi/bios-linker-loader.h"
|
#include "hw/acpi/bios-linker-loader.h"
|
||||||
#include "hw/loader.h"
|
#include "hw/loader.h"
|
||||||
|
@ -1895,6 +1896,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||||
GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||||
GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||||
PCMachineState *pcms = PC_MACHINE(machine);
|
PCMachineState *pcms = PC_MACHINE(machine);
|
||||||
|
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(machine);
|
||||||
uint32_t nr_mem = machine->ram_slots;
|
uint32_t nr_mem = machine->ram_slots;
|
||||||
int root_bus_limit = 0xFF;
|
int root_bus_limit = 0xFF;
|
||||||
PCIBus *bus = NULL;
|
PCIBus *bus = NULL;
|
||||||
|
@ -1950,7 +1952,15 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||||
build_q35_pci0_int(dsdt);
|
build_q35_pci0_int(dsdt);
|
||||||
}
|
}
|
||||||
|
|
||||||
build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base);
|
if (pcmc->legacy_cpu_hotplug) {
|
||||||
|
build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base);
|
||||||
|
} else {
|
||||||
|
CPUHotplugFeatures opts = {
|
||||||
|
.apci_1_compatible = true, .has_legacy_cphp = true
|
||||||
|
};
|
||||||
|
build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base,
|
||||||
|
"\\_SB.PCI0", "\\_GPE._E02");
|
||||||
|
}
|
||||||
build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base,
|
build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base,
|
||||||
pm->mem_hp_io_len);
|
pm->mem_hp_io_len);
|
||||||
|
|
||||||
|
|
|
@ -445,9 +445,11 @@ DEFINE_I440FX_MACHINE(v2_7, "pc-i440fx-2.7", NULL,
|
||||||
|
|
||||||
static void pc_i440fx_2_6_machine_options(MachineClass *m)
|
static void pc_i440fx_2_6_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
|
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||||
pc_i440fx_2_7_machine_options(m);
|
pc_i440fx_2_7_machine_options(m);
|
||||||
m->is_default = 0;
|
m->is_default = 0;
|
||||||
m->alias = NULL;
|
m->alias = NULL;
|
||||||
|
pcmc->legacy_cpu_hotplug = true;
|
||||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -294,8 +294,10 @@ DEFINE_Q35_MACHINE(v2_7, "pc-q35-2.7", NULL,
|
||||||
|
|
||||||
static void pc_q35_2_6_machine_options(MachineClass *m)
|
static void pc_q35_2_6_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
|
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||||
pc_q35_2_7_machine_options(m);
|
pc_q35_2_7_machine_options(m);
|
||||||
m->alias = NULL;
|
m->alias = NULL;
|
||||||
|
pcmc->legacy_cpu_hotplug = true;
|
||||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
|
||||||
|
|
||||||
typedef struct CPUHotplugFeatures {
|
typedef struct CPUHotplugFeatures {
|
||||||
bool apci_1_compatible;
|
bool apci_1_compatible;
|
||||||
|
bool has_legacy_cphp;
|
||||||
} CPUHotplugFeatures;
|
} CPUHotplugFeatures;
|
||||||
|
|
||||||
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
#include "hw/acpi/pc-hotplug.h"
|
#include "hw/acpi/pc-hotplug.h"
|
||||||
#include "hw/acpi/aml-build.h"
|
#include "hw/acpi/aml-build.h"
|
||||||
#include "hw/hotplug.h"
|
#include "hw/hotplug.h"
|
||||||
|
#include "hw/acpi/cpu.h"
|
||||||
|
|
||||||
typedef struct AcpiCpuHotplug {
|
typedef struct AcpiCpuHotplug {
|
||||||
|
Object *device;
|
||||||
MemoryRegion io;
|
MemoryRegion io;
|
||||||
uint8_t sts[ACPI_GPE_PROC_LEN];
|
uint8_t sts[ACPI_GPE_PROC_LEN];
|
||||||
} AcpiCpuHotplug;
|
} AcpiCpuHotplug;
|
||||||
|
@ -28,6 +30,10 @@ void legacy_acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
|
||||||
void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
|
void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
|
||||||
AcpiCpuHotplug *gpe_cpu, uint16_t base);
|
AcpiCpuHotplug *gpe_cpu, uint16_t base);
|
||||||
|
|
||||||
|
void acpi_switch_to_modern_cphp(AcpiCpuHotplug *gpe_cpu,
|
||||||
|
CPUHotplugState *cpuhp_state,
|
||||||
|
uint16_t io_port);
|
||||||
|
|
||||||
void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine,
|
void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine,
|
||||||
uint16_t io_base);
|
uint16_t io_base);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -137,6 +137,8 @@ struct PCMachineClass {
|
||||||
|
|
||||||
/* TSC rate migration: */
|
/* TSC rate migration: */
|
||||||
bool save_tsc_khz;
|
bool save_tsc_khz;
|
||||||
|
/* generate legacy CPU hotplug AML */
|
||||||
|
bool legacy_cpu_hotplug;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TYPE_PC_MACHINE "generic-pc-machine"
|
#define TYPE_PC_MACHINE "generic-pc-machine"
|
||||||
|
|
Loading…
Reference in New Issue