blob: 74179852e46c31108adf405e86230c3830add94a [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -07002#include <linux/hardirq.h>
3
Thomas Gleixner66bcaf02009-08-20 09:59:09 +02004#include <asm/x86_init.h>
5
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -07006#include <xen/interface/xen.h>
7#include <xen/interface/sched.h>
8#include <xen/interface/vcpu.h>
Mukesh Rathor27713742013-12-11 15:36:51 -05009#include <xen/features.h>
Stefano Stabellini0ec53ec2012-09-14 13:37:32 +000010#include <xen/events.h>
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070011
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 */
22void xen_force_evtchn_callback(void)
23{
24 (void)HYPERVISOR_xen_version(0, NULL);
25}
26
Andi Kleen2605fc22014-05-02 00:44:37 +020027asmlinkage __visible unsigned long xen_save_fl(void)
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070028{
29 struct vcpu_info *vcpu;
30 unsigned long flags;
31
Alex Shi2113f462012-01-13 23:53:35 +080032 vcpu = this_cpu_read(xen_vcpu);
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070033
34 /* flag has opposite sense of mask */
35 flags = !vcpu->evtchn_upcall_mask;
36
37 /* convert to IF type flag
38 -0 -> 0x00000000
39 -1 -> 0xffffffff
40 */
41 return (-flags) & X86_EFLAGS_IF;
42}
Jeremy Fitzhardingeecb93d12009-01-28 14:35:05 -080043PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl);
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070044
Andi Kleena2e7f0e2013-10-22 09:07:56 -070045__visible void xen_restore_fl(unsigned long flags)
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070046{
47 struct vcpu_info *vcpu;
48
49 /* convert from IF type flag */
50 flags = !(flags & X86_EFLAGS_IF);
51
David Vrabelfb58e302013-08-15 13:21:04 +010052 /* See xen_irq_enable() for why preemption must be disabled. */
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070053 preempt_disable();
Alex Shi2113f462012-01-13 23:53:35 +080054 vcpu = this_cpu_read(xen_vcpu);
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070055 vcpu->evtchn_upcall_mask = flags;
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070056
57 if (flags == 0) {
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070058 barrier(); /* unmask then check (avoid races) */
59 if (unlikely(vcpu->evtchn_upcall_pending))
60 xen_force_evtchn_callback();
David Vrabelfb58e302013-08-15 13:21:04 +010061 preempt_enable();
62 } else
63 preempt_enable_no_resched();
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070064}
Jeremy Fitzhardingeecb93d12009-01-28 14:35:05 -080065PV_CALLEE_SAVE_REGS_THUNK(xen_restore_fl);
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070066
Andi Kleen2605fc22014-05-02 00:44:37 +020067asmlinkage __visible void xen_irq_disable(void)
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070068{
69 /* There's a one instruction preempt window here. We need to
70 make sure we're don't switch CPUs between getting the vcpu
71 pointer and updating the mask. */
72 preempt_disable();
Alex Shi2113f462012-01-13 23:53:35 +080073 this_cpu_read(xen_vcpu)->evtchn_upcall_mask = 1;
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070074 preempt_enable_no_resched();
75}
Jeremy Fitzhardingeecb93d12009-01-28 14:35:05 -080076PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable);
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070077
Andi Kleen2605fc22014-05-02 00:44:37 +020078asmlinkage __visible void xen_irq_enable(void)
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070079{
80 struct vcpu_info *vcpu;
81
David Vrabelfb58e302013-08-15 13:21:04 +010082 /*
83 * We may be preempted as soon as vcpu->evtchn_upcall_mask is
84 * cleared, so disable preemption to ensure we check for
85 * events on the VCPU we are still running on.
86 */
87 preempt_disable();
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070088
Alex Shi2113f462012-01-13 23:53:35 +080089 vcpu = this_cpu_read(xen_vcpu);
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -070090 vcpu->evtchn_upcall_mask = 0;
91
92 /* Doesn't matter if we get preempted here, because any
93 pending event will get dealt with anyway. */
94
95 barrier(); /* unmask then check (avoid races) */
96 if (unlikely(vcpu->evtchn_upcall_pending))
97 xen_force_evtchn_callback();
David Vrabelfb58e302013-08-15 13:21:04 +010098
99 preempt_enable();
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -0700100}
Jeremy Fitzhardingeecb93d12009-01-28 14:35:05 -0800101PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable);
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -0700102
103static void xen_safe_halt(void)
104{
105 /* Blocking includes an implicit local_irq_enable(). */
106 if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
107 BUG();
108}
109
110static void xen_halt(void)
111{
112 if (irqs_disabled())
Vitaly Kuznetsovad5475f2016-06-30 17:56:38 +0200113 HYPERVISOR_vcpu_op(VCPUOP_down,
114 xen_vcpu_nr(smp_processor_id()), NULL);
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -0700115 else
116 xen_safe_halt();
117}
118
Daniel Kiper251511a2011-05-04 20:16:07 +0200119static const struct pv_irq_ops xen_irq_ops __initconst = {
Jeremy Fitzhardingeecb93d12009-01-28 14:35:05 -0800120 .save_fl = PV_CALLEE_SAVE(xen_save_fl),
121 .restore_fl = PV_CALLEE_SAVE(xen_restore_fl),
122 .irq_disable = PV_CALLEE_SAVE(xen_irq_disable),
123 .irq_enable = PV_CALLEE_SAVE(xen_irq_enable),
124
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -0700125 .safe_halt = xen_safe_halt,
126 .halt = xen_halt,
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -0700127};
128
Randy Dunlap7d81c3b2011-01-08 20:00:36 -0800129void __init xen_init_irq_ops(void)
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -0700130{
Mukesh Rathor27713742013-12-11 15:36:51 -0500131 /* For PVH we use default pv_irq_ops settings. */
132 if (!xen_feature(XENFEAT_hvm_callback_vector))
133 pv_irq_ops = xen_irq_ops;
Thomas Gleixner66bcaf02009-08-20 09:59:09 +0200134 x86_init.irqs.intr_init = xen_init_IRQ;
Jeremy Fitzhardinge0d1edf42008-07-28 11:53:57 -0700135}