aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/arm-cpu-features.c104
1 files changed, 102 insertions, 2 deletions
diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
index a48f9107dd..ffdbc3fce6 100644
--- a/tests/arm-cpu-features.c
+++ b/tests/arm-cpu-features.c
@@ -130,6 +130,17 @@ static QDict *resp_get_props(QDict *resp)
return qdict;
}
+static bool resp_get_feature(QDict *resp, const char *feature)
+{
+ QDict *props;
+
+ g_assert(resp);
+ g_assert(resp_has_props(resp));
+ props = resp_get_props(resp);
+ g_assert(qdict_get(props, feature));
+ return qdict_get_bool(props, feature);
+}
+
#define assert_has_feature(qts, cpu_type, feature) \
({ \
QDict *_resp = do_query_no_props(qts, cpu_type); \
@@ -359,6 +370,25 @@ static void sve_tests_sve_off(const void *data)
qtest_quit(qts);
}
+static void sve_tests_sve_off_kvm(const void *data)
+{
+ QTestState *qts;
+
+ qts = qtest_init(MACHINE_KVM "-cpu max,sve=off");
+
+ /*
+ * We don't know if this host supports SVE so we don't
+ * attempt to test enabling anything. We only test that
+ * everything is disabled (as it should be with sve=off)
+ * and that using sve<N>=off to explicitly disable vector
+ * lengths is OK too.
+ */
+ assert_sve_vls(qts, "max", 0, NULL);
+ assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
+
+ qtest_quit(qts);
+}
+
static void test_query_cpu_model_expansion(const void *data)
{
QTestState *qts;
@@ -414,14 +444,82 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
}
if (g_str_equal(qtest_get_arch(), "aarch64")) {
+ bool kvm_supports_sve;
+ char max_name[8], name[8];
+ uint32_t max_vq, vq;
+ uint64_t vls;
+ QDict *resp;
+ char *error;
+
assert_has_feature(qts, "host", "aarch64");
assert_has_feature(qts, "host", "pmu");
- assert_has_feature(qts, "max", "sve");
-
assert_error(qts, "cortex-a15",
"We cannot guarantee the CPU type 'cortex-a15' works "
"with KVM on this host", NULL);
+
+ assert_has_feature(qts, "max", "sve");
+ resp = do_query_no_props(qts, "max");
+ kvm_supports_sve = resp_get_feature(resp, "sve");
+ vls = resp_get_sve_vls(resp);
+ qobject_unref(resp);
+
+ if (kvm_supports_sve) {
+ g_assert(vls != 0);
+ max_vq = 64 - __builtin_clzll(vls);
+ sprintf(max_name, "sve%d", max_vq * 128);
+
+ /* Enabling a supported length is of course fine. */
+ assert_sve_vls(qts, "max", vls, "{ %s: true }", max_name);
+
+ /* Get the next supported length smaller than max-vq. */
+ vq = 64 - __builtin_clzll(vls & ~BIT_ULL(max_vq - 1));
+ if (vq) {
+ /*
+ * We have at least one length smaller than max-vq,
+ * so we can disable max-vq.
+ */
+ assert_sve_vls(qts, "max", (vls & ~BIT_ULL(max_vq - 1)),
+ "{ %s: false }", max_name);
+
+ /*
+ * Smaller, supported vector lengths cannot be disabled
+ * unless all larger, supported vector lengths are also
+ * disabled.
+ */
+ sprintf(name, "sve%d", vq * 128);
+ error = g_strdup_printf("cannot disable %s", name);
+ assert_error(qts, "max", error,
+ "{ %s: true, %s: false }",
+ max_name, name);
+ g_free(error);
+ }
+
+ /*
+ * The smallest, supported vector length is required, because
+ * we need at least one vector length enabled.
+ */
+ vq = __builtin_ffsll(vls);
+ sprintf(name, "sve%d", vq * 128);
+ error = g_strdup_printf("cannot disable %s", name);
+ assert_error(qts, "max", error, "{ %s: false }", name);
+ g_free(error);
+
+ /* Get an unsupported length. */
+ for (vq = 1; vq <= max_vq; ++vq) {
+ if (!(vls & BIT_ULL(vq - 1))) {
+ break;
+ }
+ }
+ if (vq <= SVE_MAX_VQ) {
+ sprintf(name, "sve%d", vq * 128);
+ error = g_strdup_printf("cannot enable %s", name);
+ assert_error(qts, "max", error, "{ %s: true }", name);
+ g_free(error);
+ }
+ } else {
+ g_assert(vls == 0);
+ }
} else {
assert_has_not_feature(qts, "host", "aarch64");
assert_has_not_feature(qts, "host", "pmu");
@@ -454,6 +552,8 @@ int main(int argc, char **argv)
NULL, sve_tests_sve_max_vq_8);
qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
NULL, sve_tests_sve_off);
+ qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
+ NULL, sve_tests_sve_off_kvm);
}
return g_test_run();