1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2024 ARM Limited
4 *
5 * Common helper functions for SVE and SME functionality.
6 */
7
8 #include <stdbool.h>
9 #include <kselftest.h>
10 #include <asm/sigcontext.h>
11 #include <sys/prctl.h>
12
13 unsigned int vls[SVE_VQ_MAX];
14 unsigned int nvls;
15
sve_fill_vls(bool use_sme,int min_vls)16 int sve_fill_vls(bool use_sme, int min_vls)
17 {
18 int vq, vl;
19 int pr_set_vl = use_sme ? PR_SME_SET_VL : PR_SVE_SET_VL;
20 int len_mask = use_sme ? PR_SME_VL_LEN_MASK : PR_SVE_VL_LEN_MASK;
21
22 /*
23 * Enumerate up to SVE_VQ_MAX vector lengths
24 */
25 for (vq = SVE_VQ_MAX; vq > 0; --vq) {
26 vl = prctl(pr_set_vl, vq * 16);
27 if (vl == -1)
28 return KSFT_FAIL;
29
30 vl &= len_mask;
31
32 /*
33 * Unlike SVE, SME does not require the minimum vector length
34 * to be implemented, or the VLs to be consecutive, so any call
35 * to the prctl might return the single implemented VL, which
36 * might be larger than 16. So to avoid this loop never
37 * terminating, bail out here when we find a higher VL than
38 * we asked for.
39 * See the ARM ARM, DDI 0487K.a, B1.4.2: I_QQRNR and I_NWYBP.
40 */
41 if (vq < sve_vq_from_vl(vl))
42 break;
43
44 /* Skip missing VLs */
45 vq = sve_vq_from_vl(vl);
46
47 vls[nvls++] = vl;
48 }
49
50 if (nvls < min_vls) {
51 fprintf(stderr, "Only %d VL supported\n", nvls);
52 return KSFT_SKIP;
53 }
54
55 return KSFT_PASS;
56 }
57