add 'cpu-del' as complementary of 'cpu-add', cpu-del doesn't really delete a previous created cpu for it depends on CPU-QOM which it's un-finished yet to unrealize it. cpu-del just records the cpu-id that guest want to remove to keep status of ACPI cpu hot-remove process.
Signed-off-by: liguang <lig.f...@cn.fujitsu.com> --- hw/i386/pc.c | 30 ++++++++++++++++++++++++++++-- hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 1 + include/hw/boards.h | 5 +++-- include/hw/i386/pc.h | 1 + qapi-schema.json | 13 +++++++++++++ qmp-commands.hx | 23 +++++++++++++++++++++++ qmp.c | 9 +++++++++ 8 files changed, 79 insertions(+), 4 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 197d218..fa037d8 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -55,6 +55,7 @@ #include "hw/acpi/acpi.h" #include "hw/cpu/icc_bus.h" #include "hw/boards.h" +#include "hw/acpi/ec.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -926,10 +927,15 @@ void pc_hot_add_cpu(const int64_t id, Error **errp) { DeviceState *icc_bridge; int64_t apic_id = x86_cpu_apic_id_from_index(id); + uint8_t cpu_sts = ec_acpi_space_peek(EC_ACPI_SPACE_CPUS); if (cpu_exists(apic_id)) { - error_setg(errp, "Unable to add CPU: %" PRIi64 - ", it already exists", id); + if (cpu_sts & 1 << id) { + error_setg(errp, "Unable to add CPU: %" PRIi64 + ", it already exists", id); + } else { + ec_acpi_space_poke(EC_ACPI_SPACE_CPUS, cpu_sts | 1 << id); + } return; } @@ -939,11 +945,31 @@ void pc_hot_add_cpu(const int64_t id, Error **errp) return; } + ec_acpi_space_poke(EC_ACPI_SPACE_CPUS, cpu_sts | 1 << id); icc_bridge = DEVICE(object_resolve_path_type("icc-bridge", TYPE_ICC_BRIDGE, NULL)); pc_new_cpu(current_cpu_model, apic_id, icc_bridge, errp); } +void pc_hot_del_cpu(const int64_t id, Error **errp) +{ + uint8_t cpu_sts = ec_acpi_space_peek(EC_ACPI_SPACE_CPUS); + + if (id >= max_cpus) { + error_setg(errp, "Unable to del CPU: %" PRIi64 + ", max allowed: %d", id, max_cpus - 1); + return; + } + + if (cpu_sts & 1 << id) { + ec_acpi_space_poke(EC_ACPI_SPACE_CPUS, cpu_sts & ~(1 << id)); + ec_acpi_space_poke(EC_ACPI_SPACE_CPUN, id); + } else { + error_setg(errp, "Unable to del CPU: %" PRIi64 + ", it was not added before.", id); + } +} + void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge) { int i; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 43ab480..f1eb791 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -334,6 +334,7 @@ static QEMUMachine pc_i440fx_machine_v1_5 = { .desc = "Standard PC (i440FX + PIIX, 1996)", .init = pc_init_pci, .hot_add_cpu = pc_hot_add_cpu, + .hot_del_cpu = pc_hot_del_cpu, .max_cpus = 255, .is_default = 1, DEFAULT_MACHINE_OPTIONS, diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 7888dfe..f171ed3 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -221,6 +221,7 @@ static QEMUMachine pc_q35_machine_v1_5 = { .desc = "Standard PC (Q35 + ICH9, 2009)", .init = pc_q35_init, .hot_add_cpu = pc_hot_add_cpu, + .hot_del_cpu = pc_hot_del_cpu, .max_cpus = 255, DEFAULT_MACHINE_OPTIONS, }; diff --git a/include/hw/boards.h b/include/hw/boards.h index fb7c6f1..fc6368a 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -22,7 +22,7 @@ typedef void QEMUMachineInitFunc(QEMUMachineInitArgs *args); typedef void QEMUMachineResetFunc(void); -typedef void QEMUMachineHotAddCPUFunc(const int64_t id, Error **errp); +typedef void QEMUMachineHotAddDelCPUFunc(const int64_t id, Error **errp); typedef struct QEMUMachine { const char *name; @@ -30,7 +30,8 @@ typedef struct QEMUMachine { const char *desc; QEMUMachineInitFunc *init; QEMUMachineResetFunc *reset; - QEMUMachineHotAddCPUFunc *hot_add_cpu; + QEMUMachineHotAddDelCPUFunc *hot_add_cpu; + QEMUMachineHotAddDelCPUFunc *hot_del_cpu; BlockInterfaceType block_default_type; int max_cpus; unsigned int no_serial:1, diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 663426c..8123e62 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -79,6 +79,7 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level); void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge); void pc_hot_add_cpu(const int64_t id, Error **errp); +void pc_hot_del_cpu(const int64_t id, Error **errp); void pc_acpi_init(const char *default_dsdt); void *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, diff --git a/qapi-schema.json b/qapi-schema.json index ef1f657..d11e43b 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1403,6 +1403,19 @@ { 'command': 'cpu-add', 'data': {'id': 'int'} } ## +# @cpu-del +# +# Deletes CPU with specified ID +# +# @id: ID of CPU to be created, valid values [0..max_cpus) +# +# Returns: Nothing on success +# +# Since 1.6 +## +{ 'command': 'cpu-del', 'data': {'id': 'int'} } + +## # @memsave: # # Save a portion of guest memory to a file. diff --git a/qmp-commands.hx b/qmp-commands.hx index ffd130e..c4e77b4 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -408,6 +408,29 @@ Example: EQMP { + .name = "cpu-del", + .args_type = "id:i", + .mhandler.cmd_new = qmp_marshal_input_cpu_del, + }, + +SQMP +cpu-del +------- + +Deletes virtual cpu + +Arguments: + +- "id": cpu id (json-int) + +Example: + +-> { "execute": "cpu-del", "arguments": { "id": 2 } } +<- { "return": {} } + +EQMP + + { .name = "memsave", .args_type = "val:l,size:i,filename:s,cpu:i?", .mhandler.cmd_new = qmp_marshal_input_memsave, diff --git a/qmp.c b/qmp.c index 4c149b3..84dc873 100644 --- a/qmp.c +++ b/qmp.c @@ -118,6 +118,15 @@ void qmp_cpu_add(int64_t id, Error **errp) } } +void qmp_cpu_del(int64_t id, Error **errp) +{ + if (current_machine->hot_del_cpu) { + current_machine->hot_del_cpu(id, errp); + } else { + error_setg(errp, "Not supported"); + } +} + #ifndef CONFIG_VNC /* If VNC support is enabled, the "true" query-vnc command is defined in the VNC subsystem */ -- 1.7.2.5