1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */ 2*4882a593Smuzhiyun #ifndef _XEN_MULTICALLS_H 3*4882a593Smuzhiyun #define _XEN_MULTICALLS_H 4*4882a593Smuzhiyun 5*4882a593Smuzhiyun #include <trace/events/xen.h> 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun #include "xen-ops.h" 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun /* Multicalls */ 10*4882a593Smuzhiyun struct multicall_space 11*4882a593Smuzhiyun { 12*4882a593Smuzhiyun struct multicall_entry *mc; 13*4882a593Smuzhiyun void *args; 14*4882a593Smuzhiyun }; 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun /* Allocate room for a multicall and its args */ 17*4882a593Smuzhiyun struct multicall_space __xen_mc_entry(size_t args); 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun DECLARE_PER_CPU(unsigned long, xen_mc_irq_flags); 20*4882a593Smuzhiyun 21*4882a593Smuzhiyun /* Call to start a batch of multiple __xen_mc_entry()s. Must be 22*4882a593Smuzhiyun paired with xen_mc_issue() */ xen_mc_batch(void)23*4882a593Smuzhiyunstatic inline void xen_mc_batch(void) 24*4882a593Smuzhiyun { 25*4882a593Smuzhiyun unsigned long flags; 26*4882a593Smuzhiyun 27*4882a593Smuzhiyun /* need to disable interrupts until this entry is complete */ 28*4882a593Smuzhiyun local_irq_save(flags); 29*4882a593Smuzhiyun trace_xen_mc_batch(paravirt_get_lazy_mode()); 30*4882a593Smuzhiyun __this_cpu_write(xen_mc_irq_flags, flags); 31*4882a593Smuzhiyun } 32*4882a593Smuzhiyun xen_mc_entry(size_t args)33*4882a593Smuzhiyunstatic inline struct multicall_space xen_mc_entry(size_t args) 34*4882a593Smuzhiyun { 35*4882a593Smuzhiyun xen_mc_batch(); 36*4882a593Smuzhiyun return __xen_mc_entry(args); 37*4882a593Smuzhiyun } 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun /* Flush all pending multicalls */ 40*4882a593Smuzhiyun void xen_mc_flush(void); 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun /* Issue a multicall if we're not in a lazy mode */ xen_mc_issue(unsigned mode)43*4882a593Smuzhiyunstatic inline void xen_mc_issue(unsigned mode) 44*4882a593Smuzhiyun { 45*4882a593Smuzhiyun trace_xen_mc_issue(mode); 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun if ((paravirt_get_lazy_mode() & mode) == 0) 48*4882a593Smuzhiyun xen_mc_flush(); 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun /* restore flags saved in xen_mc_batch */ 51*4882a593Smuzhiyun local_irq_restore(this_cpu_read(xen_mc_irq_flags)); 52*4882a593Smuzhiyun } 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun /* Set up a callback to be called when the current batch is flushed */ 55*4882a593Smuzhiyun void xen_mc_callback(void (*fn)(void *), void *data); 56*4882a593Smuzhiyun 57*4882a593Smuzhiyun /* 58*4882a593Smuzhiyun * Try to extend the arguments of the previous multicall command. The 59*4882a593Smuzhiyun * previous command's op must match. If it does, then it attempts to 60*4882a593Smuzhiyun * extend the argument space allocated to the multicall entry by 61*4882a593Smuzhiyun * arg_size bytes. 62*4882a593Smuzhiyun * 63*4882a593Smuzhiyun * The returned multicall_space will return with mc pointing to the 64*4882a593Smuzhiyun * command on success, or NULL on failure, and args pointing to the 65*4882a593Smuzhiyun * newly allocated space. 66*4882a593Smuzhiyun */ 67*4882a593Smuzhiyun struct multicall_space xen_mc_extend_args(unsigned long op, size_t arg_size); 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun #endif /* _XEN_MULTICALLS_H */ 70