multicalls.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Xen hypercall batching.
  4. *
  5. * Xen allows multiple hypercalls to be issued at once, using the
  6. * multicall interface. This allows the cost of trapping into the
  7. * hypervisor to be amortized over several calls.
  8. *
  9. * This file implements a simple interface for multicalls. There's a
  10. * per-cpu buffer of outstanding multicalls. When you want to queue a
  11. * multicall for issuing, you can allocate a multicall slot for the
  12. * call and its arguments, along with storage for space which is
  13. * pointed to by the arguments (for passing pointers to structures,
  14. * etc). When the multicall is actually issued, all the space for the
  15. * commands and allocated memory is freed for reuse.
  16. *
  17. * Multicalls are flushed whenever any of the buffers get full, or
  18. * when explicitly requested. There's no way to get per-multicall
  19. * return results back. It will BUG if any of the multicalls fail.
  20. *
  21. * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
  22. */
  23. #include <linux/percpu.h>
  24. #include <linux/hardirq.h>
  25. #include <linux/debugfs.h>
  26. #include <linux/jump_label.h>
  27. #include <linux/printk.h>
  28. #include <asm/xen/hypercall.h>
  29. #include "xen-ops.h"
  30. #define MC_BATCH 32
  31. #define MC_ARGS (MC_BATCH * 16)
  32. struct mc_buffer {
  33. unsigned mcidx, argidx, cbidx;
  34. struct multicall_entry entries[MC_BATCH];
  35. unsigned char args[MC_ARGS];
  36. struct callback {
  37. void (*fn)(void *);
  38. void *data;
  39. } callbacks[MC_BATCH];
  40. };
  41. struct mc_debug_data {
  42. struct multicall_entry entries[MC_BATCH];
  43. void *caller[MC_BATCH];
  44. size_t argsz[MC_BATCH];
  45. unsigned long *args[MC_BATCH];
  46. };
  47. static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
  48. static struct mc_debug_data mc_debug_data_early __initdata;
  49. static struct mc_debug_data __percpu *mc_debug_data_ptr;
  50. DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
  51. static struct static_key mc_debug __ro_after_init;
  52. static bool mc_debug_enabled __initdata;
  53. static struct mc_debug_data * __ref get_mc_debug(void)
  54. {
  55. if (!mc_debug_data_ptr)
  56. return &mc_debug_data_early;
  57. return this_cpu_ptr(mc_debug_data_ptr);
  58. }
  59. static int __init xen_parse_mc_debug(char *arg)
  60. {
  61. mc_debug_enabled = true;
  62. static_key_slow_inc(&mc_debug);
  63. return 0;
  64. }
  65. early_param("xen_mc_debug", xen_parse_mc_debug);
  66. static int __init mc_debug_enable(void)
  67. {
  68. unsigned long flags;
  69. struct mc_debug_data __percpu *mcdb;
  70. if (!mc_debug_enabled)
  71. return 0;
  72. mcdb = alloc_percpu(struct mc_debug_data);
  73. if (!mcdb) {
  74. pr_err("xen_mc_debug inactive\n");
  75. static_key_slow_dec(&mc_debug);
  76. return -ENOMEM;
  77. }
  78. /* Be careful when switching to percpu debug data. */
  79. local_irq_save(flags);
  80. xen_mc_flush();
  81. mc_debug_data_ptr = mcdb;
  82. local_irq_restore(flags);
  83. pr_info("xen_mc_debug active\n");
  84. return 0;
  85. }
  86. early_initcall(mc_debug_enable);
  87. /* Number of parameters of hypercalls used via multicalls. */
  88. static const uint8_t hpcpars[] = {
  89. [__HYPERVISOR_mmu_update] = 4,
  90. [__HYPERVISOR_stack_switch] = 2,
  91. [__HYPERVISOR_fpu_taskswitch] = 1,
  92. [__HYPERVISOR_update_descriptor] = 2,
  93. [__HYPERVISOR_update_va_mapping] = 3,
  94. [__HYPERVISOR_mmuext_op] = 4,
  95. };
  96. static void print_debug_data(struct mc_buffer *b, struct mc_debug_data *mcdb,
  97. int idx)
  98. {
  99. unsigned int arg;
  100. unsigned int opidx = mcdb->entries[idx].op & 0xff;
  101. unsigned int pars = 0;
  102. pr_err(" call %2d: op=%lu result=%ld caller=%pS ", idx + 1,
  103. mcdb->entries[idx].op, b->entries[idx].result,
  104. mcdb->caller[idx]);
  105. if (opidx < ARRAY_SIZE(hpcpars))
  106. pars = hpcpars[opidx];
  107. if (pars) {
  108. pr_cont("pars=");
  109. for (arg = 0; arg < pars; arg++)
  110. pr_cont("%lx ", mcdb->entries[idx].args[arg]);
  111. }
  112. if (mcdb->argsz[idx]) {
  113. pr_cont("args=");
  114. for (arg = 0; arg < mcdb->argsz[idx] / 8; arg++)
  115. pr_cont("%lx ", mcdb->args[idx][arg]);
  116. }
  117. pr_cont("\n");
  118. }
  119. void xen_mc_flush(void)
  120. {
  121. struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
  122. struct multicall_entry *mc;
  123. struct mc_debug_data *mcdb = NULL;
  124. int ret = 0;
  125. unsigned long flags;
  126. int i;
  127. BUG_ON(preemptible());
  128. /* Disable interrupts in case someone comes in and queues
  129. something in the middle */
  130. local_irq_save(flags);
  131. trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx);
  132. if (static_key_false(&mc_debug)) {
  133. mcdb = get_mc_debug();
  134. memcpy(mcdb->entries, b->entries,
  135. b->mcidx * sizeof(struct multicall_entry));
  136. }
  137. switch (b->mcidx) {
  138. case 0:
  139. /* no-op */
  140. BUG_ON(b->argidx != 0);
  141. break;
  142. case 1:
  143. /* Singleton multicall - bypass multicall machinery
  144. and just do the call directly. */
  145. mc = &b->entries[0];
  146. mc->result = xen_single_call(mc->op, mc->args[0], mc->args[1],
  147. mc->args[2], mc->args[3],
  148. mc->args[4]);
  149. ret = mc->result < 0;
  150. break;
  151. default:
  152. if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0)
  153. BUG();
  154. for (i = 0; i < b->mcidx; i++)
  155. if (b->entries[i].result < 0)
  156. ret++;
  157. }
  158. if (WARN_ON(ret)) {
  159. pr_err("%d of %d multicall(s) failed: cpu %d\n",
  160. ret, b->mcidx, smp_processor_id());
  161. for (i = 0; i < b->mcidx; i++) {
  162. if (static_key_false(&mc_debug)) {
  163. print_debug_data(b, mcdb, i);
  164. } else if (b->entries[i].result < 0) {
  165. pr_err(" call %2d: op=%lu arg=[%lx] result=%ld\n",
  166. i + 1,
  167. b->entries[i].op,
  168. b->entries[i].args[0],
  169. b->entries[i].result);
  170. }
  171. }
  172. }
  173. b->mcidx = 0;
  174. b->argidx = 0;
  175. for (i = 0; i < b->cbidx; i++) {
  176. struct callback *cb = &b->callbacks[i];
  177. (*cb->fn)(cb->data);
  178. }
  179. b->cbidx = 0;
  180. local_irq_restore(flags);
  181. }
  182. struct multicall_space __xen_mc_entry(size_t args)
  183. {
  184. struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
  185. struct multicall_space ret;
  186. unsigned argidx = roundup(b->argidx, sizeof(u64));
  187. trace_xen_mc_entry_alloc(args);
  188. BUG_ON(preemptible());
  189. BUG_ON(b->argidx >= MC_ARGS);
  190. if (unlikely(b->mcidx == MC_BATCH ||
  191. (argidx + args) >= MC_ARGS)) {
  192. trace_xen_mc_flush_reason((b->mcidx == MC_BATCH) ?
  193. XEN_MC_FL_BATCH : XEN_MC_FL_ARGS);
  194. xen_mc_flush();
  195. argidx = roundup(b->argidx, sizeof(u64));
  196. }
  197. ret.mc = &b->entries[b->mcidx];
  198. if (static_key_false(&mc_debug)) {
  199. struct mc_debug_data *mcdb = get_mc_debug();
  200. mcdb->caller[b->mcidx] = __builtin_return_address(0);
  201. mcdb->argsz[b->mcidx] = args;
  202. mcdb->args[b->mcidx] = (unsigned long *)(&b->args[argidx]);
  203. }
  204. b->mcidx++;
  205. ret.args = &b->args[argidx];
  206. b->argidx = argidx + args;
  207. BUG_ON(b->argidx >= MC_ARGS);
  208. return ret;
  209. }
  210. struct multicall_space xen_mc_extend_args(unsigned long op, size_t size)
  211. {
  212. struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
  213. struct multicall_space ret = { NULL, NULL };
  214. BUG_ON(preemptible());
  215. BUG_ON(b->argidx >= MC_ARGS);
  216. if (unlikely(b->mcidx == 0 ||
  217. b->entries[b->mcidx - 1].op != op)) {
  218. trace_xen_mc_extend_args(op, size, XEN_MC_XE_BAD_OP);
  219. goto out;
  220. }
  221. if (unlikely((b->argidx + size) >= MC_ARGS)) {
  222. trace_xen_mc_extend_args(op, size, XEN_MC_XE_NO_SPACE);
  223. goto out;
  224. }
  225. ret.mc = &b->entries[b->mcidx - 1];
  226. ret.args = &b->args[b->argidx];
  227. b->argidx += size;
  228. BUG_ON(b->argidx >= MC_ARGS);
  229. trace_xen_mc_extend_args(op, size, XEN_MC_XE_OK);
  230. out:
  231. return ret;
  232. }
  233. void xen_mc_callback(void (*fn)(void *), void *data)
  234. {
  235. struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
  236. struct callback *cb;
  237. if (b->cbidx == MC_BATCH) {
  238. trace_xen_mc_flush_reason(XEN_MC_FL_CALLBACK);
  239. xen_mc_flush();
  240. }
  241. trace_xen_mc_callback(fn, data);
  242. cb = &b->callbacks[b->cbidx++];
  243. cb->fn = fn;
  244. cb->data = data;
  245. }