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.0.0 20230214" 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 int get_page_addr(struct page *page_list, 511 struct stressapptest_params *sat) 512 { 513 ulong start_adr[CONFIG_NR_DRAM_BANKS], length[CONFIG_NR_DRAM_BANKS]; 514 ulong used_length; 515 u32 page = 0; 516 517 get_print_available_addr(start_adr, length, 1); 518 519 printf("Pages for test:\n Page Start End Length\n"); 520 521 for (int i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 522 if ((start_adr[i] == 0 && length[i] == 0) || page >= sat->page_num) 523 break; 524 if (start_adr[i] + length[i] < sat->total_start_addr) 525 continue; 526 if (start_adr[i] < sat->total_start_addr) { 527 length[i] -= sat->total_start_addr - start_adr[i]; 528 start_adr[i] = sat->total_start_addr; 529 } 530 531 used_length = 0; 532 while (page < sat->page_num && 533 length[i] >= used_length + sat->page_size_byte) { 534 page_list[page].base_addr = (void *)(start_adr[i] + used_length); 535 used_length += sat->page_size_byte; 536 printf(" %d 0x%08lx - 0x%08lx 0x%08lx\n", 537 page, (ulong)page_list[page].base_addr, 538 (ulong)page_list[page].base_addr + sat->page_size_byte, 539 (ulong)sat->page_size_byte); 540 page++; 541 } 542 } 543 544 if (page < sat->page_num) { 545 printf("ERROR: Cannot get enough pages to test.\n"); 546 printf("Please decrease page_size or test_size\n"); 547 548 return -1; 549 } 550 551 return 0; 552 } 553 554 static void page_init_valid(struct page *page, struct pattern *pattern_list, 555 struct stressapptest_params *sat) 556 { 557 int target; 558 int i = 0; 559 u64 *mem; 560 561 target = (rand() % sat->weight_count) + 1; 562 do { 563 target -= pattern_list[i++].weight; 564 if (target <= 0) 565 break; 566 } while (i < PATTERN_LIST_SIZE); 567 page->pattern = &pattern_list[--i]; 568 page->valid = 1; 569 570 mem = (u64 *)page->base_addr; 571 for (i = 0; i < sat->page_size_byte / sizeof(u64); i++) 572 mem[i] = (u64)pattern_get(page->pattern, i * 2) | 573 (u64)pattern_get(page->pattern, i * 2 + 1) << 32; 574 } 575 576 static void page_init_empty(struct page *page) 577 { 578 page->valid = 0; 579 } 580 581 static void page_init(struct pattern *pattern_list, 582 struct stressapptest_params *sat) 583 { 584 int i, cpu; 585 u32 empty_page_num; 586 587 for (cpu = 0; cpu < sat->cpu_num; cpu++) { 588 empty_page_num = 0; 589 for (i = cpu; i < sat->page_num; i += sat->cpu_num) { 590 if (rand() % 5 < 3) { 591 page_list[i].valid = 1; 592 } else { 593 page_list[i].valid = 0; 594 empty_page_num++; 595 } 596 } 597 while (empty_page_num >= sat->page_num / sat->cpu_num / 2 && i > 0) { 598 i -= sat->cpu_num; 599 if (page_list[i].valid == 0) { 600 page_list[i].valid = 1; 601 empty_page_num--; 602 } 603 } 604 i = cpu; 605 while (empty_page_num < 2 && i < sat->page_num) { 606 if (page_list[i].valid == 1) { 607 page_list[i].valid = 0; 608 empty_page_num++; 609 } 610 i += sat->cpu_num; 611 } 612 } 613 614 for (i = 0; i < sat->page_num; i++) { 615 if (page_list[i].valid == 1) 616 page_init_valid(&page_list[i], pattern_list, sat); 617 else 618 page_init_empty(&page_list[i]); 619 } 620 flush_dcache_all(); 621 } 622 623 static u32 page_rand_pick(struct page *page_list, bool valid, 624 struct stressapptest_params *sat, u8 cpu_id) 625 { 626 u32 pick; 627 628 pick = rand() % sat->page_num; 629 pick = pick / sat->cpu_num * sat->cpu_num + cpu_id; 630 if (pick >= sat->page_num) 631 pick = cpu_id; 632 633 while (page_list[pick].valid != valid) { 634 pick += sat->cpu_num; 635 if (pick >= sat->page_num) 636 pick = cpu_id; 637 } 638 639 return pick; 640 } 641 642 static u32 block_inv_mis_search(void *dst_addr, struct pattern *src_pattern, 643 struct stressapptest_params *sat) 644 { 645 u32 *dst_mem; 646 u32 dst_data; 647 u32 expc_data; 648 u32 mis_bit; 649 u32 err = 0; 650 651 dst_mem = (u32 *)dst_addr; 652 653 for (int i = 0; i < sat->block_size_byte / sizeof(u32); i++) { 654 dst_data = dst_mem[i]; 655 expc_data = pattern_get(src_pattern, i); 656 657 if (dst_data != expc_data) { 658 lock_byte_mutex(&print_mutex); 659 660 print_time_stamp(); 661 printf("INV ERROR at 0x%010lx:\n", (ulong)&dst_mem[i]); 662 printf(" data = 0x%08x\n", dst_data); 663 printf(" expc = 0x%08x\n", expc_data); 664 665 mis_bit = dst_data ^ expc_data; 666 printf(" mismatch at bit"); 667 for (int j = 31; j >= 0; j--) { 668 if (((mis_bit >> j) & 1) == 1) 669 printf(" %d", j); 670 } 671 printf("\n"); 672 673 unlock_byte_mutex(&print_mutex); 674 dst_mem[i] = expc_data; 675 err++; 676 } 677 } 678 flush_dcache_all(); 679 680 if (err == 0) { 681 lock_byte_mutex(&print_mutex); 682 printf("INV ERROR detected but cannot find mismatch data (maybe read error).\n"); 683 unlock_byte_mutex(&print_mutex); 684 } 685 686 return err; 687 } 688 689 static u32 block_inv_check(void *dst_addr, struct pattern *src_pattern, 690 struct stressapptest_params *sat, u8 cpu_id) 691 { 692 u32 *dst_mem; 693 u32 err = 0; 694 int i = 0; 695 #if defined(WARM_CPU) 696 double a, b, c, d; 697 #endif 698 699 struct adler_sum adler_sum = { 700 1, 0, 1, 0 701 }; 702 703 dst_mem = (u32 *)dst_addr; 704 705 #if defined(WARM_CPU) 706 a = 2.0 * dst_mem[0]; 707 b = 5.0 * dst_mem[0]; 708 c = 7.0 * dst_mem[0]; 709 d = 9.0 * dst_mem[0]; 710 #endif 711 712 while (i < sat->block_size_byte / sizeof(u32)) { 713 adler_sum.a1 += dst_mem[i++]; 714 adler_sum.b1 += adler_sum.a1; 715 adler_sum.a1 += dst_mem[i++]; 716 adler_sum.b1 += adler_sum.a1; 717 718 #if defined(WARM_CPU) 719 a = a * b; 720 b = b + c; 721 #endif 722 723 adler_sum.a2 += dst_mem[i++]; 724 adler_sum.b2 += adler_sum.a2; 725 adler_sum.a2 += dst_mem[i++]; 726 adler_sum.b2 += adler_sum.a2; 727 #if defined(WARM_CPU) 728 c = c * d; 729 d = d + d; 730 #endif 731 } 732 733 #if defined(WARM_CPU) 734 d = a + b + c + d; 735 if (d == 1.0) 736 /* Reference the result so that it can't be discarded by the compiler. */ 737 printf("This will probably never happen.\n"); 738 #endif 739 740 if (adler_sum.a1 != src_pattern->adler_sum.a1 || 741 adler_sum.b1 != src_pattern->adler_sum.b1 || 742 adler_sum.a2 != src_pattern->adler_sum.a2 || 743 adler_sum.b2 != src_pattern->adler_sum.b2) { 744 err = block_inv_mis_search(dst_addr, src_pattern, sat); 745 746 lock_byte_mutex(&print_mutex); 747 printf("(CPU%d, Pattern: %s, inv: %d, repeat: %d)\n\n", 748 cpu_id, src_pattern->pat->name, src_pattern->inv, 749 src_pattern->repeat); 750 unlock_byte_mutex(&print_mutex); 751 } 752 753 return err; 754 } 755 756 static void page_inv_up(void *src_addr, struct stressapptest_params *sat) 757 { 758 void *dst_addr = src_addr; 759 uint data; 760 uint *dst_mem; 761 762 for (int i = 0; i < sat->block_num; i++) { 763 dst_mem = (uint *)dst_addr; 764 for (int j = 0; j < sat->block_size_byte / sizeof(uint); j++) { 765 data = dst_mem[j]; 766 dst_mem[j] = ~data; 767 } 768 dst_addr += sat->block_size_byte; 769 flush_dcache_all(); 770 } 771 } 772 773 static void page_inv_down(void *src_addr, struct stressapptest_params *sat) 774 { 775 void *dst_addr = src_addr; 776 uint data; 777 uint *dst_mem; 778 779 dst_addr += sat->block_size_byte * (sat->block_num - 1); 780 781 for (int i = sat->block_num - 1; i >= 0; i--) { 782 dst_mem = (uint *)dst_addr; 783 for (int j = sat->block_size_byte / sizeof(uint) - 1; j >= 0; j--) { 784 data = dst_mem[j]; 785 dst_mem[j] = ~data; 786 } 787 dst_addr -= sat->block_size_byte; 788 flush_dcache_all(); 789 } 790 } 791 792 static u32 page_inv(struct stressapptest_params *sat, u8 cpu_id) 793 { 794 u32 src; 795 void *dst_block_addr; 796 u32 err = 0; 797 798 src = page_rand_pick(page_list, 1, sat, cpu_id); /* pick a valid page */ 799 dst_block_addr = page_list[src].base_addr; 800 801 for (int i = 0; i < 4; i++) { 802 if (rand() % 2 == 0) 803 page_inv_up(page_list[src].base_addr, sat); 804 else 805 page_inv_down(page_list[src].base_addr, sat); 806 } 807 808 for (int i = 0; i < sat->block_num; i++) { 809 err += block_inv_check(dst_block_addr, page_list[src].pattern, sat, cpu_id); 810 dst_block_addr += sat->block_size_byte; 811 } 812 813 flush_dcache_all(); 814 815 return err; 816 } 817 818 static u32 block_copy_mis_search(void *dst_addr, void *src_addr, 819 struct pattern *src_pattern, 820 struct stressapptest_params *sat) 821 { 822 u32 *dst_mem; 823 u32 *src_mem; 824 u32 dst_data; 825 u32 src_data; 826 u32 expc_data; 827 u32 mis_bit; 828 u32 err = 0; 829 830 dst_mem = (u32 *)dst_addr; 831 src_mem = (u32 *)src_addr; 832 833 for (int i = 0; i < sat->block_size_byte / sizeof(u32); i++) { 834 dst_data = dst_mem[i]; 835 src_data = src_mem[i]; 836 expc_data = pattern_get(src_pattern, i); 837 838 if (dst_data != expc_data) { 839 lock_byte_mutex(&print_mutex); 840 841 print_time_stamp(); 842 printf("COPY ERROR ("); 843 if (src_data == expc_data) 844 printf("read"); 845 else if (src_data != expc_data) 846 printf("write"); 847 printf(" error) at 0x%010lx:\n", (ulong)&src_mem[i]); 848 printf(" data = 0x%08x\n", dst_data); 849 printf(" expc = 0x%08x\n", expc_data); 850 851 mis_bit = dst_data ^ expc_data; 852 printf(" mismatch at bit"); 853 for (int j = 31; j >= 0; j--) { 854 if (((mis_bit >> j) & 1) == 1) 855 printf(" %d", j); 856 } 857 printf("\n"); 858 859 unlock_byte_mutex(&print_mutex); 860 err++; 861 dst_mem[i] = expc_data; 862 } 863 } 864 flush_dcache_all(); 865 866 if (err == 0) { 867 lock_byte_mutex(&print_mutex); 868 printf("COPY ERROR detected but cannot find mismatch data (maybe read error).\n"); 869 unlock_byte_mutex(&print_mutex); 870 } 871 872 return err; 873 } 874 875 static u32 block_copy_check(void *dst_addr, void *src_addr, 876 struct adler_sum *adler_sum, 877 struct pattern *src_pattern, 878 struct stressapptest_params *sat, u8 cpu_id) 879 { 880 u32 err = 0; 881 882 if (adler_sum->a1 != src_pattern->adler_sum.a1 || 883 adler_sum->b1 != src_pattern->adler_sum.b1 || 884 adler_sum->a2 != src_pattern->adler_sum.a2 || 885 adler_sum->b2 != src_pattern->adler_sum.b2) { 886 err += block_copy_mis_search(dst_addr, src_addr, src_pattern, sat); 887 888 lock_byte_mutex(&print_mutex); 889 printf("(CPU%d, Pattern: %s, inv: %d, repeat: %d)\n\n", 890 cpu_id, src_pattern->pat->name, src_pattern->inv, 891 src_pattern->repeat); 892 unlock_byte_mutex(&print_mutex); 893 } 894 895 return err; 896 } 897 898 static u32 block_copy(void *dst_addr, void *src_addr, 899 struct pattern *src_pattern, 900 struct stressapptest_params *sat, u8 cpu_id) 901 { 902 u64 *dst_mem; 903 u64 *src_mem; 904 u64 data; 905 int i = 0; 906 #if defined(WARM_CPU) 907 double a, b, c, d; 908 #endif 909 910 struct adler_sum adler_sum = { 911 1, 0, 1, 0 912 }; 913 914 dst_mem = (u64 *)dst_addr; 915 src_mem = (u64 *)src_addr; 916 917 #if defined(WARM_CPU) 918 a = 2.0 * src_mem[0]; 919 b = 5.0 * src_mem[0]; 920 c = 7.0 * src_mem[0]; 921 d = 9.0 * src_mem[0]; 922 #endif 923 924 while (i < sat->block_size_byte / sizeof(u64)) { 925 data = src_mem[i]; 926 adler_sum.a1 += data & 0xffffffff; 927 adler_sum.b1 += adler_sum.a1; 928 adler_sum.a1 += data >> 32; 929 adler_sum.b1 += adler_sum.a1; 930 dst_mem[i] = data; 931 i++; 932 933 #if defined(WARM_CPU) 934 a = a * b; 935 b = b + c; 936 #endif 937 938 data = src_mem[i]; 939 adler_sum.a2 += data & 0xffffffff; 940 adler_sum.b2 += adler_sum.a2; 941 adler_sum.a2 += data >> 32; 942 adler_sum.b2 += adler_sum.a2; 943 dst_mem[i] = data; 944 i++; 945 946 #if defined(WARM_CPU) 947 c = c * d; 948 d = d + d; 949 #endif 950 } 951 952 flush_dcache_all(); 953 954 #if defined(WARM_CPU) 955 d = a + b + c + d; 956 if (d == 1.0) 957 /* Reference the result so that it can't be discarded by the compiler. */ 958 printf("This will probably never happen.\n"); 959 #endif 960 961 return block_copy_check(dst_addr, src_addr, &adler_sum, src_pattern, sat, cpu_id); 962 } 963 964 static u32 page_copy(struct stressapptest_params *sat, u8 cpu_id) 965 { 966 u32 dst; 967 u32 src; 968 void *dst_block_addr; 969 void *src_block_addr; 970 u32 err = 0; 971 972 dst = page_rand_pick(page_list, 0, sat, cpu_id); /* pick a empty page */ 973 dst_block_addr = page_list[dst].base_addr; 974 src = page_rand_pick(page_list, 1, sat, cpu_id); /* pick a valid page */ 975 src_block_addr = page_list[src].base_addr; 976 flush_dcache_all(); 977 978 for (int i = 0; i < sat->block_num; i++) { 979 err += block_copy(dst_block_addr, src_block_addr, 980 page_list[src].pattern, sat, cpu_id); 981 dst_block_addr += sat->block_size_byte; 982 src_block_addr += sat->block_size_byte; 983 } 984 985 page_list[dst].pattern = page_list[src].pattern; 986 page_list[dst].valid = 1; 987 page_list[src].valid = 0; 988 flush_dcache_all(); 989 990 return err; 991 } 992 993 void secondary_main(void) 994 { 995 #if (CPU_NUM_MAX > 1) 996 u8 cpu_id; 997 ulong test = 0; 998 999 #ifndef CONFIG_ARM64 1000 asm volatile("mov r9, %0" : : "r" (__gd)); /* set r9 to gd addr */ 1001 #else 1002 asm volatile("mov x18, %0" : : "r" (__gd)); /* set x18 to gd addr */ 1003 #endif 1004 dcache_enable(); 1005 icache_enable(); 1006 1007 udelay(100); 1008 1009 flush_dcache_all(); 1010 1011 cpu_id = sat.cpu_num; 1012 cpu_init_finish[cpu_id] = 1; 1013 printf("CPU%d start OK.\n", cpu_id); 1014 1015 while (pattern_page_init_finish == 0) { 1016 udelay(100); 1017 flush_dcache_all(); 1018 } 1019 1020 while (1) { 1021 udelay(100); 1022 flush_dcache_all(); 1023 while (test < test_count) { 1024 cpu_test_finish[cpu_id] = 0; 1025 flush_dcache_all(); 1026 while (run_time_us() < test_time_us) { 1027 if (rand() % 2 == 0) 1028 cpu_copy_err[cpu_id] += page_copy(&sat, cpu_id); 1029 else 1030 cpu_inv_err[cpu_id] += page_inv(&sat, cpu_id); 1031 } 1032 test++; 1033 cpu_test_finish[cpu_id] = 1; 1034 flush_dcache_all(); 1035 } 1036 } 1037 #else 1038 return; 1039 #endif 1040 } 1041 1042 static int doing_stressapptest(void) 1043 { 1044 int i; 1045 u32 pre_10s; 1046 u32 now_10s; 1047 1048 struct pattern pattern_list[PATTERN_LIST_SIZE]; 1049 void *page_info; 1050 1051 u32 all_copy_err = 0; 1052 u32 all_inv_err = 0; 1053 u32 cpu_no_response_err = 0; 1054 1055 int ret = CMD_RET_SUCCESS; 1056 1057 for (i = 0; i < CPU_NUM_MAX; i++) { 1058 cpu_copy_err[i] = 0; 1059 cpu_inv_err[i] = 0; 1060 cpu_init_finish[i] = 0; 1061 cpu_test_finish[i] = 0; 1062 } 1063 pattern_page_init_finish = 0; 1064 print_mutex = 0; 1065 asm volatile("clrex"); 1066 1067 #if (CPU_NUM_MAX > 1) 1068 if (test_count == 0) { 1069 __gd = (ulong)gd; 1070 asm volatile("mov %0, sp" : "=r" (__sp)); 1071 printf("CPU0 sp is at 0x%lx now.\n", __sp); 1072 __sp &= ~(ulong)0xffff; 1073 for (sat.cpu_num = 1; sat.cpu_num < CPU_NUM_MAX; sat.cpu_num++) { 1074 __sp -= 0x10000; 1075 flush_dcache_all(); 1076 if (psci_cpu_on(sat.cpu_num, (ulong)secondary_init) == 0) { 1077 mdelay(10); 1078 printf("Calling CPU%d, sp = 0x%lx\n", sat.cpu_num, __sp); 1079 } else { 1080 break; 1081 } 1082 while (cpu_init_finish[sat.cpu_num] == 0) { 1083 udelay(1000); 1084 flush_dcache_all(); 1085 } 1086 } 1087 } 1088 #else 1089 sat.cpu_num = 1; 1090 #endif 1091 1092 sat.page_num = (sat.total_test_size_mb << 20) / sat.page_size_byte; 1093 sat.block_num = sat.page_size_byte / sat.block_size_byte; 1094 1095 udelay(100); 1096 1097 page_info = malloc(sizeof(struct page) * sat.page_num); 1098 if (page_info == 0) { 1099 printf("ERROR: StressAppTest fail to malloc.\n"); 1100 printf("Please try increasing CONFIG_SYS_MALLOC_LEN in include/configs/rxxxxx_common.h.\n"); 1101 ret = CMD_RET_FAILURE; 1102 goto out; 1103 } 1104 page_list = (struct page *)page_info; 1105 1106 if (get_page_addr(page_list, &sat) < 0) { 1107 ret = CMD_RET_FAILURE; 1108 goto out; 1109 } 1110 1111 pattern_list_init(pattern_list, &sat); 1112 page_init(pattern_list, &sat); 1113 1114 #if (CPU_NUM_MAX > 1) 1115 if (sat.cpu_num > 1) { 1116 pattern_page_init_finish = 1; 1117 test_count++; 1118 flush_dcache_all(); 1119 } 1120 #endif 1121 1122 pre_10s = (u32)(run_time_us() / 1000000 / 10); 1123 lock_byte_mutex(&print_mutex); 1124 print_time_stamp(); 1125 printf("Start StressAppTest in U-Boot:\n"); 1126 unlock_byte_mutex(&print_mutex); 1127 1128 while (run_time_us() < test_time_us) { 1129 if (rand() % 2 == 0) 1130 cpu_copy_err[0] += page_copy(&sat, 0); 1131 else 1132 cpu_inv_err[0] += page_inv(&sat, 0); 1133 1134 /* Print every 10 seconds */ 1135 now_10s = (u32)(run_time_us() / 1000000 / 10); 1136 if (now_10s > pre_10s) { 1137 pre_10s = now_10s; 1138 lock_byte_mutex(&print_mutex); 1139 print_time_stamp(); 1140 printf("Seconds remaining: %d\n", (u32)(test_time_us / 1000000 - now_10s * 10)); 1141 unlock_byte_mutex(&print_mutex); 1142 } 1143 } 1144 1145 #if (CPU_NUM_MAX > 1) 1146 for (i = 1; i < sat.cpu_num; i++) { 1147 while (cpu_test_finish[i] == 0) { 1148 if ((u32)(run_time_us() / 1000000 / 10) > pre_10s + 6) { 1149 /* wait for secondary CPU in 60s */ 1150 lock_byte_mutex(&print_mutex); 1151 print_time_stamp(); 1152 printf("ERROR: Cannot wait for CPU%d to finish!\n", i); 1153 unlock_byte_mutex(&print_mutex); 1154 cpu_no_response_err++; 1155 break; 1156 } 1157 mdelay(1); 1158 flush_dcache_all(); 1159 } 1160 } 1161 #endif 1162 1163 for (i = 0; i < sat.cpu_num; i++) { 1164 all_copy_err += cpu_copy_err[i]; 1165 all_inv_err += cpu_inv_err[i]; 1166 } 1167 print_time_stamp(); 1168 printf("StressAppTest Result: "); 1169 if (all_copy_err == 0 && all_inv_err == 0 && cpu_no_response_err == 0) 1170 printf("Pass.\n"); 1171 else 1172 printf("FAIL!\nStressAppTest detects %d copy errors, %d inv errors.\n", 1173 all_copy_err, all_inv_err); 1174 1175 out: 1176 free(page_info); 1177 1178 return ret; 1179 } 1180 1181 static int do_stressapptest(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 1182 { 1183 ulong test_time_sec = 20; 1184 ulong page_size_kb = 1024; 1185 1186 sat.total_test_size_mb = 32; 1187 sat.block_size_byte = 4096; 1188 sat.total_start_addr = 0x0; 1189 1190 printf("StressAppTest in U-Boot, " __version__ "\n"); 1191 1192 if (argc > 1) { 1193 if (strict_strtoul(argv[1], 0, &test_time_sec) < 0) 1194 return CMD_RET_USAGE; 1195 if (test_time_sec < 1) 1196 test_time_sec = 20; 1197 } 1198 if (argc > 2) { 1199 if (strict_strtoul(argv[2], 0, &sat.total_test_size_mb) < 0) 1200 return CMD_RET_USAGE; 1201 if (sat.total_test_size_mb < 1) 1202 sat.total_test_size_mb = 32; 1203 } 1204 if (argc > 3) { 1205 if (strict_strtoul(argv[3], 0, &sat.total_start_addr) < 0) 1206 return CMD_RET_USAGE; 1207 if (sat.total_start_addr < 0x1) 1208 sat.total_start_addr = 0x0; 1209 } 1210 if (argc > 4) { 1211 if (strict_strtoul(argv[4], 0, &page_size_kb) < 0) 1212 return CMD_RET_USAGE; 1213 if (page_size_kb < 1) 1214 page_size_kb = 1024; 1215 } 1216 1217 sat.page_size_byte = page_size_kb << 10; 1218 1219 start_time_us = get_time_us(); 1220 test_time_us = (u64)test_time_sec * 1000000; 1221 1222 /* Change rand seed. If not do this, rand() would be same after boot.*/ 1223 srand((unsigned int)(start_time_us & 0xffffffff)); 1224 1225 return doing_stressapptest(); 1226 } 1227 1228 U_BOOT_CMD(stressapptest, 5, 1, do_stressapptest, 1229 "StressAppTest for Rockchip\n", 1230 "\narg1: test time in second, default value is 20s.\n" 1231 "arg2: test size in MB, default value is 32MB.\n" 1232 "arg3: start addr for test.\n" 1233 "arg4: test page size in kB, default value is 1024kB(1MB).\n" 1234 "example:\n" 1235 " stressapptest: test for 20s, test size is 32MB, each page size is 1MB (32 pages).\n" 1236 " stressapptest 43200 64: test for 12h, test size is 64MB, each page size is 1MB (64 pages).\n" 1237 " 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" 1238 " 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" 1239 ); 1240