diff mbox

[v5,15/17] target-s390x: Extend arch specific QMP command query-cpu-definitions

Message ID 1428933396-37887-16-git-send-email-mimu@linux.vnet.ibm.com
State New
Headers show

Commit Message

Michael Mueller April 13, 2015, 1:56 p.m. UTC
This patch implements the QMP command 'query-cpu-definitions' in the S390
context. The command returns a list of cpu definitions in the current host
context. A runnable and migratable cpu model has the related attributes
set to true. The order attribute is used to bring the listed cpu definitions
in a release order.

request:
  {"execute": "query-cpu-definitions",
              "arguments": { "accel": "kvm",
                             "machine": "s390-ccw-virtio" }
  }

answer:
  {"return": [ { "order": 3345, "name": "2964-ga1",
                 "live-migration-safe": true },
               { "name": "zBC12", "runnable": true },
               { "name": "2828", "runnable": true },
               ...
               { "name": "host", "runnable": true },
               ...
               { "order": 3090, "name": "2827-ga2", "runnable": true,
                 "live-migration-safe": true, "is-default": true },
               ...
               { "name": "none", "runnable": true } ]
  }

The request arguments are optional and if omitted lead to different answers.
Eventually only the CPU model none gets returned as runnable and as default

               ...
               { "name": "none", "runnable": true, "is-default": true }

Signed-off-by: Michael Mueller <mimu@linux.vnet.ibm.com>
---
 target-s390x/cpu-models.c |  15 ++++++
 target-s390x/cpu-models.h |   7 +++
 target-s390x/cpu.c        | 126 +++++++++++++++++++++++++++++++++++++++++++---
 target-s390x/kvm.c        |  49 +++++++++++++++++-
 4 files changed, 189 insertions(+), 8 deletions(-)

Comments

Christian Borntraeger April 27, 2015, 8:11 a.m. UTC | #1
Am 13.04.2015 um 15:56 schrieb Michael Mueller:
> This patch implements the QMP command 'query-cpu-definitions' in the S390
> context. The command returns a list of cpu definitions in the current host
> context. A runnable and migratable cpu model has the related attributes
> set to true. The order attribute is used to bring the listed cpu definitions
> in a release order.

Can you add some explanation why we need the fallback code (e.g. something
along the line, when querying no KVM guest is available and to query the
capabilities we have to open a dummy VM bla bla)

[...]
> -static int kvm_s390_get_machine_props(KVMState *s, S390MachineProps *prop)
> +static int get_machine_props_fallback(S390MachineProps *prop)
> +{
> +    struct kvm_device_attr dev_attr;
> +    int rc, kvmfd = -1, vmfd = -1;
> +
> +    rc  = qemu_open("/dev/kvm", O_RDWR);
> +    if (rc < 0) {
> +        goto out_err;
> +    }
> +    kvmfd = rc;
> +
> +    rc = ioctl(kvmfd, KVM_CREATE_VM, 0);
> +    if (rc < 0) {
> +        goto out_err;
> +    }
> +    vmfd = rc;
> +
> +    rc = ioctl(vmfd, KVM_CHECK_EXTENSION, KVM_CAP_VM_ATTRIBUTES);
> +    if (rc < 0) {
> +        rc = -ENOSYS;
> +        goto out_err;
> +    }
> +
> +    dev_attr.group = KVM_S390_VM_CPU_MODEL;
> +    dev_attr.attr = KVM_S390_VM_CPU_MACHINE;
> +    rc = ioctl(vmfd, KVM_HAS_DEVICE_ATTR, &dev_attr);
> +    if (rc < 0) {
> +        rc = -EFAULT;
> +        goto out_err;
> +    }
> +
> +    dev_attr.addr = (uint64_t) prop;
> +    rc = ioctl(vmfd, KVM_GET_DEVICE_ATTR, &dev_attr);
> +
> +out_err:
> +    if (vmfd >= 0) {
> +        close(vmfd);
> +    }
> +    if (kvmfd >= 0) {
> +        close(kvmfd);
> +    }
> +
> +    return rc;
> +}
> +
> +int kvm_s390_get_machine_props(KVMState *s, S390MachineProps *prop)
>  {
>      int rc = -EFAULT;
> 
>      if (s) {
>          rc = cpu_model_get(s, KVM_S390_VM_CPU_MACHINE, (uint64_t) prop);
> +    } else {
> +        rc = get_machine_props_fallback(prop);
>      }
>      trace_kvm_get_machine_props(rc, prop->cpuid, prop->ibc);
>
Michael Mueller April 27, 2015, 10:29 a.m. UTC | #2
On Mon, 27 Apr 2015 10:11:29 +0200
Christian Borntraeger <borntraeger@de.ibm.com> wrote:

> > This patch implements the QMP command 'query-cpu-definitions' in the S390
> > context. The command returns a list of cpu definitions in the current host
> > context. A runnable and migratable cpu model has the related attributes
> > set to true. The order attribute is used to bring the listed cpu definitions
> > in a release order.  
> 
> Can you add some explanation why we need the fallback code (e.g. something
> along the line, when querying no KVM guest is available and to query the
> capabilities we have to open a dummy VM bla bla)

Maybe something like that:

The returned values for attributes like runnable depend on the machine type QEMU is running on.
The function kvm_s390_get_machine_props() is used to determine that. If QEMU was started for
accelerator KVM, a KVMstate is established and machine properties are retrieved by
cpu_model_get(). In case no KVMstate was established, e.g. during QEMU startup in daemonized mode
with the default accelerator TCG, a fallback routine named get_machine_props_fallback() is used
to retrieve the KVM machine properties. It first creates a temporary VM, performs the required
ioctls and finally destroys the VM again.

Michael
diff mbox

Patch

diff --git a/target-s390x/cpu-models.c b/target-s390x/cpu-models.c
index fa74a8a..b696897 100644
--- a/target-s390x/cpu-models.c
+++ b/target-s390x/cpu-models.c
@@ -208,6 +208,21 @@  int set_s390_cpu_alias(const char *name, const char *model)
     return 0;
 }
 
+/* compare order of two cpu classes for descending sort */
+gint s390_cpu_class_desc_order_compare(gconstpointer a, gconstpointer b)
+{
+    S390CPUClass *cc_a = S390_CPU_CLASS((ObjectClass *) a);
+    S390CPUClass *cc_b = S390_CPU_CLASS((ObjectClass *) b);
+
+    if (cc_a->mach.order < cc_b->mach.order) {
+        return 1;
+    }
+    if (cc_a->mach.order > cc_b->mach.order) {
+        return -1;
+    }
+    return 0;
+}
+
 /* return machine class for specific machine type */
 static void s390_machine_class_test_cpu_class(gpointer data, gpointer user_data)
 {
diff --git a/target-s390x/cpu-models.h b/target-s390x/cpu-models.h
index c24550b..76673f4 100644
--- a/target-s390x/cpu-models.h
+++ b/target-s390x/cpu-models.h
@@ -87,6 +87,7 @@  void s390_setup_cpu_classes(S390AccelMode mode, S390MachineProps *prop,
                             uint64_t *fac_list_mask);
 void s390_setup_cpu_aliases(void);
 gint s390_cpu_class_asc_order_compare(gconstpointer a, gconstpointer b);
+gint s390_cpu_class_desc_order_compare(gconstpointer a, gconstpointer b);
 void s390_cpu_list_entry(gpointer data, gpointer user_data);
 bool s390_cpu_classes_initialized(void);
 uint64_t *s390_fac_list_mask_by_machine(const char *name);
@@ -94,10 +95,16 @@  uint64_t *s390_current_fac_list_mask(void);
 void s390_cpu_model_init(S390CPUClass *cc);
 
 #ifdef CONFIG_KVM
+int kvm_s390_get_machine_props(KVMState *s, S390MachineProps *prop);
 int kvm_s390_get_processor_props(S390ProcessorProps *prop);
 int kvm_s390_set_processor_props(S390ProcessorProps *prop);
 bool kvm_s390_cpu_classes_initialized(void);
 #else
+static inline int kvm_s390_get_machine_props(KVMState *s,
+                                             S390MachineProps *prop)
+{
+    return -ENOSYS;
+}
 static inline int kvm_s390_get_processor_props(S390ProcessorProps *prop)
 {
     return -ENOSYS;
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 771acbd..a006b93 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -30,7 +30,10 @@ 
 #include "hw/hw.h"
 #include "trace.h"
 #include "cpu-models.h"
+#include "sysemu/accel.h"
+#include "qapi/qmp/qerror.h"
 #ifndef CONFIG_USER_ONLY
+#include "hw/boards.h"
 #include "sysemu/arch_init.h"
 #endif
 
@@ -61,22 +64,131 @@  void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 }
 
 #ifndef CONFIG_USER_ONLY
+static CpuDefinitionInfoList *qmp_query_cpu_definition_host(void)
+{
+    CpuDefinitionInfoList *host = NULL;
+    CpuDefinitionInfo *info;
+
+    info = g_try_new0(CpuDefinitionInfo, 1);
+    if (!info) {
+        goto out;
+    }
+    info->name = g_strdup("host");
+
+    host = g_try_new0(CpuDefinitionInfoList, 1);
+    if (!host) {
+        g_free(info->name);
+        g_free(info);
+        goto out;
+    }
+    host->value = info;
+out:
+    return host;
+}
+
+static void qmp_query_cpu_definition_entry(gpointer data, gpointer user_data)
+{
+    ObjectClass *oc = (ObjectClass *) data;
+    S390CPUClass *cc = S390_CPU_CLASS(oc);
+    CpuDefinitionInfoList *entry, **list = user_data;
+    CpuDefinitionInfo *info;
+    GSList *item;
+    S390CPUAlias *alias;
+    ObjectClass *alias_oc;
+
+    info = g_try_new0(CpuDefinitionInfo, 1);
+    if (!info) {
+        goto out;
+    }
+    info->name = strdup_cpu_name(cc);
+    info->runnable = cc->is_active[ACCEL_TEMP];
+    info->has_runnable = info->runnable;
+    info->is_default = cc->is_host[ACCEL_TEMP];
+    info->has_is_default = info->is_default;
+    info->live_migration_safe = cc->is_migration_safe;
+    info->has_live_migration_safe = info->live_migration_safe;
+    info->order = cc->mach.order;
+    info->has_order = info->order != 0;
+
+    entry = g_try_new0(CpuDefinitionInfoList, 1);
+    if (!entry) {
+        goto out;
+    }
+    entry->value = info;
+    entry->next = *list;
+    *list = entry;
+
+    for (item = s390_cpu_aliases; item != NULL; item = item->next) {
+        alias = (S390CPUAlias *) item->data;
+        alias_oc = s390_cpu_class_by_name(alias->model);
+        if (alias_oc != oc) {
+            continue;
+        }
+
+        info = g_try_new0(CpuDefinitionInfo, 1);
+        if (!info) {
+            goto out;
+        }
+        info->name = g_strdup(alias->name);
+        info->runnable = cc->is_active[ACCEL_TEMP];
+        info->has_runnable = info->runnable;
+
+        entry = g_try_new0(CpuDefinitionInfoList, 1);
+        if (!entry) {
+            goto out;
+        }
+        entry->value = info;
+        entry->next = *list;
+        *list = entry;
+    }
+
+    return;
+out:
+    if (info) {
+        g_free(info->name);
+        g_free(info);
+    }
+}
+
 CpuDefinitionInfoList *arch_query_cpu_definitions(bool has_machine,
                                                   const char *machine,
                                                   bool has_accel,
                                                   AccelId accel,
                                                   Error **errp)
 {
-    CpuDefinitionInfoList *entry;
-    CpuDefinitionInfo *info;
+    S390MachineProps mach;
+    GSList *classes;
+    uint64_t *mask = NULL;
+    CpuDefinitionInfoList *list = NULL;
+
+    if (has_machine) {
+        mask = s390_fac_list_mask_by_machine(machine);
+        if (!mask) {
+            error_set(errp, QERR_INVALID_PARAMETER_VALUE, "machine",
+                      "a valid machine type");
+            return NULL;
+        }
+    }
 
-    info = g_malloc0(sizeof(*info));
-    info->name = g_strdup("host");
+    memset(&mach, 0, sizeof(mach));
+    if (has_accel) {
+        switch (accel) {
+        case ACCEL_ID_KVM:
+            kvm_s390_get_machine_props(NULL, &mach);
+            break;
+        default:
+            return qmp_query_cpu_definition_host();
+        }
+    }
 
-    entry = g_malloc0(sizeof(*entry));
-    entry->value = info;
+    s390_setup_cpu_classes(ACCEL_TEMP, &mach, mask);
+
+    classes = object_class_get_list(TYPE_S390_CPU, false);
+    classes = g_slist_sort(classes, s390_cpu_class_asc_order_compare);
+    g_slist_foreach(classes, qmp_query_cpu_definition_entry, &list);
+    g_slist_free(classes);
 
-    return entry;
+    return list;
 }
 #endif
 
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 784ea8c..b7b1524 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -276,12 +276,59 @@  static int cpu_model_set(KVMState *s, uint64_t attr, uint64_t addr)
     return rc;
 }
 
-static int kvm_s390_get_machine_props(KVMState *s, S390MachineProps *prop)
+static int get_machine_props_fallback(S390MachineProps *prop)
+{
+    struct kvm_device_attr dev_attr;
+    int rc, kvmfd = -1, vmfd = -1;
+
+    rc  = qemu_open("/dev/kvm", O_RDWR);
+    if (rc < 0) {
+        goto out_err;
+    }
+    kvmfd = rc;
+
+    rc = ioctl(kvmfd, KVM_CREATE_VM, 0);
+    if (rc < 0) {
+        goto out_err;
+    }
+    vmfd = rc;
+
+    rc = ioctl(vmfd, KVM_CHECK_EXTENSION, KVM_CAP_VM_ATTRIBUTES);
+    if (rc < 0) {
+        rc = -ENOSYS;
+        goto out_err;
+    }
+
+    dev_attr.group = KVM_S390_VM_CPU_MODEL;
+    dev_attr.attr = KVM_S390_VM_CPU_MACHINE;
+    rc = ioctl(vmfd, KVM_HAS_DEVICE_ATTR, &dev_attr);
+    if (rc < 0) {
+        rc = -EFAULT;
+        goto out_err;
+    }
+
+    dev_attr.addr = (uint64_t) prop;
+    rc = ioctl(vmfd, KVM_GET_DEVICE_ATTR, &dev_attr);
+
+out_err:
+    if (vmfd >= 0) {
+        close(vmfd);
+    }
+    if (kvmfd >= 0) {
+        close(kvmfd);
+    }
+
+    return rc;
+}
+
+int kvm_s390_get_machine_props(KVMState *s, S390MachineProps *prop)
 {
     int rc = -EFAULT;
 
     if (s) {
         rc = cpu_model_get(s, KVM_S390_VM_CPU_MACHINE, (uint64_t) prop);
+    } else {
+        rc = get_machine_props_fallback(prop);
     }
     trace_kvm_get_machine_props(rc, prop->cpuid, prop->ibc);