@@ -419,6 +419,9 @@ static void pt_config_start(struct perf_event *event)
419419 struct pt * pt = this_cpu_ptr (& pt_ctx );
420420 u64 ctl = event -> hw .aux_config ;
421421
422+ if (READ_ONCE (event -> hw .aux_paused ))
423+ return ;
424+
422425 ctl |= RTIT_CTL_TRACEEN ;
423426 if (READ_ONCE (pt -> vmx_on ))
424427 perf_aux_output_flag (& pt -> handle , PERF_AUX_FLAG_PARTIAL );
@@ -535,7 +538,24 @@ static void pt_config(struct perf_event *event)
535538 reg |= (event -> attr .config & PT_CONFIG_MASK );
536539
537540 event -> hw .aux_config = reg ;
541+
542+ /*
543+ * Allow resume before starting so as not to overwrite a value set by a
544+ * PMI.
545+ */
546+ barrier ();
547+ WRITE_ONCE (pt -> resume_allowed , 1 );
548+ /* Configuration is complete, it is now OK to handle an NMI */
549+ barrier ();
550+ WRITE_ONCE (pt -> handle_nmi , 1 );
551+ barrier ();
538552 pt_config_start (event );
553+ barrier ();
554+ /*
555+ * Allow pause after starting so its pt_config_stop() doesn't race with
556+ * pt_config_start().
557+ */
558+ WRITE_ONCE (pt -> pause_allowed , 1 );
539559}
540560
541561static void pt_config_stop (struct perf_event * event )
@@ -829,11 +849,13 @@ static void pt_buffer_advance(struct pt_buffer *buf)
829849 buf -> cur_idx ++ ;
830850
831851 if (buf -> cur_idx == buf -> cur -> last ) {
832- if (buf -> cur == buf -> last )
852+ if (buf -> cur == buf -> last ) {
833853 buf -> cur = buf -> first ;
834- else
854+ buf -> wrapped = true;
855+ } else {
835856 buf -> cur = list_entry (buf -> cur -> list .next , struct topa ,
836857 list );
858+ }
837859 buf -> cur_idx = 0 ;
838860 }
839861}
@@ -847,8 +869,11 @@ static void pt_buffer_advance(struct pt_buffer *buf)
847869static void pt_update_head (struct pt * pt )
848870{
849871 struct pt_buffer * buf = perf_get_aux (& pt -> handle );
872+ bool wrapped = buf -> wrapped ;
850873 u64 topa_idx , base , old ;
851874
875+ buf -> wrapped = false;
876+
852877 if (buf -> single ) {
853878 local_set (& buf -> data_size , buf -> output_off );
854879 return ;
@@ -866,7 +891,7 @@ static void pt_update_head(struct pt *pt)
866891 } else {
867892 old = (local64_xchg (& buf -> head , base ) &
868893 ((buf -> nr_pages << PAGE_SHIFT ) - 1 ));
869- if (base < old )
894+ if (base < old || ( base == old && wrapped ) )
870895 base += buf -> nr_pages << PAGE_SHIFT ;
871896
872897 local_add (base - old , & buf -> data_size );
@@ -1512,6 +1537,7 @@ void intel_pt_interrupt(void)
15121537 buf = perf_aux_output_begin (& pt -> handle , event );
15131538 if (!buf ) {
15141539 event -> hw .state = PERF_HES_STOPPED ;
1540+ WRITE_ONCE (pt -> resume_allowed , 0 );
15151541 return ;
15161542 }
15171543
@@ -1520,6 +1546,7 @@ void intel_pt_interrupt(void)
15201546 ret = pt_buffer_reset_markers (buf , & pt -> handle );
15211547 if (ret ) {
15221548 perf_aux_output_end (& pt -> handle , 0 );
1549+ WRITE_ONCE (pt -> resume_allowed , 0 );
15231550 return ;
15241551 }
15251552
@@ -1574,6 +1601,26 @@ static void pt_event_start(struct perf_event *event, int mode)
15741601 struct pt * pt = this_cpu_ptr (& pt_ctx );
15751602 struct pt_buffer * buf ;
15761603
1604+ if (mode & PERF_EF_RESUME ) {
1605+ if (READ_ONCE (pt -> resume_allowed )) {
1606+ u64 status ;
1607+
1608+ /*
1609+ * Only if the trace is not active and the error and
1610+ * stopped bits are clear, is it safe to start, but a
1611+ * PMI might have just cleared these, so resume_allowed
1612+ * must be checked again also.
1613+ */
1614+ rdmsrl (MSR_IA32_RTIT_STATUS , status );
1615+ if (!(status & (RTIT_STATUS_TRIGGEREN |
1616+ RTIT_STATUS_ERROR |
1617+ RTIT_STATUS_STOPPED )) &&
1618+ READ_ONCE (pt -> resume_allowed ))
1619+ pt_config_start (event );
1620+ }
1621+ return ;
1622+ }
1623+
15771624 buf = perf_aux_output_begin (& pt -> handle , event );
15781625 if (!buf )
15791626 goto fail_stop ;
@@ -1584,7 +1631,6 @@ static void pt_event_start(struct perf_event *event, int mode)
15841631 goto fail_end_stop ;
15851632 }
15861633
1587- WRITE_ONCE (pt -> handle_nmi , 1 );
15881634 hwc -> state = 0 ;
15891635
15901636 pt_config_buffer (buf );
@@ -1602,13 +1648,28 @@ static void pt_event_stop(struct perf_event *event, int mode)
16021648{
16031649 struct pt * pt = this_cpu_ptr (& pt_ctx );
16041650
1651+ if (mode & PERF_EF_PAUSE ) {
1652+ if (READ_ONCE (pt -> pause_allowed ))
1653+ pt_config_stop (event );
1654+ return ;
1655+ }
1656+
16051657 /*
16061658 * Protect against the PMI racing with disabling wrmsr,
16071659 * see comment in intel_pt_interrupt().
16081660 */
16091661 WRITE_ONCE (pt -> handle_nmi , 0 );
16101662 barrier ();
16111663
1664+ /*
1665+ * Prevent a resume from attempting to restart tracing, or a pause
1666+ * during a subsequent start. Do this after clearing handle_nmi so that
1667+ * pt_event_snapshot_aux() will not re-allow them.
1668+ */
1669+ WRITE_ONCE (pt -> pause_allowed , 0 );
1670+ WRITE_ONCE (pt -> resume_allowed , 0 );
1671+ barrier ();
1672+
16121673 pt_config_stop (event );
16131674
16141675 if (event -> hw .state == PERF_HES_STOPPED )
@@ -1658,6 +1719,10 @@ static long pt_event_snapshot_aux(struct perf_event *event,
16581719 if (WARN_ON_ONCE (!buf -> snapshot ))
16591720 return 0 ;
16601721
1722+ /* Prevent pause/resume from attempting to start/stop tracing */
1723+ WRITE_ONCE (pt -> pause_allowed , 0 );
1724+ WRITE_ONCE (pt -> resume_allowed , 0 );
1725+ barrier ();
16611726 /*
16621727 * There is no PT interrupt in this mode, so stop the trace and it will
16631728 * remain stopped while the buffer is copied.
@@ -1677,8 +1742,13 @@ static long pt_event_snapshot_aux(struct perf_event *event,
16771742 * Here, handle_nmi tells us if the tracing was on.
16781743 * If the tracing was on, restart it.
16791744 */
1680- if (READ_ONCE (pt -> handle_nmi ))
1745+ if (READ_ONCE (pt -> handle_nmi )) {
1746+ WRITE_ONCE (pt -> resume_allowed , 1 );
1747+ barrier ();
16811748 pt_config_start (event );
1749+ barrier ();
1750+ WRITE_ONCE (pt -> pause_allowed , 1 );
1751+ }
16821752
16831753 return ret ;
16841754}
@@ -1794,7 +1864,9 @@ static __init int pt_init(void)
17941864 if (!intel_pt_validate_hw_cap (PT_CAP_topa_multiple_entries ))
17951865 pt_pmu .pmu .capabilities = PERF_PMU_CAP_AUX_NO_SG ;
17961866
1797- pt_pmu .pmu .capabilities |= PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE ;
1867+ pt_pmu .pmu .capabilities |= PERF_PMU_CAP_EXCLUSIVE |
1868+ PERF_PMU_CAP_ITRACE |
1869+ PERF_PMU_CAP_AUX_PAUSE ;
17981870 pt_pmu .pmu .attr_groups = pt_attr_groups ;
17991871 pt_pmu .pmu .task_ctx_nr = perf_sw_context ;
18001872 pt_pmu .pmu .event_init = pt_event_init ;
0 commit comments