]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
coresight-etm4x: add isb() before reading the TRCSTATR
authorYuanfang Zhang <quic_yuanfang@quicinc.com>
Thu, 16 Jan 2025 09:04:20 +0000 (17:04 +0800)
committerSuzuki K Poulose <suzuki.poulose@arm.com>
Wed, 26 Feb 2025 11:25:05 +0000 (11:25 +0000)
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
drivers/hwtracing/coresight/coresight-core.c
drivers/hwtracing/coresight/coresight-etm4x-core.c
include/linux/coresight.h

index ab55e10d4b7983ec00fec3fb5b47bca98a6a5687..48bfb80369246b9400e83eb29f8de5eb54e707a8 100644 (file)
@@ -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)
index bdb9262798cc9c79f010d1033368e95f061cede0..335fa157f30fda4e0c7aaa316a6051a5e0e03f33 100644 (file)
@@ -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);
index 3eef4e91df3fe8eeab885c8be97be58f37d697ae..c7614ccb32325ea1ae0a6ac794597fe5b6cb53d1 100644 (file)
@@ -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);