31
31
struct bts_ctx {
32
32
struct perf_output_handle handle ;
33
33
struct debug_store ds_back ;
34
- int started ;
34
+ int state ;
35
+ };
36
+
37
+ /* BTS context states: */
38
+ enum {
39
+ /* no ongoing AUX transactions */
40
+ BTS_STATE_STOPPED = 0 ,
41
+ /* AUX transaction is on, BTS tracing is disabled */
42
+ BTS_STATE_INACTIVE ,
43
+ /* AUX transaction is on, BTS tracing is running */
44
+ BTS_STATE_ACTIVE ,
35
45
};
36
46
37
47
static DEFINE_PER_CPU (struct bts_ctx , bts_ctx ) ;
@@ -204,6 +214,15 @@ static void bts_update(struct bts_ctx *bts)
204
214
static int
205
215
bts_buffer_reset (struct bts_buffer * buf , struct perf_output_handle * handle );
206
216
217
+ /*
218
+ * Ordering PMU callbacks wrt themselves and the PMI is done by means
219
+ * of bts::state, which:
220
+ * - is set when bts::handle::event is valid, that is, between
221
+ * perf_aux_output_begin() and perf_aux_output_end();
222
+ * - is zero otherwise;
223
+ * - is ordered against bts::handle::event with a compiler barrier.
224
+ */
225
+
207
226
static void __bts_event_start (struct perf_event * event )
208
227
{
209
228
struct bts_ctx * bts = this_cpu_ptr (& bts_ctx );
@@ -221,10 +240,13 @@ static void __bts_event_start(struct perf_event *event)
221
240
222
241
/*
223
242
* local barrier to make sure that ds configuration made it
224
- * before we enable BTS
243
+ * before we enable BTS and bts::state goes ACTIVE
225
244
*/
226
245
wmb ();
227
246
247
+ /* INACTIVE/STOPPED -> ACTIVE */
248
+ WRITE_ONCE (bts -> state , BTS_STATE_ACTIVE );
249
+
228
250
intel_pmu_enable_bts (config );
229
251
230
252
}
@@ -251,9 +273,6 @@ static void bts_event_start(struct perf_event *event, int flags)
251
273
252
274
__bts_event_start (event );
253
275
254
- /* PMI handler: this counter is running and likely generating PMIs */
255
- ACCESS_ONCE (bts -> started ) = 1 ;
256
-
257
276
return ;
258
277
259
278
fail_end_stop :
@@ -263,30 +282,34 @@ static void bts_event_start(struct perf_event *event, int flags)
263
282
event -> hw .state = PERF_HES_STOPPED ;
264
283
}
265
284
266
- static void __bts_event_stop (struct perf_event * event )
285
+ static void __bts_event_stop (struct perf_event * event , int state )
267
286
{
287
+ struct bts_ctx * bts = this_cpu_ptr (& bts_ctx );
288
+
289
+ /* ACTIVE -> INACTIVE(PMI)/STOPPED(->stop()) */
290
+ WRITE_ONCE (bts -> state , state );
291
+
268
292
/*
269
293
* No extra synchronization is mandated by the documentation to have
270
294
* BTS data stores globally visible.
271
295
*/
272
296
intel_pmu_disable_bts ();
273
-
274
- if (event -> hw .state & PERF_HES_STOPPED )
275
- return ;
276
-
277
- ACCESS_ONCE (event -> hw .state ) |= PERF_HES_STOPPED ;
278
297
}
279
298
280
299
static void bts_event_stop (struct perf_event * event , int flags )
281
300
{
282
301
struct cpu_hw_events * cpuc = this_cpu_ptr (& cpu_hw_events );
283
302
struct bts_ctx * bts = this_cpu_ptr (& bts_ctx );
284
- struct bts_buffer * buf = perf_get_aux (& bts -> handle );
303
+ struct bts_buffer * buf = NULL ;
304
+ int state = READ_ONCE (bts -> state );
285
305
286
- /* PMI handler: don't restart this counter */
287
- ACCESS_ONCE ( bts -> started ) = 0 ;
306
+ if ( state == BTS_STATE_ACTIVE )
307
+ __bts_event_stop ( event , BTS_STATE_STOPPED ) ;
288
308
289
- __bts_event_stop (event );
309
+ if (state != BTS_STATE_STOPPED )
310
+ buf = perf_get_aux (& bts -> handle );
311
+
312
+ event -> hw .state |= PERF_HES_STOPPED ;
290
313
291
314
if (flags & PERF_EF_UPDATE ) {
292
315
bts_update (bts );
@@ -296,6 +319,7 @@ static void bts_event_stop(struct perf_event *event, int flags)
296
319
bts -> handle .head =
297
320
local_xchg (& buf -> data_size ,
298
321
buf -> nr_pages << PAGE_SHIFT );
322
+
299
323
perf_aux_output_end (& bts -> handle , local_xchg (& buf -> data_size , 0 ),
300
324
!!local_xchg (& buf -> lost , 0 ));
301
325
}
@@ -310,17 +334,36 @@ static void bts_event_stop(struct perf_event *event, int flags)
310
334
void intel_bts_enable_local (void )
311
335
{
312
336
struct bts_ctx * bts = this_cpu_ptr (& bts_ctx );
337
+ int state = READ_ONCE (bts -> state );
338
+
339
+ /*
340
+ * Here we transition from INACTIVE to ACTIVE;
341
+ * if we instead are STOPPED from the interrupt handler,
342
+ * stay that way. Can't be ACTIVE here though.
343
+ */
344
+ if (WARN_ON_ONCE (state == BTS_STATE_ACTIVE ))
345
+ return ;
346
+
347
+ if (state == BTS_STATE_STOPPED )
348
+ return ;
313
349
314
- if (bts -> handle .event && bts -> started )
350
+ if (bts -> handle .event )
315
351
__bts_event_start (bts -> handle .event );
316
352
}
317
353
318
354
void intel_bts_disable_local (void )
319
355
{
320
356
struct bts_ctx * bts = this_cpu_ptr (& bts_ctx );
321
357
358
+ /*
359
+ * Here we transition from ACTIVE to INACTIVE;
360
+ * do nothing for STOPPED or INACTIVE.
361
+ */
362
+ if (READ_ONCE (bts -> state ) != BTS_STATE_ACTIVE )
363
+ return ;
364
+
322
365
if (bts -> handle .event )
323
- __bts_event_stop (bts -> handle .event );
366
+ __bts_event_stop (bts -> handle .event , BTS_STATE_INACTIVE );
324
367
}
325
368
326
369
static int
@@ -335,8 +378,6 @@ bts_buffer_reset(struct bts_buffer *buf, struct perf_output_handle *handle)
335
378
return 0 ;
336
379
337
380
head = handle -> head & ((buf -> nr_pages << PAGE_SHIFT ) - 1 );
338
- if (WARN_ON_ONCE (head != local_read (& buf -> head )))
339
- return - EINVAL ;
340
381
341
382
phys = & buf -> buf [buf -> cur_buf ];
342
383
space = phys -> offset + phys -> displacement + phys -> size - head ;
@@ -403,41 +444,65 @@ bts_buffer_reset(struct bts_buffer *buf, struct perf_output_handle *handle)
403
444
404
445
int intel_bts_interrupt (void )
405
446
{
447
+ struct debug_store * ds = this_cpu_ptr (& cpu_hw_events )-> ds ;
406
448
struct bts_ctx * bts = this_cpu_ptr (& bts_ctx );
407
449
struct perf_event * event = bts -> handle .event ;
408
450
struct bts_buffer * buf ;
409
451
s64 old_head ;
410
- int err ;
452
+ int err = - ENOSPC , handled = 0 ;
411
453
412
- if (!event || !bts -> started )
413
- return 0 ;
454
+ /*
455
+ * The only surefire way of knowing if this NMI is ours is by checking
456
+ * the write ptr against the PMI threshold.
457
+ */
458
+ if (ds -> bts_index >= ds -> bts_interrupt_threshold )
459
+ handled = 1 ;
460
+
461
+ /*
462
+ * this is wrapped in intel_bts_enable_local/intel_bts_disable_local,
463
+ * so we can only be INACTIVE or STOPPED
464
+ */
465
+ if (READ_ONCE (bts -> state ) == BTS_STATE_STOPPED )
466
+ return handled ;
414
467
415
468
buf = perf_get_aux (& bts -> handle );
469
+ if (!buf )
470
+ return handled ;
471
+
416
472
/*
417
473
* Skip snapshot counters: they don't use the interrupt, but
418
474
* there's no other way of telling, because the pointer will
419
475
* keep moving
420
476
*/
421
- if (! buf || buf -> snapshot )
477
+ if (buf -> snapshot )
422
478
return 0 ;
423
479
424
480
old_head = local_read (& buf -> head );
425
481
bts_update (bts );
426
482
427
483
/* no new data */
428
484
if (old_head == local_read (& buf -> head ))
429
- return 0 ;
485
+ return handled ;
430
486
431
487
perf_aux_output_end (& bts -> handle , local_xchg (& buf -> data_size , 0 ),
432
488
!!local_xchg (& buf -> lost , 0 ));
433
489
434
490
buf = perf_aux_output_begin (& bts -> handle , event );
435
- if (!buf )
436
- return 1 ;
491
+ if (buf )
492
+ err = bts_buffer_reset (buf , & bts -> handle );
493
+
494
+ if (err ) {
495
+ WRITE_ONCE (bts -> state , BTS_STATE_STOPPED );
437
496
438
- err = bts_buffer_reset (buf , & bts -> handle );
439
- if (err )
440
- perf_aux_output_end (& bts -> handle , 0 , false);
497
+ if (buf ) {
498
+ /*
499
+ * BTS_STATE_STOPPED should be visible before
500
+ * cleared handle::event
501
+ */
502
+ barrier ();
503
+ perf_aux_output_end (& bts -> handle , 0 , false);
504
+ }
505
+ }
441
506
442
507
return 1 ;
443
508
}
0 commit comments