Commit | Line | Data |
---|---|---|
4ccefbe5 SS |
1 | /* |
2 | * Xen stolen ticks accounting. | |
3 | */ | |
4 | #include <linux/kernel.h> | |
5 | #include <linux/kernel_stat.h> | |
6 | #include <linux/math64.h> | |
7 | #include <linux/gfp.h> | |
8 | ||
9 | #include <asm/xen/hypervisor.h> | |
10 | #include <asm/xen/hypercall.h> | |
11 | ||
12 | #include <xen/events.h> | |
13 | #include <xen/features.h> | |
14 | #include <xen/interface/xen.h> | |
15 | #include <xen/interface/vcpu.h> | |
16 | #include <xen/xen-ops.h> | |
17 | ||
18 | /* runstate info updated by Xen */ | |
19 | static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate); | |
20 | ||
21 | /* return an consistent snapshot of 64-bit time/counter value */ | |
22 | static u64 get64(const u64 *p) | |
23 | { | |
24 | u64 ret; | |
25 | ||
26 | if (BITS_PER_LONG < 64) { | |
27 | u32 *p32 = (u32 *)p; | |
2dd887e3 | 28 | u32 h, l, h2; |
4ccefbe5 SS |
29 | |
30 | /* | |
31 | * Read high then low, and then make sure high is | |
32 | * still the same; this will only loop if low wraps | |
33 | * and carries into high. | |
34 | * XXX some clean way to make this endian-proof? | |
35 | */ | |
36 | do { | |
2dd887e3 SS |
37 | h = READ_ONCE(p32[1]); |
38 | l = READ_ONCE(p32[0]); | |
39 | h2 = READ_ONCE(p32[1]); | |
40 | } while(h2 != h); | |
4ccefbe5 SS |
41 | |
42 | ret = (((u64)h) << 32) | l; | |
43 | } else | |
2dd887e3 | 44 | ret = READ_ONCE(*p); |
4ccefbe5 SS |
45 | |
46 | return ret; | |
47 | } | |
48 | ||
49 | /* | |
50 | * Runstate accounting | |
51 | */ | |
52 | void xen_get_runstate_snapshot(struct vcpu_runstate_info *res) | |
53 | { | |
54 | u64 state_time; | |
55 | struct vcpu_runstate_info *state; | |
56 | ||
57 | BUG_ON(preemptible()); | |
58 | ||
59 | state = this_cpu_ptr(&xen_runstate); | |
60 | ||
61 | /* | |
62 | * The runstate info is always updated by the hypervisor on | |
63 | * the current CPU, so there's no need to use anything | |
64 | * stronger than a compiler barrier when fetching it. | |
65 | */ | |
66 | do { | |
67 | state_time = get64(&state->state_entry_time); | |
2dd887e3 | 68 | *res = READ_ONCE(*state); |
4ccefbe5 SS |
69 | } while (get64(&state->state_entry_time) != state_time); |
70 | } | |
71 | ||
72 | /* return true when a vcpu could run but has no real cpu to run on */ | |
73 | bool xen_vcpu_stolen(int vcpu) | |
74 | { | |
75 | return per_cpu(xen_runstate, vcpu).state == RUNSTATE_runnable; | |
76 | } | |
77 | ||
78 | void xen_setup_runstate_info(int cpu) | |
79 | { | |
80 | struct vcpu_register_runstate_memory_area area; | |
81 | ||
82 | area.addr.v = &per_cpu(xen_runstate, cpu); | |
83 | ||
84 | if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, | |
85 | cpu, &area)) | |
86 | BUG(); | |
87 | } | |
88 |