23
23
#include <linux/percpu.h>
24
24
#include <linux/hardirq.h>
25
25
#include <linux/debugfs.h>
26
+ #include <linux/jump_label.h>
27
+ #include <linux/printk.h>
26
28
27
29
#include <asm/xen/hypercall.h>
28
30
31
33
32
34
#define MC_BATCH 32
33
35
34
- #define MC_DEBUG 0
35
-
36
36
#define MC_ARGS (MC_BATCH * 16)
37
37
38
38
39
39
struct mc_buffer {
40
40
unsigned mcidx , argidx , cbidx ;
41
41
struct multicall_entry entries [MC_BATCH ];
42
- #if MC_DEBUG
43
- struct multicall_entry debug [MC_BATCH ];
44
- void * caller [MC_BATCH ];
45
- #endif
46
42
unsigned char args [MC_ARGS ];
47
43
struct callback {
48
44
void (* fn )(void * );
49
45
void * data ;
50
46
} callbacks [MC_BATCH ];
51
47
};
52
48
49
+ struct mc_debug_data {
50
+ struct multicall_entry entries [MC_BATCH ];
51
+ void * caller [MC_BATCH ];
52
+ size_t argsz [MC_BATCH ];
53
+ unsigned long * args [MC_BATCH ];
54
+ };
55
+
53
56
static DEFINE_PER_CPU (struct mc_buffer , mc_buffer ) ;
57
+ static struct mc_debug_data mc_debug_data_early __initdata ;
58
+ static struct mc_debug_data __percpu * mc_debug_data __refdata =
59
+ & mc_debug_data_early ;
54
60
DEFINE_PER_CPU (unsigned long, xen_mc_irq_flags );
55
61
62
+ static struct static_key mc_debug __ro_after_init ;
63
+ static bool mc_debug_enabled __initdata ;
64
+
65
+ static int __init xen_parse_mc_debug (char * arg )
66
+ {
67
+ mc_debug_enabled = true;
68
+ static_key_slow_inc (& mc_debug );
69
+
70
+ return 0 ;
71
+ }
72
+ early_param ("xen_mc_debug" , xen_parse_mc_debug );
73
+
74
+ static int __init mc_debug_enable (void )
75
+ {
76
+ struct mc_debug_data __percpu * mcdb ;
77
+ unsigned long flags ;
78
+
79
+ if (!mc_debug_enabled )
80
+ return 0 ;
81
+
82
+ mcdb = alloc_percpu (struct mc_debug_data );
83
+ if (!mcdb ) {
84
+ pr_err ("xen_mc_debug inactive\n" );
85
+ static_key_slow_dec (& mc_debug );
86
+ return - ENOMEM ;
87
+ }
88
+
89
+ /* Be careful when switching to percpu debug data. */
90
+ local_irq_save (flags );
91
+ xen_mc_flush ();
92
+ mc_debug_data = mcdb ;
93
+ local_irq_restore (flags );
94
+
95
+ pr_info ("xen_mc_debug active\n" );
96
+
97
+ return 0 ;
98
+ }
99
+ early_initcall (mc_debug_enable );
100
+
101
+ /* Number of parameters of hypercalls used via multicalls. */
102
+ static const uint8_t hpcpars [] = {
103
+ [__HYPERVISOR_mmu_update ] = 4 ,
104
+ [__HYPERVISOR_stack_switch ] = 2 ,
105
+ [__HYPERVISOR_fpu_taskswitch ] = 1 ,
106
+ [__HYPERVISOR_update_descriptor ] = 2 ,
107
+ [__HYPERVISOR_update_va_mapping ] = 3 ,
108
+ [__HYPERVISOR_mmuext_op ] = 4 ,
109
+ };
110
+
111
+ static void print_debug_data (struct mc_buffer * b , struct mc_debug_data * mcdb ,
112
+ int idx )
113
+ {
114
+ unsigned int arg ;
115
+ unsigned int opidx = mcdb -> entries [idx ].op & 0xff ;
116
+ unsigned int pars = 0 ;
117
+
118
+ pr_err (" call %2d: op=%lu result=%ld caller=%pS " , idx + 1 ,
119
+ mcdb -> entries [idx ].op , b -> entries [idx ].result ,
120
+ mcdb -> caller [idx ]);
121
+ if (opidx < ARRAY_SIZE (hpcpars ))
122
+ pars = hpcpars [opidx ];
123
+ if (pars ) {
124
+ pr_cont ("pars=" );
125
+ for (arg = 0 ; arg < pars ; arg ++ )
126
+ pr_cont ("%lx " , mcdb -> entries [idx ].args [arg ]);
127
+ }
128
+ if (mcdb -> argsz [idx ]) {
129
+ pr_cont ("args=" );
130
+ for (arg = 0 ; arg < mcdb -> argsz [idx ] / 8 ; arg ++ )
131
+ pr_cont ("%lx " , mcdb -> args [idx ][arg ]);
132
+ }
133
+ pr_cont ("\n" );
134
+ }
135
+
56
136
void xen_mc_flush (void )
57
137
{
58
138
struct mc_buffer * b = this_cpu_ptr (& mc_buffer );
59
139
struct multicall_entry * mc ;
140
+ struct mc_debug_data * mcdb = NULL ;
60
141
int ret = 0 ;
61
142
unsigned long flags ;
62
143
int i ;
@@ -69,10 +150,11 @@ void xen_mc_flush(void)
69
150
70
151
trace_xen_mc_flush (b -> mcidx , b -> argidx , b -> cbidx );
71
152
72
- #if MC_DEBUG
73
- memcpy (b -> debug , b -> entries ,
74
- b -> mcidx * sizeof (struct multicall_entry ));
75
- #endif
153
+ if (static_key_false (& mc_debug )) {
154
+ mcdb = this_cpu_ptr (mc_debug_data );
155
+ memcpy (mcdb -> entries , b -> entries ,
156
+ b -> mcidx * sizeof (struct multicall_entry ));
157
+ }
76
158
77
159
switch (b -> mcidx ) {
78
160
case 0 :
@@ -103,21 +185,14 @@ void xen_mc_flush(void)
103
185
pr_err ("%d of %d multicall(s) failed: cpu %d\n" ,
104
186
ret , b -> mcidx , smp_processor_id ());
105
187
for (i = 0 ; i < b -> mcidx ; i ++ ) {
106
- if (b -> entries [i ].result < 0 ) {
107
- #if MC_DEBUG
108
- pr_err (" call %2d: op=%lu arg=[%lx] result=%ld\t%pS\n" ,
109
- i + 1 ,
110
- b -> debug [i ].op ,
111
- b -> debug [i ].args [0 ],
112
- b -> entries [i ].result ,
113
- b -> caller [i ]);
114
- #else
188
+ if (static_key_false (& mc_debug )) {
189
+ print_debug_data (b , mcdb , i );
190
+ } else if (b -> entries [i ].result < 0 ) {
115
191
pr_err (" call %2d: op=%lu arg=[%lx] result=%ld\n" ,
116
192
i + 1 ,
117
193
b -> entries [i ].op ,
118
194
b -> entries [i ].args [0 ],
119
195
b -> entries [i ].result );
120
- #endif
121
196
}
122
197
}
123
198
}
@@ -155,9 +230,13 @@ struct multicall_space __xen_mc_entry(size_t args)
155
230
}
156
231
157
232
ret .mc = & b -> entries [b -> mcidx ];
158
- #if MC_DEBUG
159
- b -> caller [b -> mcidx ] = __builtin_return_address (0 );
160
- #endif
233
+ if (static_key_false (& mc_debug )) {
234
+ struct mc_debug_data * mcdb = this_cpu_ptr (mc_debug_data );
235
+
236
+ mcdb -> caller [b -> mcidx ] = __builtin_return_address (0 );
237
+ mcdb -> argsz [b -> mcidx ] = args ;
238
+ mcdb -> args [b -> mcidx ] = (unsigned long * )(& b -> args [argidx ]);
239
+ }
161
240
b -> mcidx ++ ;
162
241
ret .args = & b -> args [argidx ];
163
242
b -> argidx = argidx + args ;
0 commit comments