ARM: etm: Add sysfs entry to enable timestamps if supported
Arve Hjønnevåg [Tue, 3 Apr 2012 00:20:32 +0000 (17:20 -0700)]
Change-Id: Iff964ba2f6236ed81863e02ec7b3ec9fbc48044a
Signed-off-by: Arve Hjønnevåg <arve@android.com>

arch/arm/include/asm/hardware/coresight.h
arch/arm/kernel/etm.c

index 0fad8f8..42059d3 100644 (file)
 #define TRACER_RUNNING_BIT     1
 #define TRACER_CYCLE_ACC_BIT   2
 #define TRACER_TRACE_DATA_BIT  3
+#define TRACER_TIMESTAMP_BIT   4
 #define TRACER_ACCESSED                BIT(TRACER_ACCESSED_BIT)
 #define TRACER_RUNNING         BIT(TRACER_RUNNING_BIT)
 #define TRACER_CYCLE_ACC       BIT(TRACER_CYCLE_ACC_BIT)
 #define TRACER_TRACE_DATA      BIT(TRACER_TRACE_DATA_BIT)
+#define TRACER_TIMESTAMP       BIT(TRACER_TIMESTAMP_BIT)
 
 #define TRACER_TIMEOUT 10000
 
@@ -57,6 +59,7 @@
 #define ETMCTRL_DATA_DO_BOTH   (ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR)
 #define ETMCTRL_BRANCH_OUTPUT  (1 << 8)
 #define ETMCTRL_CYCLEACCURATE  (1 << 12)
+#define ETMCTRL_TIMESTAMP_EN   (1 << 28)
 
 /* ETM configuration code register */
 #define ETMR_CONFCODE          (0x04)
 
 #define ETMR_ID                        0x1e4
 #define ETMIDR_VERSION(x)      (((x) >> 4) & 0xff)
+#define ETMIDR_VERSION_3_1     0x21
 #define ETMIDR_VERSION_PFT_1_0 0x30
 
+#define ETMR_CCE               0x1e8
+#define ETMCCER_TIMESTAMPING_IMPLEMENTED       BIT(22)
+
 #define ETMR_TRACEIDR          0x200
 
 /* ETM management registers, "ETM Architecture", 3.5.24 */
index e42b706..460a7d8 100644 (file)
@@ -116,6 +116,9 @@ static int trace_start_etm(struct tracectx *t, int id)
        if (t->flags & TRACER_TRACE_DATA)
                v |= ETMCTRL_DATA_DO_ADDR;
 
+       if (t->flags & TRACER_TIMESTAMP)
+               v |= ETMCTRL_TIMESTAMP_EN;
+
        etm_unlock(t, id);
 
        etm_writel(t, id, v, ETMR_CTRL);
@@ -647,6 +650,36 @@ static ssize_t trace_mode_store(struct kobject *kobj,
 static struct kobj_attribute trace_mode_attr =
        __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
 
+static ssize_t trace_timestamp_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 char *buf)
+{
+       return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_TIMESTAMP));
+}
+
+static ssize_t trace_timestamp_store(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  const char *buf, size_t n)
+{
+       unsigned int timestamp;
+
+       if (sscanf(buf, "%u", &timestamp) != 1)
+               return -EINVAL;
+
+       mutex_lock(&tracer.mutex);
+       if (timestamp)
+               tracer.flags |= TRACER_TIMESTAMP;
+       else
+               tracer.flags &= ~TRACER_TIMESTAMP;
+       mutex_unlock(&tracer.mutex);
+
+       return n;
+}
+
+static struct kobj_attribute trace_timestamp_attr =
+       __ATTR(trace_timestamp, 0644,
+               trace_timestamp_show, trace_timestamp_store);
+
 static ssize_t trace_range_show(struct kobject *kobj,
                                  struct kobj_attribute *attr,
                                  char *buf)
@@ -726,6 +759,7 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id
        int new_count;
        u32 etmccr;
        u32 etmidr;
+       u32 etmccer = 0;
        u8 etm_version = 0;
 
        mutex_lock(&t->mutex);
@@ -766,6 +800,8 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id
        if (etmccr & ETMCCR_ETMIDR_PRESENT) {
                etmidr = etm_readl(t, t->etm_regs_count, ETMR_ID);
                etm_version = ETMIDR_VERSION(etmidr);
+               if (etm_version >= ETMIDR_VERSION_3_1)
+                       etmccer = etm_readl(t, t->etm_regs_count, ETMR_CCE);
        }
        etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL);
        etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR);
@@ -785,6 +821,14 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id
        if (ret)
                dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
 
+       if (etmccer & ETMCCER_TIMESTAMPING_IMPLEMENTED) {
+               ret = sysfs_create_file(&dev->dev.kobj,
+                                       &trace_timestamp_attr.attr);
+               if (ret)
+                       dev_dbg(&dev->dev,
+                               "Failed to create trace_timestamp in sysfs\n");
+       }
+
        ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
        if (ret)
                dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");