On Mon, 30 May 2016 21:50:08 +0300 Marcel Apfelbaum <mar...@redhat.com> wrote:
> On 05/17/2016 05:43 PM, Igor Mammedov wrote: > > Signed-off-by: Igor Mammedov <imamm...@redhat.com> > > Maybe it worth adding some kind of explanation > of the functionality added here. I'll add a bit more detailed explanation here > Thanks, > Marcel > > > --- > > v1: > > - drop CPUHotplugState.is_enabled field > > --- > > hw/acpi/Makefile.objs | 1 + > > hw/acpi/cpu.c | 206 > > ++++++++++++++++++++++++++++++++++++++++++++++++++ > > include/hw/acpi/cpu.h | 52 +++++++++++++ > > trace-events | 9 +++ > > 4 files changed, 268 insertions(+) > > create mode 100644 hw/acpi/cpu.c > > create mode 100644 include/hw/acpi/cpu.h > > > > diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs > > index 66bd727..f200419 100644 > > --- a/hw/acpi/Makefile.objs > > +++ b/hw/acpi/Makefile.objs > > @@ -2,6 +2,7 @@ common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o > > common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o > > common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o > > common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o > > memory_hotplug_acpi_table.o > > +common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o > > obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o > > common-obj-$(CONFIG_ACPI) += acpi_interface.o > > common-obj-$(CONFIG_ACPI) += bios-linker-loader.o > > diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c > > new file mode 100644 > > index 0000000..171a5f5 > > --- /dev/null > > +++ b/hw/acpi/cpu.c > > @@ -0,0 +1,206 @@ > > +#include "qemu/osdep.h" > > +#include "hw/boards.h" > > +#include "hw/acpi/cpu.h" > > +#include "qapi/error.h" > > +#include "trace.h" > > + > > +#define ACPI_CPU_HOTPLUG_REG_LEN 12 > > +#define ACPI_CPU_SELECTOR_OFFSET_WR 0 > > +#define ACPI_CPU_FLAGS_OFFSET_RW 4 > > + > > +static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size) > > +{ > > + uint64_t val = ~0; > > + CPUHotplugState *cpu_st = opaque; > > + AcpiCpuStatus *cdev; > > + > > + if (cpu_st->selector >= cpu_st->dev_count) { > > + return val; > > + } > > + > > + cdev = &cpu_st->devs[cpu_st->selector]; > > + switch (addr) { > > + case ACPI_CPU_FLAGS_OFFSET_RW: /* pack and return is_* fields */ > > + val = 0; > > + val |= cdev->is_enabled ? 1 : 0; > > + val |= cdev->is_inserting ? 2 : 0; > > + val |= cdev->is_removing ? 4 : 0; > > + trace_cpuhp_acpi_read_flags(cpu_st->selector, val); > > + break; > > + default: > > + break; > > + } > > + return val; > > +} > > + > > +static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data, > > + unsigned int size) > > +{ > > + CPUHotplugState *cpu_st = opaque; > > + AcpiCpuStatus *cdev; > > + Error *local_err = NULL; > > + > > + assert(cpu_st->dev_count); > > + > > + if (addr) { > > + if (cpu_st->selector >= cpu_st->dev_count) { > > + trace_cpuhp_acpi_invalid_idx_selected(cpu_st->selector); > > + return; > > + } > > + } > > + > > + switch (addr) { > > + case ACPI_CPU_SELECTOR_OFFSET_WR: /* current CPU selector */ > > + cpu_st->selector = data; > > + trace_cpuhp_acpi_write_idx(cpu_st->selector); > > + break; > > + case ACPI_CPU_FLAGS_OFFSET_RW: /* set is_* fields */ > > + cdev = &cpu_st->devs[cpu_st->selector]; > > + if (data & 2) { /* clear insert event */ > > + cdev->is_inserting = false; > > + trace_cpuhp_acpi_clear_inserting_evt(cpu_st->selector); > > + } else if (data & 4) { /* clear remove event */ > > + cdev->is_removing = false; > > + trace_cpuhp_acpi_clear_remove_evt(cpu_st->selector); > > + } else if (data & 8) { > > + DeviceState *dev = NULL; > > + HotplugHandler *hotplug_ctrl = NULL; > > + > > + if (!cdev->is_enabled) { > > + trace_cpuhp_acpi_ejecting_invalid_cpu(cpu_st->selector); > > + break; > > + } > > + > > + trace_cpuhp_acpi_ejecting_cpu(cpu_st->selector); > > + dev = DEVICE(cdev->cpu); > > + hotplug_ctrl = qdev_get_hotplug_handler(dev); > > + hotplug_handler_unplug(hotplug_ctrl, dev, &local_err); > > + if (local_err) { > > + break; > > + } > > + } > > + break; > > + default: > > + break; > > + } > > + error_free(local_err); > > +} > > + > > +static const MemoryRegionOps cpu_hotplug_ops = { > > + .read = cpu_hotplug_rd, > > + .write = cpu_hotplug_wr, > > + .endianness = DEVICE_LITTLE_ENDIAN, > > + .valid = { > > + .min_access_size = 1, > > + .max_access_size = 4, > > + }, > > +}; > > + > > +void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, > > + CPUHotplugState *state, hwaddr base_addr) > > +{ > > + MachineState *machine = MACHINE(qdev_get_machine()); > > + MachineClass *mc = MACHINE_GET_CLASS(machine); > > + CPUArchIdList *id_list; > > + int i; > > + > > + id_list = mc->possible_cpu_arch_ids(machine); > > + state->dev_count = id_list->len; > > + state->devs = g_new0(typeof(*state->devs), state->dev_count); > > + for (i = 0; i < id_list->len; i++) { > > + state->devs[i].cpu = id_list->cpus[i].cpu; > > + state->devs[i].arch_id = id_list->cpus[i].arch_id; > > + state->devs[i].is_enabled = id_list->cpus[i].cpu ? true : false; > > + } > > + g_free(id_list); > > + memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state, > > + "acpi-mem-hotplug", ACPI_CPU_HOTPLUG_REG_LEN); > > + memory_region_add_subregion(as, base_addr, &state->ctrl_reg); > > +} > > + > > +static AcpiCpuStatus *get_cpu_status(CPUHotplugState *cpu_st, DeviceState > > *dev) > > +{ > > + CPUClass *k = CPU_GET_CLASS(dev); > > + uint64_t cpu_arch_id = k->get_arch_id(CPU(dev)); > > + int i; > > + > > + for (i = 0; i < cpu_st->dev_count; i++) { > > + if (cpu_arch_id == cpu_st->devs[i].arch_id) { > > + return &cpu_st->devs[i]; > > + } > > + } > > + return NULL; > > +} > > + > > +void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev, > > + CPUHotplugState *cpu_st, DeviceState *dev, Error > > **errp) > > +{ > > + AcpiCpuStatus *cdev; > > + > > + cdev = get_cpu_status(cpu_st, dev); > > + if (!cdev) { > > + return; > > + } > > + > > + cdev->cpu = CPU(dev); > > + cdev->is_enabled = true; > > + if (dev->hotplugged) { > > + cdev->is_inserting = true; > > + ACPI_SEND_EVENT(hotplug_dev, ACPI_CPU_HOTPLUG_STATUS); > > + } > > +} > > + > > +void acpi_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, > > + CPUHotplugState *cpu_st, > > + DeviceState *dev, Error **errp) > > +{ > > + AcpiCpuStatus *cdev; > > + > > + cdev = get_cpu_status(cpu_st, dev); > > + if (!cdev) { > > + return; > > + } > > + > > + cdev->is_removing = true; > > + ACPI_SEND_EVENT(hotplug_dev, ACPI_CPU_HOTPLUG_STATUS); > > +} > > + > > +void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st, > > + DeviceState *dev, Error **errp) > > +{ > > + AcpiCpuStatus *cdev; > > + > > + cdev = get_cpu_status(cpu_st, dev); > > + if (!cdev) { > > + return; > > + } > > + > > + cdev->cpu = NULL; > > + cdev->is_enabled = false; > > +} > > + > > +static const VMStateDescription vmstate_cpuhp_sts = { > > + .name = "CPU hotplug device state", > > + .version_id = 1, > > + .minimum_version_id = 1, > > + .minimum_version_id_old = 1, > > + .fields = (VMStateField[]) { > > + VMSTATE_BOOL(is_enabled, AcpiCpuStatus), > > + VMSTATE_BOOL(is_inserting, AcpiCpuStatus), > > + VMSTATE_BOOL(is_removing, AcpiCpuStatus), > > + VMSTATE_END_OF_LIST() > > + } > > +}; > > + > > +const VMStateDescription vmstate_cpu_hotplug = { > > + .name = "CPU hotplug state", > > + .version_id = 1, > > + .minimum_version_id = 1, > > + .minimum_version_id_old = 1, > > + .fields = (VMStateField[]) { > > + VMSTATE_UINT32(selector, CPUHotplugState), > > + VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, CPUHotplugState, > > dev_count, > > + vmstate_cpuhp_sts, > > AcpiCpuStatus), > > + VMSTATE_END_OF_LIST() > > + } > > +}; > > diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h > > new file mode 100644 > > index 0000000..3fdf4eb > > --- /dev/null > > +++ b/include/hw/acpi/cpu.h > > @@ -0,0 +1,52 @@ > > +/* > > + * QEMU ACPI hotplug utilities > > + * > > + * Copyright (C) 2016 Red Hat Inc > > + * > > + * Authors: > > + * Igor Mammedov <imamm...@redhat.com> > > + * > > + * This work is licensed under the terms of the GNU GPL, version 2 or > > later. > > + * See the COPYING file in the top-level directory. > > + */ > > +#ifndef ACPI_CPU_H > > +#define ACPI_CPU_H > > + > > +#include "hw/qdev-core.h" > > +#include "hw/acpi/acpi.h" > > +#include "hw/hotplug.h" > > + > > +typedef struct AcpiCpuStatus { > > + struct CPUState *cpu; > > + uint64_t arch_id; > > + bool is_enabled; > > + bool is_inserting; > > + bool is_removing; > > +} AcpiCpuStatus; > > + > > +typedef struct CPUHotplugState { > > + MemoryRegion ctrl_reg; > > + uint32_t selector; > > + uint32_t dev_count; > > + AcpiCpuStatus *devs; > > +} CPUHotplugState; > > + > > +void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev, > > + CPUHotplugState *cpu_st, DeviceState *dev, Error > > **errp); > > + > > +void acpi_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, > > + CPUHotplugState *cpu_st, > > + DeviceState *dev, Error **errp); > > + > > +void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st, > > + DeviceState *dev, Error **errp); > > + > > +void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, > > + CPUHotplugState *state, hwaddr base_addr); > > + > > +extern const VMStateDescription vmstate_cpu_hotplug; > > +#define VMSTATE_CPU_HOTPLUG(cpuhp, state) \ > > + VMSTATE_STRUCT(cpuhp, state, 1, \ > > + vmstate_cpu_hotplug, CPUHotplugState) > > + > > +#endif > > diff --git a/trace-events b/trace-events > > index 4fce005..7101ba9 100644 > > --- a/trace-events > > +++ b/trace-events > > @@ -1908,3 +1908,12 @@ aspeed_vic_update_fiq(int flags) "Raising FIQ: %d" > > aspeed_vic_update_irq(int flags) "Raising IRQ: %d" > > aspeed_vic_read(uint64_t offset, unsigned size, uint32_t value) "From > > 0x%" PRIx64 " of size %u: 0x%" PRIx32 > > aspeed_vic_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" > > PRIx64 " of size %u: 0x%" PRIx32 > > + > > +# hw/acpi/cpu.c > > +cpuhp_acpi_invalid_idx_selected(uint32_t idx) "0x%"PRIx32 > > +cpuhp_acpi_read_flags(uint32_t idx, uint8_t flags) "idx[0x%"PRIx32"] > > flags: 0x%"PRIx8 > > +cpuhp_acpi_clear_inserting_evt(uint32_t idx) "idx[0x%"PRIx32"]" > > +cpuhp_acpi_clear_remove_evt(uint32_t idx) "idx[0x%"PRIx32"]" > > +cpuhp_acpi_write_idx(uint32_t idx) "set active cpu idx: 0x%"PRIx32 > > +cpuhp_acpi_ejecting_invalid_cpu(uint32_t idx) "0x%"PRIx32 > > +cpuhp_acpi_ejecting_cpu(uint32_t idx) "0x%"PRIx32 > > > >