@@ -89,14 +89,22 @@ struct trbe_buf {
89
89
* - Not duplicating the detection logic
90
90
* - Streamlined detection of erratum across the system
91
91
*/
92
+ #define TRBE_WORKAROUND_OVERWRITE_FILL_MODE 0
92
93
93
94
static int trbe_errata_cpucaps [] = {
95
+ [TRBE_WORKAROUND_OVERWRITE_FILL_MODE ] = ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE ,
94
96
-1 , /* Sentinel, must be the last entry */
95
97
};
96
98
97
99
/* The total number of listed errata in trbe_errata_cpucaps */
98
100
#define TRBE_ERRATA_MAX (ARRAY_SIZE(trbe_errata_cpucaps) - 1)
99
101
102
+ /*
103
+ * Safe limit for the number of bytes that may be overwritten
104
+ * when ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE is triggered.
105
+ */
106
+ #define TRBE_WORKAROUND_OVERWRITE_FILL_MODE_SKIP_BYTES 256
107
+
100
108
/*
101
109
* struct trbe_cpudata: TRBE instance specific data
102
110
* @trbe_flag - TRBE dirty/access flag support
@@ -147,6 +155,11 @@ static inline bool trbe_has_erratum(struct trbe_cpudata *cpudata, int i)
147
155
return (i < TRBE_ERRATA_MAX ) && test_bit (i , cpudata -> errata );
148
156
}
149
157
158
+ static inline bool trbe_may_overwrite_in_fill_mode (struct trbe_cpudata * cpudata )
159
+ {
160
+ return trbe_has_erratum (cpudata , TRBE_WORKAROUND_OVERWRITE_FILL_MODE );
161
+ }
162
+
150
163
static int trbe_alloc_node (struct perf_event * event )
151
164
{
152
165
if (event -> cpu == -1 )
@@ -550,10 +563,13 @@ static void trbe_enable_hw(struct trbe_buf *buf)
550
563
set_trbe_limit_pointer_enabled (buf -> trbe_limit );
551
564
}
552
565
553
- static enum trbe_fault_action trbe_get_fault_act (u64 trbsr )
566
+ static enum trbe_fault_action trbe_get_fault_act (struct perf_output_handle * handle ,
567
+ u64 trbsr )
554
568
{
555
569
int ec = get_trbe_ec (trbsr );
556
570
int bsc = get_trbe_bsc (trbsr );
571
+ struct trbe_buf * buf = etm_perf_sink_config (handle );
572
+ struct trbe_cpudata * cpudata = buf -> cpudata ;
557
573
558
574
WARN_ON (is_trbe_running (trbsr ));
559
575
if (is_trbe_trg (trbsr ) || is_trbe_abort (trbsr ))
@@ -562,10 +578,16 @@ static enum trbe_fault_action trbe_get_fault_act(u64 trbsr)
562
578
if ((ec == TRBE_EC_STAGE1_ABORT ) || (ec == TRBE_EC_STAGE2_ABORT ))
563
579
return TRBE_FAULT_ACT_FATAL ;
564
580
565
- if (is_trbe_wrap (trbsr ) && (ec == TRBE_EC_OTHERS ) && (bsc == TRBE_BSC_FILLED )) {
566
- if (get_trbe_write_pointer () == get_trbe_base_pointer ())
567
- return TRBE_FAULT_ACT_WRAP ;
568
- }
581
+ /*
582
+ * If the trbe is affected by TRBE_WORKAROUND_OVERWRITE_FILL_MODE,
583
+ * it might write data after a WRAP event in the fill mode.
584
+ * Thus the check TRBPTR == TRBBASER will not be honored.
585
+ */
586
+ if ((is_trbe_wrap (trbsr ) && (ec == TRBE_EC_OTHERS ) && (bsc == TRBE_BSC_FILLED )) &&
587
+ (trbe_may_overwrite_in_fill_mode (cpudata ) ||
588
+ get_trbe_write_pointer () == get_trbe_base_pointer ()))
589
+ return TRBE_FAULT_ACT_WRAP ;
590
+
569
591
return TRBE_FAULT_ACT_SPURIOUS ;
570
592
}
571
593
@@ -574,6 +596,8 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
574
596
{
575
597
u64 write ;
576
598
u64 start_off , end_off ;
599
+ u64 size ;
600
+ u64 overwrite_skip = TRBE_WORKAROUND_OVERWRITE_FILL_MODE_SKIP_BYTES ;
577
601
578
602
/*
579
603
* If the TRBE has wrapped around the write pointer has
@@ -594,7 +618,18 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
594
618
595
619
if (WARN_ON_ONCE (end_off < start_off ))
596
620
return 0 ;
597
- return (end_off - start_off );
621
+
622
+ size = end_off - start_off ;
623
+ /*
624
+ * If the TRBE is affected by the following erratum, we must fill
625
+ * the space we skipped with IGNORE packets. And we are always
626
+ * guaranteed to have at least a PAGE_SIZE space in the buffer.
627
+ */
628
+ if (trbe_has_erratum (buf -> cpudata , TRBE_WORKAROUND_OVERWRITE_FILL_MODE ) &&
629
+ !WARN_ON (size < overwrite_skip ))
630
+ __trbe_pad_buf (buf , start_off , overwrite_skip );
631
+
632
+ return size ;
598
633
}
599
634
600
635
static void * arm_trbe_alloc_buffer (struct coresight_device * csdev ,
@@ -713,7 +748,7 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
713
748
clr_trbe_irq ();
714
749
isb ();
715
750
716
- act = trbe_get_fault_act (status );
751
+ act = trbe_get_fault_act (handle , status );
717
752
/*
718
753
* If this was not due to a WRAP event, we have some
719
754
* errors and as such buffer is empty.
@@ -737,21 +772,117 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
737
772
return size ;
738
773
}
739
774
775
+
776
+ static int trbe_apply_work_around_before_enable (struct trbe_buf * buf )
777
+ {
778
+ /*
779
+ * TRBE_WORKAROUND_OVERWRITE_FILL_MODE causes the TRBE to overwrite a few cache
780
+ * line size from the "TRBBASER_EL1" in the event of a "FILL".
781
+ * Thus, we could loose some amount of the trace at the base.
782
+ *
783
+ * Before Fix:
784
+ *
785
+ * normal-BASE head (normal-TRBPTR) tail (normal-LIMIT)
786
+ * | \/ /
787
+ * -------------------------------------------------------------
788
+ * | Pg0 | Pg1 | | | PgN |
789
+ * -------------------------------------------------------------
790
+ *
791
+ * In the normal course of action, we would set the TRBBASER to the
792
+ * beginning of the ring-buffer (normal-BASE). But with the erratum,
793
+ * the TRBE could overwrite the contents at the "normal-BASE", after
794
+ * hitting the "normal-LIMIT", since it doesn't stop as expected. And
795
+ * this is wrong. This could result in overwriting trace collected in
796
+ * one of the previous runs, being consumed by the user. So we must
797
+ * always make sure that the TRBBASER is within the region
798
+ * [head, head+size]. Note that TRBBASER must be PAGE aligned,
799
+ *
800
+ * After moving the BASE:
801
+ *
802
+ * normal-BASE head (normal-TRBPTR) tail (normal-LIMIT)
803
+ * | \/ /
804
+ * -------------------------------------------------------------
805
+ * | | |xyzdef. |.. tuvw| |
806
+ * -------------------------------------------------------------
807
+ * /
808
+ * New-BASER
809
+ *
810
+ * Also, we would set the TRBPTR to head (after adjusting for
811
+ * alignment) at normal-PTR. This would mean that the last few bytes
812
+ * of the trace (say, "xyz") might overwrite the first few bytes of
813
+ * trace written ("abc"). More importantly they will appear in what
814
+ * userspace sees as the beginning of the trace, which is wrong. We may
815
+ * not always have space to move the latest trace "xyz" to the correct
816
+ * order as it must appear beyond the LIMIT. (i.e, [head..head+size]).
817
+ * Thus it is easier to ignore those bytes than to complicate the
818
+ * driver to move it, assuming that the erratum was triggered and
819
+ * doing additional checks to see if there is indeed allowed space at
820
+ * TRBLIMITR.LIMIT.
821
+ *
822
+ * Thus the full workaround will move the BASE and the PTR and would
823
+ * look like (after padding at the skipped bytes at the end of
824
+ * session) :
825
+ *
826
+ * normal-BASE head (normal-TRBPTR) tail (normal-LIMIT)
827
+ * | \/ /
828
+ * -------------------------------------------------------------
829
+ * | | |///abc.. |.. rst| |
830
+ * -------------------------------------------------------------
831
+ * / |
832
+ * New-BASER New-TRBPTR
833
+ *
834
+ * To summarize, with the work around:
835
+ *
836
+ * - We always align the offset for the next session to PAGE_SIZE
837
+ * (This is to ensure we can program the TRBBASER to this offset
838
+ * within the region [head...head+size]).
839
+ *
840
+ * - At TRBE enable:
841
+ * - Set the TRBBASER to the page aligned offset of the current
842
+ * proposed write offset. (which is guaranteed to be aligned
843
+ * as above)
844
+ * - Move the TRBPTR to skip first 256bytes (that might be
845
+ * overwritten with the erratum). This ensures that the trace
846
+ * generated in the session is not re-written.
847
+ *
848
+ * - At trace collection:
849
+ * - Pad the 256bytes skipped above again with IGNORE packets.
850
+ */
851
+ if (trbe_has_erratum (buf -> cpudata , TRBE_WORKAROUND_OVERWRITE_FILL_MODE )) {
852
+ if (WARN_ON (!IS_ALIGNED (buf -> trbe_write , PAGE_SIZE )))
853
+ return - EINVAL ;
854
+ buf -> trbe_hw_base = buf -> trbe_write ;
855
+ buf -> trbe_write += TRBE_WORKAROUND_OVERWRITE_FILL_MODE_SKIP_BYTES ;
856
+ }
857
+
858
+ return 0 ;
859
+ }
860
+
740
861
static int __arm_trbe_enable (struct trbe_buf * buf ,
741
862
struct perf_output_handle * handle )
742
863
{
864
+ int ret = 0 ;
865
+
743
866
perf_aux_output_flag (handle , PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW );
744
867
buf -> trbe_limit = compute_trbe_buffer_limit (handle );
745
868
buf -> trbe_write = buf -> trbe_base + PERF_IDX2OFF (handle -> head , buf );
746
869
if (buf -> trbe_limit == buf -> trbe_base ) {
747
- trbe_stop_and_truncate_event ( handle ) ;
748
- return - ENOSPC ;
870
+ ret = - ENOSPC ;
871
+ goto err ;
749
872
}
750
873
/* Set the base of the TRBE to the buffer base */
751
874
buf -> trbe_hw_base = buf -> trbe_base ;
875
+
876
+ ret = trbe_apply_work_around_before_enable (buf );
877
+ if (ret )
878
+ goto err ;
879
+
752
880
* this_cpu_ptr (buf -> cpudata -> drvdata -> handle ) = handle ;
753
881
trbe_enable_hw (buf );
754
882
return 0 ;
883
+ err :
884
+ trbe_stop_and_truncate_event (handle );
885
+ return ret ;
755
886
}
756
887
757
888
static int arm_trbe_enable (struct coresight_device * csdev , u32 mode , void * data )
@@ -891,7 +1022,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
891
1022
if (!is_perf_trbe (handle ))
892
1023
return IRQ_NONE ;
893
1024
894
- act = trbe_get_fault_act (status );
1025
+ act = trbe_get_fault_act (handle , status );
895
1026
switch (act ) {
896
1027
case TRBE_FAULT_ACT_WRAP :
897
1028
truncated = !!trbe_handle_overflow (handle );
@@ -1043,7 +1174,22 @@ static void arm_trbe_probe_cpu(void *info)
1043
1174
*/
1044
1175
trbe_check_errata (cpudata );
1045
1176
1046
- cpudata -> trbe_align = cpudata -> trbe_hw_align ;
1177
+ /*
1178
+ * If the TRBE is affected by erratum TRBE_WORKAROUND_OVERWRITE_FILL_MODE,
1179
+ * we must always program the TBRPTR_EL1, 256bytes from a page
1180
+ * boundary, with TRBBASER_EL1 set to the page, to prevent
1181
+ * TRBE over-writing 256bytes at TRBBASER_EL1 on FILL event.
1182
+ *
1183
+ * Thus make sure we always align our write pointer to a PAGE_SIZE,
1184
+ * which also guarantees that we have at least a PAGE_SIZE space in
1185
+ * the buffer (TRBLIMITR is PAGE aligned) and thus we can skip
1186
+ * the required bytes at the base.
1187
+ */
1188
+ if (trbe_may_overwrite_in_fill_mode (cpudata ))
1189
+ cpudata -> trbe_align = PAGE_SIZE ;
1190
+ else
1191
+ cpudata -> trbe_align = cpudata -> trbe_hw_align ;
1192
+
1047
1193
cpudata -> trbe_flag = get_trbe_flag_update (trbidr );
1048
1194
cpudata -> cpu = cpu ;
1049
1195
cpudata -> drvdata = drvdata ;
0 commit comments