| 496 | } |
| 497 | |
| 498 | static int |
| 499 | test_tsc(int adj_max_count) |
| 500 | { |
| 501 | uint64_t *data, *tsc; |
| 502 | u_int i, size, adj; |
| 503 | |
| 504 | if ((!smp_tsc && !tsc_is_invariant)) |
| 505 | return (-100); |
| 506 | /* |
| 507 | * Misbehavior of TSC under VirtualBox has been observed. In |
| 508 | * particular, threads doing small (~1 second) sleeps may miss their |
| 509 | * wakeup and hang around in sleep state, causing hangs on shutdown. |
| 510 | */ |
| 511 | if (vm_guest == VM_GUEST_VBOX) |
| 512 | return (0); |
| 513 | |
| 514 | size = (mp_maxid + 1) * 3; |
| 515 | data = malloc(sizeof(*data) * size * N, M_TEMP, M_WAITOK); |
| 516 | adj = 0; |
| 517 | retry: |
| 518 | for (i = 0, tsc = data; i < N; i++, tsc += size) |
| 519 | smp_rendezvous(tsc_read_0, tsc_read_1, tsc_read_2, tsc); |
| 520 | smp_tsc = 1; /* XXX */ |
| 521 | smp_rendezvous(smp_no_rendezvous_barrier, comp_smp_tsc, |
| 522 | smp_no_rendezvous_barrier, data); |
| 523 | if (!smp_tsc && adj < adj_max_count) { |
| 524 | adj++; |
| 525 | smp_rendezvous(smp_no_rendezvous_barrier, adj_smp_tsc, |
| 526 | smp_no_rendezvous_barrier, data); |
| 527 | goto retry; |
| 528 | } |
| 529 | free(data, M_TEMP); |
| 530 | if (bootverbose) |
| 531 | printf("SMP: %sed TSC synchronization test%s\n", |
| 532 | smp_tsc ? "pass" : "fail", |
| 533 | adj > 0 ? " after adjustment" : ""); |
| 534 | if (smp_tsc && tsc_is_invariant) { |
| 535 | switch (cpu_vendor_id) { |
| 536 | case CPU_VENDOR_AMD: |
| 537 | case CPU_VENDOR_HYGON: |
| 538 | /* |
| 539 | * Processor Programming Reference (PPR) for AMD |
| 540 | * Family 17h states that the TSC uses a common |
| 541 | * reference for all sockets, cores and threads. |
| 542 | */ |
| 543 | if (CPUID_TO_FAMILY(cpu_id) >= 0x17) |
| 544 | return (1000); |
| 545 | /* |
| 546 | * Starting with Family 15h processors, TSC clock |
| 547 | * source is in the north bridge. Check whether |
| 548 | * we have a single-socket/multi-core platform. |
| 549 | * XXX Need more work for complex cases. |
| 550 | */ |
| 551 | if (CPUID_TO_FAMILY(cpu_id) < 0x15 || |
| 552 | (amd_feature2 & AMDID2_CMP) == 0 || |
| 553 | smp_cpus > (cpu_procinfo2 & AMDID_CMP_CORES) + 1) |
| 554 | break; |
| 555 | return (1000); |
no test coverage detected