hv/mod_timer: split tsc handling code from timer.

Generalize and split basic cpu cycle/tick routines from x86/timer:
- Instead of rdstc(), use cpu_ticks() in generic code.
- Instead of get_tsc_khz(), use cpu_tickrate() in generic code.
- Include "common/ticks.h" instead of "x86/timer.h" in generic code.
- CYCLES_PER_MS is renamed to TICKS_PER_MS.

The x86 specific API rdstc() and get_tsc_khz(), as well as TSC_PER_MS
are still available in arch/x86/tsc.h but only for x86 specific usage.

Tracked-On: #5920
Signed-off-by: Rong Liu <rong2.liu@intel.com>
Signed-off-by: Yi Liang <yi.liang@intel.com>
This commit is contained in:
Liang Yi
2021-04-08 17:36:12 +08:00
committed by wenlingz
parent c2df3f7940
commit 5a2b89b0a4
23 changed files with 301 additions and 209 deletions

View File

@@ -32,6 +32,7 @@
#include <ivshmem.h>
#include <asm/rtcm.h>
#include <reloc.h>
#include <ticks.h>
#define CPU_UP_TIMEOUT 100U /* millisecond */
#define CPU_DOWN_TIMEOUT 100U /* millisecond */
@@ -49,7 +50,7 @@ static void init_keylocker(void);
static void set_current_pcpu_id(uint16_t pcpu_id);
static void print_hv_banner(void);
static uint16_t get_pcpu_id_from_lapic_id(uint32_t lapic_id);
static uint64_t start_tsc __attribute__((__section__(".bss_noinit")));
static uint64_t start_tick __attribute__((__section__(".bss_noinit")));
/**
* @pre phys_cpu_num <= MAX_PCPU_NUM
@@ -124,7 +125,7 @@ void init_pcpu_pre(bool is_bsp)
if (is_bsp) {
pcpu_id = BSP_CPU_ID;
start_tsc = rdtsc();
start_tick = cpu_ticks();
/* Get CPU capabilities thru CPUID, including the physical address bit
* limit which is required for initializing paging.
@@ -220,7 +221,7 @@ void init_pcpu_post(uint16_t pcpu_id)
HV_FULL_VERSION,
HV_BUILD_TIME, HV_BUILD_VERSION, HV_BUILD_TYPE,
HV_DAILY_TAG, HV_BUILD_SCENARIO, HV_BUILD_BOARD,
HV_BUILD_USER, HV_CONFIG_TOOL, ticks_to_us(start_tsc));
HV_BUILD_USER, HV_CONFIG_TOOL, ticks_to_us(start_tick));
pr_acrnlog("API version %u.%u", HV_API_MAJOR_VERSION, HV_API_MINOR_VERSION);

View File

@@ -12,6 +12,7 @@
#include <logmsg.h>
#include <asm/vmx.h>
#include <asm/guest/hyperv.h>
#include <asm/tsc.h>
#define DBG_LEVEL_HYPERV 6U

View File

@@ -17,6 +17,7 @@
#include <asm/security.h>
#include <logmsg.h>
#include <asm/seed.h>
#include <asm/tsc.h>
#define TRUSTY_VERSION 1U
#define TRUSTY_VERSION_2 2U
@@ -282,7 +283,7 @@ static bool setup_trusty_info(struct acrn_vcpu *vcpu, uint32_t mem_size, uint64_
/* Prepare trusty startup param */
startup_param.size_of_this_struct = sizeof(struct trusty_startup_param);
startup_param.mem_size = mem_size;
startup_param.tsc_per_ms = CYCLES_PER_MS;
startup_param.tsc_per_ms = TSC_PER_MS;
startup_param.trusty_mem_base = TRUSTY_EPT_REBASE_GPA;
/* According to trusty boot protocol, it will use RDI as the

View File

@@ -13,6 +13,7 @@
#include <asm/cpufeatures.h>
#include <asm/vmx.h>
#include <asm/sgx.h>
#include <asm/tsc.h>
#include <logmsg.h>
static inline const struct vcpuid_entry *local_find_vcpuid_entry(const struct acrn_vcpu *vcpu,

View File

@@ -46,6 +46,7 @@
#include <trace.h>
#include <logmsg.h>
#include <asm/irq.h>
#include <ticks.h>
#include "vlapic_priv.h"
#define VLAPIC_VERBOS 0
@@ -281,7 +282,7 @@ static void vlapic_reset_timer(struct acrn_vlapic *vlapic)
static bool
set_expiration(struct acrn_vlapic *vlapic)
{
uint64_t now = rdtsc();
uint64_t now = cpu_ticks();
uint64_t delta;
struct vlapic_timer *vtimer;
struct hv_timer *timer;
@@ -332,7 +333,7 @@ static void vlapic_update_lvtt(struct acrn_vlapic *vlapic,
static uint32_t vlapic_get_ccr(const struct acrn_vlapic *vlapic)
{
uint64_t now = rdtsc();
uint64_t now = cpu_ticks();
uint32_t remain_count = 0U;
const struct vlapic_timer *vtimer;

View File

@@ -19,6 +19,7 @@
#include <asm/guest/nested.h>
#include <asm/cpufeatures.h>
#include <asm/rdt.h>
#include <asm/tsc.h>
#include <trace.h>
#include <logmsg.h>

View File

@@ -14,21 +14,11 @@
#include <softirq.h>
#include <trace.h>
#include <asm/irq.h>
#include <ticks.h>
#define MAX_TIMER_ACTIONS 32U
#define CAL_MS 10U
#define MIN_TIMER_PERIOD_US 500U
static uint32_t tsc_khz;
uint64_t rdtsc(void)
{
uint32_t lo, hi;
asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
return ((uint64_t)hi << 32U) | lo;
}
static void run_timer(const struct hv_timer *timer)
{
/* deadline = 0 means stop timer, we should skip */
@@ -211,129 +201,6 @@ void timer_init(void)
}
}
static uint64_t pit_calibrate_tsc(uint32_t cal_ms_arg)
{
#define PIT_TICK_RATE 1193182U
#define PIT_TARGET 0x3FFFU
#define PIT_MAX_COUNT 0xFFFFU
uint32_t cal_ms = cal_ms_arg;
uint32_t initial_pit;
uint16_t current_pit;
uint32_t max_cal_ms;
uint64_t current_tsc;
uint8_t initial_pit_high, initial_pit_low;
max_cal_ms = ((PIT_MAX_COUNT - PIT_TARGET) * 1000U) / PIT_TICK_RATE;
cal_ms = min(cal_ms, max_cal_ms);
/* 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
*/
initial_pit = (cal_ms * PIT_TICK_RATE) / 1000U;
initial_pit += PIT_TARGET;
initial_pit_high = (uint8_t)(initial_pit >> 8U);
initial_pit_low = (uint8_t)initial_pit;
/* Port 0x43 ==> Control word write; Data 0x30 ==> Select Counter 0,
* Read/Write least significant byte first, mode 0, 16 bits.
*/
pio_write8(0x30U, 0x43U);
pio_write8(initial_pit_low, 0x40U); /* Write LSB */
pio_write8(initial_pit_high, 0x40U); /* Write MSB */
current_tsc = rdtsc();
do {
/* Port 0x43 ==> Control word write; 0x00 ==> Select
* Counter 0, Counter Latch Command, Mode 0; 16 bits
*/
pio_write8(0x00U, 0x43U);
current_pit = (uint16_t)pio_read8(0x40U); /* Read LSB */
current_pit |= (uint16_t)pio_read8(0x40U) << 8U; /* Read MSB */
/* Let the counter count down to PIT_TARGET */
} while (current_pit > PIT_TARGET);
current_tsc = rdtsc() - current_tsc;
return (current_tsc / cal_ms) * 1000U;
}
/*
* Determine TSC frequency via CPUID 0x15 and 0x16.
*/
static uint64_t native_calibrate_tsc(void)
{
uint64_t tsc_hz = 0UL;
const struct cpuinfo_x86 *cpu_info = get_pcpu_info();
if (cpu_info->cpuid_level >= 0x15U) {
uint32_t eax_denominator, ebx_numerator, ecx_hz, reserved;
cpuid_subleaf(0x15U, 0x0U, &eax_denominator, &ebx_numerator,
&ecx_hz, &reserved);
if ((eax_denominator != 0U) && (ebx_numerator != 0U)) {
tsc_hz = ((uint64_t) ecx_hz *
ebx_numerator) / eax_denominator;
}
}
if ((tsc_hz == 0UL) && (cpu_info->cpuid_level >= 0x16U)) {
uint32_t eax_base_mhz, ebx_max_mhz, ecx_bus_mhz, edx;
cpuid_subleaf(0x16U, 0x0U, &eax_base_mhz, &ebx_max_mhz, &ecx_bus_mhz, &edx);
tsc_hz = (uint64_t) eax_base_mhz * 1000000U;
}
return tsc_hz;
}
void calibrate_tsc(void)
{
uint64_t tsc_hz;
tsc_hz = native_calibrate_tsc();
if (tsc_hz == 0U) {
tsc_hz = pit_calibrate_tsc(CAL_MS);
}
tsc_khz = (uint32_t)(tsc_hz / 1000UL);
printf("%s, tsc_khz=%lu\n", __func__, tsc_khz);
}
uint32_t get_tsc_khz(void)
{
return tsc_khz;
}
/**
* Frequency of TSC in KHz (where 1KHz = 1000Hz). Only valid after
* calibrate_tsc() returns.
*/
uint64_t us_to_ticks(uint32_t us)
{
return (((uint64_t)us * (uint64_t)tsc_khz) / 1000UL);
}
uint64_t ticks_to_us(uint64_t ticks)
{
uint64_t us = 0UL;
if (tsc_khz != 0U) {
us = (ticks * 1000UL) / (uint64_t)tsc_khz;
}
return us;
}
uint64_t ticks_to_ms(uint64_t ticks)
{
return ticks / (uint64_t)tsc_khz;
}
void udelay(uint32_t us)
{
uint64_t dest_tsc, delta_tsc;

124
hypervisor/arch/x86/tsc.c Normal file
View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2021 Intel Corporation.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <types.h>
#include <util.h>
#include <asm/cpuid.h>
#include <asm/cpu_caps.h>
#include <asm/io.h>
#include <asm/tsc.h>
#define CAL_MS 10U
static uint32_t tsc_khz;
static uint64_t pit_calibrate_tsc(uint32_t cal_ms_arg)
{
#define PIT_TICK_RATE 1193182U
#define PIT_TARGET 0x3FFFU
#define PIT_MAX_COUNT 0xFFFFU
uint32_t cal_ms = cal_ms_arg;
uint32_t initial_pit;
uint16_t current_pit;
uint32_t max_cal_ms;
uint64_t current_tsc;
uint8_t initial_pit_high, initial_pit_low;
max_cal_ms = ((PIT_MAX_COUNT - PIT_TARGET) * 1000U) / PIT_TICK_RATE;
cal_ms = min(cal_ms, max_cal_ms);
/* 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
*/
initial_pit = (cal_ms * PIT_TICK_RATE) / 1000U;
initial_pit += PIT_TARGET;
initial_pit_high = (uint8_t)(initial_pit >> 8U);
initial_pit_low = (uint8_t)initial_pit;
/* Port 0x43 ==> Control word write; Data 0x30 ==> Select Counter 0,
* Read/Write least significant byte first, mode 0, 16 bits.
*/
pio_write8(0x30U, 0x43U);
pio_write8(initial_pit_low, 0x40U); /* Write LSB */
pio_write8(initial_pit_high, 0x40U); /* Write MSB */
current_tsc = rdtsc();
do {
/* Port 0x43 ==> Control word write; 0x00 ==> Select
* Counter 0, Counter Latch Command, Mode 0; 16 bits
*/
pio_write8(0x00U, 0x43U);
current_pit = (uint16_t)pio_read8(0x40U); /* Read LSB */
current_pit |= (uint16_t)pio_read8(0x40U) << 8U; /* Read MSB */
/* Let the counter count down to PIT_TARGET */
} while (current_pit > PIT_TARGET);
current_tsc = rdtsc() - current_tsc;
return (current_tsc / cal_ms) * 1000U;
}
/*
* Determine TSC frequency via CPUID 0x15 and 0x16.
*/
static uint64_t native_calibrate_tsc(void)
{
uint64_t tsc_hz = 0UL;
const struct cpuinfo_x86 *cpu_info = get_pcpu_info();
if (cpu_info->cpuid_level >= 0x15U) {
uint32_t eax_denominator, ebx_numerator, ecx_hz, reserved;
cpuid_subleaf(0x15U, 0x0U, &eax_denominator, &ebx_numerator,
&ecx_hz, &reserved);
if ((eax_denominator != 0U) && (ebx_numerator != 0U)) {
tsc_hz = ((uint64_t) ecx_hz *
ebx_numerator) / eax_denominator;
}
}
if ((tsc_hz == 0UL) && (cpu_info->cpuid_level >= 0x16U)) {
uint32_t eax_base_mhz, ebx_max_mhz, ecx_bus_mhz, edx;
cpuid_subleaf(0x16U, 0x0U, &eax_base_mhz, &ebx_max_mhz, &ecx_bus_mhz, &edx);
tsc_hz = (uint64_t) eax_base_mhz * 1000000U;
}
return tsc_hz;
}
void calibrate_tsc(void)
{
uint64_t tsc_hz;
tsc_hz = native_calibrate_tsc();
if (tsc_hz == 0U) {
tsc_hz = pit_calibrate_tsc(CAL_MS);
}
tsc_khz = (uint32_t)(tsc_hz / 1000UL);
}
uint32_t get_tsc_khz(void)
{
return tsc_khz;
}
/* external API */
uint64_t cpu_ticks(void)
{
return rdtsc();
}
uint32_t cpu_tickrate(void)
{
return tsc_khz;
}

View File

@@ -17,7 +17,7 @@
#include <asm/mmu.h>
#include <asm/lapic.h>
#include <asm/vtd.h>
#include <asm/timer.h>
#include <ticks.h>
#include <logmsg.h>
#include <asm/board.h>
#include <asm/vm_config.h>
@@ -248,11 +248,11 @@ static inline void dmar_wait_completion(const struct dmar_drhd_rt *dmar_unit, ui
uint32_t mask, uint32_t pre_condition, uint32_t *status)
{
/* variable start isn't used when built as release version */
__unused uint64_t start = rdtsc();
__unused uint64_t start = cpu_ticks();
do {
*status = iommu_read32(dmar_unit, offset);
ASSERT(((rdtsc() - start) < CYCLES_PER_MS),
ASSERT(((cpu_ticks() - start) < TICKS_PER_MS),
"DMAR OP Timeout!");
asm_pause();
} while( (*status & mask) == pre_condition);
@@ -564,9 +564,9 @@ static void dmar_issue_qi_request(struct dmar_drhd_rt *dmar_unit, struct dmar_en
qi_status = DMAR_INV_STATUS_INCOMPLETE;
iommu_write32(dmar_unit, DMAR_IQT_REG, dmar_unit->qi_tail);
start = rdtsc();
start = cpu_ticks();
while (qi_status != DMAR_INV_STATUS_COMPLETED) {
if ((rdtsc() - start) > CYCLES_PER_MS) {
if ((cpu_ticks() - start) > TICKS_PER_MS) {
pr_err("DMAR OP Timeout! @ %s", __func__);
break;
}