@@ -482,6 +482,8 @@ static u64 pt_config_filters(struct perf_event *event)
482482
483483static void pt_config (struct perf_event * event )
484484{
485+ struct pt * pt = this_cpu_ptr (& pt_ctx );
486+ struct pt_buffer * buf = perf_get_aux (& pt -> handle );
485487 u64 reg ;
486488
487489 /* First round: clear STATUS, in particular the PSB byte counter. */
@@ -491,7 +493,9 @@ static void pt_config(struct perf_event *event)
491493 }
492494
493495 reg = pt_config_filters (event );
494- reg |= RTIT_CTL_TOPA | RTIT_CTL_TRACEEN ;
496+ reg |= RTIT_CTL_TRACEEN ;
497+ if (!buf -> single )
498+ reg |= RTIT_CTL_TOPA ;
495499
496500 /*
497501 * Previously, we had BRANCH_EN on by default, but now that PT has
@@ -543,18 +547,6 @@ static void pt_config_stop(struct perf_event *event)
543547 wmb ();
544548}
545549
546- static void pt_config_buffer (void * buf , unsigned int topa_idx ,
547- unsigned int output_off )
548- {
549- u64 reg ;
550-
551- wrmsrl (MSR_IA32_RTIT_OUTPUT_BASE , virt_to_phys (buf ));
552-
553- reg = 0x7f | ((u64 )topa_idx << 7 ) | ((u64 )output_off << 32 );
554-
555- wrmsrl (MSR_IA32_RTIT_OUTPUT_MASK , reg );
556- }
557-
558550/**
559551 * struct topa - ToPA metadata
560552 * @list: linkage to struct pt_buffer's list of tables
@@ -612,6 +604,26 @@ static inline phys_addr_t topa_pfn(struct topa *topa)
612604#define TOPA_ENTRY_SIZE (t , i ) (sizes(TOPA_ENTRY((t), (i))->size))
613605#define TOPA_ENTRY_PAGES (t , i ) (1 << TOPA_ENTRY((t), (i))->size)
614606
607+ static void pt_config_buffer (struct pt_buffer * buf )
608+ {
609+ u64 reg , mask ;
610+ void * base ;
611+
612+ if (buf -> single ) {
613+ base = buf -> data_pages [0 ];
614+ mask = (buf -> nr_pages * PAGE_SIZE - 1 ) >> 7 ;
615+ } else {
616+ base = topa_to_page (buf -> cur )-> table ;
617+ mask = (u64 )buf -> cur_idx ;
618+ }
619+
620+ wrmsrl (MSR_IA32_RTIT_OUTPUT_BASE , virt_to_phys (base ));
621+
622+ reg = 0x7f | (mask << 7 ) | ((u64 )buf -> output_off << 32 );
623+
624+ wrmsrl (MSR_IA32_RTIT_OUTPUT_MASK , reg );
625+ }
626+
615627/**
616628 * topa_alloc() - allocate page-sized ToPA table
617629 * @cpu: CPU on which to allocate.
@@ -812,6 +824,11 @@ static void pt_update_head(struct pt *pt)
812824 struct pt_buffer * buf = perf_get_aux (& pt -> handle );
813825 u64 topa_idx , base , old ;
814826
827+ if (buf -> single ) {
828+ local_set (& buf -> data_size , buf -> output_off );
829+ return ;
830+ }
831+
815832 /* offset of the first region in this table from the beginning of buf */
816833 base = buf -> cur -> offset + buf -> output_off ;
817834
@@ -913,18 +930,21 @@ static void pt_handle_status(struct pt *pt)
913930 */
914931static void pt_read_offset (struct pt_buffer * buf )
915932{
916- u64 offset , base_topa ;
933+ u64 offset , base ;
917934 struct topa_page * tp ;
918935
919- rdmsrl (MSR_IA32_RTIT_OUTPUT_BASE , base_topa );
920- tp = phys_to_virt (base_topa );
921- buf -> cur = & tp -> topa ;
936+ if (!buf -> single ) {
937+ rdmsrl (MSR_IA32_RTIT_OUTPUT_BASE , base );
938+ tp = phys_to_virt (base );
939+ buf -> cur = & tp -> topa ;
940+ }
922941
923942 rdmsrl (MSR_IA32_RTIT_OUTPUT_MASK , offset );
924943 /* offset within current output region */
925944 buf -> output_off = offset >> 32 ;
926945 /* index of current output region within this table */
927- buf -> cur_idx = (offset & 0xffffff80 ) >> 7 ;
946+ if (!buf -> single )
947+ buf -> cur_idx = (offset & 0xffffff80 ) >> 7 ;
928948}
929949
930950static struct topa_entry *
@@ -1040,6 +1060,9 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf,
10401060 unsigned long head = local64_read (& buf -> head );
10411061 unsigned long idx , npages , wakeup ;
10421062
1063+ if (buf -> single )
1064+ return 0 ;
1065+
10431066 /* can't stop in the middle of an output region */
10441067 if (buf -> output_off + handle -> size + 1 < pt_buffer_region_size (buf )) {
10451068 perf_aux_output_flag (handle , PERF_AUX_FLAG_TRUNCATED );
@@ -1121,13 +1144,17 @@ static void pt_buffer_reset_offsets(struct pt_buffer *buf, unsigned long head)
11211144 if (buf -> snapshot )
11221145 head &= (buf -> nr_pages << PAGE_SHIFT ) - 1 ;
11231146
1124- pg = (head >> PAGE_SHIFT ) & (buf -> nr_pages - 1 );
1125- te = pt_topa_entry_for_page (buf , pg );
1147+ if (!buf -> single ) {
1148+ pg = (head >> PAGE_SHIFT ) & (buf -> nr_pages - 1 );
1149+ te = pt_topa_entry_for_page (buf , pg );
11261150
1127- cur_tp = topa_entry_to_page (te );
1128- buf -> cur = & cur_tp -> topa ;
1129- buf -> cur_idx = te - TOPA_ENTRY (buf -> cur , 0 );
1130- buf -> output_off = head & (pt_buffer_region_size (buf ) - 1 );
1151+ cur_tp = topa_entry_to_page (te );
1152+ buf -> cur = & cur_tp -> topa ;
1153+ buf -> cur_idx = te - TOPA_ENTRY (buf -> cur , 0 );
1154+ buf -> output_off = head & (pt_buffer_region_size (buf ) - 1 );
1155+ } else {
1156+ buf -> output_off = head ;
1157+ }
11311158
11321159 local64_set (& buf -> head , head );
11331160 local_set (& buf -> data_size , 0 );
@@ -1141,6 +1168,9 @@ static void pt_buffer_fini_topa(struct pt_buffer *buf)
11411168{
11421169 struct topa * topa , * iter ;
11431170
1171+ if (buf -> single )
1172+ return ;
1173+
11441174 list_for_each_entry_safe (topa , iter , & buf -> tables , list ) {
11451175 /*
11461176 * right now, this is in free_aux() path only, so
@@ -1186,6 +1216,36 @@ static int pt_buffer_init_topa(struct pt_buffer *buf, int cpu,
11861216 return 0 ;
11871217}
11881218
1219+ static int pt_buffer_try_single (struct pt_buffer * buf , int nr_pages )
1220+ {
1221+ struct page * p = virt_to_page (buf -> data_pages [0 ]);
1222+ int ret = - ENOTSUPP , order = 0 ;
1223+
1224+ /*
1225+ * We can use single range output mode
1226+ * + in snapshot mode, where we don't need interrupts;
1227+ * + if the hardware supports it;
1228+ * + if the entire buffer is one contiguous allocation.
1229+ */
1230+ if (!buf -> snapshot )
1231+ goto out ;
1232+
1233+ if (!intel_pt_validate_hw_cap (PT_CAP_single_range_output ))
1234+ goto out ;
1235+
1236+ if (PagePrivate (p ))
1237+ order = page_private (p );
1238+
1239+ if (1 << order != nr_pages )
1240+ goto out ;
1241+
1242+ buf -> single = true;
1243+ buf -> nr_pages = nr_pages ;
1244+ ret = 0 ;
1245+ out :
1246+ return ret ;
1247+ }
1248+
11891249/**
11901250 * pt_buffer_setup_aux() - set up topa tables for a PT buffer
11911251 * @cpu: Cpu on which to allocate, -1 means current.
@@ -1230,6 +1290,10 @@ pt_buffer_setup_aux(struct perf_event *event, void **pages,
12301290
12311291 INIT_LIST_HEAD (& buf -> tables );
12321292
1293+ ret = pt_buffer_try_single (buf , nr_pages );
1294+ if (!ret )
1295+ return buf ;
1296+
12331297 ret = pt_buffer_init_topa (buf , cpu , nr_pages , GFP_KERNEL );
12341298 if (ret ) {
12351299 kfree (buf );
@@ -1396,8 +1460,7 @@ void intel_pt_interrupt(void)
13961460 return ;
13971461 }
13981462
1399- pt_config_buffer (topa_to_page (buf -> cur )-> table , buf -> cur_idx ,
1400- buf -> output_off );
1463+ pt_config_buffer (buf );
14011464 pt_config_start (event );
14021465 }
14031466}
@@ -1461,8 +1524,7 @@ static void pt_event_start(struct perf_event *event, int mode)
14611524 WRITE_ONCE (pt -> handle_nmi , 1 );
14621525 hwc -> state = 0 ;
14631526
1464- pt_config_buffer (topa_to_page (buf -> cur )-> table , buf -> cur_idx ,
1465- buf -> output_off );
1527+ pt_config_buffer (buf );
14661528 pt_config (event );
14671529
14681530 return ;
0 commit comments