Commit 15e28b8e authored by Robert Walker's avatar Robert Walker
Browse files

etm4x: Enable strobing of ETM

Controlled by sysfs parameters:
  strobe_window: How many cycles to sample for
  strobe_period: How many windows between sampled windows

To sample 1000 cycles every 20000 cycles:
  strobe_window: 1000
  strobe_period: 20
parent aafe6283
......@@ -1990,6 +1990,64 @@ static ssize_t cpu_show(struct device *dev,
}
static DEVICE_ATTR_RO(cpu);
static ssize_t strobe_period_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
val = drvdata->strobe_period;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static ssize_t strobe_period_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
drvdata->strobe_period = val;
drvdata->strobe_period_last = val;
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(strobe_period);
static ssize_t strobe_window_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
val = drvdata->strobe_window;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static ssize_t strobe_window_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
if (kstrtoul(buf, 16, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
drvdata->strobe_window = val;
drvdata->strobe_window_last = val;
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(strobe_window);
static struct attribute *coresight_etmv4_attrs[] = {
&dev_attr_nr_pe_cmp.attr,
&dev_attr_nr_addr_cmp.attr,
......@@ -2037,6 +2095,8 @@ static struct attribute *coresight_etmv4_attrs[] = {
&dev_attr_vmid_val.attr,
&dev_attr_vmid_masks.attr,
&dev_attr_cpu.attr,
&dev_attr_strobe_period.attr,
&dev_attr_strobe_window.attr,
NULL,
};
......
......@@ -48,6 +48,7 @@ static struct etmv4_drvdata *etmdrvdata[NR_CPUS];
static void etm4_set_default_config(struct etmv4_config *config);
static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
struct perf_event *event);
static int etm4_set_strobing(struct etmv4_drvdata *drvdata);
static enum cpuhp_state hp_online;
......@@ -215,6 +216,10 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
if (ret)
goto out;
ret = etm4_set_strobing(drvdata);
if (ret)
goto out;
/* Go from generic option to ETMv4 specifics */
if (attr->config & BIT(ETM_OPT_CYCACC)) {
config->cfg |= BIT(4);
......@@ -335,6 +340,12 @@ static void etm4_disable_hw(void *info)
isb();
writel_relaxed(control, drvdata->base + TRCPRGCTLR);
if (drvdata->strobe_period != 0 &&
drvdata->strobe_window != 0) {
drvdata->strobe_window_last = readl_relaxed(drvdata->base + TRCCNTVRn(0));
drvdata->strobe_period_last = readl_relaxed(drvdata->base + TRCCNTVRn(1));
}
CS_LOCK(drvdata->base);
dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
......@@ -871,6 +882,46 @@ out:
return ret;
}
static int etm4_set_strobing(struct etmv4_drvdata *drvdata)
{
int ret = 0;
struct etmv4_config *config = &drvdata->config;
if (drvdata->strobe_period != 0 &&
drvdata->strobe_window != 0) {
/* Resource selector 2 is on when counter 0 is at zero */
config->res_ctrl[2] = 0x20001;
/* Resource selector 3 is on when counter 1 is at zero */
config->res_ctrl[3] = 0x20002;
/* This means resource selector pair 1 is on when both counters
0 and 1 are at zero */
/* Counter 0 counts cycles for one window */
config->cntrldvr[0] = drvdata->strobe_window - 1;
config->cntr_val[0] = drvdata->strobe_window_last;
/* reloads on zero, always count, never reload from other events */
config->cntr_ctrl[0] = 0x10001;
/* Counter 1 counts windows in one period */
config->cntrldvr[1] = drvdata->strobe_period - 1;
config->cntr_val[1] = drvdata->strobe_period_last;
/* config->cntr_val[1] = drvdata->strobe_period - 1; */
/* reloads when both counters are at zero, count when counter 0 is zero */
config->cntr_ctrl[1] = 0x8102;
/* Move state to 1 on counter 1 */
config->seq_ctrl[0] = 0x0081;
config->seq_ctrl[1] = 0x0000;
/* activate ViewInst while counter 1 is zero (lasts one window) */
config->vinst_ctrl |= 3;
}
return ret;
}
void etm4_config_trace_mode(struct etmv4_config *config)
{
u32 addr_acc, mode;
......@@ -1014,6 +1065,10 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
etm4_init_trace_id(drvdata);
etm4_set_default(&drvdata->config);
drvdata->strobe_period = 0;
drvdata->strobe_period_last = 0;
drvdata->strobe_window = 0;
drvdata->strobe_window_last = 0;
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
......
......@@ -392,6 +392,10 @@ struct etmv4_drvdata {
bool nooverflow;
bool atbtrig;
bool lpoverride;
u32 strobe_window;
u32 strobe_period;
u32 strobe_window_last;
u32 strobe_period_last;
struct etmv4_config config;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment