1 // Copyright 2006 Google Inc. All Rights Reserved.
2 /* Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14
15 /* This is stressapptest for Rockchip platform in U-Boot, the design idea and
16 * the patterns are from code.google.com/p/stressapptest.
17 */
18
19 #include <common.h>
20 #include <amp.h>
21 #include <div64.h>
22 #include <malloc.h>
23 #include <asm/arch/rockchip_smccc.h>
24 #include "stressapptest.h"
25 #include "../ddr_tool_common.h"
26
27 #define __version__ "v1.2.0 20230619"
28
29 #if defined(CONFIG_ARM64)
30 /* Float operation in TOOLCHAIN_ARM32 will cause the compile error */
31 #define WARM_CPU
32 #endif
33
34 #define PAT_NUM 26
35 #define PATTERN_LIST_SIZE (PAT_NUM * 2 * 4)
36
37 #define CPU_NUM_MAX 16
38
39 static u32 walking_1_data[] = {
40 0x00000001, 0x00000002, 0x00000004, 0x00000008,
41 0x00000010, 0x00000020, 0x00000040, 0x00000080,
42 0x00000100, 0x00000200, 0x00000400, 0x00000800,
43 0x00001000, 0x00002000, 0x00004000, 0x00008000,
44 0x00010000, 0x00020000, 0x00040000, 0x00080000,
45 0x00100000, 0x00200000, 0x00400000, 0x00800000,
46 0x01000000, 0x02000000, 0x04000000, 0x08000000,
47 0x10000000, 0x20000000, 0x40000000, 0x80000000,
48 0x40000000, 0x20000000, 0x10000000, 0x08000000,
49 0x04000000, 0x02000000, 0x01000000, 0x00800000,
50 0x00400000, 0x00200000, 0x00100000, 0x00080000,
51 0x00040000, 0x00020000, 0x00010000, 0x00008000,
52 0x00004000, 0x00002000, 0x00001000, 0x00000800,
53 0x00000400, 0x00000200, 0x00000100, 0x00000080,
54 0x00000040, 0x00000020, 0x00000010, 0x00000008,
55 0x00000004, 0x00000002, 0x00000001, 0x00000000
56 };
57
58 static struct pat walking_1 = {
59 "walking_1",
60 walking_1_data,
61 ARRAY_SIZE(walking_1_data) - 1, /* mask */
62 {1, 1, 2, 1} /* weight */
63 };
64
65 static u32 walking_1_x16_data[] = {
66 0x00020001, 0x00080004, 0x00200010, 0x00800040,
67 0x02000100, 0x08000400, 0x20001000, 0x80004000,
68 0x20004000, 0x08001000, 0x02000400, 0x00800100,
69 0x00200040, 0x00080010, 0x00020004, 0x00000001
70 };
71
72 static struct pat walking_1_x16 = {
73 "walking_1_x16",
74 walking_1_x16_data,
75 ARRAY_SIZE(walking_1_x16_data) - 1, /* mask */
76 {2, 0, 0, 0} /* Weight for choosing 32/64/128/256 bit wide of this pattern */
77 /* Reuse for walking_0_x16, because of invert */
78 };
79
80 static u32 walking_1_x16_repeat_data[] = {
81 0x00010001, 0x00020002, 0x00040004, 0x00080008,
82 0x00100010, 0x00200020, 0x00400040, 0x00800080,
83 0x01000100, 0x02000200, 0x04000400, 0x08000800,
84 0x10001000, 0x20002000, 0x40004000, 0x80008000,
85 0x40004000, 0x20002000, 0x10001000, 0x08000800,
86 0x04000400, 0x02000200, 0x01000100, 0x00800080,
87 0x00400040, 0x00200020, 0x00100010, 0x00080008,
88 0x00040004, 0x00020002, 0x00010001, 0x00000000
89 };
90
91 static struct pat walking_1_x16_repeat = {
92 "walking_1_x16_repeat",
93 walking_1_x16_repeat_data,
94 ARRAY_SIZE(walking_1_x16_repeat_data) - 1, /* mask */
95 {2, 4, 2, 0} /* Weight for choosing 32/64/128/256 bit wide of this pattern */
96 /* Reuse for walking_0_x16_repeat, because of invert */
97 };
98
99 static u32 walking_inv_1_data[] = {
100 0x00000001, 0xfffffffe, 0x00000002, 0xfffffffd,
101 0x00000004, 0xfffffffb, 0x00000008, 0xfffffff7,
102 0x00000010, 0xffffffef, 0x00000020, 0xffffffdf,
103 0x00000040, 0xffffffbf, 0x00000080, 0xffffff7f,
104 0x00000100, 0xfffffeff, 0x00000200, 0xfffffdff,
105 0x00000400, 0xfffffbff, 0x00000800, 0xfffff7ff,
106 0x00001000, 0xffffefff, 0x00002000, 0xffffdfff,
107 0x00004000, 0xffffbfff, 0x00008000, 0xffff7fff,
108 0x00010000, 0xfffeffff, 0x00020000, 0xfffdffff,
109 0x00040000, 0xfffbffff, 0x00080000, 0xfff7ffff,
110 0x00100000, 0xffefffff, 0x00200000, 0xffdfffff,
111 0x00400000, 0xffbfffff, 0x00800000, 0xff7fffff,
112 0x01000000, 0xfeffffff, 0x02000000, 0xfdffffff,
113 0x04000000, 0xfbffffff, 0x08000000, 0xf7ffffff,
114 0x10000000, 0xefffffff, 0x20000000, 0xdfffffff,
115 0x40000000, 0xbfffffff, 0x80000000, 0x7fffffff,
116 0x40000000, 0xbfffffff, 0x20000000, 0xdfffffff,
117 0x10000000, 0xefffffff, 0x08000000, 0xf7ffffff,
118 0x04000000, 0xfbffffff, 0x02000000, 0xfdffffff,
119 0x01000000, 0xfeffffff, 0x00800000, 0xff7fffff,
120 0x00400000, 0xffbfffff, 0x00200000, 0xffdfffff,
121 0x00100000, 0xffefffff, 0x00080000, 0xfff7ffff,
122 0x00040000, 0xfffbffff, 0x00020000, 0xfffdffff,
123 0x00010000, 0xfffeffff, 0x00008000, 0xffff7fff,
124 0x00004000, 0xffffbfff, 0x00002000, 0xffffdfff,
125 0x00001000, 0xffffefff, 0x00000800, 0xfffff7ff,
126 0x00000400, 0xfffffbff, 0x00000200, 0xfffffdff,
127 0x00000100, 0xfffffeff, 0x00000080, 0xffffff7f,
128 0x00000040, 0xffffffbf, 0x00000020, 0xffffffdf,
129 0x00000010, 0xffffffef, 0x00000008, 0xfffffff7,
130 0x00000004, 0xfffffffb, 0x00000002, 0xfffffffd,
131 0x00000001, 0xfffffffe, 0x00000000, 0xffffffff
132 };
133
134 static struct pat walking_inv_1 = {
135 "walking_inv_1",
136 walking_inv_1_data,
137 ARRAY_SIZE(walking_inv_1_data) - 1, /* mask */
138 {2, 2, 5, 5} /* weight */
139 };
140
141 static u32 walking_inv_1_x16_data[] = {
142 0xfffe0001, 0xfffd0002, 0xfffb0004, 0xfff70008,
143 0xffef0010, 0xffdf0020, 0xffbf0040, 0xff7f0080,
144 0xfeff0100, 0xfdff0200, 0xfbff0400, 0xf7ff0800,
145 0xefff1000, 0xdfff2000, 0xbfff4000, 0x7fff8000,
146 0xbfff4000, 0xdfff2000, 0xefff1000, 0xf7ff0800,
147 0xfbff0400, 0xfdff0200, 0xfeff0100, 0xff7f0080,
148 0xffbf0040, 0xffdf0020, 0xffef0010, 0xfff70008,
149 0xfffb0004, 0xfffd0002, 0xfffe0001, 0xffff0000
150 };
151
152 static struct pat walking_inv_1_x16 = {
153 "walking_inv_1_x16",
154 walking_inv_1_x16_data,
155 ARRAY_SIZE(walking_inv_1_x16_data) - 1, /* mask */
156 {2, 0, 0, 0} /* weight */
157 };
158
159 static u32 walking_inv_1_x16_repeat_data[] = {
160 0x00010001, 0xfffefffe, 0x00020002, 0xfffdfffd,
161 0x00040004, 0xfffbfffb, 0x00080008, 0xfff7fff7,
162 0x00100010, 0xffefffef, 0x00200020, 0xffdfffdf,
163 0x00400040, 0xffbfffbf, 0x00800080, 0xff7fff7f,
164 0x01000100, 0xfefffeff, 0x02000200, 0xfdfffdff,
165 0x04000400, 0xfbfffbff, 0x08000800, 0xf7fff7ff,
166 0x10001000, 0xefffefff, 0x20002000, 0xdfffdfff,
167 0x40004000, 0xbfffbfff, 0x80008000, 0x7fff7fff,
168 0x40004000, 0xbfffbfff, 0x20002000, 0xdfffdfff,
169 0x10001000, 0xefffefff, 0x08000800, 0xf7fff7ff,
170 0x04000400, 0xfbfffbff, 0x02000200, 0xfdfffdff,
171 0x01000100, 0xfefffeff, 0x00800080, 0xff7fff7f,
172 0x00400040, 0xffbfffbf, 0x00200020, 0xffdfffdf,
173 0x00100010, 0xffefffef, 0x00080008, 0xfff7fff7,
174 0x00040004, 0xfffbfffb, 0x00020002, 0xfffdfffd,
175 0x00010001, 0xfffefffe, 0x00000000, 0xffffffff
176 };
177
178 static struct pat walking_inv_1_x16_repeat = {
179 "walking_inv_1_x16_repeat",
180 walking_inv_1_x16_repeat_data,
181 ARRAY_SIZE(walking_inv_1_x16_repeat_data) - 1, /* mask */
182 {2, 5, 5, 0} /* weight */
183 };
184
185 static u32 walking_0_data[] = {
186 0xfffffffe, 0xfffffffd, 0xfffffffb, 0xfffffff7,
187 0xffffffef, 0xffffffdf, 0xffffffbf, 0xffffff7f,
188 0xfffffeff, 0xfffffdff, 0xfffffbff, 0xfffff7ff,
189 0xffffefff, 0xffffdfff, 0xffffbfff, 0xffff7fff,
190 0xfffeffff, 0xfffdffff, 0xfffbffff, 0xfff7ffff,
191 0xffefffff, 0xffdfffff, 0xffbfffff, 0xff7fffff,
192 0xfeffffff, 0xfdffffff, 0xfbffffff, 0xf7ffffff,
193 0xefffffff, 0xdfffffff, 0xbfffffff, 0x7fffffff,
194 0xbfffffff, 0xdfffffff, 0xefffffff, 0xf7ffffff,
195 0xfbffffff, 0xfdffffff, 0xfeffffff, 0xff7fffff,
196 0xffbfffff, 0xffdfffff, 0xffefffff, 0xfff7ffff,
197 0xfffbffff, 0xfffdffff, 0xfffeffff, 0xffff7fff,
198 0xffffbfff, 0xffffdfff, 0xffffefff, 0xfffff7ff,
199 0xfffffbff, 0xfffffdff, 0xfffffeff, 0xffffff7f,
200 0xffffffbf, 0xffffffdf, 0xffffffef, 0xfffffff7,
201 0xfffffffb, 0xfffffffd, 0xfffffffe, 0xffffffff
202 };
203
204 static struct pat walking_0 = {
205 "walking_0",
206 walking_0_data,
207 ARRAY_SIZE(walking_0_data) - 1, /* mask */
208 {1, 1, 2, 1} /* weight */
209 };
210
211 static u32 one_zero_data[] = {0x00000000, 0xffffffff};
212
213 static struct pat one_zero = {
214 "one_zero",
215 one_zero_data,
216 ARRAY_SIZE(one_zero_data) - 1, /* mask */
217 {5, 5, 15, 5} /* weight */
218 };
219
220 static unsigned int one_zero_x16_data[] = {0x0000ffff, 0x0000ffff};
221
222 static struct pat one_zero_x16 = {
223 "one_zero_x16",
224 one_zero_x16_data,
225 ARRAY_SIZE(one_zero_x16_data) - 1, /* mask */
226 {5, 0, 0, 0} /* weight */
227 };
228
229 static u32 just_0_data[] = {0x00000000, 0x00000000};
230
231 static struct pat just_0 = {
232 "just_0",
233 just_0_data,
234 ARRAY_SIZE(just_0_data) - 1, /* mask */
235 {2, 0, 0, 0} /* weight */
236 };
237
238 static u32 just_1_data[] = {0xffffffff, 0xffffffff};
239
240 static struct pat just_1 = {
241 "just_1",
242 just_1_data,
243 ARRAY_SIZE(just_1_data) - 1, /* mask */
244 {2, 0, 0, 0} /* weight */
245 };
246
247 static u32 just_5_data[] = {0x55555555, 0x55555555};
248
249 static struct pat just_5 = {
250 "just_5",
251 just_5_data,
252 ARRAY_SIZE(just_5_data) - 1, /* mask */
253 {2, 0, 0, 0} /* weight */
254 };
255
256 static u32 just_a_data[] = {0xaaaaaaaa, 0xaaaaaaaa};
257
258 static struct pat just_a = {
259 "just_a",
260 just_a_data,
261 ARRAY_SIZE(just_a_data) - 1, /* mask */
262 {2, 0, 0, 0} /* weight */
263 };
264
265 static u32 five_a_data[] = {0x55555555, 0xaaaaaaaa};
266
267 static struct pat five_a = {
268 "five_a",
269 five_a_data,
270 ARRAY_SIZE(five_a_data) - 1, /* mask */
271 {1, 1, 1, 1} /* weight */
272 };
273
274 static unsigned int five_a_x16_data[] = {0x5555aaaa, 0x5555aaaa};
275
276 static struct pat five_a_x16 = {
277 "five_a_x16",
278 five_a_x16_data,
279 ARRAY_SIZE(five_a_x16_data) - 1, /* mask */
280 {1, 0, 0, 0} /* weight */
281 };
282
283 static u32 five_a8_data[] = {
284 0x5aa5a55a, 0xa55a5aa5, 0xa55a5aa5, 0x5aa5a55a
285 };
286
287 static struct pat five_a8 = {
288 "five_a8",
289 five_a8_data,
290 ARRAY_SIZE(five_a8_data) - 1, /* mask */
291 {1, 1, 1, 1} /* weight */
292 };
293
294 static u32 five_a8_x16_data[] = {0x5aa5a55a, 0xa55a5aa5};
295
296 static struct pat five_a8_x16 = {
297 "five_a8_x16",
298 five_a8_x16_data,
299 ARRAY_SIZE(five_a8_x16_data) - 1, /* mask */
300 {1, 0, 0, 0} /* weight */
301 };
302
303 static unsigned int five_a8_x16_repeat_data[] = {
304 0x5aa55aa5, 0xa55aa55a, 0xa55aa55a, 0x5aa55aa5
305 };
306
307 static struct pat five_a8_x16_repeat = {
308 "five_a8_x16_repeat",
309 five_a8_x16_repeat_data,
310 ARRAY_SIZE(five_a8_x16_repeat_data) - 1, /* mask */
311 {1, 1, 1, 0} /* weight */
312 };
313
314 static u32 long_8b10b_data[] = {0x16161616, 0x16161616};
315
316 static struct pat long_8b10b = {
317 "long_8b10b",
318 long_8b10b_data,
319 ARRAY_SIZE(long_8b10b_data) - 1, /* mask */
320 {2, 0, 0, 0} /* weight */
321 };
322
323 static u32 short_8b10b_data[] = {0xb5b5b5b5, 0xb5b5b5b5};
324
325 static struct pat short_8b10b = {
326 "short_8b10b",
327 short_8b10b_data,
328 ARRAY_SIZE(short_8b10b_data) - 1, /* mask */
329 {2, 0, 0, 0} /* weight */
330 };
331
332 static u32 checker_8b10b_data[] = {0xb5b5b5b5, 0x4a4a4a4a};
333
334 static struct pat checker_8b10b = {
335 "checker_8b10b",
336 checker_8b10b_data,
337 ARRAY_SIZE(checker_8b10b_data) - 1, /* mask */
338 {1, 0, 1, 1} /* weight */
339 };
340
341 static u32 checker_8b10b_x16_data[] = {0xb5b54a4a, 0xb5b54a4a};
342
343 static struct pat checker_8b10b_x16 = {
344 "checker_8b10b_x16",
345 checker_8b10b_x16_data,
346 ARRAY_SIZE(checker_8b10b_x16_data) - 1, /* mask */
347 {1, 0, 0, 0} /* weight */
348 };
349
350 static u32 five_7_data[] = {0x55555557, 0x55575555};
351
352 static struct pat five_7 = {
353 "five_7",
354 five_7_data,
355 ARRAY_SIZE(five_7_data) - 1, /* mask */
356 {0, 2, 0, 0} /* weight */
357 };
358
359 static u32 five_7_x16_data[] = {0x55575557, 0x57555755};
360
361 static struct pat five_7_x16 = {
362 "five_7_x16",
363 five_7_x16_data,
364 ARRAY_SIZE(five_7_x16_data) - 1, /* mask */
365 {2, 0, 0, 0} /* weight */
366 };
367
368 static u32 zero2_fd_data[] = {0x00020002, 0xfffdfffd};
369
370 static struct pat zero2_fd = {
371 "zero2_fd",
372 zero2_fd_data,
373 ARRAY_SIZE(zero2_fd_data) - 1, /* mask */
374 {0, 2, 0, 0} /* weight */
375 };
376
377 static u32 zero2_fd_x16_data[] = {0x02020202, 0xfdfdfdfd};
378
379 static struct pat zero2_fd_x16 = {
380 "zero2_fd_x16",
381 zero2_fd_x16_data,
382 ARRAY_SIZE(zero2_fd_x16_data) - 1, /* mask */
383 {2, 0, 0, 0} /* weight */
384 };
385
386 static struct pat *pat_array[] = {
387 &walking_1,
388 &walking_1_x16,
389 &walking_1_x16_repeat,
390 &walking_inv_1,
391 &walking_inv_1_x16,
392 &walking_inv_1_x16_repeat,
393 &walking_0,
394 &one_zero,
395 &one_zero_x16,
396 &just_0,
397 &just_1,
398 &just_5,
399 &just_a,
400 &five_a,
401 &five_a_x16,
402 &five_a8,
403 &five_a8_x16,
404 &five_a8_x16_repeat,
405 &long_8b10b,
406 &short_8b10b,
407 &checker_8b10b,
408 &checker_8b10b_x16,
409 &five_7,
410 &five_7_x16,
411 &zero2_fd,
412 &zero2_fd_x16
413 };
414
415 static u32 cpu_copy_err[CPU_NUM_MAX];
416 static u32 cpu_inv_err[CPU_NUM_MAX];
417
418 static u64 start_time_us;
419 static u64 test_time_us;
420
421 static bool cpu_init_finish[CPU_NUM_MAX];
422 static bool cpu_test_finish[CPU_NUM_MAX];
423 static bool pattern_page_init_finish;
424
425 #if (CPU_NUM_MAX > 1)
426 static ulong test_count = 0;
427 static ulong __gd; /* set r9/x18 of secondary cpu to gd addr */
428 #endif
429 ulong __sp; /* set sp of secondary cpu */
430
431 u32 print_mutex; /* 0: unlock, 1: lock */
432
get_time_us(void)433 static u64 get_time_us(void)
434 {
435 return lldiv(get_ticks(), CONFIG_SYS_HZ_CLOCK / (CONFIG_SYS_HZ * 1000));
436 }
437
run_time_us(void)438 static u64 run_time_us(void)
439 {
440 return get_time_us() - start_time_us;
441 }
442
print_time_stamp(void)443 static void print_time_stamp(void)
444 {
445 u64 time_us;
446
447 time_us = run_time_us();
448
449 printf("[%5d.%06d] ", (u32)(time_us / 1000000), (u32)(time_us % 1000000));
450 }
451
pattern_get(struct pattern * pattern,u32 offset)452 static u32 pattern_get(struct pattern *pattern, u32 offset)
453 {
454 u32 ret;
455
456 ret = pattern->pat->data_array[(offset >> pattern->repeat) &
457 pattern->pat->mask];
458
459 return pattern->inv ? ~ret : ret;
460 }
461
pattern_adler_sum_calc(struct pattern * pattern,struct stressapptest_params * sat)462 static void pattern_adler_sum_calc(struct pattern *pattern,
463 struct stressapptest_params *sat)
464 {
465 int i = 0;
466 u64 a1 = 1;
467 u64 b1 = 0;
468 u64 a2 = 1;
469 u64 b2 = 0;
470
471 while (i < sat->block_size_byte / sizeof(u32)) {
472 a1 += (u64)pattern_get(pattern, i++);
473 b1 += a1;
474 a1 += pattern_get(pattern, i++);
475 b1 += a1;
476
477 a2 += (u64)pattern_get(pattern, i++);
478 b2 += a2;
479 a2 += pattern_get(pattern, i++);
480 b2 += a2;
481 }
482
483 pattern->adler_sum.a1 = a1;
484 pattern->adler_sum.b1 = b1;
485 pattern->adler_sum.a2 = a2;
486 pattern->adler_sum.b2 = b2;
487 }
488
pattern_list_init(struct pattern * pattern_list,struct stressapptest_params * sat)489 static void pattern_list_init(struct pattern *pattern_list,
490 struct stressapptest_params *sat)
491 {
492 u32 weight_count = 0;
493 int k = 0;
494
495 for (int i = 0; i < PAT_NUM; i++) {
496 for (int j = 0; j < 8; j++) {
497 pattern_list[k].pat = pat_array[i];
498 pattern_list[k].inv = j % 2;
499 pattern_list[k].repeat = j / 2;
500 pattern_list[k].weight = pattern_list[k].pat->weight[j / 2];
501 pattern_adler_sum_calc(&pattern_list[k], sat);
502 weight_count += pattern_list[k].weight;
503 k++;
504 }
505 }
506
507 sat->weight_count = weight_count;
508 }
509
get_max_page_num(ulong page_size_byte)510 static u32 get_max_page_num(ulong page_size_byte)
511 {
512 ulong start_adr[CONFIG_NR_DRAM_BANKS], length[CONFIG_NR_DRAM_BANKS];
513 u32 page_num = 0;
514
515 get_print_available_addr(start_adr, length, 0);
516
517 page_num = 0;
518 for (int i = 0; i < ARRAY_SIZE(start_adr) || i < ARRAY_SIZE(length); i++) {
519 if ((start_adr[i] == 0 && length[i] == 0))
520 break;
521 page_num += (u32)(length[i] / page_size_byte);
522 }
523
524 return page_num;
525 }
526
get_page_addr(struct page * page_list,struct stressapptest_params * sat)527 static int get_page_addr(struct page *page_list,
528 struct stressapptest_params *sat)
529 {
530 ulong start_adr[CONFIG_NR_DRAM_BANKS], length[CONFIG_NR_DRAM_BANKS];
531 ulong used_length;
532 u32 page = 0;
533
534 get_print_available_addr(start_adr, length, 0);
535
536 printf("Address for test:\n Start End Length\n");
537 for (int i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
538 if ((start_adr[i] == 0 && length[i] == 0) || page >= sat->page_num)
539 break;
540 if (start_adr[i] + length[i] < sat->total_start_addr)
541 continue;
542 if (start_adr[i] < sat->total_start_addr) {
543 length[i] -= sat->total_start_addr - start_adr[i];
544 start_adr[i] = sat->total_start_addr;
545 }
546
547 used_length = 0;
548 while (page < sat->page_num &&
549 length[i] >= used_length + sat->page_size_byte) {
550 page_list[page].base_addr = (void *)(start_adr[i] + used_length);
551 used_length += sat->page_size_byte;
552 page++;
553 }
554 printf(" 0x%09lx - 0x%09lx 0x%09lx\n",
555 start_adr[i], start_adr[i] + used_length, used_length);
556 }
557
558 printf("page_num = %d, page_size = 0x%lx, total_test_size = 0x%lx\n",
559 page, sat->page_size_byte, sat->page_size_byte * page);
560
561 if (sat->total_test_size_mb == 0) {
562 /* No arg for total_test_size_mb, test all available space by default. */
563 sat->page_num = page;
564 } else if (page < sat->page_num || page < sat->cpu_num * 4) {
565 printf("ERROR: Cannot get enough pages to test.\n");
566 printf("Please decrease page_size or test_size\n");
567
568 return -1;
569 }
570
571 return 0;
572 }
573
page_init_valid(struct page * page,struct pattern * pattern_list,struct stressapptest_params * sat)574 static void page_init_valid(struct page *page, struct pattern *pattern_list,
575 struct stressapptest_params *sat)
576 {
577 int target;
578 int i = 0;
579 u64 *mem;
580
581 target = (rand() % sat->weight_count) + 1;
582 do {
583 target -= pattern_list[i++].weight;
584 if (target <= 0)
585 break;
586 } while (i < PATTERN_LIST_SIZE);
587 page->pattern = &pattern_list[--i];
588 page->valid = 1;
589
590 mem = (u64 *)page->base_addr;
591 for (i = 0; i < sat->page_size_byte / sizeof(u64); i++)
592 mem[i] = (u64)pattern_get(page->pattern, i * 2) |
593 (u64)pattern_get(page->pattern, i * 2 + 1) << 32;
594 }
595
page_init_empty(struct page * page)596 static void page_init_empty(struct page *page)
597 {
598 page->valid = 0;
599 }
600
page_init(struct pattern * pattern_list,struct stressapptest_params * sat)601 static void page_init(struct pattern *pattern_list,
602 struct stressapptest_params *sat)
603 {
604 int i, cpu;
605 u32 empty_page_num;
606
607 for (cpu = 0; cpu < sat->cpu_num; cpu++) {
608 empty_page_num = 0;
609 for (i = cpu; i < sat->page_num; i += sat->cpu_num) {
610 if (rand() % 5 < 3) {
611 page_list[i].valid = 1;
612 } else {
613 page_list[i].valid = 0;
614 empty_page_num++;
615 }
616 }
617 while (empty_page_num >= sat->page_num / sat->cpu_num / 2 && i > 0) {
618 i -= sat->cpu_num;
619 if (page_list[i].valid == 0) {
620 page_list[i].valid = 1;
621 empty_page_num--;
622 }
623 }
624 i = cpu;
625 while (empty_page_num < 2 && i < sat->page_num) {
626 if (page_list[i].valid == 1) {
627 page_list[i].valid = 0;
628 empty_page_num++;
629 }
630 i += sat->cpu_num;
631 }
632 }
633
634 for (i = 0; i < sat->page_num; i++) {
635 if (page_list[i].valid == 1)
636 page_init_valid(&page_list[i], pattern_list, sat);
637 else
638 page_init_empty(&page_list[i]);
639 }
640 flush_dcache_all();
641 }
642
page_rand_pick(struct page * page_list,bool valid,struct stressapptest_params * sat,u8 cpu_id)643 static u32 page_rand_pick(struct page *page_list, bool valid,
644 struct stressapptest_params *sat, u8 cpu_id)
645 {
646 u32 pick;
647
648 pick = rand() % sat->page_num;
649 pick = pick / sat->cpu_num * sat->cpu_num + cpu_id;
650 if (pick >= sat->page_num)
651 pick = cpu_id;
652
653 while (page_list[pick].valid != valid) {
654 pick += sat->cpu_num;
655 if (pick >= sat->page_num)
656 pick = cpu_id;
657 }
658
659 return pick;
660 }
661
block_mis_search(void * dst_addr,struct pattern * src_pattern,char * item,struct stressapptest_params * sat,u8 cpu_id)662 static u32 block_mis_search(void *dst_addr, struct pattern *src_pattern, char *item,
663 struct stressapptest_params *sat, u8 cpu_id)
664 {
665 u32 *dst_mem;
666 u32 read, reread, expected;
667 u32 err = 0;
668 u32 *print_addr;
669 int i, j;
670
671 dst_mem = (u32 *)dst_addr;
672
673 for (i = 0; i < sat->block_size_byte / sizeof(u32); i++) {
674 read = dst_mem[i];
675 expected = pattern_get(src_pattern, i);
676
677 if (read != expected) {
678 flush_dcache_range((ulong)&dst_mem[i], (ulong)&dst_mem[i + 1]);
679 reread = dst_mem[i];
680
681 lock_byte_mutex(&print_mutex);
682
683 print_time_stamp();
684 printf("%s Hardware Error: miscompare on CPU %d at 0x%lx:\n",
685 item, cpu_id, (ulong)&dst_mem[i]);
686 printf(" read: 0x%08x\n", read);
687 printf(" reread: 0x%08x(reread^read:0x%08x)\n",
688 reread, reread ^ read);
689 printf(" expected:0x%08x(expected^read:0x%08x)\n",
690 expected, expected ^ read);
691 printf(" \'%s%s%d\'", src_pattern->pat->name,
692 src_pattern->inv ? "~" : "",
693 32 << src_pattern->repeat);
694 if (reread == expected)
695 printf(" read error");
696 printf("\n");
697
698 /* Dump data around the error address */
699 print_addr = &dst_mem[i] - 64;
700 for (j = 0; j < 128; j += 8)
701 printf(" [0x%010lx] 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
702 (ulong)(print_addr + j),
703 *(print_addr + j), *(print_addr + j + 1),
704 *(print_addr + j + 2), *(print_addr + j + 3),
705 *(print_addr + j + 4), *(print_addr + j + 5),
706 *(print_addr + j + 6), *(print_addr + j + 7));
707
708 unlock_byte_mutex(&print_mutex);
709
710 /* fix the error */
711 dst_mem[i] = expected;
712 err++;
713 }
714 }
715 flush_dcache_all();
716
717 if (err == 0) {
718 lock_byte_mutex(&print_mutex);
719 printf("%s ERROR detected but cannot find mismatch data (maybe read error).\n", item);
720 unlock_byte_mutex(&print_mutex);
721 }
722
723 return err;
724 }
725
block_inv_check(void * dst_addr,struct pattern * src_pattern,struct stressapptest_params * sat,u8 cpu_id)726 static u32 block_inv_check(void *dst_addr, struct pattern *src_pattern,
727 struct stressapptest_params *sat, u8 cpu_id)
728 {
729 u32 *dst_mem;
730 u32 err = 0;
731 int i = 0;
732 #if defined(WARM_CPU)
733 double a, b, c, d;
734 #endif
735
736 struct adler_sum adler_sum = {
737 1, 0, 1, 0
738 };
739
740 dst_mem = (u32 *)dst_addr;
741
742 #if defined(WARM_CPU)
743 a = 2.0 * dst_mem[0];
744 b = 5.0 * dst_mem[0];
745 c = 7.0 * dst_mem[0];
746 d = 9.0 * dst_mem[0];
747 #endif
748
749 while (i < sat->block_size_byte / sizeof(u32)) {
750 adler_sum.a1 += dst_mem[i++];
751 adler_sum.b1 += adler_sum.a1;
752 adler_sum.a1 += dst_mem[i++];
753 adler_sum.b1 += adler_sum.a1;
754
755 #if defined(WARM_CPU)
756 a = a * b;
757 b = b + c;
758 #endif
759
760 adler_sum.a2 += dst_mem[i++];
761 adler_sum.b2 += adler_sum.a2;
762 adler_sum.a2 += dst_mem[i++];
763 adler_sum.b2 += adler_sum.a2;
764 #if defined(WARM_CPU)
765 c = c * d;
766 d = d + d;
767 #endif
768 }
769
770 #if defined(WARM_CPU)
771 d = a + b + c + d;
772 if (d == 1.0)
773 /* Reference the result so that it can't be discarded by the compiler. */
774 printf("This will probably never happen.\n");
775 #endif
776
777 if (adler_sum.a1 != src_pattern->adler_sum.a1 ||
778 adler_sum.b1 != src_pattern->adler_sum.b1 ||
779 adler_sum.a2 != src_pattern->adler_sum.a2 ||
780 adler_sum.b2 != src_pattern->adler_sum.b2)
781 err = block_mis_search(dst_addr, src_pattern, "Inv", sat, cpu_id);
782
783 return err;
784 }
785
page_inv_up(void * src_addr,struct stressapptest_params * sat)786 static void page_inv_up(void *src_addr, struct stressapptest_params *sat)
787 {
788 void *dst_addr = src_addr;
789 uint data;
790 uint *dst_mem;
791
792 for (int i = 0; i < sat->block_num; i++) {
793 dst_mem = (uint *)dst_addr;
794 for (int j = 0; j < sat->block_size_byte / sizeof(uint); j++) {
795 data = dst_mem[j];
796 dst_mem[j] = ~data;
797 }
798 dst_addr += sat->block_size_byte;
799 flush_dcache_all();
800 }
801 }
802
page_inv_down(void * src_addr,struct stressapptest_params * sat)803 static void page_inv_down(void *src_addr, struct stressapptest_params *sat)
804 {
805 void *dst_addr = src_addr;
806 uint data;
807 uint *dst_mem;
808
809 dst_addr += sat->block_size_byte * (sat->block_num - 1);
810
811 for (int i = sat->block_num - 1; i >= 0; i--) {
812 dst_mem = (uint *)dst_addr;
813 for (int j = sat->block_size_byte / sizeof(uint) - 1; j >= 0; j--) {
814 data = dst_mem[j];
815 dst_mem[j] = ~data;
816 }
817 dst_addr -= sat->block_size_byte;
818 flush_dcache_all();
819 }
820 }
821
page_inv(struct stressapptest_params * sat,u8 cpu_id)822 static u32 page_inv(struct stressapptest_params *sat, u8 cpu_id)
823 {
824 u32 src;
825 void *dst_block_addr;
826 u32 err = 0;
827
828 src = page_rand_pick(page_list, 1, sat, cpu_id); /* pick a valid page */
829 dst_block_addr = page_list[src].base_addr;
830
831 for (int i = 0; i < 4; i++) {
832 if (rand() % 2 == 0)
833 page_inv_up(page_list[src].base_addr, sat);
834 else
835 page_inv_down(page_list[src].base_addr, sat);
836 }
837
838 for (int i = 0; i < sat->block_num; i++) {
839 err += block_inv_check(dst_block_addr, page_list[src].pattern, sat, cpu_id);
840 dst_block_addr += sat->block_size_byte;
841 }
842
843 flush_dcache_all();
844
845 return err;
846 }
847
block_copy_check(void * dst_addr,struct adler_sum * adler_sum,struct pattern * src_pattern,struct stressapptest_params * sat,u8 cpu_id)848 static u32 block_copy_check(void *dst_addr, struct adler_sum *adler_sum,
849 struct pattern *src_pattern, struct stressapptest_params *sat,
850 u8 cpu_id)
851 {
852 u32 err = 0;
853
854 if (adler_sum->a1 != src_pattern->adler_sum.a1 ||
855 adler_sum->b1 != src_pattern->adler_sum.b1 ||
856 adler_sum->a2 != src_pattern->adler_sum.a2 ||
857 adler_sum->b2 != src_pattern->adler_sum.b2)
858 err = block_mis_search(dst_addr, src_pattern, "Copy", sat, cpu_id);
859
860 return err;
861 }
862
block_copy(void * dst_addr,void * src_addr,struct pattern * src_pattern,struct stressapptest_params * sat,u8 cpu_id)863 static u32 block_copy(void *dst_addr, void *src_addr,
864 struct pattern *src_pattern,
865 struct stressapptest_params *sat, u8 cpu_id)
866 {
867 u64 *dst_mem;
868 u64 *src_mem;
869 u64 data;
870 int i = 0;
871 #if defined(WARM_CPU)
872 double a, b, c, d;
873 #endif
874
875 struct adler_sum adler_sum = {
876 1, 0, 1, 0
877 };
878
879 dst_mem = (u64 *)dst_addr;
880 src_mem = (u64 *)src_addr;
881
882 #if defined(WARM_CPU)
883 a = 2.0 * src_mem[0];
884 b = 5.0 * src_mem[0];
885 c = 7.0 * src_mem[0];
886 d = 9.0 * src_mem[0];
887 #endif
888
889 while (i < sat->block_size_byte / sizeof(u64)) {
890 data = src_mem[i];
891 adler_sum.a1 += data & 0xffffffff;
892 adler_sum.b1 += adler_sum.a1;
893 adler_sum.a1 += data >> 32;
894 adler_sum.b1 += adler_sum.a1;
895 dst_mem[i] = data;
896 i++;
897
898 #if defined(WARM_CPU)
899 a = a * b;
900 b = b + c;
901 #endif
902
903 data = src_mem[i];
904 adler_sum.a2 += data & 0xffffffff;
905 adler_sum.b2 += adler_sum.a2;
906 adler_sum.a2 += data >> 32;
907 adler_sum.b2 += adler_sum.a2;
908 dst_mem[i] = data;
909 i++;
910
911 #if defined(WARM_CPU)
912 c = c * d;
913 d = d + d;
914 #endif
915 }
916
917 flush_dcache_all();
918
919 #if defined(WARM_CPU)
920 d = a + b + c + d;
921 if (d == 1.0)
922 /* Reference the result so that it can't be discarded by the compiler. */
923 printf("This will probably never happen.\n");
924 #endif
925
926 return block_copy_check(dst_addr, &adler_sum, src_pattern, sat, cpu_id);
927 }
928
page_copy(struct stressapptest_params * sat,u8 cpu_id)929 static u32 page_copy(struct stressapptest_params *sat, u8 cpu_id)
930 {
931 u32 dst;
932 u32 src;
933 void *dst_block_addr;
934 void *src_block_addr;
935 u32 err = 0;
936
937 dst = page_rand_pick(page_list, 0, sat, cpu_id); /* pick a empty page */
938 dst_block_addr = page_list[dst].base_addr;
939 src = page_rand_pick(page_list, 1, sat, cpu_id); /* pick a valid page */
940 src_block_addr = page_list[src].base_addr;
941 flush_dcache_all();
942
943 for (int i = 0; i < sat->block_num; i++) {
944 err += block_copy(dst_block_addr, src_block_addr,
945 page_list[src].pattern, sat, cpu_id);
946 dst_block_addr += sat->block_size_byte;
947 src_block_addr += sat->block_size_byte;
948 }
949
950 page_list[dst].pattern = page_list[src].pattern;
951 page_list[dst].valid = 1;
952 page_list[src].valid = 0;
953 flush_dcache_all();
954
955 return err;
956 }
957
secondary_main(void)958 void secondary_main(void)
959 {
960 #if (CPU_NUM_MAX > 1)
961 u8 cpu_id;
962 ulong test = 0;
963
964 #ifndef CONFIG_ARM64
965 asm volatile("mov r9, %0" : : "r" (__gd)); /* set r9 to gd addr */
966 #else
967 asm volatile("mov x18, %0" : : "r" (__gd)); /* set x18 to gd addr */
968 #endif
969 dcache_enable();
970 icache_enable();
971
972 udelay(100);
973
974 flush_dcache_all();
975
976 cpu_id = sat.cpu_num;
977 cpu_init_finish[cpu_id] = 1;
978 printf("CPU%d start OK.\n", cpu_id);
979
980 while (pattern_page_init_finish == 0) {
981 udelay(100);
982 flush_dcache_all();
983 }
984
985 while (1) {
986 udelay(100);
987 flush_dcache_all();
988 while (test < test_count) {
989 cpu_test_finish[cpu_id] = 0;
990 flush_dcache_all();
991 while (run_time_us() < test_time_us) {
992 if (rand() % 2 == 0)
993 cpu_copy_err[cpu_id] += page_copy(&sat, cpu_id);
994 else
995 cpu_inv_err[cpu_id] += page_inv(&sat, cpu_id);
996 }
997 test++;
998 cpu_test_finish[cpu_id] = 1;
999 flush_dcache_all();
1000 }
1001 }
1002 #else
1003 return;
1004 #endif
1005 }
1006
doing_stressapptest(void)1007 static int doing_stressapptest(void)
1008 {
1009 int i;
1010 u32 pre_10s;
1011 u32 now_10s;
1012
1013 struct pattern pattern_list[PATTERN_LIST_SIZE];
1014 void *page_info;
1015
1016 u32 all_copy_err = 0;
1017 u32 all_inv_err = 0;
1018 u32 cpu_no_response_err = 0;
1019
1020 int ret = CMD_RET_SUCCESS;
1021
1022 for (i = 0; i < CPU_NUM_MAX; i++) {
1023 cpu_copy_err[i] = 0;
1024 cpu_inv_err[i] = 0;
1025 cpu_init_finish[i] = 0;
1026 cpu_test_finish[i] = 0;
1027 }
1028 pattern_page_init_finish = 0;
1029 print_mutex = 0;
1030 asm volatile("clrex");
1031
1032 #if (CPU_NUM_MAX > 1)
1033 if (test_count == 0) {
1034 __gd = (ulong)gd;
1035 asm volatile("mov %0, sp" : "=r" (__sp));
1036 printf("CPU0 sp is at 0x%lx now.\n", __sp);
1037 __sp &= ~(ulong)0xffff;
1038 for (sat.cpu_num = 1; sat.cpu_num < CPU_NUM_MAX; sat.cpu_num++) {
1039 __sp -= 0x10000;
1040 flush_dcache_all();
1041 if (psci_cpu_on(sat.cpu_num, (ulong)secondary_init) == 0) {
1042 mdelay(10);
1043 printf("Calling CPU%d, sp = 0x%lx\n", sat.cpu_num, __sp);
1044 } else {
1045 break;
1046 }
1047 while (cpu_init_finish[sat.cpu_num] == 0) {
1048 udelay(1000);
1049 flush_dcache_all();
1050 }
1051 }
1052 }
1053 #else
1054 sat.cpu_num = 1;
1055 #endif
1056
1057 if (sat.total_test_size_mb == 0)
1058 sat.page_num = get_max_page_num(sat.page_size_byte);
1059 else
1060 sat.page_num = (sat.total_test_size_mb << 20) / sat.page_size_byte;
1061 sat.block_num = sat.page_size_byte / sat.block_size_byte;
1062
1063 udelay(100);
1064
1065 page_info = malloc(sizeof(struct page) * sat.page_num);
1066 if (page_info == 0) {
1067 printf("ERROR: StressAppTest fail to malloc.\n");
1068 printf("Please try increasing CONFIG_SYS_MALLOC_LEN in include/configs/rxxxxx_common.h.\n");
1069 ret = CMD_RET_FAILURE;
1070 goto out;
1071 }
1072 page_list = (struct page *)page_info;
1073
1074 if (get_page_addr(page_list, &sat) < 0) {
1075 ret = CMD_RET_FAILURE;
1076 goto out;
1077 }
1078
1079 pattern_list_init(pattern_list, &sat);
1080 page_init(pattern_list, &sat);
1081
1082 #if (CPU_NUM_MAX > 1)
1083 if (sat.cpu_num > 1) {
1084 pattern_page_init_finish = 1;
1085 test_count++;
1086 flush_dcache_all();
1087 }
1088 #endif
1089
1090 pre_10s = (u32)(run_time_us() / 1000000 / 10);
1091 lock_byte_mutex(&print_mutex);
1092 print_time_stamp();
1093 printf("Start StressAppTest in U-Boot:\n");
1094 unlock_byte_mutex(&print_mutex);
1095
1096 while (run_time_us() < test_time_us) {
1097 if (rand() % 2 == 0)
1098 cpu_copy_err[0] += page_copy(&sat, 0);
1099 else
1100 cpu_inv_err[0] += page_inv(&sat, 0);
1101
1102 /* Print every 10 seconds */
1103 now_10s = (u32)(run_time_us() / 1000000 / 10);
1104 if (now_10s > pre_10s) {
1105 pre_10s = now_10s;
1106 lock_byte_mutex(&print_mutex);
1107 print_time_stamp();
1108 printf("Seconds remaining: %d\n", (u32)(test_time_us / 1000000 - now_10s * 10));
1109 unlock_byte_mutex(&print_mutex);
1110 }
1111 }
1112
1113 #if (CPU_NUM_MAX > 1)
1114 for (i = 1; i < sat.cpu_num; i++) {
1115 while (cpu_test_finish[i] == 0) {
1116 if ((u32)(run_time_us() / 1000000 / 10) > pre_10s + 6) {
1117 /* wait for secondary CPU in 60s */
1118 lock_byte_mutex(&print_mutex);
1119 print_time_stamp();
1120 printf("ERROR: Cannot wait for CPU%d to finish!\n", i);
1121 unlock_byte_mutex(&print_mutex);
1122 cpu_no_response_err++;
1123 break;
1124 }
1125 mdelay(1);
1126 flush_dcache_all();
1127 }
1128 }
1129 #endif
1130
1131 for (i = 0; i < sat.cpu_num; i++) {
1132 all_copy_err += cpu_copy_err[i];
1133 all_inv_err += cpu_inv_err[i];
1134 }
1135 print_time_stamp();
1136 printf("StressAppTest Result: ");
1137 if (all_copy_err == 0 && all_inv_err == 0 && cpu_no_response_err == 0)
1138 printf("Pass.\n");
1139 else
1140 printf("FAIL!\nStressAppTest detects %d copy errors, %d inv errors.\n",
1141 all_copy_err, all_inv_err);
1142
1143 out:
1144 free(page_info);
1145
1146 return ret;
1147 }
1148
do_stressapptest(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])1149 static int do_stressapptest(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
1150 {
1151 ulong test_time_sec = 20;
1152 ulong page_size_kb = 1024;
1153
1154 sat.total_test_size_mb = 0;
1155 sat.block_size_byte = 4096;
1156 sat.total_start_addr = 0x0;
1157
1158 printf("StressAppTest in U-Boot, " __version__ "\n");
1159
1160 if (argc > 1) {
1161 if (strict_strtoul(argv[1], 0, &test_time_sec) < 0)
1162 return CMD_RET_USAGE;
1163 if (test_time_sec < 1)
1164 test_time_sec = 20;
1165 }
1166 if (argc > 2) {
1167 if (strict_strtoul(argv[2], 0, &sat.total_test_size_mb) < 0)
1168 return CMD_RET_USAGE;
1169 if (sat.total_test_size_mb < 1)
1170 sat.total_test_size_mb = 0;
1171 }
1172 if (argc > 3) {
1173 if (strict_strtoul(argv[3], 0, &sat.total_start_addr) < 0)
1174 return CMD_RET_USAGE;
1175 if (sat.total_start_addr < 0x1)
1176 sat.total_start_addr = 0x0;
1177 }
1178 if (argc > 4) {
1179 if (strict_strtoul(argv[4], 0, &page_size_kb) < 0)
1180 return CMD_RET_USAGE;
1181 if (page_size_kb < 1)
1182 page_size_kb = 1024;
1183 }
1184
1185 sat.page_size_byte = page_size_kb << 10;
1186
1187 start_time_us = get_time_us();
1188 test_time_us = (u64)test_time_sec * 1000000;
1189
1190 /* Change rand seed. If not do this, rand() would be same after boot.*/
1191 srand((unsigned int)(start_time_us & 0xffffffff));
1192
1193 return doing_stressapptest();
1194 }
1195
1196 U_BOOT_CMD(stressapptest, 5, 1, do_stressapptest,
1197 "StressAppTest for Rockchip\n",
1198 "\narg1: test time in second, default value is 20s.\n"
1199 "arg2: test size in MB, default value is all available space.\n"
1200 "arg3: start addr for test.\n"
1201 "arg4: test page size in kB, default value is 1024kB(1MB).\n"
1202 "example:\n"
1203 " stressapptest: test for 20s, test size is all available space, each page size is 1MB.\n"
1204 " stressapptest 43200 64: test for 12h, test size is 64MB, each page size is 1MB (64 pages).\n"
1205 " stressapptest 86400 1024 0x80000000: test for 24h, test size is 1024MB, start addr for test is 0x80000000, each page size is 1MB (1024 pages).\n"
1206 " stressapptest 43200 16 0x40000000 512: test for 12h, test size is 16MB, start addr for test is 0x40000000, each page size is 512kB (32 pages).\n"
1207 );
1208