intel_th: Add switch triggering support
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>
Fri, 3 May 2019 08:44:48 +0000 (11:44 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 May 2019 16:16:21 +0000 (18:16 +0200)
Add support for asserting window switch trigger when tracing to MSU output
ports. This allows for software controlled switching between windows of
the MSU buffer, which can be used for double buffering while exporting the
trace data further from the MSU.

Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/hwtracing/intel_th/core.c
drivers/hwtracing/intel_th/gth.c
drivers/hwtracing/intel_th/gth.h
drivers/hwtracing/intel_th/intel_th.h

index 390031d..033dce5 100644 (file)
@@ -430,9 +430,9 @@ static const struct intel_th_subdevice {
                .nres   = 1,
                .res    = {
                        {
-                               /* Handle TSCU from GTH driver */
+                               /* Handle TSCU and CTS from GTH driver */
                                .start  = REG_GTH_OFFSET,
-                               .end    = REG_TSCU_OFFSET + REG_TSCU_LENGTH - 1,
+                               .end    = REG_CTS_OFFSET + REG_CTS_LENGTH - 1,
                                .flags  = IORESOURCE_MEM,
                        },
                },
@@ -988,6 +988,27 @@ int intel_th_trace_enable(struct intel_th_device *thdev)
 EXPORT_SYMBOL_GPL(intel_th_trace_enable);
 
 /**
+ * intel_th_trace_switch() - execute a switch sequence
+ * @thdev:     output device that requests tracing switch
+ */
+int intel_th_trace_switch(struct intel_th_device *thdev)
+{
+       struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
+       struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
+
+       if (WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH))
+               return -EINVAL;
+
+       if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
+               return -EINVAL;
+
+       hubdrv->trig_switch(hub, &thdev->output);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(intel_th_trace_switch);
+
+/**
  * intel_th_trace_disable() - disable tracing for an output device
  * @thdev:     output device that requests tracing be disabled
  */
index a879445..fa9d34a 100644 (file)
@@ -308,6 +308,11 @@ static int intel_th_gth_reset(struct gth_device *gth)
        iowrite32(0, gth->base + REG_GTH_SCR);
        iowrite32(0xfc, gth->base + REG_GTH_SCR2);
 
+       /* setup CTS for single trigger */
+       iowrite32(CTS_EVENT_ENABLE_IF_ANYTHING, gth->base + REG_CTS_C0S0_EN);
+       iowrite32(CTS_ACTION_CONTROL_SET_STATE(CTS_STATE_IDLE) |
+                 CTS_ACTION_CONTROL_TRIGGER, gth->base + REG_CTS_C0S0_ACT);
+
        return 0;
 }
 
@@ -595,6 +600,37 @@ static void intel_th_gth_enable(struct intel_th_device *thdev,
 }
 
 /**
+ * intel_th_gth_switch() - execute a switch sequence
+ * @thdev:     GTH device
+ * @output:    output device's descriptor
+ *
+ * This will execute a switch sequence that will trigger a switch window
+ * when tracing to MSC in multi-block mode.
+ */
+static void intel_th_gth_switch(struct intel_th_device *thdev,
+                               struct intel_th_output *output)
+{
+       struct gth_device *gth = dev_get_drvdata(&thdev->dev);
+       unsigned long count;
+       u32 reg;
+
+       /* trigger */
+       iowrite32(0, gth->base + REG_CTS_CTL);
+       iowrite32(CTS_CTL_SEQUENCER_ENABLE, gth->base + REG_CTS_CTL);
+       /* wait on trigger status */
+       for (reg = 0, count = CTS_TRIG_WAITLOOP_DEPTH;
+            count && !(reg & BIT(4)); count--) {
+               reg = ioread32(gth->base + REG_CTS_STAT);
+               cpu_relax();
+       }
+       if (!count)
+               dev_dbg(&thdev->dev, "timeout waiting for CTS Trigger\n");
+
+       intel_th_gth_stop(gth, output, false);
+       intel_th_gth_start(gth, output);
+}
+
+/**
  * intel_th_gth_assign() - assign output device to a GTH output port
  * @thdev:     GTH device
  * @othdev:    output device
@@ -777,6 +813,7 @@ static struct intel_th_driver intel_th_gth_driver = {
        .unassign       = intel_th_gth_unassign,
        .set_output     = intel_th_gth_set_output,
        .enable         = intel_th_gth_enable,
+       .trig_switch    = intel_th_gth_switch,
        .disable        = intel_th_gth_disable,
        .driver = {
                .name   = "gth",
index 6f2b0b9..bfcc0fd 100644 (file)
@@ -49,6 +49,12 @@ enum {
        REG_GTH_SCRPD3          = 0xec, /* ScratchPad[3] */
        REG_TSCU_TSUCTRL        = 0x2000, /* TSCU control register */
        REG_TSCU_TSCUSTAT       = 0x2004, /* TSCU status register */
+
+       /* Common Capture Sequencer (CTS) registers */
+       REG_CTS_C0S0_EN         = 0x30c0, /* clause_event_enable_c0s0 */
+       REG_CTS_C0S0_ACT        = 0x3180, /* clause_action_control_c0s0 */
+       REG_CTS_STAT            = 0x32a0, /* cts_status */
+       REG_CTS_CTL             = 0x32a4, /* cts_control */
 };
 
 /* waiting for Pipeline Empty bit(s) to assert for GTH */
@@ -57,4 +63,17 @@ enum {
 #define TSUCTRL_CTCRESYNC      BIT(0)
 #define TSCUSTAT_CTCSYNCING    BIT(1)
 
+/* waiting for Trigger status to assert for CTS */
+#define CTS_TRIG_WAITLOOP_DEPTH        10000
+
+#define CTS_EVENT_ENABLE_IF_ANYTHING   BIT(31)
+#define CTS_ACTION_CONTROL_STATE_OFF   27
+#define CTS_ACTION_CONTROL_SET_STATE(x)        \
+       (((x) & 0x1f) << CTS_ACTION_CONTROL_STATE_OFF)
+#define CTS_ACTION_CONTROL_TRIGGER     BIT(4)
+
+#define CTS_STATE_IDLE                 0x10u
+
+#define CTS_CTL_SEQUENCER_ENABLE       BIT(0)
+
 #endif /* __INTEL_TH_GTH_H__ */
index 74a6a40..0df4800 100644 (file)
@@ -164,6 +164,8 @@ struct intel_th_driver {
                                            struct intel_th_device *othdev);
        void                    (*enable)(struct intel_th_device *thdev,
                                          struct intel_th_output *output);
+       void                    (*trig_switch)(struct intel_th_device *thdev,
+                                              struct intel_th_output *output);
        void                    (*disable)(struct intel_th_device *thdev,
                                           struct intel_th_output *output);
        /* output ops */
@@ -228,6 +230,7 @@ int intel_th_driver_register(struct intel_th_driver *thdrv);
 void intel_th_driver_unregister(struct intel_th_driver *thdrv);
 
 int intel_th_trace_enable(struct intel_th_device *thdev);
+int intel_th_trace_switch(struct intel_th_device *thdev);
 int intel_th_trace_disable(struct intel_th_device *thdev);
 int intel_th_set_output(struct intel_th_device *thdev,
                        unsigned int master);
@@ -308,6 +311,9 @@ enum {
        REG_TSCU_OFFSET         = 0x2000,
        REG_TSCU_LENGTH         = 0x1000,
 
+       REG_CTS_OFFSET          = 0x3000,
+       REG_CTS_LENGTH          = 0x1000,
+
        /* Software Trace Hub (STH) [0x4000..0x4fff] */
        REG_STH_OFFSET          = 0x4000,
        REG_STH_LENGTH          = 0x2000,