Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64/sve: Add sysctl to set the default vector length for new processes

Because of the effect of SVE on the size of the signal frame, the
default vector length used for new processes involves a tradeoff
between performance of SVE-enabled software on the one hand, and
reliability of non-SVE-aware software on the other hand.

For this reason, the best choice depends on the repertoire of
userspace software in use and is thus best left up to distro
maintainers, sysadmins and developers.

If CONFIG_SYSCTL and CONFIG_PROC_SYSCTL are enabled, this patch
exposes the default vector length in
/proc/sys/abi/sve_default_vector_length, where boot scripts or the
adventurous can poke it.

In common with other arm64 ABI sysctls, this control is currently
global: setting it requires CAP_SYS_ADMIN in the root user
namespace, but the value set is effective for subsequent execs in
all namespaces. The control only affects _new_ processes, however:
changing it does not affect the vector length of any existing
process.

The intended usage model is that if userspace is known to be fully
SVE-tolerant (or a developer is curious to find out) then this
parameter can be cranked up during system startup.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>

authored by

Dave Martin and committed by
Will Deacon
4ffa09a9 2d2123bc

+61 -1
+61 -1
arch/arm64/kernel/fpsimd.c
··· 37 37 #include <linux/sched/task_stack.h> 38 38 #include <linux/signal.h> 39 39 #include <linux/slab.h> 40 + #include <linux/sysctl.h> 40 41 41 42 #include <asm/fpsimd.h> 42 43 #include <asm/cputype.h> ··· 335 334 vq_to_bit(sve_vq_from_vl(vl))); 336 335 return sve_vl_from_vq(bit_to_vq(bit)); 337 336 } 337 + 338 + #ifdef CONFIG_SYSCTL 339 + 340 + static int sve_proc_do_default_vl(struct ctl_table *table, int write, 341 + void __user *buffer, size_t *lenp, 342 + loff_t *ppos) 343 + { 344 + int ret; 345 + int vl = sve_default_vl; 346 + struct ctl_table tmp_table = { 347 + .data = &vl, 348 + .maxlen = sizeof(vl), 349 + }; 350 + 351 + ret = proc_dointvec(&tmp_table, write, buffer, lenp, ppos); 352 + if (ret || !write) 353 + return ret; 354 + 355 + /* Writing -1 has the special meaning "set to max": */ 356 + if (vl == -1) { 357 + /* Fail safe if sve_max_vl wasn't initialised */ 358 + if (WARN_ON(!sve_vl_valid(sve_max_vl))) 359 + vl = SVE_VL_MIN; 360 + else 361 + vl = sve_max_vl; 362 + 363 + goto chosen; 364 + } 365 + 366 + if (!sve_vl_valid(vl)) 367 + return -EINVAL; 368 + 369 + vl = find_supported_vector_length(vl); 370 + chosen: 371 + sve_default_vl = vl; 372 + return 0; 373 + } 374 + 375 + static struct ctl_table sve_default_vl_table[] = { 376 + { 377 + .procname = "sve_default_vector_length", 378 + .mode = 0644, 379 + .proc_handler = sve_proc_do_default_vl, 380 + }, 381 + { } 382 + }; 383 + 384 + static int __init sve_sysctl_init(void) 385 + { 386 + if (system_supports_sve()) 387 + if (!register_sysctl("abi", sve_default_vl_table)) 388 + return -EINVAL; 389 + 390 + return 0; 391 + } 392 + 393 + #else /* ! CONFIG_SYSCTL */ 394 + static int __init sve_sysctl_init(void) { return 0; } 395 + #endif /* ! CONFIG_SYSCTL */ 338 396 339 397 #define ZREG(sve_state, vq, n) ((char *)(sve_state) + \ 340 398 (SVE_SIG_ZREG_OFFSET(vq, n) - SVE_SIG_REGS_OFFSET)) ··· 1269 1209 if (!(elf_hwcap & HWCAP_ASIMD)) 1270 1210 pr_notice("Advanced SIMD is not implemented\n"); 1271 1211 1272 - return 0; 1212 + return sve_sysctl_init(); 1273 1213 } 1274 1214 late_initcall(fpsimd_init);