xen/arm: introduce xen_read_wallclock
[linux-block.git] / arch / arm / xen / enlighten.c
CommitLineData
4c071ee5 1#include <xen/xen.h>
0ec53ecf 2#include <xen/events.h>
b3b52fd8
SS
3#include <xen/grant_table.h>
4#include <xen/hvm.h>
9a9ab3cc 5#include <xen/interface/vcpu.h>
4c071ee5
SS
6#include <xen/interface/xen.h>
7#include <xen/interface/memory.h>
b3b52fd8 8#include <xen/interface/hvm/params.h>
ef61ee0d 9#include <xen/features.h>
4c071ee5 10#include <xen/platform_pci.h>
b3b52fd8 11#include <xen/xenbus.h>
c61ba729 12#include <xen/page.h>
6abb749e 13#include <xen/interface/sched.h>
f832da06 14#include <xen/xen-ops.h>
34e38523 15#include <asm/paravirt.h>
4c071ee5
SS
16#include <asm/xen/hypervisor.h>
17#include <asm/xen/hypercall.h>
6abb749e 18#include <asm/system_misc.h>
0ec53ecf
SS
19#include <linux/interrupt.h>
20#include <linux/irqreturn.h>
4c071ee5 21#include <linux/module.h>
2e01f166
SS
22#include <linux/of.h>
23#include <linux/of_irq.h>
24#include <linux/of_address.h>
e1a9c16b
JG
25#include <linux/cpuidle.h>
26#include <linux/cpufreq.h>
8b271d57 27#include <linux/cpu.h>
f1dddd11 28#include <linux/console.h>
e709fba1 29#include <linux/timekeeping.h>
4c071ee5 30
f832da06
IC
31#include <linux/mm.h>
32
4c071ee5
SS
33struct start_info _xen_start_info;
34struct start_info *xen_start_info = &_xen_start_info;
35c8ab4c 35EXPORT_SYMBOL(xen_start_info);
4c071ee5
SS
36
37enum xen_domain_type xen_domain_type = XEN_NATIVE;
35c8ab4c 38EXPORT_SYMBOL(xen_domain_type);
4c071ee5
SS
39
40struct shared_info xen_dummy_shared_info;
41struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info;
42
43DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
9a9ab3cc 44static struct vcpu_info __percpu *xen_vcpu_info;
4c071ee5 45
c61ba729
IC
46/* These are unused until we support booting "pre-ballooned" */
47unsigned long xen_released_pages;
48struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata;
49
81e863c3 50static __read_mostly unsigned int xen_events_irq;
0ec53ecf 51
5882bfef
SS
52static __initdata struct device_node *xen_node;
53
a13d7201 54int xen_remap_domain_gfn_array(struct vm_area_struct *vma,
4c071ee5 55 unsigned long addr,
a13d7201 56 xen_pfn_t *gfn, int nr,
4e8c0c8c
DV
57 int *err_ptr, pgprot_t prot,
58 unsigned domid,
f832da06 59 struct page **pages)
4c071ee5 60{
a13d7201 61 return xen_xlate_remap_gfn_array(vma, addr, gfn, nr, err_ptr,
628c28ee 62 prot, domid, pages);
4c071ee5 63}
a13d7201 64EXPORT_SYMBOL_GPL(xen_remap_domain_gfn_array);
4e8c0c8c
DV
65
66/* Not used by XENFEAT_auto_translated guests. */
a13d7201 67int xen_remap_domain_gfn_range(struct vm_area_struct *vma,
4e8c0c8c 68 unsigned long addr,
a13d7201 69 xen_pfn_t gfn, int nr,
4e8c0c8c
DV
70 pgprot_t prot, unsigned domid,
71 struct page **pages)
72{
73 return -ENOSYS;
74}
a13d7201 75EXPORT_SYMBOL_GPL(xen_remap_domain_gfn_range);
2e01f166 76
a13d7201 77int xen_unmap_domain_gfn_range(struct vm_area_struct *vma,
f832da06
IC
78 int nr, struct page **pages)
79{
628c28ee 80 return xen_xlate_unmap_gfn_range(vma, nr, pages);
f832da06 81}
a13d7201 82EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range);
f832da06 83
34e38523
SS
84static unsigned long long xen_stolen_accounting(int cpu)
85{
86 struct vcpu_runstate_info state;
87
88 BUG_ON(cpu != smp_processor_id());
89
90 xen_get_runstate_snapshot(&state);
91
92 WARN_ON(state.state != RUNSTATE_running);
93
94 return state.time[RUNSTATE_runnable] + state.time[RUNSTATE_offline];
95}
96
e709fba1
SS
97static void xen_read_wallclock(struct timespec64 *ts)
98{
99 u32 version;
100 struct timespec64 now, ts_monotonic;
101 struct shared_info *s = HYPERVISOR_shared_info;
102 struct pvclock_wall_clock *wall_clock = &(s->wc);
103
104 /* get wallclock at system boot */
105 do {
106 version = wall_clock->version;
107 rmb(); /* fetch version before time */
108 now.tv_sec = ((uint64_t)wall_clock->sec_hi << 32) | wall_clock->sec;
109 now.tv_nsec = wall_clock->nsec;
110 rmb(); /* fetch time before checking version */
111 } while ((wall_clock->version & 1) || (version != wall_clock->version));
112
113 /* time since system boot */
114 ktime_get_ts64(&ts_monotonic);
115 *ts = timespec64_add(now, ts_monotonic);
116}
117
8b271d57 118static void xen_percpu_init(void)
9a9ab3cc
SS
119{
120 struct vcpu_register_vcpu_info info;
121 struct vcpu_info *vcpup;
122 int err;
3cc8e40e 123 int cpu = get_cpu();
9a9ab3cc 124
cb9644bf
SS
125 /*
126 * VCPUOP_register_vcpu_info cannot be called twice for the same
127 * vcpu, so if vcpu_info is already registered, just get out. This
128 * can happen with cpu-hotplug.
129 */
130 if (per_cpu(xen_vcpu, cpu) != NULL)
131 goto after_register_vcpu_info;
132
9a9ab3cc
SS
133 pr_info("Xen: initializing cpu%d\n", cpu);
134 vcpup = per_cpu_ptr(xen_vcpu_info, cpu);
135
250c9af3
JG
136 info.mfn = virt_to_gfn(vcpup);
137 info.offset = xen_offset_in_page(vcpup);
9a9ab3cc
SS
138
139 err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info);
d7266d78
SS
140 BUG_ON(err);
141 per_cpu(xen_vcpu, cpu) = vcpup;
142
34e38523
SS
143 xen_setup_runstate_info(cpu);
144
cb9644bf 145after_register_vcpu_info:
3cc8e40e 146 enable_percpu_irq(xen_events_irq, 0);
0d7febe5 147 put_cpu();
9a9ab3cc
SS
148}
149
2451ade0 150static void xen_restart(enum reboot_mode reboot_mode, const char *cmd)
6abb749e
SS
151{
152 struct sched_shutdown r = { .reason = SHUTDOWN_reboot };
153 int rc;
154 rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
a91c7775 155 BUG_ON(rc);
6abb749e
SS
156}
157
158static void xen_power_off(void)
159{
160 struct sched_shutdown r = { .reason = SHUTDOWN_poweroff };
161 int rc;
162 rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
a91c7775 163 BUG_ON(rc);
6abb749e
SS
164}
165
8b271d57
JG
166static int xen_cpu_notification(struct notifier_block *self,
167 unsigned long action,
168 void *hcpu)
169{
170 switch (action) {
171 case CPU_STARTING:
172 xen_percpu_init();
173 break;
cb9644bf
SS
174 case CPU_DYING:
175 disable_percpu_irq(xen_events_irq);
176 break;
8b271d57
JG
177 default:
178 break;
179 }
180
181 return NOTIFY_OK;
182}
183
184static struct notifier_block xen_cpu_notifier = {
185 .notifier_call = xen_cpu_notification,
186};
187
188static irqreturn_t xen_arm_callback(int irq, void *arg)
189{
190 xen_hvm_evtchn_do_upcall();
191 return IRQ_HANDLED;
192}
193
2e01f166
SS
194/*
195 * see Documentation/devicetree/bindings/arm/xen.txt for the
196 * documentation of the Xen Device Tree format.
197 */
b3b52fd8 198#define GRANT_TABLE_PHYSADDR 0
5882bfef 199void __init xen_early_init(void)
2e01f166 200{
2e01f166
SS
201 int len;
202 const char *s = NULL;
203 const char *version = NULL;
204 const char *xen_prefix = "xen,xen-";
205
5882bfef
SS
206 xen_node = of_find_compatible_node(NULL, NULL, "xen,xen");
207 if (!xen_node) {
2e01f166 208 pr_debug("No Xen support\n");
5882bfef 209 return;
2e01f166 210 }
5882bfef 211 s = of_get_property(xen_node, "compatible", &len);
2e01f166
SS
212 if (strlen(xen_prefix) + 3 < len &&
213 !strncmp(xen_prefix, s, strlen(xen_prefix)))
214 version = s + strlen(xen_prefix);
215 if (version == NULL) {
216 pr_debug("Xen version not found\n");
5882bfef 217 return;
81e863c3
JG
218 }
219
5882bfef 220 pr_info("Xen %s support found\n", version);
8b271d57 221
2e01f166
SS
222 xen_domain_type = XEN_HVM_DOMAIN;
223
ef61ee0d 224 xen_setup_features();
5ebc77de 225
ef61ee0d
SS
226 if (xen_feature(XENFEAT_dom0))
227 xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
228 else
229 xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
f1dddd11
AB
230
231 if (!console_set_on_cmdline && !xen_initial_domain())
232 add_preferred_console("hvc", 0, NULL);
5882bfef
SS
233}
234
235static int __init xen_guest_init(void)
236{
237 struct xen_add_to_physmap xatp;
238 struct shared_info *shared_info_page = NULL;
239 struct resource res;
240 phys_addr_t grant_frames;
241
242 if (!xen_domain())
243 return 0;
244
245 if (of_address_to_resource(xen_node, GRANT_TABLE_PHYSADDR, &res)) {
246 pr_err("Xen grant table base address not found\n");
247 return -ENODEV;
248 }
249 grant_frames = res.start;
250
251 xen_events_irq = irq_of_parse_and_map(xen_node, 0);
252 if (!xen_events_irq) {
253 pr_err("Xen event channel interrupt not found\n");
254 return -ENODEV;
255 }
256
257 shared_info_page = (struct shared_info *)get_zeroed_page(GFP_KERNEL);
ef61ee0d 258
2e01f166
SS
259 if (!shared_info_page) {
260 pr_err("not enough memory\n");
261 return -ENOMEM;
262 }
263 xatp.domid = DOMID_SELF;
264 xatp.idx = 0;
265 xatp.space = XENMAPSPACE_shared_info;
250c9af3 266 xatp.gpfn = virt_to_gfn(shared_info_page);
2e01f166
SS
267 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
268 BUG();
269
270 HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
271
272 /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
273 * page, we use it in the event channel upcall and in some pvclock
9a9ab3cc 274 * related functions.
2e01f166
SS
275 * The shared info contains exactly 1 CPU (the boot CPU). The guest
276 * is required to use VCPUOP_register_vcpu_info to place vcpu info
9a9ab3cc
SS
277 * for secondary CPUs as they are brought up.
278 * For uniformity we use VCPUOP_register_vcpu_info even on cpu0.
279 */
280 xen_vcpu_info = __alloc_percpu(sizeof(struct vcpu_info),
281 sizeof(struct vcpu_info));
282 if (xen_vcpu_info == NULL)
283 return -ENOMEM;
b3b52fd8 284
efaf30a3
KRW
285 if (gnttab_setup_auto_xlat_frames(grant_frames)) {
286 free_percpu(xen_vcpu_info);
287 return -ENOMEM;
288 }
b3b52fd8
SS
289 gnttab_init();
290 if (!xen_initial_domain())
291 xenbus_probe(NULL);
292
e1a9c16b
JG
293 /*
294 * Making sure board specific code will not set up ops for
295 * cpu idle and cpu freq.
296 */
297 disable_cpuidle();
298 disable_cpufreq();
299
8b271d57
JG
300 xen_init_IRQ();
301
302 if (request_percpu_irq(xen_events_irq, xen_arm_callback,
303 "events", &xen_vcpu)) {
304 pr_err("Error request IRQ %d\n", xen_events_irq);
305 return -EINVAL;
306 }
307
308 xen_percpu_init();
309
310 register_cpu_notifier(&xen_cpu_notifier);
311
34e38523
SS
312 pv_time_ops.steal_clock = xen_stolen_accounting;
313 static_key_slow_inc(&paravirt_steal_enabled);
314
1aa3d8d9
SS
315 return 0;
316}
8b271d57 317early_initcall(xen_guest_init);
1aa3d8d9
SS
318
319static int __init xen_pm_init(void)
320{
9dd4b294
RH
321 if (!xen_domain())
322 return -ENODEV;
323
6abb749e
SS
324 pm_power_off = xen_power_off;
325 arm_pm_restart = xen_restart;
e709fba1
SS
326 if (!xen_initial_domain()) {
327 struct timespec64 ts;
328 xen_read_wallclock(&ts);
329 do_settimeofday64(&ts);
330 }
6abb749e 331
2e01f166
SS
332 return 0;
333}
9dd4b294 334late_initcall(xen_pm_init);
0ec53ecf 335
79390289
SS
336
337/* empty stubs */
338void xen_arch_pre_suspend(void) { }
339void xen_arch_post_suspend(int suspend_cancelled) { }
340void xen_timer_resume(void) { }
341void xen_arch_resume(void) { }
ffb7dbed 342void xen_arch_suspend(void) { }
79390289
SS
343
344
d5f985c8 345/* In the hypercall.S file. */
911dec0d
KRW
346EXPORT_SYMBOL_GPL(HYPERVISOR_event_channel_op);
347EXPORT_SYMBOL_GPL(HYPERVISOR_grant_table_op);
ab277bbf
SS
348EXPORT_SYMBOL_GPL(HYPERVISOR_xen_version);
349EXPORT_SYMBOL_GPL(HYPERVISOR_console_io);
350EXPORT_SYMBOL_GPL(HYPERVISOR_sched_op);
351EXPORT_SYMBOL_GPL(HYPERVISOR_hvm_op);
352EXPORT_SYMBOL_GPL(HYPERVISOR_memory_op);
353EXPORT_SYMBOL_GPL(HYPERVISOR_physdev_op);
ea0af613 354EXPORT_SYMBOL_GPL(HYPERVISOR_vcpu_op);
176455e9 355EXPORT_SYMBOL_GPL(HYPERVISOR_tmem_op);
72d39c69 356EXPORT_SYMBOL_GPL(HYPERVISOR_platform_op);
9f1d3414 357EXPORT_SYMBOL_GPL(HYPERVISOR_multicall);
911dec0d 358EXPORT_SYMBOL_GPL(privcmd_call);