57 lines
1.3 KiB
C
57 lines
1.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2024 ARM Limited
|
|
*
|
|
* Common helper functions for SVE and SME functionality.
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include <kselftest.h>
|
|
#include <asm/sigcontext.h>
|
|
#include <sys/prctl.h>
|
|
|
|
unsigned int vls[SVE_VQ_MAX];
|
|
unsigned int nvls;
|
|
|
|
int sve_fill_vls(bool use_sme, int min_vls)
|
|
{
|
|
int vq, vl;
|
|
int pr_set_vl = use_sme ? PR_SME_SET_VL : PR_SVE_SET_VL;
|
|
int len_mask = use_sme ? PR_SME_VL_LEN_MASK : PR_SVE_VL_LEN_MASK;
|
|
|
|
/*
|
|
* Enumerate up to SVE_VQ_MAX vector lengths
|
|
*/
|
|
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
|
|
vl = prctl(pr_set_vl, vq * 16);
|
|
if (vl == -1)
|
|
return KSFT_FAIL;
|
|
|
|
vl &= len_mask;
|
|
|
|
/*
|
|
* Unlike SVE, SME does not require the minimum vector length
|
|
* to be implemented, or the VLs to be consecutive, so any call
|
|
* to the prctl might return the single implemented VL, which
|
|
* might be larger than 16. So to avoid this loop never
|
|
* terminating, bail out here when we find a higher VL than
|
|
* we asked for.
|
|
* See the ARM ARM, DDI 0487K.a, B1.4.2: I_QQRNR and I_NWYBP.
|
|
*/
|
|
if (vq < sve_vq_from_vl(vl))
|
|
break;
|
|
|
|
/* Skip missing VLs */
|
|
vq = sve_vq_from_vl(vl);
|
|
|
|
vls[nvls++] = vl;
|
|
}
|
|
|
|
if (nvls < min_vls) {
|
|
fprintf(stderr, "Only %d VL supported\n", nvls);
|
|
return KSFT_SKIP;
|
|
}
|
|
|
|
return KSFT_PASS;
|
|
}
|