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 433 static u64 get_time_us(void) 434 { 435 return lldiv(get_ticks(), CONFIG_SYS_HZ_CLOCK / (CONFIG_SYS_HZ * 1000)); 436 } 437 438 static u64 run_time_us(void) 439 { 440 return get_time_us() - start_time_us; 441 } 442 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 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 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 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 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 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 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 596 static void page_init_empty(struct page *page) 597 { 598 page->valid = 0; 599 } 600 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 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 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 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 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 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 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 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 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 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 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 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 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