Originally from Jeremy Fitzhardinge. Introduce generic, non hypervisor specific, pvclock initialization routines. Signed-off-by: Marcelo Tosatti <mtosatti@xxxxxxxxxx> Index: vsyscall/arch/x86/kernel/pvclock.c =================================================================== --- vsyscall.orig/arch/x86/kernel/pvclock.c +++ vsyscall/arch/x86/kernel/pvclock.c @@ -17,6 +17,10 @@ #include <linux/kernel.h> #include <linux/percpu.h> +#include <linux/notifier.h> +#include <linux/sched.h> +#include <linux/gfp.h> +#include <linux/bootmem.h> #include <asm/pvclock.h> static u8 valid_flags __read_mostly = 0; @@ -122,3 +126,70 @@ void pvclock_read_wallclock(struct pvclo set_normalized_timespec(ts, now.tv_sec, now.tv_nsec); } + +#ifdef CONFIG_PARAVIRT_CLOCK_VSYSCALL + +static aligned_pvti_t *pvclock_vdso_info; + +static struct pvclock_vsyscall_time_info *pvclock_get_vsyscall_user_time_info(int cpu) +{ + if (pvclock_vdso_info == NULL) { + BUG(); + return NULL; + } + + return &pvclock_vdso_info[cpu].info; +} + +struct pvclock_vcpu_time_info *pvclock_get_vsyscall_time_info(int cpu) +{ + return &pvclock_get_vsyscall_user_time_info(cpu)->pvti; +} + +int pvclock_task_migrate(struct notifier_block *nb, unsigned long l, void *v) +{ + struct task_migration_notifier *mn = v; + struct pvclock_vsyscall_time_info *pvti; + + pvti = pvclock_get_vsyscall_user_time_info(mn->from_cpu); + + if (pvti == NULL) + return NOTIFY_DONE; + + pvti->migrate_count++; + + return NOTIFY_DONE; +} + +static struct notifier_block pvclock_migrate = { + .notifier_call = pvclock_task_migrate, +}; + +/* + * Initialize the generic pvclock vsyscall state. This will allocate + * a/some page(s) for the per-vcpu pvclock information, set up a + * fixmap mapping for the page(s) + */ +int __init pvclock_init_vsyscall(void) +{ + int idx; + unsigned int size = PVCLOCK_VSYSCALL_NR_PAGES*PAGE_SIZE; + + pvclock_vdso_info = __alloc_bootmem(size, PAGE_SIZE, 0); + if (!pvclock_vdso_info) + return -ENOMEM; + + memset(pvclock_vdso_info, 0, size); + + for (idx = 0; idx <= (PVCLOCK_FIXMAP_END-PVCLOCK_FIXMAP_BEGIN); idx++) { + __set_fixmap(PVCLOCK_FIXMAP_BEGIN + idx, + __pa_symbol(pvclock_vdso_info) + (idx*PAGE_SIZE), + PAGE_KERNEL_VVAR); + } + + register_task_migration_notifier(&pvclock_migrate); + + return 0; +} + +#endif /* CONFIG_PARAVIRT_CLOCK_VSYSCALL */ Index: vsyscall/arch/x86/include/asm/fixmap.h =================================================================== --- vsyscall.orig/arch/x86/include/asm/fixmap.h +++ vsyscall/arch/x86/include/asm/fixmap.h @@ -19,6 +19,7 @@ #include <asm/acpi.h> #include <asm/apicdef.h> #include <asm/page.h> +#include <asm/pvclock.h> #ifdef CONFIG_X86_32 #include <linux/threads.h> #include <asm/kmap_types.h> @@ -81,6 +82,10 @@ enum fixed_addresses { VVAR_PAGE, VSYSCALL_HPET, #endif +#ifdef CONFIG_PARAVIRT_CLOCK_VSYSCALL + PVCLOCK_FIXMAP_BEGIN, + PVCLOCK_FIXMAP_END = PVCLOCK_FIXMAP_BEGIN+PVCLOCK_VSYSCALL_NR_PAGES-1, +#endif FIX_DBGP_BASE, FIX_EARLYCON_MEM_BASE, #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT Index: vsyscall/arch/x86/include/asm/pvclock.h =================================================================== --- vsyscall.orig/arch/x86/include/asm/pvclock.h +++ vsyscall/arch/x86/include/asm/pvclock.h @@ -13,6 +13,8 @@ void pvclock_read_wallclock(struct pvclo struct pvclock_vcpu_time_info *vcpu, struct timespec *ts); void pvclock_resume(void); +int __init pvclock_init_vsyscall(void); +struct pvclock_vcpu_time_info *pvclock_get_vsyscall_time_info(int cpu); /* * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, @@ -85,4 +87,24 @@ unsigned __pvclock_read_cycles(const str return version; } +#ifdef CONFIG_PARAVIRT_CLOCK_VSYSCALL + +struct pvclock_vsyscall_time_info { + struct pvclock_vcpu_time_info pvti; + u32 migrate_count; +}; + +typedef union { + struct pvclock_vsyscall_time_info info; + char pad[SMP_CACHE_BYTES]; +} aligned_pvti_t ____cacheline_aligned; + +#define PVTI_SIZE sizeof(aligned_pvti_t) +#if NR_CPUS == 1 +#define PVCLOCK_VSYSCALL_NR_PAGES 1 +#else +#define PVCLOCK_VSYSCALL_NR_PAGES ((NR_CPUS-1)/(PAGE_SIZE/PVTI_SIZE))+1 +#endif +#endif /* CONFIG_PARAVIRT_CLOCK_VSYSCALL */ + #endif /* _ASM_X86_PVCLOCK_H */ Index: vsyscall/arch/x86/include/asm/clocksource.h =================================================================== --- vsyscall.orig/arch/x86/include/asm/clocksource.h +++ vsyscall/arch/x86/include/asm/clocksource.h @@ -8,6 +8,7 @@ #define VCLOCK_NONE 0 /* No vDSO clock available. */ #define VCLOCK_TSC 1 /* vDSO should use vread_tsc. */ #define VCLOCK_HPET 2 /* vDSO should use vread_hpet. */ +#define VCLOCK_PVCLOCK 3 /* vDSO should use vread_pvclock. */ struct arch_clocksource_data { int vclock_mode; Index: vsyscall/arch/x86/Kconfig =================================================================== --- vsyscall.orig/arch/x86/Kconfig +++ vsyscall/arch/x86/Kconfig @@ -632,6 +632,13 @@ config PARAVIRT_SPINLOCKS config PARAVIRT_CLOCK bool +config PARAVIRT_CLOCK_VSYSCALL + bool "Paravirt clock vsyscall support" + depends on PARAVIRT_CLOCK && GENERIC_TIME_VSYSCALL + ---help--- + Enable performance critical clock related system calls to + be executed in userspace, provided that the hypervisor + supports it. endif -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html