* [PATCH 0/8] coresight: etmv4: make driver usable by Perf
@ 2016-02-29 18:54 Mathieu Poirier
2016-02-29 18:54 ` [PATCH 2/8] coresight: etm4x: adding config and traceid registers Mathieu Poirier
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Mathieu Poirier @ 2016-02-29 18:54 UTC (permalink / raw)
To: linux-arm-kernel
This patchset makes the ETMv4 driver usable from Perf by way of the
recently added AUX area functionality.
The first 7 patches move code around to obtain a configuration
granularity suitable for Perf. The last patch implement the AUX area
API. Most of the code is made to resemble the work that was done on
ETMv3 as much as possible.
Best regards,
Mathieu
Mathieu Poirier (8):
coresight: etm4x: moving sysFS entries to a dedicated file
coresight: etm4x: adding config and traceid registers
coresight: etm4x: splitting struct etmv4_drvdata
coresight: etm4x: splitting etmv4 default configuration
coresight: etm4x: unlocking tracers in default arch init
coresight: etm4x: moving etm_drvdata::enable to atomic field
coresight: etm4x: implementing user/kernel mode tracing
coresight: etm4x: implementing the perf PMU API
.../ABI/testing/sysfs-bus-coresight-devices-etm4x | 13 +
drivers/hwtracing/coresight/Makefile | 8 +-
.../hwtracing/coresight/coresight-etm4x-sysfs.c | 2133 +++++++++++++++++
drivers/hwtracing/coresight/coresight-etm4x.c | 2475 +++-----------------
drivers/hwtracing/coresight/coresight-etm4x.h | 222 +-
5 files changed, 2575 insertions(+), 2276 deletions(-)
create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
--
2.1.4
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/8] coresight: etm4x: adding config and traceid registers
2016-02-29 18:54 [PATCH 0/8] coresight: etmv4: make driver usable by Perf Mathieu Poirier
@ 2016-02-29 18:54 ` Mathieu Poirier
2016-02-29 18:54 ` [PATCH 3/8] coresight: etm4x: splitting struct etmv4_drvdata Mathieu Poirier
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Poirier @ 2016-02-29 18:54 UTC (permalink / raw)
To: linux-arm-kernel
Adding new sysFS management interface to query the configuration
and the traceid registers. Both are required to convey information
to the perf cmd line tools when using ETMv4 tracers as PMU.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x | 13 +++++++++++++
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c | 4 ++++
2 files changed, 17 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
index 2355ed8ae31f..36258bc1b473 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
@@ -359,6 +359,19 @@ Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Peripheral ID3 Register
(0xFEC). The value is taken directly from the HW.
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcconfig
+Date: February 2016
+KernelVersion: 4.07
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the trace configuration register
+ (0x010) as currently set by SW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trctraceid
+Date: February 2016
+KernelVersion: 4.07
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the trace ID register (0x040).
+
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr0
Date: April 2015
KernelVersion: 4.01
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 5db0de7d4e0e..39a8b077e0c2 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -1972,6 +1972,8 @@ coresight_simple_func(trcoslsr, TRCOSLSR);
coresight_simple_func(trcpdcr, TRCPDCR);
coresight_simple_func(trcpdsr, TRCPDSR);
coresight_simple_func(trclsr, TRCLSR);
+coresight_simple_func(trcconfig, TRCCONFIGR);
+coresight_simple_func(trctraceid, TRCTRACEIDR);
coresight_simple_func(trcauthstatus, TRCAUTHSTATUS);
coresight_simple_func(trcdevid, TRCDEVID);
coresight_simple_func(trcdevtype, TRCDEVTYPE);
@@ -1985,6 +1987,8 @@ static struct attribute *coresight_etmv4_mgmt_attrs[] = {
&dev_attr_trcpdcr.attr,
&dev_attr_trcpdsr.attr,
&dev_attr_trclsr.attr,
+ &dev_attr_trcconfig.attr,
+ &dev_attr_trctraceid.attr,
&dev_attr_trcauthstatus.attr,
&dev_attr_trcdevid.attr,
&dev_attr_trcdevtype.attr,
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/8] coresight: etm4x: splitting struct etmv4_drvdata
2016-02-29 18:54 [PATCH 0/8] coresight: etmv4: make driver usable by Perf Mathieu Poirier
2016-02-29 18:54 ` [PATCH 2/8] coresight: etm4x: adding config and traceid registers Mathieu Poirier
@ 2016-02-29 18:54 ` Mathieu Poirier
2016-02-29 18:54 ` [PATCH 4/8] coresight: etm4x: splitting etmv4 default configuration Mathieu Poirier
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Poirier @ 2016-02-29 18:54 UTC (permalink / raw)
To: linux-arm-kernel
Similar to what was done on etm3x, splitting driver structure
etmv4_drvdata in two. One half is concerned with the HW
characteristics that are generally static in nature. The other
half deals with user configuration and will change from one
trace session to another.
No gain/loss of functionality is incurred from this patch.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
.../hwtracing/coresight/coresight-etm4x-sysfs.c | 642 ++++++++++++---------
drivers/hwtracing/coresight/coresight-etm4x.c | 134 ++---
drivers/hwtracing/coresight/coresight-etm4x.h | 202 +++----
3 files changed, 533 insertions(+), 445 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 39a8b077e0c2..a996db7ef2fc 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -21,13 +21,16 @@
static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
{
- u8 idx = drvdata->addr_idx;
+ u8 idx;
+ struct etmv4_config *config = &drvdata->config;
+
+ idx = config->addr_idx;
/*
* TRCACATRn.TYPE bit[1:0]: type of comparison
* the trace unit performs
*/
- if (BMVAL(drvdata->addr_acc[idx], 0, 1) == ETM_INSTR_ADDR) {
+ if (BMVAL(config->addr_acc[idx], 0, 1) == ETM_INSTR_ADDR) {
if (idx % 2 != 0)
return -EINVAL;
@@ -36,8 +39,8 @@ static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
* relevant bit of ViewInst Include/Exclude Control register
* for corresponding address comparator pair.
*/
- if (drvdata->addr_type[idx] != ETM_ADDR_TYPE_RANGE ||
- drvdata->addr_type[idx + 1] != ETM_ADDR_TYPE_RANGE)
+ if (config->addr_type[idx] != ETM_ADDR_TYPE_RANGE ||
+ config->addr_type[idx + 1] != ETM_ADDR_TYPE_RANGE)
return -EINVAL;
if (exclude == true) {
@@ -45,15 +48,15 @@ static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
* Set exclude bit and unset the include bit
* corresponding to comparator pair
*/
- drvdata->viiectlr |= BIT(idx / 2 + 16);
- drvdata->viiectlr &= ~BIT(idx / 2);
+ config->viiectlr |= BIT(idx / 2 + 16);
+ config->viiectlr &= ~BIT(idx / 2);
} else {
/*
* Set include bit and unset exclude bit
* corresponding to comparator pair
*/
- drvdata->viiectlr |= BIT(idx / 2);
- drvdata->viiectlr &= ~BIT(idx / 2 + 16);
+ config->viiectlr |= BIT(idx / 2);
+ config->viiectlr &= ~BIT(idx / 2 + 16);
}
}
return 0;
@@ -174,104 +177,107 @@ static ssize_t reset_store(struct device *dev,
int i;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
if (val)
- drvdata->mode = 0x0;
+ config->mode = 0x0;
/* Disable data tracing: do not trace load and store data transfers */
- drvdata->mode &= ~(ETM_MODE_LOAD | ETM_MODE_STORE);
- drvdata->cfg &= ~(BIT(1) | BIT(2));
+ config->mode &= ~(ETM_MODE_LOAD | ETM_MODE_STORE);
+ config->cfg &= ~(BIT(1) | BIT(2));
/* Disable data value and data address tracing */
- drvdata->mode &= ~(ETM_MODE_DATA_TRACE_ADDR |
+ config->mode &= ~(ETM_MODE_DATA_TRACE_ADDR |
ETM_MODE_DATA_TRACE_VAL);
- drvdata->cfg &= ~(BIT(16) | BIT(17));
+ config->cfg &= ~(BIT(16) | BIT(17));
/* Disable all events tracing */
- drvdata->eventctrl0 = 0x0;
- drvdata->eventctrl1 = 0x0;
+ config->eventctrl0 = 0x0;
+ config->eventctrl1 = 0x0;
/* Disable timestamp event */
- drvdata->ts_ctrl = 0x0;
+ config->ts_ctrl = 0x0;
/* Disable stalling */
- drvdata->stall_ctrl = 0x0;
+ config->stall_ctrl = 0x0;
/* Reset trace synchronization period to 2^8 = 256 bytes*/
if (drvdata->syncpr == false)
- drvdata->syncfreq = 0x8;
+ config->syncfreq = 0x8;
/*
* Enable ViewInst to trace everything with start-stop logic in
* started state. ARM recommends start-stop logic is set before
* each trace run.
*/
- drvdata->vinst_ctrl |= BIT(0);
+ config->vinst_ctrl |= BIT(0);
if (drvdata->nr_addr_cmp == true) {
- drvdata->mode |= ETM_MODE_VIEWINST_STARTSTOP;
+ config->mode |= ETM_MODE_VIEWINST_STARTSTOP;
/* SSSTATUS, bit[9] */
- drvdata->vinst_ctrl |= BIT(9);
+ config->vinst_ctrl |= BIT(9);
}
/* No address range filtering for ViewInst */
- drvdata->viiectlr = 0x0;
+ config->viiectlr = 0x0;
/* No start-stop filtering for ViewInst */
- drvdata->vissctlr = 0x0;
+ config->vissctlr = 0x0;
/* Disable seq events */
for (i = 0; i < drvdata->nrseqstate-1; i++)
- drvdata->seq_ctrl[i] = 0x0;
- drvdata->seq_rst = 0x0;
- drvdata->seq_state = 0x0;
+ config->seq_ctrl[i] = 0x0;
+ config->seq_rst = 0x0;
+ config->seq_state = 0x0;
/* Disable external input events */
- drvdata->ext_inp = 0x0;
+ config->ext_inp = 0x0;
- drvdata->cntr_idx = 0x0;
+ config->cntr_idx = 0x0;
for (i = 0; i < drvdata->nr_cntr; i++) {
- drvdata->cntrldvr[i] = 0x0;
- drvdata->cntr_ctrl[i] = 0x0;
- drvdata->cntr_val[i] = 0x0;
+ config->cntrldvr[i] = 0x0;
+ config->cntr_ctrl[i] = 0x0;
+ config->cntr_val[i] = 0x0;
}
- drvdata->res_idx = 0x0;
+ config->res_idx = 0x0;
for (i = 0; i < drvdata->nr_resource; i++)
- drvdata->res_ctrl[i] = 0x0;
+ config->res_ctrl[i] = 0x0;
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
- drvdata->ss_ctrl[i] = 0x0;
- drvdata->ss_pe_cmp[i] = 0x0;
+ config->ss_ctrl[i] = 0x0;
+ config->ss_pe_cmp[i] = 0x0;
}
- drvdata->addr_idx = 0x0;
+ config->addr_idx = 0x0;
for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
- drvdata->addr_val[i] = 0x0;
- drvdata->addr_acc[i] = 0x0;
- drvdata->addr_type[i] = ETM_ADDR_TYPE_NONE;
+ config->addr_val[i] = 0x0;
+ config->addr_acc[i] = 0x0;
+ config->addr_type[i] = ETM_ADDR_TYPE_NONE;
}
- drvdata->ctxid_idx = 0x0;
+ config->ctxid_idx = 0x0;
for (i = 0; i < drvdata->numcidc; i++) {
- drvdata->ctxid_pid[i] = 0x0;
- drvdata->ctxid_vpid[i] = 0x0;
+ config->ctxid_pid[i] = 0x0;
+ config->ctxid_vpid[i] = 0x0;
}
- drvdata->ctxid_mask0 = 0x0;
- drvdata->ctxid_mask1 = 0x0;
+ config->ctxid_mask0 = 0x0;
+ config->ctxid_mask1 = 0x0;
- drvdata->vmid_idx = 0x0;
+ config->vmid_idx = 0x0;
for (i = 0; i < drvdata->numvmidc; i++)
- drvdata->vmid_val[i] = 0x0;
- drvdata->vmid_mask0 = 0x0;
- drvdata->vmid_mask1 = 0x0;
+ config->vmid_val[i] = 0x0;
+ config->vmid_mask0 = 0x0;
+ config->vmid_mask1 = 0x0;
drvdata->trcid = drvdata->cpu + 1;
+
spin_unlock(&drvdata->spinlock);
+
return size;
}
static DEVICE_ATTR_WO(reset);
@@ -282,8 +288,9 @@ static ssize_t mode_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->mode;
+ val = config->mode;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -293,146 +300,148 @@ static ssize_t mode_store(struct device *dev,
{
unsigned long val, mode;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
- drvdata->mode = val & ETMv4_MODE_ALL;
+ config->mode = val & ETMv4_MODE_ALL;
- if (drvdata->mode & ETM_MODE_EXCLUDE)
+ if (config->mode & ETM_MODE_EXCLUDE)
etm4_set_mode_exclude(drvdata, true);
else
etm4_set_mode_exclude(drvdata, false);
if (drvdata->instrp0 == true) {
/* start by clearing instruction P0 field */
- drvdata->cfg &= ~(BIT(1) | BIT(2));
- if (drvdata->mode & ETM_MODE_LOAD)
+ config->cfg &= ~(BIT(1) | BIT(2));
+ if (config->mode & ETM_MODE_LOAD)
/* 0b01 Trace load instructions as P0 instructions */
- drvdata->cfg |= BIT(1);
- if (drvdata->mode & ETM_MODE_STORE)
+ config->cfg |= BIT(1);
+ if (config->mode & ETM_MODE_STORE)
/* 0b10 Trace store instructions as P0 instructions */
- drvdata->cfg |= BIT(2);
- if (drvdata->mode & ETM_MODE_LOAD_STORE)
+ config->cfg |= BIT(2);
+ if (config->mode & ETM_MODE_LOAD_STORE)
/*
* 0b11 Trace load and store instructions
* as P0 instructions
*/
- drvdata->cfg |= BIT(1) | BIT(2);
+ config->cfg |= BIT(1) | BIT(2);
}
/* bit[3], Branch broadcast mode */
- if ((drvdata->mode & ETM_MODE_BB) && (drvdata->trcbb == true))
- drvdata->cfg |= BIT(3);
+ if ((config->mode & ETM_MODE_BB) && (drvdata->trcbb == true))
+ config->cfg |= BIT(3);
else
- drvdata->cfg &= ~BIT(3);
+ config->cfg &= ~BIT(3);
/* bit[4], Cycle counting instruction trace bit */
- if ((drvdata->mode & ETMv4_MODE_CYCACC) &&
+ if ((config->mode & ETMv4_MODE_CYCACC) &&
(drvdata->trccci == true))
- drvdata->cfg |= BIT(4);
+ config->cfg |= BIT(4);
else
- drvdata->cfg &= ~BIT(4);
+ config->cfg &= ~BIT(4);
/* bit[6], Context ID tracing bit */
- if ((drvdata->mode & ETMv4_MODE_CTXID) && (drvdata->ctxid_size))
- drvdata->cfg |= BIT(6);
+ if ((config->mode & ETMv4_MODE_CTXID) && (drvdata->ctxid_size))
+ config->cfg |= BIT(6);
else
- drvdata->cfg &= ~BIT(6);
+ config->cfg &= ~BIT(6);
- if ((drvdata->mode & ETM_MODE_VMID) && (drvdata->vmid_size))
- drvdata->cfg |= BIT(7);
+ if ((config->mode & ETM_MODE_VMID) && (drvdata->vmid_size))
+ config->cfg |= BIT(7);
else
- drvdata->cfg &= ~BIT(7);
+ config->cfg &= ~BIT(7);
/* bits[10:8], Conditional instruction tracing bit */
- mode = ETM_MODE_COND(drvdata->mode);
+ mode = ETM_MODE_COND(config->mode);
if (drvdata->trccond == true) {
- drvdata->cfg &= ~(BIT(8) | BIT(9) | BIT(10));
- drvdata->cfg |= mode << 8;
+ config->cfg &= ~(BIT(8) | BIT(9) | BIT(10));
+ config->cfg |= mode << 8;
}
/* bit[11], Global timestamp tracing bit */
- if ((drvdata->mode & ETMv4_MODE_TIMESTAMP) && (drvdata->ts_size))
- drvdata->cfg |= BIT(11);
+ if ((config->mode & ETMv4_MODE_TIMESTAMP) && (drvdata->ts_size))
+ config->cfg |= BIT(11);
else
- drvdata->cfg &= ~BIT(11);
+ config->cfg &= ~BIT(11);
/* bit[12], Return stack enable bit */
- if ((drvdata->mode & ETM_MODE_RETURNSTACK) &&
- (drvdata->retstack == true))
- drvdata->cfg |= BIT(12);
+ if ((config->mode & ETM_MODE_RETURNSTACK) &&
+ (drvdata->retstack == true))
+ config->cfg |= BIT(12);
else
- drvdata->cfg &= ~BIT(12);
+ config->cfg &= ~BIT(12);
/* bits[14:13], Q element enable field */
- mode = ETM_MODE_QELEM(drvdata->mode);
+ mode = ETM_MODE_QELEM(config->mode);
/* start by clearing QE bits */
- drvdata->cfg &= ~(BIT(13) | BIT(14));
+ config->cfg &= ~(BIT(13) | BIT(14));
/* if supported, Q elements with instruction counts are enabled */
if ((mode & BIT(0)) && (drvdata->q_support & BIT(0)))
- drvdata->cfg |= BIT(13);
+ config->cfg |= BIT(13);
/*
* if supported, Q elements with and without instruction
* counts are enabled
*/
if ((mode & BIT(1)) && (drvdata->q_support & BIT(1)))
- drvdata->cfg |= BIT(14);
+ config->cfg |= BIT(14);
/* bit[11], AMBA Trace Bus (ATB) trigger enable bit */
- if ((drvdata->mode & ETM_MODE_ATB_TRIGGER) &&
+ if ((config->mode & ETM_MODE_ATB_TRIGGER) &&
(drvdata->atbtrig == true))
- drvdata->eventctrl1 |= BIT(11);
+ config->eventctrl1 |= BIT(11);
else
- drvdata->eventctrl1 &= ~BIT(11);
+ config->eventctrl1 &= ~BIT(11);
/* bit[12], Low-power state behavior override bit */
- if ((drvdata->mode & ETM_MODE_LPOVERRIDE) &&
+ if ((config->mode & ETM_MODE_LPOVERRIDE) &&
(drvdata->lpoverride == true))
- drvdata->eventctrl1 |= BIT(12);
+ config->eventctrl1 |= BIT(12);
else
- drvdata->eventctrl1 &= ~BIT(12);
+ config->eventctrl1 &= ~BIT(12);
/* bit[8], Instruction stall bit */
- if (drvdata->mode & ETM_MODE_ISTALL_EN)
- drvdata->stall_ctrl |= BIT(8);
+ if (config->mode & ETM_MODE_ISTALL_EN)
+ config->stall_ctrl |= BIT(8);
else
- drvdata->stall_ctrl &= ~BIT(8);
+ config->stall_ctrl &= ~BIT(8);
/* bit[10], Prioritize instruction trace bit */
- if (drvdata->mode & ETM_MODE_INSTPRIO)
- drvdata->stall_ctrl |= BIT(10);
+ if (config->mode & ETM_MODE_INSTPRIO)
+ config->stall_ctrl |= BIT(10);
else
- drvdata->stall_ctrl &= ~BIT(10);
+ config->stall_ctrl &= ~BIT(10);
/* bit[13], Trace overflow prevention bit */
- if ((drvdata->mode & ETM_MODE_NOOVERFLOW) &&
+ if ((config->mode & ETM_MODE_NOOVERFLOW) &&
(drvdata->nooverflow == true))
- drvdata->stall_ctrl |= BIT(13);
+ config->stall_ctrl |= BIT(13);
else
- drvdata->stall_ctrl &= ~BIT(13);
+ config->stall_ctrl &= ~BIT(13);
/* bit[9] Start/stop logic control bit */
- if (drvdata->mode & ETM_MODE_VIEWINST_STARTSTOP)
- drvdata->vinst_ctrl |= BIT(9);
+ if (config->mode & ETM_MODE_VIEWINST_STARTSTOP)
+ config->vinst_ctrl |= BIT(9);
else
- drvdata->vinst_ctrl &= ~BIT(9);
+ config->vinst_ctrl &= ~BIT(9);
/* bit[10], Whether a trace unit must trace a Reset exception */
- if (drvdata->mode & ETM_MODE_TRACE_RESET)
- drvdata->vinst_ctrl |= BIT(10);
+ if (config->mode & ETM_MODE_TRACE_RESET)
+ config->vinst_ctrl |= BIT(10);
else
- drvdata->vinst_ctrl &= ~BIT(10);
+ config->vinst_ctrl &= ~BIT(10);
/* bit[11], Whether a trace unit must trace a system error exception */
- if ((drvdata->mode & ETM_MODE_TRACE_ERR) &&
+ if ((config->mode & ETM_MODE_TRACE_ERR) &&
(drvdata->trc_error == true))
- drvdata->vinst_ctrl |= BIT(11);
+ config->vinst_ctrl |= BIT(11);
else
- drvdata->vinst_ctrl &= ~BIT(11);
+ config->vinst_ctrl &= ~BIT(11);
spin_unlock(&drvdata->spinlock);
+
return size;
}
static DEVICE_ATTR_RW(mode);
@@ -443,8 +452,9 @@ static ssize_t pe_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->pe_sel;
+ val = config->pe_sel;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -454,6 +464,7 @@ static ssize_t pe_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -464,7 +475,7 @@ static ssize_t pe_store(struct device *dev,
return -EINVAL;
}
- drvdata->pe_sel = val;
+ config->pe_sel = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -476,8 +487,9 @@ static ssize_t event_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->eventctrl0;
+ val = config->eventctrl0;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -487,6 +499,7 @@ static ssize_t event_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -495,19 +508,19 @@ static ssize_t event_store(struct device *dev,
switch (drvdata->nr_event) {
case 0x0:
/* EVENT0, bits[7:0] */
- drvdata->eventctrl0 = val & 0xFF;
+ config->eventctrl0 = val & 0xFF;
break;
case 0x1:
/* EVENT1, bits[15:8] */
- drvdata->eventctrl0 = val & 0xFFFF;
+ config->eventctrl0 = val & 0xFFFF;
break;
case 0x2:
/* EVENT2, bits[23:16] */
- drvdata->eventctrl0 = val & 0xFFFFFF;
+ config->eventctrl0 = val & 0xFFFFFF;
break;
case 0x3:
/* EVENT3, bits[31:24] */
- drvdata->eventctrl0 = val;
+ config->eventctrl0 = val;
break;
default:
break;
@@ -523,8 +536,9 @@ static ssize_t event_instren_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = BMVAL(drvdata->eventctrl1, 0, 3);
+ val = BMVAL(config->eventctrl1, 0, 3);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -534,29 +548,30 @@ static ssize_t event_instren_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
/* start by clearing all instruction event enable bits */
- drvdata->eventctrl1 &= ~(BIT(0) | BIT(1) | BIT(2) | BIT(3));
+ config->eventctrl1 &= ~(BIT(0) | BIT(1) | BIT(2) | BIT(3));
switch (drvdata->nr_event) {
case 0x0:
/* generate Event element for event 1 */
- drvdata->eventctrl1 |= val & BIT(1);
+ config->eventctrl1 |= val & BIT(1);
break;
case 0x1:
/* generate Event element for event 1 and 2 */
- drvdata->eventctrl1 |= val & (BIT(0) | BIT(1));
+ config->eventctrl1 |= val & (BIT(0) | BIT(1));
break;
case 0x2:
/* generate Event element for event 1, 2 and 3 */
- drvdata->eventctrl1 |= val & (BIT(0) | BIT(1) | BIT(2));
+ config->eventctrl1 |= val & (BIT(0) | BIT(1) | BIT(2));
break;
case 0x3:
/* generate Event element for all 4 events */
- drvdata->eventctrl1 |= val & 0xF;
+ config->eventctrl1 |= val & 0xF;
break;
default:
break;
@@ -572,8 +587,9 @@ static ssize_t event_ts_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->ts_ctrl;
+ val = config->ts_ctrl;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -583,13 +599,14 @@ static ssize_t event_ts_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
if (!drvdata->ts_size)
return -EINVAL;
- drvdata->ts_ctrl = val & ETMv4_EVENT_MASK;
+ config->ts_ctrl = val & ETMv4_EVENT_MASK;
return size;
}
static DEVICE_ATTR_RW(event_ts);
@@ -600,8 +617,9 @@ static ssize_t syncfreq_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->syncfreq;
+ val = config->syncfreq;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -611,13 +629,14 @@ static ssize_t syncfreq_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
if (drvdata->syncpr == true)
return -EINVAL;
- drvdata->syncfreq = val & ETMv4_SYNC_MASK;
+ config->syncfreq = val & ETMv4_SYNC_MASK;
return size;
}
static DEVICE_ATTR_RW(syncfreq);
@@ -628,8 +647,9 @@ static ssize_t cyc_threshold_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->ccctlr;
+ val = config->ccctlr;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -639,13 +659,14 @@ static ssize_t cyc_threshold_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
if (val < drvdata->ccitmin)
return -EINVAL;
- drvdata->ccctlr = val & ETM_CYC_THRESHOLD_MASK;
+ config->ccctlr = val & ETM_CYC_THRESHOLD_MASK;
return size;
}
static DEVICE_ATTR_RW(cyc_threshold);
@@ -656,8 +677,9 @@ static ssize_t bb_ctrl_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->bb_ctrl;
+ val = config->bb_ctrl;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -667,6 +689,7 @@ static ssize_t bb_ctrl_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -681,7 +704,7 @@ static ssize_t bb_ctrl_store(struct device *dev,
if (BMVAL(val, 0, 7) > drvdata->nr_addr_cmp)
return -EINVAL;
- drvdata->bb_ctrl = val;
+ config->bb_ctrl = val;
return size;
}
static DEVICE_ATTR_RW(bb_ctrl);
@@ -692,8 +715,9 @@ static ssize_t event_vinst_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->vinst_ctrl & ETMv4_EVENT_MASK;
+ val = config->vinst_ctrl & ETMv4_EVENT_MASK;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -703,14 +727,15 @@ static ssize_t event_vinst_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
val &= ETMv4_EVENT_MASK;
- drvdata->vinst_ctrl &= ~ETMv4_EVENT_MASK;
- drvdata->vinst_ctrl |= val;
+ config->vinst_ctrl &= ~ETMv4_EVENT_MASK;
+ config->vinst_ctrl |= val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -722,8 +747,9 @@ static ssize_t s_exlevel_vinst_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = BMVAL(drvdata->vinst_ctrl, 16, 19);
+ val = BMVAL(config->vinst_ctrl, 16, 19);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -733,16 +759,17 @@ static ssize_t s_exlevel_vinst_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
/* clear all EXLEVEL_S bits (bit[18] is never implemented) */
- drvdata->vinst_ctrl &= ~(BIT(16) | BIT(17) | BIT(19));
+ config->vinst_ctrl &= ~(BIT(16) | BIT(17) | BIT(19));
/* enable instruction tracing for corresponding exception level */
val &= drvdata->s_ex_level;
- drvdata->vinst_ctrl |= (val << 16);
+ config->vinst_ctrl |= (val << 16);
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -754,9 +781,10 @@ static ssize_t ns_exlevel_vinst_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
/* EXLEVEL_NS, bits[23:20] */
- val = BMVAL(drvdata->vinst_ctrl, 20, 23);
+ val = BMVAL(config->vinst_ctrl, 20, 23);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -766,16 +794,17 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
/* clear EXLEVEL_NS bits (bit[23] is never implemented */
- drvdata->vinst_ctrl &= ~(BIT(20) | BIT(21) | BIT(22));
+ config->vinst_ctrl &= ~(BIT(20) | BIT(21) | BIT(22));
/* enable instruction tracing for corresponding exception level */
val &= drvdata->ns_ex_level;
- drvdata->vinst_ctrl |= (val << 20);
+ config->vinst_ctrl |= (val << 20);
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -787,8 +816,9 @@ static ssize_t addr_idx_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->addr_idx;
+ val = config->addr_idx;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -798,6 +828,7 @@ static ssize_t addr_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -809,7 +840,7 @@ static ssize_t addr_idx_store(struct device *dev,
* dereferenced multiple times within a spinlock block elsewhere.
*/
spin_lock(&drvdata->spinlock);
- drvdata->addr_idx = val;
+ config->addr_idx = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -822,10 +853,11 @@ static ssize_t addr_instdatatype_show(struct device *dev,
ssize_t len;
u8 val, idx;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
- val = BMVAL(drvdata->addr_acc[idx], 0, 1);
+ idx = config->addr_idx;
+ val = BMVAL(config->addr_acc[idx], 0, 1);
len = scnprintf(buf, PAGE_SIZE, "%s\n",
val == ETM_INSTR_ADDR ? "instr" :
(val == ETM_DATA_LOAD_ADDR ? "data_load" :
@@ -842,6 +874,7 @@ static ssize_t addr_instdatatype_store(struct device *dev,
u8 idx;
char str[20] = "";
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (strlen(buf) >= 20)
return -EINVAL;
@@ -849,10 +882,10 @@ static ssize_t addr_instdatatype_store(struct device *dev,
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
if (!strcmp(str, "instr"))
/* TYPE, bits[1:0] */
- drvdata->addr_acc[idx] &= ~(BIT(0) | BIT(1));
+ config->addr_acc[idx] &= ~(BIT(0) | BIT(1));
spin_unlock(&drvdata->spinlock);
return size;
@@ -866,15 +899,16 @@ static ssize_t addr_single_show(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
spin_lock(&drvdata->spinlock);
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
- val = (unsigned long)drvdata->addr_val[idx];
+ val = (unsigned long)config->addr_val[idx];
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -886,20 +920,21 @@ static ssize_t addr_single_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+ idx = config->addr_idx;
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
- drvdata->addr_val[idx] = (u64)val;
- drvdata->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
+ config->addr_val[idx] = (u64)val;
+ config->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -912,23 +947,24 @@ static ssize_t addr_range_show(struct device *dev,
u8 idx;
unsigned long val1, val2;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
if (idx % 2 != 0) {
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
- if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
- drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
- (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
- drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+ if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+ config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+ (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+ config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
- val1 = (unsigned long)drvdata->addr_val[idx];
- val2 = (unsigned long)drvdata->addr_val[idx + 1];
+ val1 = (unsigned long)config->addr_val[idx];
+ val2 = (unsigned long)config->addr_val[idx + 1];
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
}
@@ -940,6 +976,7 @@ static ssize_t addr_range_store(struct device *dev,
u8 idx;
unsigned long val1, val2;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
return -EINVAL;
@@ -948,29 +985,29 @@ static ssize_t addr_range_store(struct device *dev,
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
if (idx % 2 != 0) {
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
- if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
- drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
- (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
- drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+ if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+ config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+ (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+ config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
- drvdata->addr_val[idx] = (u64)val1;
- drvdata->addr_type[idx] = ETM_ADDR_TYPE_RANGE;
- drvdata->addr_val[idx + 1] = (u64)val2;
- drvdata->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
+ config->addr_val[idx] = (u64)val1;
+ config->addr_type[idx] = ETM_ADDR_TYPE_RANGE;
+ config->addr_val[idx + 1] = (u64)val2;
+ config->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
/*
* Program include or exclude control bits for vinst or vdata
* whenever we change addr comparators to ETM_ADDR_TYPE_RANGE
*/
- if (drvdata->mode & ETM_MODE_EXCLUDE)
+ if (config->mode & ETM_MODE_EXCLUDE)
etm4_set_mode_exclude(drvdata, true);
else
etm4_set_mode_exclude(drvdata, false);
@@ -987,17 +1024,18 @@ static ssize_t addr_start_show(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
- val = (unsigned long)drvdata->addr_val[idx];
+ val = (unsigned long)config->addr_val[idx];
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1009,27 +1047,28 @@ static ssize_t addr_start_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
if (!drvdata->nr_addr_cmp) {
spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
- drvdata->addr_val[idx] = (u64)val;
- drvdata->addr_type[idx] = ETM_ADDR_TYPE_START;
- drvdata->vissctlr |= BIT(idx);
+ config->addr_val[idx] = (u64)val;
+ config->addr_type[idx] = ETM_ADDR_TYPE_START;
+ config->vissctlr |= BIT(idx);
/* SSSTATUS, bit[9] - turn on start/stop logic */
- drvdata->vinst_ctrl |= BIT(9);
+ config->vinst_ctrl |= BIT(9);
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1042,17 +1081,18 @@ static ssize_t addr_stop_show(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
- val = (unsigned long)drvdata->addr_val[idx];
+ val = (unsigned long)config->addr_val[idx];
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1064,27 +1104,28 @@ static ssize_t addr_stop_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
if (!drvdata->nr_addr_cmp) {
spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
- if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
- drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+ if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+ config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
- drvdata->addr_val[idx] = (u64)val;
- drvdata->addr_type[idx] = ETM_ADDR_TYPE_STOP;
- drvdata->vissctlr |= BIT(idx + 16);
+ config->addr_val[idx] = (u64)val;
+ config->addr_type[idx] = ETM_ADDR_TYPE_STOP;
+ config->vissctlr |= BIT(idx + 16);
/* SSSTATUS, bit[9] - turn on start/stop logic */
- drvdata->vinst_ctrl |= BIT(9);
+ config->vinst_ctrl |= BIT(9);
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1097,11 +1138,12 @@ static ssize_t addr_ctxtype_show(struct device *dev,
ssize_t len;
u8 idx, val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
/* CONTEXTTYPE, bits[3:2] */
- val = BMVAL(drvdata->addr_acc[idx], 2, 3);
+ val = BMVAL(config->addr_acc[idx], 2, 3);
len = scnprintf(buf, PAGE_SIZE, "%s\n", val == ETM_CTX_NONE ? "none" :
(val == ETM_CTX_CTXID ? "ctxid" :
(val == ETM_CTX_VMID ? "vmid" : "all")));
@@ -1116,6 +1158,7 @@ static ssize_t addr_ctxtype_store(struct device *dev,
u8 idx;
char str[10] = "";
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (strlen(buf) >= 10)
return -EINVAL;
@@ -1123,21 +1166,21 @@ static ssize_t addr_ctxtype_store(struct device *dev,
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
if (!strcmp(str, "none"))
/* start by clearing context type bits */
- drvdata->addr_acc[idx] &= ~(BIT(2) | BIT(3));
+ config->addr_acc[idx] &= ~(BIT(2) | BIT(3));
else if (!strcmp(str, "ctxid")) {
/* 0b01 The trace unit performs a Context ID */
if (drvdata->numcidc) {
- drvdata->addr_acc[idx] |= BIT(2);
- drvdata->addr_acc[idx] &= ~BIT(3);
+ config->addr_acc[idx] |= BIT(2);
+ config->addr_acc[idx] &= ~BIT(3);
}
} else if (!strcmp(str, "vmid")) {
/* 0b10 The trace unit performs a VMID */
if (drvdata->numvmidc) {
- drvdata->addr_acc[idx] &= ~BIT(2);
- drvdata->addr_acc[idx] |= BIT(3);
+ config->addr_acc[idx] &= ~BIT(2);
+ config->addr_acc[idx] |= BIT(3);
}
} else if (!strcmp(str, "all")) {
/*
@@ -1145,9 +1188,9 @@ static ssize_t addr_ctxtype_store(struct device *dev,
* comparison and a VMID
*/
if (drvdata->numcidc)
- drvdata->addr_acc[idx] |= BIT(2);
+ config->addr_acc[idx] |= BIT(2);
if (drvdata->numvmidc)
- drvdata->addr_acc[idx] |= BIT(3);
+ config->addr_acc[idx] |= BIT(3);
}
spin_unlock(&drvdata->spinlock);
return size;
@@ -1161,11 +1204,12 @@ static ssize_t addr_context_show(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
/* context ID comparator bits[6:4] */
- val = BMVAL(drvdata->addr_acc[idx], 4, 6);
+ val = BMVAL(config->addr_acc[idx], 4, 6);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1177,6 +1221,7 @@ static ssize_t addr_context_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -1187,10 +1232,10 @@ static ssize_t addr_context_store(struct device *dev,
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->addr_idx;
+ idx = config->addr_idx;
/* clear context ID comparator bits[6:4] */
- drvdata->addr_acc[idx] &= ~(BIT(4) | BIT(5) | BIT(6));
- drvdata->addr_acc[idx] |= (val << 4);
+ config->addr_acc[idx] &= ~(BIT(4) | BIT(5) | BIT(6));
+ config->addr_acc[idx] |= (val << 4);
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1202,8 +1247,9 @@ static ssize_t seq_idx_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->seq_idx;
+ val = config->seq_idx;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1213,6 +1259,7 @@ static ssize_t seq_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -1224,7 +1271,7 @@ static ssize_t seq_idx_store(struct device *dev,
* dereferenced multiple times within a spinlock block elsewhere.
*/
spin_lock(&drvdata->spinlock);
- drvdata->seq_idx = val;
+ config->seq_idx = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1236,8 +1283,9 @@ static ssize_t seq_state_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->seq_state;
+ val = config->seq_state;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1247,13 +1295,14 @@ static ssize_t seq_state_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
if (val >= drvdata->nrseqstate)
return -EINVAL;
- drvdata->seq_state = val;
+ config->seq_state = val;
return size;
}
static DEVICE_ATTR_RW(seq_state);
@@ -1265,10 +1314,11 @@ static ssize_t seq_event_show(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->seq_idx;
- val = drvdata->seq_ctrl[idx];
+ idx = config->seq_idx;
+ val = config->seq_ctrl[idx];
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1280,14 +1330,15 @@ static ssize_t seq_event_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->seq_idx;
+ idx = config->seq_idx;
/* RST, bits[7:0] */
- drvdata->seq_ctrl[idx] = val & 0xFF;
+ config->seq_ctrl[idx] = val & 0xFF;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1299,8 +1350,9 @@ static ssize_t seq_reset_event_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->seq_rst;
+ val = config->seq_rst;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1310,13 +1362,14 @@ static ssize_t seq_reset_event_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
if (!(drvdata->nrseqstate))
return -EINVAL;
- drvdata->seq_rst = val & ETMv4_EVENT_MASK;
+ config->seq_rst = val & ETMv4_EVENT_MASK;
return size;
}
static DEVICE_ATTR_RW(seq_reset_event);
@@ -1327,8 +1380,9 @@ static ssize_t cntr_idx_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->cntr_idx;
+ val = config->cntr_idx;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1338,6 +1392,7 @@ static ssize_t cntr_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -1349,7 +1404,7 @@ static ssize_t cntr_idx_store(struct device *dev,
* dereferenced multiple times within a spinlock block elsewhere.
*/
spin_lock(&drvdata->spinlock);
- drvdata->cntr_idx = val;
+ config->cntr_idx = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1362,10 +1417,11 @@ static ssize_t cntrldvr_show(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->cntr_idx;
- val = drvdata->cntrldvr[idx];
+ idx = config->cntr_idx;
+ val = config->cntrldvr[idx];
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1377,6 +1433,7 @@ static ssize_t cntrldvr_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -1384,8 +1441,8 @@ static ssize_t cntrldvr_store(struct device *dev,
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->cntr_idx;
- drvdata->cntrldvr[idx] = val;
+ idx = config->cntr_idx;
+ config->cntrldvr[idx] = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1398,10 +1455,11 @@ static ssize_t cntr_val_show(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->cntr_idx;
- val = drvdata->cntr_val[idx];
+ idx = config->cntr_idx;
+ val = config->cntr_val[idx];
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1413,6 +1471,7 @@ static ssize_t cntr_val_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -1420,8 +1479,8 @@ static ssize_t cntr_val_store(struct device *dev,
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->cntr_idx;
- drvdata->cntr_val[idx] = val;
+ idx = config->cntr_idx;
+ config->cntr_val[idx] = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1434,10 +1493,11 @@ static ssize_t cntr_ctrl_show(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->cntr_idx;
- val = drvdata->cntr_ctrl[idx];
+ idx = config->cntr_idx;
+ val = config->cntr_ctrl[idx];
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1449,13 +1509,14 @@ static ssize_t cntr_ctrl_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->cntr_idx;
- drvdata->cntr_ctrl[idx] = val;
+ idx = config->cntr_idx;
+ config->cntr_ctrl[idx] = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1467,8 +1528,9 @@ static ssize_t res_idx_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->res_idx;
+ val = config->res_idx;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1478,6 +1540,7 @@ static ssize_t res_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -1490,7 +1553,7 @@ static ssize_t res_idx_store(struct device *dev,
* dereferenced multiple times within a spinlock block elsewhere.
*/
spin_lock(&drvdata->spinlock);
- drvdata->res_idx = val;
+ config->res_idx = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1503,10 +1566,11 @@ static ssize_t res_ctrl_show(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->res_idx;
- val = drvdata->res_ctrl[idx];
+ idx = config->res_idx;
+ val = config->res_ctrl[idx];
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1518,17 +1582,18 @@ static ssize_t res_ctrl_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
- idx = drvdata->res_idx;
+ idx = config->res_idx;
/* For odd idx pair inversal bit is RES0 */
if (idx % 2 != 0)
/* PAIRINV, bit[21] */
val &= ~BIT(21);
- drvdata->res_ctrl[idx] = val;
+ config->res_ctrl[idx] = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1540,8 +1605,9 @@ static ssize_t ctxid_idx_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->ctxid_idx;
+ val = config->ctxid_idx;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1551,6 +1617,7 @@ static ssize_t ctxid_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -1562,7 +1629,7 @@ static ssize_t ctxid_idx_store(struct device *dev,
* dereferenced multiple times within a spinlock block elsewhere.
*/
spin_lock(&drvdata->spinlock);
- drvdata->ctxid_idx = val;
+ config->ctxid_idx = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1575,10 +1642,11 @@ static ssize_t ctxid_pid_show(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- idx = drvdata->ctxid_idx;
- val = (unsigned long)drvdata->ctxid_vpid[idx];
+ idx = config->ctxid_idx;
+ val = (unsigned long)config->ctxid_vpid[idx];
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1590,6 +1658,7 @@ static ssize_t ctxid_pid_store(struct device *dev,
u8 idx;
unsigned long vpid, pid;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
/*
* only implemented when ctxid tracing is enabled, i.e. at least one
@@ -1604,9 +1673,9 @@ static ssize_t ctxid_pid_store(struct device *dev,
pid = coresight_vpid_to_pid(vpid);
spin_lock(&drvdata->spinlock);
- idx = drvdata->ctxid_idx;
- drvdata->ctxid_pid[idx] = (u64)pid;
- drvdata->ctxid_vpid[idx] = (u64)vpid;
+ idx = config->ctxid_idx;
+ config->ctxid_pid[idx] = (u64)pid;
+ config->ctxid_vpid[idx] = (u64)vpid;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1618,10 +1687,11 @@ static ssize_t ctxid_masks_show(struct device *dev,
{
unsigned long val1, val2;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- val1 = drvdata->ctxid_mask0;
- val2 = drvdata->ctxid_mask1;
+ val1 = config->ctxid_mask0;
+ val2 = config->ctxid_mask1;
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
}
@@ -1633,6 +1703,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
u8 i, j, maskbyte;
unsigned long val1, val2, mask;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
/*
* only implemented when ctxid tracing is enabled, i.e. at least one
@@ -1652,39 +1723,39 @@ static ssize_t ctxid_masks_store(struct device *dev,
switch (drvdata->numcidc) {
case 0x1:
/* COMP0, bits[7:0] */
- drvdata->ctxid_mask0 = val1 & 0xFF;
+ config->ctxid_mask0 = val1 & 0xFF;
break;
case 0x2:
/* COMP1, bits[15:8] */
- drvdata->ctxid_mask0 = val1 & 0xFFFF;
+ config->ctxid_mask0 = val1 & 0xFFFF;
break;
case 0x3:
/* COMP2, bits[23:16] */
- drvdata->ctxid_mask0 = val1 & 0xFFFFFF;
+ config->ctxid_mask0 = val1 & 0xFFFFFF;
break;
case 0x4:
/* COMP3, bits[31:24] */
- drvdata->ctxid_mask0 = val1;
+ config->ctxid_mask0 = val1;
break;
case 0x5:
/* COMP4, bits[7:0] */
- drvdata->ctxid_mask0 = val1;
- drvdata->ctxid_mask1 = val2 & 0xFF;
+ config->ctxid_mask0 = val1;
+ config->ctxid_mask1 = val2 & 0xFF;
break;
case 0x6:
/* COMP5, bits[15:8] */
- drvdata->ctxid_mask0 = val1;
- drvdata->ctxid_mask1 = val2 & 0xFFFF;
+ config->ctxid_mask0 = val1;
+ config->ctxid_mask1 = val2 & 0xFFFF;
break;
case 0x7:
/* COMP6, bits[23:16] */
- drvdata->ctxid_mask0 = val1;
- drvdata->ctxid_mask1 = val2 & 0xFFFFFF;
+ config->ctxid_mask0 = val1;
+ config->ctxid_mask1 = val2 & 0xFFFFFF;
break;
case 0x8:
/* COMP7, bits[31:24] */
- drvdata->ctxid_mask0 = val1;
- drvdata->ctxid_mask1 = val2;
+ config->ctxid_mask0 = val1;
+ config->ctxid_mask1 = val2;
break;
default:
break;
@@ -1695,7 +1766,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
* For example, if bit[3] of ctxid_mask0 is 1, we must clear bits[31:24]
* of ctxid comparator0 value (corresponding to byte 0) register.
*/
- mask = drvdata->ctxid_mask0;
+ mask = config->ctxid_mask0;
for (i = 0; i < drvdata->numcidc; i++) {
/* mask value of corresponding ctxid comparator */
maskbyte = mask & ETMv4_EVENT_MASK;
@@ -1705,13 +1776,13 @@ static ssize_t ctxid_masks_store(struct device *dev,
*/
for (j = 0; j < 8; j++) {
if (maskbyte & 1)
- drvdata->ctxid_pid[i] &= ~(0xFF << (j * 8));
+ config->ctxid_pid[i] &= ~(0xFF << (j * 8));
maskbyte >>= 1;
}
/* Select the next ctxid comparator mask value */
if (i == 3)
/* ctxid comparators[4-7] */
- mask = drvdata->ctxid_mask1;
+ mask = config->ctxid_mask1;
else
mask >>= 0x8;
}
@@ -1727,8 +1798,9 @@ static ssize_t vmid_idx_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = drvdata->vmid_idx;
+ val = config->vmid_idx;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1738,6 +1810,7 @@ static ssize_t vmid_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -1749,7 +1822,7 @@ static ssize_t vmid_idx_store(struct device *dev,
* dereferenced multiple times within a spinlock block elsewhere.
*/
spin_lock(&drvdata->spinlock);
- drvdata->vmid_idx = val;
+ config->vmid_idx = val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1761,8 +1834,9 @@ static ssize_t vmid_val_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
- val = (unsigned long)drvdata->vmid_val[drvdata->vmid_idx];
+ val = (unsigned long)config->vmid_val[config->vmid_idx];
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1772,6 +1846,7 @@ static ssize_t vmid_val_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
/*
* only implemented when vmid tracing is enabled, i.e. at least one
@@ -1783,7 +1858,7 @@ static ssize_t vmid_val_store(struct device *dev,
return -EINVAL;
spin_lock(&drvdata->spinlock);
- drvdata->vmid_val[drvdata->vmid_idx] = (u64)val;
+ config->vmid_val[config->vmid_idx] = (u64)val;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1794,10 +1869,11 @@ static ssize_t vmid_masks_show(struct device *dev,
{
unsigned long val1, val2;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
spin_lock(&drvdata->spinlock);
- val1 = drvdata->vmid_mask0;
- val2 = drvdata->vmid_mask1;
+ val1 = config->vmid_mask0;
+ val2 = config->vmid_mask1;
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
}
@@ -1809,6 +1885,8 @@ static ssize_t vmid_masks_store(struct device *dev,
u8 i, j, maskbyte;
unsigned long val1, val2, mask;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
+
/*
* only implemented when vmid tracing is enabled, i.e. at least one
* vmid comparator is implemented and at least 8 bit vmid size
@@ -1827,39 +1905,39 @@ static ssize_t vmid_masks_store(struct device *dev,
switch (drvdata->numvmidc) {
case 0x1:
/* COMP0, bits[7:0] */
- drvdata->vmid_mask0 = val1 & 0xFF;
+ config->vmid_mask0 = val1 & 0xFF;
break;
case 0x2:
/* COMP1, bits[15:8] */
- drvdata->vmid_mask0 = val1 & 0xFFFF;
+ config->vmid_mask0 = val1 & 0xFFFF;
break;
case 0x3:
/* COMP2, bits[23:16] */
- drvdata->vmid_mask0 = val1 & 0xFFFFFF;
+ config->vmid_mask0 = val1 & 0xFFFFFF;
break;
case 0x4:
/* COMP3, bits[31:24] */
- drvdata->vmid_mask0 = val1;
+ config->vmid_mask0 = val1;
break;
case 0x5:
/* COMP4, bits[7:0] */
- drvdata->vmid_mask0 = val1;
- drvdata->vmid_mask1 = val2 & 0xFF;
+ config->vmid_mask0 = val1;
+ config->vmid_mask1 = val2 & 0xFF;
break;
case 0x6:
/* COMP5, bits[15:8] */
- drvdata->vmid_mask0 = val1;
- drvdata->vmid_mask1 = val2 & 0xFFFF;
+ config->vmid_mask0 = val1;
+ config->vmid_mask1 = val2 & 0xFFFF;
break;
case 0x7:
/* COMP6, bits[23:16] */
- drvdata->vmid_mask0 = val1;
- drvdata->vmid_mask1 = val2 & 0xFFFFFF;
+ config->vmid_mask0 = val1;
+ config->vmid_mask1 = val2 & 0xFFFFFF;
break;
case 0x8:
/* COMP7, bits[31:24] */
- drvdata->vmid_mask0 = val1;
- drvdata->vmid_mask1 = val2;
+ config->vmid_mask0 = val1;
+ config->vmid_mask1 = val2;
break;
default:
break;
@@ -1871,7 +1949,7 @@ static ssize_t vmid_masks_store(struct device *dev,
* For example, if bit[3] of vmid_mask0 is 1, we must clear bits[31:24]
* of vmid comparator0 value (corresponding to byte 0) register.
*/
- mask = drvdata->vmid_mask0;
+ mask = config->vmid_mask0;
for (i = 0; i < drvdata->numvmidc; i++) {
/* mask value of corresponding vmid comparator */
maskbyte = mask & ETMv4_EVENT_MASK;
@@ -1881,13 +1959,13 @@ static ssize_t vmid_masks_store(struct device *dev,
*/
for (j = 0; j < 8; j++) {
if (maskbyte & 1)
- drvdata->vmid_val[i] &= ~(0xFF << (j * 8));
+ config->vmid_val[i] &= ~(0xFF << (j * 8));
maskbyte >>= 1;
}
/* Select the next vmid comparator mask value */
if (i == 3)
/* vmid comparators[4-7] */
- mask = drvdata->vmid_mask1;
+ mask = config->vmid_mask1;
else
mask >>= 0x8;
}
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 033e51817492..e204db40082b 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -96,6 +96,7 @@ static void etm4_enable_hw(void *info)
{
int i;
struct etmv4_drvdata *drvdata = info;
+ struct etmv4_config *config = &drvdata->config;
CS_UNLOCK(drvdata->base);
@@ -110,69 +111,69 @@ static void etm4_enable_hw(void *info)
"timeout observed when probing at offset %#x\n",
TRCSTATR);
- writel_relaxed(drvdata->pe_sel, drvdata->base + TRCPROCSELR);
- writel_relaxed(drvdata->cfg, drvdata->base + TRCCONFIGR);
+ writel_relaxed(config->pe_sel, drvdata->base + TRCPROCSELR);
+ writel_relaxed(config->cfg, drvdata->base + TRCCONFIGR);
/* nothing specific implemented */
writel_relaxed(0x0, drvdata->base + TRCAUXCTLR);
- writel_relaxed(drvdata->eventctrl0, drvdata->base + TRCEVENTCTL0R);
- writel_relaxed(drvdata->eventctrl1, drvdata->base + TRCEVENTCTL1R);
- writel_relaxed(drvdata->stall_ctrl, drvdata->base + TRCSTALLCTLR);
- writel_relaxed(drvdata->ts_ctrl, drvdata->base + TRCTSCTLR);
- writel_relaxed(drvdata->syncfreq, drvdata->base + TRCSYNCPR);
- writel_relaxed(drvdata->ccctlr, drvdata->base + TRCCCCTLR);
- writel_relaxed(drvdata->bb_ctrl, drvdata->base + TRCBBCTLR);
+ writel_relaxed(config->eventctrl0, drvdata->base + TRCEVENTCTL0R);
+ writel_relaxed(config->eventctrl1, drvdata->base + TRCEVENTCTL1R);
+ writel_relaxed(config->stall_ctrl, drvdata->base + TRCSTALLCTLR);
+ writel_relaxed(config->ts_ctrl, drvdata->base + TRCTSCTLR);
+ writel_relaxed(config->syncfreq, drvdata->base + TRCSYNCPR);
+ writel_relaxed(config->ccctlr, drvdata->base + TRCCCCTLR);
+ writel_relaxed(config->bb_ctrl, drvdata->base + TRCBBCTLR);
writel_relaxed(drvdata->trcid, drvdata->base + TRCTRACEIDR);
- writel_relaxed(drvdata->vinst_ctrl, drvdata->base + TRCVICTLR);
- writel_relaxed(drvdata->viiectlr, drvdata->base + TRCVIIECTLR);
- writel_relaxed(drvdata->vissctlr,
+ writel_relaxed(config->vinst_ctrl, drvdata->base + TRCVICTLR);
+ writel_relaxed(config->viiectlr, drvdata->base + TRCVIIECTLR);
+ writel_relaxed(config->vissctlr,
drvdata->base + TRCVISSCTLR);
- writel_relaxed(drvdata->vipcssctlr,
+ writel_relaxed(config->vipcssctlr,
drvdata->base + TRCVIPCSSCTLR);
for (i = 0; i < drvdata->nrseqstate - 1; i++)
- writel_relaxed(drvdata->seq_ctrl[i],
+ writel_relaxed(config->seq_ctrl[i],
drvdata->base + TRCSEQEVRn(i));
- writel_relaxed(drvdata->seq_rst, drvdata->base + TRCSEQRSTEVR);
- writel_relaxed(drvdata->seq_state, drvdata->base + TRCSEQSTR);
- writel_relaxed(drvdata->ext_inp, drvdata->base + TRCEXTINSELR);
+ writel_relaxed(config->seq_rst, drvdata->base + TRCSEQRSTEVR);
+ writel_relaxed(config->seq_state, drvdata->base + TRCSEQSTR);
+ writel_relaxed(config->ext_inp, drvdata->base + TRCEXTINSELR);
for (i = 0; i < drvdata->nr_cntr; i++) {
- writel_relaxed(drvdata->cntrldvr[i],
+ writel_relaxed(config->cntrldvr[i],
drvdata->base + TRCCNTRLDVRn(i));
- writel_relaxed(drvdata->cntr_ctrl[i],
+ writel_relaxed(config->cntr_ctrl[i],
drvdata->base + TRCCNTCTLRn(i));
- writel_relaxed(drvdata->cntr_val[i],
+ writel_relaxed(config->cntr_val[i],
drvdata->base + TRCCNTVRn(i));
}
/* Resource selector pair 0 is always implemented and reserved */
- for (i = 2; i < drvdata->nr_resource * 2; i++)
- writel_relaxed(drvdata->res_ctrl[i],
+ for (i = 0; i < drvdata->nr_resource * 2; i++)
+ writel_relaxed(config->res_ctrl[i],
drvdata->base + TRCRSCTLRn(i));
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
- writel_relaxed(drvdata->ss_ctrl[i],
+ writel_relaxed(config->ss_ctrl[i],
drvdata->base + TRCSSCCRn(i));
- writel_relaxed(drvdata->ss_status[i],
+ writel_relaxed(config->ss_status[i],
drvdata->base + TRCSSCSRn(i));
- writel_relaxed(drvdata->ss_pe_cmp[i],
+ writel_relaxed(config->ss_pe_cmp[i],
drvdata->base + TRCSSPCICRn(i));
}
for (i = 0; i < drvdata->nr_addr_cmp; i++) {
- writeq_relaxed(drvdata->addr_val[i],
+ writeq_relaxed(config->addr_val[i],
drvdata->base + TRCACVRn(i));
- writeq_relaxed(drvdata->addr_acc[i],
+ writeq_relaxed(config->addr_acc[i],
drvdata->base + TRCACATRn(i));
}
for (i = 0; i < drvdata->numcidc; i++)
- writeq_relaxed(drvdata->ctxid_pid[i],
+ writeq_relaxed(config->ctxid_pid[i],
drvdata->base + TRCCIDCVRn(i));
- writel_relaxed(drvdata->ctxid_mask0, drvdata->base + TRCCIDCCTLR0);
- writel_relaxed(drvdata->ctxid_mask1, drvdata->base + TRCCIDCCTLR1);
+ writel_relaxed(config->ctxid_mask0, drvdata->base + TRCCIDCCTLR0);
+ writel_relaxed(config->ctxid_mask1, drvdata->base + TRCCIDCCTLR1);
for (i = 0; i < drvdata->numvmidc; i++)
- writeq_relaxed(drvdata->vmid_val[i],
+ writeq_relaxed(config->vmid_val[i],
drvdata->base + TRCVMIDCVRn(i));
- writel_relaxed(drvdata->vmid_mask0, drvdata->base + TRCVMIDCCTLR0);
- writel_relaxed(drvdata->vmid_mask1, drvdata->base + TRCVMIDCCTLR1);
+ writel_relaxed(config->vmid_mask0, drvdata->base + TRCVMIDCCTLR0);
+ writel_relaxed(config->vmid_mask1, drvdata->base + TRCVMIDCCTLR1);
/* Enable the trace unit */
writel_relaxed(1, drvdata->base + TRCPRGCTLR);
@@ -439,83 +440,84 @@ static void etm4_init_arch_data(void *info)
static void etm4_init_default_data(struct etmv4_drvdata *drvdata)
{
int i;
+ struct etmv4_config *config = &drvdata->config;
- drvdata->pe_sel = 0x0;
- drvdata->cfg = (ETMv4_MODE_CTXID | ETM_MODE_VMID |
+ config->pe_sel = 0x0;
+ config->cfg = (ETMv4_MODE_CTXID | ETM_MODE_VMID |
ETMv4_MODE_TIMESTAMP | ETM_MODE_RETURNSTACK);
/* disable all events tracing */
- drvdata->eventctrl0 = 0x0;
- drvdata->eventctrl1 = 0x0;
+ config->eventctrl0 = 0x0;
+ config->eventctrl1 = 0x0;
/* disable stalling */
- drvdata->stall_ctrl = 0x0;
+ config->stall_ctrl = 0x0;
/* disable timestamp event */
- drvdata->ts_ctrl = 0x0;
+ config->ts_ctrl = 0x0;
/* enable trace synchronization every 4096 bytes for trace */
if (drvdata->syncpr == false)
- drvdata->syncfreq = 0xC;
+ config->syncfreq = 0xC;
/*
* enable viewInst to trace everything with start-stop logic in
* started state
*/
- drvdata->vinst_ctrl |= BIT(0);
+ config->vinst_ctrl |= BIT(0);
/* set initial state of start-stop logic */
if (drvdata->nr_addr_cmp)
- drvdata->vinst_ctrl |= BIT(9);
+ config->vinst_ctrl |= BIT(9);
/* no address range filtering for ViewInst */
- drvdata->viiectlr = 0x0;
+ config->viiectlr = 0x0;
/* no start-stop filtering for ViewInst */
- drvdata->vissctlr = 0x0;
+ config->vissctlr = 0x0;
/* disable seq events */
for (i = 0; i < drvdata->nrseqstate-1; i++)
- drvdata->seq_ctrl[i] = 0x0;
- drvdata->seq_rst = 0x0;
- drvdata->seq_state = 0x0;
+ config->seq_ctrl[i] = 0x0;
+ config->seq_rst = 0x0;
+ config->seq_state = 0x0;
/* disable external input events */
- drvdata->ext_inp = 0x0;
+ config->ext_inp = 0x0;
for (i = 0; i < drvdata->nr_cntr; i++) {
- drvdata->cntrldvr[i] = 0x0;
- drvdata->cntr_ctrl[i] = 0x0;
- drvdata->cntr_val[i] = 0x0;
+ config->cntrldvr[i] = 0x0;
+ config->cntr_ctrl[i] = 0x0;
+ config->cntr_val[i] = 0x0;
}
/* Resource selector pair 0 is always implemented and reserved */
- drvdata->res_idx = 0x2;
+ config->res_idx = 0x2;
for (i = 2; i < drvdata->nr_resource * 2; i++)
- drvdata->res_ctrl[i] = 0x0;
+ config->res_ctrl[i] = 0x0;
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
- drvdata->ss_ctrl[i] = 0x0;
- drvdata->ss_pe_cmp[i] = 0x0;
+ config->ss_ctrl[i] = 0x0;
+ config->ss_pe_cmp[i] = 0x0;
}
if (drvdata->nr_addr_cmp >= 1) {
- drvdata->addr_val[0] = (unsigned long)_stext;
- drvdata->addr_val[1] = (unsigned long)_etext;
- drvdata->addr_type[0] = ETM_ADDR_TYPE_RANGE;
- drvdata->addr_type[1] = ETM_ADDR_TYPE_RANGE;
+ config->addr_val[0] = (unsigned long)_stext;
+ config->addr_val[1] = (unsigned long)_etext;
+ config->addr_type[0] = ETM_ADDR_TYPE_RANGE;
+ config->addr_type[1] = ETM_ADDR_TYPE_RANGE;
}
for (i = 0; i < drvdata->numcidc; i++) {
- drvdata->ctxid_pid[i] = 0x0;
- drvdata->ctxid_vpid[i] = 0x0;
+ config->ctxid_pid[i] = 0x0;
+ config->ctxid_vpid[i] = 0x0;
}
- drvdata->ctxid_mask0 = 0x0;
- drvdata->ctxid_mask1 = 0x0;
+ config->ctxid_mask0 = 0x0;
+ config->ctxid_mask1 = 0x0;
for (i = 0; i < drvdata->numvmidc; i++)
- drvdata->vmid_val[i] = 0x0;
- drvdata->vmid_mask0 = 0x0;
- drvdata->vmid_mask1 = 0x0;
+ config->vmid_val[i] = 0x0;
+ config->vmid_mask0 = 0x0;
+ config->vmid_mask1 = 0x0;
/*
* A trace ID value of 0 is invalid, so let's start at some
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index e6ff9aae2a7e..709d96e63910 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -180,66 +180,19 @@
#define TRCSTATR_IDLE_BIT 0
/**
- * struct etm4_drvdata - specifics associated to an ETM component
- * @base: Memory mapped base address for this component.
- * @dev: The device entity associated to this component.
- * @csdev: Component vitals needed by the framework.
- * @spinlock: Only one at a time pls.
- * @cpu: The cpu this component is affined to.
- * @arch: ETM version number.
- * @enable: Is this ETM currently tracing.
- * @sticky_enable: true if ETM base configuration has been done.
- * @boot_enable:True if we should start tracing at boot time.
- * @os_unlock: True if access to management registers is allowed.
- * @nr_pe: The number of processing entity available for tracing.
- * @nr_pe_cmp: The number of processing entity comparator inputs that are
- * available for tracing.
- * @nr_addr_cmp:Number of pairs of address comparators available
- * as found in ETMIDR4 0-3.
- * @nr_cntr: Number of counters as found in ETMIDR5 bit 28-30.
- * @nr_ext_inp: Number of external input.
- * @numcidc: Number of contextID comparators.
- * @numvmidc: Number of VMID comparators.
- * @nrseqstate: The number of sequencer states that are implemented.
- * @nr_event: Indicates how many events the trace unit support.
- * @nr_resource:The number of resource selection pairs available for tracing.
- * @nr_ss_cmp: Number of single-shot comparator controls that are available.
+ * struct etmv4_config - configuration information related to an ETMv4
* @mode: Controls various modes supported by this ETM.
- * @trcid: value of the current ID for this component.
- * @trcid_size: Indicates the trace ID width.
- * @instrp0: Tracing of load and store instructions
- * as P0 elements is supported.
- * @trccond: If the trace unit supports conditional
- * instruction tracing.
- * @retstack: Indicates if the implementation supports a return stack.
- * @trc_error: Whether a trace unit can trace a system
- * error exception.
- * @atbtrig: If the implementation can support ATB triggers
- * @lpoverride: If the implementation can support low-power state over.
* @pe_sel: Controls which PE to trace.
* @cfg: Controls the tracing options.
* @eventctrl0: Controls the tracing of arbitrary events.
* @eventctrl1: Controls the behavior of the events that @event_ctrl0 selects.
* @stallctl: If functionality that prevents trace unit buffer overflows
* is available.
- * @sysstall: Does the system support stall control of the PE?
- * @nooverflow: Indicate if overflow prevention is supported.
- * @stall_ctrl: Enables trace unit functionality that prevents trace
- * unit buffer overflows.
- * @ts_size: Global timestamp size field.
* @ts_ctrl: Controls the insertion of global timestamps in the
* trace streams.
- * @syncpr: Indicates if an implementation has a fixed
- * synchronization period.
* @syncfreq: Controls how often trace synchronization requests occur.
- * @trccci: Indicates if the trace unit supports cycle counting
- * for instruction.
- * @ccsize: Indicates the size of the cycle counter in bits.
- * @ccitmin: minimum value that can be programmed in
* the TRCCCCTLR register.
* @ccctlr: Sets the threshold value for cycle counting.
- * @trcbb: Indicates if the trace unit supports branch broadcast tracing.
- * @q_support: Q element support characteristics.
* @vinst_ctrl: Controls instruction trace filtering.
* @viiectlr: Set or read, the address range comparators.
* @vissctlr: Set, or read, the single address comparators that control the
@@ -264,73 +217,28 @@
* @addr_acc: Address comparator access type.
* @addr_type: Current status of the comparator register.
* @ctxid_idx: Context ID index selector.
- * @ctxid_size: Size of the context ID field to consider.
* @ctxid_pid: Value of the context ID comparator.
* @ctxid_vpid: Virtual PID seen by users if PID namespace is enabled, otherwise
* the same value of ctxid_pid.
* @ctxid_mask0:Context ID comparator mask for comparator 0-3.
* @ctxid_mask1:Context ID comparator mask for comparator 4-7.
* @vmid_idx: VM ID index selector.
- * @vmid_size: Size of the VM ID comparator to consider.
* @vmid_val: Value of the VM ID comparator.
* @vmid_mask0: VM ID comparator mask for comparator 0-3.
* @vmid_mask1: VM ID comparator mask for comparator 4-7.
- * @s_ex_level: In secure state, indicates whether instruction tracing is
- * supported for the corresponding Exception level.
- * @ns_ex_level:In non-secure state, indicates whether instruction tracing is
- * supported for the corresponding Exception level.
* @ext_inp: External input selection.
*/
-struct etmv4_drvdata {
- void __iomem *base;
- struct device *dev;
- struct coresight_device *csdev;
- spinlock_t spinlock;
- int cpu;
- u8 arch;
- bool enable;
- bool sticky_enable;
- bool boot_enable;
- bool os_unlock;
- u8 nr_pe;
- u8 nr_pe_cmp;
- u8 nr_addr_cmp;
- u8 nr_cntr;
- u8 nr_ext_inp;
- u8 numcidc;
- u8 numvmidc;
- u8 nrseqstate;
- u8 nr_event;
- u8 nr_resource;
- u8 nr_ss_cmp;
+struct etmv4_config {
u32 mode;
- u8 trcid;
- u8 trcid_size;
- bool instrp0;
- bool trccond;
- bool retstack;
- bool trc_error;
- bool atbtrig;
- bool lpoverride;
u32 pe_sel;
u32 cfg;
u32 eventctrl0;
u32 eventctrl1;
- bool stallctl;
- bool sysstall;
- bool nooverflow;
u32 stall_ctrl;
- u8 ts_size;
u32 ts_ctrl;
- bool syncpr;
u32 syncfreq;
- bool trccci;
- u8 ccsize;
- u8 ccitmin;
u32 ccctlr;
- bool trcbb;
u32 bb_ctrl;
- bool q_support;
u32 vinst_ctrl;
u32 viiectlr;
u32 vissctlr;
@@ -353,19 +261,119 @@ struct etmv4_drvdata {
u64 addr_acc[ETM_MAX_SINGLE_ADDR_CMP];
u8 addr_type[ETM_MAX_SINGLE_ADDR_CMP];
u8 ctxid_idx;
- u8 ctxid_size;
u64 ctxid_pid[ETMv4_MAX_CTXID_CMP];
u64 ctxid_vpid[ETMv4_MAX_CTXID_CMP];
u32 ctxid_mask0;
u32 ctxid_mask1;
u8 vmid_idx;
- u8 vmid_size;
u64 vmid_val[ETM_MAX_VMID_CMP];
u32 vmid_mask0;
u32 vmid_mask1;
+ u32 ext_inp;
+};
+
+/**
+ * struct etm4_drvdata - specifics associated to an ETM component
+ * @base: Memory mapped base address for this component.
+ * @dev: The device entity associated to this component.
+ * @csdev: Component vitals needed by the framework.
+ * @spinlock: Only one at a time pls.
+ * @cpu: The cpu this component is affined to.
+ * @arch: ETM version number.
+ * @nr_pe: The number of processing entity available for tracing.
+ * @nr_pe_cmp: The number of processing entity comparator inputs that are
+ * available for tracing.
+ * @nr_addr_cmp:Number of pairs of address comparators available
+ * as found in ETMIDR4 0-3.
+ * @nr_cntr: Number of counters as found in ETMIDR5 bit 28-30.
+ * @nr_ext_inp: Number of external input.
+ * @numcidc: Number of contextID comparators.
+ * @numvmidc: Number of VMID comparators.
+ * @nrseqstate: The number of sequencer states that are implemented.
+ * @nr_event: Indicates how many events the trace unit support.
+ * @nr_resource:The number of resource selection pairs available for tracing.
+ * @nr_ss_cmp: Number of single-shot comparator controls that are available.
+ * @trcid: value of the current ID for this component.
+ * @trcid_size: Indicates the trace ID width.
+ * @ts_size: Global timestamp size field.
+ * @ctxid_size: Size of the context ID field to consider.
+ * @vmid_size: Size of the VM ID comparator to consider.
+ * @ccsize: Indicates the size of the cycle counter in bits.
+ * @ccitmin: minimum value that can be programmed in
+ * @s_ex_level: In secure state, indicates whether instruction tracing is
+ * supported for the corresponding Exception level.
+ * @ns_ex_level:In non-secure state, indicates whether instruction tracing is
+ * supported for the corresponding Exception level.
+ * @enable: Is this ETM currently tracing.
+ * @sticky_enable: true if ETM base configuration has been done.
+ * @boot_enable:True if we should start tracing at boot time.
+ * @os_unlock: True if access to management registers is allowed.
+ * @instrp0: Tracing of load and store instructions
+ * as P0 elements is supported.
+ * @trcbb: Indicates if the trace unit supports branch broadcast tracing.
+ * @trccond: If the trace unit supports conditional
+ * instruction tracing.
+ * @retstack: Indicates if the implementation supports a return stack.
+ * @trccci: Indicates if the trace unit supports cycle counting
+ * for instruction.
+ * @q_support: Q element support characteristics.
+ * @trc_error: Whether a trace unit can trace a system
+ * error exception.
+ * @syncpr: Indicates if an implementation has a fixed
+ * synchronization period.
+ * @stall_ctrl: Enables trace unit functionality that prevents trace
+ * unit buffer overflows.
+ * @sysstall: Does the system support stall control of the PE?
+ * @nooverflow: Indicate if overflow prevention is supported.
+ * @atbtrig: If the implementation can support ATB triggers
+ * @lpoverride: If the implementation can support low-power state over.
+ * @config: structure holding configuration parameters.
+ */
+struct etmv4_drvdata {
+ void __iomem *base;
+ struct device *dev;
+ struct coresight_device *csdev;
+ spinlock_t spinlock;
+ int cpu;
+ u8 arch;
+ u8 nr_pe;
+ u8 nr_pe_cmp;
+ u8 nr_addr_cmp;
+ u8 nr_cntr;
+ u8 nr_ext_inp;
+ u8 numcidc;
+ u8 numvmidc;
+ u8 nrseqstate;
+ u8 nr_event;
+ u8 nr_resource;
+ u8 nr_ss_cmp;
+ u8 trcid;
+ u8 trcid_size;
+ u8 ts_size;
+ u8 ctxid_size;
+ u8 vmid_size;
+ u8 ccsize;
+ u8 ccitmin;
u8 s_ex_level;
u8 ns_ex_level;
- u32 ext_inp;
+ bool enable;
+ bool sticky_enable;
+ bool boot_enable;
+ bool os_unlock;
+ bool instrp0;
+ bool trcbb;
+ bool trccond;
+ bool retstack;
+ bool trccci;
+ bool q_support;
+ bool trc_error;
+ bool syncpr;
+ bool stallctl;
+ bool sysstall;
+ bool nooverflow;
+ bool atbtrig;
+ bool lpoverride;
+ struct etmv4_config config;
};
/* Address comparator access types */
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/8] coresight: etm4x: splitting etmv4 default configuration
2016-02-29 18:54 [PATCH 0/8] coresight: etmv4: make driver usable by Perf Mathieu Poirier
2016-02-29 18:54 ` [PATCH 2/8] coresight: etm4x: adding config and traceid registers Mathieu Poirier
2016-02-29 18:54 ` [PATCH 3/8] coresight: etm4x: splitting struct etmv4_drvdata Mathieu Poirier
@ 2016-02-29 18:54 ` Mathieu Poirier
2016-02-29 18:54 ` [PATCH 5/8] coresight: etm4x: unlocking tracers in default arch init Mathieu Poirier
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Poirier @ 2016-02-29 18:54 UTC (permalink / raw)
To: linux-arm-kernel
Splitting and updating the default initialisation for each etmv4
configuration so that it can be called at the beginning of each
session rather than initialisation time only.
Since the trace ID isn't expected to change with every session,
moving it with the default tracer initialisation.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/coresight-etm4x.c | 128 ++++++++++++--------------
drivers/hwtracing/coresight/coresight-etm4x.h | 12 +++
2 files changed, 73 insertions(+), 67 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index e204db40082b..6fd554f10ba5 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -27,6 +27,7 @@
#include <linux/clk.h>
#include <linux/cpu.h>
#include <linux/coresight.h>
+#include <linux/coresight-pmu.h>
#include <linux/pm_wakeup.h>
#include <linux/amba/bus.h>
#include <linux/seq_file.h>
@@ -437,14 +438,20 @@ static void etm4_init_arch_data(void *info)
CS_LOCK(drvdata->base);
}
-static void etm4_init_default_data(struct etmv4_drvdata *drvdata)
+static void etm4_set_default(struct etmv4_config *config)
{
- int i;
- struct etmv4_config *config = &drvdata->config;
+ if (WARN_ON_ONCE(!config))
+ return;
- config->pe_sel = 0x0;
- config->cfg = (ETMv4_MODE_CTXID | ETM_MODE_VMID |
- ETMv4_MODE_TIMESTAMP | ETM_MODE_RETURNSTACK);
+ /*
+ * Make default initialisation trace everything
+ *
+ * Select the "always true" resource selector on the
+ * "Enablign Event" line and configure address range comparator
+ * '0' to trace all the possible address range. From there
+ * configure the "include/exclude" engine to include address
+ * range comparator '0'.
+ */
/* disable all events tracing */
config->eventctrl0 = 0x0;
@@ -453,78 +460,58 @@ static void etm4_init_default_data(struct etmv4_drvdata *drvdata)
/* disable stalling */
config->stall_ctrl = 0x0;
+ /* enable trace synchronization every 4096 bytes, if available */
+ config->syncfreq = 0xC;
+
/* disable timestamp event */
config->ts_ctrl = 0x0;
- /* enable trace synchronization every 4096 bytes for trace */
- if (drvdata->syncpr == false)
- config->syncfreq = 0xC;
+ /* TRCVICTLR::EVENT = 0x01, select the always on logic */
+ config->vinst_ctrl |= BIT(0);
/*
- * enable viewInst to trace everything with start-stop logic in
- * started state
+ * TRCVICTLR::SSSTATUS == 1, the start-stop logic is
+ * in the started state
*/
- config->vinst_ctrl |= BIT(0);
- /* set initial state of start-stop logic */
- if (drvdata->nr_addr_cmp)
- config->vinst_ctrl |= BIT(9);
-
- /* no address range filtering for ViewInst */
- config->viiectlr = 0x0;
- /* no start-stop filtering for ViewInst */
- config->vissctlr = 0x0;
-
- /* disable seq events */
- for (i = 0; i < drvdata->nrseqstate-1; i++)
- config->seq_ctrl[i] = 0x0;
- config->seq_rst = 0x0;
- config->seq_state = 0x0;
-
- /* disable external input events */
- config->ext_inp = 0x0;
-
- for (i = 0; i < drvdata->nr_cntr; i++) {
- config->cntrldvr[i] = 0x0;
- config->cntr_ctrl[i] = 0x0;
- config->cntr_val[i] = 0x0;
- }
-
- /* Resource selector pair 0 is always implemented and reserved */
- config->res_idx = 0x2;
- for (i = 2; i < drvdata->nr_resource * 2; i++)
- config->res_ctrl[i] = 0x0;
+ config->vinst_ctrl |= BIT(9);
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
- config->ss_ctrl[i] = 0x0;
- config->ss_pe_cmp[i] = 0x0;
- }
-
- if (drvdata->nr_addr_cmp >= 1) {
- config->addr_val[0] = (unsigned long)_stext;
- config->addr_val[1] = (unsigned long)_etext;
- config->addr_type[0] = ETM_ADDR_TYPE_RANGE;
- config->addr_type[1] = ETM_ADDR_TYPE_RANGE;
- }
-
- for (i = 0; i < drvdata->numcidc; i++) {
- config->ctxid_pid[i] = 0x0;
- config->ctxid_vpid[i] = 0x0;
- }
+ /*
+ * Configure address range comparator '0' to encompass all
+ * possible addresses.
+ */
- config->ctxid_mask0 = 0x0;
- config->ctxid_mask1 = 0x0;
+ /* First half of default address comparator: start at address 0 */
+ config->addr_val[ETM_DEFAULT_ADDR_COMP] = 0x0;
+ /* trace instruction addresses */
+ config->addr_acc[ETM_DEFAULT_ADDR_COMP] &= ~(BIT(0) | BIT(1));
+ /* EXLEVEL_NS, bits[12:15], only trace application and kernel space */
+ config->addr_acc[ETM_DEFAULT_ADDR_COMP] |= ETM_EXLEVEL_NS_HYP;
+ /* EXLEVEL_S, bits[11:8], don't trace anything in secure state */
+ config->addr_acc[ETM_DEFAULT_ADDR_COMP] |= (ETM_EXLEVEL_S_APP |
+ ETM_EXLEVEL_S_OS |
+ ETM_EXLEVEL_S_HYP);
+ config->addr_type[ETM_DEFAULT_ADDR_COMP] = ETM_ADDR_TYPE_RANGE;
- for (i = 0; i < drvdata->numvmidc; i++)
- config->vmid_val[i] = 0x0;
- config->vmid_mask0 = 0x0;
- config->vmid_mask1 = 0x0;
+ /*
+ * Second half of default address comparator: go all
+ * the way to the top.
+ */
+ config->addr_val[ETM_DEFAULT_ADDR_COMP + 1] = ~0x0;
+ /* trace instruction addresses */
+ config->addr_acc[ETM_DEFAULT_ADDR_COMP + 1] &= ~(BIT(0) | BIT(1));
+ /* Address comparator type must be equal for both halves */
+ config->addr_acc[ETM_DEFAULT_ADDR_COMP + 1] =
+ config->addr_acc[ETM_DEFAULT_ADDR_COMP];
+ config->addr_type[ETM_DEFAULT_ADDR_COMP + 1] = ETM_ADDR_TYPE_RANGE;
/*
- * A trace ID value of 0 is invalid, so let's start at some
- * random value that fits in 7 bits. ETMv3.x has 0x10 so let's
- * start at 0x20.
+ * Configure the ViewInst function to filter on address range
+ * comparator '0'.
*/
- drvdata->trcid = 0x20 + drvdata->cpu;
+ config->viiectlr = BIT(0);
+
+ /* no start-stop filtering for ViewInst */
+ config->vissctlr = 0x0;
}
static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
@@ -569,6 +556,11 @@ static struct notifier_block etm4_cpu_notifier = {
.notifier_call = etm4_cpu_callback,
};
+static void etm4_init_trace_id(struct etmv4_drvdata *drvdata)
+{
+ drvdata->trcid = coresight_get_trace_id(drvdata->cpu);
+}
+
static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret;
@@ -628,7 +620,9 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
ret = -EINVAL;
goto err_arch_supported;
}
- etm4_init_default_data(drvdata);
+
+ etm4_init_trace_id(drvdata);
+ etm4_set_default(&drvdata->config);
pm_runtime_put(&adev->dev);
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 709d96e63910..6ff499bfb2f2 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -178,6 +178,18 @@
#define ETMv4_MODE_ALL 0xFFFFFFF
#define TRCSTATR_IDLE_BIT 0
+#define ETM_DEFAULT_ADDR_COMP 0
+
+/* secure state access levels */
+#define ETM_EXLEVEL_S_APP BIT(8)
+#define ETM_EXLEVEL_S_OS BIT(9)
+#define ETM_EXLEVEL_S_NA BIT(10)
+#define ETM_EXLEVEL_S_HYP BIT(11)
+/* non-secure state access levels */
+#define ETM_EXLEVEL_NS_APP BIT(12)
+#define ETM_EXLEVEL_NS_OS BIT(13)
+#define ETM_EXLEVEL_NS_HYP BIT(14)
+#define ETM_EXLEVEL_NS_NA BIT(15)
/**
* struct etmv4_config - configuration information related to an ETMv4
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/8] coresight: etm4x: unlocking tracers in default arch init
2016-02-29 18:54 [PATCH 0/8] coresight: etmv4: make driver usable by Perf Mathieu Poirier
` (2 preceding siblings ...)
2016-02-29 18:54 ` [PATCH 4/8] coresight: etm4x: splitting etmv4 default configuration Mathieu Poirier
@ 2016-02-29 18:54 ` Mathieu Poirier
2016-02-29 18:54 ` [PATCH 6/8] coresight: etm4x: moving etm_drvdata::enable to atomic field Mathieu Poirier
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Poirier @ 2016-02-29 18:54 UTC (permalink / raw)
To: linux-arm-kernel
As with the ETMv3.x driver, calling 'smp_call_function_single()'
twice in a row is highly ineffective. As such moving function
'etm4_os_unlock()' before the default initialisation takes
place, which results in the same outcome.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/coresight-etm4x.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 6fd554f10ba5..4b83a753256b 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -45,12 +45,11 @@ module_param_named(boot_enable, boot_enable, int, S_IRUGO);
static int etm4_count;
static struct etmv4_drvdata *etmdrvdata[NR_CPUS];
-static void etm4_os_unlock(void *info)
+static void etm4_os_unlock(struct etmv4_drvdata *drvdata)
{
- struct etmv4_drvdata *drvdata = (struct etmv4_drvdata *)info;
-
/* Writing any value to ETMOSLAR unlocks the trace registers */
writel_relaxed(0x0, drvdata->base + TRCOSLAR);
+ drvdata->os_unlock = true;
isb();
}
@@ -287,6 +286,9 @@ static void etm4_init_arch_data(void *info)
u32 etmidr5;
struct etmv4_drvdata *drvdata = info;
+ /* Make sure all registers are accessible */
+ etm4_os_unlock(drvdata);
+
CS_UNLOCK(drvdata->base);
/* find all capabilities of the tracing unit */
@@ -604,9 +606,6 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
get_online_cpus();
etmdrvdata[drvdata->cpu] = drvdata;
- if (!smp_call_function_single(drvdata->cpu, etm4_os_unlock, drvdata, 1))
- drvdata->os_unlock = true;
-
if (smp_call_function_single(drvdata->cpu,
etm4_init_arch_data, drvdata, 1))
dev_err(dev, "ETM arch init failed\n");
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6/8] coresight: etm4x: moving etm_drvdata::enable to atomic field
2016-02-29 18:54 [PATCH 0/8] coresight: etmv4: make driver usable by Perf Mathieu Poirier
` (3 preceding siblings ...)
2016-02-29 18:54 ` [PATCH 5/8] coresight: etm4x: unlocking tracers in default arch init Mathieu Poirier
@ 2016-02-29 18:54 ` Mathieu Poirier
2016-02-29 18:54 ` [PATCH 7/8] coresight: etm4x: implementing user/kernel mode tracing Mathieu Poirier
2016-02-29 18:54 ` [PATCH 8/8] coresight: etm4x: implementing the perf PMU API Mathieu Poirier
6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Poirier @ 2016-02-29 18:54 UTC (permalink / raw)
To: linux-arm-kernel
Similarly to ETMv3, moving etmv4_drvdata::enable to an atomic
type that gives the 'mode' of a tracer and prevents multiple,
simultanious access by different subsystems.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/coresight-etm4x.c | 69 +++++++++++++++++++++++----
drivers/hwtracing/coresight/coresight-etm4x.h | 5 +-
2 files changed, 63 insertions(+), 11 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 4b83a753256b..738acee18967 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -35,6 +35,7 @@
#include <linux/pm_runtime.h>
#include <linux/perf_event.h>
#include <asm/sections.h>
+#include <asm/local.h>
#include "coresight-etm4x.h"
@@ -77,7 +78,7 @@ static int etm4_trace_id(struct coresight_device *csdev)
unsigned long flags;
int trace_id = -1;
- if (!drvdata->enable)
+ if (!local_read(&drvdata->mode))
return drvdata->trcid;
spin_lock_irqsave(&drvdata->spinlock, flags);
@@ -189,8 +190,7 @@ static void etm4_enable_hw(void *info)
dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
}
-static int etm4_enable(struct coresight_device *csdev,
- struct perf_event_attr *attr, u32 mode)
+static int etm4_enable_sysfs(struct coresight_device *csdev)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret;
@@ -205,18 +205,46 @@ static int etm4_enable(struct coresight_device *csdev,
etm4_enable_hw, drvdata, 1);
if (ret)
goto err;
- drvdata->enable = true;
- drvdata->sticky_enable = true;
+ drvdata->sticky_enable = true;
spin_unlock(&drvdata->spinlock);
dev_info(drvdata->dev, "ETM tracing enabled\n");
return 0;
+
err:
spin_unlock(&drvdata->spinlock);
return ret;
}
+static int etm4_enable(struct coresight_device *csdev,
+ struct perf_event_attr *attr, u32 mode)
+{
+ int ret;
+ u32 val;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
+
+ /* Someone is already using the tracer */
+ if (val)
+ return -EBUSY;
+
+ switch (mode) {
+ case CS_MODE_SYSFS:
+ ret = etm4_enable_sysfs(csdev);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ /* The tracer didn't start */
+ if (ret)
+ local_set(&drvdata->mode, CS_MODE_DISABLED);
+
+ return ret;
+}
+
static void etm4_disable_hw(void *info)
{
u32 control;
@@ -239,7 +267,7 @@ static void etm4_disable_hw(void *info)
dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
}
-static void etm4_disable(struct coresight_device *csdev)
+static void etm4_disable_sysfs(struct coresight_device *csdev)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -257,7 +285,6 @@ static void etm4_disable(struct coresight_device *csdev)
* ensures that register writes occur when cpu is powered.
*/
smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
- drvdata->enable = false;
spin_unlock(&drvdata->spinlock);
put_online_cpus();
@@ -265,6 +292,30 @@ static void etm4_disable(struct coresight_device *csdev)
dev_info(drvdata->dev, "ETM tracing disabled\n");
}
+static void etm4_disable(struct coresight_device *csdev)
+{
+ u32 mode;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ /*
+ * For as long as the tracer isn't disabled another entity can't
+ * change its status. As such we can read the status here without
+ * fearing it will change under us.
+ */
+ mode = local_read(&drvdata->mode);
+
+ switch (mode) {
+ case CS_MODE_DISABLED:
+ break;
+ case CS_MODE_SYSFS:
+ etm4_disable_sysfs(csdev);
+ break;
+ }
+
+ if (mode)
+ local_set(&drvdata->mode, CS_MODE_DISABLED);
+}
+
static const struct coresight_ops_source etm4_source_ops = {
.cpu_id = etm4_cpu_id,
.trace_id = etm4_trace_id,
@@ -532,7 +583,7 @@ static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
etmdrvdata[cpu]->os_unlock = true;
}
- if (etmdrvdata[cpu]->enable)
+ if (local_read(&etmdrvdata[cpu]->mode))
etm4_enable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
@@ -545,7 +596,7 @@ static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
case CPU_DYING:
spin_lock(&etmdrvdata[cpu]->spinlock);
- if (etmdrvdata[cpu]->enable)
+ if (local_read(&etmdrvdata[cpu]->mode))
etm4_disable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 6ff499bfb2f2..f7748ae63451 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -13,6 +13,7 @@
#ifndef _CORESIGHT_CORESIGHT_ETM_H
#define _CORESIGHT_CORESIGHT_ETM_H
+#include <asm/local.h>
#include <linux/spinlock.h>
#include "coresight-priv.h"
@@ -290,6 +291,7 @@ struct etmv4_config {
* @dev: The device entity associated to this component.
* @csdev: Component vitals needed by the framework.
* @spinlock: Only one at a time pls.
+ * @mode: This tracer's mode, i.e sysFS, Perf or disabled.
* @cpu: The cpu this component is affined to.
* @arch: ETM version number.
* @nr_pe: The number of processing entity available for tracing.
@@ -316,7 +318,6 @@ struct etmv4_config {
* supported for the corresponding Exception level.
* @ns_ex_level:In non-secure state, indicates whether instruction tracing is
* supported for the corresponding Exception level.
- * @enable: Is this ETM currently tracing.
* @sticky_enable: true if ETM base configuration has been done.
* @boot_enable:True if we should start tracing at boot time.
* @os_unlock: True if access to management registers is allowed.
@@ -346,6 +347,7 @@ struct etmv4_drvdata {
struct device *dev;
struct coresight_device *csdev;
spinlock_t spinlock;
+ local_t mode;
int cpu;
u8 arch;
u8 nr_pe;
@@ -368,7 +370,6 @@ struct etmv4_drvdata {
u8 ccitmin;
u8 s_ex_level;
u8 ns_ex_level;
- bool enable;
bool sticky_enable;
bool boot_enable;
bool os_unlock;
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 7/8] coresight: etm4x: implementing user/kernel mode tracing
2016-02-29 18:54 [PATCH 0/8] coresight: etmv4: make driver usable by Perf Mathieu Poirier
` (4 preceding siblings ...)
2016-02-29 18:54 ` [PATCH 6/8] coresight: etm4x: moving etm_drvdata::enable to atomic field Mathieu Poirier
@ 2016-02-29 18:54 ` Mathieu Poirier
2016-02-29 18:54 ` [PATCH 8/8] coresight: etm4x: implementing the perf PMU API Mathieu Poirier
6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Poirier @ 2016-02-29 18:54 UTC (permalink / raw)
To: linux-arm-kernel
Adding new mode to limit tracing to kernel or user space.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
.../hwtracing/coresight/coresight-etm4x-sysfs.c | 3 ++
drivers/hwtracing/coresight/coresight-etm4x.c | 35 ++++++++++++++++++++++
drivers/hwtracing/coresight/coresight-etm4x.h | 5 +++-
3 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index a996db7ef2fc..0e80ec668402 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -440,6 +440,9 @@ static ssize_t mode_store(struct device *dev,
else
config->vinst_ctrl &= ~BIT(11);
+ if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER))
+ etm4_config_trace_mode(config);
+
spin_unlock(&drvdata->spinlock);
return size;
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 738acee18967..743c34b92a80 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -567,6 +567,41 @@ static void etm4_set_default(struct etmv4_config *config)
config->vissctlr = 0x0;
}
+void etm4_config_trace_mode(struct etmv4_config *config)
+{
+ u32 addr_acc, mode;
+
+ mode = config->mode;
+ mode &= (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER);
+
+ /* excluding kernel AND user space doesn't make sense */
+ WARN_ON_ONCE(mode == (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER));
+
+ /* nothing to do if neither flags are set */
+ if (!(mode & ETM_MODE_EXCL_KERN) && !(mode & ETM_MODE_EXCL_USER))
+ return;
+
+ addr_acc = config->addr_acc[ETM_DEFAULT_ADDR_COMP];
+ /* clear default config */
+ addr_acc &= ~(ETM_EXLEVEL_NS_APP | ETM_EXLEVEL_NS_OS);
+
+ /*
+ * EXLEVEL_NS, bits[15:12]
+ * The Exception levels are:
+ * Bit[12] Exception level 0 - Application
+ * Bit[13] Exception level 1 - OS
+ * Bit[14] Exception level 2 - Hypervisor
+ * Bit[15] Never implemented
+ */
+ if (mode & ETM_MODE_EXCL_KERN)
+ addr_acc |= ETM_EXLEVEL_NS_OS;
+ else
+ addr_acc |= ETM_EXLEVEL_NS_APP;
+
+ config->addr_acc[ETM_DEFAULT_ADDR_COMP] = addr_acc;
+ config->addr_acc[ETM_DEFAULT_ADDR_COMP + 1] = addr_acc;
+}
+
static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
void *hcpu)
{
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index f7748ae63451..a291d4cc8bd8 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -176,7 +176,9 @@
#define ETM_MODE_TRACE_RESET BIT(25)
#define ETM_MODE_TRACE_ERR BIT(26)
#define ETM_MODE_VIEWINST_STARTSTOP BIT(27)
-#define ETMv4_MODE_ALL 0xFFFFFFF
+#define ETMv4_MODE_ALL (GENMASK(27, 0) | \
+ ETM_MODE_EXCL_KERN | \
+ ETM_MODE_EXCL_USER)
#define TRCSTATR_IDLE_BIT 0
#define ETM_DEFAULT_ADDR_COMP 0
@@ -414,4 +416,5 @@ enum etm_addr_type {
};
extern const struct attribute_group *coresight_etmv4_groups[];
+void etm4_config_trace_mode(struct etmv4_config *config);
#endif
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 8/8] coresight: etm4x: implementing the perf PMU API
2016-02-29 18:54 [PATCH 0/8] coresight: etmv4: make driver usable by Perf Mathieu Poirier
` (5 preceding siblings ...)
2016-02-29 18:54 ` [PATCH 7/8] coresight: etm4x: implementing user/kernel mode tracing Mathieu Poirier
@ 2016-02-29 18:54 ` Mathieu Poirier
6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Poirier @ 2016-02-29 18:54 UTC (permalink / raw)
To: linux-arm-kernel
Adding a set of API allowing the Perf core to treat ETMv4
tracers like other PMUs.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/Makefile | 5 +-
drivers/hwtracing/coresight/coresight-etm4x.c | 85 +++++++++++++++++++++++++--
2 files changed, 82 insertions(+), 8 deletions(-)
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 637ca978cd05..1d0e32c7dbe4 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for CoreSight drivers.
#
-obj-$(CONFIG_CORESIGHT) += coresight.o
+obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o
obj-$(CONFIG_OF) += of_coresight.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o
@@ -9,8 +9,7 @@ obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
coresight-replicator.o
obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o \
- coresight-etm3x-sysfs.o \
- coresight-etm-perf.o
+ coresight-etm3x-sysfs.o
obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \
coresight-etm4x-sysfs.o
obj-$(CONFIG_CORESIGHT_QCOM_REPLICATOR) += coresight-replicator-qcom.o
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 743c34b92a80..8bd400cce904 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -32,12 +32,14 @@
#include <linux/amba/bus.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
+#include <linux/perf_event.h>
#include <linux/pm_runtime.h>
#include <linux/perf_event.h>
#include <asm/sections.h>
#include <asm/local.h>
#include "coresight-etm4x.h"
+#include "coresight-etm-perf.h"
static int boot_enable;
module_param_named(boot_enable, boot_enable, int, S_IRUGO);
@@ -45,6 +47,7 @@ module_param_named(boot_enable, boot_enable, int, S_IRUGO);
/* The number of ETMv4 currently registered */
static int etm4_count;
static struct etmv4_drvdata *etmdrvdata[NR_CPUS];
+static void etm4_set_default(struct etmv4_config *config);
static void etm4_os_unlock(struct etmv4_drvdata *drvdata)
{
@@ -190,6 +193,58 @@ static void etm4_enable_hw(void *info)
dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
}
+static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
+ struct perf_event_attr *attr)
+{
+ struct etmv4_config *config = &drvdata->config;
+
+ if (!attr)
+ return -EINVAL;
+
+ /* Clear configuration from previous run */
+ memset(config, 0, sizeof(struct etmv4_config));
+
+ if (attr->exclude_kernel)
+ config->mode = ETM_MODE_EXCL_KERN;
+
+ if (attr->exclude_user)
+ config->mode = ETM_MODE_EXCL_USER;
+
+ /* Always start from the default config */
+ etm4_set_default(config);
+
+ /*
+ * By default the tracers are configured to trace the whole address
+ * range. Narrow the field only if requested by user space.
+ */
+ if (config->mode)
+ etm4_config_trace_mode(config);
+
+ /* Go from generic option to ETMv4 specifics */
+ if (attr->config & BIT(ETM_OPT_CYCACC))
+ config->cfg |= ETMv4_MODE_CYCACC;
+ if (attr->config & BIT(ETM_OPT_TS))
+ config->cfg |= ETMv4_MODE_TIMESTAMP;
+
+ return 0;
+}
+
+static int etm4_enable_perf(struct coresight_device *csdev,
+ struct perf_event_attr *attr)
+{
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
+ return -EINVAL;
+
+ /* Configure the tracer based on the session's specifics */
+ etm4_parse_event_config(drvdata, attr);
+ /* And enable it */
+ etm4_enable_hw(drvdata);
+
+ return 0;
+}
+
static int etm4_enable_sysfs(struct coresight_device *csdev)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -234,6 +289,9 @@ static int etm4_enable(struct coresight_device *csdev,
case CS_MODE_SYSFS:
ret = etm4_enable_sysfs(csdev);
break;
+ case CS_MODE_PERF:
+ ret = etm4_enable_perf(csdev, attr);
+ break;
default:
ret = -EINVAL;
}
@@ -267,6 +325,17 @@ static void etm4_disable_hw(void *info)
dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
}
+static int etm4_disable_perf(struct coresight_device *csdev)
+{
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
+ return -EINVAL;
+
+ etm4_disable_hw(drvdata);
+ return 0;
+}
+
static void etm4_disable_sysfs(struct coresight_device *csdev)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -310,6 +379,9 @@ static void etm4_disable(struct coresight_device *csdev)
case CS_MODE_SYSFS:
etm4_disable_sysfs(csdev);
break;
+ case CS_MODE_PERF:
+ etm4_disable_perf(csdev);
+ break;
}
if (mode)
@@ -709,8 +781,6 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
etm4_init_trace_id(drvdata);
etm4_set_default(&drvdata->config);
- pm_runtime_put(&adev->dev);
-
desc->type = CORESIGHT_DEV_TYPE_SOURCE;
desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
desc->ops = &etm4_cs_ops;
@@ -720,9 +790,16 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
- goto err_coresight_register;
+ goto err_arch_supported;
}
+ ret = etm_perf_symlink(drvdata->csdev, true);
+ if (ret) {
+ coresight_unregister(drvdata->csdev);
+ goto err_arch_supported;
+ }
+
+ pm_runtime_put(&adev->dev);
dev_info(dev, "%s initialized\n", (char *)id->data);
if (boot_enable) {
@@ -733,8 +810,6 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
err_arch_supported:
- pm_runtime_put(&adev->dev);
-err_coresight_register:
if (--etm4_count == 0)
unregister_hotcpu_notifier(&etm4_cpu_notifier);
return ret;
--
2.1.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2016-02-29 18:54 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-02-29 18:54 [PATCH 0/8] coresight: etmv4: make driver usable by Perf Mathieu Poirier
2016-02-29 18:54 ` [PATCH 2/8] coresight: etm4x: adding config and traceid registers Mathieu Poirier
2016-02-29 18:54 ` [PATCH 3/8] coresight: etm4x: splitting struct etmv4_drvdata Mathieu Poirier
2016-02-29 18:54 ` [PATCH 4/8] coresight: etm4x: splitting etmv4 default configuration Mathieu Poirier
2016-02-29 18:54 ` [PATCH 5/8] coresight: etm4x: unlocking tracers in default arch init Mathieu Poirier
2016-02-29 18:54 ` [PATCH 6/8] coresight: etm4x: moving etm_drvdata::enable to atomic field Mathieu Poirier
2016-02-29 18:54 ` [PATCH 7/8] coresight: etm4x: implementing user/kernel mode tracing Mathieu Poirier
2016-02-29 18:54 ` [PATCH 8/8] coresight: etm4x: implementing the perf PMU API Mathieu Poirier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).