diff mbox

[29/33] acpi: cpuhp: provide cpu._PXM method if running in numa mode

Message ID 1463496205-251412-30-git-send-email-imammedo@redhat.com
State New
Headers show

Commit Message

Igor Mammedov May 17, 2016, 2:43 p.m. UTC
Having proximity in SRAT table is not enough in case of
linux guest as it discards SRAT table information after
it's done with booting. So hotplugged CPUs will
go to 1st node as kernel doesn't know to what node
they belong to anymore.
So do the same as with hotplugged memory and provide
_PXM method in CPU device context so that OSPM could
assign CPU to a correct node.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
 hw/acpi/cpu.c         | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/acpi/cpu.h |  1 +
 trace-events          |  2 ++
 3 files changed, 75 insertions(+)
diff mbox

Patch

diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 28d3894..6961c64 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -7,6 +7,13 @@ 
 #define ACPI_CPU_HOTPLUG_REG_LEN 12
 #define ACPI_CPU_SELECTOR_OFFSET_WR 0
 #define ACPI_CPU_FLAGS_OFFSET_RW 4
+#define ACPI_CPU_CMD_OFFSET_WR 5
+#define ACPI_CPU_CMD_DATA_OFFSET_RW 8
+
+enum {
+    CPHP_PXM_CMD = 0,
+    CPHP_CMD_MAX
+};
 
 static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
 {
@@ -27,6 +34,18 @@  static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
         val |= cdev->is_removing  ? 4 : 0;
         trace_cpuhp_acpi_read_flags(cpu_st->selector, val);
         break;
+    case ACPI_CPU_CMD_DATA_OFFSET_RW:
+        switch (cpu_st->command) {
+        case CPHP_PXM_CMD: {
+           Object *o = OBJECT(CPU(cdev->cpu));
+           val = o ? object_property_get_int(o, "node", NULL) : ~0;
+           trace_cpuhp_acpi_read_pxm(cpu_st->selector, val);
+           break;
+        }
+        default:
+           break;
+        }
+        break;
     default:
         break;
     }
@@ -80,6 +99,12 @@  static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data,
             }
         }
         break;
+    case ACPI_CPU_CMD_OFFSET_WR:
+        trace_cpuhp_acpi_write_cmd(cpu_st->selector, data);
+        if (data < CPHP_CMD_MAX) {
+            cpu_st->command = data;
+        }
+        break;
     default:
         break;
     }
@@ -200,6 +225,7 @@  const VMStateDescription vmstate_cpu_hotplug = {
     .minimum_version_id_old = 1,
     .fields      = (VMStateField[]) {
         VMSTATE_UINT32(selector, CPUHotplugState),
+        VMSTATE_UINT32(command, CPUHotplugState),
         VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, CPUHotplugState, dev_count,
                                              vmstate_cpuhp_sts, AcpiCpuStatus),
         VMSTATE_END_OF_LIST()
@@ -213,12 +239,15 @@  const VMStateDescription vmstate_cpu_hotplug = {
 #define CPU_SCAN_METHOD   "CSCN"
 #define CPU_EJECT_METHOD  "CEJ0"
 #define CPU_NOTIFY_METHOD "CTFY"
+#define CPU_PXM_METHOD    "CPXM"
 
 #define CPU_ENABLED       "CPEN"
 #define CPU_SELECTOR      "CSEL"
 #define CPU_EJECT_EVENT   "CEJ0"
 #define CPU_INSERT_EVENT  "CINS"
 #define CPU_REMOVE_EVENT  "CRMV"
+#define CPU_COMMAND       "CCMD"
+#define CPU_DATA          "CDAT"
 
 void build_cpus_aml(Aml *table, MachineState *machine, bool acpi1_compat,
                     const char *res_root, const char *event_handler_method,
@@ -269,11 +298,16 @@  void build_cpus_aml(Aml *table, MachineState *machine, bool acpi1_compat,
         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_COMMAND, 8));
         aml_append(cpu_ctrl_dev, field);
 
         field = aml_field("PRST", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE);
         /* CPU selector, write only */
         aml_append(field, aml_named_field(CPU_SELECTOR, 32));
+        /* flags + cmd + 2byte align */
+        aml_append(field, aml_reserved_field(4 * 8));
+        aml_append(field, aml_named_field(CPU_DATA, 32));
         aml_append(cpu_ctrl_dev, field);
 
     }
@@ -282,6 +316,8 @@  void build_cpus_aml(Aml *table, MachineState *machine, bool acpi1_compat,
     cpus_dev = aml_device("\\_SB.CPUS");
     {
         int i;
+        bool has_pxm = true;
+        Error *local_err = NULL;
         Aml *one = aml_int(1);
         Aml *cpu_selector = aml_name("%s.%s", cphp_res_path, CPU_SELECTOR);
         Aml *ins_evt = aml_name("%s.%s", cphp_res_path, CPU_INSERT_EVENT);
@@ -289,10 +325,23 @@  void build_cpus_aml(Aml *table, MachineState *machine, bool acpi1_compat,
         Aml *ej_evt = aml_name("%s.%s", cphp_res_path, CPU_EJECT_EVENT);
         Aml *is_enabled = aml_name("%s.%s", cphp_res_path, CPU_ENABLED);
         Aml *ctrl_lock = aml_name("%s.%s", cphp_res_path, CPU_LOCK);
+        Aml *cpu_cmd = aml_name("%s.%s", cphp_res_path, CPU_COMMAND);
+        Aml *cpu_data = aml_name("%s.%s", cphp_res_path, CPU_DATA);
 
         aml_append(cpus_dev, aml_name_decl("_HID", aml_string("ACPI0010")));
         aml_append(cpus_dev, aml_name_decl("_CID", aml_eisaid("PNP0A05")));
 
+        /*
+         * sample 1st VCPU (BSP) if it has support for numa and use result
+         * to enable _PXM method support
+         */
+        object_property_get_int(OBJECT(arch_ids->cpus[0].cpu), "node",
+                                &local_err);
+        if (local_err) {
+            error_free(local_err);
+            has_pxm = false;
+        }
+
         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);
@@ -374,6 +423,23 @@  void build_cpus_aml(Aml *table, MachineState *machine, bool acpi1_compat,
         }
         aml_append(cpus_dev, method);
 
+        if (has_pxm) {
+            method = aml_method(CPU_PXM_METHOD, 1, AML_SERIALIZED);
+            {
+                Aml *uid = aml_arg(0);
+                Aml *pxm = aml_local(0);
+                Aml *pxm_cmd = aml_int(CPHP_PXM_CMD);
+
+                aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
+                aml_append(method, aml_store(uid, cpu_selector));
+                aml_append(method, aml_store(pxm_cmd, cpu_cmd));
+                aml_append(method, aml_store(cpu_data, pxm));
+                aml_append(method, aml_release(ctrl_lock));
+                aml_append(method, aml_return(pxm));
+            }
+            aml_append(cpus_dev, method);
+        }
+
         /* build Processor object for each processor */
         for (i = 0; i < arch_ids->len; i++) {
             Aml *dev;
@@ -413,6 +479,12 @@  void build_cpus_aml(Aml *table, MachineState *machine, bool acpi1_compat,
             aml_append(method, aml_call1(CPU_EJECT_METHOD, uid));
             aml_append(dev, method);
 
+            if (has_pxm) {
+                method = aml_method("_PXM", 0, AML_SERIALIZED);
+                aml_append(method,
+                    aml_return(aml_call1(CPU_PXM_METHOD, uid)));
+                aml_append(dev, method);
+            }
             aml_append(cpus_dev, dev);
         }
     }
diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h
index 0346f24..f1f6165 100644
--- a/include/hw/acpi/cpu.h
+++ b/include/hw/acpi/cpu.h
@@ -28,6 +28,7 @@  typedef struct AcpiCpuStatus {
 typedef struct CPUHotplugState {
     MemoryRegion ctrl_reg;
     uint32_t selector;
+    uint32_t command;
     uint32_t dev_count;
     AcpiCpuStatus *devs;
 } CPUHotplugState;
diff --git a/trace-events b/trace-events
index 7101ba9..b141d49 100644
--- a/trace-events
+++ b/trace-events
@@ -1912,8 +1912,10 @@  aspeed_vic_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64
 # hw/acpi/cpu.c
 cpuhp_acpi_invalid_idx_selected(uint32_t idx) "0x%"PRIx32
 cpuhp_acpi_read_flags(uint32_t idx, uint8_t flags) "idx[0x%"PRIx32"] flags: 0x%"PRIx8
+cpuhp_acpi_read_pxm(uint32_t idx, uint32_t pxm) "idx[0x%"PRIx32"] flags: 0x%"PRIx32
 cpuhp_acpi_clear_inserting_evt(uint32_t idx) "idx[0x%"PRIx32"]"
 cpuhp_acpi_clear_remove_evt(uint32_t idx) "idx[0x%"PRIx32"]"
 cpuhp_acpi_write_idx(uint32_t idx) "set active cpu idx: 0x%"PRIx32
+cpuhp_acpi_write_cmd(uint32_t idx, uint8_t cmd) "idx[0x%"PRIx32"] cmd: 0x%"PRIx8
 cpuhp_acpi_ejecting_invalid_cpu(uint32_t idx) "0x%"PRIx32
 cpuhp_acpi_ejecting_cpu(uint32_t idx) "0x%"PRIx32