Date: Mon, 02 Oct 2006 16:15:54 -0400 From: Bhavana Nagendra <bnagendr@redhat.com> Subject: Re: [RHEL 5 NEW PATCH] : Adding support for RDTSCP and vgetcpu syscall --- linux-2.6.17.x86_64/arch/x86_64/kernel/time.c.orig 2006-10-02 15:56:53.000000000 -0400 +++ linux-2.6.17.x86_64/arch/x86_64/kernel/time.c 2006-10-02 16:10:28.000000000 -0400 @@ -24,6 +24,8 @@ #include <linux/device.h> #include <linux/sysdev.h> #include <linux/bcd.h> +#include <linux/notifier.h> +#include <linux/cpu.h> #include <linux/kallsyms.h> #include <linux/acpi.h> #ifdef CONFIG_ACPI @@ -49,7 +51,7 @@ static void cpufreq_delayed_get(void); extern void i8254_timer_resume(void); extern int using_apic_timer; -static char *time_init_gtod(void); +static char *timename = NULL; DEFINE_SPINLOCK(rtc_lock); EXPORT_SYMBOL(rtc_lock); @@ -893,11 +895,22 @@ static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL }; -void __init time_init(void) +static int __cpuinit +time_cpu_notifier(struct notifier_block *nb, unsigned long action, void *hcpu) { - char *timename; - char *gtod; + unsigned cpu = (unsigned long) hcpu; + + if (action == CPU_ONLINE && cpu_has(&cpu_data[cpu], X86_FEATURE_RDTSCP)) { + unsigned p; + p = smp_processor_id() | (cpu_to_node(smp_processor_id())<<12); + write_rdtscp_aux(p); + } + return NOTIFY_DONE; +} + +void __init time_init(void) +{ if (nohpet) vxtime.hpet_address = 0; @@ -931,18 +944,19 @@ void __init time_init(void) } vxtime.mode = VXTIME_TSC; - gtod = time_init_gtod(); - - printk(KERN_INFO "time.c: Using %ld.%06ld MHz WALL %s GTOD %s timer.\n", - vxtime_hz / 1000000, vxtime_hz % 1000000, timename, gtod); - printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", - cpu_khz / 1000, cpu_khz % 1000); vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz; vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz; vxtime.last_tsc = get_cycles_sync(); setup_irq(0, &irq0); set_cyc2ns_scale(cpu_khz); + + hotcpu_notifier(time_cpu_notifier, 0); + time_cpu_notifier(NULL, CPU_ONLINE, (void *)(long)smp_processor_id()); + +#ifndef CONFIG_SMP + time_init_gtod(); +#endif } /* @@ -962,6 +976,11 @@ __cpuinit int unsynchronized_tsc(void) /* But TSC doesn't tick in C3 so don't use it there */ if (acpi_fadt.length > 0 && acpi_fadt.plvl3_lat < 100) return 1; + + /* AMD systems with constant TSCs have synchronized clocks */ + if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && + (boot_cpu_has(X86_FEATURE_CONSTANT_TSC))) + return 0; #endif return 0; } @@ -973,12 +992,13 @@ __cpuinit int unsynchronized_tsc(void) /* * Decide what mode gettimeofday should use. */ -__init static char *time_init_gtod(void) +void time_init_gtod(void) { char *timetype; if (unsynchronized_tsc()) notsc = 1; + if (vxtime.hpet_address && notsc) { timetype = hpet_use_timer ? "HPET" : "PIT/HPET"; if (hpet_use_timer) @@ -1001,7 +1021,16 @@ __init static char *time_init_gtod(void) timetype = hpet_use_timer ? "HPET/TSC" : "PIT/TSC"; vxtime.mode = VXTIME_TSC; } - return timetype; + + printk(KERN_INFO "time.c: Using %ld.%06ld MHz WALL %s GTOD %s timer.\n", + vxtime_hz / 1000000, vxtime_hz % 1000000, timename, timetype); + printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", + cpu_khz / 1000, cpu_khz % 1000); + vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz; + vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz; + vxtime.last_tsc = get_cycles_sync(); + + set_cyc2ns_scale(cpu_khz); } __setup("report_lost_ticks", time_setup); --- linux-2.6.17.x86_64/arch/x86_64/kernel/smpboot.c.orig 2006-10-02 15:56:47.000000000 -0400 +++ linux-2.6.17.x86_64/arch/x86_64/kernel/smpboot.c 2006-10-02 15:57:07.000000000 -0400 @@ -1181,6 +1181,8 @@ void __init smp_cpus_done(unsigned int m #endif check_nmi_watchdog(); + + time_init_gtod(); } #ifdef CONFIG_HOTPLUG_CPU --- linux-2.6.17.x86_64/include/asm-x86_64/proto.h.orig 2006-10-02 15:56:36.000000000 -0400 +++ linux-2.6.17.x86_64/include/asm-x86_64/proto.h 2006-10-02 15:57:07.000000000 -0400 @@ -49,6 +49,7 @@ extern unsigned long long monotonic_base extern int sysctl_vsyscall; extern int nohpet; extern unsigned long vxtime_hz; +extern void time_init_gtod(void); extern int numa_setup(char *opt); --- linux-2.6.17.x86_64/include/asm-x86_64/msr.h.orig 2006-10-02 15:56:42.000000000 -0400 +++ linux-2.6.17.x86_64/include/asm-x86_64/msr.h 2006-10-02 16:05:22.000000000 -0400 @@ -66,14 +66,25 @@ #define rdtscl(low) \ __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx") +#define rdtscp(low,high,aux) \ + asm volatile (".byte 0x0f,0x01,0xf9" : "=a" (low), "=d" (high), "=c" (aux)) + #define rdtscll(val) do { \ unsigned int __a,__d; \ asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \ (val) = ((unsigned long)__a) | (((unsigned long)__d)<<32); \ } while(0) +#define rdtscpll(val, aux) do { \ + unsigned long __a, __d; \ + asm volatile (".byte 0x0f,0x01,0xf9" : "=a" (__a), "=d" (__d), "=c" (aux)); \ + (val) = (__d << 32) | __a; \ +} while (0) + #define write_tsc(val1,val2) wrmsr(0x10, val1, val2) +#define write_rdtscp_aux(val) wrmsr(0xc0000103, val, 0) + #define rdpmc(counter,low,high) \ __asm__ __volatile__("rdpmc" \ : "=a" (low), "=d" (high) \