1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/hardirq.h> |
3 | |
4 | #include <asm/x86_init.h> |
5 | |
6 | #include <xen/interface/xen.h> |
7 | #include <xen/interface/sched.h> |
8 | #include <xen/interface/vcpu.h> |
9 | #include <xen/features.h> |
10 | #include <xen/events.h> |
11 | |
12 | #include <asm/xen/hypercall.h> |
13 | #include <asm/xen/hypervisor.h> |
14 | |
15 | #include "xen-ops.h" |
16 | |
17 | /* |
18 | * Force a proper event-channel callback from Xen after clearing the |
19 | * callback mask. We do this in a very simple manner, by making a call |
20 | * down into Xen. The pending flag will be checked by Xen on return. |
21 | */ |
22 | noinstr void xen_force_evtchn_callback(void) |
23 | { |
24 | (void)HYPERVISOR_xen_version(cmd: 0, NULL); |
25 | } |
26 | |
27 | static noinstr void xen_safe_halt(void) |
28 | { |
29 | /* Blocking includes an implicit local_irq_enable(). */ |
30 | if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0) |
31 | BUG(); |
32 | } |
33 | |
34 | static void xen_halt(void) |
35 | { |
36 | if (irqs_disabled()) |
37 | HYPERVISOR_vcpu_op(VCPUOP_down, |
38 | vcpuid: xen_vcpu_nr(smp_processor_id()), NULL); |
39 | else |
40 | xen_safe_halt(); |
41 | } |
42 | |
43 | static const typeof(pv_ops) xen_irq_ops __initconst = { |
44 | .irq = { |
45 | /* Initial interrupt flag handling only called while interrupts off. */ |
46 | .save_fl = __PV_IS_CALLEE_SAVE(paravirt_ret0), |
47 | .irq_disable = __PV_IS_CALLEE_SAVE(paravirt_nop), |
48 | .irq_enable = __PV_IS_CALLEE_SAVE(paravirt_BUG), |
49 | |
50 | .safe_halt = xen_safe_halt, |
51 | .halt = xen_halt, |
52 | }, |
53 | }; |
54 | |
55 | void __init xen_init_irq_ops(void) |
56 | { |
57 | pv_ops.irq = xen_irq_ops.irq; |
58 | x86_init.irqs.intr_init = xen_init_IRQ; |
59 | } |
60 | |