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