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