@@ -261,6 +261,31 @@ void machine_parse_smp_config(MachineState *ms,
}
}
+bool machine_parse_smp_cache(MachineState *ms,
+ const SmpCachePropertiesList *caches,
+ Error **errp)
+{
+ const SmpCachePropertiesList *node;
+ DECLARE_BITMAP(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX);
+
+ for (node = caches; node; node = node->next) {
+ /* Prohibit users from repeating settings. */
+ if (test_bit(node->value->cache, caches_bitmap)) {
+ error_setg(errp,
+ "Invalid cache properties: %s. "
+ "The cache properties are duplicated",
+ CacheLevelAndType_str(node->value->cache));
+ return false;
+ }
+
+ machine_set_cache_topo_level(ms, node->value->cache,
+ node->value->topology);
+ set_bit(node->value->cache, caches_bitmap);
+ }
+
+ return true;
+}
+
unsigned int machine_topo_get_cores_per_socket(const MachineState *ms)
{
return ms->smp.cores * ms->smp.modules * ms->smp.clusters * ms->smp.dies;
@@ -270,3 +295,15 @@ unsigned int machine_topo_get_threads_per_socket(const MachineState *ms)
{
return ms->smp.threads * machine_topo_get_cores_per_socket(ms);
}
+
+CpuTopologyLevel machine_get_cache_topo_level(const MachineState *ms,
+ CacheLevelAndType cache)
+{
+ return ms->smp_cache.props[cache].topology;
+}
+
+void machine_set_cache_topo_level(MachineState *ms, CacheLevelAndType cache,
+ CpuTopologyLevel level)
+{
+ ms->smp_cache.props[cache].topology = level;
+}
@@ -932,6 +932,40 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name,
machine_parse_smp_config(ms, config, errp);
}
+static void machine_get_smp_cache(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ SmpCache *cache = &ms->smp_cache;
+ SmpCachePropertiesList *head = NULL;
+ SmpCachePropertiesList **tail = &head;
+
+ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) {
+ SmpCacheProperties *node = g_new(SmpCacheProperties, 1);
+
+ node->cache = cache->props[i].cache;
+ node->topology = cache->props[i].topology;
+ QAPI_LIST_APPEND(tail, node);
+ }
+
+ visit_type_SmpCachePropertiesList(v, name, &head, errp);
+ qapi_free_SmpCachePropertiesList(head);
+}
+
+static void machine_set_smp_cache(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ SmpCachePropertiesList *caches;
+
+ if (!visit_type_SmpCachePropertiesList(v, name, &caches, errp)) {
+ return;
+ }
+
+ machine_parse_smp_cache(ms, caches, errp);
+ qapi_free_SmpCachePropertiesList(caches);
+}
+
static void machine_get_boot(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -1057,6 +1091,11 @@ static void machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "smp",
"CPU topology");
+ object_class_property_add(oc, "smp-cache", "SmpCachePropertiesWrapper",
+ machine_get_smp_cache, machine_set_smp_cache, NULL, NULL);
+ object_class_property_set_description(oc, "smp-cache",
+ "Cache properties list for SMP machine");
+
object_class_property_add(oc, "phandle-start", "int",
machine_get_phandle_start, machine_set_phandle_start,
NULL, NULL);
@@ -1195,6 +1234,11 @@ static void machine_initfn(Object *obj)
ms->smp.cores = 1;
ms->smp.threads = 1;
+ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) {
+ ms->smp_cache.props[i].cache = (CacheLevelAndType)i;
+ ms->smp_cache.props[i].topology = CPU_TOPOLOGY_LEVEL_DEFAULT;
+ }
+
machine_copy_boot_config(ms, &(BootConfiguration){ 0 });
}
@@ -44,8 +44,15 @@ void machine_set_cpu_numa_node(MachineState *machine,
Error **errp);
void machine_parse_smp_config(MachineState *ms,
const SMPConfiguration *config, Error **errp);
+bool machine_parse_smp_cache(MachineState *ms,
+ const SmpCachePropertiesList *caches,
+ Error **errp);
unsigned int machine_topo_get_cores_per_socket(const MachineState *ms);
unsigned int machine_topo_get_threads_per_socket(const MachineState *ms);
+CpuTopologyLevel machine_get_cache_topo_level(const MachineState *ms,
+ CacheLevelAndType cache);
+void machine_set_cache_topo_level(MachineState *ms, CacheLevelAndType cache,
+ CpuTopologyLevel level);
void machine_memory_devices_init(MachineState *ms, hwaddr base, uint64_t size);
/**
@@ -369,6 +376,10 @@ typedef struct CpuTopology {
unsigned int max_cpus;
} CpuTopology;
+typedef struct SmpCache {
+ SmpCacheProperties props[CACHE_LEVEL_AND_TYPE__MAX];
+} SmpCache;
+
/**
* MachineState:
*/
@@ -419,6 +430,7 @@ struct MachineState {
AccelState *accelerator;
CPUArchIdList *possible_cpus;
CpuTopology smp;
+ SmpCache smp_cache;
struct NVDIMMState *nvdimms_state;
struct NumaState *numa_state;
};
@@ -60,3 +60,53 @@
{ 'enum': 'CpuTopologyLevel',
'data': [ 'thread', 'core', 'module', 'cluster', 'die',
'socket', 'book', 'drawer', 'default' ] }
+
+##
+# @CacheLevelAndType:
+#
+# Caches a system may have. The enumeration value here is the
+# combination of cache level and cache type.
+#
+# @l1d: L1 data cache.
+#
+# @l1i: L1 instruction cache.
+#
+# @l2: L2 (unified) cache.
+#
+# @l3: L3 (unified) cache
+#
+# Since: 9.2
+##
+{ 'enum': 'CacheLevelAndType',
+ 'data': [ 'l1d', 'l1i', 'l2', 'l3' ] }
+
+##
+# @SmpCacheProperties:
+#
+# Cache information for SMP system.
+#
+# @cache: Cache name, which is the combination of cache level
+# and cache type.
+#
+# @topology: Cache topology level. It accepts the CPU topology
+# enumeration as the parameter, i.e., CPUs in the same
+# topology container share the same cache.
+#
+# Since: 9.2
+##
+{ 'struct': 'SmpCacheProperties',
+ 'data': {
+ 'cache': 'CacheLevelAndType',
+ 'topology': 'CpuTopologyLevel' } }
+
+##
+# @SmpCachePropertiesWrapper:
+#
+# List wrapper of SmpCacheProperties.
+#
+# @caches: the list of SmpCacheProperties.
+#
+# Since 9.2
+##
+{ 'struct': 'SmpCachePropertiesWrapper',
+ 'data': { 'caches': ['SmpCacheProperties'] } }