@@ -418,6 +418,9 @@ static void pt_config_start(struct perf_event *event)
418
418
struct pt * pt = this_cpu_ptr (& pt_ctx );
419
419
u64 ctl = event -> hw .aux_config ;
420
420
421
+ if (READ_ONCE (event -> hw .aux_paused ))
422
+ return ;
423
+
421
424
ctl |= RTIT_CTL_TRACEEN ;
422
425
if (READ_ONCE (pt -> vmx_on ))
423
426
perf_aux_output_flag (& pt -> handle , PERF_AUX_FLAG_PARTIAL );
@@ -534,7 +537,24 @@ static void pt_config(struct perf_event *event)
534
537
reg |= (event -> attr .config & PT_CONFIG_MASK );
535
538
536
539
event -> hw .aux_config = reg ;
540
+
541
+ /*
542
+ * Allow resume before starting so as not to overwrite a value set by a
543
+ * PMI.
544
+ */
545
+ barrier ();
546
+ WRITE_ONCE (pt -> resume_allowed , 1 );
547
+ /* Configuration is complete, it is now OK to handle an NMI */
548
+ barrier ();
549
+ WRITE_ONCE (pt -> handle_nmi , 1 );
550
+ barrier ();
537
551
pt_config_start (event );
552
+ barrier ();
553
+ /*
554
+ * Allow pause after starting so its pt_config_stop() doesn't race with
555
+ * pt_config_start().
556
+ */
557
+ WRITE_ONCE (pt -> pause_allowed , 1 );
538
558
}
539
559
540
560
static void pt_config_stop (struct perf_event * event )
@@ -1516,6 +1536,7 @@ void intel_pt_interrupt(void)
1516
1536
buf = perf_aux_output_begin (& pt -> handle , event );
1517
1537
if (!buf ) {
1518
1538
event -> hw .state = PERF_HES_STOPPED ;
1539
+ WRITE_ONCE (pt -> resume_allowed , 0 );
1519
1540
return ;
1520
1541
}
1521
1542
@@ -1524,6 +1545,7 @@ void intel_pt_interrupt(void)
1524
1545
ret = pt_buffer_reset_markers (buf , & pt -> handle );
1525
1546
if (ret ) {
1526
1547
perf_aux_output_end (& pt -> handle , 0 );
1548
+ WRITE_ONCE (pt -> resume_allowed , 0 );
1527
1549
return ;
1528
1550
}
1529
1551
@@ -1578,6 +1600,26 @@ static void pt_event_start(struct perf_event *event, int mode)
1578
1600
struct pt * pt = this_cpu_ptr (& pt_ctx );
1579
1601
struct pt_buffer * buf ;
1580
1602
1603
+ if (mode & PERF_EF_RESUME ) {
1604
+ if (READ_ONCE (pt -> resume_allowed )) {
1605
+ u64 status ;
1606
+
1607
+ /*
1608
+ * Only if the trace is not active and the error and
1609
+ * stopped bits are clear, is it safe to start, but a
1610
+ * PMI might have just cleared these, so resume_allowed
1611
+ * must be checked again also.
1612
+ */
1613
+ rdmsrl (MSR_IA32_RTIT_STATUS , status );
1614
+ if (!(status & (RTIT_STATUS_TRIGGEREN |
1615
+ RTIT_STATUS_ERROR |
1616
+ RTIT_STATUS_STOPPED )) &&
1617
+ READ_ONCE (pt -> resume_allowed ))
1618
+ pt_config_start (event );
1619
+ }
1620
+ return ;
1621
+ }
1622
+
1581
1623
buf = perf_aux_output_begin (& pt -> handle , event );
1582
1624
if (!buf )
1583
1625
goto fail_stop ;
@@ -1588,7 +1630,6 @@ static void pt_event_start(struct perf_event *event, int mode)
1588
1630
goto fail_end_stop ;
1589
1631
}
1590
1632
1591
- WRITE_ONCE (pt -> handle_nmi , 1 );
1592
1633
hwc -> state = 0 ;
1593
1634
1594
1635
pt_config_buffer (buf );
@@ -1606,13 +1647,28 @@ static void pt_event_stop(struct perf_event *event, int mode)
1606
1647
{
1607
1648
struct pt * pt = this_cpu_ptr (& pt_ctx );
1608
1649
1650
+ if (mode & PERF_EF_PAUSE ) {
1651
+ if (READ_ONCE (pt -> pause_allowed ))
1652
+ pt_config_stop (event );
1653
+ return ;
1654
+ }
1655
+
1609
1656
/*
1610
1657
* Protect against the PMI racing with disabling wrmsr,
1611
1658
* see comment in intel_pt_interrupt().
1612
1659
*/
1613
1660
WRITE_ONCE (pt -> handle_nmi , 0 );
1614
1661
barrier ();
1615
1662
1663
+ /*
1664
+ * Prevent a resume from attempting to restart tracing, or a pause
1665
+ * during a subsequent start. Do this after clearing handle_nmi so that
1666
+ * pt_event_snapshot_aux() will not re-allow them.
1667
+ */
1668
+ WRITE_ONCE (pt -> pause_allowed , 0 );
1669
+ WRITE_ONCE (pt -> resume_allowed , 0 );
1670
+ barrier ();
1671
+
1616
1672
pt_config_stop (event );
1617
1673
1618
1674
if (event -> hw .state == PERF_HES_STOPPED )
@@ -1662,6 +1718,10 @@ static long pt_event_snapshot_aux(struct perf_event *event,
1662
1718
if (WARN_ON_ONCE (!buf -> snapshot ))
1663
1719
return 0 ;
1664
1720
1721
+ /* Prevent pause/resume from attempting to start/stop tracing */
1722
+ WRITE_ONCE (pt -> pause_allowed , 0 );
1723
+ WRITE_ONCE (pt -> resume_allowed , 0 );
1724
+ barrier ();
1665
1725
/*
1666
1726
* There is no PT interrupt in this mode, so stop the trace and it will
1667
1727
* remain stopped while the buffer is copied.
@@ -1681,8 +1741,13 @@ static long pt_event_snapshot_aux(struct perf_event *event,
1681
1741
* Here, handle_nmi tells us if the tracing was on.
1682
1742
* If the tracing was on, restart it.
1683
1743
*/
1684
- if (READ_ONCE (pt -> handle_nmi ))
1744
+ if (READ_ONCE (pt -> handle_nmi )) {
1745
+ WRITE_ONCE (pt -> resume_allowed , 1 );
1746
+ barrier ();
1685
1747
pt_config_start (event );
1748
+ barrier ();
1749
+ WRITE_ONCE (pt -> pause_allowed , 1 );
1750
+ }
1686
1751
1687
1752
return ret ;
1688
1753
}
@@ -1798,7 +1863,9 @@ static __init int pt_init(void)
1798
1863
if (!intel_pt_validate_hw_cap (PT_CAP_topa_multiple_entries ))
1799
1864
pt_pmu .pmu .capabilities = PERF_PMU_CAP_AUX_NO_SG ;
1800
1865
1801
- pt_pmu .pmu .capabilities |= PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE ;
1866
+ pt_pmu .pmu .capabilities |= PERF_PMU_CAP_EXCLUSIVE |
1867
+ PERF_PMU_CAP_ITRACE |
1868
+ PERF_PMU_CAP_AUX_PAUSE ;
1802
1869
pt_pmu .pmu .attr_groups = pt_attr_groups ;
1803
1870
pt_pmu .pmu .task_ctx_nr = perf_sw_context ;
1804
1871
pt_pmu .pmu .event_init = pt_event_init ;
0 commit comments