]>
Commit | Line | Data |
---|---|---|
ad0dfdfd MP |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (c) 2014, The Linux Foundation. All rights reserved. | |
2e1cdfe1 PP |
4 | */ |
5 | ||
e7255092 | 6 | #include <linux/bitops.h> |
2e1cdfe1 PP |
7 | #include <linux/kernel.h> |
8 | #include <linux/moduleparam.h> | |
9 | #include <linux/init.h> | |
10 | #include <linux/types.h> | |
11 | #include <linux/device.h> | |
12 | #include <linux/io.h> | |
13 | #include <linux/err.h> | |
14 | #include <linux/fs.h> | |
15 | #include <linux/slab.h> | |
16 | #include <linux/delay.h> | |
17 | #include <linux/smp.h> | |
18 | #include <linux/sysfs.h> | |
19 | #include <linux/stat.h> | |
20 | #include <linux/clk.h> | |
21 | #include <linux/cpu.h> | |
f188b5e7 | 22 | #include <linux/cpu_pm.h> |
2e1cdfe1 | 23 | #include <linux/coresight.h> |
fc208abe | 24 | #include <linux/coresight-pmu.h> |
2e1cdfe1 PP |
25 | #include <linux/pm_wakeup.h> |
26 | #include <linux/amba/bus.h> | |
27 | #include <linux/seq_file.h> | |
28 | #include <linux/uaccess.h> | |
37fbbdbd | 29 | #include <linux/perf_event.h> |
2e1cdfe1 | 30 | #include <linux/pm_runtime.h> |
f188b5e7 | 31 | #include <linux/property.h> |
e7255092 | 32 | |
2e1cdfe1 | 33 | #include <asm/sections.h> |
e7255092 | 34 | #include <asm/sysreg.h> |
c38a9ec2 | 35 | #include <asm/local.h> |
b860801e | 36 | #include <asm/virt.h> |
2e1cdfe1 PP |
37 | |
38 | #include "coresight-etm4x.h" | |
37fbbdbd | 39 | #include "coresight-etm-perf.h" |
2e1cdfe1 PP |
40 | |
41 | static int boot_enable; | |
08d2ddaa AM |
42 | module_param(boot_enable, int, 0444); |
43 | MODULE_PARM_DESC(boot_enable, "Enable tracing on boot"); | |
2e1cdfe1 | 44 | |
f188b5e7 AM |
45 | #define PARAM_PM_SAVE_FIRMWARE 0 /* save self-hosted state as per firmware */ |
46 | #define PARAM_PM_SAVE_NEVER 1 /* never save any state */ | |
47 | #define PARAM_PM_SAVE_SELF_HOSTED 2 /* save self-hosted state only */ | |
48 | ||
49 | static int pm_save_enable = PARAM_PM_SAVE_FIRMWARE; | |
50 | module_param(pm_save_enable, int, 0444); | |
51 | MODULE_PARM_DESC(pm_save_enable, | |
52 | "Save/restore state on power down: 1 = never, 2 = self-hosted"); | |
53 | ||
2e1cdfe1 | 54 | static struct etmv4_drvdata *etmdrvdata[NR_CPUS]; |
2703d74c MP |
55 | static void etm4_set_default_config(struct etmv4_config *config); |
56 | static int etm4_set_event_filters(struct etmv4_drvdata *drvdata, | |
57 | struct perf_event *event); | |
096dcfb9 | 58 | static u64 etm4_get_access_type(struct etmv4_config *config); |
2e1cdfe1 | 59 | |
58eb457b SAS |
60 | static enum cpuhp_state hp_online; |
61 | ||
66bbbb77 | 62 | static void etm4_os_unlock(struct etmv4_drvdata *drvdata) |
2e1cdfe1 | 63 | { |
89e89b05 | 64 | /* Writing 0 to TRCOSLAR unlocks the trace registers */ |
2e1cdfe1 | 65 | writel_relaxed(0x0, drvdata->base + TRCOSLAR); |
66bbbb77 | 66 | drvdata->os_unlock = true; |
2e1cdfe1 PP |
67 | isb(); |
68 | } | |
69 | ||
f188b5e7 AM |
70 | static void etm4_os_lock(struct etmv4_drvdata *drvdata) |
71 | { | |
72 | /* Writing 0x1 to TRCOSLAR locks the trace registers */ | |
73 | writel_relaxed(0x1, drvdata->base + TRCOSLAR); | |
74 | drvdata->os_unlock = false; | |
75 | isb(); | |
76 | } | |
77 | ||
2e1cdfe1 PP |
78 | static bool etm4_arch_supported(u8 arch) |
79 | { | |
5666dfd1 SPR |
80 | /* Mask out the minor version number */ |
81 | switch (arch & 0xf0) { | |
2e1cdfe1 PP |
82 | case ETM_ARCH_V4: |
83 | break; | |
84 | default: | |
85 | return false; | |
86 | } | |
87 | return true; | |
88 | } | |
89 | ||
52210c87 MP |
90 | static int etm4_cpu_id(struct coresight_device *csdev) |
91 | { | |
92 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | |
93 | ||
94 | return drvdata->cpu; | |
95 | } | |
96 | ||
2e1cdfe1 PP |
97 | static int etm4_trace_id(struct coresight_device *csdev) |
98 | { | |
99 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | |
2e1cdfe1 | 100 | |
b1149ad9 | 101 | return drvdata->trcid; |
2e1cdfe1 PP |
102 | } |
103 | ||
e006d89a SP |
104 | struct etm4_enable_arg { |
105 | struct etmv4_drvdata *drvdata; | |
106 | int rc; | |
107 | }; | |
108 | ||
e7255092 QL |
109 | #ifdef CONFIG_ETM4X_IMPDEF_FEATURE |
110 | ||
111 | #define HISI_HIP08_AMBA_ID 0x000b6d01 | |
112 | #define ETM4_AMBA_MASK 0xfffff | |
113 | #define HISI_HIP08_CORE_COMMIT_MASK 0x3000 | |
114 | #define HISI_HIP08_CORE_COMMIT_SHIFT 12 | |
115 | #define HISI_HIP08_CORE_COMMIT_FULL 0b00 | |
116 | #define HISI_HIP08_CORE_COMMIT_LVL_1 0b01 | |
117 | #define HISI_HIP08_CORE_COMMIT_REG sys_reg(3, 1, 15, 2, 5) | |
118 | ||
119 | struct etm4_arch_features { | |
120 | void (*arch_callback)(bool enable); | |
121 | }; | |
122 | ||
123 | static bool etm4_hisi_match_pid(unsigned int id) | |
124 | { | |
125 | return (id & ETM4_AMBA_MASK) == HISI_HIP08_AMBA_ID; | |
126 | } | |
127 | ||
128 | static void etm4_hisi_config_core_commit(bool enable) | |
129 | { | |
130 | u8 commit = enable ? HISI_HIP08_CORE_COMMIT_LVL_1 : | |
131 | HISI_HIP08_CORE_COMMIT_FULL; | |
132 | u64 val; | |
133 | ||
134 | /* | |
135 | * bit 12 and 13 of HISI_HIP08_CORE_COMMIT_REG are used together | |
136 | * to set core-commit, 2'b00 means cpu is at full speed, 2'b01, | |
137 | * 2'b10, 2'b11 mean reduce pipeline speed, and 2'b01 means level-1 | |
138 | * speed(minimun value). So bit 12 and 13 should be cleared together. | |
139 | */ | |
140 | val = read_sysreg_s(HISI_HIP08_CORE_COMMIT_REG); | |
141 | val &= ~HISI_HIP08_CORE_COMMIT_MASK; | |
142 | val |= commit << HISI_HIP08_CORE_COMMIT_SHIFT; | |
143 | write_sysreg_s(val, HISI_HIP08_CORE_COMMIT_REG); | |
144 | } | |
145 | ||
146 | static struct etm4_arch_features etm4_features[] = { | |
147 | [ETM4_IMPDEF_HISI_CORE_COMMIT] = { | |
148 | .arch_callback = etm4_hisi_config_core_commit, | |
149 | }, | |
150 | {}, | |
151 | }; | |
152 | ||
153 | static void etm4_enable_arch_specific(struct etmv4_drvdata *drvdata) | |
154 | { | |
155 | struct etm4_arch_features *ftr; | |
156 | int bit; | |
157 | ||
158 | for_each_set_bit(bit, drvdata->arch_features, ETM4_IMPDEF_FEATURE_MAX) { | |
159 | ftr = &etm4_features[bit]; | |
160 | ||
161 | if (ftr->arch_callback) | |
162 | ftr->arch_callback(true); | |
163 | } | |
164 | } | |
165 | ||
166 | static void etm4_disable_arch_specific(struct etmv4_drvdata *drvdata) | |
167 | { | |
168 | struct etm4_arch_features *ftr; | |
169 | int bit; | |
170 | ||
171 | for_each_set_bit(bit, drvdata->arch_features, ETM4_IMPDEF_FEATURE_MAX) { | |
172 | ftr = &etm4_features[bit]; | |
173 | ||
174 | if (ftr->arch_callback) | |
175 | ftr->arch_callback(false); | |
176 | } | |
177 | } | |
178 | ||
179 | static void etm4_check_arch_features(struct etmv4_drvdata *drvdata, | |
180 | unsigned int id) | |
181 | { | |
182 | if (etm4_hisi_match_pid(id)) | |
183 | set_bit(ETM4_IMPDEF_HISI_CORE_COMMIT, drvdata->arch_features); | |
184 | } | |
185 | #else | |
186 | static void etm4_enable_arch_specific(struct etmv4_drvdata *drvdata) | |
187 | { | |
188 | } | |
189 | ||
190 | static void etm4_disable_arch_specific(struct etmv4_drvdata *drvdata) | |
191 | { | |
192 | } | |
193 | ||
194 | static void etm4_check_arch_features(struct etmv4_drvdata *drvdata, | |
195 | unsigned int id) | |
196 | { | |
197 | } | |
198 | #endif /* CONFIG_ETM4X_IMPDEF_FEATURE */ | |
199 | ||
e006d89a | 200 | static int etm4_enable_hw(struct etmv4_drvdata *drvdata) |
2e1cdfe1 | 201 | { |
68a14775 | 202 | int i, rc; |
54ff892b | 203 | struct etmv4_config *config = &drvdata->config; |
aaff7623 | 204 | struct device *etm_dev = &drvdata->csdev->dev; |
2e1cdfe1 PP |
205 | |
206 | CS_UNLOCK(drvdata->base); | |
e7255092 | 207 | etm4_enable_arch_specific(drvdata); |
2e1cdfe1 PP |
208 | |
209 | etm4_os_unlock(drvdata); | |
210 | ||
68a14775 SP |
211 | rc = coresight_claim_device_unlocked(drvdata->base); |
212 | if (rc) | |
213 | goto done; | |
214 | ||
2e1cdfe1 PP |
215 | /* Disable the trace unit before programming trace registers */ |
216 | writel_relaxed(0, drvdata->base + TRCPRGCTLR); | |
217 | ||
218 | /* wait for TRCSTATR.IDLE to go up */ | |
219 | if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 1)) | |
aaff7623 | 220 | dev_err(etm_dev, |
67337e8d | 221 | "timeout while waiting for Idle Trace Status\n"); |
6288b4ce SP |
222 | if (drvdata->nr_pe) |
223 | writel_relaxed(config->pe_sel, drvdata->base + TRCPROCSELR); | |
54ff892b | 224 | writel_relaxed(config->cfg, drvdata->base + TRCCONFIGR); |
2e1cdfe1 PP |
225 | /* nothing specific implemented */ |
226 | writel_relaxed(0x0, drvdata->base + TRCAUXCTLR); | |
54ff892b MP |
227 | writel_relaxed(config->eventctrl0, drvdata->base + TRCEVENTCTL0R); |
228 | writel_relaxed(config->eventctrl1, drvdata->base + TRCEVENTCTL1R); | |
229 | writel_relaxed(config->stall_ctrl, drvdata->base + TRCSTALLCTLR); | |
230 | writel_relaxed(config->ts_ctrl, drvdata->base + TRCTSCTLR); | |
231 | writel_relaxed(config->syncfreq, drvdata->base + TRCSYNCPR); | |
232 | writel_relaxed(config->ccctlr, drvdata->base + TRCCCCTLR); | |
233 | writel_relaxed(config->bb_ctrl, drvdata->base + TRCBBCTLR); | |
2e1cdfe1 | 234 | writel_relaxed(drvdata->trcid, drvdata->base + TRCTRACEIDR); |
54ff892b MP |
235 | writel_relaxed(config->vinst_ctrl, drvdata->base + TRCVICTLR); |
236 | writel_relaxed(config->viiectlr, drvdata->base + TRCVIIECTLR); | |
237 | writel_relaxed(config->vissctlr, | |
2e1cdfe1 | 238 | drvdata->base + TRCVISSCTLR); |
60c519c5 SP |
239 | if (drvdata->nr_pe_cmp) |
240 | writel_relaxed(config->vipcssctlr, | |
241 | drvdata->base + TRCVIPCSSCTLR); | |
2e1cdfe1 | 242 | for (i = 0; i < drvdata->nrseqstate - 1; i++) |
54ff892b | 243 | writel_relaxed(config->seq_ctrl[i], |
2e1cdfe1 | 244 | drvdata->base + TRCSEQEVRn(i)); |
54ff892b MP |
245 | writel_relaxed(config->seq_rst, drvdata->base + TRCSEQRSTEVR); |
246 | writel_relaxed(config->seq_state, drvdata->base + TRCSEQSTR); | |
247 | writel_relaxed(config->ext_inp, drvdata->base + TRCEXTINSELR); | |
2e1cdfe1 | 248 | for (i = 0; i < drvdata->nr_cntr; i++) { |
54ff892b | 249 | writel_relaxed(config->cntrldvr[i], |
2e1cdfe1 | 250 | drvdata->base + TRCCNTRLDVRn(i)); |
54ff892b | 251 | writel_relaxed(config->cntr_ctrl[i], |
2e1cdfe1 | 252 | drvdata->base + TRCCNTCTLRn(i)); |
54ff892b | 253 | writel_relaxed(config->cntr_val[i], |
2e1cdfe1 PP |
254 | drvdata->base + TRCCNTVRn(i)); |
255 | } | |
497b5956 | 256 | |
8013f32a MP |
257 | /* |
258 | * Resource selector pair 0 is always implemented and reserved. As | |
259 | * such start at 2. | |
260 | */ | |
261 | for (i = 2; i < drvdata->nr_resource * 2; i++) | |
54ff892b | 262 | writel_relaxed(config->res_ctrl[i], |
2e1cdfe1 PP |
263 | drvdata->base + TRCRSCTLRn(i)); |
264 | ||
265 | for (i = 0; i < drvdata->nr_ss_cmp; i++) { | |
ebddaad0 ML |
266 | /* always clear status bit on restart if using single-shot */ |
267 | if (config->ss_ctrl[i] || config->ss_pe_cmp[i]) | |
268 | config->ss_status[i] &= ~BIT(31); | |
54ff892b | 269 | writel_relaxed(config->ss_ctrl[i], |
2e1cdfe1 | 270 | drvdata->base + TRCSSCCRn(i)); |
54ff892b | 271 | writel_relaxed(config->ss_status[i], |
2e1cdfe1 | 272 | drvdata->base + TRCSSCSRn(i)); |
54ff892b | 273 | writel_relaxed(config->ss_pe_cmp[i], |
2e1cdfe1 PP |
274 | drvdata->base + TRCSSPCICRn(i)); |
275 | } | |
276 | for (i = 0; i < drvdata->nr_addr_cmp; i++) { | |
54ff892b | 277 | writeq_relaxed(config->addr_val[i], |
2e1cdfe1 | 278 | drvdata->base + TRCACVRn(i)); |
54ff892b | 279 | writeq_relaxed(config->addr_acc[i], |
2e1cdfe1 PP |
280 | drvdata->base + TRCACATRn(i)); |
281 | } | |
282 | for (i = 0; i < drvdata->numcidc; i++) | |
54ff892b | 283 | writeq_relaxed(config->ctxid_pid[i], |
2e1cdfe1 | 284 | drvdata->base + TRCCIDCVRn(i)); |
54ff892b | 285 | writel_relaxed(config->ctxid_mask0, drvdata->base + TRCCIDCCTLR0); |
f2603b22 SP |
286 | if (drvdata->numcidc > 4) |
287 | writel_relaxed(config->ctxid_mask1, drvdata->base + TRCCIDCCTLR1); | |
2e1cdfe1 PP |
288 | |
289 | for (i = 0; i < drvdata->numvmidc; i++) | |
54ff892b | 290 | writeq_relaxed(config->vmid_val[i], |
2e1cdfe1 | 291 | drvdata->base + TRCVMIDCVRn(i)); |
54ff892b | 292 | writel_relaxed(config->vmid_mask0, drvdata->base + TRCVMIDCCTLR0); |
93dd6440 SP |
293 | if (drvdata->numvmidc > 4) |
294 | writel_relaxed(config->vmid_mask1, drvdata->base + TRCVMIDCCTLR1); | |
2e1cdfe1 | 295 | |
02510a5a TZ |
296 | if (!drvdata->skip_power_up) { |
297 | /* | |
298 | * Request to keep the trace unit powered and also | |
299 | * emulation of powerdown | |
300 | */ | |
301 | writel_relaxed(readl_relaxed(drvdata->base + TRCPDCR) | | |
302 | TRCPDCR_PU, drvdata->base + TRCPDCR); | |
303 | } | |
46a3d5cd | 304 | |
2e1cdfe1 PP |
305 | /* Enable the trace unit */ |
306 | writel_relaxed(1, drvdata->base + TRCPRGCTLR); | |
307 | ||
308 | /* wait for TRCSTATR.IDLE to go back down to '0' */ | |
309 | if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 0)) | |
aaff7623 | 310 | dev_err(etm_dev, |
67337e8d | 311 | "timeout while waiting for Idle Trace Status\n"); |
2e1cdfe1 | 312 | |
1004ce4c AM |
313 | /* |
314 | * As recommended by section 4.3.7 ("Synchronization when using the | |
315 | * memory-mapped interface") of ARM IHI 0064D | |
316 | */ | |
317 | dsb(sy); | |
318 | isb(); | |
319 | ||
68a14775 | 320 | done: |
2e1cdfe1 PP |
321 | CS_LOCK(drvdata->base); |
322 | ||
aaff7623 | 323 | dev_dbg(etm_dev, "cpu: %d enable smp call done: %d\n", |
68a14775 SP |
324 | drvdata->cpu, rc); |
325 | return rc; | |
e006d89a SP |
326 | } |
327 | ||
328 | static void etm4_enable_hw_smp_call(void *info) | |
329 | { | |
330 | struct etm4_enable_arg *arg = info; | |
331 | ||
332 | if (WARN_ON(!arg)) | |
333 | return; | |
334 | arg->rc = etm4_enable_hw(arg->drvdata); | |
2e1cdfe1 PP |
335 | } |
336 | ||
a54e14f8 MP |
337 | /* |
338 | * The goal of function etm4_config_timestamp_event() is to configure a | |
339 | * counter that will tell the tracer to emit a timestamp packet when it | |
340 | * reaches zero. This is done in order to get a more fine grained idea | |
341 | * of when instructions are executed so that they can be correlated | |
342 | * with execution on other CPUs. | |
343 | * | |
344 | * To do this the counter itself is configured to self reload and | |
345 | * TRCRSCTLR1 (always true) used to get the counter to decrement. From | |
346 | * there a resource selector is configured with the counter and the | |
347 | * timestamp control register to use the resource selector to trigger the | |
348 | * event that will insert a timestamp packet in the stream. | |
349 | */ | |
350 | static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata) | |
351 | { | |
352 | int ctridx, ret = -EINVAL; | |
353 | int counter, rselector; | |
354 | u32 val = 0; | |
355 | struct etmv4_config *config = &drvdata->config; | |
356 | ||
357 | /* No point in trying if we don't have at least one counter */ | |
358 | if (!drvdata->nr_cntr) | |
359 | goto out; | |
360 | ||
361 | /* Find a counter that hasn't been initialised */ | |
362 | for (ctridx = 0; ctridx < drvdata->nr_cntr; ctridx++) | |
363 | if (config->cntr_val[ctridx] == 0) | |
364 | break; | |
365 | ||
366 | /* All the counters have been configured already, bail out */ | |
367 | if (ctridx == drvdata->nr_cntr) { | |
368 | pr_debug("%s: no available counter found\n", __func__); | |
369 | ret = -ENOSPC; | |
370 | goto out; | |
371 | } | |
372 | ||
373 | /* | |
374 | * Searching for an available resource selector to use, starting at | |
375 | * '2' since every implementation has at least 2 resource selector. | |
376 | * ETMIDR4 gives the number of resource selector _pairs_, | |
377 | * hence multiply by 2. | |
378 | */ | |
379 | for (rselector = 2; rselector < drvdata->nr_resource * 2; rselector++) | |
380 | if (!config->res_ctrl[rselector]) | |
381 | break; | |
382 | ||
383 | if (rselector == drvdata->nr_resource * 2) { | |
384 | pr_debug("%s: no available resource selector found\n", | |
385 | __func__); | |
386 | ret = -ENOSPC; | |
387 | goto out; | |
388 | } | |
389 | ||
390 | /* Remember what counter we used */ | |
391 | counter = 1 << ctridx; | |
392 | ||
393 | /* | |
394 | * Initialise original and reload counter value to the smallest | |
395 | * possible value in order to get as much precision as we can. | |
396 | */ | |
397 | config->cntr_val[ctridx] = 1; | |
398 | config->cntrldvr[ctridx] = 1; | |
399 | ||
400 | /* Set the trace counter control register */ | |
401 | val = 0x1 << 16 | /* Bit 16, reload counter automatically */ | |
402 | 0x0 << 7 | /* Select single resource selector */ | |
403 | 0x1; /* Resource selector 1, i.e always true */ | |
404 | ||
405 | config->cntr_ctrl[ctridx] = val; | |
406 | ||
407 | val = 0x2 << 16 | /* Group 0b0010 - Counter and sequencers */ | |
408 | counter << 0; /* Counter to use */ | |
409 | ||
410 | config->res_ctrl[rselector] = val; | |
411 | ||
412 | val = 0x0 << 7 | /* Select single resource selector */ | |
413 | rselector; /* Resource selector */ | |
414 | ||
415 | config->ts_ctrl = val; | |
416 | ||
417 | ret = 0; | |
418 | out: | |
419 | return ret; | |
420 | } | |
421 | ||
37fbbdbd | 422 | static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, |
68905d73 | 423 | struct perf_event *event) |
37fbbdbd | 424 | { |
2703d74c | 425 | int ret = 0; |
37fbbdbd | 426 | struct etmv4_config *config = &drvdata->config; |
68905d73 | 427 | struct perf_event_attr *attr = &event->attr; |
37fbbdbd | 428 | |
2703d74c MP |
429 | if (!attr) { |
430 | ret = -EINVAL; | |
431 | goto out; | |
432 | } | |
37fbbdbd MP |
433 | |
434 | /* Clear configuration from previous run */ | |
435 | memset(config, 0, sizeof(struct etmv4_config)); | |
436 | ||
437 | if (attr->exclude_kernel) | |
438 | config->mode = ETM_MODE_EXCL_KERN; | |
439 | ||
440 | if (attr->exclude_user) | |
441 | config->mode = ETM_MODE_EXCL_USER; | |
442 | ||
443 | /* Always start from the default config */ | |
2703d74c MP |
444 | etm4_set_default_config(config); |
445 | ||
446 | /* Configure filters specified on the perf cmd line, if any. */ | |
447 | ret = etm4_set_event_filters(drvdata, event); | |
448 | if (ret) | |
449 | goto out; | |
37fbbdbd | 450 | |
37fbbdbd | 451 | /* Go from generic option to ETMv4 specifics */ |
ae3fabcd ML |
452 | if (attr->config & BIT(ETM_OPT_CYCACC)) { |
453 | config->cfg |= BIT(4); | |
454 | /* TRM: Must program this for cycacc to work */ | |
455 | config->ccctlr = ETM_CYC_THRESHOLD_DEFAULT; | |
456 | } | |
a54e14f8 MP |
457 | if (attr->config & BIT(ETM_OPT_TS)) { |
458 | /* | |
459 | * Configure timestamps to be emitted at regular intervals in | |
460 | * order to correlate instructions executed on different CPUs | |
461 | * (CPU-wide trace scenarios). | |
462 | */ | |
463 | ret = etm4_config_timestamp_event(drvdata); | |
464 | ||
465 | /* | |
466 | * No need to go further if timestamp intervals can't | |
467 | * be configured. | |
468 | */ | |
469 | if (ret) | |
470 | goto out; | |
471 | ||
27a7e2a7 MP |
472 | /* bit[11], Global timestamp tracing bit */ |
473 | config->cfg |= BIT(11); | |
a54e14f8 | 474 | } |
82500a81 MP |
475 | |
476 | if (attr->config & BIT(ETM_OPT_CTXTID)) | |
477 | /* bit[6], Context ID tracing bit */ | |
478 | config->cfg |= BIT(ETM4_CFG_BIT_CTXTID); | |
479 | ||
27b8f667 ML |
480 | /* return stack - enable if selected and supported */ |
481 | if ((attr->config & BIT(ETM_OPT_RETSTK)) && drvdata->retstack) | |
482 | /* bit[12], Return stack enable bit */ | |
483 | config->cfg |= BIT(12); | |
37fbbdbd | 484 | |
2703d74c MP |
485 | out: |
486 | return ret; | |
37fbbdbd MP |
487 | } |
488 | ||
489 | static int etm4_enable_perf(struct coresight_device *csdev, | |
68905d73 | 490 | struct perf_event *event) |
37fbbdbd | 491 | { |
2703d74c | 492 | int ret = 0; |
37fbbdbd MP |
493 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
494 | ||
2703d74c MP |
495 | if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) { |
496 | ret = -EINVAL; | |
497 | goto out; | |
498 | } | |
37fbbdbd MP |
499 | |
500 | /* Configure the tracer based on the session's specifics */ | |
2703d74c MP |
501 | ret = etm4_parse_event_config(drvdata, event); |
502 | if (ret) | |
503 | goto out; | |
37fbbdbd | 504 | /* And enable it */ |
e006d89a | 505 | ret = etm4_enable_hw(drvdata); |
37fbbdbd | 506 | |
2703d74c MP |
507 | out: |
508 | return ret; | |
37fbbdbd MP |
509 | } |
510 | ||
c38a9ec2 | 511 | static int etm4_enable_sysfs(struct coresight_device *csdev) |
2e1cdfe1 PP |
512 | { |
513 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | |
bab223f9 | 514 | struct etm4_enable_arg arg = { }; |
2e1cdfe1 PP |
515 | int ret; |
516 | ||
2e1cdfe1 PP |
517 | spin_lock(&drvdata->spinlock); |
518 | ||
519 | /* | |
520 | * Executing etm4_enable_hw on the cpu whose ETM is being enabled | |
521 | * ensures that register writes occur when cpu is powered. | |
522 | */ | |
e006d89a | 523 | arg.drvdata = drvdata; |
2e1cdfe1 | 524 | ret = smp_call_function_single(drvdata->cpu, |
e006d89a SP |
525 | etm4_enable_hw_smp_call, &arg, 1); |
526 | if (!ret) | |
527 | ret = arg.rc; | |
528 | if (!ret) | |
529 | drvdata->sticky_enable = true; | |
2e1cdfe1 PP |
530 | spin_unlock(&drvdata->spinlock); |
531 | ||
e006d89a | 532 | if (!ret) |
aaff7623 | 533 | dev_dbg(&csdev->dev, "ETM tracing enabled\n"); |
2e1cdfe1 PP |
534 | return ret; |
535 | } | |
536 | ||
c38a9ec2 | 537 | static int etm4_enable(struct coresight_device *csdev, |
68905d73 | 538 | struct perf_event *event, u32 mode) |
c38a9ec2 MP |
539 | { |
540 | int ret; | |
541 | u32 val; | |
542 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | |
543 | ||
544 | val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); | |
545 | ||
546 | /* Someone is already using the tracer */ | |
547 | if (val) | |
548 | return -EBUSY; | |
549 | ||
550 | switch (mode) { | |
551 | case CS_MODE_SYSFS: | |
552 | ret = etm4_enable_sysfs(csdev); | |
553 | break; | |
37fbbdbd | 554 | case CS_MODE_PERF: |
68905d73 | 555 | ret = etm4_enable_perf(csdev, event); |
37fbbdbd | 556 | break; |
c38a9ec2 MP |
557 | default: |
558 | ret = -EINVAL; | |
559 | } | |
560 | ||
561 | /* The tracer didn't start */ | |
562 | if (ret) | |
563 | local_set(&drvdata->mode, CS_MODE_DISABLED); | |
564 | ||
565 | return ret; | |
566 | } | |
567 | ||
2e1cdfe1 PP |
568 | static void etm4_disable_hw(void *info) |
569 | { | |
570 | u32 control; | |
571 | struct etmv4_drvdata *drvdata = info; | |
ebddaad0 ML |
572 | struct etmv4_config *config = &drvdata->config; |
573 | struct device *etm_dev = &drvdata->csdev->dev; | |
574 | int i; | |
2e1cdfe1 PP |
575 | |
576 | CS_UNLOCK(drvdata->base); | |
e7255092 | 577 | etm4_disable_arch_specific(drvdata); |
2e1cdfe1 | 578 | |
02510a5a TZ |
579 | if (!drvdata->skip_power_up) { |
580 | /* power can be removed from the trace unit now */ | |
581 | control = readl_relaxed(drvdata->base + TRCPDCR); | |
582 | control &= ~TRCPDCR_PU; | |
583 | writel_relaxed(control, drvdata->base + TRCPDCR); | |
584 | } | |
46a3d5cd | 585 | |
2e1cdfe1 PP |
586 | control = readl_relaxed(drvdata->base + TRCPRGCTLR); |
587 | ||
588 | /* EN, bit[0] Trace unit enable bit */ | |
589 | control &= ~0x1; | |
590 | ||
1004ce4c AM |
591 | /* |
592 | * Make sure everything completes before disabling, as recommended | |
593 | * by section 7.3.77 ("TRCVICTLR, ViewInst Main Control Register, | |
594 | * SSTATUS") of ARM IHI 0064D | |
595 | */ | |
596 | dsb(sy); | |
2e1cdfe1 PP |
597 | isb(); |
598 | writel_relaxed(control, drvdata->base + TRCPRGCTLR); | |
599 | ||
ebddaad0 ML |
600 | /* wait for TRCSTATR.PMSTABLE to go to '1' */ |
601 | if (coresight_timeout(drvdata->base, TRCSTATR, | |
602 | TRCSTATR_PMSTABLE_BIT, 1)) | |
603 | dev_err(etm_dev, | |
604 | "timeout while waiting for PM stable Trace Status\n"); | |
605 | ||
606 | /* read the status of the single shot comparators */ | |
607 | for (i = 0; i < drvdata->nr_ss_cmp; i++) { | |
608 | config->ss_status[i] = | |
609 | readl_relaxed(drvdata->base + TRCSSCSRn(i)); | |
610 | } | |
611 | ||
8fa43700 ML |
612 | /* read back the current counter values */ |
613 | for (i = 0; i < drvdata->nr_cntr; i++) { | |
614 | config->cntr_val[i] = | |
615 | readl_relaxed(drvdata->base + TRCCNTVRn(i)); | |
616 | } | |
617 | ||
68a14775 SP |
618 | coresight_disclaim_device_unlocked(drvdata->base); |
619 | ||
2e1cdfe1 PP |
620 | CS_LOCK(drvdata->base); |
621 | ||
aaff7623 SP |
622 | dev_dbg(&drvdata->csdev->dev, |
623 | "cpu: %d disable smp call done\n", drvdata->cpu); | |
2e1cdfe1 PP |
624 | } |
625 | ||
68905d73 MP |
626 | static int etm4_disable_perf(struct coresight_device *csdev, |
627 | struct perf_event *event) | |
37fbbdbd | 628 | { |
e97b1c6a MP |
629 | u32 control; |
630 | struct etm_filters *filters = event->hw.addr_filters; | |
37fbbdbd MP |
631 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
632 | ||
633 | if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) | |
634 | return -EINVAL; | |
635 | ||
636 | etm4_disable_hw(drvdata); | |
e97b1c6a MP |
637 | |
638 | /* | |
639 | * Check if the start/stop logic was active when the unit was stopped. | |
640 | * That way we can re-enable the start/stop logic when the process is | |
641 | * scheduled again. Configuration of the start/stop logic happens in | |
642 | * function etm4_set_event_filters(). | |
643 | */ | |
644 | control = readl_relaxed(drvdata->base + TRCVICTLR); | |
645 | /* TRCVICTLR::SSSTATUS, bit[9] */ | |
646 | filters->ssstatus = (control & BIT(9)); | |
647 | ||
37fbbdbd MP |
648 | return 0; |
649 | } | |
650 | ||
c38a9ec2 | 651 | static void etm4_disable_sysfs(struct coresight_device *csdev) |
2e1cdfe1 PP |
652 | { |
653 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | |
654 | ||
655 | /* | |
656 | * Taking hotplug lock here protects from clocks getting disabled | |
657 | * with tracing being left on (crash scenario) if user disable occurs | |
658 | * after cpu online mask indicates the cpu is offline but before the | |
659 | * DYING hotplug callback is serviced by the ETM driver. | |
660 | */ | |
e9f5d63f | 661 | cpus_read_lock(); |
2e1cdfe1 PP |
662 | spin_lock(&drvdata->spinlock); |
663 | ||
664 | /* | |
665 | * Executing etm4_disable_hw on the cpu whose ETM is being disabled | |
666 | * ensures that register writes occur when cpu is powered. | |
667 | */ | |
668 | smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1); | |
2e1cdfe1 PP |
669 | |
670 | spin_unlock(&drvdata->spinlock); | |
e9f5d63f | 671 | cpus_read_unlock(); |
2e1cdfe1 | 672 | |
aaff7623 | 673 | dev_dbg(&csdev->dev, "ETM tracing disabled\n"); |
2e1cdfe1 PP |
674 | } |
675 | ||
68905d73 MP |
676 | static void etm4_disable(struct coresight_device *csdev, |
677 | struct perf_event *event) | |
c38a9ec2 MP |
678 | { |
679 | u32 mode; | |
680 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | |
681 | ||
682 | /* | |
683 | * For as long as the tracer isn't disabled another entity can't | |
684 | * change its status. As such we can read the status here without | |
685 | * fearing it will change under us. | |
686 | */ | |
687 | mode = local_read(&drvdata->mode); | |
688 | ||
689 | switch (mode) { | |
690 | case CS_MODE_DISABLED: | |
691 | break; | |
692 | case CS_MODE_SYSFS: | |
693 | etm4_disable_sysfs(csdev); | |
694 | break; | |
37fbbdbd | 695 | case CS_MODE_PERF: |
68905d73 | 696 | etm4_disable_perf(csdev, event); |
37fbbdbd | 697 | break; |
c38a9ec2 MP |
698 | } |
699 | ||
700 | if (mode) | |
701 | local_set(&drvdata->mode, CS_MODE_DISABLED); | |
702 | } | |
703 | ||
2e1cdfe1 | 704 | static const struct coresight_ops_source etm4_source_ops = { |
52210c87 | 705 | .cpu_id = etm4_cpu_id, |
2e1cdfe1 PP |
706 | .trace_id = etm4_trace_id, |
707 | .enable = etm4_enable, | |
708 | .disable = etm4_disable, | |
709 | }; | |
710 | ||
711 | static const struct coresight_ops etm4_cs_ops = { | |
712 | .source_ops = &etm4_source_ops, | |
713 | }; | |
714 | ||
2e1cdfe1 PP |
715 | static void etm4_init_arch_data(void *info) |
716 | { | |
717 | u32 etmidr0; | |
718 | u32 etmidr1; | |
719 | u32 etmidr2; | |
720 | u32 etmidr3; | |
721 | u32 etmidr4; | |
722 | u32 etmidr5; | |
723 | struct etmv4_drvdata *drvdata = info; | |
ebddaad0 | 724 | int i; |
2e1cdfe1 | 725 | |
66bbbb77 MP |
726 | /* Make sure all registers are accessible */ |
727 | etm4_os_unlock(drvdata); | |
728 | ||
2e1cdfe1 PP |
729 | CS_UNLOCK(drvdata->base); |
730 | ||
731 | /* find all capabilities of the tracing unit */ | |
732 | etmidr0 = readl_relaxed(drvdata->base + TRCIDR0); | |
733 | ||
734 | /* INSTP0, bits[2:1] P0 tracing support field */ | |
735 | if (BMVAL(etmidr0, 1, 1) && BMVAL(etmidr0, 2, 2)) | |
736 | drvdata->instrp0 = true; | |
737 | else | |
738 | drvdata->instrp0 = false; | |
739 | ||
740 | /* TRCBB, bit[5] Branch broadcast tracing support bit */ | |
741 | if (BMVAL(etmidr0, 5, 5)) | |
742 | drvdata->trcbb = true; | |
743 | else | |
744 | drvdata->trcbb = false; | |
745 | ||
746 | /* TRCCOND, bit[6] Conditional instruction tracing support bit */ | |
747 | if (BMVAL(etmidr0, 6, 6)) | |
748 | drvdata->trccond = true; | |
749 | else | |
750 | drvdata->trccond = false; | |
751 | ||
752 | /* TRCCCI, bit[7] Cycle counting instruction bit */ | |
753 | if (BMVAL(etmidr0, 7, 7)) | |
754 | drvdata->trccci = true; | |
755 | else | |
756 | drvdata->trccci = false; | |
757 | ||
758 | /* RETSTACK, bit[9] Return stack bit */ | |
759 | if (BMVAL(etmidr0, 9, 9)) | |
760 | drvdata->retstack = true; | |
761 | else | |
762 | drvdata->retstack = false; | |
763 | ||
764 | /* NUMEVENT, bits[11:10] Number of events field */ | |
765 | drvdata->nr_event = BMVAL(etmidr0, 10, 11); | |
766 | /* QSUPP, bits[16:15] Q element support field */ | |
767 | drvdata->q_support = BMVAL(etmidr0, 15, 16); | |
768 | /* TSSIZE, bits[28:24] Global timestamp size field */ | |
769 | drvdata->ts_size = BMVAL(etmidr0, 24, 28); | |
770 | ||
771 | /* base architecture of trace unit */ | |
772 | etmidr1 = readl_relaxed(drvdata->base + TRCIDR1); | |
773 | /* | |
774 | * TRCARCHMIN, bits[7:4] architecture the minor version number | |
775 | * TRCARCHMAJ, bits[11:8] architecture major versin number | |
776 | */ | |
777 | drvdata->arch = BMVAL(etmidr1, 4, 11); | |
057f2c57 | 778 | drvdata->config.arch = drvdata->arch; |
2e1cdfe1 PP |
779 | |
780 | /* maximum size of resources */ | |
781 | etmidr2 = readl_relaxed(drvdata->base + TRCIDR2); | |
782 | /* CIDSIZE, bits[9:5] Indicates the Context ID size */ | |
783 | drvdata->ctxid_size = BMVAL(etmidr2, 5, 9); | |
784 | /* VMIDSIZE, bits[14:10] Indicates the VMID size */ | |
785 | drvdata->vmid_size = BMVAL(etmidr2, 10, 14); | |
786 | /* CCSIZE, bits[28:25] size of the cycle counter in bits minus 12 */ | |
787 | drvdata->ccsize = BMVAL(etmidr2, 25, 28); | |
788 | ||
789 | etmidr3 = readl_relaxed(drvdata->base + TRCIDR3); | |
790 | /* CCITMIN, bits[11:0] minimum threshold value that can be programmed */ | |
791 | drvdata->ccitmin = BMVAL(etmidr3, 0, 11); | |
792 | /* EXLEVEL_S, bits[19:16] Secure state instruction tracing */ | |
793 | drvdata->s_ex_level = BMVAL(etmidr3, 16, 19); | |
794 | /* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */ | |
795 | drvdata->ns_ex_level = BMVAL(etmidr3, 20, 23); | |
796 | ||
797 | /* | |
798 | * TRCERR, bit[24] whether a trace unit can trace a | |
799 | * system error exception. | |
800 | */ | |
801 | if (BMVAL(etmidr3, 24, 24)) | |
802 | drvdata->trc_error = true; | |
803 | else | |
804 | drvdata->trc_error = false; | |
805 | ||
806 | /* SYNCPR, bit[25] implementation has a fixed synchronization period? */ | |
807 | if (BMVAL(etmidr3, 25, 25)) | |
808 | drvdata->syncpr = true; | |
809 | else | |
810 | drvdata->syncpr = false; | |
811 | ||
812 | /* STALLCTL, bit[26] is stall control implemented? */ | |
813 | if (BMVAL(etmidr3, 26, 26)) | |
814 | drvdata->stallctl = true; | |
815 | else | |
816 | drvdata->stallctl = false; | |
817 | ||
818 | /* SYSSTALL, bit[27] implementation can support stall control? */ | |
819 | if (BMVAL(etmidr3, 27, 27)) | |
820 | drvdata->sysstall = true; | |
821 | else | |
822 | drvdata->sysstall = false; | |
823 | ||
4e218727 SP |
824 | /* |
825 | * NUMPROC - the number of PEs available for tracing, 5bits | |
826 | * = TRCIDR3.bits[13:12]bits[30:28] | |
827 | * bits[4:3] = TRCIDR3.bits[13:12] (since etm-v4.2, otherwise RES0) | |
828 | * bits[3:0] = TRCIDR3.bits[30:28] | |
829 | */ | |
830 | drvdata->nr_pe = (BMVAL(etmidr3, 12, 13) << 3) | BMVAL(etmidr3, 28, 30); | |
2e1cdfe1 PP |
831 | |
832 | /* NOOVERFLOW, bit[31] is trace overflow prevention supported */ | |
833 | if (BMVAL(etmidr3, 31, 31)) | |
834 | drvdata->nooverflow = true; | |
835 | else | |
836 | drvdata->nooverflow = false; | |
837 | ||
838 | /* number of resources trace unit supports */ | |
839 | etmidr4 = readl_relaxed(drvdata->base + TRCIDR4); | |
840 | /* NUMACPAIRS, bits[0:3] number of addr comparator pairs for tracing */ | |
841 | drvdata->nr_addr_cmp = BMVAL(etmidr4, 0, 3); | |
842 | /* NUMPC, bits[15:12] number of PE comparator inputs for tracing */ | |
843 | drvdata->nr_pe_cmp = BMVAL(etmidr4, 12, 15); | |
497b5956 CZ |
844 | /* |
845 | * NUMRSPAIR, bits[19:16] | |
846 | * The number of resource pairs conveyed by the HW starts at 0, i.e a | |
847 | * value of 0x0 indicate 1 resource pair, 0x1 indicate two and so on. | |
848 | * As such add 1 to the value of NUMRSPAIR for a better representation. | |
14ea4db1 ML |
849 | * |
850 | * For ETM v4.3 and later, 0x0 means 0, and no pairs are available - | |
851 | * the default TRUE and FALSE resource selectors are omitted. | |
852 | * Otherwise for values 0x1 and above the number is N + 1 as per v4.2. | |
497b5956 | 853 | */ |
14ea4db1 ML |
854 | drvdata->nr_resource = BMVAL(etmidr4, 16, 19); |
855 | if ((drvdata->arch < ETM4X_ARCH_4V3) || (drvdata->nr_resource > 0)) | |
856 | drvdata->nr_resource += 1; | |
2e1cdfe1 PP |
857 | /* |
858 | * NUMSSCC, bits[23:20] the number of single-shot | |
ebddaad0 ML |
859 | * comparator control for tracing. Read any status regs as these |
860 | * also contain RO capability data. | |
2e1cdfe1 PP |
861 | */ |
862 | drvdata->nr_ss_cmp = BMVAL(etmidr4, 20, 23); | |
ebddaad0 ML |
863 | for (i = 0; i < drvdata->nr_ss_cmp; i++) { |
864 | drvdata->config.ss_status[i] = | |
865 | readl_relaxed(drvdata->base + TRCSSCSRn(i)); | |
866 | } | |
2e1cdfe1 PP |
867 | /* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */ |
868 | drvdata->numcidc = BMVAL(etmidr4, 24, 27); | |
869 | /* NUMVMIDC, bits[31:28] number of VMID comparators for tracing */ | |
870 | drvdata->numvmidc = BMVAL(etmidr4, 28, 31); | |
871 | ||
872 | etmidr5 = readl_relaxed(drvdata->base + TRCIDR5); | |
873 | /* NUMEXTIN, bits[8:0] number of external inputs implemented */ | |
874 | drvdata->nr_ext_inp = BMVAL(etmidr5, 0, 8); | |
875 | /* TRACEIDSIZE, bits[21:16] indicates the trace ID width */ | |
876 | drvdata->trcid_size = BMVAL(etmidr5, 16, 21); | |
877 | /* ATBTRIG, bit[22] implementation can support ATB triggers? */ | |
878 | if (BMVAL(etmidr5, 22, 22)) | |
879 | drvdata->atbtrig = true; | |
880 | else | |
881 | drvdata->atbtrig = false; | |
882 | /* | |
883 | * LPOVERRIDE, bit[23] implementation supports | |
884 | * low-power state override | |
885 | */ | |
ac0f82b1 | 886 | if (BMVAL(etmidr5, 23, 23) && (!drvdata->skip_power_up)) |
2e1cdfe1 PP |
887 | drvdata->lpoverride = true; |
888 | else | |
889 | drvdata->lpoverride = false; | |
890 | /* NUMSEQSTATE, bits[27:25] number of sequencer states implemented */ | |
891 | drvdata->nrseqstate = BMVAL(etmidr5, 25, 27); | |
892 | /* NUMCNTR, bits[30:28] number of counters available for tracing */ | |
893 | drvdata->nr_cntr = BMVAL(etmidr5, 28, 30); | |
894 | CS_LOCK(drvdata->base); | |
895 | } | |
896 | ||
096dcfb9 ML |
897 | /* Set ELx trace filter access in the TRCVICTLR register */ |
898 | static void etm4_set_victlr_access(struct etmv4_config *config) | |
899 | { | |
900 | u64 access_type; | |
901 | ||
902 | config->vinst_ctrl &= ~(ETM_EXLEVEL_S_VICTLR_MASK | ETM_EXLEVEL_NS_VICTLR_MASK); | |
903 | ||
904 | /* | |
905 | * TRCVICTLR::EXLEVEL_NS:EXLEVELS: Set kernel / user filtering | |
906 | * bits in vinst_ctrl, same bit pattern as TRCACATRn values returned by | |
907 | * etm4_get_access_type() but with a relative shift in this register. | |
908 | */ | |
909 | access_type = etm4_get_access_type(config) << ETM_EXLEVEL_LSHIFT_TRCVICTLR; | |
910 | config->vinst_ctrl |= (u32)access_type; | |
911 | } | |
912 | ||
2a5695a5 | 913 | static void etm4_set_default_config(struct etmv4_config *config) |
2e1cdfe1 | 914 | { |
2e1cdfe1 | 915 | /* disable all events tracing */ |
54ff892b MP |
916 | config->eventctrl0 = 0x0; |
917 | config->eventctrl1 = 0x0; | |
2e1cdfe1 PP |
918 | |
919 | /* disable stalling */ | |
54ff892b | 920 | config->stall_ctrl = 0x0; |
2e1cdfe1 | 921 | |
fc208abe MP |
922 | /* enable trace synchronization every 4096 bytes, if available */ |
923 | config->syncfreq = 0xC; | |
924 | ||
2e1cdfe1 | 925 | /* disable timestamp event */ |
54ff892b | 926 | config->ts_ctrl = 0x0; |
2e1cdfe1 | 927 | |
fc208abe | 928 | /* TRCVICTLR::EVENT = 0x01, select the always on logic */ |
ae204151 | 929 | config->vinst_ctrl = BIT(0); |
096dcfb9 ML |
930 | |
931 | /* TRCVICTLR::EXLEVEL_NS:EXLEVELS: Set kernel / user filtering */ | |
932 | etm4_set_victlr_access(config); | |
2a5695a5 | 933 | } |
2e1cdfe1 | 934 | |
b860801e | 935 | static u64 etm4_get_ns_access_type(struct etmv4_config *config) |
2a5695a5 | 936 | { |
6cccf663 | 937 | u64 access_type = 0; |
f67b467a | 938 | |
f0d30cc3 MP |
939 | /* |
940 | * EXLEVEL_NS, bits[15:12] | |
941 | * The Exception levels are: | |
942 | * Bit[12] Exception level 0 - Application | |
943 | * Bit[13] Exception level 1 - OS | |
944 | * Bit[14] Exception level 2 - Hypervisor | |
945 | * Bit[15] Never implemented | |
f0d30cc3 | 946 | */ |
b860801e TN |
947 | if (!is_kernel_in_hyp_mode()) { |
948 | /* Stay away from hypervisor mode for non-VHE */ | |
949 | access_type = ETM_EXLEVEL_NS_HYP; | |
950 | if (config->mode & ETM_MODE_EXCL_KERN) | |
951 | access_type |= ETM_EXLEVEL_NS_OS; | |
952 | } else if (config->mode & ETM_MODE_EXCL_KERN) { | |
953 | access_type = ETM_EXLEVEL_NS_HYP; | |
954 | } | |
f0d30cc3 MP |
955 | |
956 | if (config->mode & ETM_MODE_EXCL_USER) | |
957 | access_type |= ETM_EXLEVEL_NS_APP; | |
958 | ||
b860801e TN |
959 | return access_type; |
960 | } | |
961 | ||
962 | static u64 etm4_get_access_type(struct etmv4_config *config) | |
963 | { | |
964 | u64 access_type = etm4_get_ns_access_type(config); | |
057f2c57 | 965 | u64 s_hyp = (config->arch & 0x0f) >= 0x4 ? ETM_EXLEVEL_S_HYP : 0; |
b860801e | 966 | |
fc208abe | 967 | /* |
5edd944b MP |
968 | * EXLEVEL_S, bits[11:8], don't trace anything happening |
969 | * in secure state. | |
970 | */ | |
971 | access_type |= (ETM_EXLEVEL_S_APP | | |
972 | ETM_EXLEVEL_S_OS | | |
057f2c57 ML |
973 | s_hyp | |
974 | ETM_EXLEVEL_S_MON); | |
5edd944b | 975 | |
f0d30cc3 MP |
976 | return access_type; |
977 | } | |
978 | ||
979 | static void etm4_set_comparator_filter(struct etmv4_config *config, | |
980 | u64 start, u64 stop, int comparator) | |
981 | { | |
982 | u64 access_type = etm4_get_access_type(config); | |
983 | ||
5edd944b | 984 | /* First half of default address comparator */ |
6cccf663 MP |
985 | config->addr_val[comparator] = start; |
986 | config->addr_acc[comparator] = access_type; | |
987 | config->addr_type[comparator] = ETM_ADDR_TYPE_RANGE; | |
5edd944b MP |
988 | |
989 | /* Second half of default address comparator */ | |
6cccf663 MP |
990 | config->addr_val[comparator + 1] = stop; |
991 | config->addr_acc[comparator + 1] = access_type; | |
992 | config->addr_type[comparator + 1] = ETM_ADDR_TYPE_RANGE; | |
993 | ||
994 | /* | |
995 | * Configure the ViewInst function to include this address range | |
996 | * comparator. | |
997 | * | |
998 | * @comparator is divided by two since it is the index in the | |
999 | * etmv4_config::addr_val array but register TRCVIIECTLR deals with | |
1000 | * address range comparator _pairs_. | |
1001 | * | |
1002 | * Therefore: | |
1003 | * index 0 -> compatator pair 0 | |
1004 | * index 2 -> comparator pair 1 | |
1005 | * index 4 -> comparator pair 2 | |
1006 | * ... | |
1007 | * index 14 -> comparator pair 7 | |
1008 | */ | |
1009 | config->viiectlr |= BIT(comparator / 2); | |
1010 | } | |
1011 | ||
e97b1c6a MP |
1012 | static void etm4_set_start_stop_filter(struct etmv4_config *config, |
1013 | u64 address, int comparator, | |
1014 | enum etm_addr_type type) | |
1015 | { | |
1016 | int shift; | |
1017 | u64 access_type = etm4_get_access_type(config); | |
1018 | ||
1019 | /* Configure the comparator */ | |
1020 | config->addr_val[comparator] = address; | |
1021 | config->addr_acc[comparator] = access_type; | |
1022 | config->addr_type[comparator] = type; | |
1023 | ||
1024 | /* | |
1025 | * Configure ViewInst Start-Stop control register. | |
1026 | * Addresses configured to start tracing go from bit 0 to n-1, | |
1027 | * while those configured to stop tracing from 16 to 16 + n-1. | |
1028 | */ | |
1029 | shift = (type == ETM_ADDR_TYPE_START ? 0 : 16); | |
1030 | config->vissctlr |= BIT(shift + comparator); | |
1031 | } | |
1032 | ||
6cccf663 MP |
1033 | static void etm4_set_default_filter(struct etmv4_config *config) |
1034 | { | |
ae204151 ML |
1035 | /* Trace everything 'default' filter achieved by no filtering */ |
1036 | config->viiectlr = 0x0; | |
fc208abe | 1037 | |
5edd944b MP |
1038 | /* |
1039 | * TRCVICTLR::SSSTATUS == 1, the start-stop logic is | |
1040 | * in the started state | |
1041 | */ | |
1042 | config->vinst_ctrl |= BIT(9); | |
1b6b0e08 | 1043 | config->mode |= ETM_MODE_VIEWINST_STARTSTOP; |
5edd944b MP |
1044 | |
1045 | /* No start-stop filtering for ViewInst */ | |
fc208abe | 1046 | config->vissctlr = 0x0; |
2e1cdfe1 PP |
1047 | } |
1048 | ||
2a5695a5 MP |
1049 | static void etm4_set_default(struct etmv4_config *config) |
1050 | { | |
1051 | if (WARN_ON_ONCE(!config)) | |
1052 | return; | |
1053 | ||
1054 | /* | |
1055 | * Make default initialisation trace everything | |
1056 | * | |
ae204151 ML |
1057 | * This is done by a minimum default config sufficient to enable |
1058 | * full instruction trace - with a default filter for trace all | |
1059 | * achieved by having no filtering. | |
2a5695a5 MP |
1060 | */ |
1061 | etm4_set_default_config(config); | |
1062 | etm4_set_default_filter(config); | |
1063 | } | |
1064 | ||
2703d74c MP |
1065 | static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type) |
1066 | { | |
1067 | int nr_comparator, index = 0; | |
1068 | struct etmv4_config *config = &drvdata->config; | |
1069 | ||
1070 | /* | |
1071 | * nr_addr_cmp holds the number of comparator _pair_, so time 2 | |
1072 | * for the total number of comparators. | |
1073 | */ | |
1074 | nr_comparator = drvdata->nr_addr_cmp * 2; | |
1075 | ||
1076 | /* Go through the tally of comparators looking for a free one. */ | |
1077 | while (index < nr_comparator) { | |
1078 | switch (type) { | |
1079 | case ETM_ADDR_TYPE_RANGE: | |
1080 | if (config->addr_type[index] == ETM_ADDR_TYPE_NONE && | |
1081 | config->addr_type[index + 1] == ETM_ADDR_TYPE_NONE) | |
1082 | return index; | |
1083 | ||
1084 | /* Address range comparators go in pairs */ | |
1085 | index += 2; | |
1086 | break; | |
e97b1c6a MP |
1087 | case ETM_ADDR_TYPE_START: |
1088 | case ETM_ADDR_TYPE_STOP: | |
1089 | if (config->addr_type[index] == ETM_ADDR_TYPE_NONE) | |
1090 | return index; | |
1091 | ||
1092 | /* Start/stop address can have odd indexes */ | |
1093 | index += 1; | |
1094 | break; | |
2703d74c MP |
1095 | default: |
1096 | return -EINVAL; | |
1097 | } | |
1098 | } | |
1099 | ||
1100 | /* If we are here all the comparators have been used. */ | |
1101 | return -ENOSPC; | |
1102 | } | |
1103 | ||
1104 | static int etm4_set_event_filters(struct etmv4_drvdata *drvdata, | |
1105 | struct perf_event *event) | |
1106 | { | |
1107 | int i, comparator, ret = 0; | |
e97b1c6a | 1108 | u64 address; |
2703d74c MP |
1109 | struct etmv4_config *config = &drvdata->config; |
1110 | struct etm_filters *filters = event->hw.addr_filters; | |
1111 | ||
1112 | if (!filters) | |
1113 | goto default_filter; | |
1114 | ||
1115 | /* Sync events with what Perf got */ | |
1116 | perf_event_addr_filters_sync(event); | |
1117 | ||
1118 | /* | |
1119 | * If there are no filters to deal with simply go ahead with | |
1120 | * the default filter, i.e the entire address range. | |
1121 | */ | |
1122 | if (!filters->nr_filters) | |
1123 | goto default_filter; | |
1124 | ||
1125 | for (i = 0; i < filters->nr_filters; i++) { | |
1126 | struct etm_filter *filter = &filters->etm_filter[i]; | |
1127 | enum etm_addr_type type = filter->type; | |
1128 | ||
1129 | /* See if a comparator is free. */ | |
1130 | comparator = etm4_get_next_comparator(drvdata, type); | |
1131 | if (comparator < 0) { | |
1132 | ret = comparator; | |
1133 | goto out; | |
1134 | } | |
1135 | ||
1136 | switch (type) { | |
1137 | case ETM_ADDR_TYPE_RANGE: | |
1138 | etm4_set_comparator_filter(config, | |
1139 | filter->start_addr, | |
1140 | filter->stop_addr, | |
1141 | comparator); | |
1142 | /* | |
1143 | * TRCVICTLR::SSSTATUS == 1, the start-stop logic is | |
1144 | * in the started state | |
1145 | */ | |
1146 | config->vinst_ctrl |= BIT(9); | |
1147 | ||
1148 | /* No start-stop filtering for ViewInst */ | |
1149 | config->vissctlr = 0x0; | |
1150 | break; | |
e97b1c6a MP |
1151 | case ETM_ADDR_TYPE_START: |
1152 | case ETM_ADDR_TYPE_STOP: | |
1153 | /* Get the right start or stop address */ | |
1154 | address = (type == ETM_ADDR_TYPE_START ? | |
1155 | filter->start_addr : | |
1156 | filter->stop_addr); | |
1157 | ||
1158 | /* Configure comparator */ | |
1159 | etm4_set_start_stop_filter(config, address, | |
1160 | comparator, type); | |
1161 | ||
1162 | /* | |
1163 | * If filters::ssstatus == 1, trace acquisition was | |
1164 | * started but the process was yanked away before the | |
1165 | * the stop address was hit. As such the start/stop | |
1166 | * logic needs to be re-started so that tracing can | |
1167 | * resume where it left. | |
1168 | * | |
1169 | * The start/stop logic status when a process is | |
1170 | * scheduled out is checked in function | |
1171 | * etm4_disable_perf(). | |
1172 | */ | |
1173 | if (filters->ssstatus) | |
1174 | config->vinst_ctrl |= BIT(9); | |
1175 | ||
1176 | /* No include/exclude filtering for ViewInst */ | |
1177 | config->viiectlr = 0x0; | |
1178 | break; | |
2703d74c MP |
1179 | default: |
1180 | ret = -EINVAL; | |
1181 | goto out; | |
1182 | } | |
1183 | } | |
1184 | ||
1185 | goto out; | |
1186 | ||
1187 | ||
1188 | default_filter: | |
1189 | etm4_set_default_filter(config); | |
1190 | ||
1191 | out: | |
1192 | return ret; | |
1193 | } | |
1194 | ||
4f6fce54 MP |
1195 | void etm4_config_trace_mode(struct etmv4_config *config) |
1196 | { | |
096dcfb9 | 1197 | u32 mode; |
4f6fce54 MP |
1198 | |
1199 | mode = config->mode; | |
1200 | mode &= (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER); | |
1201 | ||
1202 | /* excluding kernel AND user space doesn't make sense */ | |
1203 | WARN_ON_ONCE(mode == (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER)); | |
1204 | ||
1205 | /* nothing to do if neither flags are set */ | |
1206 | if (!(mode & ETM_MODE_EXCL_KERN) && !(mode & ETM_MODE_EXCL_USER)) | |
1207 | return; | |
1208 | ||
096dcfb9 | 1209 | etm4_set_victlr_access(config); |
4f6fce54 MP |
1210 | } |
1211 | ||
58eb457b | 1212 | static int etm4_online_cpu(unsigned int cpu) |
2e1cdfe1 | 1213 | { |
2e1cdfe1 | 1214 | if (!etmdrvdata[cpu]) |
58eb457b | 1215 | return 0; |
2e1cdfe1 | 1216 | |
58eb457b SAS |
1217 | if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) |
1218 | coresight_enable(etmdrvdata[cpu]->csdev); | |
1219 | return 0; | |
1220 | } | |
2e1cdfe1 | 1221 | |
58eb457b SAS |
1222 | static int etm4_starting_cpu(unsigned int cpu) |
1223 | { | |
1224 | if (!etmdrvdata[cpu]) | |
1225 | return 0; | |
1226 | ||
1227 | spin_lock(&etmdrvdata[cpu]->spinlock); | |
6d765101 | 1228 | if (!etmdrvdata[cpu]->os_unlock) |
58eb457b | 1229 | etm4_os_unlock(etmdrvdata[cpu]); |
58eb457b SAS |
1230 | |
1231 | if (local_read(&etmdrvdata[cpu]->mode)) | |
1232 | etm4_enable_hw(etmdrvdata[cpu]); | |
1233 | spin_unlock(&etmdrvdata[cpu]->spinlock); | |
1234 | return 0; | |
2e1cdfe1 PP |
1235 | } |
1236 | ||
58eb457b SAS |
1237 | static int etm4_dying_cpu(unsigned int cpu) |
1238 | { | |
1239 | if (!etmdrvdata[cpu]) | |
1240 | return 0; | |
1241 | ||
1242 | spin_lock(&etmdrvdata[cpu]->spinlock); | |
1243 | if (local_read(&etmdrvdata[cpu]->mode)) | |
1244 | etm4_disable_hw(etmdrvdata[cpu]); | |
1245 | spin_unlock(&etmdrvdata[cpu]->spinlock); | |
1246 | return 0; | |
1247 | } | |
2e1cdfe1 | 1248 | |
fc208abe MP |
1249 | static void etm4_init_trace_id(struct etmv4_drvdata *drvdata) |
1250 | { | |
1251 | drvdata->trcid = coresight_get_trace_id(drvdata->cpu); | |
1252 | } | |
1253 | ||
f188b5e7 AM |
1254 | static int etm4_cpu_save(struct etmv4_drvdata *drvdata) |
1255 | { | |
1256 | int i, ret = 0; | |
1257 | struct etmv4_save_state *state; | |
1258 | struct device *etm_dev = &drvdata->csdev->dev; | |
1259 | ||
1260 | /* | |
1261 | * As recommended by 3.4.1 ("The procedure when powering down the PE") | |
1262 | * of ARM IHI 0064D | |
1263 | */ | |
1264 | dsb(sy); | |
1265 | isb(); | |
1266 | ||
1267 | CS_UNLOCK(drvdata->base); | |
1268 | ||
1269 | /* Lock the OS lock to disable trace and external debugger access */ | |
1270 | etm4_os_lock(drvdata); | |
1271 | ||
1272 | /* wait for TRCSTATR.PMSTABLE to go up */ | |
1273 | if (coresight_timeout(drvdata->base, TRCSTATR, | |
1274 | TRCSTATR_PMSTABLE_BIT, 1)) { | |
1275 | dev_err(etm_dev, | |
1276 | "timeout while waiting for PM Stable Status\n"); | |
1277 | etm4_os_unlock(drvdata); | |
1278 | ret = -EBUSY; | |
1279 | goto out; | |
1280 | } | |
1281 | ||
1282 | state = drvdata->save_state; | |
1283 | ||
1284 | state->trcprgctlr = readl(drvdata->base + TRCPRGCTLR); | |
6288b4ce SP |
1285 | if (drvdata->nr_pe) |
1286 | state->trcprocselr = readl(drvdata->base + TRCPROCSELR); | |
f188b5e7 AM |
1287 | state->trcconfigr = readl(drvdata->base + TRCCONFIGR); |
1288 | state->trcauxctlr = readl(drvdata->base + TRCAUXCTLR); | |
1289 | state->trceventctl0r = readl(drvdata->base + TRCEVENTCTL0R); | |
1290 | state->trceventctl1r = readl(drvdata->base + TRCEVENTCTL1R); | |
1291 | state->trcstallctlr = readl(drvdata->base + TRCSTALLCTLR); | |
1292 | state->trctsctlr = readl(drvdata->base + TRCTSCTLR); | |
1293 | state->trcsyncpr = readl(drvdata->base + TRCSYNCPR); | |
1294 | state->trcccctlr = readl(drvdata->base + TRCCCCTLR); | |
1295 | state->trcbbctlr = readl(drvdata->base + TRCBBCTLR); | |
1296 | state->trctraceidr = readl(drvdata->base + TRCTRACEIDR); | |
1297 | state->trcqctlr = readl(drvdata->base + TRCQCTLR); | |
1298 | ||
1299 | state->trcvictlr = readl(drvdata->base + TRCVICTLR); | |
1300 | state->trcviiectlr = readl(drvdata->base + TRCVIIECTLR); | |
1301 | state->trcvissctlr = readl(drvdata->base + TRCVISSCTLR); | |
60c519c5 SP |
1302 | if (drvdata->nr_pe_cmp) |
1303 | state->trcvipcssctlr = readl(drvdata->base + TRCVIPCSSCTLR); | |
f188b5e7 AM |
1304 | state->trcvdctlr = readl(drvdata->base + TRCVDCTLR); |
1305 | state->trcvdsacctlr = readl(drvdata->base + TRCVDSACCTLR); | |
1306 | state->trcvdarcctlr = readl(drvdata->base + TRCVDARCCTLR); | |
1307 | ||
4cd83037 | 1308 | for (i = 0; i < drvdata->nrseqstate - 1; i++) |
f188b5e7 AM |
1309 | state->trcseqevr[i] = readl(drvdata->base + TRCSEQEVRn(i)); |
1310 | ||
1311 | state->trcseqrstevr = readl(drvdata->base + TRCSEQRSTEVR); | |
1312 | state->trcseqstr = readl(drvdata->base + TRCSEQSTR); | |
1313 | state->trcextinselr = readl(drvdata->base + TRCEXTINSELR); | |
1314 | ||
1315 | for (i = 0; i < drvdata->nr_cntr; i++) { | |
1316 | state->trccntrldvr[i] = readl(drvdata->base + TRCCNTRLDVRn(i)); | |
1317 | state->trccntctlr[i] = readl(drvdata->base + TRCCNTCTLRn(i)); | |
1318 | state->trccntvr[i] = readl(drvdata->base + TRCCNTVRn(i)); | |
1319 | } | |
1320 | ||
1321 | for (i = 0; i < drvdata->nr_resource * 2; i++) | |
1322 | state->trcrsctlr[i] = readl(drvdata->base + TRCRSCTLRn(i)); | |
1323 | ||
1324 | for (i = 0; i < drvdata->nr_ss_cmp; i++) { | |
1325 | state->trcssccr[i] = readl(drvdata->base + TRCSSCCRn(i)); | |
1326 | state->trcsscsr[i] = readl(drvdata->base + TRCSSCSRn(i)); | |
1327 | state->trcsspcicr[i] = readl(drvdata->base + TRCSSPCICRn(i)); | |
1328 | } | |
1329 | ||
1330 | for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) { | |
342c8a1d SP |
1331 | state->trcacvr[i] = readq(drvdata->base + TRCACVRn(i)); |
1332 | state->trcacatr[i] = readq(drvdata->base + TRCACATRn(i)); | |
f188b5e7 AM |
1333 | } |
1334 | ||
1335 | /* | |
1336 | * Data trace stream is architecturally prohibited for A profile cores | |
1337 | * so we don't save (or later restore) trcdvcvr and trcdvcmr - As per | |
1338 | * section 1.3.4 ("Possible functional configurations of an ETMv4 trace | |
1339 | * unit") of ARM IHI 0064D. | |
1340 | */ | |
1341 | ||
1342 | for (i = 0; i < drvdata->numcidc; i++) | |
342c8a1d | 1343 | state->trccidcvr[i] = readq(drvdata->base + TRCCIDCVRn(i)); |
f188b5e7 AM |
1344 | |
1345 | for (i = 0; i < drvdata->numvmidc; i++) | |
342c8a1d | 1346 | state->trcvmidcvr[i] = readq(drvdata->base + TRCVMIDCVRn(i)); |
f188b5e7 AM |
1347 | |
1348 | state->trccidcctlr0 = readl(drvdata->base + TRCCIDCCTLR0); | |
f2603b22 SP |
1349 | if (drvdata->numcidc > 4) |
1350 | state->trccidcctlr1 = readl(drvdata->base + TRCCIDCCTLR1); | |
f188b5e7 AM |
1351 | |
1352 | state->trcvmidcctlr0 = readl(drvdata->base + TRCVMIDCCTLR0); | |
93dd6440 SP |
1353 | if (drvdata->numvmidc > 4) |
1354 | state->trcvmidcctlr1 = readl(drvdata->base + TRCVMIDCCTLR1); | |
f188b5e7 AM |
1355 | |
1356 | state->trcclaimset = readl(drvdata->base + TRCCLAIMCLR); | |
1357 | ||
d61aa414 SP |
1358 | if (!drvdata->skip_power_up) |
1359 | state->trcpdcr = readl(drvdata->base + TRCPDCR); | |
f188b5e7 AM |
1360 | |
1361 | /* wait for TRCSTATR.IDLE to go up */ | |
1362 | if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 1)) { | |
1363 | dev_err(etm_dev, | |
1364 | "timeout while waiting for Idle Trace Status\n"); | |
1365 | etm4_os_unlock(drvdata); | |
1366 | ret = -EBUSY; | |
1367 | goto out; | |
1368 | } | |
1369 | ||
1370 | drvdata->state_needs_restore = true; | |
1371 | ||
1372 | /* | |
1373 | * Power can be removed from the trace unit now. We do this to | |
1374 | * potentially save power on systems that respect the TRCPDCR_PU | |
1375 | * despite requesting software to save/restore state. | |
1376 | */ | |
d61aa414 SP |
1377 | if (!drvdata->skip_power_up) |
1378 | writel_relaxed((state->trcpdcr & ~TRCPDCR_PU), | |
1379 | drvdata->base + TRCPDCR); | |
f188b5e7 AM |
1380 | out: |
1381 | CS_LOCK(drvdata->base); | |
1382 | return ret; | |
1383 | } | |
1384 | ||
1385 | static void etm4_cpu_restore(struct etmv4_drvdata *drvdata) | |
1386 | { | |
1387 | int i; | |
1388 | struct etmv4_save_state *state = drvdata->save_state; | |
1389 | ||
1390 | CS_UNLOCK(drvdata->base); | |
1391 | ||
1392 | writel_relaxed(state->trcclaimset, drvdata->base + TRCCLAIMSET); | |
1393 | ||
1394 | writel_relaxed(state->trcprgctlr, drvdata->base + TRCPRGCTLR); | |
6288b4ce SP |
1395 | if (drvdata->nr_pe) |
1396 | writel_relaxed(state->trcprocselr, drvdata->base + TRCPROCSELR); | |
f188b5e7 AM |
1397 | writel_relaxed(state->trcconfigr, drvdata->base + TRCCONFIGR); |
1398 | writel_relaxed(state->trcauxctlr, drvdata->base + TRCAUXCTLR); | |
1399 | writel_relaxed(state->trceventctl0r, drvdata->base + TRCEVENTCTL0R); | |
1400 | writel_relaxed(state->trceventctl1r, drvdata->base + TRCEVENTCTL1R); | |
1401 | writel_relaxed(state->trcstallctlr, drvdata->base + TRCSTALLCTLR); | |
1402 | writel_relaxed(state->trctsctlr, drvdata->base + TRCTSCTLR); | |
1403 | writel_relaxed(state->trcsyncpr, drvdata->base + TRCSYNCPR); | |
1404 | writel_relaxed(state->trcccctlr, drvdata->base + TRCCCCTLR); | |
1405 | writel_relaxed(state->trcbbctlr, drvdata->base + TRCBBCTLR); | |
1406 | writel_relaxed(state->trctraceidr, drvdata->base + TRCTRACEIDR); | |
1407 | writel_relaxed(state->trcqctlr, drvdata->base + TRCQCTLR); | |
1408 | ||
1409 | writel_relaxed(state->trcvictlr, drvdata->base + TRCVICTLR); | |
1410 | writel_relaxed(state->trcviiectlr, drvdata->base + TRCVIIECTLR); | |
1411 | writel_relaxed(state->trcvissctlr, drvdata->base + TRCVISSCTLR); | |
60c519c5 SP |
1412 | if (drvdata->nr_pe_cmp) |
1413 | writel_relaxed(state->trcvipcssctlr, drvdata->base + TRCVIPCSSCTLR); | |
f188b5e7 AM |
1414 | writel_relaxed(state->trcvdctlr, drvdata->base + TRCVDCTLR); |
1415 | writel_relaxed(state->trcvdsacctlr, drvdata->base + TRCVDSACCTLR); | |
1416 | writel_relaxed(state->trcvdarcctlr, drvdata->base + TRCVDARCCTLR); | |
1417 | ||
4cd83037 | 1418 | for (i = 0; i < drvdata->nrseqstate - 1; i++) |
f188b5e7 AM |
1419 | writel_relaxed(state->trcseqevr[i], |
1420 | drvdata->base + TRCSEQEVRn(i)); | |
1421 | ||
1422 | writel_relaxed(state->trcseqrstevr, drvdata->base + TRCSEQRSTEVR); | |
1423 | writel_relaxed(state->trcseqstr, drvdata->base + TRCSEQSTR); | |
1424 | writel_relaxed(state->trcextinselr, drvdata->base + TRCEXTINSELR); | |
1425 | ||
1426 | for (i = 0; i < drvdata->nr_cntr; i++) { | |
1427 | writel_relaxed(state->trccntrldvr[i], | |
1428 | drvdata->base + TRCCNTRLDVRn(i)); | |
1429 | writel_relaxed(state->trccntctlr[i], | |
1430 | drvdata->base + TRCCNTCTLRn(i)); | |
1431 | writel_relaxed(state->trccntvr[i], | |
1432 | drvdata->base + TRCCNTVRn(i)); | |
1433 | } | |
1434 | ||
1435 | for (i = 0; i < drvdata->nr_resource * 2; i++) | |
1436 | writel_relaxed(state->trcrsctlr[i], | |
1437 | drvdata->base + TRCRSCTLRn(i)); | |
1438 | ||
1439 | for (i = 0; i < drvdata->nr_ss_cmp; i++) { | |
1440 | writel_relaxed(state->trcssccr[i], | |
1441 | drvdata->base + TRCSSCCRn(i)); | |
1442 | writel_relaxed(state->trcsscsr[i], | |
1443 | drvdata->base + TRCSSCSRn(i)); | |
1444 | writel_relaxed(state->trcsspcicr[i], | |
1445 | drvdata->base + TRCSSPCICRn(i)); | |
1446 | } | |
1447 | ||
1448 | for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) { | |
342c8a1d | 1449 | writeq_relaxed(state->trcacvr[i], |
f188b5e7 | 1450 | drvdata->base + TRCACVRn(i)); |
342c8a1d | 1451 | writeq_relaxed(state->trcacatr[i], |
f188b5e7 AM |
1452 | drvdata->base + TRCACATRn(i)); |
1453 | } | |
1454 | ||
1455 | for (i = 0; i < drvdata->numcidc; i++) | |
342c8a1d | 1456 | writeq_relaxed(state->trccidcvr[i], |
f188b5e7 AM |
1457 | drvdata->base + TRCCIDCVRn(i)); |
1458 | ||
1459 | for (i = 0; i < drvdata->numvmidc; i++) | |
342c8a1d | 1460 | writeq_relaxed(state->trcvmidcvr[i], |
f188b5e7 AM |
1461 | drvdata->base + TRCVMIDCVRn(i)); |
1462 | ||
1463 | writel_relaxed(state->trccidcctlr0, drvdata->base + TRCCIDCCTLR0); | |
f2603b22 SP |
1464 | if (drvdata->numcidc > 4) |
1465 | writel_relaxed(state->trccidcctlr1, drvdata->base + TRCCIDCCTLR1); | |
f188b5e7 AM |
1466 | |
1467 | writel_relaxed(state->trcvmidcctlr0, drvdata->base + TRCVMIDCCTLR0); | |
93dd6440 SP |
1468 | if (drvdata->numvmidc > 4) |
1469 | writel_relaxed(state->trcvmidcctlr1, drvdata->base + TRCVMIDCCTLR1); | |
f188b5e7 AM |
1470 | |
1471 | writel_relaxed(state->trcclaimset, drvdata->base + TRCCLAIMSET); | |
1472 | ||
d61aa414 SP |
1473 | if (!drvdata->skip_power_up) |
1474 | writel_relaxed(state->trcpdcr, drvdata->base + TRCPDCR); | |
f188b5e7 AM |
1475 | |
1476 | drvdata->state_needs_restore = false; | |
1477 | ||
1478 | /* | |
1479 | * As recommended by section 4.3.7 ("Synchronization when using the | |
1480 | * memory-mapped interface") of ARM IHI 0064D | |
1481 | */ | |
1482 | dsb(sy); | |
1483 | isb(); | |
1484 | ||
1485 | /* Unlock the OS lock to re-enable trace and external debug access */ | |
1486 | etm4_os_unlock(drvdata); | |
1487 | CS_LOCK(drvdata->base); | |
1488 | } | |
1489 | ||
1490 | static int etm4_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd, | |
1491 | void *v) | |
1492 | { | |
1493 | struct etmv4_drvdata *drvdata; | |
1494 | unsigned int cpu = smp_processor_id(); | |
1495 | ||
1496 | if (!etmdrvdata[cpu]) | |
1497 | return NOTIFY_OK; | |
1498 | ||
1499 | drvdata = etmdrvdata[cpu]; | |
1500 | ||
1501 | if (!drvdata->save_state) | |
1502 | return NOTIFY_OK; | |
1503 | ||
1504 | if (WARN_ON_ONCE(drvdata->cpu != cpu)) | |
1505 | return NOTIFY_BAD; | |
1506 | ||
1507 | switch (cmd) { | |
1508 | case CPU_PM_ENTER: | |
1509 | /* save the state if self-hosted coresight is in use */ | |
1510 | if (local_read(&drvdata->mode)) | |
1511 | if (etm4_cpu_save(drvdata)) | |
1512 | return NOTIFY_BAD; | |
1513 | break; | |
1514 | case CPU_PM_EXIT: | |
f188b5e7 AM |
1515 | case CPU_PM_ENTER_FAILED: |
1516 | if (drvdata->state_needs_restore) | |
1517 | etm4_cpu_restore(drvdata); | |
1518 | break; | |
1519 | default: | |
1520 | return NOTIFY_DONE; | |
1521 | } | |
1522 | ||
1523 | return NOTIFY_OK; | |
1524 | } | |
1525 | ||
1526 | static struct notifier_block etm4_cpu_pm_nb = { | |
1527 | .notifier_call = etm4_cpu_pm_notify, | |
1528 | }; | |
1529 | ||
2d1a8bfb SPR |
1530 | /* Setup PM. Deals with error conditions and counts */ |
1531 | static int __init etm4_pm_setup(void) | |
f188b5e7 | 1532 | { |
9b6a3f36 | 1533 | int ret; |
500589d8 | 1534 | |
9b6a3f36 ML |
1535 | ret = cpu_pm_register_notifier(&etm4_cpu_pm_nb); |
1536 | if (ret) | |
2d1a8bfb | 1537 | return ret; |
9b6a3f36 | 1538 | |
2d1a8bfb SPR |
1539 | ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING, |
1540 | "arm/coresight4:starting", | |
1541 | etm4_starting_cpu, etm4_dying_cpu); | |
9b6a3f36 ML |
1542 | |
1543 | if (ret) | |
1544 | goto unregister_notifier; | |
1545 | ||
2d1a8bfb SPR |
1546 | ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, |
1547 | "arm/coresight4:online", | |
1548 | etm4_online_cpu, NULL); | |
9b6a3f36 ML |
1549 | |
1550 | /* HP dyn state ID returned in ret on success */ | |
1551 | if (ret > 0) { | |
1552 | hp_online = ret; | |
1553 | return 0; | |
1554 | } | |
1555 | ||
1556 | /* failed dyn state - remove others */ | |
2d1a8bfb | 1557 | cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING); |
9b6a3f36 ML |
1558 | |
1559 | unregister_notifier: | |
1560 | cpu_pm_unregister_notifier(&etm4_cpu_pm_nb); | |
9b6a3f36 | 1561 | return ret; |
f188b5e7 AM |
1562 | } |
1563 | ||
22a550a3 | 1564 | static void etm4_pm_clear(void) |
f188b5e7 | 1565 | { |
9b6a3f36 ML |
1566 | cpu_pm_unregister_notifier(&etm4_cpu_pm_nb); |
1567 | cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING); | |
1568 | if (hp_online) { | |
1569 | cpuhp_remove_state_nocalls(hp_online); | |
1570 | hp_online = 0; | |
1571 | } | |
f188b5e7 | 1572 | } |
f188b5e7 | 1573 | |
2e1cdfe1 PP |
1574 | static int etm4_probe(struct amba_device *adev, const struct amba_id *id) |
1575 | { | |
1576 | int ret; | |
1577 | void __iomem *base; | |
1578 | struct device *dev = &adev->dev; | |
1579 | struct coresight_platform_data *pdata = NULL; | |
1580 | struct etmv4_drvdata *drvdata; | |
1581 | struct resource *res = &adev->res; | |
9486295a | 1582 | struct coresight_desc desc = { 0 }; |
2e1cdfe1 | 1583 | |
2e1cdfe1 PP |
1584 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
1585 | if (!drvdata) | |
1586 | return -ENOMEM; | |
1587 | ||
2e1cdfe1 PP |
1588 | dev_set_drvdata(dev, drvdata); |
1589 | ||
f188b5e7 AM |
1590 | if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE) |
1591 | pm_save_enable = coresight_loses_context_with_cpu(dev) ? | |
1592 | PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER; | |
1593 | ||
1594 | if (pm_save_enable != PARAM_PM_SAVE_NEVER) { | |
1595 | drvdata->save_state = devm_kmalloc(dev, | |
1596 | sizeof(struct etmv4_save_state), GFP_KERNEL); | |
1597 | if (!drvdata->save_state) | |
1598 | return -ENOMEM; | |
1599 | } | |
1600 | ||
02510a5a TZ |
1601 | if (fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) |
1602 | drvdata->skip_power_up = true; | |
1603 | ||
2e1cdfe1 PP |
1604 | /* Validity for the resource is already checked by the AMBA core */ |
1605 | base = devm_ioremap_resource(dev, res); | |
1606 | if (IS_ERR(base)) | |
1607 | return PTR_ERR(base); | |
1608 | ||
1609 | drvdata->base = base; | |
1610 | ||
1611 | spin_lock_init(&drvdata->spinlock); | |
1612 | ||
aff70a45 | 1613 | drvdata->cpu = coresight_get_cpu(dev); |
996cdfaf SPR |
1614 | if (drvdata->cpu < 0) |
1615 | return drvdata->cpu; | |
1616 | ||
0f5f9b6b SP |
1617 | desc.name = devm_kasprintf(dev, GFP_KERNEL, "etm%d", drvdata->cpu); |
1618 | if (!desc.name) | |
1619 | return -ENOMEM; | |
2e1cdfe1 | 1620 | |
2e1cdfe1 PP |
1621 | if (smp_call_function_single(drvdata->cpu, |
1622 | etm4_init_arch_data, drvdata, 1)) | |
1623 | dev_err(dev, "ETM arch init failed\n"); | |
1624 | ||
22a550a3 KP |
1625 | if (etm4_arch_supported(drvdata->arch) == false) |
1626 | return -EINVAL; | |
fc208abe MP |
1627 | |
1628 | etm4_init_trace_id(drvdata); | |
1629 | etm4_set_default(&drvdata->config); | |
2e1cdfe1 | 1630 | |
af7cfd0f | 1631 | pdata = coresight_get_platform_data(dev); |
22a550a3 KP |
1632 | if (IS_ERR(pdata)) |
1633 | return PTR_ERR(pdata); | |
1634 | ||
af7cfd0f SP |
1635 | adev->dev.platform_data = pdata; |
1636 | ||
9486295a SP |
1637 | desc.type = CORESIGHT_DEV_TYPE_SOURCE; |
1638 | desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; | |
1639 | desc.ops = &etm4_cs_ops; | |
1640 | desc.pdata = pdata; | |
1641 | desc.dev = dev; | |
1642 | desc.groups = coresight_etmv4_groups; | |
1643 | drvdata->csdev = coresight_register(&desc); | |
22a550a3 KP |
1644 | if (IS_ERR(drvdata->csdev)) |
1645 | return PTR_ERR(drvdata->csdev); | |
2e1cdfe1 | 1646 | |
37fbbdbd MP |
1647 | ret = etm_perf_symlink(drvdata->csdev, true); |
1648 | if (ret) { | |
1649 | coresight_unregister(drvdata->csdev); | |
22a550a3 | 1650 | return ret; |
37fbbdbd MP |
1651 | } |
1652 | ||
22a550a3 KP |
1653 | etmdrvdata[drvdata->cpu] = drvdata; |
1654 | ||
37fbbdbd | 1655 | pm_runtime_put(&adev->dev); |
aaff7623 | 1656 | dev_info(&drvdata->csdev->dev, "CPU%d: ETM v%d.%d initialized\n", |
5cedd223 | 1657 | drvdata->cpu, drvdata->arch >> 4, drvdata->arch & 0xf); |
2e1cdfe1 PP |
1658 | |
1659 | if (boot_enable) { | |
1660 | coresight_enable(drvdata->csdev); | |
1661 | drvdata->boot_enable = true; | |
1662 | } | |
1663 | ||
e7255092 QL |
1664 | etm4_check_arch_features(drvdata, id->id); |
1665 | ||
2e1cdfe1 | 1666 | return 0; |
2e1cdfe1 PP |
1667 | } |
1668 | ||
28941701 ML |
1669 | static struct amba_cs_uci_id uci_id_etm4[] = { |
1670 | { | |
1671 | /* ETMv4 UCI data */ | |
1672 | .devarch = 0x47704a13, | |
1673 | .devarch_mask = 0xfff0ffff, | |
1674 | .devtype = 0x00000013, | |
5cedd223 | 1675 | } |
28941701 | 1676 | }; |
5cedd223 | 1677 | |
45fe7bef | 1678 | static void clear_etmdrvdata(void *info) |
22a550a3 KP |
1679 | { |
1680 | int cpu = *(int *)info; | |
1681 | ||
1682 | etmdrvdata[cpu] = NULL; | |
1683 | } | |
1684 | ||
45fe7bef | 1685 | static int etm4_remove(struct amba_device *adev) |
22a550a3 KP |
1686 | { |
1687 | struct etmv4_drvdata *drvdata = dev_get_drvdata(&adev->dev); | |
1688 | ||
1689 | etm_perf_symlink(drvdata->csdev, false); | |
1690 | ||
1691 | /* | |
1692 | * Taking hotplug lock here to avoid racing between etm4_remove and | |
1693 | * CPU hotplug call backs. | |
1694 | */ | |
1695 | cpus_read_lock(); | |
1696 | /* | |
1697 | * The readers for etmdrvdata[] are CPU hotplug call backs | |
1698 | * and PM notification call backs. Change etmdrvdata[i] on | |
1699 | * CPU i ensures these call backs has consistent view | |
1700 | * inside one call back function. | |
1701 | */ | |
1702 | if (smp_call_function_single(drvdata->cpu, clear_etmdrvdata, &drvdata->cpu, 1)) | |
1703 | etmdrvdata[drvdata->cpu] = NULL; | |
1704 | ||
1705 | cpus_read_unlock(); | |
1706 | ||
1707 | coresight_unregister(drvdata->csdev); | |
1708 | ||
1709 | return 0; | |
1710 | } | |
1711 | ||
c5520c93 | 1712 | static const struct amba_id etm4_ids[] = { |
17b4add0 SPR |
1713 | CS_AMBA_ID(0x000bb95d), /* Cortex-A53 */ |
1714 | CS_AMBA_ID(0x000bb95e), /* Cortex-A57 */ | |
1715 | CS_AMBA_ID(0x000bb95a), /* Cortex-A72 */ | |
1716 | CS_AMBA_ID(0x000bb959), /* Cortex-A73 */ | |
1717 | CS_AMBA_UCI_ID(0x000bb9da, uci_id_etm4),/* Cortex-A35 */ | |
fac28c4d | 1718 | CS_AMBA_UCI_ID(0x000bbd0c, uci_id_etm4),/* Neoverse N1 */ |
17b4add0 SPR |
1719 | CS_AMBA_UCI_ID(0x000f0205, uci_id_etm4),/* Qualcomm Kryo */ |
1720 | CS_AMBA_UCI_ID(0x000f0211, uci_id_etm4),/* Qualcomm Kryo */ | |
41e8c720 SPR |
1721 | CS_AMBA_UCI_ID(0x000bb802, uci_id_etm4),/* Qualcomm Kryo 385 Cortex-A55 */ |
1722 | CS_AMBA_UCI_ID(0x000bb803, uci_id_etm4),/* Qualcomm Kryo 385 Cortex-A75 */ | |
63314ca2 SPR |
1723 | CS_AMBA_UCI_ID(0x000bb805, uci_id_etm4),/* Qualcomm Kryo 4XX Cortex-A55 */ |
1724 | CS_AMBA_UCI_ID(0x000bb804, uci_id_etm4),/* Qualcomm Kryo 4XX Cortex-A76 */ | |
0373d906 | 1725 | CS_AMBA_UCI_ID(0x000cc0af, uci_id_etm4),/* Marvell ThunderX2 */ |
447a612e QL |
1726 | CS_AMBA_UCI_ID(0x000b6d01, uci_id_etm4),/* HiSilicon-Hip08 */ |
1727 | CS_AMBA_UCI_ID(0x000b6d02, uci_id_etm4),/* HiSilicon-Hip09 */ | |
5cedd223 | 1728 | {}, |
2e1cdfe1 PP |
1729 | }; |
1730 | ||
22a550a3 KP |
1731 | MODULE_DEVICE_TABLE(amba, etm4_ids); |
1732 | ||
2e1cdfe1 PP |
1733 | static struct amba_driver etm4x_driver = { |
1734 | .drv = { | |
1735 | .name = "coresight-etm4x", | |
22a550a3 | 1736 | .owner = THIS_MODULE, |
b15f0fb6 | 1737 | .suppress_bind_attrs = true, |
2e1cdfe1 PP |
1738 | }, |
1739 | .probe = etm4_probe, | |
22a550a3 | 1740 | .remove = etm4_remove, |
2e1cdfe1 PP |
1741 | .id_table = etm4_ids, |
1742 | }; | |
2d1a8bfb SPR |
1743 | |
1744 | static int __init etm4x_init(void) | |
1745 | { | |
1746 | int ret; | |
1747 | ||
1748 | ret = etm4_pm_setup(); | |
1749 | ||
1750 | /* etm4_pm_setup() does its own cleanup - exit on error */ | |
1751 | if (ret) | |
1752 | return ret; | |
1753 | ||
1754 | ret = amba_driver_register(&etm4x_driver); | |
1755 | if (ret) { | |
1756 | pr_err("Error registering etm4x driver\n"); | |
1757 | etm4_pm_clear(); | |
1758 | } | |
1759 | ||
1760 | return ret; | |
1761 | } | |
22a550a3 KP |
1762 | |
1763 | static void __exit etm4x_exit(void) | |
1764 | { | |
1765 | amba_driver_unregister(&etm4x_driver); | |
1766 | etm4_pm_clear(); | |
1767 | } | |
1768 | ||
1769 | module_init(etm4x_init); | |
1770 | module_exit(etm4x_exit); | |
1771 | ||
1772 | MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>"); | |
1773 | MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>"); | |
1774 | MODULE_DESCRIPTION("Arm CoreSight Program Flow Trace v4.x driver"); | |
1775 | MODULE_LICENSE("GPL v2"); |