1*9702785aSThomas Gleixner /* 2*9702785aSThomas Gleixner * Xen hypercall batching. 3*9702785aSThomas Gleixner * 4*9702785aSThomas Gleixner * Xen allows multiple hypercalls to be issued at once, using the 5*9702785aSThomas Gleixner * multicall interface. This allows the cost of trapping into the 6*9702785aSThomas Gleixner * hypervisor to be amortized over several calls. 7*9702785aSThomas Gleixner * 8*9702785aSThomas Gleixner * This file implements a simple interface for multicalls. There's a 9*9702785aSThomas Gleixner * per-cpu buffer of outstanding multicalls. When you want to queue a 10*9702785aSThomas Gleixner * multicall for issuing, you can allocate a multicall slot for the 11*9702785aSThomas Gleixner * call and its arguments, along with storage for space which is 12*9702785aSThomas Gleixner * pointed to by the arguments (for passing pointers to structures, 13*9702785aSThomas Gleixner * etc). When the multicall is actually issued, all the space for the 14*9702785aSThomas Gleixner * commands and allocated memory is freed for reuse. 15*9702785aSThomas Gleixner * 16*9702785aSThomas Gleixner * Multicalls are flushed whenever any of the buffers get full, or 17*9702785aSThomas Gleixner * when explicitly requested. There's no way to get per-multicall 18*9702785aSThomas Gleixner * return results back. It will BUG if any of the multicalls fail. 19*9702785aSThomas Gleixner * 20*9702785aSThomas Gleixner * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 21*9702785aSThomas Gleixner */ 22*9702785aSThomas Gleixner #include <linux/percpu.h> 23*9702785aSThomas Gleixner #include <linux/hardirq.h> 24*9702785aSThomas Gleixner 25*9702785aSThomas Gleixner #include <asm/xen/hypercall.h> 26*9702785aSThomas Gleixner 27*9702785aSThomas Gleixner #include "multicalls.h" 28*9702785aSThomas Gleixner 29*9702785aSThomas Gleixner #define MC_BATCH 32 30*9702785aSThomas Gleixner #define MC_ARGS (MC_BATCH * 16 / sizeof(u64)) 31*9702785aSThomas Gleixner 32*9702785aSThomas Gleixner struct mc_buffer { 33*9702785aSThomas Gleixner struct multicall_entry entries[MC_BATCH]; 34*9702785aSThomas Gleixner u64 args[MC_ARGS]; 35*9702785aSThomas Gleixner unsigned mcidx, argidx; 36*9702785aSThomas Gleixner }; 37*9702785aSThomas Gleixner 38*9702785aSThomas Gleixner static DEFINE_PER_CPU(struct mc_buffer, mc_buffer); 39*9702785aSThomas Gleixner DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags); 40*9702785aSThomas Gleixner 41*9702785aSThomas Gleixner void xen_mc_flush(void) 42*9702785aSThomas Gleixner { 43*9702785aSThomas Gleixner struct mc_buffer *b = &__get_cpu_var(mc_buffer); 44*9702785aSThomas Gleixner int ret = 0; 45*9702785aSThomas Gleixner unsigned long flags; 46*9702785aSThomas Gleixner 47*9702785aSThomas Gleixner BUG_ON(preemptible()); 48*9702785aSThomas Gleixner 49*9702785aSThomas Gleixner /* Disable interrupts in case someone comes in and queues 50*9702785aSThomas Gleixner something in the middle */ 51*9702785aSThomas Gleixner local_irq_save(flags); 52*9702785aSThomas Gleixner 53*9702785aSThomas Gleixner if (b->mcidx) { 54*9702785aSThomas Gleixner int i; 55*9702785aSThomas Gleixner 56*9702785aSThomas Gleixner if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0) 57*9702785aSThomas Gleixner BUG(); 58*9702785aSThomas Gleixner for (i = 0; i < b->mcidx; i++) 59*9702785aSThomas Gleixner if (b->entries[i].result < 0) 60*9702785aSThomas Gleixner ret++; 61*9702785aSThomas Gleixner b->mcidx = 0; 62*9702785aSThomas Gleixner b->argidx = 0; 63*9702785aSThomas Gleixner } else 64*9702785aSThomas Gleixner BUG_ON(b->argidx != 0); 65*9702785aSThomas Gleixner 66*9702785aSThomas Gleixner local_irq_restore(flags); 67*9702785aSThomas Gleixner 68*9702785aSThomas Gleixner BUG_ON(ret); 69*9702785aSThomas Gleixner } 70*9702785aSThomas Gleixner 71*9702785aSThomas Gleixner struct multicall_space __xen_mc_entry(size_t args) 72*9702785aSThomas Gleixner { 73*9702785aSThomas Gleixner struct mc_buffer *b = &__get_cpu_var(mc_buffer); 74*9702785aSThomas Gleixner struct multicall_space ret; 75*9702785aSThomas Gleixner unsigned argspace = (args + sizeof(u64) - 1) / sizeof(u64); 76*9702785aSThomas Gleixner 77*9702785aSThomas Gleixner BUG_ON(preemptible()); 78*9702785aSThomas Gleixner BUG_ON(argspace > MC_ARGS); 79*9702785aSThomas Gleixner 80*9702785aSThomas Gleixner if (b->mcidx == MC_BATCH || 81*9702785aSThomas Gleixner (b->argidx + argspace) > MC_ARGS) 82*9702785aSThomas Gleixner xen_mc_flush(); 83*9702785aSThomas Gleixner 84*9702785aSThomas Gleixner ret.mc = &b->entries[b->mcidx]; 85*9702785aSThomas Gleixner b->mcidx++; 86*9702785aSThomas Gleixner ret.args = &b->args[b->argidx]; 87*9702785aSThomas Gleixner b->argidx += argspace; 88*9702785aSThomas Gleixner 89*9702785aSThomas Gleixner return ret; 90*9702785aSThomas Gleixner } 91