@samitouri / QOSamiQemu / commits / 5b3feb36ae

target/arm: Init sve_vq in kvm_arm_set_cpu_features_from_host

Probe for SVE vector sizes with the same scratch vm that we use for probing other features. Remove a separate initialization path in arm_cpu_sve_finalize. Unexport kvm_arm_sve_get_vls. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260216034432.23912-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Richard Henderson committed Feb 26, 2026 at 11:27 UTC 5b3feb36aecd15e4248b6a5f9eeb9c28189c7faf
4 files changed +27 -79
target/arm/cpu64.c
+1 -19
@@ -79,28 +79,10 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
79 */
80 uint32_t vq_map = cpu->sve_vq.map;
81 uint32_t vq_init = cpu->sve_vq.init;
82 - uint32_t vq_supported;
82 + uint32_t vq_supported = cpu->sve_vq.supported;
83 uint32_t vq_mask = 0;
84 uint32_t tmp, vq, max_vq = 0;
85
86 - /*
87 - * CPU models specify a set of supported vector lengths which are
88 - * enabled by default. Attempting to enable any vector length not set
89 - * in the supported bitmap results in an error. When KVM is enabled we
90 - * fetch the supported bitmap from the host.
91 - */
92 - if (kvm_enabled()) {
93 - if (kvm_arm_sve_supported()) {
94 - cpu->sve_vq.supported = kvm_arm_sve_get_vls(cpu);
95 - vq_supported = cpu->sve_vq.supported;
96 - } else {
97 - assert(!cpu_isar_feature(aa64_sve, cpu));
98 - vq_supported = 0;
99 - }
100 - } else {
101 - vq_supported = cpu->sve_vq.supported;
102 - }
103 -
86 /*
87 * Process explicit sve<N> properties.
88 * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
target/arm/kvm-stub.c
-5
@@ -95,11 +95,6 @@ void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp)
95 g_assert_not_reached();
96 }
97
98 -uint32_t kvm_arm_sve_get_vls(ARMCPU *cpu)
99 -{
100 - g_assert_not_reached();
101 -}
102 -
98 void kvm_arm_enable_mte(Object *cpuobj, Error **errp)
99 {
100 g_assert_not_reached();
target/arm/kvm.c
+26 -45
@@ -60,6 +60,7 @@ typedef struct ARMHostCPUFeatures {
60 ARMISARegisters isar;
61 uint64_t features;
62 uint32_t target;
63 + uint32_t sve_vq_supported;
64 const char *dtb_compatible;
65 } ARMHostCPUFeatures;
66
@@ -243,58 +244,34 @@ static int get_host_cpu_reg(int fd, ARMHostCPUFeatures *ahcf,
244 return ret;
245 }
246
246 -uint32_t kvm_arm_sve_get_vls(ARMCPU *cpu)
247 +static uint32_t kvm_arm_sve_get_vls(int fd)
248 {
249 /* Only call this function if kvm_arm_sve_supported() returns true. */
249 - static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
250 - static bool probed;
250 + uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
251 + struct kvm_one_reg reg = {
252 + .id = KVM_REG_ARM64_SVE_VLS,
253 + .addr = (uint64_t)&vls[0],
254 + };
255 uint32_t vq = 0;
252 - int i;
253 -
254 - /*
255 - * KVM ensures all host CPUs support the same set of vector lengths.
256 - * So we only need to create the scratch VCPUs once and then cache
257 - * the results.
258 - */
259 - if (!probed) {
260 - struct kvm_vcpu_init init = {
261 - .target = -1,
262 - .features[0] = (1 << KVM_ARM_VCPU_SVE),
263 - };
264 - struct kvm_one_reg reg = {
265 - .id = KVM_REG_ARM64_SVE_VLS,
266 - .addr = (uint64_t)&vls[0],
267 - };
268 - int fdarray[3], ret;
269 -
270 - probed = true;
256 + int ret;
257
272 - if (!kvm_arm_create_scratch_host_vcpu(fdarray, &init)) {
273 - error_report("failed to create scratch VCPU with SVE enabled");
274 - abort();
275 - }
276 - ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &reg);
277 - kvm_arm_destroy_scratch_host_vcpu(fdarray);
278 - if (ret) {
279 - error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s",
280 - strerror(errno));
281 - abort();
282 - }
258 + ret = ioctl(fd, KVM_GET_ONE_REG, &reg);
259 + if (ret) {
260 + error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s",
261 + strerror(errno));
262 + abort();
263 + }
264
284 - for (i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) {
285 - if (vls[i]) {
286 - vq = 64 - clz64(vls[i]) + i * 64;
287 - break;
288 - }
289 - }
290 - if (vq > ARM_MAX_VQ) {
291 - warn_report("KVM supports vector lengths larger than "
292 - "QEMU can enable");
293 - vls[0] &= MAKE_64BIT_MASK(0, ARM_MAX_VQ);
265 + for (int i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) {
266 + if (vls[i]) {
267 + vq = 64 - clz64(vls[i]) + i * 64;
268 + break;
269 }
270 }
296 -
297 - return vls[0];
271 + if (vq > ARM_MAX_VQ) {
272 + warn_report("KVM supports vector lengths larger than QEMU can enable");
273 + }
274 + return vls[0] & MAKE_64BIT_MASK(0, ARM_MAX_VQ);
275 }
276
277 static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
@@ -469,6 +446,9 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
446 * So only read the register if we set KVM_ARM_VCPU_SVE above.
447 */
448 err |= get_host_cpu_reg(fd, ahcf, ID_AA64ZFR0_EL1_IDX);
449 +
450 + /* Read the set of supported vector lengths. */
451 + arm_host_cpu_features.sve_vq_supported = kvm_arm_sve_get_vls(fd);
452 }
453 }
454
@@ -516,6 +496,7 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
496 cpu->kvm_target = arm_host_cpu_features.target;
497 cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
498 cpu->isar = arm_host_cpu_features.isar;
499 + cpu->sve_vq.supported = arm_host_cpu_features.sve_vq_supported;
500 env->features = arm_host_cpu_features.features;
501 }
502
target/arm/kvm_arm.h
-10
@@ -124,16 +124,6 @@ bool kvm_arm_create_scratch_host_vcpu(int *fdarray,
124 */
125 void kvm_arm_destroy_scratch_host_vcpu(int *fdarray);
126
127 -/**
128 - * kvm_arm_sve_get_vls:
129 - * @cpu: ARMCPU
130 - *
131 - * Get all the SVE vector lengths supported by the KVM host, setting
132 - * the bits corresponding to their length in quadwords minus one
133 - * (vq - 1) up to ARM_MAX_VQ. Return the resulting map.
134 - */
135 -uint32_t kvm_arm_sve_get_vls(ARMCPU *cpu);
136 -
127 /**
128 * kvm_arm_set_cpu_features_from_host:
129 * @cpu: ARMCPU to set the features for