From patchwork Tue Apr 23 08:29:44 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Igor Mammedov X-Patchwork-Id: 238798 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 8E9B02C0139 for ; Tue, 23 Apr 2013 18:39:07 +1000 (EST) Received: from localhost ([::1]:54870 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UUYkj-0003yI-PR for incoming@patchwork.ozlabs.org; Tue, 23 Apr 2013 04:39:05 -0400 Received: from eggs.gnu.org ([208.118.235.92]:57063) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UUYfI-0006Pe-Qn for qemu-devel@nongnu.org; Tue, 23 Apr 2013 04:33:34 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UUYfH-0001v3-4X for qemu-devel@nongnu.org; Tue, 23 Apr 2013 04:33:28 -0400 Received: from mx1.redhat.com ([209.132.183.28]:49075) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UUYfG-0001us-TT for qemu-devel@nongnu.org; Tue, 23 Apr 2013 04:33:27 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r3N8X3Db009625 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 23 Apr 2013 04:33:03 -0400 Received: from dell-pet610-01.lab.eng.brq.redhat.com (dell-pet610-01.lab.eng.brq.redhat.com [10.34.42.20]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r3N8W6jX017193; Tue, 23 Apr 2013 04:32:58 -0400 From: Igor Mammedov To: qemu-devel@nongnu.org Date: Tue, 23 Apr 2013 10:29:44 +0200 Message-Id: <1366705795-24732-11-git-send-email-imammedo@redhat.com> In-Reply-To: <1366705795-24732-1-git-send-email-imammedo@redhat.com> References: <1366705795-24732-1-git-send-email-imammedo@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: peter.maydell@linaro.org, gleb@redhat.com, mst@redhat.com, jan.kiszka@siemens.com, lcapitulino@redhat.com, blauwirbel@gmail.com, kraxel@redhat.com, quintela@redhat.com, armbru@redhat.com, yang.z.zhang@intel.com, ehabkost@redhat.com, stefano.stabellini@eu.citrix.com, aderumier@odiso.com, anthony.perard@citrix.com, alex.williamson@redhat.com, rth@twiddle.net, kwolf@redhat.com, aliguori@us.ibm.com, claudio.fontana@huawei.com, pbonzini@redhat.com, afaerber@suse.de Subject: [Qemu-devel] [PATCH 10/21] acpi_piix4: add infrastructure to send CPU hot-plug GPE to guest X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org * introduce processor status bitmask visible to guest at 0xaf00 addr, where ACPI asl code expects it * set bit corresponding to APIC ID in processor status bitmask on receiving CPU hot-plug notification * trigger CPU hot-plug SCI, to notify guest about CPU hot-plug event Signed-off-by: Igor Mammedov --- v4: * added spec for QEMU-Seabios interface * added PIIX4_ prefix to PROC_ defines v3: * s/get_firmware_id()/get_arch_id()/ due rebase * s/cpu_add_notifier/cpu_added_notifier/ v2: * use CPUClass.get_firmware_id() to make code target independent * bump up vmstate_acpi version --- docs/specs/acpi_cpu_hotplug.txt | 22 +++++++ hw/acpi/piix4.c | 117 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 docs/specs/acpi_cpu_hotplug.txt diff --git a/docs/specs/acpi_cpu_hotplug.txt b/docs/specs/acpi_cpu_hotplug.txt new file mode 100644 index 0000000..5dec0c5 --- /dev/null +++ b/docs/specs/acpi_cpu_hotplug.txt @@ -0,0 +1,22 @@ +QEMU<->ACPI BIOS CPU hotplug interface +-------------------------------------- + +QEMU supports CPU hotplug via ACPI. This document +describes the interface between QEMU and the ACPI BIOS. + +ACPI GPE block (IO ports 0xafe0-0xafe3, byte access): +----------------------------------------- + +Generic ACPI GPE block. Bit 2 (GPE.2) used to notify CPU +hot-add/remove event to ACPI BIOS, via SCI interrupt. + +CPU present bitmap (IO port 0xaf00-0xae1f, 1-byte access): +--------------------------------------------------------------- +One bit per CPU. Bit position reflects corresponding CPU APIC ID. +Read-only. + +CPU hot-add/remove notification: +----------------------------------------------------- +QEMU sets/clears corresponding CPU bit on hot-add/remove event. +CPU present map read by ACPI BIOS GPE.2 handler to notify OS of CPU +hot-(un)plug events. diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 88386d7..b845123 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -48,19 +48,28 @@ #define PCI_EJ_BASE 0xae08 #define PCI_RMV_BASE 0xae0c +#define PIIX4_PROC_BASE 0xaf00 +#define PIIX4_PROC_LEN 32 + #define PIIX4_PCI_HOTPLUG_STATUS 2 +#define PIIX4_CPU_HOTPLUG_STATUS 4 struct pci_status { uint32_t up; /* deprecated, maintained for migration compatibility */ uint32_t down; }; +struct cpu_status { + uint8_t sts[PIIX4_PROC_LEN]; +}; + typedef struct PIIX4PMState { PCIDevice dev; MemoryRegion io; MemoryRegion io_gpe; MemoryRegion io_pci; + MemoryRegion io_cpu; ACPIREGS ar; APMState apm; @@ -82,6 +91,9 @@ typedef struct PIIX4PMState { uint8_t disable_s3; uint8_t disable_s4; uint8_t s4_val; + + struct cpu_status gpe_cpu; + Notifier cpu_added_notifier; } PIIX4PMState; static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, @@ -100,8 +112,8 @@ static void pm_update_sci(PIIX4PMState *s) ACPI_BITMASK_POWER_BUTTON_ENABLE | ACPI_BITMASK_GLOBAL_LOCK_ENABLE | ACPI_BITMASK_TIMER_ENABLE)) != 0) || - (((s->ar.gpe.sts[0] & s->ar.gpe.en[0]) - & PIIX4_PCI_HOTPLUG_STATUS) != 0); + (((s->ar.gpe.sts[0] & s->ar.gpe.en[0]) & + (PIIX4_PCI_HOTPLUG_STATUS | PIIX4_CPU_HOTPLUG_STATUS)) != 0); qemu_set_irq(s->irq, sci_level); /* schedule a timer interruption if needed */ @@ -257,6 +269,18 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int version_id) return ret; } +#define VMSTATE_CPU_STATUS_ARRAY(_field, _state) \ + { \ + .name = (stringify(_field)), \ + .version_id = 0, \ + .num = PIIX4_PROC_LEN, \ + .info = &vmstate_info_uint8, \ + .size = sizeof(uint8_t), \ + .flags = VMS_ARRAY, \ + .offset = vmstate_offset_array(_state, _field, uint8_t, \ + PIIX4_PROC_LEN), \ + } + /* 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 @@ -265,7 +289,7 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int version_id) */ static const VMStateDescription vmstate_acpi = { .name = "piix4_pm", - .version_id = 3, + .version_id = 4, .minimum_version_id = 3, .minimum_version_id_old = 1, .load_state_old = acpi_load_old, @@ -281,6 +305,7 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status, struct pci_status), + VMSTATE_CPU_STATUS_ARRAY(gpe_cpu.sts, PIIX4PMState), VMSTATE_END_OF_LIST() } }; @@ -585,6 +610,85 @@ static const MemoryRegionOps piix4_pci_ops = { }, }; +static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned width) +{ + PIIX4PMState *s = opaque; + struct cpu_status *cpus = &s->gpe_cpu; + uint64_t val = cpus->sts[addr]; + + return val; +} + +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 */ +} + +static const MemoryRegionOps cpu_hotplug_ops = { + .read = cpu_status_read, + .write = cpu_status_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +typedef enum { + PLUG, + UNPLUG, +} HotplugEventType; + +static void piix4_cpu_hotplug_req(PIIX4PMState *s, CPUState *cpu, + HotplugEventType action) +{ + struct cpu_status *g = &s->gpe_cpu; + ACPIGPE *gpe = &s->ar.gpe; + CPUClass *k = CPU_GET_CLASS(cpu); + int64_t cpu_id; + + assert(s != NULL); + + *gpe->sts = *gpe->sts | PIIX4_CPU_HOTPLUG_STATUS; + cpu_id = k->get_arch_id(CPU(cpu)); + if (action == PLUG) { + g->sts[cpu_id / 8] |= (1 << (cpu_id % 8)); + } else { + g->sts[cpu_id / 8] &= ~(1 << (cpu_id % 8)); + } + pm_update_sci(s); +} + +static void piix4_cpu_added_req(Notifier *n, void *opaque) +{ + PIIX4PMState *s = container_of(n, PIIX4PMState, cpu_added_notifier); + + piix4_cpu_hotplug_req(s, CPU(opaque), PLUG); +} + +static int piix4_init_cpu_status(Object *obj, void *opaque) +{ + struct cpu_status *g = (struct cpu_status *)opaque; + Object *cpu_obj = object_dynamic_cast(obj, TYPE_CPU); + + if (cpu_obj) { + struct Error *error = NULL; + CPUClass *k = CPU_GET_CLASS(cpu_obj); + int64_t id = k->get_arch_id(CPU(cpu_obj)); + + if (error) { + fprintf(stderr, "failed to initilize CPU status for ACPI: %s\n", + error_get_pretty(error)); + error_free(error); + abort(); + } + g_assert((id / 8) < PIIX4_PROC_LEN); + g->sts[id / 8] |= (1 << (id % 8)); + } + return object_child_foreach(obj, piix4_init_cpu_status, opaque); +} + static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, PCIHotplugState state); @@ -600,6 +704,13 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR, &s->io_pci); pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev); + + piix4_init_cpu_status(qdev_get_machine(), &s->gpe_cpu); + memory_region_init_io(&s->io_cpu, &cpu_hotplug_ops, s, "apci-cpu-hotplug", + PIIX4_PROC_LEN); + memory_region_add_subregion(parent, PIIX4_PROC_BASE, &s->io_cpu); + s->cpu_added_notifier.notify = piix4_cpu_added_req; + qemu_register_cpu_added_notifier(&s->cpu_added_notifier); } static void enable_device(PIIX4PMState *s, int slot)