mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2024-11-27 01:50:20 -06:00
fa4e903509
On some modern ULV cores (eg: Gracemont), the 2 following I/O reads to check APIC Timer working status are fused in the frontend, leading to the same value being reported twice and the code falling back to the (unusually disabled on these platforms) PIT timer. Whether this behavior is intentional or not is unknown. As usleep/sleep is not available at this point, a dirty delay is added between the two reads.
97 lines
2.5 KiB
C
97 lines
2.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
|
// Copyright (C) 2004-2022 Sam Demeulemeester.
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include "acpi.h"
|
|
#include "cpuid.h"
|
|
#include "cpuinfo.h"
|
|
#include "io.h"
|
|
#include "tsc.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Constants
|
|
//------------------------------------------------------------------------------
|
|
|
|
#define PIT_TICKS_50mS 59659 // PIT clock is 1.193182MHz
|
|
#define APIC_TICKS_50mS 178977 // APIC clock is 3.579545MHz
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Private Functions
|
|
//------------------------------------------------------------------------------
|
|
|
|
static void correct_tsc(void)
|
|
{
|
|
uint32_t start_time, end_time, run_time, counter;
|
|
int loops = 0;
|
|
|
|
if (cpuid_info.flags.rdtsc == 0) {
|
|
return;
|
|
}
|
|
|
|
// If available, use APIC Timer to find TSC correction factor
|
|
if (acpi_config.pm_is_io && acpi_config.pm_addr != 0) {
|
|
rdtscl(start_time);
|
|
|
|
counter = inl(acpi_config.pm_addr);
|
|
|
|
// Generate a dirty delay
|
|
for(volatile uint8_t i=0; i<100u; i++);
|
|
|
|
// Make sure counter is incrementing
|
|
if (inl(acpi_config.pm_addr) > counter) {
|
|
|
|
while (1) {
|
|
if (inl(acpi_config.pm_addr) > (counter + APIC_TICKS_50mS) || loops > 1000000) {
|
|
break;
|
|
}
|
|
loops++;
|
|
}
|
|
|
|
rdtscl(end_time);
|
|
|
|
run_time = end_time - start_time;
|
|
|
|
// Make sure we have a credible result
|
|
if (loops >= 10 && run_time >= 50000) {
|
|
clks_per_msec = run_time / 50;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use PIT Timer to find TSC correction factor if APIC not available
|
|
outb((inb(0x61) & ~0x02) | 0x01, 0x61);
|
|
outb(0xb0, 0x43);
|
|
outb(PIT_TICKS_50mS & 0xff, 0x42);
|
|
outb(PIT_TICKS_50mS >> 8, 0x42);
|
|
|
|
rdtscl(start_time);
|
|
|
|
loops = 0;
|
|
do {
|
|
loops++;
|
|
} while ((inb(0x61) & 0x20) == 0);
|
|
|
|
rdtscl(end_time);
|
|
|
|
run_time = end_time - start_time;
|
|
|
|
// Make sure we have a credible result
|
|
if (loops >= 4 && run_time >= 50000) {
|
|
clks_per_msec = run_time / 50;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Functions
|
|
//------------------------------------------------------------------------------
|
|
|
|
void timers_init(void)
|
|
{
|
|
correct_tsc();
|
|
}
|