1 // SPDX-License-Identifier: GPL-2.0
3 * Xen hypercall batching.
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.
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.
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.
21 * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
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>
29 #include <asm/xen/hypercall.h>
35 #define MC_ARGS (MC_BATCH * 16)
39 unsigned mcidx
, argidx
, cbidx
;
40 struct multicall_entry entries
[MC_BATCH
];
41 unsigned char args
[MC_ARGS
];
45 } callbacks
[MC_BATCH
];
48 struct mc_debug_data
{
49 struct multicall_entry entries
[MC_BATCH
];
50 void *caller
[MC_BATCH
];
51 size_t argsz
[MC_BATCH
];
52 unsigned long *args
[MC_BATCH
];
55 static DEFINE_PER_CPU(struct mc_buffer
, mc_buffer
);
56 static struct mc_debug_data mc_debug_data_early __initdata
;
57 static DEFINE_PER_CPU(struct mc_debug_data
*, mc_debug_data
) =
59 static struct mc_debug_data __percpu
*mc_debug_data_ptr
;
60 DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags
);
62 static struct static_key mc_debug __ro_after_init
;
63 static bool mc_debug_enabled __initdata
;
65 static int __init
xen_parse_mc_debug(char *arg
)
67 mc_debug_enabled
= true;
68 static_key_slow_inc(&mc_debug
);
72 early_param("xen_mc_debug", xen_parse_mc_debug
);
74 void mc_percpu_init(unsigned int cpu
)
76 per_cpu(mc_debug_data
, cpu
) = per_cpu_ptr(mc_debug_data_ptr
, cpu
);
79 static int __init
mc_debug_enable(void)
83 if (!mc_debug_enabled
)
86 mc_debug_data_ptr
= alloc_percpu(struct mc_debug_data
);
87 if (!mc_debug_data_ptr
) {
88 pr_err("xen_mc_debug inactive\n");
89 static_key_slow_dec(&mc_debug
);
93 /* Be careful when switching to percpu debug data. */
94 local_irq_save(flags
);
97 local_irq_restore(flags
);
99 pr_info("xen_mc_debug active\n");
103 early_initcall(mc_debug_enable
);
105 /* Number of parameters of hypercalls used via multicalls. */
106 static const uint8_t hpcpars
[] = {
107 [__HYPERVISOR_mmu_update
] = 4,
108 [__HYPERVISOR_stack_switch
] = 2,
109 [__HYPERVISOR_fpu_taskswitch
] = 1,
110 [__HYPERVISOR_update_descriptor
] = 2,
111 [__HYPERVISOR_update_va_mapping
] = 3,
112 [__HYPERVISOR_mmuext_op
] = 4,
115 static void print_debug_data(struct mc_buffer
*b
, struct mc_debug_data
*mcdb
,
119 unsigned int opidx
= mcdb
->entries
[idx
].op
& 0xff;
120 unsigned int pars
= 0;
122 pr_err(" call %2d: op=%lu result=%ld caller=%pS ", idx
+ 1,
123 mcdb
->entries
[idx
].op
, b
->entries
[idx
].result
,
125 if (opidx
< ARRAY_SIZE(hpcpars
))
126 pars
= hpcpars
[opidx
];
129 for (arg
= 0; arg
< pars
; arg
++)
130 pr_cont("%lx ", mcdb
->entries
[idx
].args
[arg
]);
132 if (mcdb
->argsz
[idx
]) {
134 for (arg
= 0; arg
< mcdb
->argsz
[idx
] / 8; arg
++)
135 pr_cont("%lx ", mcdb
->args
[idx
][arg
]);
140 void xen_mc_flush(void)
142 struct mc_buffer
*b
= this_cpu_ptr(&mc_buffer
);
143 struct multicall_entry
*mc
;
144 struct mc_debug_data
*mcdb
= NULL
;
149 BUG_ON(preemptible());
151 /* Disable interrupts in case someone comes in and queues
152 something in the middle */
153 local_irq_save(flags
);
155 trace_xen_mc_flush(b
->mcidx
, b
->argidx
, b
->cbidx
);
157 if (static_key_false(&mc_debug
)) {
158 mcdb
= __this_cpu_read(mc_debug_data
);
159 memcpy(mcdb
->entries
, b
->entries
,
160 b
->mcidx
* sizeof(struct multicall_entry
));
166 BUG_ON(b
->argidx
!= 0);
170 /* Singleton multicall - bypass multicall machinery
171 and just do the call directly. */
174 mc
->result
= xen_single_call(mc
->op
, mc
->args
[0], mc
->args
[1],
175 mc
->args
[2], mc
->args
[3],
177 ret
= mc
->result
< 0;
181 if (HYPERVISOR_multicall(b
->entries
, b
->mcidx
) != 0)
183 for (i
= 0; i
< b
->mcidx
; i
++)
184 if (b
->entries
[i
].result
< 0)
189 pr_err("%d of %d multicall(s) failed: cpu %d\n",
190 ret
, b
->mcidx
, smp_processor_id());
191 for (i
= 0; i
< b
->mcidx
; i
++) {
192 if (static_key_false(&mc_debug
)) {
193 print_debug_data(b
, mcdb
, i
);
194 } else if (b
->entries
[i
].result
< 0) {
195 pr_err(" call %2d: op=%lu arg=[%lx] result=%ld\n",
198 b
->entries
[i
].args
[0],
199 b
->entries
[i
].result
);
207 for (i
= 0; i
< b
->cbidx
; i
++) {
208 struct callback
*cb
= &b
->callbacks
[i
];
214 local_irq_restore(flags
);
217 struct multicall_space
__xen_mc_entry(size_t args
)
219 struct mc_buffer
*b
= this_cpu_ptr(&mc_buffer
);
220 struct multicall_space ret
;
221 unsigned argidx
= roundup(b
->argidx
, sizeof(u64
));
223 trace_xen_mc_entry_alloc(args
);
225 BUG_ON(preemptible());
226 BUG_ON(b
->argidx
>= MC_ARGS
);
228 if (unlikely(b
->mcidx
== MC_BATCH
||
229 (argidx
+ args
) >= MC_ARGS
)) {
230 trace_xen_mc_flush_reason((b
->mcidx
== MC_BATCH
) ?
231 XEN_MC_FL_BATCH
: XEN_MC_FL_ARGS
);
233 argidx
= roundup(b
->argidx
, sizeof(u64
));
236 ret
.mc
= &b
->entries
[b
->mcidx
];
237 if (static_key_false(&mc_debug
)) {
238 struct mc_debug_data
*mcdb
= __this_cpu_read(mc_debug_data
);
240 mcdb
->caller
[b
->mcidx
] = __builtin_return_address(0);
241 mcdb
->argsz
[b
->mcidx
] = args
;
242 mcdb
->args
[b
->mcidx
] = (unsigned long *)(&b
->args
[argidx
]);
245 ret
.args
= &b
->args
[argidx
];
246 b
->argidx
= argidx
+ args
;
248 BUG_ON(b
->argidx
>= MC_ARGS
);
252 struct multicall_space
xen_mc_extend_args(unsigned long op
, size_t size
)
254 struct mc_buffer
*b
= this_cpu_ptr(&mc_buffer
);
255 struct multicall_space ret
= { NULL
, NULL
};
257 BUG_ON(preemptible());
258 BUG_ON(b
->argidx
>= MC_ARGS
);
260 if (unlikely(b
->mcidx
== 0 ||
261 b
->entries
[b
->mcidx
- 1].op
!= op
)) {
262 trace_xen_mc_extend_args(op
, size
, XEN_MC_XE_BAD_OP
);
266 if (unlikely((b
->argidx
+ size
) >= MC_ARGS
)) {
267 trace_xen_mc_extend_args(op
, size
, XEN_MC_XE_NO_SPACE
);
271 ret
.mc
= &b
->entries
[b
->mcidx
- 1];
272 ret
.args
= &b
->args
[b
->argidx
];
275 BUG_ON(b
->argidx
>= MC_ARGS
);
277 trace_xen_mc_extend_args(op
, size
, XEN_MC_XE_OK
);
282 void xen_mc_callback(void (*fn
)(void *), void *data
)
284 struct mc_buffer
*b
= this_cpu_ptr(&mc_buffer
);
287 if (b
->cbidx
== MC_BATCH
) {
288 trace_xen_mc_flush_reason(XEN_MC_FL_CALLBACK
);
292 trace_xen_mc_callback(fn
, data
);
294 cb
= &b
->callbacks
[b
->cbidx
++];