diff options
Diffstat (limited to 'arch/x86/xen/multicalls.c')
-rw-r--r-- | arch/x86/xen/multicalls.c | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/arch/x86/xen/multicalls.c b/arch/x86/xen/multicalls.c index c837e8e463db..5e6f36f6d876 100644 --- a/arch/x86/xen/multicalls.c +++ b/arch/x86/xen/multicalls.c | |||
@@ -26,13 +26,22 @@ | |||
26 | 26 | ||
27 | #include "multicalls.h" | 27 | #include "multicalls.h" |
28 | 28 | ||
29 | #define MC_DEBUG 1 | ||
30 | |||
29 | #define MC_BATCH 32 | 31 | #define MC_BATCH 32 |
30 | #define MC_ARGS (MC_BATCH * 16 / sizeof(u64)) | 32 | #define MC_ARGS (MC_BATCH * 16 / sizeof(u64)) |
31 | 33 | ||
32 | struct mc_buffer { | 34 | struct mc_buffer { |
33 | struct multicall_entry entries[MC_BATCH]; | 35 | struct multicall_entry entries[MC_BATCH]; |
36 | #if MC_DEBUG | ||
37 | struct multicall_entry debug[MC_BATCH]; | ||
38 | #endif | ||
34 | u64 args[MC_ARGS]; | 39 | u64 args[MC_ARGS]; |
35 | unsigned mcidx, argidx; | 40 | struct callback { |
41 | void (*fn)(void *); | ||
42 | void *data; | ||
43 | } callbacks[MC_BATCH]; | ||
44 | unsigned mcidx, argidx, cbidx; | ||
36 | }; | 45 | }; |
37 | 46 | ||
38 | static DEFINE_PER_CPU(struct mc_buffer, mc_buffer); | 47 | static DEFINE_PER_CPU(struct mc_buffer, mc_buffer); |
@@ -43,6 +52,7 @@ void xen_mc_flush(void) | |||
43 | struct mc_buffer *b = &__get_cpu_var(mc_buffer); | 52 | struct mc_buffer *b = &__get_cpu_var(mc_buffer); |
44 | int ret = 0; | 53 | int ret = 0; |
45 | unsigned long flags; | 54 | unsigned long flags; |
55 | int i; | ||
46 | 56 | ||
47 | BUG_ON(preemptible()); | 57 | BUG_ON(preemptible()); |
48 | 58 | ||
@@ -51,13 +61,31 @@ void xen_mc_flush(void) | |||
51 | local_irq_save(flags); | 61 | local_irq_save(flags); |
52 | 62 | ||
53 | if (b->mcidx) { | 63 | if (b->mcidx) { |
54 | int i; | 64 | #if MC_DEBUG |
65 | memcpy(b->debug, b->entries, | ||
66 | b->mcidx * sizeof(struct multicall_entry)); | ||
67 | #endif | ||
55 | 68 | ||
56 | if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0) | 69 | if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0) |
57 | BUG(); | 70 | BUG(); |
58 | for (i = 0; i < b->mcidx; i++) | 71 | for (i = 0; i < b->mcidx; i++) |
59 | if (b->entries[i].result < 0) | 72 | if (b->entries[i].result < 0) |
60 | ret++; | 73 | ret++; |
74 | |||
75 | #if MC_DEBUG | ||
76 | if (ret) { | ||
77 | printk(KERN_ERR "%d multicall(s) failed: cpu %d\n", | ||
78 | ret, smp_processor_id()); | ||
79 | for(i = 0; i < b->mcidx; i++) { | ||
80 | printk(" call %2d/%d: op=%lu arg=[%lx] result=%ld\n", | ||
81 | i+1, b->mcidx, | ||
82 | b->debug[i].op, | ||
83 | b->debug[i].args[0], | ||
84 | b->entries[i].result); | ||
85 | } | ||
86 | } | ||
87 | #endif | ||
88 | |||
61 | b->mcidx = 0; | 89 | b->mcidx = 0; |
62 | b->argidx = 0; | 90 | b->argidx = 0; |
63 | } else | 91 | } else |
@@ -65,6 +93,13 @@ void xen_mc_flush(void) | |||
65 | 93 | ||
66 | local_irq_restore(flags); | 94 | local_irq_restore(flags); |
67 | 95 | ||
96 | for(i = 0; i < b->cbidx; i++) { | ||
97 | struct callback *cb = &b->callbacks[i]; | ||
98 | |||
99 | (*cb->fn)(cb->data); | ||
100 | } | ||
101 | b->cbidx = 0; | ||
102 | |||
68 | BUG_ON(ret); | 103 | BUG_ON(ret); |
69 | } | 104 | } |
70 | 105 | ||
@@ -88,3 +123,16 @@ struct multicall_space __xen_mc_entry(size_t args) | |||
88 | 123 | ||
89 | return ret; | 124 | return ret; |
90 | } | 125 | } |
126 | |||
127 | void xen_mc_callback(void (*fn)(void *), void *data) | ||
128 | { | ||
129 | struct mc_buffer *b = &__get_cpu_var(mc_buffer); | ||
130 | struct callback *cb; | ||
131 | |||
132 | if (b->cbidx == MC_BATCH) | ||
133 | xen_mc_flush(); | ||
134 | |||
135 | cb = &b->callbacks[b->cbidx++]; | ||
136 | cb->fn = fn; | ||
137 | cb->data = data; | ||
138 | } | ||