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