aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/kvmclock.c
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2012-11-27 20:28:48 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2012-11-27 20:29:05 -0500
commit7069ed67635b8d574541af426d752cd7fbd465a6 (patch)
treeb94c68234d0d430e97d21b458c0d8e092680f408 /arch/x86/kernel/kvmclock.c
parent78c0337a38450f809113dd46fe038874b93909f1 (diff)
x86: kvmclock: allocate pvclock shared memory area
We want to expose the pvclock shared memory areas, which the hypervisor periodically updates, to userspace. For a linear mapping from userspace, it is necessary that entire page sized regions are used for array of pvclock structures. There is no such guarantee with per cpu areas, therefore move to memblock_alloc based allocation. Acked-by: Glauber Costa <glommer@parallels.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kernel/kvmclock.c')
-rw-r--r--arch/x86/kernel/kvmclock.c58
1 files changed, 47 insertions, 11 deletions
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index f1b42b3a186c..c7d75678886e 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -23,6 +23,7 @@
23#include <asm/apic.h> 23#include <asm/apic.h>
24#include <linux/percpu.h> 24#include <linux/percpu.h>
25#include <linux/hardirq.h> 25#include <linux/hardirq.h>
26#include <linux/memblock.h>
26 27
27#include <asm/x86_init.h> 28#include <asm/x86_init.h>
28#include <asm/reboot.h> 29#include <asm/reboot.h>
@@ -39,7 +40,11 @@ static int parse_no_kvmclock(char *arg)
39early_param("no-kvmclock", parse_no_kvmclock); 40early_param("no-kvmclock", parse_no_kvmclock);
40 41
41/* The hypervisor will put information about time periodically here */ 42/* The hypervisor will put information about time periodically here */
42static DEFINE_PER_CPU_SHARED_ALIGNED(struct pvclock_vcpu_time_info, hv_clock); 43struct pvclock_aligned_vcpu_time_info {
44 struct pvclock_vcpu_time_info clock;
45} __attribute__((__aligned__(SMP_CACHE_BYTES)));
46
47static struct pvclock_aligned_vcpu_time_info *hv_clock;
43static struct pvclock_wall_clock wall_clock; 48static struct pvclock_wall_clock wall_clock;
44 49
45/* 50/*
@@ -52,15 +57,20 @@ static unsigned long kvm_get_wallclock(void)
52 struct pvclock_vcpu_time_info *vcpu_time; 57 struct pvclock_vcpu_time_info *vcpu_time;
53 struct timespec ts; 58 struct timespec ts;
54 int low, high; 59 int low, high;
60 int cpu;
55 61
56 low = (int)__pa_symbol(&wall_clock); 62 low = (int)__pa_symbol(&wall_clock);
57 high = ((u64)__pa_symbol(&wall_clock) >> 32); 63 high = ((u64)__pa_symbol(&wall_clock) >> 32);
58 64
59 native_write_msr(msr_kvm_wall_clock, low, high); 65 native_write_msr(msr_kvm_wall_clock, low, high);
60 66
61 vcpu_time = &get_cpu_var(hv_clock); 67 preempt_disable();
68 cpu = smp_processor_id();
69
70 vcpu_time = &hv_clock[cpu].clock;
62 pvclock_read_wallclock(&wall_clock, vcpu_time, &ts); 71 pvclock_read_wallclock(&wall_clock, vcpu_time, &ts);
63 put_cpu_var(hv_clock); 72
73 preempt_enable();
64 74
65 return ts.tv_sec; 75 return ts.tv_sec;
66} 76}
@@ -74,9 +84,11 @@ static cycle_t kvm_clock_read(void)
74{ 84{
75 struct pvclock_vcpu_time_info *src; 85 struct pvclock_vcpu_time_info *src;
76 cycle_t ret; 86 cycle_t ret;
87 int cpu;
77 88
78 preempt_disable_notrace(); 89 preempt_disable_notrace();
79 src = &__get_cpu_var(hv_clock); 90 cpu = smp_processor_id();
91 src = &hv_clock[cpu].clock;
80 ret = pvclock_clocksource_read(src); 92 ret = pvclock_clocksource_read(src);
81 preempt_enable_notrace(); 93 preempt_enable_notrace();
82 return ret; 94 return ret;
@@ -99,8 +111,15 @@ static cycle_t kvm_clock_get_cycles(struct clocksource *cs)
99static unsigned long kvm_get_tsc_khz(void) 111static unsigned long kvm_get_tsc_khz(void)
100{ 112{
101 struct pvclock_vcpu_time_info *src; 113 struct pvclock_vcpu_time_info *src;
102 src = &per_cpu(hv_clock, 0); 114 int cpu;
103 return pvclock_tsc_khz(src); 115 unsigned long tsc_khz;
116
117 preempt_disable();
118 cpu = smp_processor_id();
119 src = &hv_clock[cpu].clock;
120 tsc_khz = pvclock_tsc_khz(src);
121 preempt_enable();
122 return tsc_khz;
104} 123}
105 124
106static void kvm_get_preset_lpj(void) 125static void kvm_get_preset_lpj(void)
@@ -119,10 +138,14 @@ bool kvm_check_and_clear_guest_paused(void)
119{ 138{
120 bool ret = false; 139 bool ret = false;
121 struct pvclock_vcpu_time_info *src; 140 struct pvclock_vcpu_time_info *src;
141 int cpu = smp_processor_id();
142
143 if (!hv_clock)
144 return ret;
122 145
123 src = &__get_cpu_var(hv_clock); 146 src = &hv_clock[cpu].clock;
124 if ((src->flags & PVCLOCK_GUEST_STOPPED) != 0) { 147 if ((src->flags & PVCLOCK_GUEST_STOPPED) != 0) {
125 __this_cpu_and(hv_clock.flags, ~PVCLOCK_GUEST_STOPPED); 148 src->flags &= ~PVCLOCK_GUEST_STOPPED;
126 ret = true; 149 ret = true;
127 } 150 }
128 151
@@ -141,9 +164,10 @@ int kvm_register_clock(char *txt)
141{ 164{
142 int cpu = smp_processor_id(); 165 int cpu = smp_processor_id();
143 int low, high, ret; 166 int low, high, ret;
167 struct pvclock_vcpu_time_info *src = &hv_clock[cpu].clock;
144 168
145 low = (int)__pa(&per_cpu(hv_clock, cpu)) | 1; 169 low = (int)__pa(src) | 1;
146 high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32); 170 high = ((u64)__pa(src) >> 32);
147 ret = native_write_msr_safe(msr_kvm_system_time, low, high); 171 ret = native_write_msr_safe(msr_kvm_system_time, low, high);
148 printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n", 172 printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n",
149 cpu, high, low, txt); 173 cpu, high, low, txt);
@@ -197,6 +221,8 @@ static void kvm_shutdown(void)
197 221
198void __init kvmclock_init(void) 222void __init kvmclock_init(void)
199{ 223{
224 unsigned long mem;
225
200 if (!kvm_para_available()) 226 if (!kvm_para_available())
201 return; 227 return;
202 228
@@ -209,8 +235,18 @@ void __init kvmclock_init(void)
209 printk(KERN_INFO "kvm-clock: Using msrs %x and %x", 235 printk(KERN_INFO "kvm-clock: Using msrs %x and %x",
210 msr_kvm_system_time, msr_kvm_wall_clock); 236 msr_kvm_system_time, msr_kvm_wall_clock);
211 237
212 if (kvm_register_clock("boot clock")) 238 mem = memblock_alloc(sizeof(struct pvclock_aligned_vcpu_time_info) * NR_CPUS,
239 PAGE_SIZE);
240 if (!mem)
241 return;
242 hv_clock = __va(mem);
243
244 if (kvm_register_clock("boot clock")) {
245 hv_clock = NULL;
246 memblock_free(mem,
247 sizeof(struct pvclock_aligned_vcpu_time_info)*NR_CPUS);
213 return; 248 return;
249 }
214 pv_time_ops.sched_clock = kvm_clock_read; 250 pv_time_ops.sched_clock = kvm_clock_read;
215 x86_platform.calibrate_tsc = kvm_get_tsc_khz; 251 x86_platform.calibrate_tsc = kvm_get_tsc_khz;
216 x86_platform.get_wallclock = kvm_get_wallclock; 252 x86_platform.get_wallclock = kvm_get_wallclock;