mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 12:12:16 +00:00
hv: timer: add calibrate tsc hz by cpuid 0x15
Get tsc hz by cpuid 0x15 if we supported, otherwise calibrate tsc by pit timer. Signed-off-by: Li, Fei1 <fei1.li@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
parent
5e011a89b7
commit
1a9fb03ef0
@ -41,8 +41,6 @@
|
|||||||
extern uint32_t efi_physical_available_ap_bitmap;
|
extern uint32_t efi_physical_available_ap_bitmap;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint64_t tsc_clock_freq = 1000000000;
|
|
||||||
|
|
||||||
spinlock_t cpu_secondary_spinlock = {
|
spinlock_t cpu_secondary_spinlock = {
|
||||||
.head = 0,
|
.head = 0,
|
||||||
.tail = 0
|
.tail = 0
|
||||||
@ -494,8 +492,8 @@ void bsp_boot_init(void)
|
|||||||
/* Make sure rdtsc is enabled */
|
/* Make sure rdtsc is enabled */
|
||||||
check_tsc();
|
check_tsc();
|
||||||
|
|
||||||
/* Calculate TSC Frequency */
|
/* Calibrate TSC Frequency */
|
||||||
tsc_clock_freq = tsc_cycles_in_period(1000) / 1000 * 1000000;
|
calibrate_tsc();
|
||||||
|
|
||||||
/* Enable logging */
|
/* Enable logging */
|
||||||
init_logmsg(LOG_BUF_SIZE,
|
init_logmsg(LOG_BUF_SIZE,
|
||||||
|
@ -170,7 +170,7 @@ static void init_vcpuid_entry(__unused struct vm *vm,
|
|||||||
* ECX, EDX: RESERVED (reserved fields are set to zero).
|
* ECX, EDX: RESERVED (reserved fields are set to zero).
|
||||||
*/
|
*/
|
||||||
case 0x40000010:
|
case 0x40000010:
|
||||||
entry->eax = (uint32_t)(tsc_clock_freq / 1000);
|
entry->eax = (uint32_t)(tsc_hz / 1000);
|
||||||
entry->ebx = (128 * 1024 * 1024) / 1000;
|
entry->ebx = (128 * 1024 * 1024) / 1000;
|
||||||
entry->ecx = 0;
|
entry->ecx = 0;
|
||||||
entry->edx = 0;
|
entry->edx = 0;
|
||||||
|
@ -34,7 +34,10 @@
|
|||||||
#include <hv_arch.h>
|
#include <hv_arch.h>
|
||||||
#include <hv_debug.h>
|
#include <hv_debug.h>
|
||||||
|
|
||||||
#define MAX_TIMER_ACTIONS 32
|
#define MAX_TIMER_ACTIONS 32
|
||||||
|
#define CAL_MS 10
|
||||||
|
|
||||||
|
uint64_t tsc_hz = 1000000000;
|
||||||
|
|
||||||
struct timer {
|
struct timer {
|
||||||
timer_handle_t func; /* callback if time reached */
|
timer_handle_t func; /* callback if time reached */
|
||||||
@ -421,21 +424,24 @@ void check_tsc(void)
|
|||||||
CPU_CR_WRITE(cr4, (temp64 & ~CR4_TSD));
|
CPU_CR_WRITE(cr4, (temp64 & ~CR4_TSD));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t tsc_cycles_in_period(uint16_t timer_period_in_us)
|
static uint64_t pit_calibrate_tsc(uint16_t cal_ms)
|
||||||
{
|
{
|
||||||
|
#define PIT_TICK_RATE 1193182UL
|
||||||
|
#define PIT_TARGET 0x3FFF
|
||||||
|
#define PIT_MAX_COUNT 0xFFFF
|
||||||
|
|
||||||
uint16_t initial_pit;
|
uint16_t initial_pit;
|
||||||
uint16_t current_pit;
|
uint16_t current_pit;
|
||||||
uint32_t current_tsc;
|
uint16_t max_cal_ms;
|
||||||
#define PIT_TARGET 0x3FFF
|
uint64_t current_tsc;
|
||||||
|
|
||||||
if (timer_period_in_us < 1000)
|
max_cal_ms = (PIT_MAX_COUNT - PIT_TARGET) * 1000 / PIT_TICK_RATE;
|
||||||
pr_warn("Bad timer_period_in_us: %d\n",
|
cal_ms = min(cal_ms, max_cal_ms);
|
||||||
timer_period_in_us);
|
|
||||||
|
|
||||||
/* Assume the 8254 delivers 18.2 ticks per second when 16 bits fully
|
/* Assume the 8254 delivers 18.2 ticks per second when 16 bits fully
|
||||||
* wrap. This is about 1.193MHz or a clock period of 0.8384uSec
|
* wrap. This is about 1.193MHz or a clock period of 0.8384uSec
|
||||||
*/
|
*/
|
||||||
initial_pit = (uint16_t)(timer_period_in_us*1193000UL/1000000);
|
initial_pit = (uint16_t)(cal_ms * PIT_TICK_RATE / 1000);
|
||||||
initial_pit += PIT_TARGET;
|
initial_pit += PIT_TARGET;
|
||||||
|
|
||||||
/* Port 0x43 ==> Control word write; Data 0x30 ==> Select Counter 0,
|
/* Port 0x43 ==> Control word write; Data 0x30 ==> Select Counter 0,
|
||||||
@ -444,7 +450,7 @@ uint64_t tsc_cycles_in_period(uint16_t timer_period_in_us)
|
|||||||
|
|
||||||
io_write_byte(0x30, 0x43);
|
io_write_byte(0x30, 0x43);
|
||||||
io_write_byte(initial_pit & 0x00ff, 0x40); /* Write LSB */
|
io_write_byte(initial_pit & 0x00ff, 0x40); /* Write LSB */
|
||||||
io_write_byte(initial_pit >> 8, 0x40); /* Write MSB */
|
io_write_byte(initial_pit >> 8, 0x40); /* Write MSB */
|
||||||
|
|
||||||
current_tsc = rdtsc();
|
current_tsc = rdtsc();
|
||||||
|
|
||||||
@ -461,6 +467,32 @@ uint64_t tsc_cycles_in_period(uint16_t timer_period_in_us)
|
|||||||
|
|
||||||
current_tsc = rdtsc() - current_tsc;
|
current_tsc = rdtsc() - current_tsc;
|
||||||
|
|
||||||
return (uint64_t) current_tsc;
|
return current_tsc / cal_ms * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine TSC frequency via CPUID 0x15
|
||||||
|
*/
|
||||||
|
static uint64_t native_calibrate_tsc(void)
|
||||||
|
{
|
||||||
|
if (boot_cpu_data.cpuid_level >= 0x15) {
|
||||||
|
uint32_t eax_denominator, ebx_numerator, ecx_hz, reserved;
|
||||||
|
|
||||||
|
cpuid(0x15, &eax_denominator, &ebx_numerator,
|
||||||
|
&ecx_hz, &reserved);
|
||||||
|
|
||||||
|
if (eax_denominator != 0 && ebx_numerator != 0)
|
||||||
|
return (uint64_t) ecx_hz *
|
||||||
|
ebx_numerator / eax_denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calibrate_tsc(void)
|
||||||
|
{
|
||||||
|
tsc_hz = native_calibrate_tsc();
|
||||||
|
if (!tsc_hz)
|
||||||
|
tsc_hz = pit_calibrate_tsc(CAL_MS);
|
||||||
|
printf("%s, tsc_hz=%lu\n", __func__, tsc_hz);
|
||||||
|
}
|
||||||
|
@ -258,8 +258,6 @@ extern struct cpuinfo_x86 boot_cpu_data;
|
|||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
void cpu_dead(uint32_t logical_id);
|
void cpu_dead(uint32_t logical_id);
|
||||||
uint64_t cpu_cycles_per_second(void);
|
|
||||||
uint64_t tsc_cycles_in_period(uint16_t timer_period_in_us);
|
|
||||||
void cpu_secondary_reset(void);
|
void cpu_secondary_reset(void);
|
||||||
int hv_main(int cpu_id);
|
int hv_main(int cpu_id);
|
||||||
bool is_vapic_supported(void);
|
bool is_vapic_supported(void);
|
||||||
|
@ -42,5 +42,6 @@ int timer_softirq(int pcpu_id);
|
|||||||
void timer_init(void);
|
void timer_init(void);
|
||||||
void timer_cleanup(void);
|
void timer_cleanup(void);
|
||||||
void check_tsc(void);
|
void check_tsc(void);
|
||||||
|
void calibrate_tsc(void);
|
||||||
|
|
||||||
#endif /* TIMER_H */
|
#endif /* TIMER_H */
|
||||||
|
@ -65,12 +65,12 @@ void *memcpy_s(void *d, size_t dmax, const void *s, size_t slen);
|
|||||||
int udiv64(uint64_t dividend, uint64_t divisor, struct udiv_result *res);
|
int udiv64(uint64_t dividend, uint64_t divisor, struct udiv_result *res);
|
||||||
int udiv32(uint32_t dividend, uint32_t divisor, struct udiv_result *res);
|
int udiv32(uint32_t dividend, uint32_t divisor, struct udiv_result *res);
|
||||||
|
|
||||||
extern uint64_t tsc_clock_freq;
|
extern uint64_t tsc_hz;
|
||||||
#define US_TO_TICKS(x) ((x)*tsc_clock_freq/1000000UL)
|
#define US_TO_TICKS(x) ((x) * tsc_hz / 1000000UL)
|
||||||
#define CYCLES_PER_MS US_TO_TICKS(1000UL)
|
#define CYCLES_PER_MS US_TO_TICKS(1000UL)
|
||||||
|
|
||||||
#define TICKS_TO_US(x) ((((x) * (1000000UL >> 8)) / tsc_clock_freq) << 8)
|
#define TICKS_TO_US(x) ((((x) * (1000000UL >> 8)) / tsc_hz) << 8)
|
||||||
#define TICKS_TO_MS(x) (((x) * 1000UL) / tsc_clock_freq)
|
#define TICKS_TO_MS(x) (((x) * 1000UL) / tsc_hz)
|
||||||
|
|
||||||
static inline uint64_t rdtsc(void)
|
static inline uint64_t rdtsc(void)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user