Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Jane Malalane and committed by
Juergen Gross
b1c3497e 251e90e7

+100 -15
+2
arch/x86/include/asm/xen/cpuid.h
··· 107 107 * ID field from 8 to 15 bits, allowing to target APIC IDs up 32768. 108 108 */ 109 109 #define XEN_HVM_CPUID_EXT_DEST_ID (1u << 5) 110 + /* Per-vCPU event channel upcalls */ 111 + #define XEN_HVM_CPUID_UPCALL_VECTOR (1u << 6) 110 112 111 113 /* 112 114 * Leaf 6 (0x40000x05)
+2 -1
arch/x86/include/asm/xen/events.h
··· 23 23 /* No need for a barrier -- XCHG is a barrier on x86. */ 24 24 #define xchg_xen_ulong(ptr, val) xchg((ptr), (val)) 25 25 26 - extern int xen_have_vector_callback; 26 + extern bool xen_have_vector_callback; 27 27 28 28 /* 29 29 * Events delivered via platform PCI interrupts are always ··· 34 34 return (!xen_hvm_domain() || xen_have_vector_callback); 35 35 } 36 36 37 + extern bool xen_percpu_upcall; 37 38 #endif /* _ASM_X86_XEN_EVENTS_H */
+1 -1
arch/x86/xen/enlighten.c
··· 51 51 52 52 struct shared_info xen_dummy_shared_info; 53 53 54 - __read_mostly int xen_have_vector_callback; 54 + __read_mostly bool xen_have_vector_callback = true; 55 55 EXPORT_SYMBOL_GPL(xen_have_vector_callback); 56 56 57 57 /*
+18 -6
arch/x86/xen/enlighten_hvm.c
··· 8 8 9 9 #include <xen/features.h> 10 10 #include <xen/events.h> 11 + #include <xen/hvm.h> 12 + #include <xen/interface/hvm/hvm_op.h> 11 13 #include <xen/interface/memory.h> 12 14 13 15 #include <asm/apic.h> ··· 32 30 #include "smp.h" 33 31 34 32 static unsigned long shared_info_pfn; 33 + 34 + __ro_after_init bool xen_percpu_upcall; 35 + EXPORT_SYMBOL_GPL(xen_percpu_upcall); 35 36 36 37 void xen_hvm_init_shared_info(void) 37 38 { ··· 131 126 { 132 127 struct pt_regs *old_regs = set_irq_regs(regs); 133 128 129 + if (xen_percpu_upcall) 130 + ack_APIC_irq(); 131 + 134 132 inc_irq_stat(irq_hv_callback_count); 135 133 136 134 xen_hvm_evtchn_do_upcall(); ··· 177 169 if (!xen_have_vector_callback) 178 170 return 0; 179 171 172 + if (xen_percpu_upcall) { 173 + rc = xen_set_upcall_vector(cpu); 174 + if (rc) { 175 + WARN(1, "HVMOP_set_evtchn_upcall_vector" 176 + " for CPU %d failed: %d\n", cpu, rc); 177 + return rc; 178 + } 179 + } 180 + 180 181 if (xen_feature(XENFEAT_hvm_safe_pvclock)) 181 182 xen_setup_timer(cpu); 182 183 ··· 205 188 xen_teardown_timer(cpu); 206 189 return 0; 207 190 } 208 - 209 - static bool no_vector_callback __initdata; 210 191 211 192 static void __init xen_hvm_guest_init(void) 212 193 { ··· 227 212 xen_vcpu_info_reset(0); 228 213 229 214 xen_panic_handler_init(); 230 - 231 - if (!no_vector_callback && xen_feature(XENFEAT_hvm_callback_vector)) 232 - xen_have_vector_callback = 1; 233 215 234 216 xen_hvm_smp_init(); 235 217 WARN_ON(xen_cpuhp_setup(xen_cpu_up_prepare_hvm, xen_cpu_dead_hvm)); ··· 253 241 254 242 static __init int xen_parse_no_vector_callback(char *arg) 255 243 { 256 - no_vector_callback = true; 244 + xen_have_vector_callback = false; 257 245 return 0; 258 246 } 259 247 early_param("xen_no_vector_callback", xen_parse_no_vector_callback);
+9 -1
arch/x86/xen/suspend_hvm.c
··· 5 5 #include <xen/hvm.h> 6 6 #include <xen/features.h> 7 7 #include <xen/interface/features.h> 8 + #include <xen/events.h> 8 9 9 10 #include "xen-ops.h" 10 11 ··· 15 14 xen_hvm_init_shared_info(); 16 15 xen_vcpu_restore(); 17 16 } 18 - xen_setup_callback_vector(); 17 + if (xen_percpu_upcall) { 18 + unsigned int cpu; 19 + 20 + for_each_online_cpu(cpu) 21 + BUG_ON(xen_set_upcall_vector(cpu)); 22 + } else { 23 + xen_setup_callback_vector(); 24 + } 19 25 xen_unplug_emulated_devices(); 20 26 }
+47 -6
drivers/xen/events/events_base.c
··· 45 45 #include <asm/irq.h> 46 46 #include <asm/io_apic.h> 47 47 #include <asm/i8259.h> 48 + #include <asm/xen/cpuid.h> 48 49 #include <asm/xen/pci.h> 49 50 #endif 50 51 #include <asm/sync_bitops.h> ··· 2184 2183 .irq_ack = ack_dynirq, 2185 2184 }; 2186 2185 2186 + #ifdef CONFIG_X86 2187 2187 #ifdef CONFIG_XEN_PVHVM 2188 2188 /* Vector callbacks are better than PCI interrupts to receive event 2189 2189 * channel notifications because we can receive vector callbacks on any ··· 2197 2195 callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR); 2198 2196 if (xen_set_callback_via(callback_via)) { 2199 2197 pr_err("Request for Xen HVM callback vector failed\n"); 2200 - xen_have_vector_callback = 0; 2198 + xen_have_vector_callback = false; 2201 2199 } 2202 2200 } 2201 + } 2202 + 2203 + /* 2204 + * Setup per-vCPU vector-type callbacks. If this setup is unavailable, 2205 + * fallback to the global vector-type callback. 2206 + */ 2207 + static __init void xen_init_setup_upcall_vector(void) 2208 + { 2209 + if (!xen_have_vector_callback) 2210 + return; 2211 + 2212 + if ((cpuid_eax(xen_cpuid_base() + 4) & XEN_HVM_CPUID_UPCALL_VECTOR) && 2213 + !xen_set_upcall_vector(0)) 2214 + xen_percpu_upcall = true; 2215 + else if (xen_feature(XENFEAT_hvm_callback_vector)) 2216 + xen_setup_callback_vector(); 2217 + else 2218 + xen_have_vector_callback = false; 2219 + } 2220 + 2221 + int xen_set_upcall_vector(unsigned int cpu) 2222 + { 2223 + int rc; 2224 + xen_hvm_evtchn_upcall_vector_t op = { 2225 + .vector = HYPERVISOR_CALLBACK_VECTOR, 2226 + .vcpu = per_cpu(xen_vcpu_id, cpu), 2227 + }; 2228 + 2229 + rc = HYPERVISOR_hvm_op(HVMOP_set_evtchn_upcall_vector, &op); 2230 + if (rc) 2231 + return rc; 2232 + 2233 + /* Trick toolstack to think we are enlightened. */ 2234 + if (!cpu) 2235 + rc = xen_set_callback_via(1); 2236 + 2237 + return rc; 2203 2238 } 2204 2239 2205 2240 static __init void xen_alloc_callback_vector(void) ··· 2249 2210 } 2250 2211 #else 2251 2212 void xen_setup_callback_vector(void) {} 2213 + static inline void xen_init_setup_upcall_vector(void) {} 2214 + int xen_set_upcall_vector(unsigned int cpu) {} 2252 2215 static inline void xen_alloc_callback_vector(void) {} 2253 - #endif 2216 + #endif /* CONFIG_XEN_PVHVM */ 2217 + #endif /* CONFIG_X86 */ 2254 2218 2255 2219 bool xen_fifo_events = true; 2256 2220 module_param_named(fifo_events, xen_fifo_events, bool, 0); ··· 2313 2271 if (xen_initial_domain()) 2314 2272 pci_xen_initial_domain(); 2315 2273 } 2316 - if (xen_feature(XENFEAT_hvm_callback_vector)) { 2317 - xen_setup_callback_vector(); 2318 - xen_alloc_callback_vector(); 2319 - } 2274 + xen_init_setup_upcall_vector(); 2275 + xen_alloc_callback_vector(); 2276 + 2320 2277 2321 2278 if (xen_hvm_domain()) { 2322 2279 native_init_IRQ();
+2
include/xen/hvm.h
··· 60 60 61 61 void xen_setup_callback_vector(void); 62 62 63 + int xen_set_upcall_vector(unsigned int cpu); 64 + 63 65 #endif /* XEN_HVM_H__ */
+19
include/xen/interface/hvm/hvm_op.h
··· 46 46 }; 47 47 DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_get_mem_type); 48 48 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 + 49 68 #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */