diff options
-rw-r--r-- | drivers/xen/manage.c | 7 | ||||
-rw-r--r-- | drivers/xen/time.c | 72 | ||||
-rw-r--r-- | include/xen/xen-ops.h | 1 |
3 files changed, 73 insertions, 7 deletions
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index c425d03d37d2..8835065029d3 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c | |||
@@ -72,18 +72,15 @@ static int xen_suspend(void *data) | |||
72 | } | 72 | } |
73 | 73 | ||
74 | gnttab_suspend(); | 74 | gnttab_suspend(); |
75 | xen_manage_runstate_time(-1); | ||
75 | xen_arch_pre_suspend(); | 76 | xen_arch_pre_suspend(); |
76 | 77 | ||
77 | /* | ||
78 | * This hypercall returns 1 if suspend was cancelled | ||
79 | * or the domain was merely checkpointed, and 0 if it | ||
80 | * is resuming in a new domain. | ||
81 | */ | ||
82 | si->cancelled = HYPERVISOR_suspend(xen_pv_domain() | 78 | si->cancelled = HYPERVISOR_suspend(xen_pv_domain() |
83 | ? virt_to_gfn(xen_start_info) | 79 | ? virt_to_gfn(xen_start_info) |
84 | : 0); | 80 | : 0); |
85 | 81 | ||
86 | xen_arch_post_suspend(si->cancelled); | 82 | xen_arch_post_suspend(si->cancelled); |
83 | xen_manage_runstate_time(si->cancelled ? 1 : 0); | ||
87 | gnttab_resume(); | 84 | gnttab_resume(); |
88 | 85 | ||
89 | if (!si->cancelled) { | 86 | if (!si->cancelled) { |
diff --git a/drivers/xen/time.c b/drivers/xen/time.c index ac5f23fcafc2..8c46f555d82a 100644 --- a/drivers/xen/time.c +++ b/drivers/xen/time.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/kernel_stat.h> | 5 | #include <linux/kernel_stat.h> |
6 | #include <linux/math64.h> | 6 | #include <linux/math64.h> |
7 | #include <linux/gfp.h> | 7 | #include <linux/gfp.h> |
8 | #include <linux/slab.h> | ||
8 | 9 | ||
9 | #include <asm/paravirt.h> | 10 | #include <asm/paravirt.h> |
10 | #include <asm/xen/hypervisor.h> | 11 | #include <asm/xen/hypervisor.h> |
@@ -19,6 +20,8 @@ | |||
19 | /* runstate info updated by Xen */ | 20 | /* runstate info updated by Xen */ |
20 | static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate); | 21 | static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate); |
21 | 22 | ||
23 | static DEFINE_PER_CPU(u64[4], old_runstate_time); | ||
24 | |||
22 | /* return an consistent snapshot of 64-bit time/counter value */ | 25 | /* return an consistent snapshot of 64-bit time/counter value */ |
23 | static u64 get64(const u64 *p) | 26 | static u64 get64(const u64 *p) |
24 | { | 27 | { |
@@ -47,8 +50,8 @@ static u64 get64(const u64 *p) | |||
47 | return ret; | 50 | return ret; |
48 | } | 51 | } |
49 | 52 | ||
50 | static void xen_get_runstate_snapshot_cpu(struct vcpu_runstate_info *res, | 53 | static void xen_get_runstate_snapshot_cpu_delta( |
51 | unsigned int cpu) | 54 | struct vcpu_runstate_info *res, unsigned int cpu) |
52 | { | 55 | { |
53 | u64 state_time; | 56 | u64 state_time; |
54 | struct vcpu_runstate_info *state; | 57 | struct vcpu_runstate_info *state; |
@@ -66,6 +69,71 @@ static void xen_get_runstate_snapshot_cpu(struct vcpu_runstate_info *res, | |||
66 | (state_time & XEN_RUNSTATE_UPDATE)); | 69 | (state_time & XEN_RUNSTATE_UPDATE)); |
67 | } | 70 | } |
68 | 71 | ||
72 | static void xen_get_runstate_snapshot_cpu(struct vcpu_runstate_info *res, | ||
73 | unsigned int cpu) | ||
74 | { | ||
75 | int i; | ||
76 | |||
77 | xen_get_runstate_snapshot_cpu_delta(res, cpu); | ||
78 | |||
79 | for (i = 0; i < 4; i++) | ||
80 | res->time[i] += per_cpu(old_runstate_time, cpu)[i]; | ||
81 | } | ||
82 | |||
83 | void xen_manage_runstate_time(int action) | ||
84 | { | ||
85 | static struct vcpu_runstate_info *runstate_delta; | ||
86 | struct vcpu_runstate_info state; | ||
87 | int cpu, i; | ||
88 | |||
89 | switch (action) { | ||
90 | case -1: /* backup runstate time before suspend */ | ||
91 | if (unlikely(runstate_delta)) | ||
92 | pr_warn_once("%s: memory leak as runstate_delta is not NULL\n", | ||
93 | __func__); | ||
94 | |||
95 | runstate_delta = kmalloc_array(num_possible_cpus(), | ||
96 | sizeof(*runstate_delta), | ||
97 | GFP_ATOMIC); | ||
98 | if (unlikely(!runstate_delta)) { | ||
99 | pr_warn("%s: failed to allocate runstate_delta\n", | ||
100 | __func__); | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | for_each_possible_cpu(cpu) { | ||
105 | xen_get_runstate_snapshot_cpu_delta(&state, cpu); | ||
106 | memcpy(runstate_delta[cpu].time, state.time, | ||
107 | sizeof(runstate_delta[cpu].time)); | ||
108 | } | ||
109 | |||
110 | break; | ||
111 | |||
112 | case 0: /* backup runstate time after resume */ | ||
113 | if (unlikely(!runstate_delta)) { | ||
114 | pr_warn("%s: cannot accumulate runstate time as runstate_delta is NULL\n", | ||
115 | __func__); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | for_each_possible_cpu(cpu) { | ||
120 | for (i = 0; i < 4; i++) | ||
121 | per_cpu(old_runstate_time, cpu)[i] += | ||
122 | runstate_delta[cpu].time[i]; | ||
123 | } | ||
124 | |||
125 | break; | ||
126 | |||
127 | default: /* do not accumulate runstate time for checkpointing */ | ||
128 | break; | ||
129 | } | ||
130 | |||
131 | if (action != -1 && runstate_delta) { | ||
132 | kfree(runstate_delta); | ||
133 | runstate_delta = NULL; | ||
134 | } | ||
135 | } | ||
136 | |||
69 | /* | 137 | /* |
70 | * Runstate accounting | 138 | * Runstate accounting |
71 | */ | 139 | */ |
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 218e6aae5433..09072271f122 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h | |||
@@ -32,6 +32,7 @@ void xen_resume_notifier_unregister(struct notifier_block *nb); | |||
32 | bool xen_vcpu_stolen(int vcpu); | 32 | bool xen_vcpu_stolen(int vcpu); |
33 | void xen_setup_runstate_info(int cpu); | 33 | void xen_setup_runstate_info(int cpu); |
34 | void xen_time_setup_guest(void); | 34 | void xen_time_setup_guest(void); |
35 | void xen_manage_runstate_time(int action); | ||
35 | void xen_get_runstate_snapshot(struct vcpu_runstate_info *res); | 36 | void xen_get_runstate_snapshot(struct vcpu_runstate_info *res); |
36 | u64 xen_steal_clock(int cpu); | 37 | u64 xen_steal_clock(int cpu); |
37 | 38 | ||