coresight: etm4x: Save restore TRFCR_EL1
authorSuzuki K Poulose <suzuki.poulose@arm.com>
Tue, 14 Sep 2021 10:26:32 +0000 (11:26 +0100)
committerMathieu Poirier <mathieu.poirier@linaro.org>
Wed, 27 Oct 2021 17:45:16 +0000 (11:45 -0600)
When the CPU enters a low power mode, the TRFCR_EL1 contents could be
reset. Thus we need to save/restore the TRFCR_EL1 along with the ETM4x
registers to allow the tracing.

The TRFCR related helpers are in a new header file, as we need to use
them for TRBE in the later patches.

Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
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/20210914102641.1852544-2-suzuki.poulose@arm.com
[Fixed cosmetic details]
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
drivers/hwtracing/coresight/coresight-etm4x-core.c
drivers/hwtracing/coresight/coresight-etm4x.h
drivers/hwtracing/coresight/coresight-self-hosted-trace.h [new file with mode: 0644]

index e24252e..537c0d7 100644 (file)
@@ -40,6 +40,7 @@
 #include "coresight-etm4x.h"
 #include "coresight-etm-perf.h"
 #include "coresight-etm4x-cfg.h"
+#include "coresight-self-hosted-trace.h"
 #include "coresight-syscfg.h"
 
 static int boot_enable;
@@ -1011,7 +1012,7 @@ static void cpu_enable_tracing(struct etmv4_drvdata *drvdata)
        if (is_kernel_in_hyp_mode())
                trfcr |= TRFCR_EL2_CX;
 
-       write_sysreg_s(trfcr, SYS_TRFCR_EL1);
+       write_trfcr(trfcr);
 }
 
 static void etm4_init_arch_data(void *info)
@@ -1554,7 +1555,7 @@ static void etm4_init_trace_id(struct etmv4_drvdata *drvdata)
        drvdata->trcid = coresight_get_trace_id(drvdata->cpu);
 }
 
-static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
+static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
 {
        int i, ret = 0;
        struct etmv4_save_state *state;
@@ -1693,7 +1694,23 @@ out:
        return ret;
 }
 
-static void etm4_cpu_restore(struct etmv4_drvdata *drvdata)
+static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
+{
+       int ret = 0;
+
+       /* Save the TRFCR irrespective of whether the ETM is ON */
+       if (drvdata->trfc)
+               drvdata->save_trfcr = read_trfcr();
+       /*
+        * Save and restore the ETM Trace registers only if
+        * the ETM is active.
+        */
+       if (local_read(&drvdata->mode) && drvdata->save_state)
+               ret = __etm4_cpu_save(drvdata);
+       return ret;
+}
+
+static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
 {
        int i;
        struct etmv4_save_state *state = drvdata->save_state;
@@ -1789,6 +1806,14 @@ static void etm4_cpu_restore(struct etmv4_drvdata *drvdata)
        etm4_cs_lock(drvdata, csa);
 }
 
+static void etm4_cpu_restore(struct etmv4_drvdata *drvdata)
+{
+       if (drvdata->trfc)
+               write_trfcr(drvdata->save_trfcr);
+       if (drvdata->state_needs_restore)
+               __etm4_cpu_restore(drvdata);
+}
+
 static int etm4_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
                              void *v)
 {
@@ -1800,23 +1825,17 @@ static int etm4_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
 
        drvdata = etmdrvdata[cpu];
 
-       if (!drvdata->save_state)
-               return NOTIFY_OK;
-
        if (WARN_ON_ONCE(drvdata->cpu != cpu))
                return NOTIFY_BAD;
 
        switch (cmd) {
        case CPU_PM_ENTER:
-               /* save the state if self-hosted coresight is in use */
-               if (local_read(&drvdata->mode))
-                       if (etm4_cpu_save(drvdata))
-                               return NOTIFY_BAD;
+               if (etm4_cpu_save(drvdata))
+                       return NOTIFY_BAD;
                break;
        case CPU_PM_EXIT:
        case CPU_PM_ENTER_FAILED:
-               if (drvdata->state_needs_restore)
-                       etm4_cpu_restore(drvdata);
+               etm4_cpu_restore(drvdata);
                break;
        default:
                return NOTIFY_DONE;
index e5b79bd..82cba16 100644 (file)
@@ -921,6 +921,7 @@ struct etmv4_save_state {
  * @lpoverride:        If the implementation can support low-power state over.
  * @trfc:      If the implementation supports Arm v8.4 trace filter controls.
  * @config:    structure holding configuration parameters.
+ * @save_trfcr:        Saved TRFCR_EL1 register during a CPU PM event.
  * @save_state:        State to be preserved across power loss
  * @state_needs_restore: True when there is context to restore after PM exit
  * @skip_power_up: Indicates if an implementation can skip powering up
@@ -973,6 +974,7 @@ struct etmv4_drvdata {
        bool                            lpoverride;
        bool                            trfc;
        struct etmv4_config             config;
+       u64                             save_trfcr;
        struct etmv4_save_state         *save_state;
        bool                            state_needs_restore;
        bool                            skip_power_up;
diff --git a/drivers/hwtracing/coresight/coresight-self-hosted-trace.h b/drivers/hwtracing/coresight/coresight-self-hosted-trace.h
new file mode 100644 (file)
index 0000000..303d719
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Arm v8 Self-Hosted trace support.
+ *
+ * Copyright (C) 2021 ARM Ltd.
+ */
+
+#ifndef __CORESIGHT_SELF_HOSTED_TRACE_H
+#define __CORESIGHT_SELF_HOSTED_TRACE_H
+
+#include <asm/sysreg.h>
+
+static inline u64 read_trfcr(void)
+{
+       return read_sysreg_s(SYS_TRFCR_EL1);
+}
+
+static inline void write_trfcr(u64 val)
+{
+       write_sysreg_s(val, SYS_TRFCR_EL1);
+       isb();
+}
+
+#endif /*  __CORESIGHT_SELF_HOSTED_TRACE_H */