@@ -276,3 +276,83 @@ CpuTopologyLevel machine_get_cache_topo_level(const MachineState *ms,
{
return ms->smp_cache->props[cache].topo;
}
+
+static bool machine_check_topo_support(MachineState *ms,
+ CpuTopologyLevel topo,
+ Error **errp)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ if ((topo == CPU_TOPO_LEVEL_MODULE && !mc->smp_props.modules_supported) ||
+ (topo == CPU_TOPO_LEVEL_CLUSTER && !mc->smp_props.clusters_supported) ||
+ (topo == CPU_TOPO_LEVEL_DIE && !mc->smp_props.dies_supported) ||
+ (topo == CPU_TOPO_LEVEL_BOOK && !mc->smp_props.books_supported) ||
+ (topo == CPU_TOPO_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,
+ SMPCacheName cache1,
+ SMPCacheName cache2)
+{
+ if (smp_cache->props[cache1].topo != CPU_TOPO_LEVEL_DEFAULT &&
+ smp_cache->props[cache1].topo > smp_cache->props[cache2].topo) {
+ return true;
+ }
+ return false;
+}
+
+bool machine_check_smp_cache_support(MachineState *ms,
+ const SMPCache *smp_cache,
+ Error **errp)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ for (int i = 0; i < SMP_CACHE__MAX; i++) {
+ const SMPCacheProperty *prop = &smp_cache->props[i];
+
+ /*
+ * Allow setting "default" topology level even though the cache
+ * isn't supported by machine.
+ */
+ if (prop->topo != CPU_TOPO_LEVEL_DEFAULT &&
+ !mc->smp_props.cache_supported[prop->name]) {
+ error_setg(errp,
+ "%s cache topology not supported by this machine",
+ SMPCacheName_str(prop->name));
+ return false;
+ }
+
+ if (!machine_check_topo_support(ms, prop->topo, errp)) {
+ return false;
+ }
+ }
+
+ if (smp_cache_topo_cmp(smp_cache, SMP_CACHE_L1D, SMP_CACHE_L2) ||
+ smp_cache_topo_cmp(smp_cache, SMP_CACHE_L1I, SMP_CACHE_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(smp_cache, SMP_CACHE_L2, SMP_CACHE_L3)) {
+ error_setg(errp,
+ "Invalid smp cache topology. "
+ "L3 cache topology level shouldn't be lower than L2 cache");
+ return false;
+ }
+
+ return true;
+}
@@ -926,6 +926,20 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name,
machine_parse_smp_config(ms, config, errp);
}
+static void machine_check_smp_cache(const Object *obj, const char *name,
+ Object *child, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ SMPCache *smp_cache = SMP_CACHE(child);
+
+ if (ms->smp_cache) {
+ error_setg(errp, "Invalid smp cache property. which has been set");
+ return;
+ }
+
+ machine_check_smp_cache_support(ms, smp_cache, errp);
+}
+
static void machine_get_boot(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -1045,11 +1059,10 @@ static void machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "smp",
"CPU topology");
- /* TODO: Implement check() method based on machine support. */
object_class_property_add_link(oc, "smp-cache",
TYPE_SMP_CACHE,
offsetof(MachineState, smp_cache),
- object_property_allow_set_link,
+ machine_check_smp_cache,
OBJ_PROP_LINK_STRONG);
object_class_property_set_description(oc, "smp-cache",
"SMP cache property");
@@ -47,6 +47,9 @@ 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,
SMPCacheName cache);
+bool machine_check_smp_cache_support(MachineState *ms,
+ const SMPCache *smp_cache,
+ Error **errp);
void machine_memory_devices_init(MachineState *ms, hwaddr base, uint64_t size);
/**
@@ -147,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;
@@ -156,6 +161,7 @@ typedef struct {
bool books_supported;
bool drawers_supported;
bool modules_supported;
+ bool cache_supported[SMP_CACHE__MAX];
} SMPCompatProps;
/**
Add cache_supported flags in SMPCompatProps to allow machines to configure various caches support. And implement check() method for machine's "smp-cache" link property, which will check the compatibility of the cache properties with the machine support. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- Changes since RFC v2: * Split as a separate commit to just include compatibility checking and topology checking. * Allow setting "default" topology level even though the cache isn't supported by machine. (Daniel) --- hw/core/machine-smp.c | 80 +++++++++++++++++++++++++++++++++++++++++++ hw/core/machine.c | 17 +++++++-- include/hw/boards.h | 6 ++++ 3 files changed, 101 insertions(+), 2 deletions(-)