13
13
/* x86_pmu.handle_irq definition */
14
14
#include "../kernel/cpu/perf_event.h"
15
15
16
+ #define XENPMU_IRQ_PROCESSING 1
17
+ struct xenpmu {
18
+ /* Shared page between hypervisor and domain */
19
+ struct xen_pmu_data * xenpmu_data ;
16
20
17
- /* Shared page between hypervisor and domain */
18
- static DEFINE_PER_CPU (struct xen_pmu_data * , xenpmu_shared ) ;
19
- #define get_xenpmu_data () per_cpu(xenpmu_shared, smp_processor_id())
21
+ uint8_t flags ;
22
+ };
23
+ static DEFINE_PER_CPU (struct xenpmu , xenpmu_shared ) ;
24
+ #define get_xenpmu_data () (this_cpu_ptr(&xenpmu_shared)->xenpmu_data)
25
+ #define get_xenpmu_flags () (this_cpu_ptr(&xenpmu_shared)->flags)
20
26
27
+ /* Macro for computing address of a PMU MSR bank */
28
+ #define field_offset (ctxt , field ) ((void *)((uintptr_t)ctxt + \
29
+ (uintptr_t)ctxt->field))
21
30
22
31
/* AMD PMU */
23
32
#define F15H_NUM_COUNTERS 6
@@ -169,19 +178,124 @@ static int is_intel_pmu_msr(u32 msr_index, int *type, int *index)
169
178
}
170
179
}
171
180
172
- bool pmu_msr_read (unsigned int msr , uint64_t * val , int * err )
181
+ static bool xen_intel_pmu_emulate (unsigned int msr , u64 * val , int type ,
182
+ int index , bool is_read )
173
183
{
184
+ uint64_t * reg = NULL ;
185
+ struct xen_pmu_intel_ctxt * ctxt ;
186
+ uint64_t * fix_counters ;
187
+ struct xen_pmu_cntr_pair * arch_cntr_pair ;
188
+ struct xen_pmu_data * xenpmu_data = get_xenpmu_data ();
189
+ uint8_t xenpmu_flags = get_xenpmu_flags ();
190
+
174
191
192
+ if (!xenpmu_data || !(xenpmu_flags & XENPMU_IRQ_PROCESSING ))
193
+ return false;
194
+
195
+ ctxt = & xenpmu_data -> pmu .c .intel ;
196
+
197
+ switch (msr ) {
198
+ case MSR_CORE_PERF_GLOBAL_OVF_CTRL :
199
+ reg = & ctxt -> global_ovf_ctrl ;
200
+ break ;
201
+ case MSR_CORE_PERF_GLOBAL_STATUS :
202
+ reg = & ctxt -> global_status ;
203
+ break ;
204
+ case MSR_CORE_PERF_GLOBAL_CTRL :
205
+ reg = & ctxt -> global_ctrl ;
206
+ break ;
207
+ case MSR_CORE_PERF_FIXED_CTR_CTRL :
208
+ reg = & ctxt -> fixed_ctrl ;
209
+ break ;
210
+ default :
211
+ switch (type ) {
212
+ case MSR_TYPE_COUNTER :
213
+ fix_counters = field_offset (ctxt , fixed_counters );
214
+ reg = & fix_counters [index ];
215
+ break ;
216
+ case MSR_TYPE_ARCH_COUNTER :
217
+ arch_cntr_pair = field_offset (ctxt , arch_counters );
218
+ reg = & arch_cntr_pair [index ].counter ;
219
+ break ;
220
+ case MSR_TYPE_ARCH_CTRL :
221
+ arch_cntr_pair = field_offset (ctxt , arch_counters );
222
+ reg = & arch_cntr_pair [index ].control ;
223
+ break ;
224
+ default :
225
+ return false;
226
+ }
227
+ }
228
+
229
+ if (reg ) {
230
+ if (is_read )
231
+ * val = * reg ;
232
+ else {
233
+ * reg = * val ;
234
+
235
+ if (msr == MSR_CORE_PERF_GLOBAL_OVF_CTRL )
236
+ ctxt -> global_status &= (~(* val ));
237
+ }
238
+ return true;
239
+ }
240
+
241
+ return false;
242
+ }
243
+
244
+ static bool xen_amd_pmu_emulate (unsigned int msr , u64 * val , bool is_read )
245
+ {
246
+ uint64_t * reg = NULL ;
247
+ int i , off = 0 ;
248
+ struct xen_pmu_amd_ctxt * ctxt ;
249
+ uint64_t * counter_regs , * ctrl_regs ;
250
+ struct xen_pmu_data * xenpmu_data = get_xenpmu_data ();
251
+ uint8_t xenpmu_flags = get_xenpmu_flags ();
252
+
253
+ if (!xenpmu_data || !(xenpmu_flags & XENPMU_IRQ_PROCESSING ))
254
+ return false;
255
+
256
+ if (k7_counters_mirrored &&
257
+ ((msr >= MSR_K7_EVNTSEL0 ) && (msr <= MSR_K7_PERFCTR3 )))
258
+ msr = get_fam15h_addr (msr );
259
+
260
+ ctxt = & xenpmu_data -> pmu .c .amd ;
261
+ for (i = 0 ; i < amd_num_counters ; i ++ ) {
262
+ if (msr == amd_ctrls_base + off ) {
263
+ ctrl_regs = field_offset (ctxt , ctrls );
264
+ reg = & ctrl_regs [i ];
265
+ break ;
266
+ } else if (msr == amd_counters_base + off ) {
267
+ counter_regs = field_offset (ctxt , counters );
268
+ reg = & counter_regs [i ];
269
+ break ;
270
+ }
271
+ off += amd_msr_step ;
272
+ }
273
+
274
+ if (reg ) {
275
+ if (is_read )
276
+ * val = * reg ;
277
+ else
278
+ * reg = * val ;
279
+
280
+ return true;
281
+ }
282
+ return false;
283
+ }
284
+
285
+ bool pmu_msr_read (unsigned int msr , uint64_t * val , int * err )
286
+ {
175
287
if (boot_cpu_data .x86_vendor == X86_VENDOR_AMD ) {
176
288
if (is_amd_pmu_msr (msr )) {
177
- * val = native_read_msr_safe (msr , err );
289
+ if (!xen_amd_pmu_emulate (msr , val , 1 ))
290
+ * val = native_read_msr_safe (msr , err );
178
291
return true;
179
292
}
180
293
} else {
181
294
int type , index ;
182
295
183
296
if (is_intel_pmu_msr (msr , & type , & index )) {
184
- * val = native_read_msr_safe (msr , err );
297
+ if (!xen_intel_pmu_emulate (msr , val , type , index , 1 ))
298
+ * val = native_read_msr_safe (msr , err );
185
299
return true;
186
300
}
187
301
}
@@ -191,16 +305,20 @@ bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err)
191
305
192
306
bool pmu_msr_write (unsigned int msr , uint32_t low , uint32_t high , int * err )
193
307
{
308
+ uint64_t val = ((uint64_t )high << 32 ) | low ;
309
+
194
310
if (boot_cpu_data .x86_vendor == X86_VENDOR_AMD ) {
195
311
if (is_amd_pmu_msr (msr )) {
196
- * err = native_write_msr_safe (msr , low , high );
312
+ if (!xen_amd_pmu_emulate (msr , & val , 0 ))
313
+ * err = native_write_msr_safe (msr , low , high );
197
314
return true;
198
315
}
199
316
} else {
200
317
int type , index ;
201
318
202
319
if (is_intel_pmu_msr (msr , & type , & index )) {
203
- * err = native_write_msr_safe (msr , low , high );
320
+ if (!xen_intel_pmu_emulate (msr , & val , type , index , 0 ))
321
+ * err = native_write_msr_safe (msr , low , high );
204
322
return true;
205
323
}
206
324
}
@@ -210,24 +328,52 @@ bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err)
210
328
211
329
static unsigned long long xen_amd_read_pmc (int counter )
212
330
{
213
- uint32_t msr ;
214
- int err ;
331
+ struct xen_pmu_amd_ctxt * ctxt ;
332
+ uint64_t * counter_regs ;
333
+ struct xen_pmu_data * xenpmu_data = get_xenpmu_data ();
334
+ uint8_t xenpmu_flags = get_xenpmu_flags ();
335
+
336
+ if (!xenpmu_data || !(xenpmu_flags & XENPMU_IRQ_PROCESSING )) {
337
+ uint32_t msr ;
338
+ int err ;
215
339
216
- msr = amd_counters_base + (counter * amd_msr_step );
217
- return native_read_msr_safe (msr , & err );
340
+ msr = amd_counters_base + (counter * amd_msr_step );
341
+ return native_read_msr_safe (msr , & err );
342
+ }
343
+
344
+ ctxt = & xenpmu_data -> pmu .c .amd ;
345
+ counter_regs = field_offset (ctxt , counters );
346
+ return counter_regs [counter ];
218
347
}
219
348
220
349
static unsigned long long xen_intel_read_pmc (int counter )
221
350
{
222
- int err ;
223
- uint32_t msr ;
351
+ struct xen_pmu_intel_ctxt * ctxt ;
352
+ uint64_t * fixed_counters ;
353
+ struct xen_pmu_cntr_pair * arch_cntr_pair ;
354
+ struct xen_pmu_data * xenpmu_data = get_xenpmu_data ();
355
+ uint8_t xenpmu_flags = get_xenpmu_flags ();
224
356
225
- if (counter & (1 <<INTEL_PMC_TYPE_SHIFT ))
226
- msr = MSR_CORE_PERF_FIXED_CTR0 + (counter & 0xffff );
227
- else
228
- msr = MSR_IA32_PERFCTR0 + counter ;
357
+ if (!xenpmu_data || !(xenpmu_flags & XENPMU_IRQ_PROCESSING )) {
358
+ uint32_t msr ;
359
+ int err ;
229
360
230
- return native_read_msr_safe (msr , & err );
361
+ if (counter & (1 << INTEL_PMC_TYPE_SHIFT ))
362
+ msr = MSR_CORE_PERF_FIXED_CTR0 + (counter & 0xffff );
363
+ else
364
+ msr = MSR_IA32_PERFCTR0 + counter ;
365
+
366
+ return native_read_msr_safe (msr , & err );
367
+ }
368
+
369
+ ctxt = & xenpmu_data -> pmu .c .intel ;
370
+ if (counter & (1 << INTEL_PMC_TYPE_SHIFT )) {
371
+ fixed_counters = field_offset (ctxt , fixed_counters );
372
+ return fixed_counters [counter & 0xffff ];
373
+ }
374
+
375
+ arch_cntr_pair = field_offset (ctxt , arch_counters );
376
+ return arch_cntr_pair [counter ].counter ;
231
377
}
232
378
233
379
unsigned long long xen_read_pmc (int counter )
@@ -249,6 +395,10 @@ int pmu_apic_update(uint32_t val)
249
395
}
250
396
251
397
xenpmu_data -> pmu .l .lapic_lvtpc = val ;
398
+
399
+ if (get_xenpmu_flags () & XENPMU_IRQ_PROCESSING )
400
+ return 0 ;
401
+
252
402
ret = HYPERVISOR_xenpmu_op (XENPMU_lvtpc_set , NULL );
253
403
254
404
return ret ;
@@ -329,29 +479,34 @@ irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id)
329
479
int err , ret = IRQ_NONE ;
330
480
struct pt_regs regs ;
331
481
const struct xen_pmu_data * xenpmu_data = get_xenpmu_data ();
482
+ uint8_t xenpmu_flags = get_xenpmu_flags ();
332
483
333
484
if (!xenpmu_data ) {
334
485
pr_warn_once ("%s: pmudata not initialized\n" , __func__ );
335
486
return ret ;
336
487
}
337
488
338
- err = HYPERVISOR_xenpmu_op (XENPMU_flush , NULL );
339
- if (err ) {
340
- pr_warn_once ("%s: failed hypercall, err: %d\n" , __func__ , err );
341
- return ret ;
342
- }
343
-
489
+ this_cpu_ptr (& xenpmu_shared )-> flags =
490
+ xenpmu_flags | XENPMU_IRQ_PROCESSING ;
344
491
xen_convert_regs (& xenpmu_data -> pmu .r .regs , & regs ,
345
492
xenpmu_data -> pmu .pmu_flags );
346
493
if (x86_pmu .handle_irq (& regs ))
347
494
ret = IRQ_HANDLED ;
348
495
496
+ /* Write out cached context to HW */
497
+ err = HYPERVISOR_xenpmu_op (XENPMU_flush , NULL );
498
+ this_cpu_ptr (& xenpmu_shared )-> flags = xenpmu_flags ;
499
+ if (err ) {
500
+ pr_warn_once ("%s: failed hypercall, err: %d\n" , __func__ , err );
501
+ return IRQ_NONE ;
502
+ }
503
+
349
504
return ret ;
350
505
}
351
506
352
507
bool is_xen_pmu (int cpu )
353
508
{
354
- return (per_cpu ( xenpmu_shared , cpu ) != NULL );
509
+ return (get_xenpmu_data ( ) != NULL );
355
510
}
356
511
357
512
void xen_pmu_init (int cpu )
@@ -381,7 +536,8 @@ void xen_pmu_init(int cpu)
381
536
if (err )
382
537
goto fail ;
383
538
384
- per_cpu (xenpmu_shared , cpu ) = xenpmu_data ;
539
+ per_cpu (xenpmu_shared , cpu ).xenpmu_data = xenpmu_data ;
540
+ per_cpu (xenpmu_shared , cpu ).flags = 0 ;
385
541
386
542
if (cpu == 0 ) {
387
543
perf_register_guest_info_callbacks (& xen_guest_cbs );
@@ -409,6 +565,6 @@ void xen_pmu_finish(int cpu)
409
565
410
566
(void )HYPERVISOR_xenpmu_op (XENPMU_finish , & xp );
411
567
412
- free_pages ((unsigned long )per_cpu (xenpmu_shared , cpu ), 0 );
413
- per_cpu (xenpmu_shared , cpu ) = NULL ;
568
+ free_pages ((unsigned long )per_cpu (xenpmu_shared , cpu ). xenpmu_data , 0 );
569
+ per_cpu (xenpmu_shared , cpu ). xenpmu_data = NULL ;
414
570
}
0 commit comments