This patch provides routines to dynamically update the previously defined s390
cpu classes in the current host context. The main function issuing this process
is s390_setup_cpu_classes(). It takes the current host context as parameter to
setup the classes accordingly. It basically performs the following sub-tasks:

- update of cpu classes with KVM host properties
- mark cpu class for cpu model "host"
- invalidate cpu classes not supported by this host
- set machine type aliases to latest ga of model (e.g. 2064 -> 2064-ga3)
- set aliases for common model names to machine types
- set alias for cpu model "host"

Signed-off-by: Michael Mueller <m...@linux.vnet.ibm.com>
---
 target-s390x/cpu-models.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++
 target-s390x/cpu-models.h |   2 +
 2 files changed, 261 insertions(+)

diff --git a/target-s390x/cpu-models.c b/target-s390x/cpu-models.c
index 4ce1546..ecf94a4 100644
--- a/target-s390x/cpu-models.c
+++ b/target-s390x/cpu-models.c
@@ -234,6 +234,265 @@ static int set_s390_cpu_alias(const char *name, const 
char *model)
         return 0;
 }
 
+/* compare order of two cpu classes for ascending sort */
+gint s390_cpu_class_asc_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->order < cc_b->order) {
+        return -1;
+    }
+    if (cc_a->order > cc_b->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)
+{
+    S390CPUClass *cc = S390_CPU_CLASS((ObjectClass *) data);
+    struct {
+        unsigned short type;
+        unsigned short class;
+        bool valid;
+    } *arg = user_data;
+
+    if (arg->valid || !cc->type || arg->type != cc->type) {
+        return;
+    }
+
+    arg->class = cc->class;
+    arg->valid = true;
+}
+
+/* return machine class by machine type */
+static unsigned short machine_class(unsigned short type, void *user_data)
+{
+    GSList *list = object_class_get_list(TYPE_S390_CPU, false);
+    struct {
+        unsigned short type;
+        unsigned short class;
+    } *arg = user_data;
+
+    if (arg->type != type) {
+        arg->class = 0;
+    }
+    if (!arg->class) {
+        struct {
+            unsigned short type;
+            unsigned short class;
+            bool valid;
+        } arg_class= {
+            .type = type,
+            .class = 0,
+            .valid = false,
+        };
+        g_slist_foreach(list, (GFunc) s390_machine_class_test_cpu_class, 
&arg_class);
+        g_slist_free(list);
+        if (arg_class.valid) {
+            arg->class = arg_class.class;
+                }
+    }
+    arg->type = type;
+
+    return arg->class;
+}
+
+/* mark cpu class, used in host cpu model case */
+static void s390_mark_host_cpu_class(gpointer data, gpointer user_data)
+{
+    S390CPUClass *cc = S390_CPU_CLASS((ObjectClass *) data);
+    struct {
+        struct S390HostProps *prop;
+        S390CPUClass *host_cc;
+    } *arg = user_data;
+
+    if (!cc->is_active) {
+        return;
+    }
+
+    struct {
+        unsigned short type;
+        unsigned short class;
+    } arg_class = {
+        .type = 0,
+        .class = 0,
+    };
+    if (cc->class != machine_class(arg->prop->vcpu.type, &arg_class)) {
+        return;
+    }
+    if (!arg->host_cc) {
+        cc->is_host = true;
+        arg->host_cc = cc;
+        return;
+    }
+    if (cc->order > arg->host_cc->order) {
+        arg->host_cc->is_host = false;
+        cc->is_host = true;
+        arg->host_cc = cc;
+    }
+}
+
+/* update a specific cpu model class with host retrieved configuration */
+static void s390_update_cpu_class(gpointer data, gpointer user_data)
+{
+    ObjectClass *oc = data;
+    struct S390HostProps *prop = user_data;
+    S390CPUClass *cc = S390_CPU_CLASS(oc);
+    unsigned int i;
+
+    if (!cc->type) {
+        return;
+    }
+
+    /* define model specific mandatory facility set in current host context */
+    cc->kvm_facilities = g_malloc0(MAX_S390_FACILITY_BYTE);
+    if (cc->kvm_facilities) {
+        for (i = 0; i < MAX_S390_FACILITY_ULONG; i++) {
+            cc->kvm_facilities[i] = cc->facilities[i] & 
prop->host.facility_mask[i];
+        }
+    }
+
+    /* mark cpu class active if all required facility bits are available */
+    for (i = 0; i < MAX_S390_FACILITY_BIT && cc->is_active; i++) {
+        if (test_facility(i, cc->kvm_facilities) && !test_facility(i, 
prop->vcpu.facilities)) {
+            cc->is_active = false;
+        }
+    }
+}
+
+/* a cpu class that is newer then the current host */
+static void s390_deactive_not_supported_cpu_class(gpointer data, gpointer 
user_data)
+{
+    S390CPUClass *cc = S390_CPU_CLASS((ObjectClass *) data);
+    struct {
+        S390CPUClass *host_cc;
+    } *arg = user_data;
+
+    if (!cc->is_active) {
+        return;
+    }
+    if (cc->order > arg->host_cc->order) {
+        cc->is_active = false;
+    }
+}
+
+/* set alias by type and ga */
+static int set_s390_cpu_alias_by_type_ga(unsigned short type, unsigned short 
ga)
+{
+    char name[8], model[16];
+
+    snprintf(name, sizeof(name), "%04x", type);
+    snprintf(model, sizeof(model), "%04x-ga%u", type, ga);
+
+    return set_s390_cpu_alias(name, model);
+}
+
+/* set alias if sytem has latest ga of a type type */
+static void s390_set_ga_alias_from_cpu_class(gpointer data, gpointer user_data)
+{
+    S390CPUClass *cc = S390_CPU_CLASS((ObjectClass *) data);
+    struct {
+        unsigned short type;
+        unsigned short ga;
+    } *arg = user_data;
+
+    if (!cc->is_active) {
+        return;
+    }
+    if (!arg->type) {
+        arg->type = cc->type;
+    }
+    if (cc->type == arg->type) {
+        arg->ga = cc->ga;
+        return;
+    }
+    set_s390_cpu_alias_by_type_ga(arg->type, arg->ga);
+    arg->type = cc->type;
+    arg->ga = cc->ga;
+}
+
+/* set host marked cpu class as alias to respective class */
+static void s390_set_host_alias_from_cpu_class(gpointer data, gpointer 
user_data)
+{
+    S390CPUClass *cc = S390_CPU_CLASS((ObjectClass *) data);
+    char model[16];
+
+    if (!cc->is_active || !cc->is_host) {
+        return;
+    }
+    snprintf(model, sizeof(model), "%04x-ga%u", cc->type, cc->ga);
+    set_s390_cpu_alias("host", model);
+}
+
+/*
+ * apply host properties retrieved from KVM to cpu model classes,
+ * then find cpu model host and define further aliases
+ */
+int s390_setup_cpu_classes(struct S390HostProps *prop)
+{
+    GSList *list;
+
+    list = object_class_get_list(TYPE_S390_CPU, false);
+    list = g_slist_sort(list, s390_cpu_class_asc_order_compare);
+
+    /* update cpu classes with KVM properties */
+    g_slist_foreach(list, (GFunc) s390_update_cpu_class, (gpointer) prop);
+
+    /* define cpu model "host" */
+    struct {
+        struct S390HostProps *prop;
+        S390CPUClass *host_cc;
+    } arg_host = {
+        .prop = prop,
+        .host_cc = NULL,
+    };
+    g_slist_foreach(list, (GFunc) s390_mark_host_cpu_class, (gpointer) 
&arg_host);
+
+    /* invalidate cpu classes not supported by this host */
+    struct {
+        S390CPUClass *host_cc;
+    } arg_deactivate = {
+        .host_cc = arg_host.host_cc,
+    };
+    g_slist_foreach(list, (GFunc) s390_deactive_not_supported_cpu_class, 
&arg_deactivate);
+
+    /* set machine type aliases to latest ga of model (e.g. 2064 -> 2064-ga3) 
*/
+    struct {
+        unsigned short type;
+        unsigned short ga;
+    } arg_alias = {
+        .type = 0,
+        .ga = 0,
+    };
+    g_slist_foreach(list, (GFunc) s390_set_ga_alias_from_cpu_class, 
&arg_alias);
+    set_s390_cpu_alias_by_type_ga(arg_alias.type, arg_alias.ga);
+
+    /* set aliases for common model names to machine types */
+    set_s390_cpu_alias("z900",   "2064");
+    set_s390_cpu_alias("z800",   "2066");
+    set_s390_cpu_alias("z990",   "2084");
+    set_s390_cpu_alias("z890",   "2086");
+    set_s390_cpu_alias("z9-109", "2094-ga1");
+    set_s390_cpu_alias("z9",     "2094");
+    set_s390_cpu_alias("z9-bc",  "2096");
+    set_s390_cpu_alias("z10",    "2097");
+    set_s390_cpu_alias("z10-bc", "2098");
+    set_s390_cpu_alias("z196",   "2817");
+    set_s390_cpu_alias("z114",   "2818");
+    set_s390_cpu_alias("zEC12",  "2827");
+    set_s390_cpu_alias("zBC12",  "2828");
+
+    /* set alias for cpu model "host" */
+    g_slist_foreach(list, (GFunc) s390_set_host_alias_from_cpu_class, NULL);
+
+    g_slist_free(list);
+
+    return 0;
+}
+
 /* return host specific properties */
 int s390_fetch_kvm_host_props(struct S390HostProps *prop)
 {
diff --git a/target-s390x/cpu-models.h b/target-s390x/cpu-models.h
index 0789a5e..6164114 100644
--- a/target-s390x/cpu-models.h
+++ b/target-s390x/cpu-models.h
@@ -50,6 +50,8 @@ struct S390HostProps {
 
 int s390_fetch_kvm_host_props(struct S390HostProps *prop);
 int s390_request_kvm_cpu_config(S390CPUClass *cc);
+gint s390_cpu_class_asc_order_compare(gconstpointer a, gconstpointer b);
+int s390_setup_cpu_classes(struct S390HostProps *prop);
 ObjectClass *s390_cpu_class_by_name(const char *name);
 
 /*
-- 
1.8.3.1


Reply via email to