mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
x86: Add TSC stop support for Deep C state
TSC may stop at deep C state (C3/C4...) entry/exit. this patch add the logic that save and restore TSC during deep C state entry/exit, by using platform timer (PIT/HPET) Signed-off-by: Yu Ke <ke.yu@intel.com> Signed-off-by: Tian Kevin <kevin.tian@intel.com> Signed-off-by: Wei Gang<gang.wei@intel.com>
This commit is contained in:
1 parent
d751218ce1
commit
fe30f626cc
3 files changed
+45
-3
No files matched your search
@@ -442,8 +442,8 @@ static void acpi_processor_idle(void)
|
||||
* stopped by H/W. Without carefully handling of TSC/APIC stop issues,
|
||||
* deep C state can't work correctly.
|
||||
*/
|
||||
/* placeholder for preparing TSC stop */
|
||||
|
||||
/* preparing TSC stop */
|
||||
cstate_save_tsc();
|
||||
/* placeholder for preparing APIC stop */
|
||||
|
||||
/* Invoke C3 */
|
||||
@@ -451,7 +451,8 @@ static void acpi_processor_idle(void)
|
||||
|
||||
/* placeholder for recovering APIC */
|
||||
|
||||
/* placeholder for recovering TSC */
|
||||
/* recovering TSC */
|
||||
cstate_restore_tsc();
|
||||
|
||||
/* Get end time (ticks) */
|
||||
t2 = inl(pmtmr_ioport);
|
||||
|
||||
@@ -51,9 +51,11 @@ struct time_scale {
|
||||
|
||||
struct cpu_time {
|
||||
u64 local_tsc_stamp;
|
||||
u64 cstate_tsc_stamp;
|
||||
s_time_t stime_local_stamp;
|
||||
s_time_t stime_master_stamp;
|
||||
struct time_scale tsc_scale;
|
||||
u32 cstate_plt_count_stamp;
|
||||
struct timer calibration_timer;
|
||||
};
|
||||
|
||||
@@ -66,6 +68,8 @@ struct platform_timesource {
|
||||
|
||||
static DEFINE_PER_CPU(struct cpu_time, cpu_time);
|
||||
|
||||
static u8 tsc_invariant=0; /* TSC is invariant upon C state entry */
|
||||
|
||||
/*
|
||||
* We simulate a 32-bit platform timer from the 16-bit PIT ch2 counter.
|
||||
* Otherwise overflow happens too quickly (~50ms) for us to guarantee that
|
||||
@@ -594,6 +598,36 @@ static void init_platform_timer(void)
|
||||
freq_string(pts->frequency), pts->name);
|
||||
}
|
||||
|
||||
void cstate_save_tsc(void)
|
||||
{
|
||||
struct cpu_time *t = &this_cpu(cpu_time);
|
||||
|
||||
if (!tsc_invariant){
|
||||
t->cstate_plt_count_stamp = plt_src.read_counter();
|
||||
rdtscll(t->cstate_tsc_stamp);
|
||||
}
|
||||
}
|
||||
|
||||
void cstate_restore_tsc(void)
|
||||
{
|
||||
struct cpu_time *t;
|
||||
u32 plt_count_delta;
|
||||
u64 tsc_delta;
|
||||
|
||||
if (!tsc_invariant){
|
||||
t = &this_cpu(cpu_time);
|
||||
|
||||
/* if platform counter overflow happens, interrupt will bring CPU from
|
||||
C state to working state, so the platform counter won't wrap the
|
||||
cstate_plt_count_stamp, and the 32 bit unsigned platform counter
|
||||
is enough for delta calculation
|
||||
*/
|
||||
plt_count_delta =
|
||||
(plt_src.read_counter() - t->cstate_plt_count_stamp) & plt_mask;
|
||||
tsc_delta = scale_delta(plt_count_delta, &plt_scale)*cpu_khz/1000000UL;
|
||||
wrmsrl(MSR_IA32_TSC, t->cstate_tsc_stamp + tsc_delta);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* CMOS Timer functions
|
||||
@@ -973,6 +1007,11 @@ int __init init_xen_time(void)
|
||||
stime_platform_stamp = 0;
|
||||
init_platform_timer();
|
||||
|
||||
/* check if TSC is invariant during deep C state
|
||||
this is a new feature introduced by Nehalem*/
|
||||
if ( cpuid_edx(0x80000007) & (1U<<8) )
|
||||
tsc_invariant = 1;
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <asm/time.h>
|
||||
|
||||
extern int init_xen_time(void);
|
||||
extern void cstate_save_tsc(void);
|
||||
extern void cstate_restore_tsc(void);
|
||||
|
||||
extern unsigned long cpu_khz;
|
||||
|
||||
|
||||