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