@@ -482,6 +482,8 @@ static u64 pt_config_filters(struct perf_event *event)
482
482
483
483
static void pt_config (struct perf_event * event )
484
484
{
485
+ struct pt * pt = this_cpu_ptr (& pt_ctx );
486
+ struct pt_buffer * buf = perf_get_aux (& pt -> handle );
485
487
u64 reg ;
486
488
487
489
/* First round: clear STATUS, in particular the PSB byte counter. */
@@ -491,7 +493,9 @@ static void pt_config(struct perf_event *event)
491
493
}
492
494
493
495
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 ;
495
499
496
500
/*
497
501
* 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)
543
547
wmb ();
544
548
}
545
549
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
-
558
550
/**
559
551
* struct topa - ToPA metadata
560
552
* @list: linkage to struct pt_buffer's list of tables
@@ -612,6 +604,26 @@ static inline phys_addr_t topa_pfn(struct topa *topa)
612
604
#define TOPA_ENTRY_SIZE (t , i ) (sizes(TOPA_ENTRY((t), (i))->size))
613
605
#define TOPA_ENTRY_PAGES (t , i ) (1 << TOPA_ENTRY((t), (i))->size)
614
606
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
+
615
627
/**
616
628
* topa_alloc() - allocate page-sized ToPA table
617
629
* @cpu: CPU on which to allocate.
@@ -812,6 +824,11 @@ static void pt_update_head(struct pt *pt)
812
824
struct pt_buffer * buf = perf_get_aux (& pt -> handle );
813
825
u64 topa_idx , base , old ;
814
826
827
+ if (buf -> single ) {
828
+ local_set (& buf -> data_size , buf -> output_off );
829
+ return ;
830
+ }
831
+
815
832
/* offset of the first region in this table from the beginning of buf */
816
833
base = buf -> cur -> offset + buf -> output_off ;
817
834
@@ -913,18 +930,21 @@ static void pt_handle_status(struct pt *pt)
913
930
*/
914
931
static void pt_read_offset (struct pt_buffer * buf )
915
932
{
916
- u64 offset , base_topa ;
933
+ u64 offset , base ;
917
934
struct topa_page * tp ;
918
935
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
+ }
922
941
923
942
rdmsrl (MSR_IA32_RTIT_OUTPUT_MASK , offset );
924
943
/* offset within current output region */
925
944
buf -> output_off = offset >> 32 ;
926
945
/* 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 ;
928
948
}
929
949
930
950
static struct topa_entry *
@@ -1040,6 +1060,9 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf,
1040
1060
unsigned long head = local64_read (& buf -> head );
1041
1061
unsigned long idx , npages , wakeup ;
1042
1062
1063
+ if (buf -> single )
1064
+ return 0 ;
1065
+
1043
1066
/* can't stop in the middle of an output region */
1044
1067
if (buf -> output_off + handle -> size + 1 < pt_buffer_region_size (buf )) {
1045
1068
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)
1121
1144
if (buf -> snapshot )
1122
1145
head &= (buf -> nr_pages << PAGE_SHIFT ) - 1 ;
1123
1146
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 );
1126
1150
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
+ }
1131
1158
1132
1159
local64_set (& buf -> head , head );
1133
1160
local_set (& buf -> data_size , 0 );
@@ -1141,6 +1168,9 @@ static void pt_buffer_fini_topa(struct pt_buffer *buf)
1141
1168
{
1142
1169
struct topa * topa , * iter ;
1143
1170
1171
+ if (buf -> single )
1172
+ return ;
1173
+
1144
1174
list_for_each_entry_safe (topa , iter , & buf -> tables , list ) {
1145
1175
/*
1146
1176
* 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,
1186
1216
return 0 ;
1187
1217
}
1188
1218
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
+
1189
1249
/**
1190
1250
* pt_buffer_setup_aux() - set up topa tables for a PT buffer
1191
1251
* @cpu: Cpu on which to allocate, -1 means current.
@@ -1230,6 +1290,10 @@ pt_buffer_setup_aux(struct perf_event *event, void **pages,
1230
1290
1231
1291
INIT_LIST_HEAD (& buf -> tables );
1232
1292
1293
+ ret = pt_buffer_try_single (buf , nr_pages );
1294
+ if (!ret )
1295
+ return buf ;
1296
+
1233
1297
ret = pt_buffer_init_topa (buf , cpu , nr_pages , GFP_KERNEL );
1234
1298
if (ret ) {
1235
1299
kfree (buf );
@@ -1396,8 +1460,7 @@ void intel_pt_interrupt(void)
1396
1460
return ;
1397
1461
}
1398
1462
1399
- pt_config_buffer (topa_to_page (buf -> cur )-> table , buf -> cur_idx ,
1400
- buf -> output_off );
1463
+ pt_config_buffer (buf );
1401
1464
pt_config_start (event );
1402
1465
}
1403
1466
}
@@ -1461,8 +1524,7 @@ static void pt_event_start(struct perf_event *event, int mode)
1461
1524
WRITE_ONCE (pt -> handle_nmi , 1 );
1462
1525
hwc -> state = 0 ;
1463
1526
1464
- pt_config_buffer (topa_to_page (buf -> cur )-> table , buf -> cur_idx ,
1465
- buf -> output_off );
1527
+ pt_config_buffer (buf );
1466
1528
pt_config (event );
1467
1529
1468
1530
return ;
0 commit comments