blob: 8811af12fdbbce9c36ad3431d1d7f5283bd8a83c [file] [log] [blame]
Arunachalam Ganapathy0bbdc2d2023-04-05 15:30:18 +01001/*
2 * Copyright (c) 2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_features.h>
8#include <arch_helpers.h>
9#include <assert.h>
10#include <debug.h>
11#include <lib/extensions/sve.h>
12
13static inline uint64_t sve_read_zcr_elx(void)
14{
15 return IS_IN_EL2() ? read_zcr_el2() : read_zcr_el1();
16}
17
18static inline void sve_write_zcr_elx(uint64_t reg_val)
19{
20 if (IS_IN_EL2()) {
21 write_zcr_el2(reg_val);
22 } else {
23 write_zcr_el1(reg_val);
24 }
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +010025
Arunachalam Ganapathy0bbdc2d2023-04-05 15:30:18 +010026 isb();
27}
28
29static void _sve_config_vq(uint8_t sve_vq)
30{
31 u_register_t zcr_elx;
32
33 zcr_elx = sve_read_zcr_elx();
34 if (IS_IN_EL2()) {
35 zcr_elx &= ~(MASK(ZCR_EL2_SVE_VL));
36 zcr_elx |= INPLACE(ZCR_EL2_SVE_VL, sve_vq);
37 } else {
38 zcr_elx &= ~(MASK(ZCR_EL1_SVE_VL));
39 zcr_elx |= INPLACE(ZCR_EL1_SVE_VL, sve_vq);
40 }
41 sve_write_zcr_elx(zcr_elx);
42}
43
44/* Set the SVE vector length in the current EL's ZCR_ELx register */
45void sve_config_vq(uint8_t sve_vq)
46{
47 assert(is_armv8_2_sve_present());
48
49 /* cap vq to arch supported max value */
50 if (sve_vq > SVE_VQ_ARCH_MAX) {
51 sve_vq = SVE_VQ_ARCH_MAX;
52 }
53
54 _sve_config_vq(sve_vq);
55}
56
57/*
58 * Probes all valid vector length upto 'sve_max_vq'. Configures ZCR_ELx with 0
59 * to 'sve_max_vq'. And for each step, call sve_rdvl to get the vector length.
60 * Convert the vector length to VQ and set the bit corresponding to the VQ.
61 * Returns:
62 * bitmap corresponding to each support VL
63 */
64uint32_t sve_probe_vl(uint8_t sve_max_vq)
65{
66 uint32_t vl_bitmap = 0;
67 uint8_t vq, rdvl_vq;
68
69 assert(is_armv8_2_sve_present());
70
71 /* cap vq to arch supported max value */
72 if (sve_max_vq > SVE_VQ_ARCH_MAX) {
73 sve_max_vq = SVE_VQ_ARCH_MAX;
74 }
75
76 for (vq = 0; vq <= sve_max_vq; vq++) {
77 _sve_config_vq(vq);
Arunachalam Ganapathy03589972023-08-30 11:04:51 +010078 rdvl_vq = SVE_VL_TO_VQ(sve_rdvl_1());
Arunachalam Ganapathy0bbdc2d2023-04-05 15:30:18 +010079 if (vl_bitmap & BIT_32(rdvl_vq)) {
80 continue;
81 }
82 vl_bitmap |= BIT_32(rdvl_vq);
83 }
84
85 return vl_bitmap;
86}
Arunachalam Ganapathyd179ddc2023-04-12 10:41:42 +010087
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +010088/*
89 * Write SVE Z[0-31] registers passed in 'z_regs' for Normal SVE or Streaming
90 * SVE mode
91 */
Arunachalam Ganapathy03589972023-08-30 11:04:51 +010092void sve_z_regs_write(const sve_z_regs_t *z_regs)
Arunachalam Ganapathyd179ddc2023-04-12 10:41:42 +010093{
Arunachalam Ganapathyd179ddc2023-04-12 10:41:42 +010094 __asm__ volatile(
95 ".arch_extension sve\n"
96 fill_sve_helper(0)
97 fill_sve_helper(1)
98 fill_sve_helper(2)
99 fill_sve_helper(3)
100 fill_sve_helper(4)
101 fill_sve_helper(5)
102 fill_sve_helper(6)
103 fill_sve_helper(7)
104 fill_sve_helper(8)
105 fill_sve_helper(9)
106 fill_sve_helper(10)
107 fill_sve_helper(11)
108 fill_sve_helper(12)
109 fill_sve_helper(13)
110 fill_sve_helper(14)
111 fill_sve_helper(15)
112 fill_sve_helper(16)
113 fill_sve_helper(17)
114 fill_sve_helper(18)
115 fill_sve_helper(19)
116 fill_sve_helper(20)
117 fill_sve_helper(21)
118 fill_sve_helper(22)
119 fill_sve_helper(23)
120 fill_sve_helper(24)
121 fill_sve_helper(25)
122 fill_sve_helper(26)
123 fill_sve_helper(27)
124 fill_sve_helper(28)
125 fill_sve_helper(29)
126 fill_sve_helper(30)
127 fill_sve_helper(31)
128 ".arch_extension nosve\n"
Arunachalam Ganapathy03589972023-08-30 11:04:51 +0100129 : : "r" (z_regs));
Arunachalam Ganapathyd179ddc2023-04-12 10:41:42 +0100130}
131
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100132/*
133 * Read SVE Z[0-31] and store it in 'zregs' for Normal SVE or Streaming SVE mode
134 */
Arunachalam Ganapathy03589972023-08-30 11:04:51 +0100135void sve_z_regs_read(sve_z_regs_t *z_regs)
Arunachalam Ganapathyd179ddc2023-04-12 10:41:42 +0100136{
Arunachalam Ganapathyd179ddc2023-04-12 10:41:42 +0100137 __asm__ volatile(
138 ".arch_extension sve\n"
139 read_sve_helper(0)
140 read_sve_helper(1)
141 read_sve_helper(2)
142 read_sve_helper(3)
143 read_sve_helper(4)
144 read_sve_helper(5)
145 read_sve_helper(6)
146 read_sve_helper(7)
147 read_sve_helper(8)
148 read_sve_helper(9)
149 read_sve_helper(10)
150 read_sve_helper(11)
151 read_sve_helper(12)
152 read_sve_helper(13)
153 read_sve_helper(14)
154 read_sve_helper(15)
155 read_sve_helper(16)
156 read_sve_helper(17)
157 read_sve_helper(18)
158 read_sve_helper(19)
159 read_sve_helper(20)
160 read_sve_helper(21)
161 read_sve_helper(22)
162 read_sve_helper(23)
163 read_sve_helper(24)
164 read_sve_helper(25)
165 read_sve_helper(26)
166 read_sve_helper(27)
167 read_sve_helper(28)
168 read_sve_helper(29)
169 read_sve_helper(30)
170 read_sve_helper(31)
171 ".arch_extension nosve\n"
Arunachalam Ganapathy03589972023-08-30 11:04:51 +0100172 : : "r" (z_regs));
Arunachalam Ganapathyd179ddc2023-04-12 10:41:42 +0100173}
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100174
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100175/*
176 * Write SVE P[0-15] registers passed in 'p_regs' for Normal SVE or Streaming
177 * SVE mode
178 */
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100179void sve_p_regs_write(const sve_p_regs_t *p_regs)
180{
181 __asm__ volatile(
182 ".arch_extension sve\n"
183 fill_sve_p_helper(0)
184 fill_sve_p_helper(1)
185 fill_sve_p_helper(2)
186 fill_sve_p_helper(3)
187 fill_sve_p_helper(4)
188 fill_sve_p_helper(5)
189 fill_sve_p_helper(6)
190 fill_sve_p_helper(7)
191 fill_sve_p_helper(8)
192 fill_sve_p_helper(9)
193 fill_sve_p_helper(10)
194 fill_sve_p_helper(11)
195 fill_sve_p_helper(12)
196 fill_sve_p_helper(13)
197 fill_sve_p_helper(14)
198 fill_sve_p_helper(15)
199 ".arch_extension nosve\n"
200 : : "r" (p_regs));
201}
202
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100203/*
204 * Read SVE P[0-15] registers and store it in 'p_regs' for Normal SVE or
205 * Streaming SVE mode
206 */
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100207void sve_p_regs_read(sve_p_regs_t *p_regs)
208{
209 __asm__ volatile(
210 ".arch_extension sve\n"
211 read_sve_p_helper(0)
212 read_sve_p_helper(1)
213 read_sve_p_helper(2)
214 read_sve_p_helper(3)
215 read_sve_p_helper(4)
216 read_sve_p_helper(5)
217 read_sve_p_helper(6)
218 read_sve_p_helper(7)
219 read_sve_p_helper(8)
220 read_sve_p_helper(9)
221 read_sve_p_helper(10)
222 read_sve_p_helper(11)
223 read_sve_p_helper(12)
224 read_sve_p_helper(13)
225 read_sve_p_helper(14)
226 read_sve_p_helper(15)
227 ".arch_extension nosve\n"
228 : : "r" (p_regs));
229}
230
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100231/*
232 * Write SVE FFR registers passed in 'ffr_regs' for Normal SVE or Streaming SVE
233 * mode
234 */
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100235void sve_ffr_regs_write(const sve_ffr_regs_t *ffr_regs)
236{
237 uint8_t sve_p_reg[SVE_P_REG_LEN_BYTES];
238
239 /* Save p0. Load 'ffr_regs' to p0 and write FFR. Restore p0 */
240 __asm__ volatile(
241 ".arch_extension sve\n"
242 " str p0, [%1]\n"
243 " ldr p0, [%0]\n"
244 " wrffr p0.B\n"
245 " ldr p0, [%1]\n"
246 ".arch_extension nosve\n"
247 :
248 : "r" (ffr_regs), "r" (sve_p_reg)
249 : "memory");
250}
251
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100252/*
253 * Read SVE FFR registers and store it in 'ffr_regs' for Normal SVE or Streaming
254 * SVE mode
255 */
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100256void sve_ffr_regs_read(sve_ffr_regs_t *ffr_regs)
257{
258 uint8_t sve_p_reg[SVE_P_REG_LEN_BYTES];
259
260 /* Save p0. Read FFR to p0 and save p0 (ffr) to 'ffr_regs'. Restore p0 */
261 __asm__ volatile(
262 ".arch_extension sve\n"
263 " str p0, [%1]\n"
264 " rdffr p0.B\n"
265 " str p0, [%0]\n"
266 " ldr p0, [%1]\n"
267 ".arch_extension nosve\n"
268 :
269 : "r" (ffr_regs), "r" (sve_p_reg)
270 : "memory");
271}
272
273/*
274 * Generate random values and write it to 'z_regs', then write it to SVE Z
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100275 * registers for Normal SVE or Streaming SVE mode.
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100276 */
277void sve_z_regs_write_rand(sve_z_regs_t *z_regs)
278{
279 uint32_t rval;
280 uint32_t z_size;
281 uint8_t *z_reg;
282
283 z_size = (uint32_t)sve_rdvl_1();
284
285 /* Write Z regs */
286 rval = rand();
287 memset((void *)z_regs, 0, sizeof(sve_z_regs_t));
288 for (uint32_t i = 0U; i < SVE_NUM_VECTORS; i++) {
289 z_reg = (uint8_t *)z_regs + (i * z_size);
290
291 memset((void *)z_reg, rval * (i + 1), z_size);
292 }
293 sve_z_regs_write(z_regs);
294}
295
296/*
297 * Generate random values and write it to 'p_regs', then write it to SVE P
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100298 * registers for Normal SVE or Streaming SVE mode.
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100299 */
300void sve_p_regs_write_rand(sve_p_regs_t *p_regs)
301{
302 uint32_t p_size;
303 uint8_t *p_reg;
304 uint32_t rval;
305
306 p_size = (uint32_t)sve_rdvl_1() / 8;
307
308 /* Write P regs */
309 rval = rand();
310 memset((void *)p_regs, 0, sizeof(sve_p_regs_t));
311 for (uint32_t i = 0U; i < SVE_NUM_P_REGS; i++) {
312 p_reg = (uint8_t *)p_regs + (i * p_size);
313
314 memset((void *)p_reg, rval * (i + 1), p_size);
315 }
316 sve_p_regs_write(p_regs);
317}
318
319/*
320 * Generate random values and write it to 'ffr_regs', then write it to SVE FFR
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100321 * registers for Normal SVE or Streaming SVE mode.
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100322 */
323void sve_ffr_regs_write_rand(sve_ffr_regs_t *ffr_regs)
324{
325 uint32_t ffr_size;
326 uint8_t *ffr_reg;
327 uint32_t rval;
328
329 ffr_size = (uint32_t)sve_rdvl_1() / 8;
330
331 rval = rand();
332 memset((void *)ffr_regs, 0, sizeof(sve_ffr_regs_t));
333 for (uint32_t i = 0U; i < SVE_NUM_FFR_REGS; i++) {
334 ffr_reg = (uint8_t *)ffr_regs + (i * ffr_size);
335
336 memset((void *)ffr_reg, rval * (i + 1), ffr_size);
337 }
338 sve_ffr_regs_write(ffr_regs);
339}
340
341/*
342 * Compare Z registers passed in 's1' (old values) with 's2' (new values).
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100343 * This routine works for Normal SVE or Streaming SVE mode.
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100344 *
345 * Returns:
346 * 0 : All Z[0-31] registers in 's1' and 's2' are equal
347 * nonzero : Sets the Nth bit of the Z register that is not equal
348 */
349uint64_t sve_z_regs_compare(const sve_z_regs_t *s1, const sve_z_regs_t *s2)
350{
351 uint32_t z_size;
352 uint64_t cmp_bitmap = 0UL;
353
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100354 /*
355 * 'rdvl' returns Streaming SVE VL if PSTATE.SM=1 else returns normal
356 * SVE VL
357 */
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100358 z_size = (uint32_t)sve_rdvl_1();
359
360 for (uint32_t i = 0U; i < SVE_NUM_VECTORS; i++) {
361 uint8_t *s1_z = (uint8_t *)s1 + (i * z_size);
362 uint8_t *s2_z = (uint8_t *)s2 + (i * z_size);
363
364 if ((memcmp(s1_z, s2_z, z_size) == 0)) {
365 continue;
366 }
367
368 cmp_bitmap |= BIT_64(i);
369 VERBOSE("SVE Z_%u mismatch\n", i);
370 }
371
372 return cmp_bitmap;
373}
374
375/*
376 * Compare P registers passed in 's1' (old values) with 's2' (new values).
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100377 * This routine works for Normal SVE or Streaming SVE mode.
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100378 *
379 * Returns:
380 * 0 : All P[0-15] registers in 's1' and 's2' are equal
381 * nonzero : Sets the Nth bit of the P register that is not equal
382 */
383uint64_t sve_p_regs_compare(const sve_p_regs_t *s1, const sve_p_regs_t *s2)
384{
385 uint32_t p_size;
386 uint64_t cmp_bitmap = 0UL;
387
388 /* Size of one predicate register 1/8 of Z register */
389 p_size = (uint32_t)sve_rdvl_1() / 8U;
390
391 for (uint32_t i = 0U; i < SVE_NUM_P_REGS; i++) {
392 uint8_t *s1_p = (uint8_t *)s1 + (i * p_size);
393 uint8_t *s2_p = (uint8_t *)s2 + (i * p_size);
394
395 if ((memcmp(s1_p, s2_p, p_size) == 0)) {
396 continue;
397 }
398
399 cmp_bitmap |= BIT_64(i);
400 VERBOSE("SVE P_%u mismatch\n", i);
401 }
402
403 return cmp_bitmap;
404}
405
406/*
407 * Compare FFR register passed in 's1' (old values) with 's2' (new values).
Arunachalam Ganapathy5b68e202023-06-06 16:31:19 +0100408 * This routine works for Normal SVE or Streaming SVE mode.
Arunachalam Ganapathyfa05bd92023-08-30 14:36:53 +0100409 *
410 * Returns:
411 * 0 : FFR register in 's1' and 's2' are equal
412 * nonzero : FFR register is not equal
413 */
414uint64_t sve_ffr_regs_compare(const sve_ffr_regs_t *s1, const sve_ffr_regs_t *s2)
415{
416 uint32_t ffr_size;
417 uint64_t cmp_bitmap = 0UL;
418
419 /* Size of one FFR register 1/8 of Z register */
420 ffr_size = (uint32_t)sve_rdvl_1() / 8U;
421
422 for (uint32_t i = 0U; i < SVE_NUM_FFR_REGS; i++) {
423 uint8_t *s1_ffr = (uint8_t *)s1 + (i * ffr_size);
424 uint8_t *s2_ffr = (uint8_t *)s2 + (i * ffr_size);
425
426 if ((memcmp(s1_ffr, s2_ffr, ffr_size) == 0)) {
427 continue;
428 }
429
430 cmp_bitmap |= BIT_64(i);
431 VERBOSE("SVE FFR_%u mismatch:\n", i);
432 }
433
434 return cmp_bitmap;
435}