xref: /OK3568_Linux_fs/u-boot/cmd/ddr_tool/stressapptest/stressapptest.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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