@@ -625,3 +625,129 @@ void machine_free_hybrid_topology(MachineState *ms)
g_free(ms->topo.hybrid.cluster_list);
}
}
+
+/*
+ * Report information of a machine's supported CPU hybrid topology
+ * hierarchy. Topology members will be ordered in the string as:
+ * sockets (%u) * dies (%u) * ( cluster0:[ core0:[ cores (type: %s, %u) *
+ * threads (%u) ] + ... + core_n:[ cores (type: %s, %u) * threads (%u) ] ] +
+ * ... + cluster_m:[ core0:[ cores (type: %s, %u) * threads (%u) ] + ... +
+ * core_m:[ cores (type: %s, %u) * threads (%u)) ] ].
+ */
+static char *hybrid_cpu_hierarchy_to_string(MachineState *ms)
+{
+ HybridCluster *cluster;
+ HybridCorePack *core_pack;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ GString *s = g_string_new(NULL);
+
+ g_string_append_printf(s, "sockets (%u)", ms->topo.hybrid.sockets);
+
+ if (mc->topo_props.dies_supported) {
+ g_string_append_printf(s, " * dies (%u)", ms->topo.hybrid.dies);
+ }
+
+ if (ms->topo.hybrid.cluster_list != NULL) {
+ g_string_append_printf(s, " * ( ");
+ for (int i = 0; i < ms->topo.hybrid.clusters; i++) {
+ if (i) {
+ g_string_append_printf(s, " + ");
+ }
+ if (mc->topo_props.clusters_supported) {
+ g_string_append_printf(s, "cluster%u ", i);
+ }
+ if (ms->topo.hybrid.cluster_list[i].cores) {
+ int core_idx = 0;
+ cluster = &ms->topo.hybrid.cluster_list[i];
+
+ QSLIST_FOREACH(core_pack, &cluster->core_pack_list, node) {
+ if (!core_idx) {
+ g_string_append_printf(
+ s, "%s ",
+ mc->topo_props.clusters_supported ?
+ ":[" : "[");
+ } else {
+ g_string_append_printf(s, " + ");
+ }
+ g_string_append_printf(
+ s, "core%u:[ cores (type: %u, "
+ "num: %u) * threads (%u) ]",
+ core_idx++, core_pack->core.core_type,
+ core_pack->core_num, core_pack->core.threads);
+ }
+ if (mc->topo_props.clusters_supported) {
+ g_string_append_printf(s, " ] ");
+ }
+ }
+ }
+ g_string_append_printf(s, " )");
+ }
+
+ return g_string_free(s, false);
+}
+
+void machine_validate_hybrid_topology(MachineState *ms, Error **errp)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ HybridCluster *cluster;
+
+ if (ms->topo.max_cpus == 0) {
+ /*
+ * Cores are not set, and maybe clusters are also not set.
+ * At present, since the coretype cannot be omitted, the core
+ * level must be specified.
+ *
+ * TODO: Support coretype and core level can be omitted.
+ */
+ g_autofree char *topo_msg = hybrid_cpu_hierarchy_to_string(ms);
+ error_setg(errp, "Invalid hybrid CPU topology: Lack "
+ "of core configuration, unable to generate "
+ "valid topology: %s", topo_msg);
+ exit(1);
+ } else {
+ /*
+ * Though currently max_cpus equals to cpus, still check cpus here
+ * as the complete code logic.
+ *
+ * TODO: Consider adding more complete online cpus configuration
+ * support in the future.
+ *
+ * Since cpus = 0 is deprecated CPU topology for smp, now -hybrid
+ * returns error directly.
+ */
+ if (ms->topo.cpus == 0) {
+ error_setg(errp, "Must set at least one cpu online");
+ exit(1);
+ }
+ }
+
+ /* Each cluster need at least one core. */
+ for (int i = 0; i < ms->topo.hybrid.clusters; i++) {
+ cluster = &ms->topo.hybrid.cluster_list[i];
+
+ if (!cluster->cores) {
+ g_autofree char *topo_msg = hybrid_cpu_hierarchy_to_string(ms);
+ error_setg(errp, "Invalid hybrid CPU topology: no core is "
+ "specified for cluster (id: %d), unable to "
+ "generate valid topology: %s",
+ i, topo_msg);
+ exit(1);
+ }
+ }
+
+ if (ms->topo.cpus < mc->min_cpus) {
+ g_autofree char *topo_msg = hybrid_cpu_hierarchy_to_string(ms);
+ error_setg(errp, "Invalid Hybrid CPUs %d. The min CPUs "
+ "supported by machine '%s' is %d. Topology: %s",
+ ms->topo.cpus, mc->name, mc->min_cpus, topo_msg);
+ exit(1);
+ }
+
+ if (ms->topo.max_cpus > mc->max_cpus) {
+ g_autofree char *topo_msg = hybrid_cpu_hierarchy_to_string(ms);
+ error_setg(errp, "Invalid Hybrid CPUs %d. The max CPUs "
+ "supported by machine '%s' is %d. Topology: %s",
+ ms->topo.max_cpus, mc->name, mc->max_cpus, topo_msg);
+ exit(1);
+ }
+}
@@ -1327,6 +1327,10 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error *
}
}
+ if (!machine_topo_is_smp(machine)) {
+ machine_validate_hybrid_topology(machine, errp);
+ }
+
if (machine->memdev) {
ram_addr_t backend_size = object_property_get_uint(OBJECT(machine->memdev),
"size", &error_abort);
@@ -41,6 +41,7 @@ void set_hybrid_options(MachineState *ms,
const HybridOptions *config,
Error **errp);
void machine_free_hybrid_topology(MachineState *ms);
+void machine_validate_hybrid_topology(MachineState *ms, Error **errp);
/**
* machine_class_allow_dynamic_sysbus_dev: Add type to list of valid devices