2323#include <linux/percpu.h>
2424#include <linux/hardirq.h>
2525#include <linux/debugfs.h>
26+ #include <linux/jump_label.h>
27+ #include <linux/printk.h>
2628
2729#include <asm/xen/hypercall.h>
2830
3133
3234#define MC_BATCH 32
3335
34- #define MC_DEBUG 0
35-
3636#define MC_ARGS (MC_BATCH * 16)
3737
3838
3939struct mc_buffer {
4040 unsigned mcidx , argidx , cbidx ;
4141 struct multicall_entry entries [MC_BATCH ];
42- #if MC_DEBUG
43- struct multicall_entry debug [MC_BATCH ];
44- void * caller [MC_BATCH ];
45- #endif
4642 unsigned char args [MC_ARGS ];
4743 struct callback {
4844 void (* fn )(void * );
4945 void * data ;
5046 } callbacks [MC_BATCH ];
5147};
5248
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+
5356static 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 ;
5460DEFINE_PER_CPU (unsigned long, xen_mc_irq_flags );
5561
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+
56136void xen_mc_flush (void )
57137{
58138 struct mc_buffer * b = this_cpu_ptr (& mc_buffer );
59139 struct multicall_entry * mc ;
140+ struct mc_debug_data * mcdb = NULL ;
60141 int ret = 0 ;
61142 unsigned long flags ;
62143 int i ;
@@ -69,10 +150,11 @@ void xen_mc_flush(void)
69150
70151 trace_xen_mc_flush (b -> mcidx , b -> argidx , b -> cbidx );
71152
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+ }
76158
77159 switch (b -> mcidx ) {
78160 case 0 :
@@ -103,21 +185,14 @@ void xen_mc_flush(void)
103185 pr_err ("%d of %d multicall(s) failed: cpu %d\n" ,
104186 ret , b -> mcidx , smp_processor_id ());
105187 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 ) {
115191 pr_err (" call %2d: op=%lu arg=[%lx] result=%ld\n" ,
116192 i + 1 ,
117193 b -> entries [i ].op ,
118194 b -> entries [i ].args [0 ],
119195 b -> entries [i ].result );
120- #endif
121196 }
122197 }
123198 }
@@ -155,9 +230,13 @@ struct multicall_space __xen_mc_entry(size_t args)
155230 }
156231
157232 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+ }
161240 b -> mcidx ++ ;
162241 ret .args = & b -> args [argidx ];
163242 b -> argidx = argidx + args ;
0 commit comments