19702785aSThomas Gleixner /* 29702785aSThomas Gleixner * Xen hypercall batching. 39702785aSThomas Gleixner * 49702785aSThomas Gleixner * Xen allows multiple hypercalls to be issued at once, using the 59702785aSThomas Gleixner * multicall interface. This allows the cost of trapping into the 69702785aSThomas Gleixner * hypervisor to be amortized over several calls. 79702785aSThomas Gleixner * 89702785aSThomas Gleixner * This file implements a simple interface for multicalls. There's a 99702785aSThomas Gleixner * per-cpu buffer of outstanding multicalls. When you want to queue a 109702785aSThomas Gleixner * multicall for issuing, you can allocate a multicall slot for the 119702785aSThomas Gleixner * call and its arguments, along with storage for space which is 129702785aSThomas Gleixner * pointed to by the arguments (for passing pointers to structures, 139702785aSThomas Gleixner * etc). When the multicall is actually issued, all the space for the 149702785aSThomas Gleixner * commands and allocated memory is freed for reuse. 159702785aSThomas Gleixner * 169702785aSThomas Gleixner * Multicalls are flushed whenever any of the buffers get full, or 179702785aSThomas Gleixner * when explicitly requested. There's no way to get per-multicall 189702785aSThomas Gleixner * return results back. It will BUG if any of the multicalls fail. 199702785aSThomas Gleixner * 209702785aSThomas Gleixner * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 219702785aSThomas Gleixner */ 229702785aSThomas Gleixner #include <linux/percpu.h> 239702785aSThomas Gleixner #include <linux/hardirq.h> 249702785aSThomas Gleixner 259702785aSThomas Gleixner #include <asm/xen/hypercall.h> 269702785aSThomas Gleixner 279702785aSThomas Gleixner #include "multicalls.h" 289702785aSThomas Gleixner 299702785aSThomas Gleixner #define MC_BATCH 32 309702785aSThomas Gleixner #define MC_ARGS (MC_BATCH * 16 / sizeof(u64)) 319702785aSThomas Gleixner 329702785aSThomas Gleixner struct mc_buffer { 339702785aSThomas Gleixner struct multicall_entry entries[MC_BATCH]; 349702785aSThomas Gleixner u64 args[MC_ARGS]; 35*91e0c5f3SJeremy Fitzhardinge struct callback { 36*91e0c5f3SJeremy Fitzhardinge void (*fn)(void *); 37*91e0c5f3SJeremy Fitzhardinge void *data; 38*91e0c5f3SJeremy Fitzhardinge } callbacks[MC_BATCH]; 39*91e0c5f3SJeremy Fitzhardinge unsigned mcidx, argidx, cbidx; 409702785aSThomas Gleixner }; 419702785aSThomas Gleixner 429702785aSThomas Gleixner static DEFINE_PER_CPU(struct mc_buffer, mc_buffer); 439702785aSThomas Gleixner DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags); 449702785aSThomas Gleixner 459702785aSThomas Gleixner void xen_mc_flush(void) 469702785aSThomas Gleixner { 479702785aSThomas Gleixner struct mc_buffer *b = &__get_cpu_var(mc_buffer); 489702785aSThomas Gleixner int ret = 0; 499702785aSThomas Gleixner unsigned long flags; 50*91e0c5f3SJeremy Fitzhardinge int i; 519702785aSThomas Gleixner 529702785aSThomas Gleixner BUG_ON(preemptible()); 539702785aSThomas Gleixner 549702785aSThomas Gleixner /* Disable interrupts in case someone comes in and queues 559702785aSThomas Gleixner something in the middle */ 569702785aSThomas Gleixner local_irq_save(flags); 579702785aSThomas Gleixner 589702785aSThomas Gleixner if (b->mcidx) { 599702785aSThomas Gleixner if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0) 609702785aSThomas Gleixner BUG(); 619702785aSThomas Gleixner for (i = 0; i < b->mcidx; i++) 629702785aSThomas Gleixner if (b->entries[i].result < 0) 639702785aSThomas Gleixner ret++; 649702785aSThomas Gleixner b->mcidx = 0; 659702785aSThomas Gleixner b->argidx = 0; 669702785aSThomas Gleixner } else 679702785aSThomas Gleixner BUG_ON(b->argidx != 0); 689702785aSThomas Gleixner 699702785aSThomas Gleixner local_irq_restore(flags); 709702785aSThomas Gleixner 71*91e0c5f3SJeremy Fitzhardinge for(i = 0; i < b->cbidx; i++) { 72*91e0c5f3SJeremy Fitzhardinge struct callback *cb = &b->callbacks[i]; 73*91e0c5f3SJeremy Fitzhardinge 74*91e0c5f3SJeremy Fitzhardinge (*cb->fn)(cb->data); 75*91e0c5f3SJeremy Fitzhardinge } 76*91e0c5f3SJeremy Fitzhardinge b->cbidx = 0; 77*91e0c5f3SJeremy Fitzhardinge 789702785aSThomas Gleixner BUG_ON(ret); 799702785aSThomas Gleixner } 809702785aSThomas Gleixner 819702785aSThomas Gleixner struct multicall_space __xen_mc_entry(size_t args) 829702785aSThomas Gleixner { 839702785aSThomas Gleixner struct mc_buffer *b = &__get_cpu_var(mc_buffer); 849702785aSThomas Gleixner struct multicall_space ret; 859702785aSThomas Gleixner unsigned argspace = (args + sizeof(u64) - 1) / sizeof(u64); 869702785aSThomas Gleixner 879702785aSThomas Gleixner BUG_ON(preemptible()); 889702785aSThomas Gleixner BUG_ON(argspace > MC_ARGS); 899702785aSThomas Gleixner 909702785aSThomas Gleixner if (b->mcidx == MC_BATCH || 919702785aSThomas Gleixner (b->argidx + argspace) > MC_ARGS) 929702785aSThomas Gleixner xen_mc_flush(); 939702785aSThomas Gleixner 949702785aSThomas Gleixner ret.mc = &b->entries[b->mcidx]; 959702785aSThomas Gleixner b->mcidx++; 969702785aSThomas Gleixner ret.args = &b->args[b->argidx]; 979702785aSThomas Gleixner b->argidx += argspace; 989702785aSThomas Gleixner 999702785aSThomas Gleixner return ret; 1009702785aSThomas Gleixner } 101*91e0c5f3SJeremy Fitzhardinge 102*91e0c5f3SJeremy Fitzhardinge void xen_mc_callback(void (*fn)(void *), void *data) 103*91e0c5f3SJeremy Fitzhardinge { 104*91e0c5f3SJeremy Fitzhardinge struct mc_buffer *b = &__get_cpu_var(mc_buffer); 105*91e0c5f3SJeremy Fitzhardinge struct callback *cb; 106*91e0c5f3SJeremy Fitzhardinge 107*91e0c5f3SJeremy Fitzhardinge if (b->cbidx == MC_BATCH) 108*91e0c5f3SJeremy Fitzhardinge xen_mc_flush(); 109*91e0c5f3SJeremy Fitzhardinge 110*91e0c5f3SJeremy Fitzhardinge cb = &b->callbacks[b->cbidx++]; 111*91e0c5f3SJeremy Fitzhardinge cb->fn = fn; 112*91e0c5f3SJeremy Fitzhardinge cb->data = data; 113*91e0c5f3SJeremy Fitzhardinge } 114