|
@@ -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 {
|