Skip to content

Commit b1c3497

Browse files
janeyasminjgross1
authored andcommitted
x86/xen: Add support for HVMOP_set_evtchn_upcall_vector
Implement support for the HVMOP_set_evtchn_upcall_vector hypercall in order to set the per-vCPU event channel vector callback on Linux and use it in preference of HVM_PARAM_CALLBACK_IRQ. If the per-VCPU vector setup is successful on BSP, use this method for the APs. If not, fallback to the global vector-type callback. Also register callback_irq at per-vCPU event channel setup to trick toolstack to think the domain is enlightened. Suggested-by: "Roger Pau Monné" <roger.pau@citrix.com> Signed-off-by: Jane Malalane <jane.malalane@citrix.com> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Link: https://lore.kernel.org/r/20220729070416.23306-1-jane.malalane@citrix.com Signed-off-by: Juergen Gross <jgross@suse.com>
1 parent 251e90e commit b1c3497

File tree

8 files changed

+100
-15
lines changed

8 files changed

+100
-15
lines changed

arch/x86/include/asm/xen/cpuid.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@
107107
* ID field from 8 to 15 bits, allowing to target APIC IDs up 32768.
108108
*/
109109
#define XEN_HVM_CPUID_EXT_DEST_ID (1u << 5)
110+
/* Per-vCPU event channel upcalls */
111+
#define XEN_HVM_CPUID_UPCALL_VECTOR (1u << 6)
110112

111113
/*
112114
* Leaf 6 (0x40000x05)

arch/x86/include/asm/xen/events.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ static inline int xen_irqs_disabled(struct pt_regs *regs)
2323
/* No need for a barrier -- XCHG is a barrier on x86. */
2424
#define xchg_xen_ulong(ptr, val) xchg((ptr), (val))
2525

26-
extern int xen_have_vector_callback;
26+
extern bool xen_have_vector_callback;
2727

2828
/*
2929
* Events delivered via platform PCI interrupts are always
@@ -34,4 +34,5 @@ static inline bool xen_support_evtchn_rebind(void)
3434
return (!xen_hvm_domain() || xen_have_vector_callback);
3535
}
3636

37+
extern bool xen_percpu_upcall;
3738
#endif /* _ASM_X86_XEN_EVENTS_H */

arch/x86/xen/enlighten.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ EXPORT_SYMBOL_GPL(xen_start_info);
5151

5252
struct shared_info xen_dummy_shared_info;
5353

54-
__read_mostly int xen_have_vector_callback;
54+
__read_mostly bool xen_have_vector_callback = true;
5555
EXPORT_SYMBOL_GPL(xen_have_vector_callback);
5656

5757
/*

arch/x86/xen/enlighten_hvm.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include <xen/features.h>
1010
#include <xen/events.h>
11+
#include <xen/hvm.h>
12+
#include <xen/interface/hvm/hvm_op.h>
1113
#include <xen/interface/memory.h>
1214

1315
#include <asm/apic.h>
@@ -31,6 +33,9 @@
3133

3234
static unsigned long shared_info_pfn;
3335

36+
__ro_after_init bool xen_percpu_upcall;
37+
EXPORT_SYMBOL_GPL(xen_percpu_upcall);
38+
3439
void xen_hvm_init_shared_info(void)
3540
{
3641
struct xen_add_to_physmap xatp;
@@ -126,6 +131,9 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_xen_hvm_callback)
126131
{
127132
struct pt_regs *old_regs = set_irq_regs(regs);
128133

134+
if (xen_percpu_upcall)
135+
ack_APIC_irq();
136+
129137
inc_irq_stat(irq_hv_callback_count);
130138

131139
xen_hvm_evtchn_do_upcall();
@@ -169,6 +177,15 @@ static int xen_cpu_up_prepare_hvm(unsigned int cpu)
169177
if (!xen_have_vector_callback)
170178
return 0;
171179

180+
if (xen_percpu_upcall) {
181+
rc = xen_set_upcall_vector(cpu);
182+
if (rc) {
183+
WARN(1, "HVMOP_set_evtchn_upcall_vector"
184+
" for CPU %d failed: %d\n", cpu, rc);
185+
return rc;
186+
}
187+
}
188+
172189
if (xen_feature(XENFEAT_hvm_safe_pvclock))
173190
xen_setup_timer(cpu);
174191

@@ -189,8 +206,6 @@ static int xen_cpu_dead_hvm(unsigned int cpu)
189206
return 0;
190207
}
191208

192-
static bool no_vector_callback __initdata;
193-
194209
static void __init xen_hvm_guest_init(void)
195210
{
196211
if (xen_pv_domain())
@@ -213,9 +228,6 @@ static void __init xen_hvm_guest_init(void)
213228

214229
xen_panic_handler_init();
215230

216-
if (!no_vector_callback && xen_feature(XENFEAT_hvm_callback_vector))
217-
xen_have_vector_callback = 1;
218-
219231
xen_hvm_smp_init();
220232
WARN_ON(xen_cpuhp_setup(xen_cpu_up_prepare_hvm, xen_cpu_dead_hvm));
221233
xen_unplug_emulated_devices();
@@ -241,7 +253,7 @@ early_param("xen_nopv", xen_parse_nopv);
241253

242254
static __init int xen_parse_no_vector_callback(char *arg)
243255
{
244-
no_vector_callback = true;
256+
xen_have_vector_callback = false;
245257
return 0;
246258
}
247259
early_param("xen_no_vector_callback", xen_parse_no_vector_callback);

arch/x86/xen/suspend_hvm.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <xen/hvm.h>
66
#include <xen/features.h>
77
#include <xen/interface/features.h>
8+
#include <xen/events.h>
89

910
#include "xen-ops.h"
1011

@@ -14,6 +15,13 @@ void xen_hvm_post_suspend(int suspend_cancelled)
1415
xen_hvm_init_shared_info();
1516
xen_vcpu_restore();
1617
}
17-
xen_setup_callback_vector();
18+
if (xen_percpu_upcall) {
19+
unsigned int cpu;
20+
21+
for_each_online_cpu(cpu)
22+
BUG_ON(xen_set_upcall_vector(cpu));
23+
} else {
24+
xen_setup_callback_vector();
25+
}
1826
xen_unplug_emulated_devices();
1927
}

drivers/xen/events/events_base.c

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <asm/irq.h>
4646
#include <asm/io_apic.h>
4747
#include <asm/i8259.h>
48+
#include <asm/xen/cpuid.h>
4849
#include <asm/xen/pci.h>
4950
#endif
5051
#include <asm/sync_bitops.h>
@@ -2183,6 +2184,7 @@ static struct irq_chip xen_percpu_chip __read_mostly = {
21832184
.irq_ack = ack_dynirq,
21842185
};
21852186

2187+
#ifdef CONFIG_X86
21862188
#ifdef CONFIG_XEN_PVHVM
21872189
/* Vector callbacks are better than PCI interrupts to receive event
21882190
* channel notifications because we can receive vector callbacks on any
@@ -2195,11 +2197,48 @@ void xen_setup_callback_vector(void)
21952197
callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR);
21962198
if (xen_set_callback_via(callback_via)) {
21972199
pr_err("Request for Xen HVM callback vector failed\n");
2198-
xen_have_vector_callback = 0;
2200+
xen_have_vector_callback = false;
21992201
}
22002202
}
22012203
}
22022204

2205+
/*
2206+
* Setup per-vCPU vector-type callbacks. If this setup is unavailable,
2207+
* fallback to the global vector-type callback.
2208+
*/
2209+
static __init void xen_init_setup_upcall_vector(void)
2210+
{
2211+
if (!xen_have_vector_callback)
2212+
return;
2213+
2214+
if ((cpuid_eax(xen_cpuid_base() + 4) & XEN_HVM_CPUID_UPCALL_VECTOR) &&
2215+
!xen_set_upcall_vector(0))
2216+
xen_percpu_upcall = true;
2217+
else if (xen_feature(XENFEAT_hvm_callback_vector))
2218+
xen_setup_callback_vector();
2219+
else
2220+
xen_have_vector_callback = false;
2221+
}
2222+
2223+
int xen_set_upcall_vector(unsigned int cpu)
2224+
{
2225+
int rc;
2226+
xen_hvm_evtchn_upcall_vector_t op = {
2227+
.vector = HYPERVISOR_CALLBACK_VECTOR,
2228+
.vcpu = per_cpu(xen_vcpu_id, cpu),
2229+
};
2230+
2231+
rc = HYPERVISOR_hvm_op(HVMOP_set_evtchn_upcall_vector, &op);
2232+
if (rc)
2233+
return rc;
2234+
2235+
/* Trick toolstack to think we are enlightened. */
2236+
if (!cpu)
2237+
rc = xen_set_callback_via(1);
2238+
2239+
return rc;
2240+
}
2241+
22032242
static __init void xen_alloc_callback_vector(void)
22042243
{
22052244
if (!xen_have_vector_callback)
@@ -2210,8 +2249,11 @@ static __init void xen_alloc_callback_vector(void)
22102249
}
22112250
#else
22122251
void xen_setup_callback_vector(void) {}
2252+
static inline void xen_init_setup_upcall_vector(void) {}
2253+
int xen_set_upcall_vector(unsigned int cpu) {}
22132254
static inline void xen_alloc_callback_vector(void) {}
2214-
#endif
2255+
#endif /* CONFIG_XEN_PVHVM */
2256+
#endif /* CONFIG_X86 */
22152257

22162258
bool xen_fifo_events = true;
22172259
module_param_named(fifo_events, xen_fifo_events, bool, 0);
@@ -2271,10 +2313,9 @@ void __init xen_init_IRQ(void)
22712313
if (xen_initial_domain())
22722314
pci_xen_initial_domain();
22732315
}
2274-
if (xen_feature(XENFEAT_hvm_callback_vector)) {
2275-
xen_setup_callback_vector();
2276-
xen_alloc_callback_vector();
2277-
}
2316+
xen_init_setup_upcall_vector();
2317+
xen_alloc_callback_vector();
2318+
22782319

22792320
if (xen_hvm_domain()) {
22802321
native_init_IRQ();

include/xen/hvm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,6 @@ static inline int hvm_get_parameter(int idx, uint64_t *value)
6060

6161
void xen_setup_callback_vector(void);
6262

63+
int xen_set_upcall_vector(unsigned int cpu);
64+
6365
#endif /* XEN_HVM_H__ */

include/xen/interface/hvm/hvm_op.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,23 @@ struct xen_hvm_get_mem_type {
4646
};
4747
DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_get_mem_type);
4848

49+
#if defined(__i386__) || defined(__x86_64__)
50+
51+
/*
52+
* HVMOP_set_evtchn_upcall_vector: Set a <vector> that should be used for event
53+
* channel upcalls on the specified <vcpu>. If set,
54+
* this vector will be used in preference to the
55+
* domain global callback via (see
56+
* HVM_PARAM_CALLBACK_IRQ).
57+
*/
58+
#define HVMOP_set_evtchn_upcall_vector 23
59+
struct xen_hvm_evtchn_upcall_vector {
60+
uint32_t vcpu;
61+
uint8_t vector;
62+
};
63+
typedef struct xen_hvm_evtchn_upcall_vector xen_hvm_evtchn_upcall_vector_t;
64+
DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_evtchn_upcall_vector_t);
65+
66+
#endif /* defined(__i386__) || defined(__x86_64__) */
67+
4968
#endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */

0 commit comments

Comments
 (0)