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