coresight: trbe: Prohibit trace before disabling TRBE

When the TRBE generates an IRQ, we stop the TRBE, collect the trace
and then reprogram the TRBE with the updated buffer pointers, whenever
possible. We might also leave the TRBE disabled, if there is not
enough space left in the buffer. However, we do not touch the ETE at
all during all of this. This means the ETE is only disabled when
the event is disabled later (via irq_work). This is incorrect, as the
ETE trace is still ON without actually being captured and may be routed
to the ATB (even if it is for a short duration).

So, we move the CPU into trace prohibited state always before disabling
the TRBE, upon entering the IRQ handler. The state is restored if the
TRBE is enabled back. Otherwise the trace remains prohibited.

Since, the ETM/ETE driver now controls the TRFCR_EL1 per session, the
tracing can be restored/enabled back when the event is rescheduled
in.

Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Leo Yan <leo.yan@linaro.org>
Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20210923143919.2944311-6-suzuki.poulose@arm.com
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
This commit is contained in:
Suzuki K Poulose 2021-09-23 15:39:19 +01:00 committed by Mathieu Poirier
parent 9bef9d0850
commit dcfecfa444
2 changed files with 12 additions and 1 deletions

View File

@ -21,11 +21,13 @@ static inline void write_trfcr(u64 val)
isb(); isb();
} }
static inline void cpu_prohibit_trace(void) static inline u64 cpu_prohibit_trace(void)
{ {
u64 trfcr = read_trfcr(); u64 trfcr = read_trfcr();
/* Prohibit tracing at EL0 & the kernel EL */ /* Prohibit tracing at EL0 & the kernel EL */
write_trfcr(trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE)); write_trfcr(trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE));
/* Return the original value of the TRFCR */
return trfcr;
} }
#endif /* __CORESIGHT_SELF_HOSTED_TRACE_H */ #endif /* __CORESIGHT_SELF_HOSTED_TRACE_H */

View File

@ -16,6 +16,7 @@
#define pr_fmt(fmt) DRVNAME ": " fmt #define pr_fmt(fmt) DRVNAME ": " fmt
#include <asm/barrier.h> #include <asm/barrier.h>
#include "coresight-self-hosted-trace.h"
#include "coresight-trbe.h" #include "coresight-trbe.h"
#define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages << PAGE_SHIFT)) #define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages << PAGE_SHIFT))
@ -775,6 +776,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
enum trbe_fault_action act; enum trbe_fault_action act;
u64 status; u64 status;
bool truncated = false; bool truncated = false;
u64 trfcr;
/* Reads to TRBSR_EL1 is fine when TRBE is active */ /* Reads to TRBSR_EL1 is fine when TRBE is active */
status = read_sysreg_s(SYS_TRBSR_EL1); status = read_sysreg_s(SYS_TRBSR_EL1);
@ -785,6 +787,8 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
if (!is_trbe_irq(status)) if (!is_trbe_irq(status))
return IRQ_NONE; return IRQ_NONE;
/* Prohibit the CPU from tracing before we disable the TRBE */
trfcr = cpu_prohibit_trace();
/* /*
* Ensure the trace is visible to the CPUs and * Ensure the trace is visible to the CPUs and
* any external aborts have been resolved. * any external aborts have been resolved.
@ -816,9 +820,14 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
/* /*
* If the buffer was truncated, ensure perf callbacks * If the buffer was truncated, ensure perf callbacks
* have completed, which will disable the event. * have completed, which will disable the event.
*
* Otherwise, restore the trace filter controls to
* allow the tracing.
*/ */
if (truncated) if (truncated)
irq_work_run(); irq_work_run();
else
write_trfcr(trfcr);
return IRQ_HANDLED; return IRQ_HANDLED;
} }