mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
X86: Prefer TSC-deadline timer in Xen
The new TSC Deadline Timer offers system software a low overhead per-logical-thread deadline timer in TSC units. The timer is implemented via a new architectural 64-bit register, IA32_TSC_DEADLINE_MSR. Reads and writes of this MSR occur in program order, but are non-serializing. The support for this feature is indicated by CPUID.01H:ECX.TSC_Deadline[bit 24] =3D 1 as documented in the Intel Architecture Software Developer's Manual. The LOCAL APIC on new processors has a mode where its underlying hardware timer can now be accessed via the non-serializing IA32_TSC_DEADLINE_MSR in TSC tick units. If this mode is present, prefer it over the traditional LAPIC timer mode. KERN_DEBUG dmesg will print "TSC deadline timer enabled" when TDT is used. Bootparam "tdt=off" is available to revert to LAPIC timer mode. This patch is based on original work by Len Brown for Linux kernel. cc: Len Brown <len.brown@intel.com> Signed-off-by: Wei Gang <gang.wei@intel.com> Signed-off-by: Keir Fraser <keir@xen.org>
This commit is contained in:
1 parent
9dbd100737
commit
fd1291a826
6 files changed
+46
-9
No files matched your search
@@ -38,6 +38,15 @@
|
|||||||
#include <mach_apic.h>
|
#include <mach_apic.h>
|
||||||
#include <io_ports.h>
|
#include <io_ports.h>
|
||||||
|
|
||||||
|
#define APIC_TIMER_MODE_ONESHOT (0 << 17)
|
||||||
|
#define APIC_TIMER_MODE_PERIODIC (1 << 17)
|
||||||
|
#define APIC_TIMER_MODE_TSC_DEADLINE (2 << 17)
|
||||||
|
#define APIC_TIMER_MODE_MASK (3 << 17)
|
||||||
|
|
||||||
|
static int tdt_enabled __read_mostly;
|
||||||
|
static int tdt_enable __initdata = 1;
|
||||||
|
boolean_param("tdt", tdt_enable);
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
int active;
|
int active;
|
||||||
/* r/w apic fields */
|
/* r/w apic fields */
|
||||||
@@ -1198,6 +1207,13 @@ static void __setup_APIC_LVTT(unsigned int clocks)
|
|||||||
lvtt_value = /*APIC_LVT_TIMER_PERIODIC |*/ LOCAL_TIMER_VECTOR;
|
lvtt_value = /*APIC_LVT_TIMER_PERIODIC |*/ LOCAL_TIMER_VECTOR;
|
||||||
if (!APIC_INTEGRATED(ver))
|
if (!APIC_INTEGRATED(ver))
|
||||||
lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV);
|
lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV);
|
||||||
|
|
||||||
|
if ( tdt_enabled )
|
||||||
|
{
|
||||||
|
lvtt_value &= (~APIC_TIMER_MODE_MASK);
|
||||||
|
lvtt_value |= APIC_TIMER_MODE_TSC_DEADLINE;
|
||||||
|
}
|
||||||
|
|
||||||
apic_write_around(APIC_LVTT, lvtt_value);
|
apic_write_around(APIC_LVTT, lvtt_value);
|
||||||
|
|
||||||
tmp_value = apic_read(APIC_TDCR);
|
tmp_value = apic_read(APIC_TDCR);
|
||||||
@@ -1311,6 +1327,12 @@ void __init setup_boot_APIC_clock(void)
|
|||||||
|
|
||||||
calibrate_APIC_clock();
|
calibrate_APIC_clock();
|
||||||
|
|
||||||
|
if ( tdt_enable && boot_cpu_has(X86_FEATURE_TSC_DEADLINE) )
|
||||||
|
{
|
||||||
|
printk(KERN_DEBUG "TSC deadline timer enabled\n");
|
||||||
|
tdt_enabled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
setup_APIC_timer();
|
setup_APIC_timer();
|
||||||
|
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
@@ -1360,6 +1382,12 @@ int reprogram_timer(s_time_t timeout)
|
|||||||
if ( !cpu_has_apic )
|
if ( !cpu_has_apic )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if ( tdt_enabled )
|
||||||
|
{
|
||||||
|
wrmsrl(MSR_IA32_TSC_DEADLINE, timeout ? stime2tsc(timeout) : 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if ( timeout && ((expire = timeout - NOW()) > 0) )
|
if ( timeout && ((expire = timeout - NOW()) > 0) )
|
||||||
apic_tmict = min_t(u64, (bus_scale * expire) >> 18, UINT_MAX);
|
apic_tmict = min_t(u64, (bus_scale * expire) >> 18, UINT_MAX);
|
||||||
|
|
||||||
|
|||||||
+10
-8
@@ -662,26 +662,28 @@ static void __init init_platform_timer(void)
|
|||||||
freq_string(pts->frequency), pts->name);
|
freq_string(pts->frequency), pts->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cstate_restore_tsc(void)
|
u64 stime2tsc(s_time_t stime)
|
||||||
{
|
{
|
||||||
struct cpu_time *t;
|
struct cpu_time *t;
|
||||||
struct time_scale sys_to_tsc;
|
struct time_scale sys_to_tsc;
|
||||||
s_time_t stime_delta;
|
s_time_t stime_delta;
|
||||||
u64 new_tsc;
|
|
||||||
|
|
||||||
if ( boot_cpu_has(X86_FEATURE_NONSTOP_TSC) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
t = &this_cpu(cpu_time);
|
t = &this_cpu(cpu_time);
|
||||||
sys_to_tsc = scale_reciprocal(t->tsc_scale);
|
sys_to_tsc = scale_reciprocal(t->tsc_scale);
|
||||||
|
|
||||||
stime_delta = read_platform_stime() - t->stime_master_stamp;
|
stime_delta = stime - t->stime_local_stamp;
|
||||||
if ( stime_delta < 0 )
|
if ( stime_delta < 0 )
|
||||||
stime_delta = 0;
|
stime_delta = 0;
|
||||||
|
|
||||||
new_tsc = t->local_tsc_stamp + scale_delta(stime_delta, &sys_to_tsc);
|
return t->local_tsc_stamp + scale_delta(stime_delta, &sys_to_tsc);
|
||||||
|
}
|
||||||
|
|
||||||
write_tsc(new_tsc);
|
void cstate_restore_tsc(void)
|
||||||
|
{
|
||||||
|
if ( boot_cpu_has(X86_FEATURE_NONSTOP_TSC) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
write_tsc(stime2tsc(read_platform_stime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
|||||||
@@ -99,6 +99,7 @@
|
|||||||
#define X86_FEATURE_SSE4_2 (4*32+20) /* Streaming SIMD Extensions 4.2 */
|
#define X86_FEATURE_SSE4_2 (4*32+20) /* Streaming SIMD Extensions 4.2 */
|
||||||
#define X86_FEATURE_X2APIC (4*32+21) /* Extended xAPIC */
|
#define X86_FEATURE_X2APIC (4*32+21) /* Extended xAPIC */
|
||||||
#define X86_FEATURE_POPCNT (4*32+23) /* POPCNT instruction */
|
#define X86_FEATURE_POPCNT (4*32+23) /* POPCNT instruction */
|
||||||
|
#define X86_FEATURE_TSC_DEADLINE (4*32+24) /* "tdt" TSC Deadline Timer */
|
||||||
#define X86_FEATURE_XSAVE (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
|
#define X86_FEATURE_XSAVE (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
|
||||||
#define X86_FEATURE_OSXSAVE (4*32+27) /* OSXSAVE */
|
#define X86_FEATURE_OSXSAVE (4*32+27) /* OSXSAVE */
|
||||||
#define X86_FEATURE_HYPERVISOR (4*32+31) /* Running under some hypervisor */
|
#define X86_FEATURE_HYPERVISOR (4*32+31) /* Running under some hypervisor */
|
||||||
|
|||||||
@@ -328,6 +328,8 @@
|
|||||||
#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1<<22)
|
#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1<<22)
|
||||||
#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1<<23)
|
#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1<<23)
|
||||||
|
|
||||||
|
#define MSR_IA32_TSC_DEADLINE 0x000006E0
|
||||||
|
|
||||||
/* Intel Model 6 */
|
/* Intel Model 6 */
|
||||||
#define MSR_P6_EVNTSEL0 0x00000186
|
#define MSR_P6_EVNTSEL0 0x00000186
|
||||||
#define MSR_P6_EVNTSEL1 0x00000187
|
#define MSR_P6_EVNTSEL1 0x00000187
|
||||||
|
|||||||
@@ -74,4 +74,6 @@ int host_tsc_is_safe(void);
|
|||||||
void cpuid_time_leaf(uint32_t sub_idx, unsigned int *eax, unsigned int *ebx,
|
void cpuid_time_leaf(uint32_t sub_idx, unsigned int *eax, unsigned int *ebx,
|
||||||
unsigned int *ecx, unsigned int *edx);
|
unsigned int *ecx, unsigned int *edx);
|
||||||
|
|
||||||
|
u64 stime2tsc(s_time_t stime);
|
||||||
|
|
||||||
#endif /* __X86_TIME_H__ */
|
#endif /* __X86_TIME_H__ */
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include <xen/types.h>
|
#include <xen/types.h>
|
||||||
#include <public/xen.h>
|
#include <public/xen.h>
|
||||||
#include <asm/time.h>
|
|
||||||
|
|
||||||
extern int init_xen_time(void);
|
extern int init_xen_time(void);
|
||||||
extern void cstate_restore_tsc(void);
|
extern void cstate_restore_tsc(void);
|
||||||
@@ -18,6 +17,7 @@ extern void cstate_restore_tsc(void);
|
|||||||
extern unsigned long cpu_khz;
|
extern unsigned long cpu_khz;
|
||||||
|
|
||||||
struct domain;
|
struct domain;
|
||||||
|
struct vcpu;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* System Time
|
* System Time
|
||||||
@@ -63,6 +63,8 @@ extern void send_timer_event(struct vcpu *v);
|
|||||||
|
|
||||||
void domain_set_time_offset(struct domain *d, int32_t time_offset_seconds);
|
void domain_set_time_offset(struct domain *d, int32_t time_offset_seconds);
|
||||||
|
|
||||||
|
#include <asm/time.h>
|
||||||
|
|
||||||
#endif /* __XEN_TIME_H__ */
|
#endif /* __XEN_TIME_H__ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||