2012-06-13 02:03:03

by John Stultz

[permalink] [raw]
Subject: [PATCH 00/15][RFC] Android ETM driver changes

The Android kernel tree has a number of changes to the ETM driver.
Arve sent the first 9 of these to the list over a year ago and
got very little response.

I didn't want these to get lost, so I pinged Alexander about
these privately and he stated that he wasn't actively
maintaining the driver, but after skimming the entire set
acked the series and suggested I send it on to Russel for
review and possible inclusion.

So here they are. Please let me know if there are any
objections to merging these, or if further changes are
needed.


CC: Russell King <[email protected]>
CC: Paul Gortmaker <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Arve Hjønnevåg <[email protected]>

Arve Hjønnevåg (15):
ARM: etm: Don't require clock control
ARM: etm: Don't limit tracing to only non-secure code.
ARM: etm: Don't try to clear the buffer full status after reading the
buffer
ARM: etm: Allow range selection
ARM: etm: Configure data tracing
ARM: etm: Add some missing locks and error checks
ARM: etm: Return the entire trace buffer if it is empty after reset
ARM: etm: Support multiple ETMs/PTMs.
ARM: etm: Power down etm(s) when tracing is not enabled
ARM: etm: Wait for etm/ptm(s) to stop before requesting PowerDown
ARM: etm: Check arch version and disable data tracing for ptm
ARM: etm: Add sysfs entry to enable timestamps if supported
ARM: etm: Add sysfs entry to set context-id-size
ARM: etm: Add sysfs entry to disable branch_output flag
ARM: etm: Add sysfs entry to enable return stack if supported

arch/arm/include/asm/hardware/coresight.h | 50 ++-
arch/arm/kernel/etm.c | 680 +++++++++++++++++++++++------
2 files changed, 587 insertions(+), 143 deletions(-)

--
1.7.3.2.146.gca209


2012-06-13 02:01:50

by John Stultz

[permalink] [raw]
Subject: [PATCH 02/15] ARM: etm: Don't limit tracing to only non-secure code.

From: Arve Hjønnevåg <[email protected]>

On some systems kernel code is considered secure, and this code
already limits tracing to the kernel text segment which results
in no trace data.

CC: Russell King <[email protected]>
CC: Paul Gortmaker <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Mathieu Poirier <[email protected]>

Acked-by: Alexander Shishkin <[email protected]>
Signed-off-by: Arve Hjønnevåg <[email protected]>
Signed-off-by: John Stultz <[email protected]>
---
arch/arm/kernel/etm.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index bd295e8..d7622f9 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -56,7 +56,7 @@ static inline bool trace_isrunning(struct tracectx *t)
static int etm_setup_address_range(struct tracectx *t, int n,
unsigned long start, unsigned long end, int exclude, int data)
{
- u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_NSONLY | \
+ u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY |
ETMAAT_NOVALCMP;

if (n < 1 || n > t->ncmppairs)
--
1.7.3.2.146.gca209

2012-06-13 02:01:52

by John Stultz

[permalink] [raw]
Subject: [PATCH 08/15] ARM: etm: Support multiple ETMs/PTMs.

From: Arve Hjønnevåg <[email protected]>

If more than one ETM or PTM are present, configure all of them
and enable the formatter in the ETB. This allows tracing on dual
core systems (e.g. omap4).

CC: Russell King <[email protected]>
CC: Paul Gortmaker <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Mathieu Poirier <[email protected]>

Acked-by: Alexander Shishkin <[email protected]>
Signed-off-by: Arve Hjønnevåg <[email protected]>
Signed-off-by: John Stultz <[email protected]>
---
arch/arm/include/asm/hardware/coresight.h | 16 ++-
arch/arm/kernel/etm.c | 234 +++++++++++++++++++----------
2 files changed, 166 insertions(+), 84 deletions(-)

diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h
index 6ea507f..6643d6c 100644
--- a/arch/arm/include/asm/hardware/coresight.h
+++ b/arch/arm/include/asm/hardware/coresight.h
@@ -25,9 +25,9 @@

#define TRACER_TIMEOUT 10000

-#define etm_writel(t, v, x) \
- (__raw_writel((v), (t)->etm_regs + (x)))
-#define etm_readl(t, x) (__raw_readl((t)->etm_regs + (x)))
+#define etm_writel(t, id, v, x) \
+ (__raw_writel((v), (t)->etm_regs[(id)] + (x)))
+#define etm_readl(t, id, x) (__raw_readl((t)->etm_regs[(id)] + (x)))

/* CoreSight Management Registers */
#define CSMR_LOCKACCESS 0xfb0
@@ -126,6 +126,8 @@
ETMCTRL_BRANCH_OUTPUT | \
ETMCTRL_DO_CONTEXTID)

+#define ETMR_TRACEIDR 0x200
+
/* ETM management registers, "ETM Architecture", 3.5.24 */
#define ETMMR_OSLAR 0x300
#define ETMMR_OSLSR 0x304
@@ -148,14 +150,16 @@
#define ETBFF_TRIGIN BIT(8)
#define ETBFF_TRIGEVT BIT(9)
#define ETBFF_TRIGFL BIT(10)
+#define ETBFF_STOPFL BIT(12)

#define etb_writel(t, v, x) \
(__raw_writel((v), (t)->etb_regs + (x)))
#define etb_readl(t, x) (__raw_readl((t)->etb_regs + (x)))

-#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0)
-#define etm_unlock(t) \
- do { etm_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
+#define etm_lock(t, id) \
+ do { etm_writel((t), (id), 0, CSMR_LOCKACCESS); } while (0)
+#define etm_unlock(t, id) \
+ do { etm_writel((t), (id), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)

#define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0)
#define etb_unlock(t) \
diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index 74444e5..e3309ea 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/clk.h>
@@ -37,10 +38,12 @@ MODULE_AUTHOR("Alexander Shishkin");
struct tracectx {
unsigned int etb_bufsz;
void __iomem *etb_regs;
- void __iomem *etm_regs;
+ void __iomem **etm_regs;
+ int etm_regs_count;
unsigned long flags;
int ncmppairs;
int etm_portsz;
+ u32 etb_fc;
unsigned long range_start;
unsigned long range_end;
unsigned long data_range_start;
@@ -61,7 +64,7 @@ static inline bool trace_isrunning(struct tracectx *t)
return !!(t->flags & TRACER_RUNNING);
}

-static int etm_setup_address_range(struct tracectx *t, int n,
+static int etm_setup_address_range(struct tracectx *t, int id, int n,
unsigned long start, unsigned long end, int exclude, int data)
{
u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY |
@@ -80,41 +83,31 @@ static int etm_setup_address_range(struct tracectx *t, int n,
flags |= ETMAAT_IEXEC;

/* first comparator for the range */
- etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
- etm_writel(t, start, ETMR_COMP_VAL(n * 2));
+ etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2));
+ etm_writel(t, id, start, ETMR_COMP_VAL(n * 2));

/* second comparator is right next to it */
- etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
- etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
+ etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
+ etm_writel(t, id, end, ETMR_COMP_VAL(n * 2 + 1));

if (data) {
flags = exclude ? ETMVDC3_EXCLONLY : 0;
if (exclude)
n += 8;
- etm_writel(t, flags | BIT(n), ETMR_VIEWDATACTRL3);
+ etm_writel(t, id, flags | BIT(n), ETMR_VIEWDATACTRL3);
} else {
flags = exclude ? ETMTE_INCLEXCL : 0;
- etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
+ etm_writel(t, id, flags | (1 << n), ETMR_TRACEENCTRL);
}

return 0;
}

-static int trace_start(struct tracectx *t)
+static int trace_start_etm(struct tracectx *t, int id)
{
u32 v;
unsigned long timeout = TRACER_TIMEOUT;

- etb_unlock(t);
-
- t->dump_initial_etb = false;
- etb_writel(t, 0, ETBR_WRITEADDR);
- etb_writel(t, 0, ETBR_FORMATTERCTRL);
- etb_writel(t, 1, ETBR_CTRL);
-
- etb_lock(t);
-
- /* configure etm */
v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);

if (t->flags & TRACER_CYCLE_ACC)
@@ -123,79 +116,122 @@ static int trace_start(struct tracectx *t)
if (t->flags & TRACER_TRACE_DATA)
v |= ETMCTRL_DATA_DO_ADDR;

- etm_unlock(t);
+ etm_unlock(t, id);

- etm_writel(t, v, ETMR_CTRL);
+ etm_writel(t, id, v, ETMR_CTRL);

- while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
+ while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
;
if (!timeout) {
dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
- etm_lock(t);
+ etm_lock(t, id);
return -EFAULT;
}

if (t->range_start || t->range_end)
- etm_setup_address_range(t, 1,
+ etm_setup_address_range(t, id, 1,
t->range_start, t->range_end, 0, 0);
else
- etm_writel(t, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);
+ etm_writel(t, id, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);

- etm_writel(t, 0, ETMR_TRACEENCTRL2);
- etm_writel(t, 0, ETMR_TRACESSCTRL);
- etm_writel(t, 0x6f, ETMR_TRACEENEVT);
+ etm_writel(t, id, 0, ETMR_TRACEENCTRL2);
+ etm_writel(t, id, 0, ETMR_TRACESSCTRL);
+ etm_writel(t, id, 0x6f, ETMR_TRACEENEVT);

- etm_writel(t, 0, ETMR_VIEWDATACTRL1);
- etm_writel(t, 0, ETMR_VIEWDATACTRL2);
+ etm_writel(t, id, 0, ETMR_VIEWDATACTRL1);
+ etm_writel(t, id, 0, ETMR_VIEWDATACTRL2);

if (t->data_range_start || t->data_range_end)
- etm_setup_address_range(t, 2, t->data_range_start,
+ etm_setup_address_range(t, id, 2, t->data_range_start,
t->data_range_end, 0, 1);
else
- etm_writel(t, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3);
+ etm_writel(t, id, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3);

- etm_writel(t, 0x6f, ETMR_VIEWDATAEVT);
+ etm_writel(t, id, 0x6f, ETMR_VIEWDATAEVT);

v &= ~ETMCTRL_PROGRAM;
v |= ETMCTRL_PORTSEL;

- etm_writel(t, v, ETMR_CTRL);
+ etm_writel(t, id, v, ETMR_CTRL);

timeout = TRACER_TIMEOUT;
- while (etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
+ while (etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
;
if (!timeout) {
dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
- etm_lock(t);
+ etm_lock(t, id);
return -EFAULT;
}

- etm_lock(t);
+ etm_lock(t, id);
+ return 0;
+}
+
+static int trace_start(struct tracectx *t)
+{
+ int ret;
+ int id;
+ u32 etb_fc = t->etb_fc;
+
+ etb_unlock(t);
+
+ t->dump_initial_etb = false;
+ etb_writel(t, 0, ETBR_WRITEADDR);
+ etb_writel(t, etb_fc, ETBR_FORMATTERCTRL);
+ etb_writel(t, 1, ETBR_CTRL);
+
+ etb_lock(t);
+
+ /* configure etm(s) */
+ for (id = 0; id < t->etm_regs_count; id++) {
+ ret = trace_start_etm(t, id);
+ if (ret)
+ return ret;
+ }

t->flags |= TRACER_RUNNING;

return 0;
}

-static int trace_stop(struct tracectx *t)
+static int trace_stop_etm(struct tracectx *t, int id)
{
unsigned long timeout = TRACER_TIMEOUT;

- etm_unlock(t);
+ etm_unlock(t, id);

- etm_writel(t, 0x440, ETMR_CTRL);
- while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
+ etm_writel(t, id, 0x440, ETMR_CTRL);
+ while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
;
if (!timeout) {
dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
- etm_lock(t);
+ etm_lock(t, id);
return -EFAULT;
}

- etm_lock(t);
+ etm_lock(t, id);
+ return 0;
+}
+
+static int trace_stop(struct tracectx *t)
+{
+ int id;
+ int ret;
+ unsigned long timeout = TRACER_TIMEOUT;
+ u32 etb_fc = t->etb_fc;
+
+ for (id = 0; id < t->etm_regs_count; id++) {
+ ret = trace_stop_etm(t, id);
+ if (ret)
+ return ret;
+ }

etb_unlock(t);
- etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
+ if (etb_fc) {
+ etb_fc |= ETBFF_STOPFL;
+ etb_writel(t, t->etb_fc, ETBR_FORMATTERCTRL);
+ }
+ etb_writel(t, etb_fc | ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);

timeout = TRACER_TIMEOUT;
while (etb_readl(t, ETBR_FORMATTERCTRL) &
@@ -390,6 +426,7 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id
goto out_release;
}

+ t->dev = &dev->dev;
t->dump_initial_etb = true;
amba_set_drvdata(dev, t);

@@ -508,6 +545,8 @@ static ssize_t trace_info_show(struct kobject *kobj,
{
u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
int datalen;
+ int id;
+ int ret;

mutex_lock(&tracer.mutex);
if (tracer.etb_regs) {
@@ -523,28 +562,33 @@ static ssize_t trace_info_show(struct kobject *kobj,
datalen = -1;
}

- etm_unlock(&tracer);
- etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
- etm_st = etm_readl(&tracer, ETMR_STATUS);
- etm_lock(&tracer);
- mutex_unlock(&tracer.mutex);
-
- return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
+ ret = sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
"ETBR_WRITEADDR:\t%08x\n"
"ETBR_READADDR:\t%08x\n"
"ETBR_STATUS:\t%08x\n"
- "ETBR_FORMATTERCTRL:\t%08x\n"
- "ETMR_CTRL:\t%08x\n"
- "ETMR_STATUS:\t%08x\n",
+ "ETBR_FORMATTERCTRL:\t%08x\n",
datalen,
tracer.ncmppairs,
etb_wa,
etb_ra,
etb_st,
- etb_fc,
+ etb_fc
+ );
+
+ for (id = 0; id < tracer.etm_regs_count; id++) {
+ etm_unlock(&tracer, id);
+ etm_ctrl = etm_readl(&tracer, id, ETMR_CTRL);
+ etm_st = etm_readl(&tracer, id, ETMR_STATUS);
+ etm_lock(&tracer, id);
+ ret += sprintf(buf + ret, "ETMR_CTRL:\t%08x\n"
+ "ETMR_STATUS:\t%08x\n",
etm_ctrl,
etm_st
);
+ }
+ mutex_unlock(&tracer.mutex);
+
+ return ret;
}

static struct kobj_attribute trace_info_attr =
@@ -658,37 +702,46 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id
{
struct tracectx *t = &tracer;
int ret = 0;
+ void __iomem **new_regs;
+ int new_count;

- if (t->etm_regs) {
- dev_dbg(&dev->dev, "ETM already initialized\n");
- ret = -EBUSY;
+ mutex_lock(&t->mutex);
+ new_count = t->etm_regs_count + 1;
+ new_regs = krealloc(t->etm_regs,
+ sizeof(t->etm_regs[0]) * new_count, GFP_KERNEL);
+
+ if (!new_regs) {
+ dev_dbg(&dev->dev, "Failed to allocate ETM register array\n");
+ ret = -ENOMEM;
goto out;
}
+ t->etm_regs = new_regs;

ret = amba_request_regions(dev, NULL);
if (ret)
goto out;

- t->etm_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
- if (!t->etm_regs) {
+ t->etm_regs[t->etm_regs_count] =
+ ioremap_nocache(dev->res.start, resource_size(&dev->res));
+ if (!t->etm_regs[t->etm_regs_count]) {
ret = -ENOMEM;
goto out_release;
}

- amba_set_drvdata(dev, t);
+ amba_set_drvdata(dev, t->etm_regs[t->etm_regs_count]);

- t->dev = &dev->dev;
t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA;
t->etm_portsz = 1;

- etm_unlock(t);
- (void)etm_readl(t, ETMMR_PDSR);
+ etm_unlock(t, t->etm_regs_count);
+ (void)etm_readl(t, t->etm_regs_count, ETMMR_PDSR);
/* dummy first read */
- (void)etm_readl(&tracer, ETMMR_OSSRR);
+ (void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR);

- t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
- etm_writel(t, 0x440, ETMR_CTRL);
- etm_lock(t);
+ t->ncmppairs = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE) & 0xf;
+ etm_writel(t, t->etm_regs_count, 0x440, ETMR_CTRL);
+ etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR);
+ etm_lock(t, t->etm_regs_count);

ret = sysfs_create_file(&dev->dev.kobj,
&trace_running_attr.attr);
@@ -713,31 +766,34 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id
dev_dbg(&dev->dev,
"Failed to create trace_data_range in sysfs\n");

- dev_dbg(t->dev, "ETM AMBA driver initialized.\n");
+ dev_dbg(&dev->dev, "ETM AMBA driver initialized.\n");
+
+ /* Enable formatter if there are multiple trace sources */
+ if (new_count > 1)
+ t->etb_fc = ETBFF_ENFCONT | ETBFF_ENFTC;
+
+ t->etm_regs_count = new_count;

out:
+ mutex_unlock(&t->mutex);
return ret;

out_unmap:
amba_set_drvdata(dev, NULL);
- iounmap(t->etm_regs);
+ iounmap(t->etm_regs[t->etm_regs_count]);

out_release:
amba_release_regions(dev);

+ mutex_unlock(&t->mutex);
return ret;
}

static int etm_remove(struct amba_device *dev)
{
- struct tracectx *t = amba_get_drvdata(dev);
-
- amba_set_drvdata(dev, NULL);
-
- iounmap(t->etm_regs);
- t->etm_regs = NULL;
-
- amba_release_regions(dev);
+ int i;
+ struct tracectx *t = &tracer;
+ void __iomem *etm_regs = amba_get_drvdata(dev);

sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
@@ -745,6 +801,24 @@ static int etm_remove(struct amba_device *dev)
sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr);

+ amba_set_drvdata(dev, NULL);
+
+ mutex_lock(&t->mutex);
+ for (i = 0; i < t->etm_regs_count; i++)
+ if (t->etm_regs[i] == etm_regs)
+ break;
+ for (; i < t->etm_regs_count - 1; i++)
+ t->etm_regs[i] = t->etm_regs[i + 1];
+ t->etm_regs_count--;
+ if (!t->etm_regs_count) {
+ kfree(t->etm_regs);
+ t->etm_regs = NULL;
+ }
+ mutex_unlock(&t->mutex);
+
+ iounmap(etm_regs);
+ amba_release_regions(dev);
+
return 0;
}

@@ -753,6 +827,10 @@ static struct amba_id etm_ids[] = {
.id = 0x0003b921,
.mask = 0x0007ffff,
},
+ {
+ .id = 0x0003b950,
+ .mask = 0x0007ffff,
+ },
{ 0, 0 },
};

--
1.7.3.2.146.gca209

2012-06-13 02:02:00

by John Stultz

[permalink] [raw]
Subject: [PATCH 01/15] ARM: etm: Don't require clock control

From: Arve Hjønnevåg <[email protected]>

If clk_get fail, assume the etb does not need a separate clock.

CC: Russell King <[email protected]>
CC: Paul Gortmaker <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Mathieu Poirier <[email protected]>

Acked-by: Alexander Shishkin <[email protected]>
Signed-off-by: Arve Hjønnevåg <[email protected]>
Signed-off-by: John Stultz <[email protected]>
---
arch/arm/kernel/etm.c | 15 ++++++++-------
1 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index 36d20bd..bd295e8 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -362,13 +362,12 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id
if (ret)
goto out_unmap;

+ /* Get optional clock. Currently used to select clock source on omap3 */
t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
- if (IS_ERR(t->emu_clk)) {
+ if (IS_ERR(t->emu_clk))
dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
- return -EFAULT;
- }
-
- clk_enable(t->emu_clk);
+ else
+ clk_enable(t->emu_clk);

etb_unlock(t);
t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
@@ -403,8 +402,10 @@ static int etb_remove(struct amba_device *dev)
iounmap(t->etb_regs);
t->etb_regs = NULL;

- clk_disable(t->emu_clk);
- clk_put(t->emu_clk);
+ if (!IS_ERR(t->emu_clk)) {
+ clk_disable(t->emu_clk);
+ clk_put(t->emu_clk);
+ }

amba_release_regions(dev);

--
1.7.3.2.146.gca209

2012-06-13 02:02:10

by John Stultz

[permalink] [raw]
Subject: [PATCH 05/15] ARM: etm: Configure data tracing

From: Arve Hjønnevåg <[email protected]>

The old code enabled data tracing, but did not configure the
range. We now configure it to trace all data addresses by default,
and add a trace_data_range attribute to change the range or disable
data tracing.

CC: Russell King <[email protected]>
CC: Paul Gortmaker <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Mathieu Poirier <[email protected]>

Acked-by: Alexander Shishkin <[email protected]>
Signed-off-by: Arve Hjønnevåg <[email protected]>
Signed-off-by: John Stultz <[email protected]>
---
arch/arm/include/asm/hardware/coresight.h | 10 +++-
arch/arm/kernel/etm.c | 77 +++++++++++++++++++++++++++-
2 files changed, 83 insertions(+), 4 deletions(-)

diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h
index 7ecd793..6ea507f 100644
--- a/arch/arm/include/asm/hardware/coresight.h
+++ b/arch/arm/include/asm/hardware/coresight.h
@@ -17,9 +17,11 @@
#define TRACER_ACCESSED_BIT 0
#define TRACER_RUNNING_BIT 1
#define TRACER_CYCLE_ACC_BIT 2
+#define TRACER_TRACE_DATA_BIT 3
#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_TIMEOUT 10000

@@ -113,8 +115,14 @@
#define ETMR_TRACEENCTRL 0x24
#define ETMTE_INCLEXCL BIT(24)
#define ETMR_TRACEENEVT 0x20
+
+#define ETMR_VIEWDATAEVT 0x30
+#define ETMR_VIEWDATACTRL1 0x34
+#define ETMR_VIEWDATACTRL2 0x38
+#define ETMR_VIEWDATACTRL3 0x3c
+#define ETMVDC3_EXCLONLY BIT(16)
+
#define ETMCTRL_OPTS (ETMCTRL_DO_CPRT | \
- ETMCTRL_DATA_DO_ADDR | \
ETMCTRL_BRANCH_OUTPUT | \
ETMCTRL_DO_CONTEXTID)

diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index bf34d34..c651cf9 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -43,6 +43,8 @@ struct tracectx {
int etm_portsz;
unsigned long range_start;
unsigned long range_end;
+ unsigned long data_range_start;
+ unsigned long data_range_end;
struct device *dev;
struct clk *emu_clk;
struct mutex mutex;
@@ -84,8 +86,15 @@ static int etm_setup_address_range(struct tracectx *t, int n,
etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));

- flags = exclude ? ETMTE_INCLEXCL : 0;
- etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
+ if (data) {
+ flags = exclude ? ETMVDC3_EXCLONLY : 0;
+ if (exclude)
+ n += 8;
+ etm_writel(t, flags | BIT(n), ETMR_VIEWDATACTRL3);
+ } else {
+ flags = exclude ? ETMTE_INCLEXCL : 0;
+ etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
+ }

return 0;
}
@@ -109,6 +118,9 @@ static int trace_start(struct tracectx *t)
if (t->flags & TRACER_CYCLE_ACC)
v |= ETMCTRL_CYCLEACCURATE;

+ if (t->flags & TRACER_TRACE_DATA)
+ v |= ETMCTRL_DATA_DO_ADDR;
+
etm_unlock(t);

etm_writel(t, v, ETMR_CTRL);
@@ -131,6 +143,17 @@ static int trace_start(struct tracectx *t)
etm_writel(t, 0, ETMR_TRACESSCTRL);
etm_writel(t, 0x6f, ETMR_TRACEENEVT);

+ etm_writel(t, 0, ETMR_VIEWDATACTRL1);
+ etm_writel(t, 0, ETMR_VIEWDATACTRL2);
+
+ if (t->data_range_start || t->data_range_end)
+ etm_setup_address_range(t, 2, t->data_range_start,
+ t->data_range_end, 0, 1);
+ else
+ etm_writel(t, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3);
+
+ etm_writel(t, 0x6f, ETMR_VIEWDATAEVT);
+
v &= ~ETMCTRL_PROGRAM;
v |= ETMCTRL_PORTSEL;

@@ -564,6 +587,48 @@ static ssize_t trace_range_store(struct kobject *kobj,
static struct kobj_attribute trace_range_attr =
__ATTR(trace_range, 0644, trace_range_show, trace_range_store);

+static ssize_t trace_data_range_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ unsigned long range_start;
+ u64 range_end;
+ mutex_lock(&tracer.mutex);
+ range_start = tracer.data_range_start;
+ range_end = tracer.data_range_end;
+ if (!range_end && (tracer.flags & TRACER_TRACE_DATA))
+ range_end = 0x100000000ULL;
+ mutex_unlock(&tracer.mutex);
+ return sprintf(buf, "%08lx %08llx\n", range_start, range_end);
+}
+
+static ssize_t trace_data_range_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned long range_start;
+ u64 range_end;
+
+ if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2)
+ return -EINVAL;
+
+ mutex_lock(&tracer.mutex);
+ tracer.data_range_start = range_start;
+ tracer.data_range_end = (unsigned long)range_end;
+ if (range_end)
+ tracer.flags |= TRACER_TRACE_DATA;
+ else
+ tracer.flags &= ~TRACER_TRACE_DATA;
+ mutex_unlock(&tracer.mutex);
+
+ return n;
+}
+
+
+static struct kobj_attribute trace_data_range_attr =
+ __ATTR(trace_data_range, 0644,
+ trace_data_range_show, trace_data_range_store);
+
static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
{
struct tracectx *t = &tracer;
@@ -589,7 +654,7 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id

mutex_init(&t->mutex);
t->dev = &dev->dev;
- t->flags = TRACER_CYCLE_ACC;
+ t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA;
t->etm_portsz = 1;

etm_unlock(t);
@@ -619,6 +684,11 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id
if (ret)
dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");

+ ret = sysfs_create_file(&dev->dev.kobj, &trace_data_range_attr.attr);
+ if (ret)
+ dev_dbg(&dev->dev,
+ "Failed to create trace_data_range in sysfs\n");
+
dev_dbg(t->dev, "ETM AMBA driver initialized.\n");

out:
@@ -649,6 +719,7 @@ static int etm_remove(struct amba_device *dev)
sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
+ sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr);

return 0;
}
--
1.7.3.2.146.gca209

2012-06-13 02:02:16

by John Stultz

[permalink] [raw]
Subject: [PATCH 04/15] ARM: etm: Allow range selection

From: Arve Hjønnevåg <[email protected]>

Trace kernel text segment by default as before, allow tracing of other
ranges by writing a range to /sys/devices/etm/trace_range, or to trace
everything by writing 0 0.

CC: Russell King <[email protected]>
CC: Paul Gortmaker <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Mathieu Poirier <[email protected]>

Acked-by: Alexander Shishkin <[email protected]>
Signed-off-by: Arve Hjønnevåg <[email protected]>
Signed-off-by: John Stultz <[email protected]>
---
arch/arm/kernel/etm.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index a51bccc..bf34d34 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -41,12 +41,17 @@ struct tracectx {
unsigned long flags;
int ncmppairs;
int etm_portsz;
+ unsigned long range_start;
+ unsigned long range_end;
struct device *dev;
struct clk *emu_clk;
struct mutex mutex;
};

-static struct tracectx tracer;
+static struct tracectx tracer = {
+ .range_start = (unsigned long)_stext,
+ .range_end = (unsigned long)_etext,
+};

static inline bool trace_isrunning(struct tracectx *t)
{
@@ -116,8 +121,12 @@ static int trace_start(struct tracectx *t)
return -EFAULT;
}

- etm_setup_address_range(t, 1, (unsigned long)_stext,
- (unsigned long)_etext, 0, 0);
+ if (t->range_start || t->range_end)
+ etm_setup_address_range(t, 1,
+ t->range_start, t->range_end, 0, 0);
+ else
+ etm_writel(t, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);
+
etm_writel(t, 0, ETMR_TRACEENCTRL2);
etm_writel(t, 0, ETMR_TRACESSCTRL);
etm_writel(t, 0x6f, ETMR_TRACEENEVT);
@@ -526,6 +535,35 @@ 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_range_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%08lx %08lx\n",
+ tracer.range_start, tracer.range_end);
+}
+
+static ssize_t trace_range_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned long range_start, range_end;
+
+ if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2)
+ return -EINVAL;
+
+ mutex_lock(&tracer.mutex);
+ tracer.range_start = range_start;
+ tracer.range_end = range_end;
+ mutex_unlock(&tracer.mutex);
+
+ return n;
+}
+
+
+static struct kobj_attribute trace_range_attr =
+ __ATTR(trace_range, 0644, trace_range_show, trace_range_store);
+
static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
{
struct tracectx *t = &tracer;
@@ -577,6 +615,10 @@ 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");

+ 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");
+
dev_dbg(t->dev, "ETM AMBA driver initialized.\n");

out:
@@ -606,6 +648,7 @@ static int etm_remove(struct amba_device *dev)
sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
+ sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);

return 0;
}
--
1.7.3.2.146.gca209

2012-06-13 02:02:24

by John Stultz

[permalink] [raw]
Subject: [PATCH 06/15] ARM: etm: Add some missing locks and error checks

From: Arve Hjønnevåg <[email protected]>

It is not safe to call etm_lock or etb_lock without holding the
mutex since another thread may also have unlocked the registers.

Also add some missing checks for valid etb_regs in the etm sysfs
entries.

CC: Russell King <[email protected]>
CC: Paul Gortmaker <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Mathieu Poirier <[email protected]>

Acked-by: Alexander Shishkin <[email protected]>
Signed-off-by: Arve Hjønnevåg <[email protected]>
Signed-off-by: John Stultz <[email protected]>
---
arch/arm/kernel/etm.c | 57 +++++++++++++++++++++++++++++++++---------------
1 files changed, 39 insertions(+), 18 deletions(-)

diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index c651cf9..3d21cf6 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -264,8 +264,13 @@ static void etm_dump(void)

static void sysrq_etm_dump(int key)
{
+ if (!mutex_trylock(&tracer.mutex)) {
+ printk(KERN_INFO "Tracing hardware busy\n");
+ return;
+ }
dev_dbg(tracer.dev, "Dumping ETB buffer\n");
etm_dump();
+ mutex_unlock(&tracer.mutex);
}

static struct sysrq_key_op sysrq_etm_op = {
@@ -374,6 +379,7 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id
if (ret)
goto out;

+ mutex_lock(&t->mutex);
t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
if (!t->etb_regs) {
ret = -ENOMEM;
@@ -382,6 +388,16 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id

amba_set_drvdata(dev, t);

+ etb_unlock(t);
+ t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
+ dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
+
+ /* make sure trace capture is disabled */
+ etb_writel(t, 0, ETBR_CTRL);
+ etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
+ etb_lock(t);
+ mutex_unlock(&t->mutex);
+
etb_miscdev.parent = &dev->dev;

ret = misc_register(&etb_miscdev);
@@ -395,25 +411,19 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id
else
clk_enable(t->emu_clk);

- etb_unlock(t);
- t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
- dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
-
- /* make sure trace capture is disabled */
- etb_writel(t, 0, ETBR_CTRL);
- etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
- etb_lock(t);
-
dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");

out:
return ret;

out_unmap:
+ mutex_lock(&t->mutex);
amba_set_drvdata(dev, NULL);
iounmap(t->etb_regs);
+ t->etb_regs = NULL;

out_release:
+ mutex_unlock(&t->mutex);
amba_release_regions(dev);

return ret;
@@ -475,7 +485,10 @@ static ssize_t trace_running_store(struct kobject *kobj,
return -EINVAL;

mutex_lock(&tracer.mutex);
- ret = value ? trace_start(&tracer) : trace_stop(&tracer);
+ if (!tracer.etb_regs)
+ ret = -ENODEV;
+ else
+ ret = value ? trace_start(&tracer) : trace_stop(&tracer);
mutex_unlock(&tracer.mutex);

return ret ? : n;
@@ -491,18 +504,25 @@ static ssize_t trace_info_show(struct kobject *kobj,
u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
int datalen;

- etb_unlock(&tracer);
- datalen = etb_getdatalen(&tracer);
- etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
- etb_ra = etb_readl(&tracer, ETBR_READADDR);
- etb_st = etb_readl(&tracer, ETBR_STATUS);
- etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
- etb_lock(&tracer);
+ mutex_lock(&tracer.mutex);
+ if (tracer.etb_regs) {
+ etb_unlock(&tracer);
+ datalen = etb_getdatalen(&tracer);
+ etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
+ etb_ra = etb_readl(&tracer, ETBR_READADDR);
+ etb_st = etb_readl(&tracer, ETBR_STATUS);
+ etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
+ etb_lock(&tracer);
+ } else {
+ etb_wa = etb_ra = etb_st = etb_fc = ~0;
+ datalen = -1;
+ }

etm_unlock(&tracer);
etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
etm_st = etm_readl(&tracer, ETMR_STATUS);
etm_lock(&tracer);
+ mutex_unlock(&tracer.mutex);

return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
"ETBR_WRITEADDR:\t%08x\n"
@@ -652,7 +672,6 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id

amba_set_drvdata(dev, t);

- mutex_init(&t->mutex);
t->dev = &dev->dev;
t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA;
t->etm_portsz = 1;
@@ -746,6 +765,8 @@ static int __init etm_init(void)
{
int retval;

+ mutex_init(&tracer.mutex);
+
retval = amba_driver_register(&etb_driver);
if (retval) {
printk(KERN_ERR "Failed to register etb\n");
--
1.7.3.2.146.gca209

2012-06-13 02:02:49

by John Stultz

[permalink] [raw]
Subject: [PATCH 09/15] ARM: etm: Power down etm(s) when tracing is not enabled

From: Arve Hjønnevåg <[email protected]>

Without this change a saw an 18% increase in idle power consumption
on one deivce when trace support is compiled into the kernel. Now
I see the same increase only when tracing.

CC: Russell King <[email protected]>
CC: Paul Gortmaker <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Mathieu Poirier <[email protected]>

Acked-by: Alexander Shishkin <[email protected]>
Signed-off-by: Arve Hjønnevåg <[email protected]>
Signed-off-by: John Stultz <[email protected]>
---
arch/arm/kernel/etm.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index e3309ea..66bf592 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -200,7 +200,7 @@ static int trace_stop_etm(struct tracectx *t, int id)

etm_unlock(t, id);

- etm_writel(t, id, 0x440, ETMR_CTRL);
+ etm_writel(t, id, 0x441, ETMR_CTRL);
while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
;
if (!timeout) {
@@ -739,7 +739,7 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id
(void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR);

t->ncmppairs = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE) & 0xf;
- etm_writel(t, t->etm_regs_count, 0x440, ETMR_CTRL);
+ etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL);
etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR);
etm_lock(t, t->etm_regs_count);

--
1.7.3.2.146.gca209

2012-06-13 02:01:59

by John Stultz

[permalink] [raw]
Subject: [PATCH 07/15] ARM: etm: Return the entire trace buffer if it is empty after reset

From: Arve Hjønnevåg <[email protected]>

On some SOCs the read and write pointer are reset when the chip
resets, but the trace buffer content is preserved. If the status
bits indicates that the buffer is empty and we have never started
tracing, assume the buffer is full instead. This can be useful
if the system rebooted from a watchdog reset.

CC: Russell King <[email protected]>
CC: Paul Gortmaker <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Mathieu Poirier <[email protected]>

Acked-by: Alexander Shishkin <[email protected]>
Signed-off-by: Arve Hjønnevåg <[email protected]>
Signed-off-by: John Stultz <[email protected]>
---
arch/arm/kernel/etm.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index 3d21cf6..74444e5 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -45,6 +45,7 @@ struct tracectx {
unsigned long range_end;
unsigned long data_range_start;
unsigned long data_range_end;
+ bool dump_initial_etb;
struct device *dev;
struct clk *emu_clk;
struct mutex mutex;
@@ -106,6 +107,7 @@ static int trace_start(struct tracectx *t)

etb_unlock(t);

+ t->dump_initial_etb = false;
etb_writel(t, 0, ETBR_WRITEADDR);
etb_writel(t, 0, ETBR_FORMATTERCTRL);
etb_writel(t, 1, ETBR_CTRL);
@@ -312,6 +314,8 @@ static ssize_t etb_read(struct file *file, char __user *data,
etb_unlock(t);

total = etb_getdatalen(t);
+ if (total == 0 && t->dump_initial_etb)
+ total = t->etb_bufsz;
if (total == t->etb_bufsz)
first = etb_readl(t, ETBR_WRITEADDR);

@@ -386,6 +390,7 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id
goto out_release;
}

+ t->dump_initial_etb = true;
amba_set_drvdata(dev, t);

etb_unlock(t);
--
1.7.3.2.146.gca209

2012-06-13 02:03:40

by John Stultz

[permalink] [raw]
Subject: [PATCH 03/15] ARM: etm: Don't try to clear the buffer full status after reading the buffer

From: Arve Hjønnevåg <[email protected]>

If the write address was at the end of the buffer, toggling the trace
capture bit would set the RAM-full status instead of clearing it, and
if any of the stop bits in the formatter is set toggling the trace
capture bit may not do anything.

Instead use the read position to find out if the data has already
been returned.

This also fixes the read function so it works when the trace buffer is
larger than the buffer passed in from user space. The old version
would reset the trace buffer pointers after every read, so the second
call to read would always return 0.

CC: Russell King <[email protected]>
CC: Paul Gortmaker <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Mathieu Poirier <[email protected]>

Acked-by: Alexander Shishkin <[email protected]>
Signed-off-by: Arve Hjønnevåg <[email protected]>
Signed-off-by: John Stultz <[email protected]>
---
arch/arm/kernel/etm.c | 58 ++++++++++++++++++++++---------------------------
1 files changed, 26 insertions(+), 32 deletions(-)

diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index d7622f9..a51bccc 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -92,6 +92,7 @@ static int trace_start(struct tracectx *t)

etb_unlock(t);

+ etb_writel(t, 0, ETBR_WRITEADDR);
etb_writel(t, 0, ETBR_FORMATTERCTRL);
etb_writel(t, 1, ETBR_CTRL);

@@ -185,24 +186,15 @@ static int trace_stop(struct tracectx *t)
static int etb_getdatalen(struct tracectx *t)
{
u32 v;
- int rp, wp;
+ int wp;

v = etb_readl(t, ETBR_STATUS);

if (v & 1)
return t->etb_bufsz;

- rp = etb_readl(t, ETBR_READADDR);
wp = etb_readl(t, ETBR_WRITEADDR);
-
- if (rp > wp) {
- etb_writel(t, 0, ETBR_READADDR);
- etb_writel(t, 0, ETBR_WRITEADDR);
-
- return 0;
- }
-
- return wp - rp;
+ return wp;
}

/* sysrq+v will always stop the running trace and leave it at that */
@@ -235,14 +227,6 @@ static void etm_dump(void)
printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
printk(KERN_INFO "\n--- ETB buffer end ---\n");

- /* deassert the overflow bit */
- etb_writel(t, 1, ETBR_CTRL);
- etb_writel(t, 0, ETBR_CTRL);
-
- etb_writel(t, 0, ETBR_TRIGGERCOUNT);
- etb_writel(t, 0, ETBR_READADDR);
- etb_writel(t, 0, ETBR_WRITEADDR);
-
etb_lock(t);
}

@@ -276,6 +260,10 @@ static ssize_t etb_read(struct file *file, char __user *data,
struct tracectx *t = file->private_data;
u32 first = 0;
u32 *buf;
+ int wpos;
+ int skip;
+ long wlength;
+ loff_t pos = *ppos;

mutex_lock(&t->mutex);

@@ -290,28 +278,34 @@ static ssize_t etb_read(struct file *file, char __user *data,
if (total == t->etb_bufsz)
first = etb_readl(t, ETBR_WRITEADDR);

+ if (pos > total * 4) {
+ skip = 0;
+ wpos = total;
+ } else {
+ skip = (int)pos % 4;
+ wpos = (int)pos / 4;
+ }
+ total -= wpos;
+ first = (first + wpos) % t->etb_bufsz;
+
etb_writel(t, first, ETBR_READADDR);

- length = min(total * 4, (int)len);
- buf = vmalloc(length);
+ wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4));
+ length = min(total * 4 - skip, (int)len);
+ buf = vmalloc(wlength * 4);

- dev_dbg(t->dev, "ETB buffer length: %d\n", total);
+ dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n",
+ length, pos, wlength, first);
+ dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos);
dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
- for (i = 0; i < length / 4; i++)
+ for (i = 0; i < wlength; i++)
buf[i] = etb_readl(t, ETBR_READMEM);

- /* the only way to deassert overflow bit in ETB status is this */
- etb_writel(t, 1, ETBR_CTRL);
- etb_writel(t, 0, ETBR_CTRL);
-
- etb_writel(t, 0, ETBR_WRITEADDR);
- etb_writel(t, 0, ETBR_READADDR);
- etb_writel(t, 0, ETBR_TRIGGERCOUNT);
-
etb_lock(t);

- length -= copy_to_user(data, buf, length);
+ length -= copy_to_user(data, (u8 *)buf + skip, length);
vfree(buf);
+ *ppos = pos + length;

out:
mutex_unlock(&t->mutex);
--
1.7.3.2.146.gca209

2012-06-13 08:33:57

by Paul Mundt

[permalink] [raw]
Subject: Re: [PATCH 01/15] ARM: etm: Don't require clock control

On Tue, Jun 12, 2012 at 07:01:19PM -0700, John Stultz wrote:
> diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
> index 36d20bd..bd295e8 100644
> --- a/arch/arm/kernel/etm.c
> +++ b/arch/arm/kernel/etm.c
> @@ -362,13 +362,12 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id
> if (ret)
> goto out_unmap;
>
> + /* Get optional clock. Currently used to select clock source on omap3 */
> t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
> - if (IS_ERR(t->emu_clk)) {
> + if (IS_ERR(t->emu_clk))
> dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
> - return -EFAULT;
> - }
> -
> - clk_enable(t->emu_clk);
> + else
> + clk_enable(t->emu_clk);
>
Optionally you could just:

if (IS_ERR(t->emu_clk))
t->emu_clk = NULL;

and use the clk API as you were, as it does handle NULL being passed in.

In this case you don't have too many callsites to worry about, but it's
reasonably convenient to be able to pass a NULL clk pointer around
without constant special-casing when those start to balloon up.

2012-06-13 23:10:27

by John Stultz

[permalink] [raw]
Subject: Re: [PATCH 01/15] ARM: etm: Don't require clock control

On 06/13/2012 01:33 AM, Paul Mundt wrote:
> On Tue, Jun 12, 2012 at 07:01:19PM -0700, John Stultz wrote:
>> diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
>> index 36d20bd..bd295e8 100644
>> --- a/arch/arm/kernel/etm.c
>> +++ b/arch/arm/kernel/etm.c
>> @@ -362,13 +362,12 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id
>> if (ret)
>> goto out_unmap;
>>
>> + /* Get optional clock. Currently used to select clock source on omap3 */
>> t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
>> - if (IS_ERR(t->emu_clk)) {
>> + if (IS_ERR(t->emu_clk))
>> dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
>> - return -EFAULT;
>> - }
>> -
>> - clk_enable(t->emu_clk);
>> + else
>> + clk_enable(t->emu_clk);
>>
> Optionally you could just:
>
> if (IS_ERR(t->emu_clk))
> t->emu_clk = NULL;
>
> and use the clk API as you were, as it does handle NULL being passed in.
>
> In this case you don't have too many callsites to worry about, but it's
> reasonably convenient to be able to pass a NULL clk pointer around
> without constant special-casing when those start to balloon up.
>
Hrm. That's a good trick to remember for the future!

Although in this case I'm not sure it wins much (since the re-adding of
the braces and the null assignment is still more code then using the
else). So unless this is a major style problem for you (and do let me
know if it is), I'll probably leave it alone.

thanks
-john

2012-06-28 16:13:37

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 00/15][RFC] Android ETM driver changes

On Wed, Jun 13, 2012 at 4:01 AM, John Stultz <[email protected]> wrote:

> The Android kernel tree has a number of changes to the ETM driver.
> Arve sent the first 9 of these to the list over a year ago and
> got very little response.
>
> I didn't want these to get lost, so I pinged Alexander about
> these privately and he stated that he wasn't actively
> maintaining the driver, but after skimming the entire set
> acked the series and suggested I send it on to Russel for
> review and possible inclusion.
>
> So here they are. Please let me know if there are any
> objections to merging these, or if further changes are
> needed.

I finally reviewed them, sorry for the lag.

In all this is very useful stuff, maybe people just don't realize how
useful it really is. I suggest you to write a small doc in
Documentation/arm/etm.txt on how to get started etc.

Thanks for your efforts!

Yours,
Linus Walleij

2012-06-29 20:26:12

by John Stultz

[permalink] [raw]
Subject: Re: [PATCH 00/15][RFC] Android ETM driver changes

On 06/28/2012 09:13 AM, Linus Walleij wrote:
> On Wed, Jun 13, 2012 at 4:01 AM, John Stultz <[email protected]> wrote:
>
>> The Android kernel tree has a number of changes to the ETM driver.
>> Arve sent the first 9 of these to the list over a year ago and
>> got very little response.
>>
>> I didn't want these to get lost, so I pinged Alexander about
>> these privately and he stated that he wasn't actively
>> maintaining the driver, but after skimming the entire set
>> acked the series and suggested I send it on to Russel for
>> review and possible inclusion.
>>
>> So here they are. Please let me know if there are any
>> objections to merging these, or if further changes are
>> needed.
> I finally reviewed them, sorry for the lag.
>
> In all this is very useful stuff, maybe people just don't realize how
> useful it really is. I suggest you to write a small doc in
> Documentation/arm/etm.txt on how to get started etc.
>
> Thanks for your efforts!
Thanks for the review! I'll try to work with Arve to see if I can help
address some of the issues you pointed out and to improve the documentation.

thanks
-john