@@ -261,10 +261,47 @@ void machine_parse_smp_config(MachineState *ms,
}
}
+static bool machine_check_topo_support(MachineState *ms,
+ CpuTopologyLevel topo,
+ Error **errp)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ if ((topo == CPU_TOPOLOGY_LEVEL_MODULE && !mc->smp_props.modules_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_CLUSTER && !mc->smp_props.clusters_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_DIE && !mc->smp_props.dies_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_BOOK && !mc->smp_props.books_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_DRAWER && !mc->smp_props.drawers_supported)) {
+ error_setg(errp,
+ "Invalid topology level: %s. "
+ "The topology level is not supported by this machine",
+ CpuTopologyLevel_str(topo));
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * When both cache1 and cache2 are configured with specific topology levels
+ * (not default level), is cache1's topology level higher than cache2?
+ */
+static bool smp_cache_topo_cmp(const SmpCache *smp_cache,
+ CacheLevelAndType cache1,
+ CacheLevelAndType cache2)
+{
+ if (smp_cache->props[cache1].topology != CPU_TOPOLOGY_LEVEL_DEFAULT &&
+ smp_cache->props[cache1].topology > smp_cache->props[cache2].topology) {
+ return true;
+ }
+ return false;
+}
+
bool machine_parse_smp_cache(MachineState *ms,
const SmpCachePropertiesList *caches,
Error **errp)
{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
const SmpCachePropertiesList *node;
DECLARE_BITMAP(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX);
@@ -293,6 +330,47 @@ bool machine_parse_smp_cache(MachineState *ms,
}
}
+ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) {
+ const SmpCacheProperties *props = &ms->smp_cache.props[i];
+
+ /*
+ * Allow setting "default" topology level even though the cache
+ * isn't supported by machine.
+ */
+ if (props->topology != CPU_TOPOLOGY_LEVEL_DEFAULT &&
+ !mc->smp_props.cache_supported[props->cache]) {
+ error_setg(errp,
+ "%s cache topology not supported by this machine",
+ CacheLevelAndType_str(node->value->cache));
+ return false;
+ }
+
+ if (!machine_check_topo_support(ms, props->topology, errp)) {
+ return false;
+ }
+ }
+
+ if (smp_cache_topo_cmp(&ms->smp_cache,
+ CACHE_LEVEL_AND_TYPE_L1D,
+ CACHE_LEVEL_AND_TYPE_L2) ||
+ smp_cache_topo_cmp(&ms->smp_cache,
+ CACHE_LEVEL_AND_TYPE_L1I,
+ CACHE_LEVEL_AND_TYPE_L2)) {
+ error_setg(errp,
+ "Invalid smp cache topology. "
+ "L2 cache topology level shouldn't be lower than L1 cache");
+ return false;
+ }
+
+ if (smp_cache_topo_cmp(&ms->smp_cache,
+ CACHE_LEVEL_AND_TYPE_L2,
+ CACHE_LEVEL_AND_TYPE_L3)) {
+ error_setg(errp,
+ "Invalid smp cache topology. "
+ "L3 cache topology level shouldn't be lower than L2 cache");
+ return false;
+ }
+
return true;
}
@@ -150,6 +150,8 @@ typedef struct {
* @books_supported - whether books are supported by the machine
* @drawers_supported - whether drawers are supported by the machine
* @modules_supported - whether modules are supported by the machine
+ * @cache_supported - whether cache topologies (l1d, l1i, l2 and l3) are
+ * supported by the machine
*/
typedef struct {
bool prefer_sockets;
@@ -159,6 +161,7 @@ typedef struct {
bool books_supported;
bool drawers_supported;
bool modules_supported;
+ bool cache_supported[CACHE_LEVEL_AND_TYPE__MAX];
} SMPCompatProps;
/**