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.3.0 20230713" 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 flush_dcache_range((ulong)&dst_mem[i], (ulong)&dst_mem[i + 1]); 714 } 715 } 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 += 32) { 795 for (int k = j; k < j + 32; k++) { 796 data = dst_mem[k]; 797 dst_mem[k] = ~data; 798 } 799 flush_dcache_range((ulong)&dst_mem[j], (ulong)&dst_mem[j + 1]); 800 } 801 dst_addr += sat->block_size_byte; 802 } 803 } 804 805 static void page_inv_down(void *src_addr, struct stressapptest_params *sat) 806 { 807 void *dst_addr = src_addr; 808 uint data; 809 uint *dst_mem; 810 811 dst_addr += sat->block_size_byte * (sat->block_num - 1); 812 813 for (int i = sat->block_num - 1; i >= 0; i--) { 814 dst_mem = (uint *)dst_addr; 815 for (int j = sat->block_size_byte / sizeof(uint) - 32; j >= 0; j -= 32) { 816 for (int k = j + 31; k >= j; k--) { 817 data = dst_mem[k]; 818 dst_mem[k] = ~data; 819 } 820 flush_dcache_range((ulong)&dst_mem[j], (ulong)&dst_mem[j + 1]); 821 } 822 dst_addr -= sat->block_size_byte; 823 } 824 } 825 826 static u32 page_inv(struct stressapptest_params *sat, u8 cpu_id) 827 { 828 u32 src; 829 void *dst_block_addr; 830 u32 err = 0; 831 832 src = page_rand_pick(page_list, 1, sat, cpu_id); /* pick a valid page */ 833 dst_block_addr = page_list[src].base_addr; 834 835 for (int i = 0; i < 4; i++) { 836 if (rand() % 2 == 0) 837 page_inv_up(page_list[src].base_addr, sat); 838 else 839 page_inv_down(page_list[src].base_addr, sat); 840 } 841 842 for (int i = 0; i < sat->block_num; i++) { 843 err += block_inv_check(dst_block_addr, page_list[src].pattern, sat, cpu_id); 844 dst_block_addr += sat->block_size_byte; 845 } 846 847 return err; 848 } 849 850 static u32 block_copy_check(void *dst_addr, struct adler_sum *adler_sum, 851 struct pattern *src_pattern, struct stressapptest_params *sat, 852 u8 cpu_id) 853 { 854 u32 err = 0; 855 856 if (adler_sum->a1 != src_pattern->adler_sum.a1 || 857 adler_sum->b1 != src_pattern->adler_sum.b1 || 858 adler_sum->a2 != src_pattern->adler_sum.a2 || 859 adler_sum->b2 != src_pattern->adler_sum.b2) 860 err = block_mis_search(dst_addr, src_pattern, "Copy", sat, cpu_id); 861 862 return err; 863 } 864 865 static u32 block_copy(void *dst_addr, void *src_addr, 866 struct pattern *src_pattern, 867 struct stressapptest_params *sat, u8 cpu_id) 868 { 869 u64 *dst_mem; 870 u64 *src_mem; 871 u64 data; 872 int i = 0; 873 #if defined(WARM_CPU) 874 double a, b, c, d; 875 #endif 876 877 struct adler_sum adler_sum = { 878 1, 0, 1, 0 879 }; 880 881 dst_mem = (u64 *)dst_addr; 882 src_mem = (u64 *)src_addr; 883 884 #if defined(WARM_CPU) 885 a = 2.0 * src_mem[0]; 886 b = 5.0 * src_mem[0]; 887 c = 7.0 * src_mem[0]; 888 d = 9.0 * src_mem[0]; 889 #endif 890 891 while (i < sat->block_size_byte / sizeof(u64)) { 892 data = src_mem[i]; 893 adler_sum.a1 += data & 0xffffffff; 894 adler_sum.b1 += adler_sum.a1; 895 adler_sum.a1 += data >> 32; 896 adler_sum.b1 += adler_sum.a1; 897 dst_mem[i] = data; 898 i++; 899 900 #if defined(WARM_CPU) 901 a = a * b; 902 b = b + c; 903 #endif 904 905 data = src_mem[i]; 906 adler_sum.a2 += data & 0xffffffff; 907 adler_sum.b2 += adler_sum.a2; 908 adler_sum.a2 += data >> 32; 909 adler_sum.b2 += adler_sum.a2; 910 dst_mem[i] = data; 911 i++; 912 913 #if defined(WARM_CPU) 914 c = c * d; 915 d = d + d; 916 #endif 917 } 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 942 for (int i = 0; i < sat->block_num; i++) { 943 err += block_copy(dst_block_addr, src_block_addr, 944 page_list[src].pattern, sat, cpu_id); 945 dst_block_addr += sat->block_size_byte; 946 src_block_addr += sat->block_size_byte; 947 } 948 949 page_list[dst].pattern = page_list[src].pattern; 950 page_list[dst].valid = 1; 951 page_list[src].valid = 0; 952 flush_dcache_range((ulong)&page_list[src], (ulong)&page_list[src + 1]); 953 flush_dcache_range((ulong)&page_list[dst], (ulong)&page_list[dst + 1]); 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_range((ulong)&cpu_test_finish[cpu_id], 1000 (ulong)&cpu_test_finish[cpu_id + 1]); 1001 flush_dcache_range((ulong)&cpu_copy_err[cpu_id], 1002 (ulong)&cpu_copy_err[cpu_id + 1]); 1003 flush_dcache_range((ulong)&cpu_inv_err[cpu_id], 1004 (ulong)&cpu_inv_err[cpu_id + 1]); 1005 } 1006 } 1007 #else 1008 return; 1009 #endif 1010 } 1011 1012 static int doing_stressapptest(void) 1013 { 1014 int i; 1015 u32 pre_10s; 1016 u32 now_10s; 1017 1018 struct pattern pattern_list[PATTERN_LIST_SIZE]; 1019 void *page_info; 1020 1021 u32 all_copy_err = 0; 1022 u32 all_inv_err = 0; 1023 u32 cpu_no_response_err = 0; 1024 1025 int ret = CMD_RET_SUCCESS; 1026 1027 for (i = 0; i < CPU_NUM_MAX; i++) { 1028 cpu_copy_err[i] = 0; 1029 cpu_inv_err[i] = 0; 1030 cpu_init_finish[i] = 0; 1031 cpu_test_finish[i] = 0; 1032 } 1033 pattern_page_init_finish = 0; 1034 print_mutex = 0; 1035 asm volatile("clrex"); 1036 1037 #if (CPU_NUM_MAX > 1) 1038 if (test_count == 0) { 1039 __gd = (ulong)gd; 1040 asm volatile("mov %0, sp" : "=r" (__sp)); 1041 printf("CPU0 sp is at 0x%lx now.\n", __sp); 1042 __sp &= ~(ulong)0xffff; 1043 for (sat.cpu_num = 1; sat.cpu_num < CPU_NUM_MAX; sat.cpu_num++) { 1044 __sp -= 0x10000; 1045 flush_dcache_all(); 1046 if (psci_cpu_on(sat.cpu_num, (ulong)secondary_init) == 0) { 1047 mdelay(10); 1048 printf("Calling CPU%d, sp = 0x%lx\n", sat.cpu_num, __sp); 1049 } else { 1050 break; 1051 } 1052 while (cpu_init_finish[sat.cpu_num] == 0) { 1053 udelay(1000); 1054 flush_dcache_all(); 1055 } 1056 } 1057 } 1058 #else 1059 sat.cpu_num = 1; 1060 #endif 1061 1062 if (sat.total_test_size_mb == 0) 1063 sat.page_num = get_max_page_num(sat.page_size_byte); 1064 else 1065 sat.page_num = (sat.total_test_size_mb << 20) / sat.page_size_byte; 1066 sat.block_num = sat.page_size_byte / sat.block_size_byte; 1067 1068 udelay(100); 1069 1070 page_info = malloc(sizeof(struct page) * sat.page_num); 1071 if (page_info == 0) { 1072 printf("ERROR: StressAppTest fail to malloc.\n"); 1073 printf("Please try increasing CONFIG_SYS_MALLOC_LEN in include/configs/rxxxxx_common.h.\n"); 1074 ret = CMD_RET_FAILURE; 1075 goto out; 1076 } 1077 page_list = (struct page *)page_info; 1078 1079 if (get_page_addr(page_list, &sat) < 0) { 1080 ret = CMD_RET_FAILURE; 1081 goto out; 1082 } 1083 1084 pattern_list_init(pattern_list, &sat); 1085 page_init(pattern_list, &sat); 1086 1087 #if (CPU_NUM_MAX > 1) 1088 if (sat.cpu_num > 1) { 1089 pattern_page_init_finish = 1; 1090 test_count++; 1091 flush_dcache_all(); 1092 } 1093 #endif 1094 1095 pre_10s = (u32)(run_time_us() / 1000000 / 10); 1096 lock_byte_mutex(&print_mutex); 1097 print_time_stamp(); 1098 printf("Start StressAppTest in U-Boot:\n"); 1099 unlock_byte_mutex(&print_mutex); 1100 1101 while (run_time_us() < test_time_us) { 1102 if (rand() % 2 == 0) 1103 cpu_copy_err[0] += page_copy(&sat, 0); 1104 else 1105 cpu_inv_err[0] += page_inv(&sat, 0); 1106 1107 /* Print every 10 seconds */ 1108 now_10s = (u32)(run_time_us() / 1000000 / 10); 1109 if (now_10s > pre_10s) { 1110 pre_10s = now_10s; 1111 lock_byte_mutex(&print_mutex); 1112 print_time_stamp(); 1113 printf("Seconds remaining: %d\n", (u32)(test_time_us / 1000000 - now_10s * 10)); 1114 unlock_byte_mutex(&print_mutex); 1115 } 1116 } 1117 1118 #if (CPU_NUM_MAX > 1) 1119 for (i = 1; i < sat.cpu_num; i++) { 1120 while (cpu_test_finish[i] == 0) { 1121 if ((u32)(run_time_us() / 1000000 / 10) > pre_10s + 6) { 1122 /* wait for secondary CPU in 60s */ 1123 lock_byte_mutex(&print_mutex); 1124 print_time_stamp(); 1125 printf("ERROR: Cannot wait for CPU%d to finish!\n", i); 1126 unlock_byte_mutex(&print_mutex); 1127 cpu_no_response_err++; 1128 break; 1129 } 1130 mdelay(1); 1131 flush_dcache_range((ulong)&cpu_test_finish[i], 1132 (ulong)&cpu_test_finish[i + 1]); 1133 } 1134 } 1135 flush_dcache_all(); 1136 #endif 1137 1138 for (i = 0; i < sat.cpu_num; i++) { 1139 all_copy_err += cpu_copy_err[i]; 1140 all_inv_err += cpu_inv_err[i]; 1141 } 1142 print_time_stamp(); 1143 printf("StressAppTest Result: "); 1144 if (all_copy_err == 0 && all_inv_err == 0 && cpu_no_response_err == 0) 1145 printf("Pass.\n"); 1146 else 1147 printf("FAIL!\nStressAppTest detects %d copy errors, %d inv errors.\n", 1148 all_copy_err, all_inv_err); 1149 1150 out: 1151 free(page_info); 1152 1153 return ret; 1154 } 1155 1156 static int do_stressapptest(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 1157 { 1158 ulong test_time_sec = 20; 1159 ulong page_size_kb = 1024; 1160 1161 sat.total_test_size_mb = 0; 1162 sat.block_size_byte = 4096; 1163 sat.total_start_addr = 0x0; 1164 1165 printf("StressAppTest in U-Boot, " __version__ "\n"); 1166 1167 if (argc > 1) { 1168 if (strict_strtoul(argv[1], 0, &test_time_sec) < 0) 1169 return CMD_RET_USAGE; 1170 if (test_time_sec < 1) 1171 test_time_sec = 20; 1172 } 1173 if (argc > 2) { 1174 if (strict_strtoul(argv[2], 0, &sat.total_test_size_mb) < 0) 1175 return CMD_RET_USAGE; 1176 if (sat.total_test_size_mb < 1) 1177 sat.total_test_size_mb = 0; 1178 } 1179 if (argc > 3) { 1180 if (strict_strtoul(argv[3], 0, &sat.total_start_addr) < 0) 1181 return CMD_RET_USAGE; 1182 if (sat.total_start_addr < 0x1) 1183 sat.total_start_addr = 0x0; 1184 } 1185 if (argc > 4) { 1186 if (strict_strtoul(argv[4], 0, &page_size_kb) < 0) 1187 return CMD_RET_USAGE; 1188 if (page_size_kb < 1) 1189 page_size_kb = 1024; 1190 } 1191 1192 sat.page_size_byte = page_size_kb << 10; 1193 1194 start_time_us = get_time_us(); 1195 test_time_us = (u64)test_time_sec * 1000000; 1196 1197 /* Change rand seed. If not do this, rand() would be same after boot.*/ 1198 srand((unsigned int)(start_time_us & 0xffffffff)); 1199 1200 return doing_stressapptest(); 1201 } 1202 1203 U_BOOT_CMD(stressapptest, 5, 1, do_stressapptest, 1204 "StressAppTest for Rockchip\n", 1205 "\narg1: test time in second, default value is 20s.\n" 1206 "arg2: test size in MB, default value is all available space.\n" 1207 "arg3: start addr for test.\n" 1208 "arg4: test page size in kB, default value is 1024kB(1MB).\n" 1209 "example:\n" 1210 " stressapptest: test for 20s, test size is all available space, each page size is 1MB.\n" 1211 " stressapptest 43200 64: test for 12h, test size is 64MB, each page size is 1MB (64 pages).\n" 1212 " 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" 1213 " 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" 1214 ); 1215