xref: /openbmc/linux/arch/x86/xen/multicalls.c (revision 9702785a747aa27baf46ff504beab6528f21f2dd)
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