qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Igor Mammedov <imammedo@redhat.com>
To: Salil Mehta <salil.mehta@huawei.com>
Cc: "salil.mehta@opnsrc.net" <salil.mehta@opnsrc.net>,
	"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>,
	"qemu-arm@nongnu.org" <qemu-arm@nongnu.org>,
	"mst@redhat.com" <mst@redhat.com>,
	"maz@kernel.org" <maz@kernel.org>,
	"jean-philippe@linaro.org" <jean-philippe@linaro.org>,
	Jonathan Cameron <jonathan.cameron@huawei.com>,
	"lpieralisi@kernel.org" <lpieralisi@kernel.org>,
	"peter.maydell@linaro.org" <peter.maydell@linaro.org>,
	"richard.henderson@linaro.org" <richard.henderson@linaro.org>,
	"armbru@redhat.com" <armbru@redhat.com>,
	"andrew.jones@linux.dev" <andrew.jones@linux.dev>,
	"david@redhat.com" <david@redhat.com>,
	"philmd@linaro.org" <philmd@linaro.org>,
	"eric.auger@redhat.com" <eric.auger@redhat.com>,
	"will@kernel.org" <will@kernel.org>,
	"ardb@kernel.org" <ardb@kernel.org>,
	"oliver.upton@linux.dev" <oliver.upton@linux.dev>,
	"pbonzini@redhat.com" <pbonzini@redhat.com>,
	"gshan@redhat.com" <gshan@redhat.com>,
	"rafael@kernel.org" <rafael@kernel.org>,
	"borntraeger@linux.ibm.com" <borntraeger@linux.ibm.com>,
	"alex.bennee@linaro.org" <alex.bennee@linaro.org>,
	"gustavo.romero@linaro.org" <gustavo.romero@linaro.org>,
	"npiggin@gmail.com" <npiggin@gmail.com>,
	"harshpb@linux.ibm.com" <harshpb@linux.ibm.com>,
	"linux@armlinux.org.uk" <linux@armlinux.org.uk>,
	"darren@os.amperecomputing.com" <darren@os.amperecomputing.com>,
	"ilkka@os.amperecomputing.com" <ilkka@os.amperecomputing.com>,
	"vishnu@os.amperecomputing.com" <vishnu@os.amperecomputing.com>,
	"gankulkarni@os.amperecomputing.com"
	<gankulkarni@os.amperecomputing.com>,
	"karl.heubaum@oracle.com" <karl.heubaum@oracle.com>,
	"miguel.luis@oracle.com" <miguel.luis@oracle.com>,
	zhukeqian <zhukeqian1@huawei.com>,
	"wangxiongfeng (C)" <wangxiongfeng2@huawei.com>,
	"wangyanan (Y)" <wangyanan55@huawei.com>,
	"Wangzhou (B)" <wangzhou1@hisilicon.com>,
	Linuxarm <linuxarm@huawei.com>,
	"jiakernel2@gmail.com" <jiakernel2@gmail.com>,
	"maobibo@loongson.cn" <maobibo@loongson.cn>,
	"lixianglai@loongson.cn" <lixianglai@loongson.cn>,
	"shahuang@redhat.com" <shahuang@redhat.com>,
	"zhao1.liu@intel.com" <zhao1.liu@intel.com>
Subject: Re: [PATCH RFC V6 14/24] arm/acpi: Introduce dedicated CPU OSPM interface for ARM-like platforms
Date: Tue, 7 Oct 2025 14:06:13 +0200	[thread overview]
Message-ID: <20251007140613.5916df08@fedora> (raw)
In-Reply-To: <7da6a9c470684754810414f0abd23a62@huawei.com>

On Tue, 7 Oct 2025 11:15:47 +0000
Salil Mehta <salil.mehta@huawei.com> wrote:

> Hi Igor,
> 
> Thanks for the reviews and sorry for the late reply. Please find my replies inline.
> 
> 
> > From: Igor Mammedov <imammedo@redhat.com>
> > Sent: Friday, October 3, 2025 3:58 PM
> > 
> > On Wed,  1 Oct 2025 01:01:17 +0000
> > salil.mehta@opnsrc.net wrote:
> >   
> > > From: Salil Mehta <salil.mehta@huawei.com>
> > >
> > > The existing ACPI CPU hotplug interface is built for x86 platforms
> > > where CPUs can be inserted or removed and resources are allocated
> > > dynamically. On ARM, CPUs are never hotpluggable: resources are
> > > allocated at boot and QOM vCPU objects always exist. Instead, CPUs are
> > > administratively managed by toggling ACPI _STA to enable or disable
> > > them, which gives a hotplug-like effect but does not match the x86 model.
> > >
> > > Reusing the x86 hotplug AML code would complicate maintenance since
> > > much of its logic relies on toggling the _STA.Present bit to notify
> > > OSPM about CPU insertion or removal. Such usage is not architecturally
> > > valid on ARM, where CPUs cannot appear or disappear at runtime. Mixing
> > > both models in one interface would increase complexity and make the
> > > AML harder to extend. A separate path is therefore required. The new
> > > design is heavily inspired by the CPU hotplug interface but avoids its  
> > unsuitable semantics.
> > 
> > Let me ask how much existing CPUHP AML code will become, if you reuse it
> > and add handling of 'enabled' bit there?
> > 
> > Would it be the same 700LOC as in this patch, which is basically duplication of
> > existing CPUHP ACPI interface?  
> 
> 
> It is by design as we have adopted non-hotplug approach now and closely aligned
> ourselves with what PSCI standard perceives to be the definition of CPU hotplug on ARM
> platforms - at least, as of today! And it is *NOT* what 'CPU hotplug' means on x86 platform. 

There is no argument that they are different but,
Could you point to PSCI specific parts in this patch?

> In crux, this means,
> 1. Dropping any hotplug/unplug infrastructure and its related paraphernalia from the
>     ARM implementation till the time the meaning of physical CPU hotplug is not clear as
>     per the specification. We do not want to model in Qemu something which does not
>     exist or defined, especially for the CPU hotplug case.

there is 'opts' config struct that lets user to opt in/out from specific AML
being generated. You could use that to disable some hotplug only bits of AML.
Other bits that are more generic/reusable, just refactor/rename them to a more
generic names.

> 2. This also means *NOT* enabling the  ACPI_CPU_HOTPLUG compilation switch to 
>      preserve the sanctity of the clean design.

that's semantics, I'd suggest renaming that to ACPI_CPU.

> 3. Yes, there is a code duplicity for now but that’s a case of further optimization and
>     cleanup not a design issue. Some of them are:
>     (1)  ACPI device-check and eject-request  handling code can be extracted and
>     made generic for all devices not just for CPUs.

make it more generic in acpi/cpu.c, instead of copying.
I don't have any objections to refactoring existing code if it makes sense and
we can share the code.

>     (2)  Right now, acpi/cpu.c is assuming that resources and templates should be
>      same for all the CPUs using CPUs AML described in it. There is no need for
>      such a restriction. Every platform should be free to choose the way it wants to
>      manage the resources and the interpretation of the fields inside it.

be more specific why you'd need different resources/MMIO layout for this series?

The thing is if we copied every time when we needed something that's a bit different,
we would end up with unsupportable/bloated QEMU.

>     (3) Call backs used with GED  makes an assumption of HOTPLUG interface etc.
>     (4) In fact, the prototype of the GED event handler makes a similar mistake of
>      assuming that GED is only meant for devices supporting hotplug when this is not
>      the case even as per the ACPI specification.
please be more specific and point to problematic code.

current acpi/cpu.c might be compiled under ACPI_CPU_HOTPLUG knob but it's not really
limited to hotplug, the reason for being compiled as such is that hotplug was
the sole reason for building CPUs AML at all.

What I see in the patch is simplifying current code somewhat by dropping
some hotplug related bits and a bunch of renaming.
Otherwise it's pretty much duplicating current acpi/cpu.c.

Beside that simplification, I don't see any reason why duplicating such amount is good idea.
Consider making exiting acpi/cpu.c more generic instead.

> RFC V5 was an attempt to implement this feature using the hotplug infrastructure
> and this RFC V6 is a deviation from previous approach towards non-hotplug. We do
> not want a hotchpotch approach because that’s a recipe for future disaster.
> 
> 
> Many Thanks!
> Salil.
> 
> 
> >   
> > >
> > > This patch adds a dedicated CPU OSPM (Operating System Power
> > > Management) interface. It provides a memory-mapped control region with
> > > selector, flags, command, and data fields, and AML methods for
> > > device-check, eject request, and _OST reporting. OSPM is notified
> > > through GED events and can coordinate CPU events directly with QEMU.
> > > Other ARM-like architectures may also use this interface.
> > >
> > > Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
> > > ---
> > >  hw/acpi/Kconfig                        |   3 +
> > >  hw/acpi/acpi-cpu-ospm-interface-stub.c |  41 ++
> > >  hw/acpi/cpu_ospm_interface.c           | 747  
> > +++++++++++++++++++++++++  
> > >  hw/acpi/meson.build                    |   2 +
> > >  hw/acpi/trace-events                   |  17 +
> > >  hw/arm/Kconfig                         |   1 +
> > >  include/hw/acpi/cpu_ospm_interface.h   |  78 +++
> > >  7 files changed, 889 insertions(+)
> > >  create mode 100644 hw/acpi/acpi-cpu-ospm-interface-stub.c
> > >  create mode 100644 hw/acpi/cpu_ospm_interface.c  create mode 100644
> > > include/hw/acpi/cpu_ospm_interface.h
> > >
> > > diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index
> > > 1d4e9f0845..aa52f0468f 100644
> > > --- a/hw/acpi/Kconfig
> > > +++ b/hw/acpi/Kconfig
> > > @@ -21,6 +21,9 @@ config ACPI_ICH9
> > >  config ACPI_CPU_HOTPLUG
> > >      bool
> > >
> > > +config ACPI_CPU_OSPM_INTERFACE
> > > +    bool
> > > +
> > >  config ACPI_MEMORY_HOTPLUG
> > >      bool
> > >      select MEM_DEVICE
> > > diff --git a/hw/acpi/acpi-cpu-ospm-interface-stub.c
> > > b/hw/acpi/acpi-cpu-ospm-interface-stub.c
> > > new file mode 100644
> > > index 0000000000..f6f333f641
> > > --- /dev/null
> > > +++ b/hw/acpi/acpi-cpu-ospm-interface-stub.c
> > > @@ -0,0 +1,41 @@
> > > +/*
> > > + * ACPI CPU OSPM Interface Handling.
> > > + *
> > > + * Copyright (c) 2025 Huawei Technologies R&D (UK) Ltd.
> > > + *
> > > + * Author: Salil Mehta <salil.mehta@huawei.com>
> > > + *
> > > + * SPDX-License-Identifier: GPL-2.0-or-later
> > > + *
> > > + * This program is free software; you can redistribute it and/or
> > > +modify
> > > + * it under the terms of the GNU General Public License as published
> > > +by
> > > + * the Free Software Foundation; either version 2 of the License, or
> > > + * (at your option) any later version.
> > > + */
> > > +
> > > +#include "qemu/osdep.h"
> > > +#include "hw/acpi/cpu_ospm_interface.h"
> > > +
> > > +void acpi_cpu_device_check_cb(AcpiCpuOspmState *cpu_st, DeviceState  
> > *dev,  
> > > +                              uint32_t event_st, Error **errp) { }
> > > +
> > > +void acpi_cpu_eject_request_cb(AcpiCpuOspmState *cpu_st,  
> > DeviceState *dev,  
> > > +                               uint32_t event_st, Error **errp) { }
> > > +
> > > +void acpi_cpu_eject_cb(AcpiCpuOspmState *cpu_st, DeviceState *dev,
> > > +Error **errp) { }
> > > +
> > > +void acpi_cpu_ospm_state_interface_init(MemoryRegion *as, Object  
> > *owner,  
> > > +                                        AcpiCpuOspmState *state,
> > > +                                        hwaddr base_addr) { }
> > > +
> > > +void acpi_cpus_ospm_status(AcpiCpuOspmState *cpu_st,  
> > ACPIOSTInfoList  
> > > +***list) { }
> > > diff --git a/hw/acpi/cpu_ospm_interface.c
> > > b/hw/acpi/cpu_ospm_interface.c new file mode 100644 index
> > > 0000000000..61aab8a793
> > > --- /dev/null
> > > +++ b/hw/acpi/cpu_ospm_interface.c
> > > @@ -0,0 +1,747 @@
> > > +/*
> > > + * ACPI CPU OSPM Interface Handling.
> > > + *
> > > + * Copyright (c) 2025 Huawei Technologies R&D (UK) Ltd.
> > > + *
> > > + * Author: Salil Mehta <salil.mehta@huawei.com>
> > > + *
> > > + * SPDX-License-Identifier: GPL-2.0-or-later
> > > + *
> > > + * This program is free software; you can redistribute it and/or
> > > +modify
> > > + * it under the terms of the GNU General Public License as published
> > > +by
> > > + * the Free Software Foundation; either version 2 of the License, or
> > > + * (at your option) any later version.
> > > + */
> > > +
> > > +#include "qemu/osdep.h"
> > > +#include "migration/vmstate.h"
> > > +#include "hw/core/cpu.h"
> > > +#include "qapi/error.h"
> > > +#include "trace.h"
> > > +#include "qapi/qapi-events-acpi.h"
> > > +#include "hw/acpi/cpu_ospm_interface.h"
> > > +
> > > +/* CPU identifier and resource device */
> > > +#define CPU_NAME_FMT      "C%.03X" /* CPU name format (e.g., C001)  
> > */  
> > > +#define CPU_RES_DEVICE    "CPUR" /* CPU resource device name */
> > > +#define CPU_DEVICE        "CPUS" /* CPUs device name */
> > > +#define CPU_LOCK          "CPLK" /* CPU lock object */
> > > +/* ACPI method(_STA, _EJ0, etc.) handlers */
> > > +#define CPU_STS_METHOD    "CSTA" /* CPU status method  
> > (_STA.Enabled) */  
> > > +#define CPU_SCAN_METHOD   "CSCN" /* CPU scan method for  
> > enumeration */  
> > > +#define CPU_NOTIFY_METHOD "CTFY" /* Notify method for CPU events  
> > */  
> > > +#define CPU_EJECT_METHOD  "CEJ0" /* CPU eject method (_EJ0) */
> > > +#define CPU_OST_METHOD    "COST" /* OSPM status reporting (_OST) */
> > > +/* CPU MMIO region fields (in PRST region) */
> > > +#define CPU_SELECTOR      "CSEL" /* CPU selector index (WO) */
> > > +#define CPU_ENABLED_F     "CPEN" /* Flag: CPU enabled status(_STA)  
> > (RO) */  
> > > +#define CPU_DEVCHK_F      "CDCK" /* Flag: Device-check event (RW) */
> > > +#define CPU_EJECTRQ_F     "CEJR" /* Flag: Eject-request event (RW)*/
> > > +#define CPU_EJECT_F       "CEJ0" /* Flag: Ejection trigger (WO) */
> > > +#define CPU_COMMAND       "CCMD" /* Command register (RW) */
> > > +#define CPU_DATA          "CDAT" /* Data register (RW) */
> > > +
> > > + /*
> > > + * CPU OSPM Interface MMIO Layout (Total: 16 bytes)
> > > + *
> > > + *
> > > + +--------+--------+--------+--------+--------+--------+--------+----
> > > + ----+
> > > + * |  0x00  |  0x01  |  0x02  |  0x03  |  0x04  |  0x05  |  0x06  |
> > > + 0x07  |
> > > + * +--------+--------+--------+--------+--------+--------+--------+--------+
> > > + * |       Selector (DWord, write-only)         | Flags  |Command |Reserved|
> > > + * |                                            | (RO/RW)|  (WO)  |(2B pad)|
> > > + * |        4 bytes (32 bits)                   | 1B     |   1B   | 2B     |
> > > + *
> > > + +-------------------------------------------------------------------
> > > + ----+
> > > + * |  0x08  |  0x09  |  0x0A  |  0x0B  |  0x0C  |  0x0D  |  0x0E  |
> > > + 0x0F  |
> > > + * +--------+--------+--------+--------+--------+--------+--------+--------+
> > > + * |                        Data (QWord, read/write)                       |
> > > + * |               Used by CPU scan and _OST methods (64 bits)             |
> > > + *
> > > + +-------------------------------------------------------------------
> > > + ----+
> > > + *
> > > + * Field Overview:
> > > + *
> > > + * - Selector: 4 bytes @0x00 (DWord, WO)
> > > + *               - Selects target CPU index for the current operation.
> > > + * - Flags:    1 byte  @0x04 (RO/RW)
> > > + *               - Bit 0: ENABLED  – CPU is powered on (RO)
> > > + *               - Bit 1: DEVCHK   – Device-check completed (RW)
> > > + *               - Bit 2: EJECTRQ  – Guest requests CPU eject (RW)
> > > + *               - Bit 3: EJECT    – Trigger CPU ejection (WO)
> > > + *               - Bits 4–7: Reserved (write 0)
> > > + * - Command:  1 byte  @0x05 (WO)
> > > + *               - Specifies control operation (e.g., scan, _OST, eject).
> > > + * - Reserved: 2 bytes @0x06–0x07
> > > + *               - Alignment padding; must be zero on write.
> > > + * - Data:     8 bytes @0x08 (QWord, RW)
> > > + *               - Input/output for command-specific data.
> > > + *               - Used by CPU scan or _OST.
> > > + */
> > > +
> > > +/*
> > > + * Macros defining the CPU MMIO region layout. Change field sizes
> > > +here to
> > > + * alter the overall MMIO region size.
> > > + */
> > > +/* Sub-Field sizes (in bytes) */
> > > +#define ACPI_CPU_MR_SELECTOR_SIZE  4 /* Write-only (DWord access)  
> > */  
> > > +#define ACPI_CPU_MR_FLAGS_SIZE     1 /* Read-write (Byte access) */
> > > +#define ACPI_CPU_MR_RES_FLAGS_SIZE 0 /* Reserved padding */
> > > +#define ACPI_CPU_MR_CMD_SIZE       1 /* Write-only (Byte access) */
> > > +#define ACPI_CPU_MR_RES_CMD_SIZE   2 /* Reserved padding */
> > > +#define ACPI_CPU_MR_CMD_DATA_SIZE  8 /* Read-write (QWord  
> > access) */  
> > > +
> > > +#define ACPI_CPU_OSPM_IF_MAX_FIELD_SIZE \
> > > +    MAX_CONST(ACPI_CPU_MR_CMD_DATA_SIZE, \
> > > +    MAX_CONST(ACPI_CPU_MR_SELECTOR_SIZE, \
> > > +    MAX_CONST(ACPI_CPU_MR_CMD_SIZE,  
> > ACPI_CPU_MR_FLAGS_SIZE)))  
> > > +
> > > +/* Validate layout against exported total length */
> > > +_Static_assert(ACPI_CPU_OSPM_IF_REG_LEN ==
> > > +               (ACPI_CPU_MR_SELECTOR_SIZE +
> > > +                ACPI_CPU_MR_FLAGS_SIZE +
> > > +                ACPI_CPU_MR_RES_FLAGS_SIZE +
> > > +                ACPI_CPU_MR_CMD_SIZE +
> > > +                ACPI_CPU_MR_RES_CMD_SIZE +
> > > +                ACPI_CPU_MR_CMD_DATA_SIZE),
> > > +               "ACPI_CPU_OSPM_IF_REG_LEN mismatch with internal MMIO
> > > +layout");
> > > +
> > > +/* Sub-Field sizes (in bits) */
> > > +#define ACPI_CPU_MR_SELECTOR_SIZE_BITS \
> > > +    (ACPI_CPU_MR_SELECTOR_SIZE * BITS_PER_BYTE)  /* Write-only  
> > (DWord  
> > > +Acc) */ #define ACPI_CPU_MR_FLAGS_SIZE_BITS \
> > > +    (ACPI_CPU_MR_FLAGS_SIZE * BITS_PER_BYTE)     /* Read-write (Byte  
> > Acc) */  
> > > +#define ACPI_CPU_MR_RES_FLAGS_SIZE_BITS \
> > > +    (ACPI_CPU_MR_RES_FLAGS_SIZE * BITS_PER_BYTE) /* Reserved  
> > padding  
> > > +*/ #define ACPI_CPU_MR_CMD_SIZE_BITS \
> > > +    (ACPI_CPU_MR_CMD_SIZE * BITS_PER_BYTE)       /* Write-only (Byte  
> > Acc) */  
> > > +#define ACPI_CPU_MR_RES_CMD_SIZE_BITS \
> > > +    (ACPI_CPU_MR_RES_CMD_SIZE * BITS_PER_BYTE)   /* Reserved  
> > padding */  
> > > +#define ACPI_CPU_MR_CMD_DATA_SIZE_BITS \
> > > +    (ACPI_CPU_MR_CMD_DATA_SIZE * BITS_PER_BYTE)  /* Read-write  
> > (QWord  
> > > +Acc) */
> > > +
> > > +/* Field offsets (in bytes) */
> > > +#define ACPI_CPU_MR_SELECTOR_OFFSET_WO  0 #define
> > > +ACPI_CPU_MR_FLAGS_OFFSET_RW \
> > > +    (ACPI_CPU_MR_SELECTOR_OFFSET_WO + \
> > > +     ACPI_CPU_MR_SELECTOR_SIZE)
> > > +#define ACPI_CPU_MR_CMD_OFFSET_WO \
> > > +    (ACPI_CPU_MR_FLAGS_OFFSET_RW + \
> > > +     ACPI_CPU_MR_FLAGS_SIZE + \
> > > +     ACPI_CPU_MR_RES_FLAGS_SIZE)
> > > +#define ACPI_CPU_MR_CMD_DATA_OFFSET_RW \
> > > +    (ACPI_CPU_MR_CMD_OFFSET_WO + \
> > > +     ACPI_CPU_MR_CMD_SIZE + \
> > > +     ACPI_CPU_MR_RES_CMD_SIZE)
> > > +
> > > +/* ensure all offsets are at their natural size alignment boundaries */
> > > +#define STATIC_ASSERT_FIELD_ALIGNMENT(offset, type, field_name)  
> > \  
> > > +    _Static_assert((offset) % sizeof(type) == 0,                              \
> > > +                   field_name " is not aligned to its natural
> > > +boundary")
> > > +
> > >  
> > +STATIC_ASSERT_FIELD_ALIGNMENT(ACPI_CPU_MR_SELECTOR_OFFSET_W
> > O,  
> > > +                              uint32_t, "Selector");
> > > +STATIC_ASSERT_FIELD_ALIGNMENT(ACPI_CPU_MR_FLAGS_OFFSET_RW,
> > > +                              uint8_t, "Flags");
> > > +STATIC_ASSERT_FIELD_ALIGNMENT(ACPI_CPU_MR_CMD_OFFSET_WO,
> > > +                              uint8_t, "Command");
> > >  
> > +STATIC_ASSERT_FIELD_ALIGNMENT(ACPI_CPU_MR_CMD_DATA_OFFSET_
> > RW,  
> > > +                              uint64_t, "Command Data");
> > > +
> > > +/* Flag bit positions (used within 'flags' subfield) */ #define
> > > +ACPI_CPU_FLAGS_USED_BITS 4 #define  
> > ACPI_CPU_MR_FLAGS_BIT_ENABLED  
> > > +BIT(0) #define ACPI_CPU_MR_FLAGS_BIT_DEVCHK  BIT(1) #define
> > > +ACPI_CPU_MR_FLAGS_BIT_EJECTRQ BIT(2)
> > > +#define ACPI_CPU_MR_FLAGS_BIT_EJECT  
> > BIT(ACPI_CPU_FLAGS_USED_BITS - 1)  
> > > +
> > > +#define ACPI_CPU_MR_RES_FLAG_BITS (BITS_PER_BYTE -
> > > +ACPI_CPU_FLAGS_USED_BITS)
> > > +
> > > +enum {
> > > +    ACPI_GET_NEXT_CPU_WITH_EVENT_CMD = 0,
> > > +    ACPI_OST_EVENT_CMD = 1,
> > > +    ACPI_OST_STATUS_CMD = 2,
> > > +    ACPI_CMD_MAX
> > > +};
> > > +
> > > +#define AML_APPEND_MR_RESVD_FIELD(mr_field, size_bits)       \
> > > +    do {                                                        \
> > > +        if ((size_bits) != 0) {                                 \
> > > +            aml_append((mr_field), aml_reserved_field(size_bits)); \
> > > +        }                                                       \
> > > +    } while (0)
> > > +
> > > +#define AML_APPEND_MR_NAMED_FIELD(mr_field, name, size_bits)    \
> > > +    do {                                                        \
> > > +        if ((size_bits) != 0) {                                 \
> > > +            aml_append((mr_field), aml_named_field((name), (size_bits))); \
> > > +        }                                                       \
> > > +    } while (0)
> > > +
> > > +#define AML_CPU_RES_DEV(base, field) \
> > > +        aml_name("%s.%s.%s", (base), CPU_RES_DEVICE, (field))
> > > +
> > > +static ACPIOSTInfo *
> > > +acpi_cpu_ospm_ost_status(int idx, AcpiCpuOspmStateStatus *cdev) {
> > > +    ACPIOSTInfo *info = g_new0(ACPIOSTInfo, 1);
> > > +
> > > +    info->source = cdev->ost_event;
> > > +    info->status = cdev->ost_status;
> > > +    if (cdev->cpu) {
> > > +        DeviceState *dev = DEVICE(cdev->cpu);
> > > +        if (dev->id) {
> > > +            info->device = g_strdup(dev->id);
> > > +        }
> > > +    }
> > > +    return info;
> > > +}
> > > +
> > > +void acpi_cpus_ospm_status(AcpiCpuOspmState *cpu_st,  
> > ACPIOSTInfoList  
> > > +***list) {
> > > +    ACPIOSTInfoList ***tail = list;
> > > +    int i;
> > > +
> > > +    for (i = 0; i < cpu_st->dev_count; i++) {
> > > +        QAPI_LIST_APPEND(*tail, acpi_cpu_ospm_ost_status(i, &cpu_st-
> > >devs[i]));
> > > +    }
> > > +}
> > > +
> > > +static uint64_t
> > > +acpi_cpu_ospm_intf_mr_read(void *opaque, hwaddr addr, unsigned  
> > size)  
> > > +{
> > > +    AcpiCpuOspmState *cpu_st = opaque;
> > > +    AcpiCpuOspmStateStatus *cdev;
> > > +    uint64_t val = 0;
> > > +
> > > +    if (cpu_st->selector >= cpu_st->dev_count) {
> > > +        return val;
> > > +    }
> > > +    cdev = &cpu_st->devs[cpu_st->selector];
> > > +    switch (addr) {
> > > +    case ACPI_CPU_MR_FLAGS_OFFSET_RW:
> > > +        val |= qdev_check_enabled(DEVICE(cdev->cpu)) ?
> > > +                                  ACPI_CPU_MR_FLAGS_BIT_ENABLED : 0;
> > > +        val |= cdev->devchk_pending ? ACPI_CPU_MR_FLAGS_BIT_DEVCHK :  
> > 0;  
> > > +        val |= cdev->ejrqst_pending ? ACPI_CPU_MR_FLAGS_BIT_EJECTRQ :  
> > 0;  
> > > +        trace_acpi_cpuos_if_read_flags(cpu_st->selector, val);
> > > +        break;
> > > +    case ACPI_CPU_MR_CMD_DATA_OFFSET_RW:
> > > +        switch (cpu_st->command) {
> > > +        case ACPI_GET_NEXT_CPU_WITH_EVENT_CMD:
> > > +           val = cpu_st->selector;
> > > +           break;
> > > +        default:
> > > +           trace_acpi_cpuos_if_read_invalid_cmd_data(cpu_st->selector,
> > > +                                                     cpu_st->command);
> > > +           break;
> > > +        }
> > > +        trace_acpi_cpuos_if_read_cmd_data(cpu_st->selector, val);
> > > +        break;
> > > +    default:
> > > +        break;
> > > +    }
> > > +    return val;
> > > +}
> > > +
> > > +static void
> > > +acpi_cpu_ospm_intf_mr_write(void *opaque, hwaddr addr, uint64_t  
> > data,  
> > > +                            unsigned int size) {
> > > +    AcpiCpuOspmState *cpu_st = opaque;
> > > +    AcpiCpuOspmStateStatus *cdev;
> > > +    ACPIOSTInfo *info;
> > > +
> > > +    assert(cpu_st->dev_count);
> > > +    if (addr) {
> > > +        if (cpu_st->selector >= cpu_st->dev_count) {
> > > +            trace_acpi_cpuos_if_invalid_idx_selected(cpu_st->selector);
> > > +            return;
> > > +        }
> > > +    }
> > > +
> > > +    switch (addr) {
> > > +    case ACPI_CPU_MR_SELECTOR_OFFSET_WO: /* current CPU selector  
> > */  
> > > +        cpu_st->selector = data;
> > > +        trace_acpi_cpuos_if_write_idx(cpu_st->selector);
> > > +        break;
> > > +    case ACPI_CPU_MR_FLAGS_OFFSET_RW: /* set is_* fields  */
> > > +        cdev = &cpu_st->devs[cpu_st->selector];
> > > +        if (data & ACPI_CPU_MR_FLAGS_BIT_DEVCHK) {
> > > +            /* clear device-check pending event */
> > > +            cdev->devchk_pending = false;
> > > +            trace_acpi_cpuos_if_clear_devchk_evt(cpu_st->selector);
> > > +        } else if (data & ACPI_CPU_MR_FLAGS_BIT_EJECTRQ) {
> > > +            /* clear eject-request pending event */
> > > +            cdev->ejrqst_pending = false;
> > > +            trace_acpi_cpuos_if_clear_ejrqst_evt(cpu_st->selector);
> > > +        } else if (data & ACPI_CPU_MR_FLAGS_BIT_EJECT) {
> > > +            DeviceState *dev = NULL;
> > > +            if (!cdev->cpu || cdev->cpu == first_cpu) {
> > > +                trace_acpi_cpuos_if_ejecting_invalid_cpu(cpu_st->selector);
> > > +                break;
> > > +            }
> > > +            /*
> > > +             * OSPM has returned with eject. Hence, it is now safe to put the
> > > +             * cpu device on powered-off state.
> > > +             */
> > > +            trace_acpi_cpuos_if_ejecting_cpu(cpu_st->selector);
> > > +            dev = DEVICE(cdev->cpu);
> > > +            qdev_sync_disable(dev, &error_fatal);
> > > +        }
> > > +        break;
> > > +    case ACPI_CPU_MR_CMD_OFFSET_WO:
> > > +        trace_acpi_cpuos_if_write_cmd(cpu_st->selector, data);
> > > +        if (data < ACPI_CMD_MAX) {
> > > +            cpu_st->command = data;
> > > +            if (cpu_st->command ==  
> > ACPI_GET_NEXT_CPU_WITH_EVENT_CMD) {  
> > > +                uint32_t iter = cpu_st->selector;
> > > +
> > > +                do {
> > > +                    cdev = &cpu_st->devs[iter];
> > > +                    if (cdev->devchk_pending || cdev->ejrqst_pending) {
> > > +                        cpu_st->selector = iter;
> > > +                        trace_acpi_cpuos_if_cpu_has_events(cpu_st->selector,
> > > +                            cdev->devchk_pending, cdev->ejrqst_pending);
> > > +                        break;
> > > +                    }
> > > +                    iter = iter + 1 < cpu_st->dev_count ? iter + 1 : 0;
> > > +                } while (iter != cpu_st->selector);
> > > +            }
> > > +        }
> > > +        break;
> > > +    case ACPI_CPU_MR_CMD_DATA_OFFSET_RW:
> > > +        switch (cpu_st->command) {
> > > +        case ACPI_OST_EVENT_CMD: {
> > > +           cdev = &cpu_st->devs[cpu_st->selector];
> > > +           cdev->ost_event = data;
> > > +           trace_acpi_cpuos_if_write_ost_ev(cpu_st->selector, cdev-
> > >ost_event);
> > > +           break;
> > > +        }
> > > +        case ACPI_OST_STATUS_CMD: {
> > > +           cdev = &cpu_st->devs[cpu_st->selector];
> > > +           cdev->ost_status = data;
> > > +           info = acpi_cpu_ospm_ost_status(cpu_st->selector, cdev);
> > > +           qapi_event_send_acpi_device_ost(info);
> > > +           qapi_free_ACPIOSTInfo(info);
> > > +           trace_acpi_cpuos_if_write_ost_status(cpu_st->selector,
> > > +                                                cdev->ost_status);
> > > +           break;
> > > +        }
> > > +        default:
> > > +           trace_acpi_cpuos_if_write_invalid_cmd(cpu_st->selector,
> > > +                                                 cpu_st->command);
> > > +           break;
> > > +        }
> > > +        break;
> > > +    default:
> > > +        trace_acpi_cpuos_if_write_invalid_offset(cpu_st->selector, addr);
> > > +        break;
> > > +    }
> > > +}
> > > +
> > > +static const MemoryRegionOps cpu_common_mr_ops = {
> > > +    .read = acpi_cpu_ospm_intf_mr_read,
> > > +    .write = acpi_cpu_ospm_intf_mr_write,
> > > +    .endianness = DEVICE_LITTLE_ENDIAN,
> > > +    .valid = {
> > > +        .min_access_size = 1,
> > > +        .max_access_size = ACPI_CPU_OSPM_IF_MAX_FIELD_SIZE,
> > > +    },
> > > +    .impl = {
> > > +        .min_access_size = 1,
> > > +        .max_access_size = ACPI_CPU_OSPM_IF_MAX_FIELD_SIZE,
> > > +        .unaligned = false,
> > > +    },
> > > +};
> > > +
> > > +void acpi_cpu_ospm_state_interface_init(MemoryRegion *as, Object  
> > *owner,  
> > > +                                        AcpiCpuOspmState *state,
> > > +                                        hwaddr base_addr) {
> > > +    MachineState *machine = MACHINE(qdev_get_machine());
> > > +    MachineClass *mc = MACHINE_GET_CLASS(machine);
> > > +    const CPUArchIdList *id_list;
> > > +    int i;
> > > +
> > > +    assert(mc->possible_cpu_arch_ids);
> > > +    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 =  CPU(id_list->cpus[i].cpu);
> > > +        state->devs[i].arch_id = id_list->cpus[i].arch_id;
> > > +    }
> > > +    memory_region_init_io(&state->ctrl_reg, owner,  
> > &cpu_common_mr_ops, state,  
> > > +                          "ACPI CPU OSPM State Interface Memory Region",
> > > +                          ACPI_CPU_OSPM_IF_REG_LEN);
> > > +    memory_region_add_subregion(as, base_addr, &state->ctrl_reg); }
> > > +
> > > +static AcpiCpuOspmStateStatus *
> > > +acpi_get_cpu_status(AcpiCpuOspmState *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_device_check_cb(AcpiCpuOspmState *cpu_st, DeviceState  
> > *dev,  
> > > +                              uint32_t event_st, Error **errp) {
> > > +    AcpiCpuOspmStateStatus *cdev;
> > > +    cdev = acpi_get_cpu_status(cpu_st, dev);
> > > +    if (!cdev) {
> > > +        return;
> > > +    }
> > > +    assert(cdev->cpu);
> > > +
> > > +    /*
> > > +     * Tell OSPM via GED IRQ(GSI) that a powered-off cpu is being powered-  
> > on.  
> > > +     * Also, mark 'device-check' event pending for this cpu. This will
> > > +     * eventually result in OSPM evaluating the ACPI _EVT method and scan  
> > of  
> > > +     * cpus
> > > +     */
> > > +    cdev->devchk_pending = true;
> > > +    acpi_send_event(cpu_st->acpi_dev, event_st); }
> > > +
> > > +void acpi_cpu_eject_request_cb(AcpiCpuOspmState *cpu_st,  
> > DeviceState *dev,  
> > > +                              uint32_t event_st, Error **errp) {
> > > +    AcpiCpuOspmStateStatus *cdev;
> > > +    cdev = acpi_get_cpu_status(cpu_st, dev);
> > > +    if (!cdev) {
> > > +        return;
> > > +    }
> > > +    assert(cdev->cpu);
> > > +
> > > +    /*
> > > +     * Tell OSPM via GED IRQ(GSI) that a cpu wants to power-off or go on  
> > standby  
> > > +     * Also,mark 'eject-request' event pending for this cpu. (graceful  
> > shutdown)  
> > > +     */
> > > +    cdev->ejrqst_pending = true;
> > > +    acpi_send_event(cpu_st->acpi_dev, event_st); }
> > > +
> > > +void
> > > +acpi_cpu_eject_cb(AcpiCpuOspmState *cpu_st, DeviceState *dev, Error
> > > +**errp) {
> > > +    /* TODO: possible handling here */ }
> > > +
> > > +static const VMStateDescription vmstate_cpu_ospm_state_sts = {
> > > +    .name = "CPU OSPM state status",
> > > +    .version_id = 1,
> > > +    .minimum_version_id = 1,
> > > +    .fields = (const VMStateField[]) {
> > > +        VMSTATE_BOOL(devchk_pending, AcpiCpuOspmStateStatus),
> > > +        VMSTATE_BOOL(ejrqst_pending, AcpiCpuOspmStateStatus),
> > > +        VMSTATE_UINT32(ost_event, AcpiCpuOspmStateStatus),
> > > +        VMSTATE_UINT32(ost_status, AcpiCpuOspmStateStatus),
> > > +        VMSTATE_END_OF_LIST()
> > > +    }
> > > +};
> > > +
> > > +const VMStateDescription vmstate_cpu_ospm_state = {
> > > +    .name = "CPU OSPM state",
> > > +    .version_id = 1,
> > > +    .minimum_version_id = 1,
> > > +    .fields = (const VMStateField[]) {
> > > +        VMSTATE_UINT32(selector, AcpiCpuOspmState),
> > > +        VMSTATE_UINT8(command, AcpiCpuOspmState),
> > > +        VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs,  
> > AcpiCpuOspmState,  
> > > +                                             dev_count,
> > > +                                             vmstate_cpu_ospm_state_sts,
> > > +                                             AcpiCpuOspmStateStatus),
> > > +        VMSTATE_END_OF_LIST()
> > > +    }
> > > +};
> > > +
> > > +void acpi_build_cpus_aml(Aml *table, hwaddr base_addr, const char  
> > *root,  
> > > +                         const char *event_handler_method) {
> > > +    MachineState *machine = MACHINE(qdev_get_machine());
> > > +    MachineClass *mc = MACHINE_GET_CLASS(machine);
> > > +    const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
> > > +    Aml *sb_scope = aml_scope("_SB"); /* System Bus Scope */
> > > +    Aml *ifctx, *field, *method, *cpu_res_dev, *cpus_dev;
> > > +    Aml *zero = aml_int(0);
> > > +    Aml *one = aml_int(1);
> > > +
> > > +    cpu_res_dev = aml_device("%s.%s", root, CPU_RES_DEVICE);
> > > +    {
> > > +        Aml *crs;
> > > +
> > > +        aml_append(cpu_res_dev,
> > > +            aml_name_decl("_HID", aml_eisaid("PNP0A06")));
> > > +        aml_append(cpu_res_dev,
> > > +            aml_name_decl("_UID", aml_string("CPU OSPM Interface  
> > resources")));  
> > > +        aml_append(cpu_res_dev, aml_mutex(CPU_LOCK, 0));
> > > +
> > > +        crs = aml_resource_template();
> > > +        aml_append(crs, aml_memory32_fixed(base_addr,  
> > ACPI_CPU_OSPM_IF_REG_LEN,  
> > > +                   AML_READ_WRITE));
> > > +
> > > +        aml_append(cpu_res_dev, aml_name_decl("_CRS", crs));
> > > +
> > > +        /* declare CPU OSPM Interface MMIO region related access fields */
> > > +        aml_append(cpu_res_dev,
> > > +                   aml_operation_region("PRST", AML_SYSTEM_MEMORY,
> > > +                                        aml_int(base_addr),
> > > +                                        ACPI_CPU_OSPM_IF_REG_LEN));
> > > +
> > > +        /*
> > > +         * define named fields within PRST region with 'Byte' access widths
> > > +         * and reserve fields with other access width
> > > +         */
> > > +        field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK,  
> > AML_PRESERVE);  
> > > +        /* reserve CPU 'selector' field (size in bits) */
> > > +        AML_APPEND_MR_RESVD_FIELD(field,  
> > ACPI_CPU_MR_SELECTOR_SIZE_BITS);  
> > > +        /* Flag::Enabled Bit(RO) - Read '1' if enabled */
> > > +        AML_APPEND_MR_NAMED_FIELD(field, CPU_ENABLED_F, 1);
> > > +        /* Flag::Devchk Bit(RW) - Read '1', has a event. Write '1', to clear */
> > > +        AML_APPEND_MR_NAMED_FIELD(field, CPU_DEVCHK_F, 1);
> > > +        /* Flag::Ejectrq Bit(RW) - Read 1, has event. Write 1 to clear */
> > > +        AML_APPEND_MR_NAMED_FIELD(field, CPU_EJECTRQ_F, 1);
> > > +        /* Flag::Eject Bit(WO) - OSPM evals _EJx, initiates CPU Eject in  
> > Qemu*/  
> > > +        AML_APPEND_MR_NAMED_FIELD(field, CPU_EJECT_F, 1);
> > > +        /* Flag::Bit(ACPI_CPU_FLAGS_USED_BITS)-Bit(7) - Reserve left over  
> > bits*/  
> > > +        AML_APPEND_MR_RESVD_FIELD(field,  
> > ACPI_CPU_MR_RES_FLAG_BITS);  
> > > +        /* Reserved space: padding after flags */
> > > +        AML_APPEND_MR_RESVD_FIELD(field,  
> > ACPI_CPU_MR_RES_FLAGS_SIZE_BITS);  
> > > +        /* Command field written by OSPM */
> > > +        AML_APPEND_MR_NAMED_FIELD(field, CPU_COMMAND,
> > > +                                  ACPI_CPU_MR_CMD_SIZE_BITS);
> > > +        /* Reserved space: padding after command field */
> > > +        AML_APPEND_MR_RESVD_FIELD(field,  
> > ACPI_CPU_MR_RES_CMD_SIZE_BITS);  
> > > +        /* Command data: 64-bit payload associated with command */
> > > +        AML_APPEND_MR_RESVD_FIELD(field,  
> > ACPI_CPU_MR_CMD_DATA_SIZE_BITS);  
> > > +        aml_append(cpu_res_dev, field);
> > > +
> > > +        /*
> > > +         * define named fields with 'Dword' access widths and reserve fields
> > > +         * with other access width
> > > +         */
> > > +        field = aml_field("PRST", AML_DWORD_ACC, AML_NOLOCK,  
> > AML_PRESERVE);  
> > > +        /* CPU selector, write only */
> > > +        AML_APPEND_MR_NAMED_FIELD(field, CPU_SELECTOR,
> > > +                                  ACPI_CPU_MR_SELECTOR_SIZE_BITS);
> > > +        aml_append(cpu_res_dev, field);
> > > +
> > > +        /*
> > > +         * define named fields with 'Qword' access widths and reserve fields
> > > +         * with other access width
> > > +         */
> > > +        field = aml_field("PRST", AML_QWORD_ACC, AML_NOLOCK,  
> > AML_PRESERVE);  
> > > +        /*
> > > +         * Reserve space: selector, flags, reserved flags, command, reserved
> > > +         * command for Qword alignment.
> > > +         */
> > > +        AML_APPEND_MR_RESVD_FIELD(field,  
> > ACPI_CPU_MR_SELECTOR_SIZE_BITS +  
> > > +                                            ACPI_CPU_MR_FLAGS_SIZE_BITS +
> > > +                                            ACPI_CPU_MR_RES_FLAGS_SIZE_BITS +
> > > +                                            ACPI_CPU_MR_CMD_SIZE_BITS +
> > > +                                            ACPI_CPU_MR_RES_CMD_SIZE_BITS);
> > > +        /* Command data accessible via Qword */
> > > +        AML_APPEND_MR_NAMED_FIELD(field, CPU_DATA,
> > > +                                  ACPI_CPU_MR_CMD_DATA_SIZE_BITS);
> > > +        aml_append(cpu_res_dev, field);
> > > +    }
> > > +    aml_append(sb_scope, cpu_res_dev);
> > > +
> > > +    cpus_dev = aml_device("%s.%s", root, CPU_DEVICE);
> > > +    {
> > > +        Aml *ctrl_lock = AML_CPU_RES_DEV(root, CPU_LOCK);
> > > +        Aml *cpu_selector = AML_CPU_RES_DEV(root, CPU_SELECTOR);
> > > +        Aml *is_enabled = AML_CPU_RES_DEV(root, CPU_ENABLED_F);
> > > +        Aml *dvchk_evt = AML_CPU_RES_DEV(root, CPU_DEVCHK_F);
> > > +        Aml *ejrq_evt = AML_CPU_RES_DEV(root, CPU_EJECTRQ_F);
> > > +        Aml *ej_evt = AML_CPU_RES_DEV(root, CPU_EJECT_F);
> > > +        Aml *cpu_cmd = AML_CPU_RES_DEV(root, CPU_COMMAND);
> > > +        Aml *cpu_data = AML_CPU_RES_DEV(root, CPU_DATA);
> > > +        int i;
> > > +
> > > +        aml_append(cpus_dev, aml_name_decl("_HID",  
> > aml_string("ACPI0010")));  
> > > +        aml_append(cpus_dev, aml_name_decl("_CID",
> > > + aml_eisaid("PNP0A05")));
> > > +
> > > +        method = aml_method(CPU_NOTIFY_METHOD, 2,  
> > AML_NOTSERIALIZED);  
> > > +        for (i = 0; i < arch_ids->len; i++) {
> > > +            Aml *cpu = aml_name(CPU_NAME_FMT, i);
> > > +            Aml *uid = aml_arg(0);
> > > +            Aml *event = aml_arg(1);
> > > +
> > > +            ifctx = aml_if(aml_equal(uid, aml_int(i)));
> > > +            {
> > > +                aml_append(ifctx, aml_notify(cpu, event));
> > > +            }
> > > +            aml_append(method, ifctx);
> > > +        }
> > > +        aml_append(cpus_dev, method);
> > > +
> > > +        method = aml_method(CPU_STS_METHOD, 1, AML_SERIALIZED);
> > > +        {
> > > +            Aml *idx = aml_arg(0);
> > > +            Aml *sta = aml_local(0);
> > > +            Aml *else_ctx;
> > > +
> > > +            aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
> > > +            aml_append(method, aml_store(idx, cpu_selector));
> > > +            aml_append(method, aml_store(zero, sta));
> > > +            ifctx = aml_if(aml_equal(is_enabled, one));
> > > +            {
> > > +                /* cpu is present and enabled */
> > > +                aml_append(ifctx, aml_store(aml_int(0xF), sta));
> > > +            }
> > > +            aml_append(method, ifctx);
> > > +            else_ctx = aml_else();
> > > +            {
> > > +                /* cpu is present but disabled */
> > > +                aml_append(else_ctx, aml_store(aml_int(0xD), sta));
> > > +            }
> > > +            aml_append(method, else_ctx);
> > > +            aml_append(method, aml_release(ctrl_lock));
> > > +            aml_append(method, aml_return(sta));
> > > +        }
> > > +        aml_append(cpus_dev, method);
> > > +
> > > +        method = aml_method(CPU_EJECT_METHOD, 1, AML_SERIALIZED);
> > > +        {
> > > +            Aml *idx = aml_arg(0);
> > > +
> > > +            aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
> > > +            aml_append(method, aml_store(idx, cpu_selector));
> > > +            aml_append(method, aml_store(one, ej_evt));
> > > +            aml_append(method, aml_release(ctrl_lock));
> > > +        }
> > > +        aml_append(cpus_dev, method);
> > > +
> > > +        method = aml_method(CPU_SCAN_METHOD, 0, AML_SERIALIZED);
> > > +        {
> > > +            Aml *has_event = aml_local(0); /* Local0: Loop control flag */
> > > +            Aml *uid = aml_local(1); /* Local1: Current CPU UID */
> > > +            /* Constants */
> > > +            Aml *dev_chk = aml_int(1); /* Notify: device check to enable */
> > > +            Aml *eject_req = aml_int(3); /* Notify: eject for removal */
> > > +            Aml *next_cpu_cmd =
> > > + aml_int(ACPI_GET_NEXT_CPU_WITH_EVENT_CMD);
> > > +
> > > +            /* Acquire CPU lock */
> > > +            aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
> > > +
> > > +            /* Initialize loop */
> > > +            aml_append(method, aml_store(zero, uid));
> > > +            aml_append(method, aml_store(one, has_event));
> > > +
> > > +            Aml *while_ctx = aml_while(aml_land(
> > > +                aml_equal(has_event, one),
> > > +                aml_lless(uid, aml_int(arch_ids->len))
> > > +            ));
> > > +            {
> > > +                aml_append(while_ctx, aml_store(zero, has_event));
> > > +                /*
> > > +                 * Issue scan cmd: QEMU will return next CPU with event in
> > > +                 * cpu_data
> > > +                 */
> > > +                aml_append(while_ctx, aml_store(uid, cpu_selector));
> > > +                aml_append(while_ctx, aml_store(next_cpu_cmd,
> > > + cpu_cmd));
> > > +
> > > +                /* If scan wrapped around to an earlier UID, exit loop */
> > > +                Aml *wrap_check = aml_if(aml_lless(cpu_data, uid));
> > > +                aml_append(wrap_check, aml_break());
> > > +                aml_append(while_ctx, wrap_check);
> > > +
> > > +                /* Set UID to scanned result */
> > > +                aml_append(while_ctx, aml_store(cpu_data, uid));
> > > +
> > > +                /* send CPU device-check(resume) event to OSPM */
> > > +                Aml *if_devchk = aml_if(aml_equal(dvchk_evt, one));
> > > +                {
> > > +                    aml_append(if_devchk,
> > > +                        aml_call2(CPU_NOTIFY_METHOD, uid, dev_chk));
> > > +                    /* clear local device-check event sent flag */
> > > +                    aml_append(if_devchk, aml_store(one, dvchk_evt));
> > > +                    aml_append(if_devchk, aml_store(one, has_event));
> > > +                }
> > > +                aml_append(while_ctx, if_devchk);
> > > +
> > > +                /*
> > > +                 * send CPU eject-request event to OSPM to gracefully handle
> > > +                 * OSPM related tasks running on this CPU
> > > +                 */
> > > +                Aml *else_ctx = aml_else();
> > > +                Aml *if_ejrq = aml_if(aml_equal(ejrq_evt, one));
> > > +                {
> > > +                    aml_append(if_ejrq,
> > > +                        aml_call2(CPU_NOTIFY_METHOD, uid, eject_req));
> > > +                    /* clear local eject-request event sent flag */
> > > +                    aml_append(if_ejrq, aml_store(one, ejrq_evt));
> > > +                    aml_append(if_ejrq, aml_store(one, has_event));
> > > +                }
> > > +                aml_append(else_ctx, if_ejrq);
> > > +                aml_append(while_ctx, else_ctx);
> > > +
> > > +                /* Increment UID */
> > > +                aml_append(while_ctx, aml_increment(uid));
> > > +            }
> > > +            aml_append(method, while_ctx);
> > > +
> > > +            /* Release cpu lock */
> > > +            aml_append(method, aml_release(ctrl_lock));
> > > +        }
> > > +        aml_append(cpus_dev, method);
> > > +
> > > +        method = aml_method(CPU_OST_METHOD, 4, AML_SERIALIZED);
> > > +        {
> > > +            Aml *uid = aml_arg(0);
> > > +            Aml *ev_cmd = aml_int(ACPI_OST_EVENT_CMD);
> > > +            Aml *st_cmd = aml_int(ACPI_OST_STATUS_CMD);
> > > +
> > > +            aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
> > > +            aml_append(method, aml_store(uid, cpu_selector));
> > > +            aml_append(method, aml_store(ev_cmd, cpu_cmd));
> > > +            aml_append(method, aml_store(aml_arg(1), cpu_data));
> > > +            aml_append(method, aml_store(st_cmd, cpu_cmd));
> > > +            aml_append(method, aml_store(aml_arg(2), cpu_data));
> > > +            aml_append(method, aml_release(ctrl_lock));
> > > +        }
> > > +        aml_append(cpus_dev, method);
> > > +
> > > +        /* build Processor object for each processor */
> > > +        for (i = 0; i < arch_ids->len; i++) {
> > > +            Aml *dev;
> > > +            Aml *uid = aml_int(i);
> > > +
> > > +            dev = aml_device(CPU_NAME_FMT, i);
> > > +            aml_append(dev, aml_name_decl("_HID",  
> > aml_string("ACPI0007")));  
> > > +            aml_append(dev, aml_name_decl("_UID", uid));
> > > +
> > > +            method = aml_method("_STA", 0, AML_SERIALIZED);
> > > +            aml_append(method, aml_return(aml_call1(CPU_STS_METHOD,  
> > uid)));  
> > > +            aml_append(dev, method);
> > > +
> > > +            if (CPU(arch_ids->cpus[i].cpu) != first_cpu) {
> > > +                method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
> > > +                aml_append(method, aml_call1(CPU_EJECT_METHOD, uid));
> > > +                aml_append(dev, method);
> > > +            }
> > > +
> > > +            method = aml_method("_OST", 3, AML_SERIALIZED);
> > > +            aml_append(method,
> > > +                aml_call4(CPU_OST_METHOD, uid, aml_arg(0),
> > > +                          aml_arg(1), aml_arg(2))
> > > +            );
> > > +            aml_append(dev, method);
> > > +            aml_append(cpus_dev, dev);
> > > +        }
> > > +    }
> > > +    aml_append(sb_scope, cpus_dev);
> > > +    aml_append(table, sb_scope);
> > > +
> > > +    method = aml_method(event_handler_method, 0,  
> > AML_NOTSERIALIZED);  
> > > +    aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD));
> > > +    aml_append(table, method);
> > > +}
> > > diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index
> > > 73f02b9691..6d83396ab4 100644
> > > --- a/hw/acpi/meson.build
> > > +++ b/hw/acpi/meson.build
> > > @@ -8,6 +8,8 @@ acpi_ss.add(files(
> > >  ))
> > >  acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_true: files('cpu.c',
> > > 'cpu_hotplug.c'))
> > >  acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_false:
> > > files('acpi-cpu-hotplug-stub.c'))
> > > +acpi_ss.add(when: 'CONFIG_ACPI_CPU_OSPM_INTERFACE', if_true:
> > > +files('cpu_ospm_interface.c'))
> > > +acpi_ss.add(when: 'CONFIG_ACPI_CPU_OSPM_INTERFACE', if_false:
> > > +files('acpi-cpu-ospm-interface-stub.c'))
> > >  acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_true:
> > > files('memory_hotplug.c'))
> > >  acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_false:
> > > files('acpi-mem-hotplug-stub.c'))
> > >  acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_true: files('nvdimm.c'))
> > > diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events index
> > > edc93e703c..c0ecbdd48f 100644
> > > --- a/hw/acpi/trace-events
> > > +++ b/hw/acpi/trace-events
> > > @@ -40,6 +40,23 @@ cpuhp_acpi_fw_remove_cpu(uint32_t idx)  
> > "0x%"PRIx32  
> > > cpuhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "idx[0x%"PRIx32"]
> > > OST EVENT: 0x%"PRIx32  cpuhp_acpi_write_ost_status(uint32_t slot,
> > > uint32_t st) "idx[0x%"PRIx32"] OST STATUS: 0x%"PRIx32
> > >
> > > +#cpu_ospm_interface.c
> > > +acpi_cpuos_if_invalid_idx_selected(uint32_t idx) "selector  
> > idx[0x%"PRIx32"]"  
> > > +acpi_cpuos_if_read_flags(uint32_t idx, uint8_t flags) "cpu
> > > +idx[0x%"PRIx32"] flags: 0x%"PRIx8 acpi_cpuos_if_write_idx(uint32_t
> > > +idx) "set active cpu idx: 0x%"PRIx32 acpi_cpuos_if_write_cmd(uint32_t
> > > +idx, uint8_t cmd) "cpu idx[0x%"PRIx32"] cmd: 0x%"PRIx8
> > > +acpi_cpuos_if_write_invalid_cmd(uint32_t idx, uint8_t cmd) "cpu
> > > +idx[0x%"PRIx32"] invalid cmd: 0x%"PRIx8
> > > +acpi_cpuos_if_write_invalid_offset(uint32_t idx, uint64_t addr) "cpu
> > > +idx[0x%"PRIx32"] invalid offset: 0x%"PRIx64  
> > acpi_cpuos_if_read_cmd_data(uint32_t idx, uint32_t data) "cpu
> > idx[0x%"PRIx32"] data: 0x%"PRIx32
> > acpi_cpuos_if_read_invalid_cmd_data(uint32_t idx, uint8_t cmd) "cpu
> > idx[0x%"PRIx32"] invalid cmd: 0x%"PRIx8
> > acpi_cpuos_if_cpu_has_events(uint32_t idx, bool devchk, bool ejrqst) "cpu
> > idx[0x%"PRIx32"] device-check pending: %d, eject-request pending: %d"  
> > > +acpi_cpuos_if_clear_devchk_evt(uint32_t idx) "cpu idx[0x%"PRIx32"]"
> > > +acpi_cpuos_if_clear_ejrqst_evt(uint32_t idx) "cpu idx[0x%"PRIx32"]"
> > > +acpi_cpuos_if_ejecting_invalid_cpu(uint32_t idx) "invalid cpu  
> > idx[0x%"PRIx32"]"  
> > > +acpi_cpuos_if_ejecting_cpu(uint32_t idx) "cpu idx[0x%"PRIx32"]"
> > > +acpi_cpuos_if_write_ost_ev(uint32_t idx, uint32_t ev) "cpu
> > > +idx[0x%"PRIx32"] OST Event: 0x%"PRIx32
> > > +acpi_cpuos_if_write_ost_status(uint32_t idx, uint32_t st) "cpu
> > > +idx[0x%"PRIx32"] OST Status: 0x%"PRIx32
> > > +
> > >  # pcihp.c
> > >  acpi_pci_eject_slot(unsigned bsel, unsigned slot) "bsel: %u slot: %u"
> > >  acpi_pci_unplug(int bsel, int slot) "bsel: %d slot: %d"
> > > diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index
> > > 2aa4b5d778..c9991e00c7 100644
> > > --- a/hw/arm/Kconfig
> > > +++ b/hw/arm/Kconfig
> > > @@ -39,6 +39,7 @@ config ARM_VIRT
> > >      select VIRTIO_MEM_SUPPORTED
> > >      select ACPI_CXL
> > >      select ACPI_HMAT
> > > +    select ACPI_CPU_OSPM_INTERFACE
> > >
> > >  config CUBIEBOARD
> > >      bool
> > > diff --git a/include/hw/acpi/cpu_ospm_interface.h
> > > b/include/hw/acpi/cpu_ospm_interface.h
> > > new file mode 100644
> > > index 0000000000..5dda327a34
> > > --- /dev/null
> > > +++ b/include/hw/acpi/cpu_ospm_interface.h
> > > @@ -0,0 +1,78 @@
> > > +/*
> > > + * ACPI CPU OSPM Interface Handling.
> > > + *
> > > + * Copyright (c) 2025 Huawei Technologies R&D (UK) Ltd.
> > > + *
> > > + * Author: Salil Mehta <salil.mehta@huawei.com>
> > > + *
> > > + * SPDX-License-Identifier: GPL-2.0-or-later
> > > + *
> > > + * This program is free software; you can redistribute it and/or
> > > +modify
> > > + * it under the terms of the GNU General Public License as published
> > > +by
> > > + * the ree Software Foundation; either version 2 of the License, or
> > > + * (at your option) any later version.
> > > + */
> > > +#ifndef CPU_OSPM_INTERFACE_H
> > > +#define CPU_OSPM_INTERFACE_H
> > > +
> > > +#include "qapi/qapi-types-acpi.h"
> > > +#include "hw/qdev-core.h"
> > > +#include "hw/acpi/acpi.h"
> > > +#include "hw/acpi/aml-build.h"
> > > +#include "hw/boards.h"
> > > +
> > > +/**
> > > + * Total size (in bytes) of the ACPI CPU OSPM Interface MMIO region.
> > > + *
> > > + * This region contains control and status fields such as CPU
> > > +selector,
> > > + * flags, command register, and data register. It must exactly match
> > > +the
> > > + * layout defined in the AML code and the memory region  
> > implementation.  
> > > + *
> > > + * Any mismatch between this definition and the AML layout may result
> > > +in
> > > + * runtime errors or build-time assertion failures (e.g.,
> > > +_Static_assert),
> > > + * breaking correct device emulation and guest OS coordination.
> > > + */
> > > +#define ACPI_CPU_OSPM_IF_REG_LEN 16
> > > +
> > > +typedef struct  {
> > > +    CPUState *cpu;
> > > +    uint64_t arch_id;
> > > +    bool devchk_pending; /* device-check pending */
> > > +    bool ejrqst_pending; /* eject-request pending */
> > > +    uint32_t ost_event;
> > > +    uint32_t ost_status;
> > > +} AcpiCpuOspmStateStatus;
> > > +
> > > +typedef struct AcpiCpuOspmState {
> > > +    DeviceState *acpi_dev;
> > > +    MemoryRegion ctrl_reg;
> > > +    uint32_t selector;
> > > +    uint8_t command;
> > > +    uint32_t dev_count;
> > > +    AcpiCpuOspmStateStatus *devs;
> > > +} AcpiCpuOspmState;
> > > +
> > > +void acpi_cpu_device_check_cb(AcpiCpuOspmState *cpu_st, DeviceState  
> > *dev,  
> > > +                              uint32_t event_st, Error **errp);
> > > +
> > > +void acpi_cpu_eject_request_cb(AcpiCpuOspmState *cpu_st,  
> > DeviceState *dev,  
> > > +                               uint32_t event_st, Error **errp);
> > > +
> > > +void acpi_cpu_eject_cb(AcpiCpuOspmState *cpu_st, DeviceState *dev,
> > > +                       Error **errp);
> > > +
> > > +void acpi_cpu_ospm_state_interface_init(MemoryRegion *as, Object  
> > *owner,  
> > > +                                        AcpiCpuOspmState *state,
> > > +                                        hwaddr base_addr);
> > > +
> > > +void acpi_build_cpus_aml(Aml *table, hwaddr base_addr, const char  
> > *root,  
> > > +                         const char *event_handler_method);
> > > +
> > > +void acpi_cpus_ospm_status(AcpiCpuOspmState *cpu_st,
> > > +                           ACPIOSTInfoList ***list);
> > > +
> > > +extern const VMStateDescription vmstate_cpu_ospm_state; #define
> > > +VMSTATE_CPU_OSPM_STATE(cpuospm, state) \
> > > +    VMSTATE_STRUCT(cpuospm, state, 1, \
> > > +                   vmstate_cpu_ospm_state, AcpiCpuOspmState) #endif
> > > +/* CPU_OSPM_INTERFACE_H */  
> >   
> 



  parent reply	other threads:[~2025-10-07 12:07 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-01  1:01 [PATCH RFC V6 00/24] Support of Virtual CPU Hotplug-like Feature for ARMv8+ Arch salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 01/24] hw/core: Introduce administrative power-state property and its accessors salil.mehta
2025-10-09 10:48   ` Miguel Luis
2025-10-01  1:01 ` [PATCH RFC V6 02/24] hw/core, qemu-options.hx: Introduce 'disabledcpus' SMP parameter salil.mehta
2025-10-09 11:28   ` Miguel Luis
2025-10-09 13:17     ` Igor Mammedov
2025-10-09 11:51   ` Markus Armbruster
2025-10-28  5:48   ` Gavin Shan
2025-10-01  1:01 ` [PATCH RFC V6 03/24] hw/arm/virt: Clamp 'maxcpus' as-per machine's vCPU deferred online-capability salil.mehta
2025-10-09 12:32   ` Miguel Luis
2025-10-09 13:11     ` Igor Mammedov
2025-10-01  1:01 ` [PATCH RFC V6 04/24] arm/virt, target/arm: Add new ARMCPU {socket, cluster, core, thread}-id property salil.mehta
2025-10-28  6:24   ` [PATCH RFC V6 04/24] arm/virt,target/arm: Add new ARMCPU {socket,cluster,core,thread}-id property Gavin Shan
2025-10-01  1:01 ` [PATCH RFC V6 05/24] arm/virt, kvm: Pre-create KVM vCPUs for 'disabled' QOM vCPUs at machine init salil.mehta
2025-10-22 10:36   ` [PATCH RFC V6 05/24] arm/virt,kvm: " Gavin Shan
2025-10-22 18:18     ` Salil Mehta
2025-10-22 18:50       ` Salil Mehta
2025-10-23  0:14         ` Gavin Shan
2025-10-23  0:35           ` Salil Mehta
2025-10-23  1:29             ` Salil Mehta
2025-10-23  4:14               ` Gavin Shan
2025-10-23 11:27                 ` Salil Mehta
2025-10-23  1:58             ` Gavin Shan
2025-10-23 11:17               ` Salil Mehta
2025-10-01  1:01 ` [PATCH RFC V6 06/24] arm/virt, gicv3: Pre-size GIC with possible " salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 07/24] arm/gicv3: Refactor CPU interface init for shared TCG/KVM use salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 08/24] arm/virt, gicv3: Guard CPU interface access for admin disabled vCPUs salil.mehta
2025-10-24  4:07   ` Gavin Shan
2025-10-28 11:59   ` Gavin Shan
2025-10-01  1:01 ` [PATCH RFC V6 09/24] hw/intc/arm_gicv3_common: Migrate & check 'GICv3CPUState' accessibility mismatch salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 10/24] arm/virt: Init PMU at host for all present vCPUs salil.mehta
2025-10-03 15:02   ` Igor Mammedov
2025-10-01  1:01 ` [PATCH RFC V6 11/24] hw/arm/acpi: MADT change to size the guest with possible vCPUs salil.mehta
2025-10-03 15:09   ` Igor Mammedov
     [not found]     ` <0175e40f70424dd9a29389b8a4f16c42@huawei.com>
2025-10-07 12:20       ` Igor Mammedov
2025-10-10  3:15         ` Salil Mehta
2025-10-01  1:01 ` [PATCH RFC V6 12/24] hw/core: Introduce generic device power-state handler interface salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 13/24] qdev: make admin power state changes trigger platform transitions via ACPI salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 14/24] arm/acpi: Introduce dedicated CPU OSPM interface for ARM-like platforms salil.mehta
2025-10-03 14:58   ` Igor Mammedov
     [not found]     ` <7da6a9c470684754810414f0abd23a62@huawei.com>
2025-10-07 12:06       ` Igor Mammedov [this message]
2025-10-10  3:00         ` Salil Mehta
2025-11-12 16:55           ` Igor Mammedov
2025-10-24  4:47   ` Gavin Shan
2025-10-01  1:01 ` [PATCH RFC V6 15/24] acpi/ged: Notify OSPM of CPU administrative state changes via GED salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 16/24] arm/virt/acpi: Update ACPI DSDT Tbl to include 'Online-Capable' CPUs AML salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 17/24] hw/arm/virt, acpi/ged: Add PowerStateHandler hooks for runtime CPU state changes salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 18/24] target/arm/kvm, tcg: Handle SMCCC hypercall exits in VMM during PSCI_CPU_{ON, OFF} salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 19/24] target/arm/cpu: Add the Accessor hook to fetch ARM CPU arch-id salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 20/24] target/arm/kvm: Write vCPU's state back to KVM on cold-reset salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 21/24] hw/intc/arm-gicv3-kvm: Pause all vCPUs & cache ICC_CTLR_EL1 for userspace PSCI CPU_ON salil.mehta
2025-10-01  1:01 ` [PATCH RFC V6 22/24] monitor, qdev: Introduce 'device_set' to change admin state of existing devices salil.mehta
2025-10-09  8:55   ` [PATCH RFC V6 22/24] monitor,qdev: " Markus Armbruster
2025-10-09 12:51     ` Igor Mammedov
2025-10-09 14:03       ` Daniel P. Berrangé
2025-10-09 14:55       ` Markus Armbruster
2025-10-09 15:19         ` Peter Maydell
2025-10-10  4:59           ` Markus Armbruster
2025-10-17 14:50         ` Igor Mammedov
2025-10-20 11:22           ` Markus Armbruster
2025-10-29 10:08             ` Igor Mammedov
2025-10-29 11:38               ` Markus Armbruster
2025-11-03  8:27                 ` Igor Mammedov
2025-11-07 13:10                   ` Markus Armbruster
2025-10-01  1:01 ` [PATCH RFC V6 23/24] monitor, qapi: add 'info cpus-powerstate' and QMP query (Admin + Oper states) salil.mehta
2025-10-09 11:53   ` [PATCH RFC V6 23/24] monitor,qapi: " Markus Armbruster
2025-10-01  1:01 ` [PATCH RFC V6 24/24] tcg: Defer TB flush for 'lazy realized' vCPUs on first region alloc salil.mehta
2025-10-01 21:34   ` Richard Henderson
2025-10-02 12:27     ` Salil Mehta via
2025-10-02 15:41       ` Richard Henderson
2025-10-07 10:14         ` Salil Mehta via
2025-10-06 14:00 ` [PATCH RFC V6 00/24] Support of Virtual CPU Hotplug-like Feature for ARMv8+ Arch Igor Mammedov
2025-10-13  0:34 ` Gavin Shan
2025-10-22 10:07 ` Gavin Shan
2025-10-24  6:55   ` Gavin Shan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251007140613.5916df08@fedora \
    --to=imammedo@redhat.com \
    --cc=alex.bennee@linaro.org \
    --cc=andrew.jones@linux.dev \
    --cc=ardb@kernel.org \
    --cc=armbru@redhat.com \
    --cc=borntraeger@linux.ibm.com \
    --cc=darren@os.amperecomputing.com \
    --cc=david@redhat.com \
    --cc=eric.auger@redhat.com \
    --cc=gankulkarni@os.amperecomputing.com \
    --cc=gshan@redhat.com \
    --cc=gustavo.romero@linaro.org \
    --cc=harshpb@linux.ibm.com \
    --cc=ilkka@os.amperecomputing.com \
    --cc=jean-philippe@linaro.org \
    --cc=jiakernel2@gmail.com \
    --cc=jonathan.cameron@huawei.com \
    --cc=karl.heubaum@oracle.com \
    --cc=linux@armlinux.org.uk \
    --cc=linuxarm@huawei.com \
    --cc=lixianglai@loongson.cn \
    --cc=lpieralisi@kernel.org \
    --cc=maobibo@loongson.cn \
    --cc=maz@kernel.org \
    --cc=miguel.luis@oracle.com \
    --cc=mst@redhat.com \
    --cc=npiggin@gmail.com \
    --cc=oliver.upton@linux.dev \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=rafael@kernel.org \
    --cc=richard.henderson@linaro.org \
    --cc=salil.mehta@huawei.com \
    --cc=salil.mehta@opnsrc.net \
    --cc=shahuang@redhat.com \
    --cc=vishnu@os.amperecomputing.com \
    --cc=wangxiongfeng2@huawei.com \
    --cc=wangyanan55@huawei.com \
    --cc=wangzhou1@hisilicon.com \
    --cc=will@kernel.org \
    --cc=zhao1.liu@intel.com \
    --cc=zhukeqian1@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).