Skip to content

Commit 810ac40

Browse files
mikel-armbbgregkh
authored andcommitted
coresight: etm4x: Add complex configuration handlers to etmv4
Adds in handlers to allow the ETMv4 to use the complex configuration support. Features and configurations can be loaded and selected in the device. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mike Leach <[email protected]> Signed-off-by: Mathieu Poirier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent a0114b4 commit 810ac40

File tree

5 files changed

+238
-3
lines changed

5 files changed

+238
-3
lines changed

drivers/hwtracing/coresight/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o
1616
coresight-etm3x-y := coresight-etm3x-core.o coresight-etm-cp14.o \
1717
coresight-etm3x-sysfs.o
1818
obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o
19-
coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o
19+
coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o \
20+
coresight-etm4x-cfg.o
2021
obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
2122
obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o
2223
obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright(C) 2020 Linaro Limited. All rights reserved.
4+
* Author: Mike Leach <[email protected]>
5+
*/
6+
7+
#include "coresight-etm4x.h"
8+
#include "coresight-etm4x-cfg.h"
9+
#include "coresight-priv.h"
10+
#include "coresight-syscfg.h"
11+
12+
/* defines to associate register IDs with driver data locations */
13+
#define CHECKREG(cval, elem) \
14+
{ \
15+
if (offset == cval) { \
16+
reg_csdev->driver_regval = &drvcfg->elem; \
17+
err = 0; \
18+
break; \
19+
} \
20+
}
21+
22+
#define CHECKREGIDX(cval, elem, off_idx, mask) \
23+
{ \
24+
if (mask == cval) { \
25+
reg_csdev->driver_regval = &drvcfg->elem[off_idx]; \
26+
err = 0; \
27+
break; \
28+
} \
29+
}
30+
31+
/**
32+
* etm4_cfg_map_reg_offset - validate and map the register offset into a
33+
* location in the driver config struct.
34+
*
35+
* Limits the number of registers that can be accessed and programmed in
36+
* features, to those which are used to control the trace capture parameters.
37+
*
38+
* Omits or limits access to those which the driver must use exclusively.
39+
*
40+
* Invalid offsets will result in fail code return and feature load failure.
41+
*
42+
* @drvdata: driver data to map into.
43+
* @reg: register to map.
44+
* @offset: device offset for the register
45+
*/
46+
static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
47+
struct cscfg_regval_csdev *reg_csdev, u32 offset)
48+
{
49+
int err = -EINVAL, idx;
50+
struct etmv4_config *drvcfg = &drvdata->config;
51+
u32 off_mask;
52+
53+
if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
54+
((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) ||
55+
((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) {
56+
do {
57+
CHECKREG(TRCEVENTCTL0R, eventctrl0);
58+
CHECKREG(TRCEVENTCTL1R, eventctrl1);
59+
CHECKREG(TRCSTALLCTLR, stall_ctrl);
60+
CHECKREG(TRCTSCTLR, ts_ctrl);
61+
CHECKREG(TRCSYNCPR, syncfreq);
62+
CHECKREG(TRCCCCTLR, ccctlr);
63+
CHECKREG(TRCBBCTLR, bb_ctrl);
64+
CHECKREG(TRCVICTLR, vinst_ctrl);
65+
CHECKREG(TRCVIIECTLR, viiectlr);
66+
CHECKREG(TRCVISSCTLR, vissctlr);
67+
CHECKREG(TRCVIPCSSCTLR, vipcssctlr);
68+
CHECKREG(TRCSEQRSTEVR, seq_rst);
69+
CHECKREG(TRCSEQSTR, seq_state);
70+
CHECKREG(TRCEXTINSELR, ext_inp);
71+
CHECKREG(TRCCIDCCTLR0, ctxid_mask0);
72+
CHECKREG(TRCCIDCCTLR1, ctxid_mask1);
73+
CHECKREG(TRCVMIDCCTLR0, vmid_mask0);
74+
CHECKREG(TRCVMIDCCTLR1, vmid_mask1);
75+
} while (0);
76+
} else if ((offset & GENMASK(11, 4)) == TRCSEQEVRn(0)) {
77+
/* sequencer state control registers */
78+
idx = (offset & GENMASK(3, 0)) / 4;
79+
if (idx < ETM_MAX_SEQ_STATES) {
80+
reg_csdev->driver_regval = &drvcfg->seq_ctrl[idx];
81+
err = 0;
82+
}
83+
} else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) {
84+
/* 32 bit, 8 off indexed register sets */
85+
idx = (offset & GENMASK(4, 0)) / 4;
86+
off_mask = (offset & GENMASK(11, 5));
87+
do {
88+
CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
89+
CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
90+
CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
91+
} while (0);
92+
} else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
93+
/* 64 bit, 8 off indexed register sets */
94+
idx = (offset & GENMASK(5, 0)) / 8;
95+
off_mask = (offset & GENMASK(11, 6));
96+
do {
97+
CHECKREGIDX(TRCCIDCVRn(0), ctxid_pid, idx, off_mask);
98+
CHECKREGIDX(TRCVMIDCVRn(0), vmid_val, idx, off_mask);
99+
} while (0);
100+
} else if ((offset >= TRCRSCTLRn(2)) &&
101+
(offset <= TRCRSCTLRn((ETM_MAX_RES_SEL - 1)))) {
102+
/* 32 bit resource selection regs, 32 off, skip fixed 0,1 */
103+
idx = (offset & GENMASK(6, 0)) / 4;
104+
if (idx < ETM_MAX_RES_SEL) {
105+
reg_csdev->driver_regval = &drvcfg->res_ctrl[idx];
106+
err = 0;
107+
}
108+
} else if ((offset >= TRCACVRn(0)) &&
109+
(offset <= TRCACATRn((ETM_MAX_SINGLE_ADDR_CMP - 1)))) {
110+
/* 64 bit addr cmp regs, 16 off */
111+
idx = (offset & GENMASK(6, 0)) / 8;
112+
off_mask = offset & GENMASK(11, 7);
113+
do {
114+
CHECKREGIDX(TRCACVRn(0), addr_val, idx, off_mask);
115+
CHECKREGIDX(TRCACATRn(0), addr_acc, idx, off_mask);
116+
} while (0);
117+
} else if ((offset >= TRCCNTRLDVRn(0)) &&
118+
(offset <= TRCCNTVRn((ETMv4_MAX_CNTR - 1)))) {
119+
/* 32 bit counter regs, 4 off (ETMv4_MAX_CNTR - 1) */
120+
idx = (offset & GENMASK(3, 0)) / 4;
121+
off_mask = offset & GENMASK(11, 4);
122+
do {
123+
CHECKREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx, off_mask);
124+
CHECKREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx, off_mask);
125+
CHECKREGIDX(TRCCNTVRn(0), cntr_val, idx, off_mask);
126+
} while (0);
127+
}
128+
return err;
129+
}
130+
131+
/**
132+
* etm4_cfg_load_feature - load a feature into a device instance.
133+
*
134+
* @csdev: An ETMv4 CoreSight device.
135+
* @feat: The feature to be loaded.
136+
*
137+
* The function will load a feature instance into the device, checking that
138+
* the register definitions are valid for the device.
139+
*
140+
* Parameter and register definitions will be converted into internal
141+
* structures that are used to set the values in the driver when the
142+
* feature is enabled for the device.
143+
*
144+
* The feature spinlock pointer is initialised to the same spinlock
145+
* that the driver uses to protect the internal register values.
146+
*/
147+
static int etm4_cfg_load_feature(struct coresight_device *csdev,
148+
struct cscfg_feature_csdev *feat_csdev)
149+
{
150+
struct device *dev = csdev->dev.parent;
151+
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
152+
const struct cscfg_feature_desc *feat_desc = feat_csdev->feat_desc;
153+
u32 offset;
154+
int i = 0, err = 0;
155+
156+
/*
157+
* essential we set the device spinlock - this is used in the generic
158+
* programming routines when copying values into the drvdata structures
159+
* via the pointers setup in etm4_cfg_map_reg_offset().
160+
*/
161+
feat_csdev->drv_spinlock = &drvdata->spinlock;
162+
163+
/* process the register descriptions */
164+
for (i = 0; i < feat_csdev->nr_regs && !err; i++) {
165+
offset = feat_desc->regs_desc[i].offset;
166+
err = etm4_cfg_map_reg_offset(drvdata, &feat_csdev->regs_csdev[i], offset);
167+
}
168+
return err;
169+
}
170+
171+
/* match information when loading configurations */
172+
#define CS_CFG_ETM4_MATCH_FLAGS (CS_CFG_MATCH_CLASS_SRC_ALL | \
173+
CS_CFG_MATCH_CLASS_SRC_ETM4)
174+
175+
int etm4_cscfg_register(struct coresight_device *csdev)
176+
{
177+
struct cscfg_csdev_feat_ops ops;
178+
179+
ops.load_feat = &etm4_cfg_load_feature;
180+
181+
return cscfg_register_csdev(csdev, CS_CFG_ETM4_MATCH_FLAGS, &ops);
182+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
4+
*/
5+
6+
#ifndef _CORESIGHT_ETM4X_CFG_H
7+
#define _CORESIGHT_ETM4X_CFG_H
8+
9+
#include "coresight-config.h"
10+
#include "coresight-etm4x.h"
11+
12+
/* ETMv4 specific config functions */
13+
int etm4_cscfg_register(struct coresight_device *csdev);
14+
15+
#endif /* CORESIGHT_ETM4X_CFG_H */

drivers/hwtracing/coresight/coresight-etm4x-core.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939

4040
#include "coresight-etm4x.h"
4141
#include "coresight-etm-perf.h"
42+
#include "coresight-etm4x-cfg.h"
43+
#include "coresight-syscfg.h"
4244

4345
static int boot_enable;
4446
module_param(boot_enable, int, 0444);
@@ -561,12 +563,15 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata)
561563
return ret;
562564
}
563565

564-
static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
566+
static int etm4_parse_event_config(struct coresight_device *csdev,
565567
struct perf_event *event)
566568
{
567569
int ret = 0;
570+
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
568571
struct etmv4_config *config = &drvdata->config;
569572
struct perf_event_attr *attr = &event->attr;
573+
unsigned long cfg_hash;
574+
int preset;
570575

571576
/* Clear configuration from previous run */
572577
memset(config, 0, sizeof(struct etmv4_config));
@@ -632,6 +637,20 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
632637
/* bit[12], Return stack enable bit */
633638
config->cfg |= BIT(12);
634639

640+
/*
641+
* Set any selected configuration and preset.
642+
*
643+
* This extracts the values of PMU_FORMAT_ATTR(configid) and PMU_FORMAT_ATTR(preset)
644+
* in the perf attributes defined in coresight-etm-perf.c.
645+
* configid uses bits 63:32 of attr->config2, preset uses bits 3:0 of attr->config.
646+
* A zero configid means no configuration active, preset = 0 means no preset selected.
647+
*/
648+
if (attr->config2 & GENMASK_ULL(63, 32)) {
649+
cfg_hash = (u32)(attr->config2 >> 32);
650+
preset = attr->config & 0xF;
651+
ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
652+
}
653+
635654
out:
636655
return ret;
637656
}
@@ -648,7 +667,7 @@ static int etm4_enable_perf(struct coresight_device *csdev,
648667
}
649668

650669
/* Configure the tracer based on the session's specifics */
651-
ret = etm4_parse_event_config(drvdata, event);
670+
ret = etm4_parse_event_config(csdev, event);
652671
if (ret)
653672
goto out;
654673
/* And enable it */
@@ -794,11 +813,18 @@ static int etm4_disable_perf(struct coresight_device *csdev,
794813
u32 control;
795814
struct etm_filters *filters = event->hw.addr_filters;
796815
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
816+
struct perf_event_attr *attr = &event->attr;
797817

798818
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
799819
return -EINVAL;
800820

801821
etm4_disable_hw(drvdata);
822+
/*
823+
* The config_id occupies bits 63:32 of the config2 perf event attr
824+
* field. If this is non-zero then we will have enabled a config.
825+
*/
826+
if (attr->config2 & GENMASK_ULL(63, 32))
827+
cscfg_csdev_disable_active_config(csdev);
802828

803829
/*
804830
* Check if the start/stop logic was active when the unit was stopped.
@@ -1939,6 +1965,13 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)
19391965
return ret;
19401966
}
19411967

1968+
/* register with config infrastructure & load any current features */
1969+
ret = etm4_cscfg_register(drvdata->csdev);
1970+
if (ret) {
1971+
coresight_unregister(drvdata->csdev);
1972+
return ret;
1973+
}
1974+
19421975
etmdrvdata[drvdata->cpu] = drvdata;
19431976

19441977
dev_info(&drvdata->csdev->dev, "CPU%d: %s v%d.%d initialized\n",
@@ -2025,6 +2058,7 @@ static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata)
20252058

20262059
cpus_read_unlock();
20272060

2061+
cscfg_unregister_csdev(drvdata->csdev);
20282062
coresight_unregister(drvdata->csdev);
20292063

20302064
return 0;

drivers/hwtracing/coresight/coresight-etm4x-sysfs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/sysfs.h>
1010
#include "coresight-etm4x.h"
1111
#include "coresight-priv.h"
12+
#include "coresight-syscfg.h"
1213

1314
static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
1415
{
@@ -269,6 +270,8 @@ static ssize_t reset_store(struct device *dev,
269270

270271
spin_unlock(&drvdata->spinlock);
271272

273+
cscfg_csdev_reset_feats(to_coresight_device(dev));
274+
272275
return size;
273276
}
274277
static DEVICE_ATTR_WO(reset);

0 commit comments

Comments
 (0)