summaryrefslogtreecommitdiff
path: root/include/lib/extensions/sve.h
blob: 4458001d27b6fb37f8210956a4c2ae5748c75e49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
 * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef SVE_H
#define SVE_H

#include <arch.h>
#include <stdlib.h> /* for rand() */

#define fill_sve_helper(num) "ldr z"#num", [%0, #"#num", MUL VL];"
#define read_sve_helper(num) "str z"#num", [%0, #"#num", MUL VL];"

#define fill_sve_p_helper(num) "ldr p"#num", [%0, #"#num", MUL VL];"
#define read_sve_p_helper(num) "str p"#num", [%0, #"#num", MUL VL];"

/*
 * Max. vector length permitted by the architecture:
 * SVE:	 2048 bits = 256 bytes
 */
#define SVE_VECTOR_LEN_BYTES		(256U)
#define SVE_NUM_VECTORS			(32U)

/* Max size of one predicate register is 1/8 of Z register */
#define SVE_P_REG_LEN_BYTES		(SVE_VECTOR_LEN_BYTES / 8U)
#define SVE_NUM_P_REGS			(16U)

/* Max size of one FFR register is 1/8 of Z register */
#define SVE_FFR_REG_LEN_BYTES		(SVE_VECTOR_LEN_BYTES / 8U)
#define SVE_NUM_FFR_REGS		(1U)

#define SVE_VQ_ARCH_MIN			(0U)
#define SVE_VQ_ARCH_MAX			((1U << ZCR_EL2_SVE_VL_WIDTH) - 1U)

/* convert SVE VL in bytes to VQ */
#define SVE_VL_TO_VQ(vl_bytes)		(((vl_bytes) >> 4U) - 1U)

/* convert SVE VQ to bits */
#define SVE_VQ_TO_BITS(vq)		(((vq) + 1U) << 7U)

/* convert SVE VQ to bytes */
#define SVE_VQ_TO_BYTES(vq)		(SVE_VQ_TO_BITS(vq) / 8U)

/* get a random SVE VQ b/w 0 to SVE_VQ_ARCH_MAX */
#define SVE_GET_RANDOM_VQ		(rand() % (SVE_VQ_ARCH_MAX + 1U))

#ifndef __ASSEMBLY__

typedef uint8_t sve_z_regs_t[SVE_NUM_VECTORS * SVE_VECTOR_LEN_BYTES]
		__aligned(16);
typedef uint8_t sve_p_regs_t[SVE_NUM_P_REGS * SVE_P_REG_LEN_BYTES]
		__aligned(16);
typedef uint8_t sve_ffr_regs_t[SVE_NUM_FFR_REGS * SVE_FFR_REG_LEN_BYTES]
		__aligned(16);

void sve_config_vq(uint8_t sve_vq);
uint32_t sve_probe_vl(uint8_t sve_max_vq);

void sve_z_regs_write(const sve_z_regs_t *z_regs);
void sve_z_regs_write_rand(sve_z_regs_t *z_regs);
void sve_z_regs_read(sve_z_regs_t *z_regs);
uint64_t sve_z_regs_compare(const sve_z_regs_t *s1, const sve_z_regs_t *s2);

void sve_p_regs_write(const sve_p_regs_t *p_regs);
void sve_p_regs_write_rand(sve_p_regs_t *p_regs);
void sve_p_regs_read(sve_p_regs_t *p_regs);
uint64_t sve_p_regs_compare(const sve_p_regs_t *s1, const sve_p_regs_t *s2);

void sve_ffr_regs_write(const sve_ffr_regs_t *ffr_regs);
void sve_ffr_regs_write_rand(sve_ffr_regs_t *ffr_regs);
void sve_ffr_regs_read(sve_ffr_regs_t *ffr_regs);
uint64_t sve_ffr_regs_compare(const sve_ffr_regs_t *s1,
			      const sve_ffr_regs_t *s2);

/* Assembly routines */
bool sve_subtract_arrays_interleaved(int *dst_array, int *src_array1,
				     int *src_array2, int array_size,
				     bool (*world_switch_cb)(void));

void sve_subtract_arrays(int *dst_array, int *src_array1, int *src_array2,
			 int array_size);

#ifdef __aarch64__

/* Returns the SVE implemented VL in bytes (constrained by ZCR_EL3.LEN) */
static inline uint64_t sve_rdvl_1(void)
{
	uint64_t vl;

	__asm__ volatile(
		".arch_extension sve\n"
		"rdvl %0, #1;"
		".arch_extension nosve\n"
		: "=r" (vl)
	);

	return vl;
}

#endif /* __aarch64__ */
#endif /* __ASSEMBLY__ */
#endif /* SVE_H */