[PATCH v2 08/13] acpi: generic event device for x86

Gerd Hoffmann posted 13 patches 5 years, 7 months ago
Maintainers: Eduardo Habkost <ehabkost@redhat.com>, Igor Mammedov <imammedo@redhat.com>, Marcel Apfelbaum <marcel.apfelbaum@gmail.com>, "Michael S. Tsirkin" <mst@redhat.com>, Richard Henderson <rth@twiddle.net>, Paolo Bonzini <pbonzini@redhat.com>, Sergio Lopez <slp@redhat.com>
There is a newer version of this series
[PATCH v2 08/13] acpi: generic event device for x86
Posted by Gerd Hoffmann 5 years, 7 months ago
Uses TYPE_ACPI_GED as QOM parent for code reuse.
Add registers for sleep states and reset.
Add powerdown notifier for power button events.
Set AcpiDeviceIfClass->madt_cpu.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/hw/acpi/generic_event_device.h |  10 +++
 hw/i386/generic_event_device_x86.c     | 114 +++++++++++++++++++++++++
 hw/i386/Makefile.objs                  |   1 +
 3 files changed, 125 insertions(+)
 create mode 100644 hw/i386/generic_event_device_x86.c

diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index 9eb86ca4fd94..16d1f2b3cd30 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -68,9 +68,19 @@
 #define ACPI_GED(obj) \
     OBJECT_CHECK(AcpiGedState, (obj), TYPE_ACPI_GED)
 
+#define TYPE_ACPI_GED_X86 "acpi-ged-x86"
+#define ACPI_GED_X86(obj) \
+    OBJECT_CHECK(AcpiGedX86State, (obj), TYPE_ACPI_GED_X86)
+
 #define ACPI_GED_EVT_SEL_OFFSET    0x0
 #define ACPI_GED_EVT_SEL_LEN       0x4
 
+#define ACPI_GED_X86_REG_SLEEP_CTL 0x00
+#define ACPI_GED_X86_REG_SLEEP_STS 0x01
+#define ACPI_GED_X86_REG_RESET     0x02
+#define   ACPI_GED_X86_RESET_VALUE 0x42
+#define ACPI_GED_X86_REG_COUNT     0x03
+
 #define GED_DEVICE      "GED"
 #define AML_GED_EVT_REG "EREG"
 #define AML_GED_EVT_SEL "ESEL"
diff --git a/hw/i386/generic_event_device_x86.c b/hw/i386/generic_event_device_x86.c
new file mode 100644
index 000000000000..8ae4a63084f3
--- /dev/null
+++ b/hw/i386/generic_event_device_x86.c
@@ -0,0 +1,114 @@
+/*
+ * x86 variant of the generic event device for hw reduced acpi
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "exec/address-spaces.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/generic_event_device.h"
+#include "hw/i386/pc.h"
+#include "hw/irq.h"
+#include "hw/mem/pc-dimm.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "qemu/error-report.h"
+#include "sysemu/runstate.h"
+
+typedef struct AcpiGedX86State {
+    struct AcpiGedState parent_obj;
+    MemoryRegion regs;
+    Notifier powerdown_req;
+} AcpiGedX86State;
+
+static uint64_t acpi_ged_x86_regs_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return 0;
+}
+
+static void acpi_ged_x86_regs_write(void *opaque, hwaddr addr, uint64_t data,
+                                    unsigned int size)
+{
+    bool slp_en;
+    int slp_typ;
+
+    switch (addr) {
+    case ACPI_GED_X86_REG_SLEEP_CTL:
+        slp_typ = (data >> 2) & 0x07;
+        slp_en  = (data >> 5) & 0x01;
+        if (slp_en && slp_typ == 5) {
+            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+        }
+        return;
+    case ACPI_GED_X86_REG_SLEEP_STS:
+        return;
+    case ACPI_GED_X86_REG_RESET:
+        if (data == ACPI_GED_X86_RESET_VALUE) {
+            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+        }
+        return;
+    }
+}
+
+static const MemoryRegionOps acpi_ged_x86_regs_ops = {
+    .read = acpi_ged_x86_regs_read,
+    .write = acpi_ged_x86_regs_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void acpi_ged_x86_powerdown_req(Notifier *n, void *opaque)
+{
+    AcpiGedX86State *s = container_of(n, AcpiGedX86State, powerdown_req);
+    AcpiDeviceIf *adev = ACPI_DEVICE_IF(s);
+    AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(OBJECT(s));
+
+    adevc->send_event(adev, ACPI_POWER_DOWN_STATUS);
+}
+
+static void acpi_ged_x86_initfn(Object *obj)
+{
+    AcpiGedX86State *s = ACPI_GED_X86(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+    memory_region_init_io(&s->regs, obj, &acpi_ged_x86_regs_ops,
+                          obj, "acpi-regs", ACPI_GED_X86_REG_COUNT);
+    sysbus_init_mmio(sbd, &s->regs);
+
+    s->powerdown_req.notify = acpi_ged_x86_powerdown_req;
+    qemu_register_powerdown_notifier(&s->powerdown_req);
+}
+
+static void acpi_ged_x86_class_init(ObjectClass *class, void *data)
+{
+    AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
+
+    adevc->madt_cpu = pc_madt_cpu_entry;
+}
+
+static const TypeInfo acpi_ged_x86_info = {
+    .name          = TYPE_ACPI_GED_X86,
+    .parent        = TYPE_ACPI_GED,
+    .instance_size = sizeof(AcpiGedX86State),
+    .instance_init  = acpi_ged_x86_initfn,
+    .class_init    = acpi_ged_x86_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_HOTPLUG_HANDLER },
+        { TYPE_ACPI_DEVICE_IF },
+        { }
+    }
+};
+
+static void acpi_ged_x86_register_types(void)
+{
+    type_register_static(&acpi_ged_x86_info);
+}
+
+type_init(acpi_ged_x86_register_types)
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 6abc74551a72..622739305882 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -17,4 +17,5 @@ obj-$(CONFIG_PC) += port92.o
 
 obj-y += kvmvapic.o
 obj-$(CONFIG_ACPI) += acpi-common.o
+obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device_x86.o
 obj-$(CONFIG_PC) += acpi-build.o
-- 
2.18.4


Re: [PATCH v2 08/13] acpi: generic event device for x86
Posted by Igor Mammedov 5 years, 7 months ago
On Tue,  5 May 2020 15:43:00 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:

> Uses TYPE_ACPI_GED as QOM parent for code reuse.
> Add registers for sleep states and reset.
> Add powerdown notifier for power button events.
registers aren't x86 specific per spec,
can we put these registers into TYPE_ACPI_GED
and enable the optionally like is done with memory hotplug registers
in acpi_ged_initfn()

> Set AcpiDeviceIfClass->madt_cpu.
that's the only reason I could justify adding x86 specific flavour.

> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/hw/acpi/generic_event_device.h |  10 +++
>  hw/i386/generic_event_device_x86.c     | 114 +++++++++++++++++++++++++
>  hw/i386/Makefile.objs                  |   1 +
>  3 files changed, 125 insertions(+)
>  create mode 100644 hw/i386/generic_event_device_x86.c
> 
> diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
> index 9eb86ca4fd94..16d1f2b3cd30 100644
> --- a/include/hw/acpi/generic_event_device.h
> +++ b/include/hw/acpi/generic_event_device.h
> @@ -68,9 +68,19 @@
>  #define ACPI_GED(obj) \
>      OBJECT_CHECK(AcpiGedState, (obj), TYPE_ACPI_GED)
>  
> +#define TYPE_ACPI_GED_X86 "acpi-ged-x86"
> +#define ACPI_GED_X86(obj) \
> +    OBJECT_CHECK(AcpiGedX86State, (obj), TYPE_ACPI_GED_X86)
> +
>  #define ACPI_GED_EVT_SEL_OFFSET    0x0
>  #define ACPI_GED_EVT_SEL_LEN       0x4
>  
> +#define ACPI_GED_X86_REG_SLEEP_CTL 0x00
> +#define ACPI_GED_X86_REG_SLEEP_STS 0x01
> +#define ACPI_GED_X86_REG_RESET     0x02
> +#define   ACPI_GED_X86_RESET_VALUE 0x42
> +#define ACPI_GED_X86_REG_COUNT     0x03
> +
>  #define GED_DEVICE      "GED"
>  #define AML_GED_EVT_REG "EREG"
>  #define AML_GED_EVT_SEL "ESEL"
> diff --git a/hw/i386/generic_event_device_x86.c b/hw/i386/generic_event_device_x86.c
> new file mode 100644
> index 000000000000..8ae4a63084f3
> --- /dev/null
> +++ b/hw/i386/generic_event_device_x86.c
> @@ -0,0 +1,114 @@
> +/*
> + * x86 variant of the generic event device for hw reduced acpi
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "exec/address-spaces.h"
> +#include "hw/acpi/acpi.h"
> +#include "hw/acpi/generic_event_device.h"
> +#include "hw/i386/pc.h"
> +#include "hw/irq.h"
> +#include "hw/mem/pc-dimm.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qemu/error-report.h"
> +#include "sysemu/runstate.h"
> +
> +typedef struct AcpiGedX86State {
> +    struct AcpiGedState parent_obj;
> +    MemoryRegion regs;
> +    Notifier powerdown_req;
> +} AcpiGedX86State;
> +
> +static uint64_t acpi_ged_x86_regs_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    return 0;
> +}
> +
> +static void acpi_ged_x86_regs_write(void *opaque, hwaddr addr, uint64_t data,
> +                                    unsigned int size)
> +{
> +    bool slp_en;
> +    int slp_typ;
> +
> +    switch (addr) {
> +    case ACPI_GED_X86_REG_SLEEP_CTL:
> +        slp_typ = (data >> 2) & 0x07;
> +        slp_en  = (data >> 5) & 0x01;
> +        if (slp_en && slp_typ == 5) {
> +            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> +        }
> +        return;
> +    case ACPI_GED_X86_REG_SLEEP_STS:
> +        return;
> +    case ACPI_GED_X86_REG_RESET:
> +        if (data == ACPI_GED_X86_RESET_VALUE) {
> +            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> +        }
> +        return;
> +    }
> +}
> +
> +static const MemoryRegionOps acpi_ged_x86_regs_ops = {
> +    .read = acpi_ged_x86_regs_read,
> +    .write = acpi_ged_x86_regs_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static void acpi_ged_x86_powerdown_req(Notifier *n, void *opaque)
> +{
> +    AcpiGedX86State *s = container_of(n, AcpiGedX86State, powerdown_req);
> +    AcpiDeviceIf *adev = ACPI_DEVICE_IF(s);
> +    AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(OBJECT(s));
> +
> +    adevc->send_event(adev, ACPI_POWER_DOWN_STATUS);
> +}
> +
> +static void acpi_ged_x86_initfn(Object *obj)
> +{
> +    AcpiGedX86State *s = ACPI_GED_X86(obj);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> +
> +    memory_region_init_io(&s->regs, obj, &acpi_ged_x86_regs_ops,
> +                          obj, "acpi-regs", ACPI_GED_X86_REG_COUNT);
> +    sysbus_init_mmio(sbd, &s->regs);
> +
> +    s->powerdown_req.notify = acpi_ged_x86_powerdown_req;
> +    qemu_register_powerdown_notifier(&s->powerdown_req);
> +}
> +
> +static void acpi_ged_x86_class_init(ObjectClass *class, void *data)
> +{
> +    AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
> +
> +    adevc->madt_cpu = pc_madt_cpu_entry;
> +}
> +
> +static const TypeInfo acpi_ged_x86_info = {
> +    .name          = TYPE_ACPI_GED_X86,
> +    .parent        = TYPE_ACPI_GED,
> +    .instance_size = sizeof(AcpiGedX86State),
> +    .instance_init  = acpi_ged_x86_initfn,
> +    .class_init    = acpi_ged_x86_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { TYPE_HOTPLUG_HANDLER },
> +        { TYPE_ACPI_DEVICE_IF },
> +        { }
> +    }
> +};
> +
> +static void acpi_ged_x86_register_types(void)
> +{
> +    type_register_static(&acpi_ged_x86_info);
> +}
> +
> +type_init(acpi_ged_x86_register_types)
> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
> index 6abc74551a72..622739305882 100644
> --- a/hw/i386/Makefile.objs
> +++ b/hw/i386/Makefile.objs
> @@ -17,4 +17,5 @@ obj-$(CONFIG_PC) += port92.o
>  
>  obj-y += kvmvapic.o
>  obj-$(CONFIG_ACPI) += acpi-common.o
> +obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device_x86.o
>  obj-$(CONFIG_PC) += acpi-build.o


Re: [PATCH v2 08/13] acpi: generic event device for x86
Posted by Gerd Hoffmann 5 years, 7 months ago
On Tue, May 05, 2020 at 05:03:16PM +0200, Igor Mammedov wrote:
> On Tue,  5 May 2020 15:43:00 +0200
> Gerd Hoffmann <kraxel@redhat.com> wrote:
> 
> > Uses TYPE_ACPI_GED as QOM parent for code reuse.
> > Add registers for sleep states and reset.
> > Add powerdown notifier for power button events.
> registers aren't x86 specific per spec,
> can we put these registers into TYPE_ACPI_GED
> and enable the optionally like is done with memory hotplug registers
> in acpi_ged_initfn()

Sure, will do.

> > Set AcpiDeviceIfClass->madt_cpu.
> that's the only reason I could justify adding x86 specific flavour.

Also the powerdown notifier.  Seems the workflow is slightly different
on x86 (acpi device registers notifier) and arm (machine registers
notifier and calls acpidev->send_event).

take care,
  Gerd


Re: [PATCH v2 08/13] acpi: generic event device for x86
Posted by Igor Mammedov 5 years, 7 months ago
On Wed, 6 May 2020 12:31:06 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:

> On Tue, May 05, 2020 at 05:03:16PM +0200, Igor Mammedov wrote:
> > On Tue,  5 May 2020 15:43:00 +0200
> > Gerd Hoffmann <kraxel@redhat.com> wrote:
> >   
> > > Uses TYPE_ACPI_GED as QOM parent for code reuse.
> > > Add registers for sleep states and reset.
> > > Add powerdown notifier for power button events.  
> > registers aren't x86 specific per spec,
> > can we put these registers into TYPE_ACPI_GED
> > and enable the optionally like is done with memory hotplug registers
> > in acpi_ged_initfn()  
> 
> Sure, will do.
> 
> > > Set AcpiDeviceIfClass->madt_cpu.  
> > that's the only reason I could justify adding x86 specific flavour.  
> 
> Also the powerdown notifier.  Seems the workflow is slightly different
> on x86 (acpi device registers notifier) and arm (machine registers
> notifier and calls acpidev->send_event).

Is it possible to use ARM's approach, without notifier?

> 
> take care,
>   Gerd
> 


Re: [PATCH v2 08/13] acpi: generic event device for x86
Posted by Gerd Hoffmann 5 years, 7 months ago
  Hi,

> > Also the powerdown notifier.  Seems the workflow is slightly different
> > on x86 (acpi device registers notifier) and arm (machine registers
> > notifier and calls acpidev->send_event).
> 
> Is it possible to use ARM's approach, without notifier?

Without notifier isn't going to work, it has to be somewhere.

(Moving the notifier from ged to microvm shouldn't be much of
an issue, didn't try that yet though).

take care,
  Gerd