@@ -80,11 +80,21 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
return;
}
-static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
+static int __tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
{
+ int rc;
+
CS_UNLOCK(drvdata->base);
tmc_flush_and_stop(drvdata);
+
+ rc = tmc_wait_for_tmcready(drvdata);
+ if (rc) {
+ dev_err(&drvdata->csdev->dev,
+ "Failed to disable : TMC is not ready\n");
+ CS_LOCK(drvdata->base);
+ return rc;
+ }
/*
* When operating in sysFS mode the content of the buffer needs to be
* read before the TMC is disabled.
@@ -94,6 +104,7 @@ static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
tmc_disable_hw(drvdata);
CS_LOCK(drvdata->base);
+ return 0;
}
static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
@@ -650,7 +661,9 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
ret = -EINVAL;
goto out;
}
- __tmc_etb_disable_hw(drvdata);
+ ret = __tmc_etb_disable_hw(drvdata);
+ if (ret)
+ goto out;
}
drvdata->reading = true;
@@ -1135,11 +1135,21 @@ static void tmc_etr_sync_sysfs_buf(struct tmc_drvdata *drvdata)
}
}
-static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
+static int __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
{
+ int rc;
+
CS_UNLOCK(drvdata->base);
tmc_flush_and_stop(drvdata);
+
+ rc = tmc_wait_for_tmcready(drvdata);
+ if (rc) {
+ dev_err(&drvdata->csdev->dev,
+ "Failed to disable : TMC is not ready\n");
+ CS_LOCK(drvdata->base);
+ return rc;
+ }
/*
* When operating in sysFS mode the content of the buffer needs to be
* read before the TMC is disabled.
@@ -1150,7 +1160,7 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
tmc_disable_hw(drvdata);
CS_LOCK(drvdata->base);
-
+ return 0;
}
void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
@@ -1779,9 +1789,11 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
}
/* Disable the TMC if we are trying to read from a running session. */
- if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
- __tmc_etr_disable_hw(drvdata);
-
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
+ ret = __tmc_etr_disable_hw(drvdata);
+ if (ret)
+ goto out;
+ }
drvdata->reading = true;
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
When multiple ETMs are enabled simultaneously, the time required to complete a flush in the process of reading the TMC device node may exceed the default wait time of 100us. If the TMC capture is stopped while any ETM has not completed its flush, it can cause the corresponding CPU to hang. Fix the by checking the TMCReady bit after the flush. If TMCReady bit is set, TraceCaptEn bit can be clear; otherwise, return directly and stop the TMC read. Signed-off-by: Yuanfang Zhang <quic_yuanfang@quicinc.com> --- drivers/hwtracing/coresight/coresight-tmc-etf.c | 17 +++++++++++++++-- drivers/hwtracing/coresight/coresight-tmc-etr.c | 22 +++++++++++++++++----- 2 files changed, 32 insertions(+), 7 deletions(-) --- base-commit: fac04efc5c793dccbd07e2d59af9f90b7fc0dca4 change-id: 20250103-fix_cpu_hung-b5a95179ada4 Best regards,