mirror of
https://github.com/torvalds/linux.git
synced 2025-04-12 16:47:42 +00:00
coresight-etm4x: add isb() before reading the TRCSTATR
As recommended by section 4.3.7 ("Synchronization when using system instructions to progrom the trace unit") of ARM IHI 0064H.b, the self-hosted trace analyzer must perform a Context synchronization event between writing to the TRCPRGCTLR and reading the TRCSTATR. Additionally, add an ISB between the each read of TRCSTATR on coresight_timeout() when using system instructions to program the trace unit. Fixes: 1ab3bb9df5e3 ("coresight: etm4x: Add necessary synchronization for sysreg access") Signed-off-by: Yuanfang Zhang <quic_yuanfang@quicinc.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Link: https://lore.kernel.org/r/20250116-etm_sync-v4-1-39f2b05e9514@quicinc.com
This commit is contained in:
parent
cade8a89b1
commit
4ff6039ffb
@ -1093,18 +1093,20 @@ static void coresight_remove_conns(struct coresight_device *csdev)
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_timeout - loop until a bit has changed to a specific register
|
||||
* state.
|
||||
* coresight_timeout_action - loop until a bit has changed to a specific register
|
||||
* state, with a callback after every trial.
|
||||
* @csa: coresight device access for the device
|
||||
* @offset: Offset of the register from the base of the device.
|
||||
* @position: the position of the bit of interest.
|
||||
* @value: the value the bit should have.
|
||||
* @cb: Call back after each trial.
|
||||
*
|
||||
* Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
|
||||
* TIMEOUT_US has elapsed, which ever happens first.
|
||||
*/
|
||||
int coresight_timeout(struct csdev_access *csa, u32 offset,
|
||||
int position, int value)
|
||||
int coresight_timeout_action(struct csdev_access *csa, u32 offset,
|
||||
int position, int value,
|
||||
coresight_timeout_cb_t cb)
|
||||
{
|
||||
int i;
|
||||
u32 val;
|
||||
@ -1120,7 +1122,8 @@ int coresight_timeout(struct csdev_access *csa, u32 offset,
|
||||
if (!(val & BIT(position)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cb)
|
||||
cb(csa, offset, position, value);
|
||||
/*
|
||||
* Delay is arbitrary - the specification doesn't say how long
|
||||
* we are expected to wait. Extra check required to make sure
|
||||
@ -1132,6 +1135,13 @@ int coresight_timeout(struct csdev_access *csa, u32 offset,
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_timeout_action);
|
||||
|
||||
int coresight_timeout(struct csdev_access *csa, u32 offset,
|
||||
int position, int value)
|
||||
{
|
||||
return coresight_timeout_action(csa, offset, position, value, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_timeout);
|
||||
|
||||
u32 coresight_relaxed_read32(struct coresight_device *csdev, u32 offset)
|
||||
|
@ -427,6 +427,29 @@ static void etm4_check_arch_features(struct etmv4_drvdata *drvdata,
|
||||
}
|
||||
#endif /* CONFIG_ETM4X_IMPDEF_FEATURE */
|
||||
|
||||
static void etm4x_sys_ins_barrier(struct csdev_access *csa, u32 offset, int pos, int val)
|
||||
{
|
||||
if (!csa->io_mem)
|
||||
isb();
|
||||
}
|
||||
|
||||
/*
|
||||
* etm4x_wait_status: Poll for TRCSTATR.<pos> == <val>. While using system
|
||||
* instruction to access the trace unit, each access must be separated by a
|
||||
* synchronization barrier. See ARM IHI0064H.b section "4.3.7 Synchronization of
|
||||
* register updates", for system instructions section, in "Notes":
|
||||
*
|
||||
* "In particular, whenever disabling or enabling the trace unit, a poll of
|
||||
* TRCSTATR needs explicit synchronization between each read of TRCSTATR"
|
||||
*/
|
||||
static int etm4x_wait_status(struct csdev_access *csa, int pos, int val)
|
||||
{
|
||||
if (!csa->io_mem)
|
||||
return coresight_timeout_action(csa, TRCSTATR, pos, val,
|
||||
etm4x_sys_ins_barrier);
|
||||
return coresight_timeout(csa, TRCSTATR, pos, val);
|
||||
}
|
||||
|
||||
static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
|
||||
{
|
||||
int i, rc;
|
||||
@ -458,7 +481,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
|
||||
isb();
|
||||
|
||||
/* wait for TRCSTATR.IDLE to go up */
|
||||
if (coresight_timeout(csa, TRCSTATR, TRCSTATR_IDLE_BIT, 1))
|
||||
if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 1))
|
||||
dev_err(etm_dev,
|
||||
"timeout while waiting for Idle Trace Status\n");
|
||||
if (drvdata->nr_pe)
|
||||
@ -551,7 +574,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
|
||||
isb();
|
||||
|
||||
/* wait for TRCSTATR.IDLE to go back down to '0' */
|
||||
if (coresight_timeout(csa, TRCSTATR, TRCSTATR_IDLE_BIT, 0))
|
||||
if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 0))
|
||||
dev_err(etm_dev,
|
||||
"timeout while waiting for Idle Trace Status\n");
|
||||
|
||||
@ -940,10 +963,25 @@ static void etm4_disable_hw(void *info)
|
||||
tsb_csync();
|
||||
etm4x_relaxed_write32(csa, control, TRCPRGCTLR);
|
||||
|
||||
/*
|
||||
* As recommended by section 4.3.7 ("Synchronization when using system
|
||||
* instructions to progrom the trace unit") of ARM IHI 0064H.b, the
|
||||
* self-hosted trace analyzer must perform a Context synchronization
|
||||
* event between writing to the TRCPRGCTLR and reading the TRCSTATR.
|
||||
*/
|
||||
if (!csa->io_mem)
|
||||
isb();
|
||||
|
||||
/* wait for TRCSTATR.PMSTABLE to go to '1' */
|
||||
if (coresight_timeout(csa, TRCSTATR, TRCSTATR_PMSTABLE_BIT, 1))
|
||||
if (etm4x_wait_status(csa, TRCSTATR_PMSTABLE_BIT, 1))
|
||||
dev_err(etm_dev,
|
||||
"timeout while waiting for PM stable Trace Status\n");
|
||||
/*
|
||||
* As recommended by section 4.3.7 (Synchronization of register updates)
|
||||
* of ARM IHI 0064H.b.
|
||||
*/
|
||||
isb();
|
||||
|
||||
/* read the status of the single shot comparators */
|
||||
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
|
||||
config->ss_status[i] =
|
||||
@ -1745,7 +1783,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
|
||||
etm4_os_lock(drvdata);
|
||||
|
||||
/* wait for TRCSTATR.PMSTABLE to go up */
|
||||
if (coresight_timeout(csa, TRCSTATR, TRCSTATR_PMSTABLE_BIT, 1)) {
|
||||
if (etm4x_wait_status(csa, TRCSTATR_PMSTABLE_BIT, 1)) {
|
||||
dev_err(etm_dev,
|
||||
"timeout while waiting for PM Stable Status\n");
|
||||
etm4_os_unlock(drvdata);
|
||||
@ -1836,7 +1874,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
|
||||
state->trcpdcr = etm4x_read32(csa, TRCPDCR);
|
||||
|
||||
/* wait for TRCSTATR.IDLE to go up */
|
||||
if (coresight_timeout(csa, TRCSTATR, TRCSTATR_IDLE_BIT, 1)) {
|
||||
if (etm4x_wait_status(csa, TRCSTATR_PMSTABLE_BIT, 1)) {
|
||||
dev_err(etm_dev,
|
||||
"timeout while waiting for Idle Trace Status\n");
|
||||
etm4_os_unlock(drvdata);
|
||||
|
@ -661,6 +661,10 @@ extern int coresight_enable_sysfs(struct coresight_device *csdev);
|
||||
extern void coresight_disable_sysfs(struct coresight_device *csdev);
|
||||
extern int coresight_timeout(struct csdev_access *csa, u32 offset,
|
||||
int position, int value);
|
||||
typedef void (*coresight_timeout_cb_t) (struct csdev_access *, u32, int, int);
|
||||
extern int coresight_timeout_action(struct csdev_access *csa, u32 offset,
|
||||
int position, int value,
|
||||
coresight_timeout_cb_t cb);
|
||||
|
||||
extern int coresight_claim_device(struct coresight_device *csdev);
|
||||
extern int coresight_claim_device_unlocked(struct coresight_device *csdev);
|
||||
|
Loading…
x
Reference in New Issue
Block a user