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 525 used_length = 0; 526 while (page < sat->page_num && 527 length[i] >= used_length + sat->page_size_byte) { 528 page_list[page].base_addr = (void *)(start_adr[i] + used_length); 529 used_length += sat->page_size_byte; 530 printf(" %d 0x%08lx - 0x%08lx 0x%08lx\n", 531 page, (ulong)page_list[page].base_addr, 532 (ulong)page_list[page].base_addr + sat->page_size_byte, 533 (ulong)sat->page_size_byte); 534 page++; 535 } 536 } 537 538 if (page < sat->page_num) { 539 printf("ERROR: Cannot get enough pages to test.\n"); 540 printf("Please decrease page_size or test_size\n"); 541 542 return -1; 543 } 544 545 return 0; 546 } 547 548 static void page_init_valid(struct page *page, struct pattern *pattern_list, 549 struct stressapptest_params *sat) 550 { 551 int target; 552 int i = 0; 553 u64 *mem; 554 555 target = (rand() % sat->weight_count) + 1; 556 do { 557 target -= pattern_list[i++].weight; 558 if (target <= 0) 559 break; 560 } while (i < PATTERN_LIST_SIZE); 561 page->pattern = &pattern_list[--i]; 562 page->valid = 1; 563 564 mem = (u64 *)page->base_addr; 565 for (i = 0; i < sat->page_size_byte / sizeof(u64); i++) 566 mem[i] = (u64)pattern_get(page->pattern, i * 2) | 567 (u64)pattern_get(page->pattern, i * 2 + 1) << 32; 568 } 569 570 static void page_init_empty(struct page *page) 571 { 572 page->valid = 0; 573 } 574 575 static void page_init(struct pattern *pattern_list, 576 struct stressapptest_params *sat) 577 { 578 int i, cpu; 579 u32 empty_page_num; 580 581 for (cpu = 0; cpu < sat->cpu_num; cpu++) { 582 empty_page_num = 0; 583 for (i = cpu; i < sat->page_num; i += sat->cpu_num) { 584 if (rand() % 5 < 3) { 585 page_list[i].valid = 1; 586 } else { 587 page_list[i].valid = 0; 588 empty_page_num++; 589 } 590 } 591 while (empty_page_num >= sat->page_num / sat->cpu_num / 2 && i > 0) { 592 i -= sat->cpu_num; 593 if (page_list[i].valid == 0) { 594 page_list[i].valid = 1; 595 empty_page_num--; 596 } 597 } 598 i = cpu; 599 while (empty_page_num < 2 && i < sat->page_num) { 600 if (page_list[i].valid == 1) { 601 page_list[i].valid = 0; 602 empty_page_num++; 603 } 604 i += sat->cpu_num; 605 } 606 } 607 608 for (i = 0; i < sat->page_num; i++) { 609 if (page_list[i].valid == 1) 610 page_init_valid(&page_list[i], pattern_list, sat); 611 else 612 page_init_empty(&page_list[i]); 613 } 614 flush_dcache_all(); 615 } 616 617 static u32 page_rand_pick(struct page *page_list, bool valid, 618 struct stressapptest_params *sat) 619 { 620 u32 pick; 621 u32 cpu_id; 622 623 cpu_id = get_cpu_id(); 624 pick = rand() % (sat->page_num / sat->cpu_num) * sat->cpu_num + cpu_id; 625 while (page_list[pick].valid != valid) { 626 pick += sat->cpu_num; 627 if (pick >= sat->page_num) 628 pick = cpu_id; 629 } 630 631 return pick; 632 } 633 634 static u32 block_inv_mis_search(void *dst_addr, struct pattern *src_pattern, 635 struct stressapptest_params *sat) 636 { 637 u32 *dst_mem; 638 u32 dst_data; 639 u32 expc_data; 640 u32 mis_bit; 641 u32 err = 0; 642 643 dst_mem = (u32 *)dst_addr; 644 645 for (int i = 0; i < sat->block_size_byte / sizeof(u32); i++) { 646 dst_data = dst_mem[i]; 647 expc_data = pattern_get(src_pattern, i); 648 649 if (dst_data != expc_data) { 650 lock_byte_mutex(&print_mutex); 651 652 print_time_stamp(); 653 printf("INV ERROR at 0x%010lx:\n", (ulong)&dst_mem[i]); 654 printf(" data = 0x%08x\n", dst_data); 655 printf(" expc = 0x%08x\n", expc_data); 656 657 mis_bit = dst_data ^ expc_data; 658 printf(" mismatch at bit"); 659 for (int j = 31; j >= 0; j--) { 660 if (((mis_bit >> j) & 1) == 1) 661 printf(" %d", j); 662 } 663 printf("\n"); 664 665 unlock_byte_mutex(&print_mutex); 666 dst_mem[i] = expc_data; 667 err++; 668 } 669 } 670 flush_dcache_all(); 671 672 if (err == 0) { 673 lock_byte_mutex(&print_mutex); 674 printf("INV ERROR detected but cannot find mismatch data (maybe read error).\n"); 675 unlock_byte_mutex(&print_mutex); 676 } 677 678 return err; 679 } 680 681 static u32 block_inv_check(void *dst_addr, struct pattern *src_pattern, 682 struct stressapptest_params *sat) 683 { 684 u32 *dst_mem; 685 u32 err = 0; 686 int i = 0; 687 #if defined(WARM_CPU) 688 double a, b, c, d; 689 #endif 690 691 struct adler_sum adler_sum = { 692 1, 0, 1, 0 693 }; 694 695 dst_mem = (u32 *)dst_addr; 696 697 #if defined(WARM_CPU) 698 a = 2.0 * dst_mem[0]; 699 b = 5.0 * dst_mem[0]; 700 c = 7.0 * dst_mem[0]; 701 d = 9.0 * dst_mem[0]; 702 #endif 703 704 while (i < sat->block_size_byte / sizeof(u32)) { 705 adler_sum.a1 += dst_mem[i++]; 706 adler_sum.b1 += adler_sum.a1; 707 adler_sum.a1 += dst_mem[i++]; 708 adler_sum.b1 += adler_sum.a1; 709 710 #if defined(WARM_CPU) 711 a = a * b; 712 b = b + c; 713 #endif 714 715 adler_sum.a2 += dst_mem[i++]; 716 adler_sum.b2 += adler_sum.a2; 717 adler_sum.a2 += dst_mem[i++]; 718 adler_sum.b2 += adler_sum.a2; 719 #if defined(WARM_CPU) 720 c = c * d; 721 d = d + d; 722 #endif 723 } 724 725 #if defined(WARM_CPU) 726 d = a + b + c + d; 727 if (d == 1.0) 728 /* Reference the result so that it can't be discarded by the compiler. */ 729 printf("This will probably never happen.\n"); 730 #endif 731 732 if (adler_sum.a1 != src_pattern->adler_sum.a1 || 733 adler_sum.b1 != src_pattern->adler_sum.b1 || 734 adler_sum.a2 != src_pattern->adler_sum.a2 || 735 adler_sum.b2 != src_pattern->adler_sum.b2) { 736 err = block_inv_mis_search(dst_addr, src_pattern, sat); 737 738 lock_byte_mutex(&print_mutex); 739 printf("(CPU%d, Pattern: %s, inv: %d, repeat: %d)\n\n", 740 get_cpu_id(), src_pattern->pat->name, src_pattern->inv, 741 src_pattern->repeat); 742 unlock_byte_mutex(&print_mutex); 743 } 744 745 return err; 746 } 747 748 static void page_inv_up(void *src_addr, struct stressapptest_params *sat) 749 { 750 void *dst_addr = src_addr; 751 uint data; 752 uint *dst_mem; 753 754 for (int i = 0; i < sat->block_num; i++) { 755 dst_mem = (uint *)dst_addr; 756 for (int j = 0; j < sat->block_size_byte / sizeof(uint); j++) { 757 data = dst_mem[j]; 758 dst_mem[j] = ~data; 759 } 760 dst_addr += sat->block_size_byte; 761 flush_dcache_all(); 762 } 763 } 764 765 static void page_inv_down(void *src_addr, struct stressapptest_params *sat) 766 { 767 void *dst_addr = src_addr; 768 uint data; 769 uint *dst_mem; 770 771 dst_addr += sat->block_size_byte * (sat->block_num - 1); 772 773 for (int i = sat->block_num - 1; i >= 0; i--) { 774 dst_mem = (uint *)dst_addr; 775 for (int j = sat->block_size_byte / sizeof(uint) - 1; j >= 0; j--) { 776 data = dst_mem[j]; 777 dst_mem[j] = ~data; 778 } 779 dst_addr -= sat->block_size_byte; 780 flush_dcache_all(); 781 } 782 } 783 784 static u32 page_inv(struct stressapptest_params *sat) 785 { 786 u32 src; 787 void *dst_block_addr; 788 u32 err = 0; 789 790 src = page_rand_pick(page_list, 1, sat); /* pick a valid page */ 791 dst_block_addr = page_list[src].base_addr; 792 793 for (int i = 0; i < 4; i++) { 794 if (rand() % 2 == 0) 795 page_inv_up(page_list[src].base_addr, sat); 796 else 797 page_inv_down(page_list[src].base_addr, sat); 798 } 799 800 for (int i = 0; i < sat->block_num; i++) { 801 err += block_inv_check(dst_block_addr, page_list[src].pattern, sat); 802 dst_block_addr += sat->block_size_byte; 803 } 804 805 flush_dcache_all(); 806 807 return err; 808 } 809 810 static u32 block_copy_mis_search(void *dst_addr, void *src_addr, 811 struct pattern *src_pattern, 812 struct stressapptest_params *sat) 813 { 814 u32 *dst_mem; 815 u32 *src_mem; 816 u32 dst_data; 817 u32 src_data; 818 u32 expc_data; 819 u32 mis_bit; 820 u32 err = 0; 821 822 dst_mem = (u32 *)dst_addr; 823 src_mem = (u32 *)src_addr; 824 825 for (int i = 0; i < sat->block_size_byte / sizeof(u32); i++) { 826 dst_data = dst_mem[i]; 827 src_data = src_mem[i]; 828 expc_data = pattern_get(src_pattern, i); 829 830 if (dst_data != expc_data) { 831 lock_byte_mutex(&print_mutex); 832 833 print_time_stamp(); 834 printf("COPY ERROR ("); 835 if (src_data == expc_data) 836 printf("read"); 837 else if (src_data != expc_data) 838 printf("write"); 839 printf(" error) at 0x%010lx:\n", (ulong)&src_mem[i]); 840 printf(" data = 0x%08x\n", dst_data); 841 printf(" expc = 0x%08x\n", expc_data); 842 843 mis_bit = dst_data ^ expc_data; 844 printf(" mismatch at bit"); 845 for (int j = 31; j >= 0; j--) { 846 if (((mis_bit >> j) & 1) == 1) 847 printf(" %d", j); 848 } 849 printf("\n"); 850 851 unlock_byte_mutex(&print_mutex); 852 err++; 853 dst_mem[i] = expc_data; 854 } 855 } 856 flush_dcache_all(); 857 858 if (err == 0) { 859 lock_byte_mutex(&print_mutex); 860 printf("COPY ERROR detected but cannot find mismatch data (maybe read error).\n"); 861 unlock_byte_mutex(&print_mutex); 862 } 863 864 return err; 865 } 866 867 static u32 block_copy_check(void *dst_addr, void *src_addr, 868 struct adler_sum *adler_sum, 869 struct pattern *src_pattern, 870 struct stressapptest_params *sat) 871 { 872 u32 err = 0; 873 874 if (adler_sum->a1 != src_pattern->adler_sum.a1 || 875 adler_sum->b1 != src_pattern->adler_sum.b1 || 876 adler_sum->a2 != src_pattern->adler_sum.a2 || 877 adler_sum->b2 != src_pattern->adler_sum.b2) { 878 err += block_copy_mis_search(dst_addr, src_addr, src_pattern, sat); 879 880 lock_byte_mutex(&print_mutex); 881 printf("(CPU%d, Pattern: %s, inv: %d, repeat: %d)\n\n", 882 get_cpu_id(), src_pattern->pat->name, src_pattern->inv, 883 src_pattern->repeat); 884 unlock_byte_mutex(&print_mutex); 885 } 886 887 return err; 888 } 889 890 static u32 block_copy(void *dst_addr, void *src_addr, 891 struct pattern *src_pattern, 892 struct stressapptest_params *sat) 893 { 894 u64 *dst_mem; 895 u64 *src_mem; 896 u64 data; 897 int i = 0; 898 #if defined(WARM_CPU) 899 double a, b, c, d; 900 #endif 901 902 struct adler_sum adler_sum = { 903 1, 0, 1, 0 904 }; 905 906 dst_mem = (u64 *)dst_addr; 907 src_mem = (u64 *)src_addr; 908 909 #if defined(WARM_CPU) 910 a = 2.0 * src_mem[0]; 911 b = 5.0 * src_mem[0]; 912 c = 7.0 * src_mem[0]; 913 d = 9.0 * src_mem[0]; 914 #endif 915 916 while (i < sat->block_size_byte / sizeof(u64)) { 917 data = src_mem[i]; 918 adler_sum.a1 += data & 0xffffffff; 919 adler_sum.b1 += adler_sum.a1; 920 adler_sum.a1 += data >> 32; 921 adler_sum.b1 += adler_sum.a1; 922 dst_mem[i] = data; 923 i++; 924 925 #if defined(WARM_CPU) 926 a = a * b; 927 b = b + c; 928 #endif 929 930 data = src_mem[i]; 931 adler_sum.a2 += data & 0xffffffff; 932 adler_sum.b2 += adler_sum.a2; 933 adler_sum.a2 += data >> 32; 934 adler_sum.b2 += adler_sum.a2; 935 dst_mem[i] = data; 936 i++; 937 938 #if defined(WARM_CPU) 939 c = c * d; 940 d = d + d; 941 #endif 942 } 943 944 flush_dcache_all(); 945 946 #if defined(WARM_CPU) 947 d = a + b + c + d; 948 if (d == 1.0) 949 /* Reference the result so that it can't be discarded by the compiler. */ 950 printf("This will probably never happen.\n"); 951 #endif 952 953 return block_copy_check(dst_addr, src_addr, &adler_sum, src_pattern, sat); 954 } 955 956 static u32 page_copy(struct stressapptest_params *sat) 957 { 958 u32 dst; 959 u32 src; 960 void *dst_block_addr; 961 void *src_block_addr; 962 u32 err = 0; 963 964 dst = page_rand_pick(page_list, 0, sat); /* pick a empty page */ 965 dst_block_addr = page_list[dst].base_addr; 966 src = page_rand_pick(page_list, 1, sat); /* pick a valid page */ 967 src_block_addr = page_list[src].base_addr; 968 flush_dcache_all(); 969 970 for (int i = 0; i < sat->block_num; i++) { 971 err += block_copy(dst_block_addr, src_block_addr, 972 page_list[src].pattern, sat); 973 dst_block_addr += sat->block_size_byte; 974 src_block_addr += sat->block_size_byte; 975 } 976 977 page_list[dst].pattern = page_list[src].pattern; 978 page_list[dst].valid = 1; 979 page_list[src].valid = 0; 980 flush_dcache_all(); 981 982 return err; 983 } 984 985 void secondary_main(void) 986 { 987 #if (CPU_NUM_MAX > 1) 988 u8 cpu_id; 989 ulong test = 0; 990 991 #ifndef CONFIG_ARM64 992 asm volatile("mov r9, %0" : : "r" (__gd)); /* set r9 to gd addr */ 993 #else 994 asm volatile("mov x18, %0" : : "r" (__gd)); /* set x18 to gd addr */ 995 #endif 996 dcache_enable(); 997 icache_enable(); 998 999 udelay(100); 1000 1001 flush_dcache_all(); 1002 cpu_id = get_cpu_id(); 1003 if (cpu_id != sat.cpu_num) { 1004 printf("Note: Cannot get correct CPU ID, CPU%d is identified as CPU%d.\n", 1005 sat.cpu_num, cpu_id); 1006 cpu_id = sat.cpu_num; 1007 } 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); 1025 else 1026 cpu_inv_err[cpu_id] += page_inv(&sat); 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); 1127 else 1128 cpu_inv_err[0] += page_inv(&sat); 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 1185 printf("StressAppTest in U-Boot, " __version__ "\n"); 1186 1187 if (argc > 1) { 1188 if (strict_strtoul(argv[1], 0, &test_time_sec) < 0) 1189 return CMD_RET_USAGE; 1190 if (test_time_sec < 1) 1191 test_time_sec = 20; 1192 } 1193 if (argc > 2) { 1194 if (strict_strtoul(argv[2], 0, &sat.total_test_size_mb) < 0) 1195 return CMD_RET_USAGE; 1196 if (sat.total_test_size_mb < 1) 1197 sat.total_test_size_mb = 32; 1198 } 1199 if (argc > 3) { 1200 if (strict_strtoul(argv[3], 0, &page_size_kb) < 0) 1201 return CMD_RET_USAGE; 1202 if (page_size_kb < 1) 1203 page_size_kb = 1024; 1204 } 1205 1206 sat.page_size_byte = page_size_kb << 10; 1207 1208 start_time_us = get_time_us(); 1209 test_time_us = (u64)test_time_sec * 1000000; 1210 1211 /* Change rand seed. If not do this, rand() would be same after boot.*/ 1212 srand((unsigned int)(start_time_us & 0xffffffff)); 1213 1214 return doing_stressapptest(); 1215 } 1216 1217 U_BOOT_CMD(stressapptest, 4, 1, do_stressapptest, 1218 "StressAppTest for Rockship\n", 1219 "\narg1: test time in second, null or 0 for 20s.\n" 1220 "arg2: test size in MB, null or 0 for 32MB.\n" 1221 "arg3: test page size in Byte, null or 0 for 1024kB(1MB).\n" 1222 "example:\n" 1223 " stressapptest: test for 20s, test size is 32MB, each page size is 1MB (32 pages).\n" 1224 " stressapptest 43200 64: test for 12h, test size is 64MB, each page size is 1MB (64 pages).\n" 1225 " stressapptest 43200 16 512: test for 12h, test size is 16MB, each page size is 512kB (32 pages).\n" 1226 ); 1227