1ad0dfdfdSMathieu Poirier // SPDX-License-Identifier: GPL-2.0
2a77de263SMathieu Poirier /*
3a77de263SMathieu Poirier * Copyright(C) 2015 Linaro Limited. All rights reserved.
4a77de263SMathieu Poirier * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
5a77de263SMathieu Poirier */
6a77de263SMathieu Poirier
7450367f0SMathieu Poirier #include <linux/pid_namespace.h>
8a77de263SMathieu Poirier #include <linux/pm_runtime.h>
9a77de263SMathieu Poirier #include <linux/sysfs.h>
10a77de263SMathieu Poirier #include "coresight-etm4x.h"
112b7adc46SMathieu Poirier #include "coresight-priv.h"
12810ac401SMike Leach #include "coresight-syscfg.h"
13a77de263SMathieu Poirier
etm4_set_mode_exclude(struct etmv4_drvdata * drvdata,bool exclude)14a77de263SMathieu Poirier static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
15a77de263SMathieu Poirier {
1654ff892bSMathieu Poirier u8 idx;
1754ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1854ff892bSMathieu Poirier
1954ff892bSMathieu Poirier idx = config->addr_idx;
20a77de263SMathieu Poirier
21a77de263SMathieu Poirier /*
22a77de263SMathieu Poirier * TRCACATRn.TYPE bit[1:0]: type of comparison
23a77de263SMathieu Poirier * the trace unit performs
24a77de263SMathieu Poirier */
25f5def772SJames Clark if (FIELD_GET(TRCACATRn_TYPE_MASK, config->addr_acc[idx]) == TRCACATRn_TYPE_ADDR) {
26a77de263SMathieu Poirier if (idx % 2 != 0)
27a77de263SMathieu Poirier return -EINVAL;
28a77de263SMathieu Poirier
29a77de263SMathieu Poirier /*
30a77de263SMathieu Poirier * We are performing instruction address comparison. Set the
31a77de263SMathieu Poirier * relevant bit of ViewInst Include/Exclude Control register
32a77de263SMathieu Poirier * for corresponding address comparator pair.
33a77de263SMathieu Poirier */
3454ff892bSMathieu Poirier if (config->addr_type[idx] != ETM_ADDR_TYPE_RANGE ||
3554ff892bSMathieu Poirier config->addr_type[idx + 1] != ETM_ADDR_TYPE_RANGE)
36a77de263SMathieu Poirier return -EINVAL;
37a77de263SMathieu Poirier
38a77de263SMathieu Poirier if (exclude == true) {
39a77de263SMathieu Poirier /*
40a77de263SMathieu Poirier * Set exclude bit and unset the include bit
41a77de263SMathieu Poirier * corresponding to comparator pair
42a77de263SMathieu Poirier */
4354ff892bSMathieu Poirier config->viiectlr |= BIT(idx / 2 + 16);
4454ff892bSMathieu Poirier config->viiectlr &= ~BIT(idx / 2);
45a77de263SMathieu Poirier } else {
46a77de263SMathieu Poirier /*
47a77de263SMathieu Poirier * Set include bit and unset exclude bit
48a77de263SMathieu Poirier * corresponding to comparator pair
49a77de263SMathieu Poirier */
5054ff892bSMathieu Poirier config->viiectlr |= BIT(idx / 2);
5154ff892bSMathieu Poirier config->viiectlr &= ~BIT(idx / 2 + 16);
52a77de263SMathieu Poirier }
53a77de263SMathieu Poirier }
54a77de263SMathieu Poirier return 0;
55a77de263SMathieu Poirier }
56a77de263SMathieu Poirier
nr_pe_cmp_show(struct device * dev,struct device_attribute * attr,char * buf)57a77de263SMathieu Poirier static ssize_t nr_pe_cmp_show(struct device *dev,
58a77de263SMathieu Poirier struct device_attribute *attr,
59a77de263SMathieu Poirier char *buf)
60a77de263SMathieu Poirier {
61a77de263SMathieu Poirier unsigned long val;
62a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
63a77de263SMathieu Poirier
64a77de263SMathieu Poirier val = drvdata->nr_pe_cmp;
65a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
66a77de263SMathieu Poirier }
67a77de263SMathieu Poirier static DEVICE_ATTR_RO(nr_pe_cmp);
68a77de263SMathieu Poirier
nr_addr_cmp_show(struct device * dev,struct device_attribute * attr,char * buf)69a77de263SMathieu Poirier static ssize_t nr_addr_cmp_show(struct device *dev,
70a77de263SMathieu Poirier struct device_attribute *attr,
71a77de263SMathieu Poirier char *buf)
72a77de263SMathieu Poirier {
73a77de263SMathieu Poirier unsigned long val;
74a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
75a77de263SMathieu Poirier
76a77de263SMathieu Poirier val = drvdata->nr_addr_cmp;
77a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
78a77de263SMathieu Poirier }
79a77de263SMathieu Poirier static DEVICE_ATTR_RO(nr_addr_cmp);
80a77de263SMathieu Poirier
nr_cntr_show(struct device * dev,struct device_attribute * attr,char * buf)81a77de263SMathieu Poirier static ssize_t nr_cntr_show(struct device *dev,
82a77de263SMathieu Poirier struct device_attribute *attr,
83a77de263SMathieu Poirier char *buf)
84a77de263SMathieu Poirier {
85a77de263SMathieu Poirier unsigned long val;
86a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
87a77de263SMathieu Poirier
88a77de263SMathieu Poirier val = drvdata->nr_cntr;
89a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
90a77de263SMathieu Poirier }
91a77de263SMathieu Poirier static DEVICE_ATTR_RO(nr_cntr);
92a77de263SMathieu Poirier
nr_ext_inp_show(struct device * dev,struct device_attribute * attr,char * buf)93a77de263SMathieu Poirier static ssize_t nr_ext_inp_show(struct device *dev,
94a77de263SMathieu Poirier struct device_attribute *attr,
95a77de263SMathieu Poirier char *buf)
96a77de263SMathieu Poirier {
97a77de263SMathieu Poirier unsigned long val;
98a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
99a77de263SMathieu Poirier
100a77de263SMathieu Poirier val = drvdata->nr_ext_inp;
101a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
102a77de263SMathieu Poirier }
103a77de263SMathieu Poirier static DEVICE_ATTR_RO(nr_ext_inp);
104a77de263SMathieu Poirier
numcidc_show(struct device * dev,struct device_attribute * attr,char * buf)105a77de263SMathieu Poirier static ssize_t numcidc_show(struct device *dev,
106a77de263SMathieu Poirier struct device_attribute *attr,
107a77de263SMathieu Poirier char *buf)
108a77de263SMathieu Poirier {
109a77de263SMathieu Poirier unsigned long val;
110a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
111a77de263SMathieu Poirier
112a77de263SMathieu Poirier val = drvdata->numcidc;
113a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
114a77de263SMathieu Poirier }
115a77de263SMathieu Poirier static DEVICE_ATTR_RO(numcidc);
116a77de263SMathieu Poirier
numvmidc_show(struct device * dev,struct device_attribute * attr,char * buf)117a77de263SMathieu Poirier static ssize_t numvmidc_show(struct device *dev,
118a77de263SMathieu Poirier struct device_attribute *attr,
119a77de263SMathieu Poirier char *buf)
120a77de263SMathieu Poirier {
121a77de263SMathieu Poirier unsigned long val;
122a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
123a77de263SMathieu Poirier
124a77de263SMathieu Poirier val = drvdata->numvmidc;
125a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
126a77de263SMathieu Poirier }
127a77de263SMathieu Poirier static DEVICE_ATTR_RO(numvmidc);
128a77de263SMathieu Poirier
nrseqstate_show(struct device * dev,struct device_attribute * attr,char * buf)129a77de263SMathieu Poirier static ssize_t nrseqstate_show(struct device *dev,
130a77de263SMathieu Poirier struct device_attribute *attr,
131a77de263SMathieu Poirier char *buf)
132a77de263SMathieu Poirier {
133a77de263SMathieu Poirier unsigned long val;
134a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
135a77de263SMathieu Poirier
136a77de263SMathieu Poirier val = drvdata->nrseqstate;
137a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
138a77de263SMathieu Poirier }
139a77de263SMathieu Poirier static DEVICE_ATTR_RO(nrseqstate);
140a77de263SMathieu Poirier
nr_resource_show(struct device * dev,struct device_attribute * attr,char * buf)141a77de263SMathieu Poirier static ssize_t nr_resource_show(struct device *dev,
142a77de263SMathieu Poirier struct device_attribute *attr,
143a77de263SMathieu Poirier char *buf)
144a77de263SMathieu Poirier {
145a77de263SMathieu Poirier unsigned long val;
146a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
147a77de263SMathieu Poirier
148a77de263SMathieu Poirier val = drvdata->nr_resource;
149a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
150a77de263SMathieu Poirier }
151a77de263SMathieu Poirier static DEVICE_ATTR_RO(nr_resource);
152a77de263SMathieu Poirier
nr_ss_cmp_show(struct device * dev,struct device_attribute * attr,char * buf)153a77de263SMathieu Poirier static ssize_t nr_ss_cmp_show(struct device *dev,
154a77de263SMathieu Poirier struct device_attribute *attr,
155a77de263SMathieu Poirier char *buf)
156a77de263SMathieu Poirier {
157a77de263SMathieu Poirier unsigned long val;
158a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
159a77de263SMathieu Poirier
160a77de263SMathieu Poirier val = drvdata->nr_ss_cmp;
161a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
162a77de263SMathieu Poirier }
163a77de263SMathieu Poirier static DEVICE_ATTR_RO(nr_ss_cmp);
164a77de263SMathieu Poirier
reset_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)165a77de263SMathieu Poirier static ssize_t reset_store(struct device *dev,
166a77de263SMathieu Poirier struct device_attribute *attr,
167a77de263SMathieu Poirier const char *buf, size_t size)
168a77de263SMathieu Poirier {
169a77de263SMathieu Poirier int i;
170a77de263SMathieu Poirier unsigned long val;
171a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
17254ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
173a77de263SMathieu Poirier
174a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
175a77de263SMathieu Poirier return -EINVAL;
176a77de263SMathieu Poirier
177a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
178a77de263SMathieu Poirier if (val)
17954ff892bSMathieu Poirier config->mode = 0x0;
180a77de263SMathieu Poirier
181a77de263SMathieu Poirier /* Disable data tracing: do not trace load and store data transfers */
18254ff892bSMathieu Poirier config->mode &= ~(ETM_MODE_LOAD | ETM_MODE_STORE);
1831cf50f64SJames Clark config->cfg &= ~(TRCCONFIGR_INSTP0_LOAD | TRCCONFIGR_INSTP0_STORE);
184a77de263SMathieu Poirier
185a77de263SMathieu Poirier /* Disable data value and data address tracing */
18654ff892bSMathieu Poirier config->mode &= ~(ETM_MODE_DATA_TRACE_ADDR |
187a77de263SMathieu Poirier ETM_MODE_DATA_TRACE_VAL);
1881cf50f64SJames Clark config->cfg &= ~(TRCCONFIGR_DA | TRCCONFIGR_DV);
189a77de263SMathieu Poirier
190a77de263SMathieu Poirier /* Disable all events tracing */
19154ff892bSMathieu Poirier config->eventctrl0 = 0x0;
19254ff892bSMathieu Poirier config->eventctrl1 = 0x0;
193a77de263SMathieu Poirier
194a77de263SMathieu Poirier /* Disable timestamp event */
19554ff892bSMathieu Poirier config->ts_ctrl = 0x0;
196a77de263SMathieu Poirier
197a77de263SMathieu Poirier /* Disable stalling */
19854ff892bSMathieu Poirier config->stall_ctrl = 0x0;
199a77de263SMathieu Poirier
200a77de263SMathieu Poirier /* Reset trace synchronization period to 2^8 = 256 bytes*/
201a77de263SMathieu Poirier if (drvdata->syncpr == false)
20254ff892bSMathieu Poirier config->syncfreq = 0x8;
203a77de263SMathieu Poirier
204a77de263SMathieu Poirier /*
205a77de263SMathieu Poirier * Enable ViewInst to trace everything with start-stop logic in
206a77de263SMathieu Poirier * started state. ARM recommends start-stop logic is set before
207a77de263SMathieu Poirier * each trace run.
208a77de263SMathieu Poirier */
2096ba7f2bcSJames Clark config->vinst_ctrl = FIELD_PREP(TRCVICTLR_EVENT_MASK, 0x01);
2104020fc8dSJonathan Zhou if (drvdata->nr_addr_cmp > 0) {
21154ff892bSMathieu Poirier config->mode |= ETM_MODE_VIEWINST_STARTSTOP;
212a77de263SMathieu Poirier /* SSSTATUS, bit[9] */
2136ba7f2bcSJames Clark config->vinst_ctrl |= TRCVICTLR_SSSTATUS;
214a77de263SMathieu Poirier }
215a77de263SMathieu Poirier
216a77de263SMathieu Poirier /* No address range filtering for ViewInst */
21754ff892bSMathieu Poirier config->viiectlr = 0x0;
218a77de263SMathieu Poirier
219a77de263SMathieu Poirier /* No start-stop filtering for ViewInst */
22054ff892bSMathieu Poirier config->vissctlr = 0x0;
2211b6b0e08SMike Leach config->vipcssctlr = 0x0;
222a77de263SMathieu Poirier
223a77de263SMathieu Poirier /* Disable seq events */
224a77de263SMathieu Poirier for (i = 0; i < drvdata->nrseqstate-1; i++)
22554ff892bSMathieu Poirier config->seq_ctrl[i] = 0x0;
22654ff892bSMathieu Poirier config->seq_rst = 0x0;
22754ff892bSMathieu Poirier config->seq_state = 0x0;
228a77de263SMathieu Poirier
229a77de263SMathieu Poirier /* Disable external input events */
23054ff892bSMathieu Poirier config->ext_inp = 0x0;
231a77de263SMathieu Poirier
23254ff892bSMathieu Poirier config->cntr_idx = 0x0;
233a77de263SMathieu Poirier for (i = 0; i < drvdata->nr_cntr; i++) {
23454ff892bSMathieu Poirier config->cntrldvr[i] = 0x0;
23554ff892bSMathieu Poirier config->cntr_ctrl[i] = 0x0;
23654ff892bSMathieu Poirier config->cntr_val[i] = 0x0;
237a77de263SMathieu Poirier }
238a77de263SMathieu Poirier
23954ff892bSMathieu Poirier config->res_idx = 0x0;
240685d84a7SJonathan Zhou for (i = 2; i < 2 * drvdata->nr_resource; i++)
24154ff892bSMathieu Poirier config->res_ctrl[i] = 0x0;
242a77de263SMathieu Poirier
243ebddaad0SMike Leach config->ss_idx = 0x0;
244a77de263SMathieu Poirier for (i = 0; i < drvdata->nr_ss_cmp; i++) {
24554ff892bSMathieu Poirier config->ss_ctrl[i] = 0x0;
24654ff892bSMathieu Poirier config->ss_pe_cmp[i] = 0x0;
247a77de263SMathieu Poirier }
248a77de263SMathieu Poirier
24954ff892bSMathieu Poirier config->addr_idx = 0x0;
250a77de263SMathieu Poirier for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
25154ff892bSMathieu Poirier config->addr_val[i] = 0x0;
25254ff892bSMathieu Poirier config->addr_acc[i] = 0x0;
25354ff892bSMathieu Poirier config->addr_type[i] = ETM_ADDR_TYPE_NONE;
254a77de263SMathieu Poirier }
255a77de263SMathieu Poirier
25654ff892bSMathieu Poirier config->ctxid_idx = 0x0;
257450367f0SMathieu Poirier for (i = 0; i < drvdata->numcidc; i++)
25854ff892bSMathieu Poirier config->ctxid_pid[i] = 0x0;
259a77de263SMathieu Poirier
26054ff892bSMathieu Poirier config->ctxid_mask0 = 0x0;
26154ff892bSMathieu Poirier config->ctxid_mask1 = 0x0;
262a77de263SMathieu Poirier
26354ff892bSMathieu Poirier config->vmid_idx = 0x0;
264a77de263SMathieu Poirier for (i = 0; i < drvdata->numvmidc; i++)
26554ff892bSMathieu Poirier config->vmid_val[i] = 0x0;
26654ff892bSMathieu Poirier config->vmid_mask0 = 0x0;
26754ff892bSMathieu Poirier config->vmid_mask1 = 0x0;
268a77de263SMathieu Poirier
269a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
27054ff892bSMathieu Poirier
271df487120SMike Leach /* for sysfs - only release trace id when resetting */
272df487120SMike Leach etm4_release_trace_id(drvdata);
273df487120SMike Leach
274810ac401SMike Leach cscfg_csdev_reset_feats(to_coresight_device(dev));
275810ac401SMike Leach
276a77de263SMathieu Poirier return size;
277a77de263SMathieu Poirier }
278a77de263SMathieu Poirier static DEVICE_ATTR_WO(reset);
279a77de263SMathieu Poirier
mode_show(struct device * dev,struct device_attribute * attr,char * buf)280a77de263SMathieu Poirier static ssize_t mode_show(struct device *dev,
281a77de263SMathieu Poirier struct device_attribute *attr,
282a77de263SMathieu Poirier char *buf)
283a77de263SMathieu Poirier {
284a77de263SMathieu Poirier unsigned long val;
285a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
28654ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
287a77de263SMathieu Poirier
28854ff892bSMathieu Poirier val = config->mode;
289a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
290a77de263SMathieu Poirier }
291a77de263SMathieu Poirier
mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)292a77de263SMathieu Poirier static ssize_t mode_store(struct device *dev,
293a77de263SMathieu Poirier struct device_attribute *attr,
294a77de263SMathieu Poirier const char *buf, size_t size)
295a77de263SMathieu Poirier {
296a77de263SMathieu Poirier unsigned long val, mode;
297a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
29854ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
299a77de263SMathieu Poirier
300a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
301a77de263SMathieu Poirier return -EINVAL;
302a77de263SMathieu Poirier
303a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
30454ff892bSMathieu Poirier config->mode = val & ETMv4_MODE_ALL;
305a77de263SMathieu Poirier
306a77de263SMathieu Poirier if (drvdata->instrp0 == true) {
307a77de263SMathieu Poirier /* start by clearing instruction P0 field */
3081cf50f64SJames Clark config->cfg &= ~TRCCONFIGR_INSTP0_LOAD_STORE;
30954ff892bSMathieu Poirier if (config->mode & ETM_MODE_LOAD)
310a77de263SMathieu Poirier /* 0b01 Trace load instructions as P0 instructions */
3111cf50f64SJames Clark config->cfg |= TRCCONFIGR_INSTP0_LOAD;
31254ff892bSMathieu Poirier if (config->mode & ETM_MODE_STORE)
313a77de263SMathieu Poirier /* 0b10 Trace store instructions as P0 instructions */
3141cf50f64SJames Clark config->cfg |= TRCCONFIGR_INSTP0_STORE;
31554ff892bSMathieu Poirier if (config->mode & ETM_MODE_LOAD_STORE)
316a77de263SMathieu Poirier /*
317a77de263SMathieu Poirier * 0b11 Trace load and store instructions
318a77de263SMathieu Poirier * as P0 instructions
319a77de263SMathieu Poirier */
3201cf50f64SJames Clark config->cfg |= TRCCONFIGR_INSTP0_LOAD_STORE;
321a77de263SMathieu Poirier }
322a77de263SMathieu Poirier
323a77de263SMathieu Poirier /* bit[3], Branch broadcast mode */
32454ff892bSMathieu Poirier if ((config->mode & ETM_MODE_BB) && (drvdata->trcbb == true))
3251cf50f64SJames Clark config->cfg |= TRCCONFIGR_BB;
326a77de263SMathieu Poirier else
3271cf50f64SJames Clark config->cfg &= ~TRCCONFIGR_BB;
328a77de263SMathieu Poirier
329a77de263SMathieu Poirier /* bit[4], Cycle counting instruction trace bit */
33054ff892bSMathieu Poirier if ((config->mode & ETMv4_MODE_CYCACC) &&
331a77de263SMathieu Poirier (drvdata->trccci == true))
3321cf50f64SJames Clark config->cfg |= TRCCONFIGR_CCI;
333a77de263SMathieu Poirier else
3341cf50f64SJames Clark config->cfg &= ~TRCCONFIGR_CCI;
335a77de263SMathieu Poirier
336a77de263SMathieu Poirier /* bit[6], Context ID tracing bit */
33754ff892bSMathieu Poirier if ((config->mode & ETMv4_MODE_CTXID) && (drvdata->ctxid_size))
3381cf50f64SJames Clark config->cfg |= TRCCONFIGR_CID;
339a77de263SMathieu Poirier else
3401cf50f64SJames Clark config->cfg &= ~TRCCONFIGR_CID;
341a77de263SMathieu Poirier
34254ff892bSMathieu Poirier if ((config->mode & ETM_MODE_VMID) && (drvdata->vmid_size))
3431cf50f64SJames Clark config->cfg |= TRCCONFIGR_VMID;
344a77de263SMathieu Poirier else
3451cf50f64SJames Clark config->cfg &= ~TRCCONFIGR_VMID;
346a77de263SMathieu Poirier
347a77de263SMathieu Poirier /* bits[10:8], Conditional instruction tracing bit */
34854ff892bSMathieu Poirier mode = ETM_MODE_COND(config->mode);
349a77de263SMathieu Poirier if (drvdata->trccond == true) {
3501cf50f64SJames Clark config->cfg &= ~TRCCONFIGR_COND_MASK;
3511cf50f64SJames Clark config->cfg |= mode << __bf_shf(TRCCONFIGR_COND_MASK);
352a77de263SMathieu Poirier }
353a77de263SMathieu Poirier
354a77de263SMathieu Poirier /* bit[11], Global timestamp tracing bit */
35554ff892bSMathieu Poirier if ((config->mode & ETMv4_MODE_TIMESTAMP) && (drvdata->ts_size))
3561cf50f64SJames Clark config->cfg |= TRCCONFIGR_TS;
357a77de263SMathieu Poirier else
3581cf50f64SJames Clark config->cfg &= ~TRCCONFIGR_TS;
359a77de263SMathieu Poirier
360a77de263SMathieu Poirier /* bit[12], Return stack enable bit */
36154ff892bSMathieu Poirier if ((config->mode & ETM_MODE_RETURNSTACK) &&
362a77de263SMathieu Poirier (drvdata->retstack == true))
3631cf50f64SJames Clark config->cfg |= TRCCONFIGR_RS;
364a77de263SMathieu Poirier else
3651cf50f64SJames Clark config->cfg &= ~TRCCONFIGR_RS;
366a77de263SMathieu Poirier
367a77de263SMathieu Poirier /* bits[14:13], Q element enable field */
36854ff892bSMathieu Poirier mode = ETM_MODE_QELEM(config->mode);
369a77de263SMathieu Poirier /* start by clearing QE bits */
3701cf50f64SJames Clark config->cfg &= ~(TRCCONFIGR_QE_W_COUNTS | TRCCONFIGR_QE_WO_COUNTS);
371ea75a342SJames Clark /*
372ea75a342SJames Clark * if supported, Q elements with instruction counts are enabled.
373ea75a342SJames Clark * Always set the low bit for any requested mode. Valid combos are
374ea75a342SJames Clark * 0b00, 0b01 and 0b11.
375ea75a342SJames Clark */
376ea75a342SJames Clark if (mode && drvdata->q_support)
3771cf50f64SJames Clark config->cfg |= TRCCONFIGR_QE_W_COUNTS;
378a77de263SMathieu Poirier /*
379a77de263SMathieu Poirier * if supported, Q elements with and without instruction
380a77de263SMathieu Poirier * counts are enabled
381a77de263SMathieu Poirier */
382a77de263SMathieu Poirier if ((mode & BIT(1)) && (drvdata->q_support & BIT(1)))
3831cf50f64SJames Clark config->cfg |= TRCCONFIGR_QE_WO_COUNTS;
384a77de263SMathieu Poirier
385a77de263SMathieu Poirier /* bit[11], AMBA Trace Bus (ATB) trigger enable bit */
38654ff892bSMathieu Poirier if ((config->mode & ETM_MODE_ATB_TRIGGER) &&
387a77de263SMathieu Poirier (drvdata->atbtrig == true))
388eeae6dddSJames Clark config->eventctrl1 |= TRCEVENTCTL1R_ATB;
389a77de263SMathieu Poirier else
390eeae6dddSJames Clark config->eventctrl1 &= ~TRCEVENTCTL1R_ATB;
391a77de263SMathieu Poirier
392a77de263SMathieu Poirier /* bit[12], Low-power state behavior override bit */
39354ff892bSMathieu Poirier if ((config->mode & ETM_MODE_LPOVERRIDE) &&
394a77de263SMathieu Poirier (drvdata->lpoverride == true))
395eeae6dddSJames Clark config->eventctrl1 |= TRCEVENTCTL1R_LPOVERRIDE;
396a77de263SMathieu Poirier else
397eeae6dddSJames Clark config->eventctrl1 &= ~TRCEVENTCTL1R_LPOVERRIDE;
398a77de263SMathieu Poirier
399a77de263SMathieu Poirier /* bit[8], Instruction stall bit */
400f7289606SSuzuki K Poulose if ((config->mode & ETM_MODE_ISTALL_EN) && (drvdata->stallctl == true))
401b5bc16abSJames Clark config->stall_ctrl |= TRCSTALLCTLR_ISTALL;
402a77de263SMathieu Poirier else
403b5bc16abSJames Clark config->stall_ctrl &= ~TRCSTALLCTLR_ISTALL;
404a77de263SMathieu Poirier
405a77de263SMathieu Poirier /* bit[10], Prioritize instruction trace bit */
40654ff892bSMathieu Poirier if (config->mode & ETM_MODE_INSTPRIO)
407b5bc16abSJames Clark config->stall_ctrl |= TRCSTALLCTLR_INSTPRIORITY;
408a77de263SMathieu Poirier else
409b5bc16abSJames Clark config->stall_ctrl &= ~TRCSTALLCTLR_INSTPRIORITY;
410a77de263SMathieu Poirier
411a77de263SMathieu Poirier /* bit[13], Trace overflow prevention bit */
41254ff892bSMathieu Poirier if ((config->mode & ETM_MODE_NOOVERFLOW) &&
413a77de263SMathieu Poirier (drvdata->nooverflow == true))
414b5bc16abSJames Clark config->stall_ctrl |= TRCSTALLCTLR_NOOVERFLOW;
415a77de263SMathieu Poirier else
416b5bc16abSJames Clark config->stall_ctrl &= ~TRCSTALLCTLR_NOOVERFLOW;
417a77de263SMathieu Poirier
418a77de263SMathieu Poirier /* bit[9] Start/stop logic control bit */
41954ff892bSMathieu Poirier if (config->mode & ETM_MODE_VIEWINST_STARTSTOP)
4206ba7f2bcSJames Clark config->vinst_ctrl |= TRCVICTLR_SSSTATUS;
421a77de263SMathieu Poirier else
4226ba7f2bcSJames Clark config->vinst_ctrl &= ~TRCVICTLR_SSSTATUS;
423a77de263SMathieu Poirier
424a77de263SMathieu Poirier /* bit[10], Whether a trace unit must trace a Reset exception */
42554ff892bSMathieu Poirier if (config->mode & ETM_MODE_TRACE_RESET)
4266ba7f2bcSJames Clark config->vinst_ctrl |= TRCVICTLR_TRCRESET;
427a77de263SMathieu Poirier else
4286ba7f2bcSJames Clark config->vinst_ctrl &= ~TRCVICTLR_TRCRESET;
429a77de263SMathieu Poirier
430a77de263SMathieu Poirier /* bit[11], Whether a trace unit must trace a system error exception */
43154ff892bSMathieu Poirier if ((config->mode & ETM_MODE_TRACE_ERR) &&
432a77de263SMathieu Poirier (drvdata->trc_error == true))
4336ba7f2bcSJames Clark config->vinst_ctrl |= TRCVICTLR_TRCERR;
434a77de263SMathieu Poirier else
4356ba7f2bcSJames Clark config->vinst_ctrl &= ~TRCVICTLR_TRCERR;
436a77de263SMathieu Poirier
4374f6fce54SMathieu Poirier if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER))
4384f6fce54SMathieu Poirier etm4_config_trace_mode(config);
4394f6fce54SMathieu Poirier
440a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
44154ff892bSMathieu Poirier
442a77de263SMathieu Poirier return size;
443a77de263SMathieu Poirier }
444a77de263SMathieu Poirier static DEVICE_ATTR_RW(mode);
445a77de263SMathieu Poirier
pe_show(struct device * dev,struct device_attribute * attr,char * buf)446a77de263SMathieu Poirier static ssize_t pe_show(struct device *dev,
447a77de263SMathieu Poirier struct device_attribute *attr,
448a77de263SMathieu Poirier char *buf)
449a77de263SMathieu Poirier {
450a77de263SMathieu Poirier unsigned long val;
451a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
45254ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
453a77de263SMathieu Poirier
45454ff892bSMathieu Poirier val = config->pe_sel;
455a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
456a77de263SMathieu Poirier }
457a77de263SMathieu Poirier
pe_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)458a77de263SMathieu Poirier static ssize_t pe_store(struct device *dev,
459a77de263SMathieu Poirier struct device_attribute *attr,
460a77de263SMathieu Poirier const char *buf, size_t size)
461a77de263SMathieu Poirier {
462a77de263SMathieu Poirier unsigned long val;
463a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
46454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
465a77de263SMathieu Poirier
466a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
467a77de263SMathieu Poirier return -EINVAL;
468a77de263SMathieu Poirier
469a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
470a77de263SMathieu Poirier if (val > drvdata->nr_pe) {
471a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
472a77de263SMathieu Poirier return -EINVAL;
473a77de263SMathieu Poirier }
474a77de263SMathieu Poirier
47554ff892bSMathieu Poirier config->pe_sel = val;
476a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
477a77de263SMathieu Poirier return size;
478a77de263SMathieu Poirier }
479a77de263SMathieu Poirier static DEVICE_ATTR_RW(pe);
480a77de263SMathieu Poirier
event_show(struct device * dev,struct device_attribute * attr,char * buf)481a77de263SMathieu Poirier static ssize_t event_show(struct device *dev,
482a77de263SMathieu Poirier struct device_attribute *attr,
483a77de263SMathieu Poirier char *buf)
484a77de263SMathieu Poirier {
485a77de263SMathieu Poirier unsigned long val;
486a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
48754ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
488a77de263SMathieu Poirier
48954ff892bSMathieu Poirier val = config->eventctrl0;
490a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
491a77de263SMathieu Poirier }
492a77de263SMathieu Poirier
event_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)493a77de263SMathieu Poirier static ssize_t event_store(struct device *dev,
494a77de263SMathieu Poirier struct device_attribute *attr,
495a77de263SMathieu Poirier const char *buf, size_t size)
496a77de263SMathieu Poirier {
497a77de263SMathieu Poirier unsigned long val;
498a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
49954ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
500a77de263SMathieu Poirier
501a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
502a77de263SMathieu Poirier return -EINVAL;
503a77de263SMathieu Poirier
504a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
505a77de263SMathieu Poirier switch (drvdata->nr_event) {
506a77de263SMathieu Poirier case 0x0:
507a77de263SMathieu Poirier /* EVENT0, bits[7:0] */
50854ff892bSMathieu Poirier config->eventctrl0 = val & 0xFF;
509a77de263SMathieu Poirier break;
510a77de263SMathieu Poirier case 0x1:
511a77de263SMathieu Poirier /* EVENT1, bits[15:8] */
51254ff892bSMathieu Poirier config->eventctrl0 = val & 0xFFFF;
513a77de263SMathieu Poirier break;
514a77de263SMathieu Poirier case 0x2:
515a77de263SMathieu Poirier /* EVENT2, bits[23:16] */
51654ff892bSMathieu Poirier config->eventctrl0 = val & 0xFFFFFF;
517a77de263SMathieu Poirier break;
518a77de263SMathieu Poirier case 0x3:
519a77de263SMathieu Poirier /* EVENT3, bits[31:24] */
52054ff892bSMathieu Poirier config->eventctrl0 = val;
521a77de263SMathieu Poirier break;
522a77de263SMathieu Poirier default:
523a77de263SMathieu Poirier break;
524a77de263SMathieu Poirier }
525a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
526a77de263SMathieu Poirier return size;
527a77de263SMathieu Poirier }
528a77de263SMathieu Poirier static DEVICE_ATTR_RW(event);
529a77de263SMathieu Poirier
event_instren_show(struct device * dev,struct device_attribute * attr,char * buf)530a77de263SMathieu Poirier static ssize_t event_instren_show(struct device *dev,
531a77de263SMathieu Poirier struct device_attribute *attr,
532a77de263SMathieu Poirier char *buf)
533a77de263SMathieu Poirier {
534a77de263SMathieu Poirier unsigned long val;
535a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
53654ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
537a77de263SMathieu Poirier
538eeae6dddSJames Clark val = FIELD_GET(TRCEVENTCTL1R_INSTEN_MASK, config->eventctrl1);
539a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
540a77de263SMathieu Poirier }
541a77de263SMathieu Poirier
event_instren_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)542a77de263SMathieu Poirier static ssize_t event_instren_store(struct device *dev,
543a77de263SMathieu Poirier struct device_attribute *attr,
544a77de263SMathieu Poirier const char *buf, size_t size)
545a77de263SMathieu Poirier {
546a77de263SMathieu Poirier unsigned long val;
547a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
54854ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
549a77de263SMathieu Poirier
550a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
551a77de263SMathieu Poirier return -EINVAL;
552a77de263SMathieu Poirier
553a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
554a77de263SMathieu Poirier /* start by clearing all instruction event enable bits */
555eeae6dddSJames Clark config->eventctrl1 &= ~TRCEVENTCTL1R_INSTEN_MASK;
556a77de263SMathieu Poirier switch (drvdata->nr_event) {
557a77de263SMathieu Poirier case 0x0:
558a77de263SMathieu Poirier /* generate Event element for event 1 */
559eeae6dddSJames Clark config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_1;
560a77de263SMathieu Poirier break;
561a77de263SMathieu Poirier case 0x1:
562a77de263SMathieu Poirier /* generate Event element for event 1 and 2 */
563eeae6dddSJames Clark config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 | TRCEVENTCTL1R_INSTEN_1);
564a77de263SMathieu Poirier break;
565a77de263SMathieu Poirier case 0x2:
566a77de263SMathieu Poirier /* generate Event element for event 1, 2 and 3 */
567eeae6dddSJames Clark config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
568eeae6dddSJames Clark TRCEVENTCTL1R_INSTEN_1 |
569eeae6dddSJames Clark TRCEVENTCTL1R_INSTEN_2);
570a77de263SMathieu Poirier break;
571a77de263SMathieu Poirier case 0x3:
572a77de263SMathieu Poirier /* generate Event element for all 4 events */
573eeae6dddSJames Clark config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
574eeae6dddSJames Clark TRCEVENTCTL1R_INSTEN_1 |
575eeae6dddSJames Clark TRCEVENTCTL1R_INSTEN_2 |
576eeae6dddSJames Clark TRCEVENTCTL1R_INSTEN_3);
577a77de263SMathieu Poirier break;
578a77de263SMathieu Poirier default:
579a77de263SMathieu Poirier break;
580a77de263SMathieu Poirier }
581a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
582a77de263SMathieu Poirier return size;
583a77de263SMathieu Poirier }
584a77de263SMathieu Poirier static DEVICE_ATTR_RW(event_instren);
585a77de263SMathieu Poirier
event_ts_show(struct device * dev,struct device_attribute * attr,char * buf)586a77de263SMathieu Poirier static ssize_t event_ts_show(struct device *dev,
587a77de263SMathieu Poirier struct device_attribute *attr,
588a77de263SMathieu Poirier char *buf)
589a77de263SMathieu Poirier {
590a77de263SMathieu Poirier unsigned long val;
591a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
59254ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
593a77de263SMathieu Poirier
59454ff892bSMathieu Poirier val = config->ts_ctrl;
595a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
596a77de263SMathieu Poirier }
597a77de263SMathieu Poirier
event_ts_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)598a77de263SMathieu Poirier static ssize_t event_ts_store(struct device *dev,
599a77de263SMathieu Poirier struct device_attribute *attr,
600a77de263SMathieu Poirier const char *buf, size_t size)
601a77de263SMathieu Poirier {
602a77de263SMathieu Poirier unsigned long val;
603a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
60454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
605a77de263SMathieu Poirier
606a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
607a77de263SMathieu Poirier return -EINVAL;
608a77de263SMathieu Poirier if (!drvdata->ts_size)
609a77de263SMathieu Poirier return -EINVAL;
610a77de263SMathieu Poirier
61154ff892bSMathieu Poirier config->ts_ctrl = val & ETMv4_EVENT_MASK;
612a77de263SMathieu Poirier return size;
613a77de263SMathieu Poirier }
614a77de263SMathieu Poirier static DEVICE_ATTR_RW(event_ts);
615a77de263SMathieu Poirier
syncfreq_show(struct device * dev,struct device_attribute * attr,char * buf)616a77de263SMathieu Poirier static ssize_t syncfreq_show(struct device *dev,
617a77de263SMathieu Poirier struct device_attribute *attr,
618a77de263SMathieu Poirier char *buf)
619a77de263SMathieu Poirier {
620a77de263SMathieu Poirier unsigned long val;
621a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
62254ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
623a77de263SMathieu Poirier
62454ff892bSMathieu Poirier val = config->syncfreq;
625a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
626a77de263SMathieu Poirier }
627a77de263SMathieu Poirier
syncfreq_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)628a77de263SMathieu Poirier static ssize_t syncfreq_store(struct device *dev,
629a77de263SMathieu Poirier struct device_attribute *attr,
630a77de263SMathieu Poirier const char *buf, size_t size)
631a77de263SMathieu Poirier {
632a77de263SMathieu Poirier unsigned long val;
633a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
63454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
635a77de263SMathieu Poirier
636a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
637a77de263SMathieu Poirier return -EINVAL;
638a77de263SMathieu Poirier if (drvdata->syncpr == true)
639a77de263SMathieu Poirier return -EINVAL;
640a77de263SMathieu Poirier
64154ff892bSMathieu Poirier config->syncfreq = val & ETMv4_SYNC_MASK;
642a77de263SMathieu Poirier return size;
643a77de263SMathieu Poirier }
644a77de263SMathieu Poirier static DEVICE_ATTR_RW(syncfreq);
645a77de263SMathieu Poirier
cyc_threshold_show(struct device * dev,struct device_attribute * attr,char * buf)646a77de263SMathieu Poirier static ssize_t cyc_threshold_show(struct device *dev,
647a77de263SMathieu Poirier struct device_attribute *attr,
648a77de263SMathieu Poirier char *buf)
649a77de263SMathieu Poirier {
650a77de263SMathieu Poirier unsigned long val;
651a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
65254ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
653a77de263SMathieu Poirier
65454ff892bSMathieu Poirier val = config->ccctlr;
655a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
656a77de263SMathieu Poirier }
657a77de263SMathieu Poirier
cyc_threshold_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)658a77de263SMathieu Poirier static ssize_t cyc_threshold_store(struct device *dev,
659a77de263SMathieu Poirier struct device_attribute *attr,
660a77de263SMathieu Poirier const char *buf, size_t size)
661a77de263SMathieu Poirier {
662a77de263SMathieu Poirier unsigned long val;
663a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
66454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
665a77de263SMathieu Poirier
666a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
667a77de263SMathieu Poirier return -EINVAL;
6682fe6899eSMike Leach
6692fe6899eSMike Leach /* mask off max threshold before checking min value */
6702fe6899eSMike Leach val &= ETM_CYC_THRESHOLD_MASK;
671a77de263SMathieu Poirier if (val < drvdata->ccitmin)
672a77de263SMathieu Poirier return -EINVAL;
673a77de263SMathieu Poirier
6742fe6899eSMike Leach config->ccctlr = val;
675a77de263SMathieu Poirier return size;
676a77de263SMathieu Poirier }
677a77de263SMathieu Poirier static DEVICE_ATTR_RW(cyc_threshold);
678a77de263SMathieu Poirier
bb_ctrl_show(struct device * dev,struct device_attribute * attr,char * buf)679a77de263SMathieu Poirier static ssize_t bb_ctrl_show(struct device *dev,
680a77de263SMathieu Poirier struct device_attribute *attr,
681a77de263SMathieu Poirier char *buf)
682a77de263SMathieu Poirier {
683a77de263SMathieu Poirier unsigned long val;
684a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
68554ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
686a77de263SMathieu Poirier
68754ff892bSMathieu Poirier val = config->bb_ctrl;
688a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
689a77de263SMathieu Poirier }
690a77de263SMathieu Poirier
bb_ctrl_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)691a77de263SMathieu Poirier static ssize_t bb_ctrl_store(struct device *dev,
692a77de263SMathieu Poirier struct device_attribute *attr,
693a77de263SMathieu Poirier const char *buf, size_t size)
694a77de263SMathieu Poirier {
695a77de263SMathieu Poirier unsigned long val;
696a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
69754ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
698a77de263SMathieu Poirier
699a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
700a77de263SMathieu Poirier return -EINVAL;
701a77de263SMathieu Poirier if (drvdata->trcbb == false)
702a77de263SMathieu Poirier return -EINVAL;
703a77de263SMathieu Poirier if (!drvdata->nr_addr_cmp)
704a77de263SMathieu Poirier return -EINVAL;
7052fe6899eSMike Leach
706a77de263SMathieu Poirier /*
7072fe6899eSMike Leach * Bit[8] controls include(1) / exclude(0), bits[0-7] select
7082fe6899eSMike Leach * individual range comparators. If include then at least 1
7092fe6899eSMike Leach * range must be selected.
710a77de263SMathieu Poirier */
71167493ca4SJames Clark if ((val & TRCBBCTLR_MODE) && (FIELD_GET(TRCBBCTLR_RANGE_MASK, val) == 0))
712a77de263SMathieu Poirier return -EINVAL;
713a77de263SMathieu Poirier
71467493ca4SJames Clark config->bb_ctrl = val & (TRCBBCTLR_MODE | TRCBBCTLR_RANGE_MASK);
715a77de263SMathieu Poirier return size;
716a77de263SMathieu Poirier }
717a77de263SMathieu Poirier static DEVICE_ATTR_RW(bb_ctrl);
718a77de263SMathieu Poirier
event_vinst_show(struct device * dev,struct device_attribute * attr,char * buf)719a77de263SMathieu Poirier static ssize_t event_vinst_show(struct device *dev,
720a77de263SMathieu Poirier struct device_attribute *attr,
721a77de263SMathieu Poirier char *buf)
722a77de263SMathieu Poirier {
723a77de263SMathieu Poirier unsigned long val;
724a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
72554ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
726a77de263SMathieu Poirier
7276ba7f2bcSJames Clark val = FIELD_GET(TRCVICTLR_EVENT_MASK, config->vinst_ctrl);
728a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
729a77de263SMathieu Poirier }
730a77de263SMathieu Poirier
event_vinst_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)731a77de263SMathieu Poirier static ssize_t event_vinst_store(struct device *dev,
732a77de263SMathieu Poirier struct device_attribute *attr,
733a77de263SMathieu Poirier const char *buf, size_t size)
734a77de263SMathieu Poirier {
735a77de263SMathieu Poirier unsigned long val;
736a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
73754ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
738a77de263SMathieu Poirier
739a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
740a77de263SMathieu Poirier return -EINVAL;
741a77de263SMathieu Poirier
742a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
7436ba7f2bcSJames Clark val &= TRCVICTLR_EVENT_MASK >> __bf_shf(TRCVICTLR_EVENT_MASK);
7446ba7f2bcSJames Clark config->vinst_ctrl &= ~TRCVICTLR_EVENT_MASK;
7456ba7f2bcSJames Clark config->vinst_ctrl |= FIELD_PREP(TRCVICTLR_EVENT_MASK, val);
746a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
747a77de263SMathieu Poirier return size;
748a77de263SMathieu Poirier }
749a77de263SMathieu Poirier static DEVICE_ATTR_RW(event_vinst);
750a77de263SMathieu Poirier
s_exlevel_vinst_show(struct device * dev,struct device_attribute * attr,char * buf)751a77de263SMathieu Poirier static ssize_t s_exlevel_vinst_show(struct device *dev,
752a77de263SMathieu Poirier struct device_attribute *attr,
753a77de263SMathieu Poirier char *buf)
754a77de263SMathieu Poirier {
755a77de263SMathieu Poirier unsigned long val;
756a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
75754ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
758a77de263SMathieu Poirier
7596ba7f2bcSJames Clark val = FIELD_GET(TRCVICTLR_EXLEVEL_S_MASK, config->vinst_ctrl);
760a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
761a77de263SMathieu Poirier }
762a77de263SMathieu Poirier
s_exlevel_vinst_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)763a77de263SMathieu Poirier static ssize_t s_exlevel_vinst_store(struct device *dev,
764a77de263SMathieu Poirier struct device_attribute *attr,
765a77de263SMathieu Poirier const char *buf, size_t size)
766a77de263SMathieu Poirier {
767a77de263SMathieu Poirier unsigned long val;
768a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
76954ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
770a77de263SMathieu Poirier
771a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
772a77de263SMathieu Poirier return -EINVAL;
773a77de263SMathieu Poirier
774a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
775057f2c57SMike Leach /* clear all EXLEVEL_S bits */
7766ba7f2bcSJames Clark config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_S_MASK;
777a77de263SMathieu Poirier /* enable instruction tracing for corresponding exception level */
778a77de263SMathieu Poirier val &= drvdata->s_ex_level;
7796ba7f2bcSJames Clark config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_S_MASK);
780a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
781a77de263SMathieu Poirier return size;
782a77de263SMathieu Poirier }
783a77de263SMathieu Poirier static DEVICE_ATTR_RW(s_exlevel_vinst);
784a77de263SMathieu Poirier
ns_exlevel_vinst_show(struct device * dev,struct device_attribute * attr,char * buf)785a77de263SMathieu Poirier static ssize_t ns_exlevel_vinst_show(struct device *dev,
786a77de263SMathieu Poirier struct device_attribute *attr,
787a77de263SMathieu Poirier char *buf)
788a77de263SMathieu Poirier {
789a77de263SMathieu Poirier unsigned long val;
790a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
79154ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
792a77de263SMathieu Poirier
793a77de263SMathieu Poirier /* EXLEVEL_NS, bits[23:20] */
7946ba7f2bcSJames Clark val = FIELD_GET(TRCVICTLR_EXLEVEL_NS_MASK, config->vinst_ctrl);
795a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
796a77de263SMathieu Poirier }
797a77de263SMathieu Poirier
ns_exlevel_vinst_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)798a77de263SMathieu Poirier static ssize_t ns_exlevel_vinst_store(struct device *dev,
799a77de263SMathieu Poirier struct device_attribute *attr,
800a77de263SMathieu Poirier const char *buf, size_t size)
801a77de263SMathieu Poirier {
802a77de263SMathieu Poirier unsigned long val;
803a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
80454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
805a77de263SMathieu Poirier
806a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
807a77de263SMathieu Poirier return -EINVAL;
808a77de263SMathieu Poirier
809a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
810057f2c57SMike Leach /* clear EXLEVEL_NS bits */
8116ba7f2bcSJames Clark config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_NS_MASK;
812a77de263SMathieu Poirier /* enable instruction tracing for corresponding exception level */
813a77de263SMathieu Poirier val &= drvdata->ns_ex_level;
8146ba7f2bcSJames Clark config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_NS_MASK);
815a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
816a77de263SMathieu Poirier return size;
817a77de263SMathieu Poirier }
818a77de263SMathieu Poirier static DEVICE_ATTR_RW(ns_exlevel_vinst);
819a77de263SMathieu Poirier
addr_idx_show(struct device * dev,struct device_attribute * attr,char * buf)820a77de263SMathieu Poirier static ssize_t addr_idx_show(struct device *dev,
821a77de263SMathieu Poirier struct device_attribute *attr,
822a77de263SMathieu Poirier char *buf)
823a77de263SMathieu Poirier {
824a77de263SMathieu Poirier unsigned long val;
825a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
82654ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
827a77de263SMathieu Poirier
82854ff892bSMathieu Poirier val = config->addr_idx;
829a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
830a77de263SMathieu Poirier }
831a77de263SMathieu Poirier
addr_idx_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)832a77de263SMathieu Poirier static ssize_t addr_idx_store(struct device *dev,
833a77de263SMathieu Poirier struct device_attribute *attr,
834a77de263SMathieu Poirier const char *buf, size_t size)
835a77de263SMathieu Poirier {
836a77de263SMathieu Poirier unsigned long val;
837a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
83854ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
839a77de263SMathieu Poirier
840a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
841a77de263SMathieu Poirier return -EINVAL;
842a77de263SMathieu Poirier if (val >= drvdata->nr_addr_cmp * 2)
843a77de263SMathieu Poirier return -EINVAL;
844a77de263SMathieu Poirier
845a77de263SMathieu Poirier /*
846a77de263SMathieu Poirier * Use spinlock to ensure index doesn't change while it gets
847a77de263SMathieu Poirier * dereferenced multiple times within a spinlock block elsewhere.
848a77de263SMathieu Poirier */
849a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
85054ff892bSMathieu Poirier config->addr_idx = val;
851a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
852a77de263SMathieu Poirier return size;
853a77de263SMathieu Poirier }
854a77de263SMathieu Poirier static DEVICE_ATTR_RW(addr_idx);
855a77de263SMathieu Poirier
addr_instdatatype_show(struct device * dev,struct device_attribute * attr,char * buf)856a77de263SMathieu Poirier static ssize_t addr_instdatatype_show(struct device *dev,
857a77de263SMathieu Poirier struct device_attribute *attr,
858a77de263SMathieu Poirier char *buf)
859a77de263SMathieu Poirier {
860a77de263SMathieu Poirier ssize_t len;
861a77de263SMathieu Poirier u8 val, idx;
862a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
86354ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
864a77de263SMathieu Poirier
865a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
86654ff892bSMathieu Poirier idx = config->addr_idx;
867f5def772SJames Clark val = FIELD_GET(TRCACATRn_TYPE_MASK, config->addr_acc[idx]);
868a77de263SMathieu Poirier len = scnprintf(buf, PAGE_SIZE, "%s\n",
869f5def772SJames Clark val == TRCACATRn_TYPE_ADDR ? "instr" :
870f5def772SJames Clark (val == TRCACATRn_TYPE_DATA_LOAD_ADDR ? "data_load" :
871f5def772SJames Clark (val == TRCACATRn_TYPE_DATA_STORE_ADDR ? "data_store" :
872a77de263SMathieu Poirier "data_load_store")));
873a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
874a77de263SMathieu Poirier return len;
875a77de263SMathieu Poirier }
876a77de263SMathieu Poirier
addr_instdatatype_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)877a77de263SMathieu Poirier static ssize_t addr_instdatatype_store(struct device *dev,
878a77de263SMathieu Poirier struct device_attribute *attr,
879a77de263SMathieu Poirier const char *buf, size_t size)
880a77de263SMathieu Poirier {
881a77de263SMathieu Poirier u8 idx;
882a77de263SMathieu Poirier char str[20] = "";
883a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
88454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
885a77de263SMathieu Poirier
886a77de263SMathieu Poirier if (strlen(buf) >= 20)
887a77de263SMathieu Poirier return -EINVAL;
888a77de263SMathieu Poirier if (sscanf(buf, "%s", str) != 1)
889a77de263SMathieu Poirier return -EINVAL;
890a77de263SMathieu Poirier
891a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
89254ff892bSMathieu Poirier idx = config->addr_idx;
893a77de263SMathieu Poirier if (!strcmp(str, "instr"))
894a77de263SMathieu Poirier /* TYPE, bits[1:0] */
895f5def772SJames Clark config->addr_acc[idx] &= ~TRCACATRn_TYPE_MASK;
896a77de263SMathieu Poirier
897a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
898a77de263SMathieu Poirier return size;
899a77de263SMathieu Poirier }
900a77de263SMathieu Poirier static DEVICE_ATTR_RW(addr_instdatatype);
901a77de263SMathieu Poirier
addr_single_show(struct device * dev,struct device_attribute * attr,char * buf)902a77de263SMathieu Poirier static ssize_t addr_single_show(struct device *dev,
903a77de263SMathieu Poirier struct device_attribute *attr,
904a77de263SMathieu Poirier char *buf)
905a77de263SMathieu Poirier {
906a77de263SMathieu Poirier u8 idx;
907a77de263SMathieu Poirier unsigned long val;
908a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
90954ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
910a77de263SMathieu Poirier
91154ff892bSMathieu Poirier idx = config->addr_idx;
912a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
91354ff892bSMathieu Poirier if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
91454ff892bSMathieu Poirier config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
915a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
916a77de263SMathieu Poirier return -EPERM;
917a77de263SMathieu Poirier }
91854ff892bSMathieu Poirier val = (unsigned long)config->addr_val[idx];
919a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
920a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
921a77de263SMathieu Poirier }
922a77de263SMathieu Poirier
addr_single_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)923a77de263SMathieu Poirier static ssize_t addr_single_store(struct device *dev,
924a77de263SMathieu Poirier struct device_attribute *attr,
925a77de263SMathieu Poirier const char *buf, size_t size)
926a77de263SMathieu Poirier {
927a77de263SMathieu Poirier u8 idx;
928a77de263SMathieu Poirier unsigned long val;
929a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
93054ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
931a77de263SMathieu Poirier
932a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
933a77de263SMathieu Poirier return -EINVAL;
934a77de263SMathieu Poirier
935a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
93654ff892bSMathieu Poirier idx = config->addr_idx;
93754ff892bSMathieu Poirier if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
93854ff892bSMathieu Poirier config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
939a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
940a77de263SMathieu Poirier return -EPERM;
941a77de263SMathieu Poirier }
942a77de263SMathieu Poirier
94354ff892bSMathieu Poirier config->addr_val[idx] = (u64)val;
94454ff892bSMathieu Poirier config->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
945a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
946a77de263SMathieu Poirier return size;
947a77de263SMathieu Poirier }
948a77de263SMathieu Poirier static DEVICE_ATTR_RW(addr_single);
949a77de263SMathieu Poirier
addr_range_show(struct device * dev,struct device_attribute * attr,char * buf)950a77de263SMathieu Poirier static ssize_t addr_range_show(struct device *dev,
951a77de263SMathieu Poirier struct device_attribute *attr,
952a77de263SMathieu Poirier char *buf)
953a77de263SMathieu Poirier {
954a77de263SMathieu Poirier u8 idx;
955a77de263SMathieu Poirier unsigned long val1, val2;
956a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
95754ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
958a77de263SMathieu Poirier
959a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
96054ff892bSMathieu Poirier idx = config->addr_idx;
961a77de263SMathieu Poirier if (idx % 2 != 0) {
962a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
963a77de263SMathieu Poirier return -EPERM;
964a77de263SMathieu Poirier }
96554ff892bSMathieu Poirier if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
96654ff892bSMathieu Poirier config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
96754ff892bSMathieu Poirier (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
96854ff892bSMathieu Poirier config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
969a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
970a77de263SMathieu Poirier return -EPERM;
971a77de263SMathieu Poirier }
972a77de263SMathieu Poirier
97354ff892bSMathieu Poirier val1 = (unsigned long)config->addr_val[idx];
97454ff892bSMathieu Poirier val2 = (unsigned long)config->addr_val[idx + 1];
975a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
976a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
977a77de263SMathieu Poirier }
978a77de263SMathieu Poirier
addr_range_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)979a77de263SMathieu Poirier static ssize_t addr_range_store(struct device *dev,
980a77de263SMathieu Poirier struct device_attribute *attr,
981a77de263SMathieu Poirier const char *buf, size_t size)
982a77de263SMathieu Poirier {
983a77de263SMathieu Poirier u8 idx;
984a77de263SMathieu Poirier unsigned long val1, val2;
985a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
98654ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
987c2431fedSMike Leach int elements, exclude;
988a77de263SMathieu Poirier
989c2431fedSMike Leach elements = sscanf(buf, "%lx %lx %x", &val1, &val2, &exclude);
990c2431fedSMike Leach
991c2431fedSMike Leach /* exclude is optional, but need at least two parameter */
992c2431fedSMike Leach if (elements < 2)
993a77de263SMathieu Poirier return -EINVAL;
994a77de263SMathieu Poirier /* lower address comparator cannot have a higher address value */
995a77de263SMathieu Poirier if (val1 > val2)
996a77de263SMathieu Poirier return -EINVAL;
997a77de263SMathieu Poirier
998a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
99954ff892bSMathieu Poirier idx = config->addr_idx;
1000a77de263SMathieu Poirier if (idx % 2 != 0) {
1001a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1002a77de263SMathieu Poirier return -EPERM;
1003a77de263SMathieu Poirier }
1004a77de263SMathieu Poirier
100554ff892bSMathieu Poirier if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
100654ff892bSMathieu Poirier config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
100754ff892bSMathieu Poirier (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
100854ff892bSMathieu Poirier config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
1009a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1010a77de263SMathieu Poirier return -EPERM;
1011a77de263SMathieu Poirier }
1012a77de263SMathieu Poirier
101354ff892bSMathieu Poirier config->addr_val[idx] = (u64)val1;
101454ff892bSMathieu Poirier config->addr_type[idx] = ETM_ADDR_TYPE_RANGE;
101554ff892bSMathieu Poirier config->addr_val[idx + 1] = (u64)val2;
101654ff892bSMathieu Poirier config->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
1017a77de263SMathieu Poirier /*
1018a77de263SMathieu Poirier * Program include or exclude control bits for vinst or vdata
1019a77de263SMathieu Poirier * whenever we change addr comparators to ETM_ADDR_TYPE_RANGE
1020c2431fedSMike Leach * use supplied value, or default to bit set in 'mode'
1021a77de263SMathieu Poirier */
1022c2431fedSMike Leach if (elements != 3)
1023c2431fedSMike Leach exclude = config->mode & ETM_MODE_EXCLUDE;
1024c2431fedSMike Leach etm4_set_mode_exclude(drvdata, exclude ? true : false);
1025a77de263SMathieu Poirier
1026a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1027a77de263SMathieu Poirier return size;
1028a77de263SMathieu Poirier }
1029a77de263SMathieu Poirier static DEVICE_ATTR_RW(addr_range);
1030a77de263SMathieu Poirier
addr_start_show(struct device * dev,struct device_attribute * attr,char * buf)1031a77de263SMathieu Poirier static ssize_t addr_start_show(struct device *dev,
1032a77de263SMathieu Poirier struct device_attribute *attr,
1033a77de263SMathieu Poirier char *buf)
1034a77de263SMathieu Poirier {
1035a77de263SMathieu Poirier u8 idx;
1036a77de263SMathieu Poirier unsigned long val;
1037a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
103854ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1039a77de263SMathieu Poirier
1040a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
104154ff892bSMathieu Poirier idx = config->addr_idx;
1042a77de263SMathieu Poirier
104354ff892bSMathieu Poirier if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
104454ff892bSMathieu Poirier config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
1045a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1046a77de263SMathieu Poirier return -EPERM;
1047a77de263SMathieu Poirier }
1048a77de263SMathieu Poirier
104954ff892bSMathieu Poirier val = (unsigned long)config->addr_val[idx];
1050a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1051a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1052a77de263SMathieu Poirier }
1053a77de263SMathieu Poirier
addr_start_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1054a77de263SMathieu Poirier static ssize_t addr_start_store(struct device *dev,
1055a77de263SMathieu Poirier struct device_attribute *attr,
1056a77de263SMathieu Poirier const char *buf, size_t size)
1057a77de263SMathieu Poirier {
1058a77de263SMathieu Poirier u8 idx;
1059a77de263SMathieu Poirier unsigned long val;
1060a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
106154ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1062a77de263SMathieu Poirier
1063a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1064a77de263SMathieu Poirier return -EINVAL;
1065a77de263SMathieu Poirier
1066a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
106754ff892bSMathieu Poirier idx = config->addr_idx;
1068a77de263SMathieu Poirier if (!drvdata->nr_addr_cmp) {
1069a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1070a77de263SMathieu Poirier return -EINVAL;
1071a77de263SMathieu Poirier }
107254ff892bSMathieu Poirier if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
107354ff892bSMathieu Poirier config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
1074a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1075a77de263SMathieu Poirier return -EPERM;
1076a77de263SMathieu Poirier }
1077a77de263SMathieu Poirier
107854ff892bSMathieu Poirier config->addr_val[idx] = (u64)val;
107954ff892bSMathieu Poirier config->addr_type[idx] = ETM_ADDR_TYPE_START;
108054ff892bSMathieu Poirier config->vissctlr |= BIT(idx);
1081a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1082a77de263SMathieu Poirier return size;
1083a77de263SMathieu Poirier }
1084a77de263SMathieu Poirier static DEVICE_ATTR_RW(addr_start);
1085a77de263SMathieu Poirier
addr_stop_show(struct device * dev,struct device_attribute * attr,char * buf)1086a77de263SMathieu Poirier static ssize_t addr_stop_show(struct device *dev,
1087a77de263SMathieu Poirier struct device_attribute *attr,
1088a77de263SMathieu Poirier char *buf)
1089a77de263SMathieu Poirier {
1090a77de263SMathieu Poirier u8 idx;
1091a77de263SMathieu Poirier unsigned long val;
1092a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
109354ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1094a77de263SMathieu Poirier
1095a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
109654ff892bSMathieu Poirier idx = config->addr_idx;
1097a77de263SMathieu Poirier
109854ff892bSMathieu Poirier if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
109954ff892bSMathieu Poirier config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
1100a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1101a77de263SMathieu Poirier return -EPERM;
1102a77de263SMathieu Poirier }
1103a77de263SMathieu Poirier
110454ff892bSMathieu Poirier val = (unsigned long)config->addr_val[idx];
1105a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1106a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1107a77de263SMathieu Poirier }
1108a77de263SMathieu Poirier
addr_stop_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1109a77de263SMathieu Poirier static ssize_t addr_stop_store(struct device *dev,
1110a77de263SMathieu Poirier struct device_attribute *attr,
1111a77de263SMathieu Poirier const char *buf, size_t size)
1112a77de263SMathieu Poirier {
1113a77de263SMathieu Poirier u8 idx;
1114a77de263SMathieu Poirier unsigned long val;
1115a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
111654ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1117a77de263SMathieu Poirier
1118a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1119a77de263SMathieu Poirier return -EINVAL;
1120a77de263SMathieu Poirier
1121a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
112254ff892bSMathieu Poirier idx = config->addr_idx;
1123a77de263SMathieu Poirier if (!drvdata->nr_addr_cmp) {
1124a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1125a77de263SMathieu Poirier return -EINVAL;
1126a77de263SMathieu Poirier }
112754ff892bSMathieu Poirier if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
112854ff892bSMathieu Poirier config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
1129a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1130a77de263SMathieu Poirier return -EPERM;
1131a77de263SMathieu Poirier }
1132a77de263SMathieu Poirier
113354ff892bSMathieu Poirier config->addr_val[idx] = (u64)val;
113454ff892bSMathieu Poirier config->addr_type[idx] = ETM_ADDR_TYPE_STOP;
113554ff892bSMathieu Poirier config->vissctlr |= BIT(idx + 16);
1136a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1137a77de263SMathieu Poirier return size;
1138a77de263SMathieu Poirier }
1139a77de263SMathieu Poirier static DEVICE_ATTR_RW(addr_stop);
1140a77de263SMathieu Poirier
addr_ctxtype_show(struct device * dev,struct device_attribute * attr,char * buf)1141a77de263SMathieu Poirier static ssize_t addr_ctxtype_show(struct device *dev,
1142a77de263SMathieu Poirier struct device_attribute *attr,
1143a77de263SMathieu Poirier char *buf)
1144a77de263SMathieu Poirier {
1145a77de263SMathieu Poirier ssize_t len;
1146a77de263SMathieu Poirier u8 idx, val;
1147a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
114854ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1149a77de263SMathieu Poirier
1150a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
115154ff892bSMathieu Poirier idx = config->addr_idx;
1152a77de263SMathieu Poirier /* CONTEXTTYPE, bits[3:2] */
1153f5def772SJames Clark val = FIELD_GET(TRCACATRn_CONTEXTTYPE_MASK, config->addr_acc[idx]);
1154a77de263SMathieu Poirier len = scnprintf(buf, PAGE_SIZE, "%s\n", val == ETM_CTX_NONE ? "none" :
1155a77de263SMathieu Poirier (val == ETM_CTX_CTXID ? "ctxid" :
1156a77de263SMathieu Poirier (val == ETM_CTX_VMID ? "vmid" : "all")));
1157a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1158a77de263SMathieu Poirier return len;
1159a77de263SMathieu Poirier }
1160a77de263SMathieu Poirier
addr_ctxtype_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1161a77de263SMathieu Poirier static ssize_t addr_ctxtype_store(struct device *dev,
1162a77de263SMathieu Poirier struct device_attribute *attr,
1163a77de263SMathieu Poirier const char *buf, size_t size)
1164a77de263SMathieu Poirier {
1165a77de263SMathieu Poirier u8 idx;
1166a77de263SMathieu Poirier char str[10] = "";
1167a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
116854ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1169a77de263SMathieu Poirier
1170a77de263SMathieu Poirier if (strlen(buf) >= 10)
1171a77de263SMathieu Poirier return -EINVAL;
1172a77de263SMathieu Poirier if (sscanf(buf, "%s", str) != 1)
1173a77de263SMathieu Poirier return -EINVAL;
1174a77de263SMathieu Poirier
1175a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
117654ff892bSMathieu Poirier idx = config->addr_idx;
1177a77de263SMathieu Poirier if (!strcmp(str, "none"))
1178a77de263SMathieu Poirier /* start by clearing context type bits */
1179f5def772SJames Clark config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_MASK;
1180a77de263SMathieu Poirier else if (!strcmp(str, "ctxid")) {
1181a77de263SMathieu Poirier /* 0b01 The trace unit performs a Context ID */
1182a77de263SMathieu Poirier if (drvdata->numcidc) {
1183f5def772SJames Clark config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_CTXID;
1184f5def772SJames Clark config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_VMID;
1185a77de263SMathieu Poirier }
1186a77de263SMathieu Poirier } else if (!strcmp(str, "vmid")) {
1187a77de263SMathieu Poirier /* 0b10 The trace unit performs a VMID */
1188a77de263SMathieu Poirier if (drvdata->numvmidc) {
1189f5def772SJames Clark config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_CTXID;
1190f5def772SJames Clark config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
1191a77de263SMathieu Poirier }
1192a77de263SMathieu Poirier } else if (!strcmp(str, "all")) {
1193a77de263SMathieu Poirier /*
1194a77de263SMathieu Poirier * 0b11 The trace unit performs a Context ID
1195a77de263SMathieu Poirier * comparison and a VMID
1196a77de263SMathieu Poirier */
1197a77de263SMathieu Poirier if (drvdata->numcidc)
1198f5def772SJames Clark config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_CTXID;
1199a77de263SMathieu Poirier if (drvdata->numvmidc)
1200f5def772SJames Clark config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
1201a77de263SMathieu Poirier }
1202a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1203a77de263SMathieu Poirier return size;
1204a77de263SMathieu Poirier }
1205a77de263SMathieu Poirier static DEVICE_ATTR_RW(addr_ctxtype);
1206a77de263SMathieu Poirier
addr_context_show(struct device * dev,struct device_attribute * attr,char * buf)1207a77de263SMathieu Poirier static ssize_t addr_context_show(struct device *dev,
1208a77de263SMathieu Poirier struct device_attribute *attr,
1209a77de263SMathieu Poirier char *buf)
1210a77de263SMathieu Poirier {
1211a77de263SMathieu Poirier u8 idx;
1212a77de263SMathieu Poirier unsigned long val;
1213a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
121454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1215a77de263SMathieu Poirier
1216a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
121754ff892bSMathieu Poirier idx = config->addr_idx;
1218a77de263SMathieu Poirier /* context ID comparator bits[6:4] */
1219f5def772SJames Clark val = FIELD_GET(TRCACATRn_CONTEXT_MASK, config->addr_acc[idx]);
1220a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1221a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1222a77de263SMathieu Poirier }
1223a77de263SMathieu Poirier
addr_context_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1224a77de263SMathieu Poirier static ssize_t addr_context_store(struct device *dev,
1225a77de263SMathieu Poirier struct device_attribute *attr,
1226a77de263SMathieu Poirier const char *buf, size_t size)
1227a77de263SMathieu Poirier {
1228a77de263SMathieu Poirier u8 idx;
1229a77de263SMathieu Poirier unsigned long val;
1230a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
123154ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1232a77de263SMathieu Poirier
1233a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1234a77de263SMathieu Poirier return -EINVAL;
1235a77de263SMathieu Poirier if ((drvdata->numcidc <= 1) && (drvdata->numvmidc <= 1))
1236a77de263SMathieu Poirier return -EINVAL;
1237a77de263SMathieu Poirier if (val >= (drvdata->numcidc >= drvdata->numvmidc ?
1238a77de263SMathieu Poirier drvdata->numcidc : drvdata->numvmidc))
1239a77de263SMathieu Poirier return -EINVAL;
1240a77de263SMathieu Poirier
1241a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
124254ff892bSMathieu Poirier idx = config->addr_idx;
1243a77de263SMathieu Poirier /* clear context ID comparator bits[6:4] */
1244f5def772SJames Clark config->addr_acc[idx] &= ~TRCACATRn_CONTEXT_MASK;
1245f5def772SJames Clark config->addr_acc[idx] |= val << __bf_shf(TRCACATRn_CONTEXT_MASK);
1246a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1247a77de263SMathieu Poirier return size;
1248a77de263SMathieu Poirier }
1249a77de263SMathieu Poirier static DEVICE_ATTR_RW(addr_context);
1250a77de263SMathieu Poirier
addr_exlevel_s_ns_show(struct device * dev,struct device_attribute * attr,char * buf)125175198a7dSMike Leach static ssize_t addr_exlevel_s_ns_show(struct device *dev,
125275198a7dSMike Leach struct device_attribute *attr,
125375198a7dSMike Leach char *buf)
125475198a7dSMike Leach {
125575198a7dSMike Leach u8 idx;
125675198a7dSMike Leach unsigned long val;
125775198a7dSMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
125875198a7dSMike Leach struct etmv4_config *config = &drvdata->config;
125975198a7dSMike Leach
126075198a7dSMike Leach spin_lock(&drvdata->spinlock);
126175198a7dSMike Leach idx = config->addr_idx;
1262f5def772SJames Clark val = FIELD_GET(TRCACATRn_EXLEVEL_MASK, config->addr_acc[idx]);
126375198a7dSMike Leach spin_unlock(&drvdata->spinlock);
126475198a7dSMike Leach return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
126575198a7dSMike Leach }
126675198a7dSMike Leach
addr_exlevel_s_ns_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)126775198a7dSMike Leach static ssize_t addr_exlevel_s_ns_store(struct device *dev,
126875198a7dSMike Leach struct device_attribute *attr,
126975198a7dSMike Leach const char *buf, size_t size)
127075198a7dSMike Leach {
127175198a7dSMike Leach u8 idx;
127275198a7dSMike Leach unsigned long val;
127375198a7dSMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
127475198a7dSMike Leach struct etmv4_config *config = &drvdata->config;
127575198a7dSMike Leach
127675198a7dSMike Leach if (kstrtoul(buf, 0, &val))
127775198a7dSMike Leach return -EINVAL;
127875198a7dSMike Leach
1279f5def772SJames Clark if (val & ~(TRCACATRn_EXLEVEL_MASK >> __bf_shf(TRCACATRn_EXLEVEL_MASK)))
128075198a7dSMike Leach return -EINVAL;
128175198a7dSMike Leach
128275198a7dSMike Leach spin_lock(&drvdata->spinlock);
128375198a7dSMike Leach idx = config->addr_idx;
128475198a7dSMike Leach /* clear Exlevel_ns & Exlevel_s bits[14:12, 11:8], bit[15] is res0 */
1285f5def772SJames Clark config->addr_acc[idx] &= ~TRCACATRn_EXLEVEL_MASK;
1286f5def772SJames Clark config->addr_acc[idx] |= val << __bf_shf(TRCACATRn_EXLEVEL_MASK);
128775198a7dSMike Leach spin_unlock(&drvdata->spinlock);
128875198a7dSMike Leach return size;
128975198a7dSMike Leach }
129075198a7dSMike Leach static DEVICE_ATTR_RW(addr_exlevel_s_ns);
129175198a7dSMike Leach
1292a578427dSMike Leach static const char * const addr_type_names[] = {
1293a578427dSMike Leach "unused",
1294a578427dSMike Leach "single",
1295a578427dSMike Leach "range",
1296a578427dSMike Leach "start",
1297a578427dSMike Leach "stop"
1298a578427dSMike Leach };
1299a578427dSMike Leach
addr_cmp_view_show(struct device * dev,struct device_attribute * attr,char * buf)1300a578427dSMike Leach static ssize_t addr_cmp_view_show(struct device *dev,
1301a578427dSMike Leach struct device_attribute *attr, char *buf)
1302a578427dSMike Leach {
1303a578427dSMike Leach u8 idx, addr_type;
1304a578427dSMike Leach unsigned long addr_v, addr_v2, addr_ctrl;
1305a578427dSMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
1306a578427dSMike Leach struct etmv4_config *config = &drvdata->config;
1307a578427dSMike Leach int size = 0;
1308a578427dSMike Leach bool exclude = false;
1309a578427dSMike Leach
1310a578427dSMike Leach spin_lock(&drvdata->spinlock);
1311a578427dSMike Leach idx = config->addr_idx;
1312a578427dSMike Leach addr_v = config->addr_val[idx];
1313a578427dSMike Leach addr_ctrl = config->addr_acc[idx];
1314a578427dSMike Leach addr_type = config->addr_type[idx];
1315a578427dSMike Leach if (addr_type == ETM_ADDR_TYPE_RANGE) {
1316a578427dSMike Leach if (idx & 0x1) {
1317a578427dSMike Leach idx -= 1;
1318a578427dSMike Leach addr_v2 = addr_v;
1319a578427dSMike Leach addr_v = config->addr_val[idx];
1320a578427dSMike Leach } else {
1321a578427dSMike Leach addr_v2 = config->addr_val[idx + 1];
1322a578427dSMike Leach }
1323a578427dSMike Leach exclude = config->viiectlr & BIT(idx / 2 + 16);
1324a578427dSMike Leach }
1325a578427dSMike Leach spin_unlock(&drvdata->spinlock);
1326a578427dSMike Leach if (addr_type) {
1327a578427dSMike Leach size = scnprintf(buf, PAGE_SIZE, "addr_cmp[%i] %s %#lx", idx,
1328a578427dSMike Leach addr_type_names[addr_type], addr_v);
1329a578427dSMike Leach if (addr_type == ETM_ADDR_TYPE_RANGE) {
1330a578427dSMike Leach size += scnprintf(buf + size, PAGE_SIZE - size,
1331a578427dSMike Leach " %#lx %s", addr_v2,
1332a578427dSMike Leach exclude ? "exclude" : "include");
1333a578427dSMike Leach }
1334a578427dSMike Leach size += scnprintf(buf + size, PAGE_SIZE - size,
1335a578427dSMike Leach " ctrl(%#lx)\n", addr_ctrl);
1336a578427dSMike Leach } else {
1337a578427dSMike Leach size = scnprintf(buf, PAGE_SIZE, "addr_cmp[%i] unused\n", idx);
1338a578427dSMike Leach }
1339a578427dSMike Leach return size;
1340a578427dSMike Leach }
1341a578427dSMike Leach static DEVICE_ATTR_RO(addr_cmp_view);
1342a578427dSMike Leach
vinst_pe_cmp_start_stop_show(struct device * dev,struct device_attribute * attr,char * buf)13431b6b0e08SMike Leach static ssize_t vinst_pe_cmp_start_stop_show(struct device *dev,
13441b6b0e08SMike Leach struct device_attribute *attr,
13451b6b0e08SMike Leach char *buf)
13461b6b0e08SMike Leach {
13471b6b0e08SMike Leach unsigned long val;
13481b6b0e08SMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
13491b6b0e08SMike Leach struct etmv4_config *config = &drvdata->config;
13501b6b0e08SMike Leach
13511b6b0e08SMike Leach if (!drvdata->nr_pe_cmp)
13521b6b0e08SMike Leach return -EINVAL;
13531b6b0e08SMike Leach val = config->vipcssctlr;
13541b6b0e08SMike Leach return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
13551b6b0e08SMike Leach }
vinst_pe_cmp_start_stop_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)13561b6b0e08SMike Leach static ssize_t vinst_pe_cmp_start_stop_store(struct device *dev,
13571b6b0e08SMike Leach struct device_attribute *attr,
13581b6b0e08SMike Leach const char *buf, size_t size)
13591b6b0e08SMike Leach {
13601b6b0e08SMike Leach unsigned long val;
13611b6b0e08SMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
13621b6b0e08SMike Leach struct etmv4_config *config = &drvdata->config;
13631b6b0e08SMike Leach
13641b6b0e08SMike Leach if (kstrtoul(buf, 16, &val))
13651b6b0e08SMike Leach return -EINVAL;
13661b6b0e08SMike Leach if (!drvdata->nr_pe_cmp)
13671b6b0e08SMike Leach return -EINVAL;
13681b6b0e08SMike Leach
13691b6b0e08SMike Leach spin_lock(&drvdata->spinlock);
13701b6b0e08SMike Leach config->vipcssctlr = val;
13711b6b0e08SMike Leach spin_unlock(&drvdata->spinlock);
13721b6b0e08SMike Leach return size;
13731b6b0e08SMike Leach }
13741b6b0e08SMike Leach static DEVICE_ATTR_RW(vinst_pe_cmp_start_stop);
13751b6b0e08SMike Leach
seq_idx_show(struct device * dev,struct device_attribute * attr,char * buf)1376a77de263SMathieu Poirier static ssize_t seq_idx_show(struct device *dev,
1377a77de263SMathieu Poirier struct device_attribute *attr,
1378a77de263SMathieu Poirier char *buf)
1379a77de263SMathieu Poirier {
1380a77de263SMathieu Poirier unsigned long val;
1381a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
138254ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1383a77de263SMathieu Poirier
138454ff892bSMathieu Poirier val = config->seq_idx;
1385a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1386a77de263SMathieu Poirier }
1387a77de263SMathieu Poirier
seq_idx_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1388a77de263SMathieu Poirier static ssize_t seq_idx_store(struct device *dev,
1389a77de263SMathieu Poirier struct device_attribute *attr,
1390a77de263SMathieu Poirier const char *buf, size_t size)
1391a77de263SMathieu Poirier {
1392a77de263SMathieu Poirier unsigned long val;
1393a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
139454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1395a77de263SMathieu Poirier
1396a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1397a77de263SMathieu Poirier return -EINVAL;
1398a77de263SMathieu Poirier if (val >= drvdata->nrseqstate - 1)
1399a77de263SMathieu Poirier return -EINVAL;
1400a77de263SMathieu Poirier
1401a77de263SMathieu Poirier /*
1402a77de263SMathieu Poirier * Use spinlock to ensure index doesn't change while it gets
1403a77de263SMathieu Poirier * dereferenced multiple times within a spinlock block elsewhere.
1404a77de263SMathieu Poirier */
1405a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
140654ff892bSMathieu Poirier config->seq_idx = val;
1407a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1408a77de263SMathieu Poirier return size;
1409a77de263SMathieu Poirier }
1410a77de263SMathieu Poirier static DEVICE_ATTR_RW(seq_idx);
1411a77de263SMathieu Poirier
seq_state_show(struct device * dev,struct device_attribute * attr,char * buf)1412a77de263SMathieu Poirier static ssize_t seq_state_show(struct device *dev,
1413a77de263SMathieu Poirier struct device_attribute *attr,
1414a77de263SMathieu Poirier char *buf)
1415a77de263SMathieu Poirier {
1416a77de263SMathieu Poirier unsigned long val;
1417a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
141854ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1419a77de263SMathieu Poirier
142054ff892bSMathieu Poirier val = config->seq_state;
1421a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1422a77de263SMathieu Poirier }
1423a77de263SMathieu Poirier
seq_state_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1424a77de263SMathieu Poirier static ssize_t seq_state_store(struct device *dev,
1425a77de263SMathieu Poirier struct device_attribute *attr,
1426a77de263SMathieu Poirier const char *buf, size_t size)
1427a77de263SMathieu Poirier {
1428a77de263SMathieu Poirier unsigned long val;
1429a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
143054ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1431a77de263SMathieu Poirier
1432a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1433a77de263SMathieu Poirier return -EINVAL;
1434a77de263SMathieu Poirier if (val >= drvdata->nrseqstate)
1435a77de263SMathieu Poirier return -EINVAL;
1436a77de263SMathieu Poirier
143754ff892bSMathieu Poirier config->seq_state = val;
1438a77de263SMathieu Poirier return size;
1439a77de263SMathieu Poirier }
1440a77de263SMathieu Poirier static DEVICE_ATTR_RW(seq_state);
1441a77de263SMathieu Poirier
seq_event_show(struct device * dev,struct device_attribute * attr,char * buf)1442a77de263SMathieu Poirier static ssize_t seq_event_show(struct device *dev,
1443a77de263SMathieu Poirier struct device_attribute *attr,
1444a77de263SMathieu Poirier char *buf)
1445a77de263SMathieu Poirier {
1446a77de263SMathieu Poirier u8 idx;
1447a77de263SMathieu Poirier unsigned long val;
1448a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
144954ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1450a77de263SMathieu Poirier
1451a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
145254ff892bSMathieu Poirier idx = config->seq_idx;
145354ff892bSMathieu Poirier val = config->seq_ctrl[idx];
1454a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1455a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1456a77de263SMathieu Poirier }
1457a77de263SMathieu Poirier
seq_event_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1458a77de263SMathieu Poirier static ssize_t seq_event_store(struct device *dev,
1459a77de263SMathieu Poirier struct device_attribute *attr,
1460a77de263SMathieu Poirier const char *buf, size_t size)
1461a77de263SMathieu Poirier {
1462a77de263SMathieu Poirier u8 idx;
1463a77de263SMathieu Poirier unsigned long val;
1464a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
146554ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1466a77de263SMathieu Poirier
1467a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1468a77de263SMathieu Poirier return -EINVAL;
1469a77de263SMathieu Poirier
1470a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
147154ff892bSMathieu Poirier idx = config->seq_idx;
14722fe6899eSMike Leach /* Seq control has two masks B[15:8] F[7:0] */
14732fe6899eSMike Leach config->seq_ctrl[idx] = val & 0xFFFF;
1474a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1475a77de263SMathieu Poirier return size;
1476a77de263SMathieu Poirier }
1477a77de263SMathieu Poirier static DEVICE_ATTR_RW(seq_event);
1478a77de263SMathieu Poirier
seq_reset_event_show(struct device * dev,struct device_attribute * attr,char * buf)1479a77de263SMathieu Poirier static ssize_t seq_reset_event_show(struct device *dev,
1480a77de263SMathieu Poirier struct device_attribute *attr,
1481a77de263SMathieu Poirier char *buf)
1482a77de263SMathieu Poirier {
1483a77de263SMathieu Poirier unsigned long val;
1484a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
148554ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1486a77de263SMathieu Poirier
148754ff892bSMathieu Poirier val = config->seq_rst;
1488a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1489a77de263SMathieu Poirier }
1490a77de263SMathieu Poirier
seq_reset_event_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1491a77de263SMathieu Poirier static ssize_t seq_reset_event_store(struct device *dev,
1492a77de263SMathieu Poirier struct device_attribute *attr,
1493a77de263SMathieu Poirier const char *buf, size_t size)
1494a77de263SMathieu Poirier {
1495a77de263SMathieu Poirier unsigned long val;
1496a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
149754ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1498a77de263SMathieu Poirier
1499a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1500a77de263SMathieu Poirier return -EINVAL;
1501a77de263SMathieu Poirier if (!(drvdata->nrseqstate))
1502a77de263SMathieu Poirier return -EINVAL;
1503a77de263SMathieu Poirier
150454ff892bSMathieu Poirier config->seq_rst = val & ETMv4_EVENT_MASK;
1505a77de263SMathieu Poirier return size;
1506a77de263SMathieu Poirier }
1507a77de263SMathieu Poirier static DEVICE_ATTR_RW(seq_reset_event);
1508a77de263SMathieu Poirier
cntr_idx_show(struct device * dev,struct device_attribute * attr,char * buf)1509a77de263SMathieu Poirier static ssize_t cntr_idx_show(struct device *dev,
1510a77de263SMathieu Poirier struct device_attribute *attr,
1511a77de263SMathieu Poirier char *buf)
1512a77de263SMathieu Poirier {
1513a77de263SMathieu Poirier unsigned long val;
1514a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
151554ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1516a77de263SMathieu Poirier
151754ff892bSMathieu Poirier val = config->cntr_idx;
1518a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1519a77de263SMathieu Poirier }
1520a77de263SMathieu Poirier
cntr_idx_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1521a77de263SMathieu Poirier static ssize_t cntr_idx_store(struct device *dev,
1522a77de263SMathieu Poirier struct device_attribute *attr,
1523a77de263SMathieu Poirier const char *buf, size_t size)
1524a77de263SMathieu Poirier {
1525a77de263SMathieu Poirier unsigned long val;
1526a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
152754ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1528a77de263SMathieu Poirier
1529a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1530a77de263SMathieu Poirier return -EINVAL;
1531a77de263SMathieu Poirier if (val >= drvdata->nr_cntr)
1532a77de263SMathieu Poirier return -EINVAL;
1533a77de263SMathieu Poirier
1534a77de263SMathieu Poirier /*
1535a77de263SMathieu Poirier * Use spinlock to ensure index doesn't change while it gets
1536a77de263SMathieu Poirier * dereferenced multiple times within a spinlock block elsewhere.
1537a77de263SMathieu Poirier */
1538a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
153954ff892bSMathieu Poirier config->cntr_idx = val;
1540a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1541a77de263SMathieu Poirier return size;
1542a77de263SMathieu Poirier }
1543a77de263SMathieu Poirier static DEVICE_ATTR_RW(cntr_idx);
1544a77de263SMathieu Poirier
cntrldvr_show(struct device * dev,struct device_attribute * attr,char * buf)1545a77de263SMathieu Poirier static ssize_t cntrldvr_show(struct device *dev,
1546a77de263SMathieu Poirier struct device_attribute *attr,
1547a77de263SMathieu Poirier char *buf)
1548a77de263SMathieu Poirier {
1549a77de263SMathieu Poirier u8 idx;
1550a77de263SMathieu Poirier unsigned long val;
1551a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
155254ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1553a77de263SMathieu Poirier
1554a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
155554ff892bSMathieu Poirier idx = config->cntr_idx;
155654ff892bSMathieu Poirier val = config->cntrldvr[idx];
1557a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1558a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1559a77de263SMathieu Poirier }
1560a77de263SMathieu Poirier
cntrldvr_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1561a77de263SMathieu Poirier static ssize_t cntrldvr_store(struct device *dev,
1562a77de263SMathieu Poirier struct device_attribute *attr,
1563a77de263SMathieu Poirier const char *buf, size_t size)
1564a77de263SMathieu Poirier {
1565a77de263SMathieu Poirier u8 idx;
1566a77de263SMathieu Poirier unsigned long val;
1567a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
156854ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1569a77de263SMathieu Poirier
1570a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1571a77de263SMathieu Poirier return -EINVAL;
1572a77de263SMathieu Poirier if (val > ETM_CNTR_MAX_VAL)
1573a77de263SMathieu Poirier return -EINVAL;
1574a77de263SMathieu Poirier
1575a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
157654ff892bSMathieu Poirier idx = config->cntr_idx;
157754ff892bSMathieu Poirier config->cntrldvr[idx] = val;
1578a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1579a77de263SMathieu Poirier return size;
1580a77de263SMathieu Poirier }
1581a77de263SMathieu Poirier static DEVICE_ATTR_RW(cntrldvr);
1582a77de263SMathieu Poirier
cntr_val_show(struct device * dev,struct device_attribute * attr,char * buf)1583a77de263SMathieu Poirier static ssize_t cntr_val_show(struct device *dev,
1584a77de263SMathieu Poirier struct device_attribute *attr,
1585a77de263SMathieu Poirier char *buf)
1586a77de263SMathieu Poirier {
1587a77de263SMathieu Poirier u8 idx;
1588a77de263SMathieu Poirier unsigned long val;
1589a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
159054ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1591a77de263SMathieu Poirier
1592a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
159354ff892bSMathieu Poirier idx = config->cntr_idx;
159454ff892bSMathieu Poirier val = config->cntr_val[idx];
1595a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1596a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1597a77de263SMathieu Poirier }
1598a77de263SMathieu Poirier
cntr_val_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1599a77de263SMathieu Poirier static ssize_t cntr_val_store(struct device *dev,
1600a77de263SMathieu Poirier struct device_attribute *attr,
1601a77de263SMathieu Poirier const char *buf, size_t size)
1602a77de263SMathieu Poirier {
1603a77de263SMathieu Poirier u8 idx;
1604a77de263SMathieu Poirier unsigned long val;
1605a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
160654ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1607a77de263SMathieu Poirier
1608a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1609a77de263SMathieu Poirier return -EINVAL;
1610a77de263SMathieu Poirier if (val > ETM_CNTR_MAX_VAL)
1611a77de263SMathieu Poirier return -EINVAL;
1612a77de263SMathieu Poirier
1613a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
161454ff892bSMathieu Poirier idx = config->cntr_idx;
161554ff892bSMathieu Poirier config->cntr_val[idx] = val;
1616a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1617a77de263SMathieu Poirier return size;
1618a77de263SMathieu Poirier }
1619a77de263SMathieu Poirier static DEVICE_ATTR_RW(cntr_val);
1620a77de263SMathieu Poirier
cntr_ctrl_show(struct device * dev,struct device_attribute * attr,char * buf)1621a77de263SMathieu Poirier static ssize_t cntr_ctrl_show(struct device *dev,
1622a77de263SMathieu Poirier struct device_attribute *attr,
1623a77de263SMathieu Poirier char *buf)
1624a77de263SMathieu Poirier {
1625a77de263SMathieu Poirier u8 idx;
1626a77de263SMathieu Poirier unsigned long val;
1627a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
162854ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1629a77de263SMathieu Poirier
1630a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
163154ff892bSMathieu Poirier idx = config->cntr_idx;
163254ff892bSMathieu Poirier val = config->cntr_ctrl[idx];
1633a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1634a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1635a77de263SMathieu Poirier }
1636a77de263SMathieu Poirier
cntr_ctrl_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1637a77de263SMathieu Poirier static ssize_t cntr_ctrl_store(struct device *dev,
1638a77de263SMathieu Poirier struct device_attribute *attr,
1639a77de263SMathieu Poirier const char *buf, size_t size)
1640a77de263SMathieu Poirier {
1641a77de263SMathieu Poirier u8 idx;
1642a77de263SMathieu Poirier unsigned long val;
1643a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
164454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1645a77de263SMathieu Poirier
1646a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1647a77de263SMathieu Poirier return -EINVAL;
1648a77de263SMathieu Poirier
1649a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
165054ff892bSMathieu Poirier idx = config->cntr_idx;
165154ff892bSMathieu Poirier config->cntr_ctrl[idx] = val;
1652a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1653a77de263SMathieu Poirier return size;
1654a77de263SMathieu Poirier }
1655a77de263SMathieu Poirier static DEVICE_ATTR_RW(cntr_ctrl);
1656a77de263SMathieu Poirier
res_idx_show(struct device * dev,struct device_attribute * attr,char * buf)1657a77de263SMathieu Poirier static ssize_t res_idx_show(struct device *dev,
1658a77de263SMathieu Poirier struct device_attribute *attr,
1659a77de263SMathieu Poirier char *buf)
1660a77de263SMathieu Poirier {
1661a77de263SMathieu Poirier unsigned long val;
1662a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
166354ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1664a77de263SMathieu Poirier
166554ff892bSMathieu Poirier val = config->res_idx;
1666a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1667a77de263SMathieu Poirier }
1668a77de263SMathieu Poirier
res_idx_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1669a77de263SMathieu Poirier static ssize_t res_idx_store(struct device *dev,
1670a77de263SMathieu Poirier struct device_attribute *attr,
1671a77de263SMathieu Poirier const char *buf, size_t size)
1672a77de263SMathieu Poirier {
1673a77de263SMathieu Poirier unsigned long val;
1674a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
167554ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1676a77de263SMathieu Poirier
1677a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1678a77de263SMathieu Poirier return -EINVAL;
1679685d84a7SJonathan Zhou /*
1680685d84a7SJonathan Zhou * Resource selector pair 0 is always implemented and reserved,
1681685d84a7SJonathan Zhou * namely an idx with 0 and 1 is illegal.
1682685d84a7SJonathan Zhou */
1683685d84a7SJonathan Zhou if ((val < 2) || (val >= 2 * drvdata->nr_resource))
1684a77de263SMathieu Poirier return -EINVAL;
1685a77de263SMathieu Poirier
1686a77de263SMathieu Poirier /*
1687a77de263SMathieu Poirier * Use spinlock to ensure index doesn't change while it gets
1688a77de263SMathieu Poirier * dereferenced multiple times within a spinlock block elsewhere.
1689a77de263SMathieu Poirier */
1690a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
169154ff892bSMathieu Poirier config->res_idx = val;
1692a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1693a77de263SMathieu Poirier return size;
1694a77de263SMathieu Poirier }
1695a77de263SMathieu Poirier static DEVICE_ATTR_RW(res_idx);
1696a77de263SMathieu Poirier
res_ctrl_show(struct device * dev,struct device_attribute * attr,char * buf)1697a77de263SMathieu Poirier static ssize_t res_ctrl_show(struct device *dev,
1698a77de263SMathieu Poirier struct device_attribute *attr,
1699a77de263SMathieu Poirier char *buf)
1700a77de263SMathieu Poirier {
1701a77de263SMathieu Poirier u8 idx;
1702a77de263SMathieu Poirier unsigned long val;
1703a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
170454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1705a77de263SMathieu Poirier
1706a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
170754ff892bSMathieu Poirier idx = config->res_idx;
170854ff892bSMathieu Poirier val = config->res_ctrl[idx];
1709a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1710a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1711a77de263SMathieu Poirier }
1712a77de263SMathieu Poirier
res_ctrl_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1713a77de263SMathieu Poirier static ssize_t res_ctrl_store(struct device *dev,
1714a77de263SMathieu Poirier struct device_attribute *attr,
1715a77de263SMathieu Poirier const char *buf, size_t size)
1716a77de263SMathieu Poirier {
1717a77de263SMathieu Poirier u8 idx;
1718a77de263SMathieu Poirier unsigned long val;
1719a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
172054ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1721a77de263SMathieu Poirier
1722a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1723a77de263SMathieu Poirier return -EINVAL;
1724a77de263SMathieu Poirier
1725a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
172654ff892bSMathieu Poirier idx = config->res_idx;
1727a77de263SMathieu Poirier /* For odd idx pair inversal bit is RES0 */
1728a77de263SMathieu Poirier if (idx % 2 != 0)
1729a77de263SMathieu Poirier /* PAIRINV, bit[21] */
1730c86dd986SJames Clark val &= ~TRCRSCTLRn_PAIRINV;
1731c86dd986SJames Clark config->res_ctrl[idx] = val & (TRCRSCTLRn_PAIRINV |
1732c86dd986SJames Clark TRCRSCTLRn_INV |
1733c86dd986SJames Clark TRCRSCTLRn_GROUP_MASK |
1734c86dd986SJames Clark TRCRSCTLRn_SELECT_MASK);
1735a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1736a77de263SMathieu Poirier return size;
1737a77de263SMathieu Poirier }
1738a77de263SMathieu Poirier static DEVICE_ATTR_RW(res_ctrl);
1739a77de263SMathieu Poirier
sshot_idx_show(struct device * dev,struct device_attribute * attr,char * buf)1740ebddaad0SMike Leach static ssize_t sshot_idx_show(struct device *dev,
1741ebddaad0SMike Leach struct device_attribute *attr, char *buf)
1742ebddaad0SMike Leach {
1743ebddaad0SMike Leach unsigned long val;
1744ebddaad0SMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
1745ebddaad0SMike Leach struct etmv4_config *config = &drvdata->config;
1746ebddaad0SMike Leach
1747ebddaad0SMike Leach val = config->ss_idx;
1748ebddaad0SMike Leach return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1749ebddaad0SMike Leach }
1750ebddaad0SMike Leach
sshot_idx_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1751ebddaad0SMike Leach static ssize_t sshot_idx_store(struct device *dev,
1752ebddaad0SMike Leach struct device_attribute *attr,
1753ebddaad0SMike Leach const char *buf, size_t size)
1754ebddaad0SMike Leach {
1755ebddaad0SMike Leach unsigned long val;
1756ebddaad0SMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
1757ebddaad0SMike Leach struct etmv4_config *config = &drvdata->config;
1758ebddaad0SMike Leach
1759ebddaad0SMike Leach if (kstrtoul(buf, 16, &val))
1760ebddaad0SMike Leach return -EINVAL;
1761ebddaad0SMike Leach if (val >= drvdata->nr_ss_cmp)
1762ebddaad0SMike Leach return -EINVAL;
1763ebddaad0SMike Leach
1764ebddaad0SMike Leach spin_lock(&drvdata->spinlock);
1765ebddaad0SMike Leach config->ss_idx = val;
1766ebddaad0SMike Leach spin_unlock(&drvdata->spinlock);
1767ebddaad0SMike Leach return size;
1768ebddaad0SMike Leach }
1769ebddaad0SMike Leach static DEVICE_ATTR_RW(sshot_idx);
1770ebddaad0SMike Leach
sshot_ctrl_show(struct device * dev,struct device_attribute * attr,char * buf)1771ebddaad0SMike Leach static ssize_t sshot_ctrl_show(struct device *dev,
1772ebddaad0SMike Leach struct device_attribute *attr,
1773ebddaad0SMike Leach char *buf)
1774ebddaad0SMike Leach {
1775ebddaad0SMike Leach unsigned long val;
1776ebddaad0SMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
1777ebddaad0SMike Leach struct etmv4_config *config = &drvdata->config;
1778ebddaad0SMike Leach
1779ebddaad0SMike Leach spin_lock(&drvdata->spinlock);
1780ebddaad0SMike Leach val = config->ss_ctrl[config->ss_idx];
1781ebddaad0SMike Leach spin_unlock(&drvdata->spinlock);
1782ebddaad0SMike Leach return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1783ebddaad0SMike Leach }
1784ebddaad0SMike Leach
sshot_ctrl_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1785ebddaad0SMike Leach static ssize_t sshot_ctrl_store(struct device *dev,
1786ebddaad0SMike Leach struct device_attribute *attr,
1787ebddaad0SMike Leach const char *buf, size_t size)
1788ebddaad0SMike Leach {
1789ebddaad0SMike Leach u8 idx;
1790ebddaad0SMike Leach unsigned long val;
1791ebddaad0SMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
1792ebddaad0SMike Leach struct etmv4_config *config = &drvdata->config;
1793ebddaad0SMike Leach
1794ebddaad0SMike Leach if (kstrtoul(buf, 16, &val))
1795ebddaad0SMike Leach return -EINVAL;
1796ebddaad0SMike Leach
1797ebddaad0SMike Leach spin_lock(&drvdata->spinlock);
1798ebddaad0SMike Leach idx = config->ss_idx;
17990544f32bSJames Clark config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
1800ebddaad0SMike Leach /* must clear bit 31 in related status register on programming */
18010544f32bSJames Clark config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
1802ebddaad0SMike Leach spin_unlock(&drvdata->spinlock);
1803ebddaad0SMike Leach return size;
1804ebddaad0SMike Leach }
1805ebddaad0SMike Leach static DEVICE_ATTR_RW(sshot_ctrl);
1806ebddaad0SMike Leach
sshot_status_show(struct device * dev,struct device_attribute * attr,char * buf)1807ebddaad0SMike Leach static ssize_t sshot_status_show(struct device *dev,
1808ebddaad0SMike Leach struct device_attribute *attr, char *buf)
1809ebddaad0SMike Leach {
1810ebddaad0SMike Leach unsigned long val;
1811ebddaad0SMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
1812ebddaad0SMike Leach struct etmv4_config *config = &drvdata->config;
1813ebddaad0SMike Leach
1814ebddaad0SMike Leach spin_lock(&drvdata->spinlock);
1815ebddaad0SMike Leach val = config->ss_status[config->ss_idx];
1816ebddaad0SMike Leach spin_unlock(&drvdata->spinlock);
1817ebddaad0SMike Leach return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1818ebddaad0SMike Leach }
1819ebddaad0SMike Leach static DEVICE_ATTR_RO(sshot_status);
1820ebddaad0SMike Leach
sshot_pe_ctrl_show(struct device * dev,struct device_attribute * attr,char * buf)1821ebddaad0SMike Leach static ssize_t sshot_pe_ctrl_show(struct device *dev,
1822ebddaad0SMike Leach struct device_attribute *attr,
1823ebddaad0SMike Leach char *buf)
1824ebddaad0SMike Leach {
1825ebddaad0SMike Leach unsigned long val;
1826ebddaad0SMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
1827ebddaad0SMike Leach struct etmv4_config *config = &drvdata->config;
1828ebddaad0SMike Leach
1829ebddaad0SMike Leach spin_lock(&drvdata->spinlock);
1830ebddaad0SMike Leach val = config->ss_pe_cmp[config->ss_idx];
1831ebddaad0SMike Leach spin_unlock(&drvdata->spinlock);
1832ebddaad0SMike Leach return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1833ebddaad0SMike Leach }
1834ebddaad0SMike Leach
sshot_pe_ctrl_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1835ebddaad0SMike Leach static ssize_t sshot_pe_ctrl_store(struct device *dev,
1836ebddaad0SMike Leach struct device_attribute *attr,
1837ebddaad0SMike Leach const char *buf, size_t size)
1838ebddaad0SMike Leach {
1839ebddaad0SMike Leach u8 idx;
1840ebddaad0SMike Leach unsigned long val;
1841ebddaad0SMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
1842ebddaad0SMike Leach struct etmv4_config *config = &drvdata->config;
1843ebddaad0SMike Leach
1844ebddaad0SMike Leach if (kstrtoul(buf, 16, &val))
1845ebddaad0SMike Leach return -EINVAL;
1846ebddaad0SMike Leach
1847ebddaad0SMike Leach spin_lock(&drvdata->spinlock);
1848ebddaad0SMike Leach idx = config->ss_idx;
184966192082SJames Clark config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
1850ebddaad0SMike Leach /* must clear bit 31 in related status register on programming */
18510544f32bSJames Clark config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
1852ebddaad0SMike Leach spin_unlock(&drvdata->spinlock);
1853ebddaad0SMike Leach return size;
1854ebddaad0SMike Leach }
1855ebddaad0SMike Leach static DEVICE_ATTR_RW(sshot_pe_ctrl);
1856ebddaad0SMike Leach
ctxid_idx_show(struct device * dev,struct device_attribute * attr,char * buf)1857a77de263SMathieu Poirier static ssize_t ctxid_idx_show(struct device *dev,
1858a77de263SMathieu Poirier struct device_attribute *attr,
1859a77de263SMathieu Poirier char *buf)
1860a77de263SMathieu Poirier {
1861a77de263SMathieu Poirier unsigned long val;
1862a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
186354ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1864a77de263SMathieu Poirier
186554ff892bSMathieu Poirier val = config->ctxid_idx;
1866a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1867a77de263SMathieu Poirier }
1868a77de263SMathieu Poirier
ctxid_idx_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1869a77de263SMathieu Poirier static ssize_t ctxid_idx_store(struct device *dev,
1870a77de263SMathieu Poirier struct device_attribute *attr,
1871a77de263SMathieu Poirier const char *buf, size_t size)
1872a77de263SMathieu Poirier {
1873a77de263SMathieu Poirier unsigned long val;
1874a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
187554ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1876a77de263SMathieu Poirier
1877a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
1878a77de263SMathieu Poirier return -EINVAL;
1879a77de263SMathieu Poirier if (val >= drvdata->numcidc)
1880a77de263SMathieu Poirier return -EINVAL;
1881a77de263SMathieu Poirier
1882a77de263SMathieu Poirier /*
1883a77de263SMathieu Poirier * Use spinlock to ensure index doesn't change while it gets
1884a77de263SMathieu Poirier * dereferenced multiple times within a spinlock block elsewhere.
1885a77de263SMathieu Poirier */
1886a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
188754ff892bSMathieu Poirier config->ctxid_idx = val;
1888a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1889a77de263SMathieu Poirier return size;
1890a77de263SMathieu Poirier }
1891a77de263SMathieu Poirier static DEVICE_ATTR_RW(ctxid_idx);
1892a77de263SMathieu Poirier
ctxid_pid_show(struct device * dev,struct device_attribute * attr,char * buf)1893a77de263SMathieu Poirier static ssize_t ctxid_pid_show(struct device *dev,
1894a77de263SMathieu Poirier struct device_attribute *attr,
1895a77de263SMathieu Poirier char *buf)
1896a77de263SMathieu Poirier {
1897a77de263SMathieu Poirier u8 idx;
1898a77de263SMathieu Poirier unsigned long val;
1899a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
190054ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1901a77de263SMathieu Poirier
1902450367f0SMathieu Poirier /*
1903450367f0SMathieu Poirier * Don't use contextID tracing if coming from a PID namespace. See
1904450367f0SMathieu Poirier * comment in ctxid_pid_store().
1905450367f0SMathieu Poirier */
1906450367f0SMathieu Poirier if (task_active_pid_ns(current) != &init_pid_ns)
1907450367f0SMathieu Poirier return -EINVAL;
1908450367f0SMathieu Poirier
1909a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
191054ff892bSMathieu Poirier idx = config->ctxid_idx;
1911450367f0SMathieu Poirier val = (unsigned long)config->ctxid_pid[idx];
1912a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1913a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
1914a77de263SMathieu Poirier }
1915a77de263SMathieu Poirier
ctxid_pid_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1916a77de263SMathieu Poirier static ssize_t ctxid_pid_store(struct device *dev,
1917a77de263SMathieu Poirier struct device_attribute *attr,
1918a77de263SMathieu Poirier const char *buf, size_t size)
1919a77de263SMathieu Poirier {
1920a77de263SMathieu Poirier u8 idx;
1921450367f0SMathieu Poirier unsigned long pid;
1922a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
192354ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1924a77de263SMathieu Poirier
1925a77de263SMathieu Poirier /*
1926450367f0SMathieu Poirier * When contextID tracing is enabled the tracers will insert the
1927450367f0SMathieu Poirier * value found in the contextID register in the trace stream. But if
1928450367f0SMathieu Poirier * a process is in a namespace the PID of that process as seen from the
1929450367f0SMathieu Poirier * namespace won't be what the kernel sees, something that makes the
1930450367f0SMathieu Poirier * feature confusing and can potentially leak kernel only information.
1931450367f0SMathieu Poirier * As such refuse to use the feature if @current is not in the initial
1932450367f0SMathieu Poirier * PID namespace.
1933450367f0SMathieu Poirier */
1934450367f0SMathieu Poirier if (task_active_pid_ns(current) != &init_pid_ns)
1935450367f0SMathieu Poirier return -EINVAL;
1936450367f0SMathieu Poirier
1937450367f0SMathieu Poirier /*
1938a77de263SMathieu Poirier * only implemented when ctxid tracing is enabled, i.e. at least one
1939a77de263SMathieu Poirier * ctxid comparator is implemented and ctxid is greater than 0 bits
1940a77de263SMathieu Poirier * in length
1941a77de263SMathieu Poirier */
1942a77de263SMathieu Poirier if (!drvdata->ctxid_size || !drvdata->numcidc)
1943a77de263SMathieu Poirier return -EINVAL;
1944450367f0SMathieu Poirier if (kstrtoul(buf, 16, &pid))
1945a77de263SMathieu Poirier return -EINVAL;
1946a77de263SMathieu Poirier
1947a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
194854ff892bSMathieu Poirier idx = config->ctxid_idx;
194954ff892bSMathieu Poirier config->ctxid_pid[idx] = (u64)pid;
1950a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1951a77de263SMathieu Poirier return size;
1952a77de263SMathieu Poirier }
1953a77de263SMathieu Poirier static DEVICE_ATTR_RW(ctxid_pid);
1954a77de263SMathieu Poirier
ctxid_masks_show(struct device * dev,struct device_attribute * attr,char * buf)1955a77de263SMathieu Poirier static ssize_t ctxid_masks_show(struct device *dev,
1956a77de263SMathieu Poirier struct device_attribute *attr,
1957a77de263SMathieu Poirier char *buf)
1958a77de263SMathieu Poirier {
1959a77de263SMathieu Poirier unsigned long val1, val2;
1960a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
196154ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
1962a77de263SMathieu Poirier
1963450367f0SMathieu Poirier /*
1964450367f0SMathieu Poirier * Don't use contextID tracing if coming from a PID namespace. See
1965450367f0SMathieu Poirier * comment in ctxid_pid_store().
1966450367f0SMathieu Poirier */
1967450367f0SMathieu Poirier if (task_active_pid_ns(current) != &init_pid_ns)
1968450367f0SMathieu Poirier return -EINVAL;
1969450367f0SMathieu Poirier
1970a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
197154ff892bSMathieu Poirier val1 = config->ctxid_mask0;
197254ff892bSMathieu Poirier val2 = config->ctxid_mask1;
1973a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
1974a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
1975a77de263SMathieu Poirier }
1976a77de263SMathieu Poirier
ctxid_masks_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1977a77de263SMathieu Poirier static ssize_t ctxid_masks_store(struct device *dev,
1978a77de263SMathieu Poirier struct device_attribute *attr,
1979a77de263SMathieu Poirier const char *buf, size_t size)
1980a77de263SMathieu Poirier {
1981a77de263SMathieu Poirier u8 i, j, maskbyte;
1982a77de263SMathieu Poirier unsigned long val1, val2, mask;
1983a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
198454ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
19853e12d3b0SMike Leach int nr_inputs;
1986a77de263SMathieu Poirier
1987a77de263SMathieu Poirier /*
1988450367f0SMathieu Poirier * Don't use contextID tracing if coming from a PID namespace. See
1989450367f0SMathieu Poirier * comment in ctxid_pid_store().
1990450367f0SMathieu Poirier */
1991450367f0SMathieu Poirier if (task_active_pid_ns(current) != &init_pid_ns)
1992450367f0SMathieu Poirier return -EINVAL;
1993450367f0SMathieu Poirier
1994450367f0SMathieu Poirier /*
1995a77de263SMathieu Poirier * only implemented when ctxid tracing is enabled, i.e. at least one
1996a77de263SMathieu Poirier * ctxid comparator is implemented and ctxid is greater than 0 bits
1997a77de263SMathieu Poirier * in length
1998a77de263SMathieu Poirier */
1999a77de263SMathieu Poirier if (!drvdata->ctxid_size || !drvdata->numcidc)
2000a77de263SMathieu Poirier return -EINVAL;
20013e12d3b0SMike Leach /* one mask if <= 4 comparators, two for up to 8 */
20023e12d3b0SMike Leach nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2);
20033e12d3b0SMike Leach if ((drvdata->numcidc > 4) && (nr_inputs != 2))
2004a77de263SMathieu Poirier return -EINVAL;
2005a77de263SMathieu Poirier
2006a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
2007a77de263SMathieu Poirier /*
2008a77de263SMathieu Poirier * each byte[0..3] controls mask value applied to ctxid
2009a77de263SMathieu Poirier * comparator[0..3]
2010a77de263SMathieu Poirier */
2011a77de263SMathieu Poirier switch (drvdata->numcidc) {
2012a77de263SMathieu Poirier case 0x1:
2013a77de263SMathieu Poirier /* COMP0, bits[7:0] */
201454ff892bSMathieu Poirier config->ctxid_mask0 = val1 & 0xFF;
2015a77de263SMathieu Poirier break;
2016a77de263SMathieu Poirier case 0x2:
2017a77de263SMathieu Poirier /* COMP1, bits[15:8] */
201854ff892bSMathieu Poirier config->ctxid_mask0 = val1 & 0xFFFF;
2019a77de263SMathieu Poirier break;
2020a77de263SMathieu Poirier case 0x3:
2021a77de263SMathieu Poirier /* COMP2, bits[23:16] */
202254ff892bSMathieu Poirier config->ctxid_mask0 = val1 & 0xFFFFFF;
2023a77de263SMathieu Poirier break;
2024a77de263SMathieu Poirier case 0x4:
2025a77de263SMathieu Poirier /* COMP3, bits[31:24] */
202654ff892bSMathieu Poirier config->ctxid_mask0 = val1;
2027a77de263SMathieu Poirier break;
2028a77de263SMathieu Poirier case 0x5:
2029a77de263SMathieu Poirier /* COMP4, bits[7:0] */
203054ff892bSMathieu Poirier config->ctxid_mask0 = val1;
203154ff892bSMathieu Poirier config->ctxid_mask1 = val2 & 0xFF;
2032a77de263SMathieu Poirier break;
2033a77de263SMathieu Poirier case 0x6:
2034a77de263SMathieu Poirier /* COMP5, bits[15:8] */
203554ff892bSMathieu Poirier config->ctxid_mask0 = val1;
203654ff892bSMathieu Poirier config->ctxid_mask1 = val2 & 0xFFFF;
2037a77de263SMathieu Poirier break;
2038a77de263SMathieu Poirier case 0x7:
2039a77de263SMathieu Poirier /* COMP6, bits[23:16] */
204054ff892bSMathieu Poirier config->ctxid_mask0 = val1;
204154ff892bSMathieu Poirier config->ctxid_mask1 = val2 & 0xFFFFFF;
2042a77de263SMathieu Poirier break;
2043a77de263SMathieu Poirier case 0x8:
2044a77de263SMathieu Poirier /* COMP7, bits[31:24] */
204554ff892bSMathieu Poirier config->ctxid_mask0 = val1;
204654ff892bSMathieu Poirier config->ctxid_mask1 = val2;
2047a77de263SMathieu Poirier break;
2048a77de263SMathieu Poirier default:
2049a77de263SMathieu Poirier break;
2050a77de263SMathieu Poirier }
2051a77de263SMathieu Poirier /*
2052a77de263SMathieu Poirier * If software sets a mask bit to 1, it must program relevant byte
2053a77de263SMathieu Poirier * of ctxid comparator value 0x0, otherwise behavior is unpredictable.
2054a77de263SMathieu Poirier * For example, if bit[3] of ctxid_mask0 is 1, we must clear bits[31:24]
2055a77de263SMathieu Poirier * of ctxid comparator0 value (corresponding to byte 0) register.
2056a77de263SMathieu Poirier */
205754ff892bSMathieu Poirier mask = config->ctxid_mask0;
2058a77de263SMathieu Poirier for (i = 0; i < drvdata->numcidc; i++) {
2059a77de263SMathieu Poirier /* mask value of corresponding ctxid comparator */
2060a77de263SMathieu Poirier maskbyte = mask & ETMv4_EVENT_MASK;
2061a77de263SMathieu Poirier /*
2062a77de263SMathieu Poirier * each bit corresponds to a byte of respective ctxid comparator
2063a77de263SMathieu Poirier * value register
2064a77de263SMathieu Poirier */
2065a77de263SMathieu Poirier for (j = 0; j < 8; j++) {
2066a77de263SMathieu Poirier if (maskbyte & 1)
206757adbeeaSBo Yan config->ctxid_pid[i] &= ~(0xFFUL << (j * 8));
2068a77de263SMathieu Poirier maskbyte >>= 1;
2069a77de263SMathieu Poirier }
2070a77de263SMathieu Poirier /* Select the next ctxid comparator mask value */
2071a77de263SMathieu Poirier if (i == 3)
2072a77de263SMathieu Poirier /* ctxid comparators[4-7] */
207354ff892bSMathieu Poirier mask = config->ctxid_mask1;
2074a77de263SMathieu Poirier else
2075a77de263SMathieu Poirier mask >>= 0x8;
2076a77de263SMathieu Poirier }
2077a77de263SMathieu Poirier
2078a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
2079a77de263SMathieu Poirier return size;
2080a77de263SMathieu Poirier }
2081a77de263SMathieu Poirier static DEVICE_ATTR_RW(ctxid_masks);
2082a77de263SMathieu Poirier
vmid_idx_show(struct device * dev,struct device_attribute * attr,char * buf)2083a77de263SMathieu Poirier static ssize_t vmid_idx_show(struct device *dev,
2084a77de263SMathieu Poirier struct device_attribute *attr,
2085a77de263SMathieu Poirier char *buf)
2086a77de263SMathieu Poirier {
2087a77de263SMathieu Poirier unsigned long val;
2088a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
208954ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
2090a77de263SMathieu Poirier
209154ff892bSMathieu Poirier val = config->vmid_idx;
2092a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
2093a77de263SMathieu Poirier }
2094a77de263SMathieu Poirier
vmid_idx_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)2095a77de263SMathieu Poirier static ssize_t vmid_idx_store(struct device *dev,
2096a77de263SMathieu Poirier struct device_attribute *attr,
2097a77de263SMathieu Poirier const char *buf, size_t size)
2098a77de263SMathieu Poirier {
2099a77de263SMathieu Poirier unsigned long val;
2100a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
210154ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
2102a77de263SMathieu Poirier
2103a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
2104a77de263SMathieu Poirier return -EINVAL;
2105a77de263SMathieu Poirier if (val >= drvdata->numvmidc)
2106a77de263SMathieu Poirier return -EINVAL;
2107a77de263SMathieu Poirier
2108a77de263SMathieu Poirier /*
2109a77de263SMathieu Poirier * Use spinlock to ensure index doesn't change while it gets
2110a77de263SMathieu Poirier * dereferenced multiple times within a spinlock block elsewhere.
2111a77de263SMathieu Poirier */
2112a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
211354ff892bSMathieu Poirier config->vmid_idx = val;
2114a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
2115a77de263SMathieu Poirier return size;
2116a77de263SMathieu Poirier }
2117a77de263SMathieu Poirier static DEVICE_ATTR_RW(vmid_idx);
2118a77de263SMathieu Poirier
vmid_val_show(struct device * dev,struct device_attribute * attr,char * buf)2119a77de263SMathieu Poirier static ssize_t vmid_val_show(struct device *dev,
2120a77de263SMathieu Poirier struct device_attribute *attr,
2121a77de263SMathieu Poirier char *buf)
2122a77de263SMathieu Poirier {
2123a77de263SMathieu Poirier unsigned long val;
2124a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
212554ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
2126a77de263SMathieu Poirier
21271314dd19SLeo Yan /*
21281314dd19SLeo Yan * Don't use virtual contextID tracing if coming from a PID namespace.
21291314dd19SLeo Yan * See comment in ctxid_pid_store().
21301314dd19SLeo Yan */
21311314dd19SLeo Yan if (!task_is_in_init_pid_ns(current))
21321314dd19SLeo Yan return -EINVAL;
21331314dd19SLeo Yan
2134bf0ef4f1SLeo Yan spin_lock(&drvdata->spinlock);
213554ff892bSMathieu Poirier val = (unsigned long)config->vmid_val[config->vmid_idx];
2136bf0ef4f1SLeo Yan spin_unlock(&drvdata->spinlock);
2137a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
2138a77de263SMathieu Poirier }
2139a77de263SMathieu Poirier
vmid_val_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)2140a77de263SMathieu Poirier static ssize_t vmid_val_store(struct device *dev,
2141a77de263SMathieu Poirier struct device_attribute *attr,
2142a77de263SMathieu Poirier const char *buf, size_t size)
2143a77de263SMathieu Poirier {
2144a77de263SMathieu Poirier unsigned long val;
2145a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
214654ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
2147a77de263SMathieu Poirier
2148a77de263SMathieu Poirier /*
21491314dd19SLeo Yan * Don't use virtual contextID tracing if coming from a PID namespace.
21501314dd19SLeo Yan * See comment in ctxid_pid_store().
21511314dd19SLeo Yan */
21521314dd19SLeo Yan if (!task_is_in_init_pid_ns(current))
21531314dd19SLeo Yan return -EINVAL;
21541314dd19SLeo Yan
21551314dd19SLeo Yan /*
2156a77de263SMathieu Poirier * only implemented when vmid tracing is enabled, i.e. at least one
2157a77de263SMathieu Poirier * vmid comparator is implemented and at least 8 bit vmid size
2158a77de263SMathieu Poirier */
2159a77de263SMathieu Poirier if (!drvdata->vmid_size || !drvdata->numvmidc)
2160a77de263SMathieu Poirier return -EINVAL;
2161a77de263SMathieu Poirier if (kstrtoul(buf, 16, &val))
2162a77de263SMathieu Poirier return -EINVAL;
2163a77de263SMathieu Poirier
2164a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
216554ff892bSMathieu Poirier config->vmid_val[config->vmid_idx] = (u64)val;
2166a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
2167a77de263SMathieu Poirier return size;
2168a77de263SMathieu Poirier }
2169a77de263SMathieu Poirier static DEVICE_ATTR_RW(vmid_val);
2170a77de263SMathieu Poirier
vmid_masks_show(struct device * dev,struct device_attribute * attr,char * buf)2171a77de263SMathieu Poirier static ssize_t vmid_masks_show(struct device *dev,
2172a77de263SMathieu Poirier struct device_attribute *attr, char *buf)
2173a77de263SMathieu Poirier {
2174a77de263SMathieu Poirier unsigned long val1, val2;
2175a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
217654ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
2177a77de263SMathieu Poirier
21781314dd19SLeo Yan /*
21791314dd19SLeo Yan * Don't use virtual contextID tracing if coming from a PID namespace.
21801314dd19SLeo Yan * See comment in ctxid_pid_store().
21811314dd19SLeo Yan */
21821314dd19SLeo Yan if (!task_is_in_init_pid_ns(current))
21831314dd19SLeo Yan return -EINVAL;
21841314dd19SLeo Yan
2185a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
218654ff892bSMathieu Poirier val1 = config->vmid_mask0;
218754ff892bSMathieu Poirier val2 = config->vmid_mask1;
2188a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
2189a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
2190a77de263SMathieu Poirier }
2191a77de263SMathieu Poirier
vmid_masks_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)2192a77de263SMathieu Poirier static ssize_t vmid_masks_store(struct device *dev,
2193a77de263SMathieu Poirier struct device_attribute *attr,
2194a77de263SMathieu Poirier const char *buf, size_t size)
2195a77de263SMathieu Poirier {
2196a77de263SMathieu Poirier u8 i, j, maskbyte;
2197a77de263SMathieu Poirier unsigned long val1, val2, mask;
2198a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
219954ff892bSMathieu Poirier struct etmv4_config *config = &drvdata->config;
22003e12d3b0SMike Leach int nr_inputs;
220154ff892bSMathieu Poirier
2202a77de263SMathieu Poirier /*
22031314dd19SLeo Yan * Don't use virtual contextID tracing if coming from a PID namespace.
22041314dd19SLeo Yan * See comment in ctxid_pid_store().
22051314dd19SLeo Yan */
22061314dd19SLeo Yan if (!task_is_in_init_pid_ns(current))
22071314dd19SLeo Yan return -EINVAL;
22081314dd19SLeo Yan
22091314dd19SLeo Yan /*
2210a77de263SMathieu Poirier * only implemented when vmid tracing is enabled, i.e. at least one
2211a77de263SMathieu Poirier * vmid comparator is implemented and at least 8 bit vmid size
2212a77de263SMathieu Poirier */
2213a77de263SMathieu Poirier if (!drvdata->vmid_size || !drvdata->numvmidc)
2214a77de263SMathieu Poirier return -EINVAL;
22153e12d3b0SMike Leach /* one mask if <= 4 comparators, two for up to 8 */
22163e12d3b0SMike Leach nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2);
22173e12d3b0SMike Leach if ((drvdata->numvmidc > 4) && (nr_inputs != 2))
2218a77de263SMathieu Poirier return -EINVAL;
2219a77de263SMathieu Poirier
2220a77de263SMathieu Poirier spin_lock(&drvdata->spinlock);
2221a77de263SMathieu Poirier
2222a77de263SMathieu Poirier /*
2223a77de263SMathieu Poirier * each byte[0..3] controls mask value applied to vmid
2224a77de263SMathieu Poirier * comparator[0..3]
2225a77de263SMathieu Poirier */
2226a77de263SMathieu Poirier switch (drvdata->numvmidc) {
2227a77de263SMathieu Poirier case 0x1:
2228a77de263SMathieu Poirier /* COMP0, bits[7:0] */
222954ff892bSMathieu Poirier config->vmid_mask0 = val1 & 0xFF;
2230a77de263SMathieu Poirier break;
2231a77de263SMathieu Poirier case 0x2:
2232a77de263SMathieu Poirier /* COMP1, bits[15:8] */
223354ff892bSMathieu Poirier config->vmid_mask0 = val1 & 0xFFFF;
2234a77de263SMathieu Poirier break;
2235a77de263SMathieu Poirier case 0x3:
2236a77de263SMathieu Poirier /* COMP2, bits[23:16] */
223754ff892bSMathieu Poirier config->vmid_mask0 = val1 & 0xFFFFFF;
2238a77de263SMathieu Poirier break;
2239a77de263SMathieu Poirier case 0x4:
2240a77de263SMathieu Poirier /* COMP3, bits[31:24] */
224154ff892bSMathieu Poirier config->vmid_mask0 = val1;
2242a77de263SMathieu Poirier break;
2243a77de263SMathieu Poirier case 0x5:
2244a77de263SMathieu Poirier /* COMP4, bits[7:0] */
224554ff892bSMathieu Poirier config->vmid_mask0 = val1;
224654ff892bSMathieu Poirier config->vmid_mask1 = val2 & 0xFF;
2247a77de263SMathieu Poirier break;
2248a77de263SMathieu Poirier case 0x6:
2249a77de263SMathieu Poirier /* COMP5, bits[15:8] */
225054ff892bSMathieu Poirier config->vmid_mask0 = val1;
225154ff892bSMathieu Poirier config->vmid_mask1 = val2 & 0xFFFF;
2252a77de263SMathieu Poirier break;
2253a77de263SMathieu Poirier case 0x7:
2254a77de263SMathieu Poirier /* COMP6, bits[23:16] */
225554ff892bSMathieu Poirier config->vmid_mask0 = val1;
225654ff892bSMathieu Poirier config->vmid_mask1 = val2 & 0xFFFFFF;
2257a77de263SMathieu Poirier break;
2258a77de263SMathieu Poirier case 0x8:
2259a77de263SMathieu Poirier /* COMP7, bits[31:24] */
226054ff892bSMathieu Poirier config->vmid_mask0 = val1;
226154ff892bSMathieu Poirier config->vmid_mask1 = val2;
2262a77de263SMathieu Poirier break;
2263a77de263SMathieu Poirier default:
2264a77de263SMathieu Poirier break;
2265a77de263SMathieu Poirier }
2266a77de263SMathieu Poirier
2267a77de263SMathieu Poirier /*
2268a77de263SMathieu Poirier * If software sets a mask bit to 1, it must program relevant byte
2269a77de263SMathieu Poirier * of vmid comparator value 0x0, otherwise behavior is unpredictable.
2270a77de263SMathieu Poirier * For example, if bit[3] of vmid_mask0 is 1, we must clear bits[31:24]
2271a77de263SMathieu Poirier * of vmid comparator0 value (corresponding to byte 0) register.
2272a77de263SMathieu Poirier */
227354ff892bSMathieu Poirier mask = config->vmid_mask0;
2274a77de263SMathieu Poirier for (i = 0; i < drvdata->numvmidc; i++) {
2275a77de263SMathieu Poirier /* mask value of corresponding vmid comparator */
2276a77de263SMathieu Poirier maskbyte = mask & ETMv4_EVENT_MASK;
2277a77de263SMathieu Poirier /*
2278a77de263SMathieu Poirier * each bit corresponds to a byte of respective vmid comparator
2279a77de263SMathieu Poirier * value register
2280a77de263SMathieu Poirier */
2281a77de263SMathieu Poirier for (j = 0; j < 8; j++) {
2282a77de263SMathieu Poirier if (maskbyte & 1)
228357adbeeaSBo Yan config->vmid_val[i] &= ~(0xFFUL << (j * 8));
2284a77de263SMathieu Poirier maskbyte >>= 1;
2285a77de263SMathieu Poirier }
2286a77de263SMathieu Poirier /* Select the next vmid comparator mask value */
2287a77de263SMathieu Poirier if (i == 3)
2288a77de263SMathieu Poirier /* vmid comparators[4-7] */
228954ff892bSMathieu Poirier mask = config->vmid_mask1;
2290a77de263SMathieu Poirier else
2291a77de263SMathieu Poirier mask >>= 0x8;
2292a77de263SMathieu Poirier }
2293a77de263SMathieu Poirier spin_unlock(&drvdata->spinlock);
2294a77de263SMathieu Poirier return size;
2295a77de263SMathieu Poirier }
2296a77de263SMathieu Poirier static DEVICE_ATTR_RW(vmid_masks);
2297a77de263SMathieu Poirier
cpu_show(struct device * dev,struct device_attribute * attr,char * buf)2298a77de263SMathieu Poirier static ssize_t cpu_show(struct device *dev,
2299a77de263SMathieu Poirier struct device_attribute *attr, char *buf)
2300a77de263SMathieu Poirier {
2301a77de263SMathieu Poirier int val;
2302a77de263SMathieu Poirier struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
2303a77de263SMathieu Poirier
2304a77de263SMathieu Poirier val = drvdata->cpu;
2305a77de263SMathieu Poirier return scnprintf(buf, PAGE_SIZE, "%d\n", val);
2306a77de263SMathieu Poirier
2307a77de263SMathieu Poirier }
2308a77de263SMathieu Poirier static DEVICE_ATTR_RO(cpu);
2309a77de263SMathieu Poirier
ts_source_show(struct device * dev,struct device_attribute * attr,char * buf)23100f00b223SGerman Gomez static ssize_t ts_source_show(struct device *dev,
23110f00b223SGerman Gomez struct device_attribute *attr,
23120f00b223SGerman Gomez char *buf)
23130f00b223SGerman Gomez {
23140f00b223SGerman Gomez int val;
23150f00b223SGerman Gomez struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
23160f00b223SGerman Gomez
23170f00b223SGerman Gomez if (!drvdata->trfcr) {
23180f00b223SGerman Gomez val = -1;
23190f00b223SGerman Gomez goto out;
23200f00b223SGerman Gomez }
23210f00b223SGerman Gomez
23220f00b223SGerman Gomez switch (drvdata->trfcr & TRFCR_ELx_TS_MASK) {
23230f00b223SGerman Gomez case TRFCR_ELx_TS_VIRTUAL:
23240f00b223SGerman Gomez case TRFCR_ELx_TS_GUEST_PHYSICAL:
23250f00b223SGerman Gomez case TRFCR_ELx_TS_PHYSICAL:
23260f00b223SGerman Gomez val = FIELD_GET(TRFCR_ELx_TS_MASK, drvdata->trfcr);
23270f00b223SGerman Gomez break;
23280f00b223SGerman Gomez default:
23290f00b223SGerman Gomez val = -1;
23300f00b223SGerman Gomez break;
23310f00b223SGerman Gomez }
23320f00b223SGerman Gomez
23330f00b223SGerman Gomez out:
23340f00b223SGerman Gomez return sysfs_emit(buf, "%d\n", val);
23350f00b223SGerman Gomez }
23360f00b223SGerman Gomez static DEVICE_ATTR_RO(ts_source);
23370f00b223SGerman Gomez
2338a77de263SMathieu Poirier static struct attribute *coresight_etmv4_attrs[] = {
2339a77de263SMathieu Poirier &dev_attr_nr_pe_cmp.attr,
2340a77de263SMathieu Poirier &dev_attr_nr_addr_cmp.attr,
2341a77de263SMathieu Poirier &dev_attr_nr_cntr.attr,
2342a77de263SMathieu Poirier &dev_attr_nr_ext_inp.attr,
2343a77de263SMathieu Poirier &dev_attr_numcidc.attr,
2344a77de263SMathieu Poirier &dev_attr_numvmidc.attr,
2345a77de263SMathieu Poirier &dev_attr_nrseqstate.attr,
2346a77de263SMathieu Poirier &dev_attr_nr_resource.attr,
2347a77de263SMathieu Poirier &dev_attr_nr_ss_cmp.attr,
2348a77de263SMathieu Poirier &dev_attr_reset.attr,
2349a77de263SMathieu Poirier &dev_attr_mode.attr,
2350a77de263SMathieu Poirier &dev_attr_pe.attr,
2351a77de263SMathieu Poirier &dev_attr_event.attr,
2352a77de263SMathieu Poirier &dev_attr_event_instren.attr,
2353a77de263SMathieu Poirier &dev_attr_event_ts.attr,
2354a77de263SMathieu Poirier &dev_attr_syncfreq.attr,
2355a77de263SMathieu Poirier &dev_attr_cyc_threshold.attr,
2356a77de263SMathieu Poirier &dev_attr_bb_ctrl.attr,
2357a77de263SMathieu Poirier &dev_attr_event_vinst.attr,
2358a77de263SMathieu Poirier &dev_attr_s_exlevel_vinst.attr,
2359a77de263SMathieu Poirier &dev_attr_ns_exlevel_vinst.attr,
2360a77de263SMathieu Poirier &dev_attr_addr_idx.attr,
2361a77de263SMathieu Poirier &dev_attr_addr_instdatatype.attr,
2362a77de263SMathieu Poirier &dev_attr_addr_single.attr,
2363a77de263SMathieu Poirier &dev_attr_addr_range.attr,
2364a77de263SMathieu Poirier &dev_attr_addr_start.attr,
2365a77de263SMathieu Poirier &dev_attr_addr_stop.attr,
2366a77de263SMathieu Poirier &dev_attr_addr_ctxtype.attr,
2367a77de263SMathieu Poirier &dev_attr_addr_context.attr,
236875198a7dSMike Leach &dev_attr_addr_exlevel_s_ns.attr,
2369a578427dSMike Leach &dev_attr_addr_cmp_view.attr,
23701b6b0e08SMike Leach &dev_attr_vinst_pe_cmp_start_stop.attr,
2371ebddaad0SMike Leach &dev_attr_sshot_idx.attr,
2372ebddaad0SMike Leach &dev_attr_sshot_ctrl.attr,
2373ebddaad0SMike Leach &dev_attr_sshot_pe_ctrl.attr,
2374ebddaad0SMike Leach &dev_attr_sshot_status.attr,
2375a77de263SMathieu Poirier &dev_attr_seq_idx.attr,
2376a77de263SMathieu Poirier &dev_attr_seq_state.attr,
2377a77de263SMathieu Poirier &dev_attr_seq_event.attr,
2378a77de263SMathieu Poirier &dev_attr_seq_reset_event.attr,
2379a77de263SMathieu Poirier &dev_attr_cntr_idx.attr,
2380a77de263SMathieu Poirier &dev_attr_cntrldvr.attr,
2381a77de263SMathieu Poirier &dev_attr_cntr_val.attr,
2382a77de263SMathieu Poirier &dev_attr_cntr_ctrl.attr,
2383a77de263SMathieu Poirier &dev_attr_res_idx.attr,
2384a77de263SMathieu Poirier &dev_attr_res_ctrl.attr,
2385a77de263SMathieu Poirier &dev_attr_ctxid_idx.attr,
2386a77de263SMathieu Poirier &dev_attr_ctxid_pid.attr,
2387a77de263SMathieu Poirier &dev_attr_ctxid_masks.attr,
2388a77de263SMathieu Poirier &dev_attr_vmid_idx.attr,
2389a77de263SMathieu Poirier &dev_attr_vmid_val.attr,
2390a77de263SMathieu Poirier &dev_attr_vmid_masks.attr,
2391a77de263SMathieu Poirier &dev_attr_cpu.attr,
23920f00b223SGerman Gomez &dev_attr_ts_source.attr,
2393a77de263SMathieu Poirier NULL,
2394a77de263SMathieu Poirier };
2395a77de263SMathieu Poirier
2396df487120SMike Leach /*
2397df487120SMike Leach * Trace ID allocated dynamically on enable - but also allocate on read
2398df487120SMike Leach * in case sysfs or perf read before enable to ensure consistent metadata
2399df487120SMike Leach * information for trace decode
2400df487120SMike Leach */
trctraceid_show(struct device * dev,struct device_attribute * attr,char * buf)2401df487120SMike Leach static ssize_t trctraceid_show(struct device *dev,
2402df487120SMike Leach struct device_attribute *attr,
2403df487120SMike Leach char *buf)
2404df487120SMike Leach {
2405df487120SMike Leach int trace_id;
2406df487120SMike Leach struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
2407df487120SMike Leach
2408df487120SMike Leach trace_id = etm4_read_alloc_trace_id(drvdata);
2409df487120SMike Leach if (trace_id < 0)
2410df487120SMike Leach return trace_id;
2411df487120SMike Leach
2412df487120SMike Leach return sysfs_emit(buf, "0x%x\n", trace_id);
2413df487120SMike Leach }
2414df487120SMike Leach
24153224dcc5SSudeep Holla struct etmv4_reg {
2416f5bd5236SSuzuki K Poulose struct coresight_device *csdev;
2417f5bd5236SSuzuki K Poulose u32 offset;
24183224dcc5SSudeep Holla u32 data;
24193224dcc5SSudeep Holla };
2420a77de263SMathieu Poirier
do_smp_cross_read(void * data)24213224dcc5SSudeep Holla static void do_smp_cross_read(void *data)
24223224dcc5SSudeep Holla {
24233224dcc5SSudeep Holla struct etmv4_reg *reg = data;
24243224dcc5SSudeep Holla
2425f5bd5236SSuzuki K Poulose reg->data = etm4x_relaxed_read32(®->csdev->access, reg->offset);
24263224dcc5SSudeep Holla }
24273224dcc5SSudeep Holla
etmv4_cross_read(const struct etmv4_drvdata * drvdata,u32 offset)2428c03ceec1SSuzuki K Poulose static u32 etmv4_cross_read(const struct etmv4_drvdata *drvdata, u32 offset)
24293224dcc5SSudeep Holla {
24303224dcc5SSudeep Holla struct etmv4_reg reg;
24313224dcc5SSudeep Holla
2432f5bd5236SSuzuki K Poulose reg.offset = offset;
2433f5bd5236SSuzuki K Poulose reg.csdev = drvdata->csdev;
2434f5bd5236SSuzuki K Poulose
24353224dcc5SSudeep Holla /*
24363224dcc5SSudeep Holla * smp cross call ensures the CPU will be powered up before
24373224dcc5SSudeep Holla * accessing the ETMv4 trace core registers
24383224dcc5SSudeep Holla */
24393224dcc5SSudeep Holla smp_call_function_single(drvdata->cpu, do_smp_cross_read, ®, 1);
24403224dcc5SSudeep Holla return reg.data;
24413224dcc5SSudeep Holla }
24423224dcc5SSudeep Holla
coresight_etm4x_attr_to_offset(struct device_attribute * attr)2443c03ceec1SSuzuki K Poulose static inline u32 coresight_etm4x_attr_to_offset(struct device_attribute *attr)
2444c03ceec1SSuzuki K Poulose {
2445c03ceec1SSuzuki K Poulose struct dev_ext_attribute *eattr;
24463224dcc5SSudeep Holla
2447c03ceec1SSuzuki K Poulose eattr = container_of(attr, struct dev_ext_attribute, attr);
2448c03ceec1SSuzuki K Poulose return (u32)(unsigned long)eattr->var;
2449c03ceec1SSuzuki K Poulose }
2450c03ceec1SSuzuki K Poulose
coresight_etm4x_reg_show(struct device * dev,struct device_attribute * d_attr,char * buf)2451c03ceec1SSuzuki K Poulose static ssize_t coresight_etm4x_reg_show(struct device *dev,
2452c03ceec1SSuzuki K Poulose struct device_attribute *d_attr,
2453c03ceec1SSuzuki K Poulose char *buf)
2454c03ceec1SSuzuki K Poulose {
2455c03ceec1SSuzuki K Poulose u32 val, offset;
2456c03ceec1SSuzuki K Poulose struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
2457c03ceec1SSuzuki K Poulose
2458c03ceec1SSuzuki K Poulose offset = coresight_etm4x_attr_to_offset(d_attr);
2459c03ceec1SSuzuki K Poulose
2460c03ceec1SSuzuki K Poulose pm_runtime_get_sync(dev->parent);
2461c03ceec1SSuzuki K Poulose val = etmv4_cross_read(drvdata, offset);
2462c03ceec1SSuzuki K Poulose pm_runtime_put_sync(dev->parent);
2463c03ceec1SSuzuki K Poulose
2464c03ceec1SSuzuki K Poulose return scnprintf(buf, PAGE_SIZE, "0x%x\n", val);
2465c03ceec1SSuzuki K Poulose }
2466c03ceec1SSuzuki K Poulose
246791b9f018SSuzuki K Poulose static inline bool
etm4x_register_implemented(struct etmv4_drvdata * drvdata,u32 offset)246891b9f018SSuzuki K Poulose etm4x_register_implemented(struct etmv4_drvdata *drvdata, u32 offset)
246991b9f018SSuzuki K Poulose {
247091b9f018SSuzuki K Poulose switch (offset) {
247135e1c916SSuzuki K Poulose ETM_COMMON_SYSREG_LIST_CASES
247291b9f018SSuzuki K Poulose /*
247335e1c916SSuzuki K Poulose * Common registers to ETE & ETM4x accessible via system
247435e1c916SSuzuki K Poulose * instructions are always implemented.
247591b9f018SSuzuki K Poulose */
247691b9f018SSuzuki K Poulose return true;
247735e1c916SSuzuki K Poulose
247835e1c916SSuzuki K Poulose ETM4x_ONLY_SYSREG_LIST_CASES
247935e1c916SSuzuki K Poulose /*
248035e1c916SSuzuki K Poulose * We only support etm4x and ete. So if the device is not
248135e1c916SSuzuki K Poulose * ETE, it must be ETMv4x.
248235e1c916SSuzuki K Poulose */
248335e1c916SSuzuki K Poulose return !etm4x_is_ete(drvdata);
248435e1c916SSuzuki K Poulose
248591b9f018SSuzuki K Poulose ETM4x_MMAP_LIST_CASES
248691b9f018SSuzuki K Poulose /*
248791b9f018SSuzuki K Poulose * Registers accessible only via memory-mapped registers
248891b9f018SSuzuki K Poulose * must not be accessed via system instructions.
248991b9f018SSuzuki K Poulose * We cannot access the drvdata->csdev here, as this
249091b9f018SSuzuki K Poulose * function is called during the device creation, via
249191b9f018SSuzuki K Poulose * coresight_register() and the csdev is not initialized
249291b9f018SSuzuki K Poulose * until that is done. So rely on the drvdata->base to
249391b9f018SSuzuki K Poulose * detect if we have a memory mapped access.
249435e1c916SSuzuki K Poulose * Also ETE doesn't implement memory mapped access, thus
249535e1c916SSuzuki K Poulose * it is sufficient to check that we are using mmio.
249691b9f018SSuzuki K Poulose */
249791b9f018SSuzuki K Poulose return !!drvdata->base;
249835e1c916SSuzuki K Poulose
249935e1c916SSuzuki K Poulose ETE_ONLY_SYSREG_LIST_CASES
250035e1c916SSuzuki K Poulose return etm4x_is_ete(drvdata);
250191b9f018SSuzuki K Poulose }
250291b9f018SSuzuki K Poulose
250391b9f018SSuzuki K Poulose return false;
250491b9f018SSuzuki K Poulose }
250591b9f018SSuzuki K Poulose
250691b9f018SSuzuki K Poulose /*
250791b9f018SSuzuki K Poulose * Hide the ETM4x registers that may not be available on the
250891b9f018SSuzuki K Poulose * hardware.
250991b9f018SSuzuki K Poulose * There are certain management registers unavailable via system
251091b9f018SSuzuki K Poulose * instructions. Make those sysfs attributes hidden on such
251191b9f018SSuzuki K Poulose * systems.
251291b9f018SSuzuki K Poulose */
251391b9f018SSuzuki K Poulose static umode_t
coresight_etm4x_attr_reg_implemented(struct kobject * kobj,struct attribute * attr,int unused)251491b9f018SSuzuki K Poulose coresight_etm4x_attr_reg_implemented(struct kobject *kobj,
251591b9f018SSuzuki K Poulose struct attribute *attr, int unused)
251691b9f018SSuzuki K Poulose {
251791b9f018SSuzuki K Poulose struct device *dev = kobj_to_dev(kobj);
251891b9f018SSuzuki K Poulose struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
251991b9f018SSuzuki K Poulose struct device_attribute *d_attr;
252091b9f018SSuzuki K Poulose u32 offset;
252191b9f018SSuzuki K Poulose
252291b9f018SSuzuki K Poulose d_attr = container_of(attr, struct device_attribute, attr);
252391b9f018SSuzuki K Poulose offset = coresight_etm4x_attr_to_offset(d_attr);
252491b9f018SSuzuki K Poulose
252591b9f018SSuzuki K Poulose if (etm4x_register_implemented(drvdata, offset))
252691b9f018SSuzuki K Poulose return attr->mode;
252791b9f018SSuzuki K Poulose return 0;
252891b9f018SSuzuki K Poulose }
252991b9f018SSuzuki K Poulose
2530*9f37d379SMike Leach /*
2531*9f37d379SMike Leach * Macro to set an RO ext attribute with offset and show function.
2532*9f37d379SMike Leach * Offset is used in mgmt group to ensure only correct registers for
2533*9f37d379SMike Leach * the ETM / ETE variant are visible.
2534*9f37d379SMike Leach */
2535*9f37d379SMike Leach #define coresight_etm4x_reg_showfn(name, offset, showfn) ( \
2536c03ceec1SSuzuki K Poulose &((struct dev_ext_attribute[]) { \
2537c03ceec1SSuzuki K Poulose { \
2538*9f37d379SMike Leach __ATTR(name, 0444, showfn, NULL), \
2539c03ceec1SSuzuki K Poulose (void *)(unsigned long)offset \
2540c03ceec1SSuzuki K Poulose } \
2541*9f37d379SMike Leach })[0].attr.attr \
2542*9f37d379SMike Leach )
2543*9f37d379SMike Leach
2544*9f37d379SMike Leach /* macro using the default coresight_etm4x_reg_show function */
2545*9f37d379SMike Leach #define coresight_etm4x_reg(name, offset) \
2546*9f37d379SMike Leach coresight_etm4x_reg_showfn(name, offset, coresight_etm4x_reg_show)
2547a77de263SMathieu Poirier
2548a77de263SMathieu Poirier static struct attribute *coresight_etmv4_mgmt_attrs[] = {
2549c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcpdcr, TRCPDCR),
2550c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcpdsr, TRCPDSR),
2551c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trclsr, TRCLSR),
2552c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcauthstatus, TRCAUTHSTATUS),
2553c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcdevid, TRCDEVID),
2554c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcdevtype, TRCDEVTYPE),
2555c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcpidr0, TRCPIDR0),
2556c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcpidr1, TRCPIDR1),
2557c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcpidr2, TRCPIDR2),
2558c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcpidr3, TRCPIDR3),
2559c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcoslsr, TRCOSLSR),
2560c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcconfig, TRCCONFIGR),
2561*9f37d379SMike Leach coresight_etm4x_reg_showfn(trctraceid, TRCTRACEIDR, trctraceid_show),
25624211bfceSSuzuki K Poulose coresight_etm4x_reg(trcdevarch, TRCDEVARCH),
2563a77de263SMathieu Poirier NULL,
2564a77de263SMathieu Poirier };
2565a77de263SMathieu Poirier
2566a77de263SMathieu Poirier static struct attribute *coresight_etmv4_trcidr_attrs[] = {
2567c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr0, TRCIDR0),
2568c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr1, TRCIDR1),
2569c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr2, TRCIDR2),
2570c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr3, TRCIDR3),
2571c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr4, TRCIDR4),
2572c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr5, TRCIDR5),
2573a77de263SMathieu Poirier /* trcidr[6,7] are reserved */
2574c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr8, TRCIDR8),
2575c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr9, TRCIDR9),
2576c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr10, TRCIDR10),
2577c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr11, TRCIDR11),
2578c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr12, TRCIDR12),
2579c03ceec1SSuzuki K Poulose coresight_etm4x_reg(trcidr13, TRCIDR13),
2580a77de263SMathieu Poirier NULL,
2581a77de263SMathieu Poirier };
2582a77de263SMathieu Poirier
2583a77de263SMathieu Poirier static const struct attribute_group coresight_etmv4_group = {
2584a77de263SMathieu Poirier .attrs = coresight_etmv4_attrs,
2585a77de263SMathieu Poirier };
2586a77de263SMathieu Poirier
2587a77de263SMathieu Poirier static const struct attribute_group coresight_etmv4_mgmt_group = {
258891b9f018SSuzuki K Poulose .is_visible = coresight_etm4x_attr_reg_implemented,
2589a77de263SMathieu Poirier .attrs = coresight_etmv4_mgmt_attrs,
2590a77de263SMathieu Poirier .name = "mgmt",
2591a77de263SMathieu Poirier };
2592a77de263SMathieu Poirier
2593a77de263SMathieu Poirier static const struct attribute_group coresight_etmv4_trcidr_group = {
2594a77de263SMathieu Poirier .attrs = coresight_etmv4_trcidr_attrs,
2595a77de263SMathieu Poirier .name = "trcidr",
2596a77de263SMathieu Poirier };
2597a77de263SMathieu Poirier
2598a77de263SMathieu Poirier const struct attribute_group *coresight_etmv4_groups[] = {
2599a77de263SMathieu Poirier &coresight_etmv4_group,
2600a77de263SMathieu Poirier &coresight_etmv4_mgmt_group,
2601a77de263SMathieu Poirier &coresight_etmv4_trcidr_group,
2602a77de263SMathieu Poirier NULL,
2603a77de263SMathieu Poirier };
2604