summaryrefslogtreecommitdiffstats
path: root/target/arm/cpu64.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/cpu64.c')
-rw-r--r--target/arm/cpu64.c172
1 files changed, 131 insertions, 41 deletions
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index a771a28daa..c161a146ff 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -273,9 +273,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
* any of the above. Finally, if SVE is not disabled, then at least one
* vector length must be enabled.
*/
+ DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
DECLARE_BITMAP(tmp, ARM_MAX_VQ);
uint32_t vq, max_vq = 0;
+ /* Collect the set of vector lengths supported by KVM. */
+ bitmap_zero(kvm_supported, ARM_MAX_VQ);
+ if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
+ kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
+ } else if (kvm_enabled()) {
+ assert(!cpu_isar_feature(aa64_sve, cpu));
+ }
+
/*
* Process explicit sve<N> properties.
* From the properties, sve_vq_map<N> implies sve_vq_init<N>.
@@ -293,10 +302,19 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
return;
}
- /* Propagate enabled bits down through required powers-of-two. */
- for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
- if (!test_bit(vq - 1, cpu->sve_vq_init)) {
- set_bit(vq - 1, cpu->sve_vq_map);
+ if (kvm_enabled()) {
+ /*
+ * For KVM we have to automatically enable all supported unitialized
+ * lengths, even when the smaller lengths are not all powers-of-two.
+ */
+ bitmap_andnot(tmp, kvm_supported, cpu->sve_vq_init, max_vq);
+ bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
+ } else {
+ /* Propagate enabled bits down through required powers-of-two. */
+ for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
+ if (!test_bit(vq - 1, cpu->sve_vq_init)) {
+ set_bit(vq - 1, cpu->sve_vq_map);
+ }
}
}
} else if (cpu->sve_max_vq == 0) {
@@ -308,23 +326,45 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
return;
}
- /* Disabling a power-of-two disables all larger lengths. */
- if (test_bit(0, cpu->sve_vq_init)) {
- error_setg(errp, "cannot disable sve128");
- error_append_hint(errp, "Disabling sve128 results in all vector "
- "lengths being disabled.\n");
- error_append_hint(errp, "With SVE enabled, at least one vector "
- "length must be enabled.\n");
- return;
- }
- for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
- if (test_bit(vq - 1, cpu->sve_vq_init)) {
- break;
+ if (kvm_enabled()) {
+ /* Disabling a supported length disables all larger lengths. */
+ for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
+ if (test_bit(vq - 1, cpu->sve_vq_init) &&
+ test_bit(vq - 1, kvm_supported)) {
+ break;
+ }
+ }
+ max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
+ bitmap_andnot(cpu->sve_vq_map, kvm_supported,
+ cpu->sve_vq_init, max_vq);
+ if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
+ error_setg(errp, "cannot disable sve%d", vq * 128);
+ error_append_hint(errp, "Disabling sve%d results in all "
+ "vector lengths being disabled.\n",
+ vq * 128);
+ error_append_hint(errp, "With SVE enabled, at least one "
+ "vector length must be enabled.\n");
+ return;
+ }
+ } else {
+ /* Disabling a power-of-two disables all larger lengths. */
+ if (test_bit(0, cpu->sve_vq_init)) {
+ error_setg(errp, "cannot disable sve128");
+ error_append_hint(errp, "Disabling sve128 results in all "
+ "vector lengths being disabled.\n");
+ error_append_hint(errp, "With SVE enabled, at least one "
+ "vector length must be enabled.\n");
+ return;
+ }
+ for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
+ if (test_bit(vq - 1, cpu->sve_vq_init)) {
+ break;
+ }
}
+ max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
+ bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
}
- max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
- bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
}
@@ -358,16 +398,48 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
assert(max_vq != 0);
bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
- /* Ensure all required powers-of-two are enabled. */
- for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
- if (!test_bit(vq - 1, cpu->sve_vq_map)) {
- error_setg(errp, "cannot disable sve%d", vq * 128);
- error_append_hint(errp, "sve%d is required as it "
- "is a power-of-two length smaller than "
- "the maximum, sve%d\n",
- vq * 128, max_vq * 128);
+ if (kvm_enabled()) {
+ /* Ensure the set of lengths matches what KVM supports. */
+ bitmap_xor(tmp, cpu->sve_vq_map, kvm_supported, max_vq);
+ if (!bitmap_empty(tmp, max_vq)) {
+ vq = find_last_bit(tmp, max_vq) + 1;
+ if (test_bit(vq - 1, cpu->sve_vq_map)) {
+ if (cpu->sve_max_vq) {
+ error_setg(errp, "cannot set sve-max-vq=%d",
+ cpu->sve_max_vq);
+ error_append_hint(errp, "This KVM host does not support "
+ "the vector length %d-bits.\n",
+ vq * 128);
+ error_append_hint(errp, "It may not be possible to use "
+ "sve-max-vq with this KVM host. Try "
+ "using only sve<N> properties.\n");
+ } else {
+ error_setg(errp, "cannot enable sve%d", vq * 128);
+ error_append_hint(errp, "This KVM host does not support "
+ "the vector length %d-bits.\n",
+ vq * 128);
+ }
+ } else {
+ error_setg(errp, "cannot disable sve%d", vq * 128);
+ error_append_hint(errp, "The KVM host requires all "
+ "supported vector lengths smaller "
+ "than %d bits to also be enabled.\n",
+ max_vq * 128);
+ }
return;
}
+ } else {
+ /* Ensure all required powers-of-two are enabled. */
+ for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
+ if (!test_bit(vq - 1, cpu->sve_vq_map)) {
+ error_setg(errp, "cannot disable sve%d", vq * 128);
+ error_append_hint(errp, "sve%d is required as it "
+ "is a power-of-two length smaller than "
+ "the maximum, sve%d\n",
+ vq * 128, max_vq * 128);
+ return;
+ }
+ }
}
/*
@@ -421,15 +493,28 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
{
ARMCPU *cpu = ARM_CPU(obj);
Error *err = NULL;
+ uint32_t max_vq;
+
+ visit_type_uint32(v, name, &max_vq, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
- visit_type_uint32(v, name, &cpu->sve_max_vq, &err);
+ if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
+ error_setg(errp, "cannot set sve-max-vq");
+ error_append_hint(errp, "SVE not supported by KVM on this host\n");
+ return;
+ }
- if (!err && (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ)) {
- error_setg(&err, "unsupported SVE vector length");
- error_append_hint(&err, "Valid sve-max-vq in range [1-%d]\n",
+ if (max_vq == 0 || max_vq > ARM_MAX_VQ) {
+ error_setg(errp, "unsupported SVE vector length");
+ error_append_hint(errp, "Valid sve-max-vq in range [1-%d]\n",
ARM_MAX_VQ);
+ return;
}
- error_propagate(errp, err);
+
+ cpu->sve_max_vq = max_vq;
}
static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
@@ -462,6 +547,12 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
return;
}
+ if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
+ error_setg(errp, "cannot enable %s", name);
+ error_append_hint(errp, "SVE not supported by KVM on this host\n");
+ return;
+ }
+
if (value) {
set_bit(vq - 1, cpu->sve_vq_map);
} else {
@@ -619,20 +710,19 @@ static void aarch64_max_initfn(Object *obj)
cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
cpu->dcz_blocksize = 7; /* 512 bytes */
#endif
-
- object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
- cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
-
- for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
- char name[8];
- sprintf(name, "sve%d", vq * 128);
- object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
- cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
- }
}
object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
cpu_arm_set_sve, NULL, NULL, &error_fatal);
+ object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
+ cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
+
+ for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
+ char name[8];
+ sprintf(name, "sve%d", vq * 128);
+ object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
+ cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
+ }
}
struct ARMCPUInfo {