From patchwork Wed Jun 13 02:01:26 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 9253 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 7B7A123E37 for ; Wed, 13 Jun 2012 02:02:00 +0000 (UTC) Received: from mail-gg0-f180.google.com (mail-gg0-f180.google.com [209.85.161.180]) by fiordland.canonical.com (Postfix) with ESMTP id 2FD9AA18221 for ; Wed, 13 Jun 2012 02:02:00 +0000 (UTC) Received: by mail-gg0-f180.google.com with SMTP id f1so52452ggn.11 for ; Tue, 12 Jun 2012 19:02:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:in-reply-to:references :mime-version:content-type:content-transfer-encoding :x-content-scanned:x-cbid:x-gm-message-state; bh=rpmFq2f+ce2btA46gRS3u1jPcIyQYTRw8w8P72wAmdg=; b=FNdZ1+WUP3ATWRxzFQ0n6GW+Tl8WWNhpQXcjCQHSOfVPfAnWALscBPpAH+AHFKv6Px 8XojGEmX20CvwPoTJzqi/V2J/LSucAadHN9bZbHi2xKU0yaosAC2O3mvk2TrPjK4Z5Zi h9DhLfvR0WhVrPJPH70Cvu8QSQTTzLWC8ackmhPyTi4z5K3EdHj+ElLq+V2z8bpdw4qB JMC+RvWF+2JH+3AplknhFmCrMT0O9baLRtZfTQ2nfULFCNFKpnUV6E7CuFaXtC+H7Pbg 1O9ACzHSy0vqBRddqU8u/UBfEdRrcE2/2s1G7yNXkaof3pAxYiDZ7EaTIqlzyFV2Zm6n 3j5g== Received: by 10.50.193.196 with SMTP id hq4mr9540111igc.57.1339552919445; Tue, 12 Jun 2012 19:01:59 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.24.148 with SMTP id v20csp200435ibb; Tue, 12 Jun 2012 19:01:58 -0700 (PDT) Received: by 10.236.152.97 with SMTP id c61mr30817947yhk.130.1339552917963; Tue, 12 Jun 2012 19:01:57 -0700 (PDT) Received: from e32.co.us.ibm.com (e32.co.us.ibm.com. [32.97.110.150]) by mx.google.com with ESMTPS id v69si1598024yhl.151.2012.06.12.19.01.57 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 12 Jun 2012 19:01:57 -0700 (PDT) Received-SPF: pass (google.com: domain of jstultz@us.ibm.com designates 32.97.110.150 as permitted sender) client-ip=32.97.110.150; Authentication-Results: mx.google.com; spf=pass (google.com: domain of jstultz@us.ibm.com designates 32.97.110.150 as permitted sender) smtp.mail=jstultz@us.ibm.com Received: from /spool/local by e32.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 12 Jun 2012 20:01:57 -0600 Received: from d01dlp03.pok.ibm.com (9.56.224.17) by e32.co.us.ibm.com (192.168.1.132) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 12 Jun 2012 20:01:55 -0600 Received: from d01relay04.pok.ibm.com (d01relay04.pok.ibm.com [9.56.227.236]) by d01dlp03.pok.ibm.com (Postfix) with ESMTP id 8204FC90065; Tue, 12 Jun 2012 22:01:53 -0400 (EDT) Received: from d01av01.pok.ibm.com (d01av01.pok.ibm.com [9.56.224.215]) by d01relay04.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q5D21skW148658; Tue, 12 Jun 2012 22:01:54 -0400 Received: from d01av01.pok.ibm.com (loopback [127.0.0.1]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q5D7WZFP027831; Wed, 13 Jun 2012 03:32:35 -0400 Received: from kernel.beaverton.ibm.com (kernel.beaverton.ibm.com [9.47.67.96]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q5D7WZgm027745; Wed, 13 Jun 2012 03:32:35 -0400 Received: by kernel.beaverton.ibm.com (Postfix, from userid 1056) id 289FAC0629; Tue, 12 Jun 2012 19:01:41 -0700 (PDT) From: John Stultz To: LKML Cc: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= , Russell King , Paul Gortmaker , Alexander Shishkin , Mathieu Poirier , John Stultz Subject: [PATCH 08/15] ARM: etm: Support multiple ETMs/PTMs. Date: Tue, 12 Jun 2012 19:01:26 -0700 Message-Id: <1339552887-17204-9-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.7.3.2.146.gca209 In-Reply-To: <1339552887-17204-1-git-send-email-john.stultz@linaro.org> References: <1339552887-17204-1-git-send-email-john.stultz@linaro.org> MIME-Version: 1.0 X-Content-Scanned: Fidelis XPS MAILER x-cbid: 12061302-3270-0000-0000-0000072046E4 X-Gm-Message-State: ALoCoQlhHftlQgHiPqH0cObmAWN5ncRxYHdzSt+/MdUPZgbiBYz96x9sWmMXt8g+Lear6AUTkakR From: Arve Hjønnevåg 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 CC: Paul Gortmaker CC: Alexander Shishkin CC: Mathieu Poirier Acked-by: Alexander Shishkin Signed-off-by: Arve Hjønnevåg Signed-off-by: John Stultz --- 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 #include #include +#include #include #include #include @@ -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 }, };