From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44013) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b7SGg-0001v1-QC for qemu-devel@nongnu.org; Mon, 30 May 2016 14:50:28 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1b7SGd-0008Bv-K5 for qemu-devel@nongnu.org; Mon, 30 May 2016 14:50:26 -0400 Received: from mx1.redhat.com ([209.132.183.28]:49134) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b7SGd-0008Bq-Bj for qemu-devel@nongnu.org; Mon, 30 May 2016 14:50:23 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A93A8C05B1C7 for ; Mon, 30 May 2016 18:50:22 +0000 (UTC) References: <1463496205-251412-1-git-send-email-imammedo@redhat.com> <1463496205-251412-17-git-send-email-imammedo@redhat.com> From: Marcel Apfelbaum Message-ID: <574C8B60.5020809@redhat.com> Date: Mon, 30 May 2016 21:50:08 +0300 MIME-Version: 1.0 In-Reply-To: <1463496205-251412-17-git-send-email-imammedo@redhat.com> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH 16/33] acpi: hardware side of CPU hotplug List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Igor Mammedov , qemu-devel@nongnu.org Cc: mst@redhat.com, rkrcmar@redhat.com, ehabkost@redhat.com, drjones@redhat.com, armbru@redhat.com On 05/17/2016 05:43 PM, Igor Mammedov wrote: > Signed-off-by: Igor Mammedov Maybe it worth adding some kind of explanation of the functionality added 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 > + * > + * 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 >