aboutsummaryrefslogtreecommitdiff
path: root/hw/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'hw/acpi')
-rw-r--r--hw/acpi/cpu.c9
-rw-r--r--hw/acpi/cpu_hotplug.c21
-rw-r--r--hw/acpi/ich9.c33
-rw-r--r--hw/acpi/piix4.c32
4 files changed, 94 insertions, 1 deletions
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 401ac0d..c13b65c 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -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(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);
diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c
index fe75bd9..e19d902 100644
--- a/hw/acpi/cpu_hotplug.c
+++ b/hw/acpi/cpu_hotplug.c
@@ -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,
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 = {
@@ -83,6 +91,17 @@ void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops,
gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN);
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,
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index d12cc62..e5a3c18 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -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 = {
.name = "ich9_pm",
.version_id = 1,
@@ -209,6 +236,7 @@ const VMStateDescription vmstate_ich9_pm = {
.subsections = (const VMStateDescription*[]) {
&vmstate_memhp_state,
&vmstate_tco_io_state,
+ &vmstate_cpuhp_state,
NULL
}
};
@@ -318,6 +346,11 @@ static void ich9_pm_set_cpu_hotplug_legacy(Object *obj, bool value,
{
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;
}
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 858244a..2adc246 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -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
* To support incoming qemu-kvm 1.2 migration, change version_id
* and minimum_version_id to 2 below (which breaks migration from
@@ -310,6 +336,7 @@ static const VMStateDescription vmstate_acpi = {
},
.subsections = (const VMStateDescription*[]) {
&vmstate_memhp_state,
+ &vmstate_cpuhp_state,
NULL
}
};
@@ -585,6 +612,11 @@ static void piix4_set_cpu_hotplug_legacy(Object *obj, bool value, Error **errp)
{
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;
}