(Ab)use cpu hotplug event infrastructure to report per-CPU _CST change
events.

Signed-off-by: Michael S. Tsirkin <m...@redhat.com>
---

Untested infrastructure to notify about _CST changes.

 include/hw/acpi/cpu.h |  4 ++++
 hw/acpi/cpu.c         | 39 +++++++++++++++++++++++++++++++++++----
 hw/acpi/trace-events  |  3 ++-
 3 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h
index 89ce172941..31e20c590b 100644
--- a/include/hw/acpi/cpu.h
+++ b/include/hw/acpi/cpu.h
@@ -22,6 +22,7 @@ typedef struct AcpiCpuStatus {
     uint64_t arch_id;
     bool is_inserting;
     bool is_removing;
+    bool is_cst_changing;
     uint32_t ost_event;
     uint32_t ost_status;
 } AcpiCpuStatus;
@@ -37,6 +38,9 @@ typedef struct CPUHotplugState {
 void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
                       CPUHotplugState *cpu_st, DeviceState *dev, Error **errp);
 
+void acpi_cpu_change_cst(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);
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index e9e207b033..6dc0cfb901 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -66,6 +66,7 @@ static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, 
unsigned size)
         val |= cdev->cpu ? 1 : 0;
         val |= cdev->is_inserting ? 2 : 0;
         val |= cdev->is_removing  ? 4 : 0;
+        val |= cdev->is_cst_changing  ? 0x10 : 0;
         trace_cpuhp_acpi_read_flags(cpu_st->selector, val);
         break;
     case ACPI_CPU_CMD_DATA_OFFSET_RW:
@@ -126,6 +127,9 @@ static void cpu_hotplug_wr(void *opaque, hwaddr addr, 
uint64_t data,
             dev = DEVICE(cdev->cpu);
             hotplug_ctrl = qdev_get_hotplug_handler(dev);
             hotplug_handler_unplug(hotplug_ctrl, dev, NULL);
+        } else if (data & 0x10) {
+            cdev->is_cst_changing = false;
+            trace_cpuhp_acpi_clear_cst_evt(cpu_st->selector);
         }
         break;
     case ACPI_CPU_CMD_OFFSET_WR:
@@ -137,10 +141,12 @@ static void cpu_hotplug_wr(void *opaque, hwaddr addr, 
uint64_t data,
 
                 do {
                     cdev = &cpu_st->devs[iter];
-                    if (cdev->is_inserting || cdev->is_removing) {
+                    if (cdev->is_inserting || cdev->is_removing ||
+                        cdev->is_cst_changing) {
                         cpu_st->selector = iter;
                         trace_cpuhp_acpi_cpu_has_events(cpu_st->selector,
-                            cdev->is_inserting, cdev->is_removing);
+                            cdev->is_inserting, cdev->is_removing,
+                            cdev->is_cst_changing);
                         break;
                     }
                     iter = iter + 1 < cpu_st->dev_count ? iter + 1 : 0;
@@ -237,6 +243,18 @@ void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
+void acpi_cpu_change_cst(HotplugHandler *hotplug_dev,
+                         CPUHotplugState *cpu_st, DeviceState *dev, Error 
**errp)
+{
+    AcpiCpuStatus *cdev = get_cpu_status(cpu_st, dev);
+    if (!cdev) {
+        return;
+    }
+
+    cdev->is_cst_changing = true;
+    acpi_send_event(DEVICE(hotplug_dev), ACPI_CPU_HOTPLUG_STATUS);
+}
+
 void acpi_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
                                 CPUHotplugState *cpu_st,
                                 DeviceState *dev, Error **errp)
@@ -273,6 +291,7 @@ static const VMStateDescription vmstate_cpuhp_sts = {
     .fields      = (VMStateField[]) {
         VMSTATE_BOOL(is_inserting, AcpiCpuStatus),
         VMSTATE_BOOL(is_removing, AcpiCpuStatus),
+        VMSTATE_BOOL(is_cst_changing, AcpiCpuStatus),
         VMSTATE_UINT32(ost_event, AcpiCpuStatus),
         VMSTATE_UINT32(ost_status, AcpiCpuStatus),
         VMSTATE_END_OF_LIST()
@@ -309,6 +328,7 @@ const VMStateDescription vmstate_cpu_hotplug = {
 #define CPU_INSERT_EVENT  "CINS"
 #define CPU_REMOVE_EVENT  "CRMV"
 #define CPU_EJECT_EVENT   "CEJ0"
+#define CPU_CSTATE_EVENT  "CSTE"
 
 void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
                     hwaddr io_base,
@@ -361,7 +381,8 @@ void build_cpus_aml(Aml *table, MachineState *machine, 
CPUHotplugFeatures opts,
         aml_append(field, aml_named_field(CPU_REMOVE_EVENT, 1));
         /* initiates device eject, write only */
         aml_append(field, aml_named_field(CPU_EJECT_EVENT, 1));
-        aml_append(field, aml_reserved_field(4));
+        aml_append(field, aml_named_field(CPU_CSTATE_EVENT, 1));
+        aml_append(field, aml_reserved_field(3));
         aml_append(field, aml_named_field(CPU_COMMAND, 8));
         aml_append(cpu_ctrl_dev, field);
 
@@ -396,6 +417,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, 
CPUHotplugFeatures opts,
         Aml *ins_evt = aml_name("%s.%s", cphp_res_path, CPU_INSERT_EVENT);
         Aml *rm_evt = aml_name("%s.%s", cphp_res_path, CPU_REMOVE_EVENT);
         Aml *ej_evt = aml_name("%s.%s", cphp_res_path, CPU_EJECT_EVENT);
+        Aml *cst_evt = aml_name("%s.%s", cphp_res_path, CPU_CSTATE_EVENT);
 
         aml_append(cpus_dev, aml_name_decl("_HID", aml_string("ACPI0010")));
         aml_append(cpus_dev, aml_name_decl("_CID", aml_eisaid("PNP0A05")));
@@ -450,17 +472,26 @@ void build_cpus_aml(Aml *table, MachineState *machine, 
CPUHotplugFeatures opts,
             Aml *has_event = aml_local(0);
             Aml *dev_chk = aml_int(1);
             Aml *eject_req = aml_int(3);
+            Aml *cst_changed = aml_int(0x81); /* Re-evaluate _CST: ACPI 2.0: 
8.3.2 _CST (C States) */
             Aml *next_cpu_cmd = aml_int(CPHP_GET_NEXT_CPU_WITH_EVENT_CMD);
 
             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
             aml_append(method, aml_store(one, has_event));
             while_ctx = aml_while(aml_equal(has_event, one));
             {
-                 /* clear loop exit condition, ins_evt/rm_evt checks
+                 /* clear loop exit condition, ins_evt/rm_evt/cst_evt checks
                   * will set it to 1 while next_cpu_cmd returns a CPU
                   * with events */
                  aml_append(while_ctx, aml_store(zero, has_event));
                  aml_append(while_ctx, aml_store(next_cpu_cmd, cpu_cmd));
+                 ifctx = aml_if(aml_equal(cst_evt, one));
+                 {
+                     aml_append(ifctx,
+                         aml_call2(CPU_NOTIFY_METHOD, cpu_data, cst_changed));
+                     aml_append(ifctx, aml_store(one, cst_evt));
+                     aml_append(ifctx, aml_store(one, has_event));
+                 }
+                 aml_append(while_ctx, ifctx);
                  ifctx = aml_if(aml_equal(ins_evt, one));
                  {
                      aml_append(ifctx,
diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events
index df0024f8b2..d9ea0dc0e3 100644
--- a/hw/acpi/trace-events
+++ b/hw/acpi/trace-events
@@ -23,9 +23,10 @@ cpuhp_acpi_read_flags(uint32_t idx, uint8_t flags) 
"idx[0x%"PRIx32"] flags: 0x%"
 cpuhp_acpi_write_idx(uint32_t idx) "set active cpu idx: 0x%"PRIx32
 cpuhp_acpi_write_cmd(uint32_t idx, uint8_t cmd) "idx[0x%"PRIx32"] cmd: 
0x%"PRIx8
 cpuhp_acpi_read_cmd_data(uint32_t idx, uint32_t data) "idx[0x%"PRIx32"] data: 
0x%"PRIx32
-cpuhp_acpi_cpu_has_events(uint32_t idx, bool ins, bool rm) "idx[0x%"PRIx32"] 
inserting: %d, removing: %d"
+cpuhp_acpi_cpu_has_events(uint32_t idx, bool ins, bool rm, bool cst) 
"idx[0x%"PRIx32"] inserting: %d, removing: %d, cst: %d"
 cpuhp_acpi_clear_inserting_evt(uint32_t idx) "idx[0x%"PRIx32"]"
 cpuhp_acpi_clear_remove_evt(uint32_t idx) "idx[0x%"PRIx32"]"
+cpuhp_acpi_clear_cst_evt(uint32_t idx) "idx[0x%"PRIx32"]"
 cpuhp_acpi_ejecting_invalid_cpu(uint32_t idx) "0x%"PRIx32
 cpuhp_acpi_ejecting_cpu(uint32_t idx) "0x%"PRIx32
 cpuhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "idx[0x%"PRIx32"] OST 
EVENT: 0x%"PRIx32
-- 
MST

Reply via email to