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 29*a122d623SJeremy Fitzhardinge #define MC_DEBUG 1 30*a122d623SJeremy Fitzhardinge 319702785aSThomas Gleixner #define MC_BATCH 32 329702785aSThomas Gleixner #define MC_ARGS (MC_BATCH * 16 / sizeof(u64)) 339702785aSThomas Gleixner 349702785aSThomas Gleixner struct mc_buffer { 359702785aSThomas Gleixner struct multicall_entry entries[MC_BATCH]; 36*a122d623SJeremy Fitzhardinge #if MC_DEBUG 37*a122d623SJeremy Fitzhardinge struct multicall_entry debug[MC_BATCH]; 38*a122d623SJeremy Fitzhardinge #endif 399702785aSThomas Gleixner u64 args[MC_ARGS]; 4091e0c5f3SJeremy Fitzhardinge struct callback { 4191e0c5f3SJeremy Fitzhardinge void (*fn)(void *); 4291e0c5f3SJeremy Fitzhardinge void *data; 4391e0c5f3SJeremy Fitzhardinge } callbacks[MC_BATCH]; 4491e0c5f3SJeremy Fitzhardinge unsigned mcidx, argidx, cbidx; 459702785aSThomas Gleixner }; 469702785aSThomas Gleixner 479702785aSThomas Gleixner static DEFINE_PER_CPU(struct mc_buffer, mc_buffer); 489702785aSThomas Gleixner DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags); 499702785aSThomas Gleixner 509702785aSThomas Gleixner void xen_mc_flush(void) 519702785aSThomas Gleixner { 529702785aSThomas Gleixner struct mc_buffer *b = &__get_cpu_var(mc_buffer); 539702785aSThomas Gleixner int ret = 0; 549702785aSThomas Gleixner unsigned long flags; 5591e0c5f3SJeremy Fitzhardinge int i; 569702785aSThomas Gleixner 579702785aSThomas Gleixner BUG_ON(preemptible()); 589702785aSThomas Gleixner 599702785aSThomas Gleixner /* Disable interrupts in case someone comes in and queues 609702785aSThomas Gleixner something in the middle */ 619702785aSThomas Gleixner local_irq_save(flags); 629702785aSThomas Gleixner 639702785aSThomas Gleixner if (b->mcidx) { 64*a122d623SJeremy Fitzhardinge #if MC_DEBUG 65*a122d623SJeremy Fitzhardinge memcpy(b->debug, b->entries, 66*a122d623SJeremy Fitzhardinge b->mcidx * sizeof(struct multicall_entry)); 67*a122d623SJeremy Fitzhardinge #endif 68*a122d623SJeremy Fitzhardinge 699702785aSThomas Gleixner if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0) 709702785aSThomas Gleixner BUG(); 719702785aSThomas Gleixner for (i = 0; i < b->mcidx; i++) 729702785aSThomas Gleixner if (b->entries[i].result < 0) 739702785aSThomas Gleixner ret++; 74*a122d623SJeremy Fitzhardinge 75*a122d623SJeremy Fitzhardinge #if MC_DEBUG 76*a122d623SJeremy Fitzhardinge if (ret) { 77*a122d623SJeremy Fitzhardinge printk(KERN_ERR "%d multicall(s) failed: cpu %d\n", 78*a122d623SJeremy Fitzhardinge ret, smp_processor_id()); 79*a122d623SJeremy Fitzhardinge for(i = 0; i < b->mcidx; i++) { 80*a122d623SJeremy Fitzhardinge printk(" call %2d/%d: op=%lu arg=[%lx] result=%ld\n", 81*a122d623SJeremy Fitzhardinge i+1, b->mcidx, 82*a122d623SJeremy Fitzhardinge b->debug[i].op, 83*a122d623SJeremy Fitzhardinge b->debug[i].args[0], 84*a122d623SJeremy Fitzhardinge b->entries[i].result); 85*a122d623SJeremy Fitzhardinge } 86*a122d623SJeremy Fitzhardinge } 87*a122d623SJeremy Fitzhardinge #endif 88*a122d623SJeremy Fitzhardinge 899702785aSThomas Gleixner b->mcidx = 0; 909702785aSThomas Gleixner b->argidx = 0; 919702785aSThomas Gleixner } else 929702785aSThomas Gleixner BUG_ON(b->argidx != 0); 939702785aSThomas Gleixner 949702785aSThomas Gleixner local_irq_restore(flags); 959702785aSThomas Gleixner 9691e0c5f3SJeremy Fitzhardinge for(i = 0; i < b->cbidx; i++) { 9791e0c5f3SJeremy Fitzhardinge struct callback *cb = &b->callbacks[i]; 9891e0c5f3SJeremy Fitzhardinge 9991e0c5f3SJeremy Fitzhardinge (*cb->fn)(cb->data); 10091e0c5f3SJeremy Fitzhardinge } 10191e0c5f3SJeremy Fitzhardinge b->cbidx = 0; 10291e0c5f3SJeremy Fitzhardinge 1039702785aSThomas Gleixner BUG_ON(ret); 1049702785aSThomas Gleixner } 1059702785aSThomas Gleixner 1069702785aSThomas Gleixner struct multicall_space __xen_mc_entry(size_t args) 1079702785aSThomas Gleixner { 1089702785aSThomas Gleixner struct mc_buffer *b = &__get_cpu_var(mc_buffer); 1099702785aSThomas Gleixner struct multicall_space ret; 1109702785aSThomas Gleixner unsigned argspace = (args + sizeof(u64) - 1) / sizeof(u64); 1119702785aSThomas Gleixner 1129702785aSThomas Gleixner BUG_ON(preemptible()); 1139702785aSThomas Gleixner BUG_ON(argspace > MC_ARGS); 1149702785aSThomas Gleixner 1159702785aSThomas Gleixner if (b->mcidx == MC_BATCH || 1169702785aSThomas Gleixner (b->argidx + argspace) > MC_ARGS) 1179702785aSThomas Gleixner xen_mc_flush(); 1189702785aSThomas Gleixner 1199702785aSThomas Gleixner ret.mc = &b->entries[b->mcidx]; 1209702785aSThomas Gleixner b->mcidx++; 1219702785aSThomas Gleixner ret.args = &b->args[b->argidx]; 1229702785aSThomas Gleixner b->argidx += argspace; 1239702785aSThomas Gleixner 1249702785aSThomas Gleixner return ret; 1259702785aSThomas Gleixner } 12691e0c5f3SJeremy Fitzhardinge 12791e0c5f3SJeremy Fitzhardinge void xen_mc_callback(void (*fn)(void *), void *data) 12891e0c5f3SJeremy Fitzhardinge { 12991e0c5f3SJeremy Fitzhardinge struct mc_buffer *b = &__get_cpu_var(mc_buffer); 13091e0c5f3SJeremy Fitzhardinge struct callback *cb; 13191e0c5f3SJeremy Fitzhardinge 13291e0c5f3SJeremy Fitzhardinge if (b->cbidx == MC_BATCH) 13391e0c5f3SJeremy Fitzhardinge xen_mc_flush(); 13491e0c5f3SJeremy Fitzhardinge 13591e0c5f3SJeremy Fitzhardinge cb = &b->callbacks[b->cbidx++]; 13691e0c5f3SJeremy Fitzhardinge cb->fn = fn; 13791e0c5f3SJeremy Fitzhardinge cb->data = data; 13891e0c5f3SJeremy Fitzhardinge } 139