Commit | Line | Data |
---|---|---|
c04148e7 MP |
1 | /* |
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | |
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License version 2 as published by | |
7 | * the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along with | |
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
17 | ||
18 | #include <linux/pm_runtime.h> | |
19 | #include <linux/sysfs.h> | |
20 | #include "coresight-etm.h" | |
2b7adc46 | 21 | #include "coresight-priv.h" |
c04148e7 MP |
22 | |
23 | static ssize_t nr_addr_cmp_show(struct device *dev, | |
24 | struct device_attribute *attr, char *buf) | |
25 | { | |
26 | unsigned long val; | |
27 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
28 | ||
29 | val = drvdata->nr_addr_cmp; | |
30 | return sprintf(buf, "%#lx\n", val); | |
31 | } | |
32 | static DEVICE_ATTR_RO(nr_addr_cmp); | |
33 | ||
34 | static ssize_t nr_cntr_show(struct device *dev, | |
35 | struct device_attribute *attr, char *buf) | |
36 | { unsigned long val; | |
37 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
38 | ||
39 | val = drvdata->nr_cntr; | |
40 | return sprintf(buf, "%#lx\n", val); | |
41 | } | |
42 | static DEVICE_ATTR_RO(nr_cntr); | |
43 | ||
44 | static ssize_t nr_ctxid_cmp_show(struct device *dev, | |
45 | struct device_attribute *attr, char *buf) | |
46 | { | |
47 | unsigned long val; | |
48 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
49 | ||
50 | val = drvdata->nr_ctxid_cmp; | |
51 | return sprintf(buf, "%#lx\n", val); | |
52 | } | |
53 | static DEVICE_ATTR_RO(nr_ctxid_cmp); | |
54 | ||
55 | static ssize_t etmsr_show(struct device *dev, | |
56 | struct device_attribute *attr, char *buf) | |
57 | { | |
58 | unsigned long flags, val; | |
59 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
60 | ||
61 | pm_runtime_get_sync(drvdata->dev); | |
62 | spin_lock_irqsave(&drvdata->spinlock, flags); | |
63 | CS_UNLOCK(drvdata->base); | |
64 | ||
65 | val = etm_readl(drvdata, ETMSR); | |
66 | ||
67 | CS_LOCK(drvdata->base); | |
68 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | |
69 | pm_runtime_put(drvdata->dev); | |
70 | ||
71 | return sprintf(buf, "%#lx\n", val); | |
72 | } | |
73 | static DEVICE_ATTR_RO(etmsr); | |
74 | ||
75 | static ssize_t reset_store(struct device *dev, | |
76 | struct device_attribute *attr, | |
77 | const char *buf, size_t size) | |
78 | { | |
79 | int i, ret; | |
80 | unsigned long val; | |
81 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 82 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
83 | |
84 | ret = kstrtoul(buf, 16, &val); | |
85 | if (ret) | |
86 | return ret; | |
87 | ||
88 | if (val) { | |
89 | spin_lock(&drvdata->spinlock); | |
1925a470 MP |
90 | memset(config, 0, sizeof(struct etm_config)); |
91 | config->mode = ETM_MODE_EXCLUDE; | |
92 | config->trigger_event = ETM_DEFAULT_EVENT_VAL; | |
c04148e7 | 93 | for (i = 0; i < drvdata->nr_addr_cmp; i++) { |
1925a470 | 94 | config->addr_type[i] = ETM_ADDR_TYPE_NONE; |
c04148e7 | 95 | } |
c04148e7 | 96 | |
1925a470 | 97 | etm_set_default(config); |
c04148e7 MP |
98 | spin_unlock(&drvdata->spinlock); |
99 | } | |
100 | ||
101 | return size; | |
102 | } | |
103 | static DEVICE_ATTR_WO(reset); | |
104 | ||
105 | static ssize_t mode_show(struct device *dev, | |
106 | struct device_attribute *attr, char *buf) | |
107 | { | |
108 | unsigned long val; | |
109 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 110 | struct etm_config *config = &drvdata->config; |
c04148e7 | 111 | |
1925a470 | 112 | val = config->mode; |
c04148e7 MP |
113 | return sprintf(buf, "%#lx\n", val); |
114 | } | |
115 | ||
116 | static ssize_t mode_store(struct device *dev, | |
117 | struct device_attribute *attr, | |
118 | const char *buf, size_t size) | |
119 | { | |
120 | int ret; | |
121 | unsigned long val; | |
122 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 123 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
124 | |
125 | ret = kstrtoul(buf, 16, &val); | |
126 | if (ret) | |
127 | return ret; | |
128 | ||
129 | spin_lock(&drvdata->spinlock); | |
1925a470 | 130 | config->mode = val & ETM_MODE_ALL; |
c04148e7 | 131 | |
1925a470 MP |
132 | if (config->mode & ETM_MODE_EXCLUDE) |
133 | config->enable_ctrl1 |= ETMTECR1_INC_EXC; | |
c04148e7 | 134 | else |
1925a470 | 135 | config->enable_ctrl1 &= ~ETMTECR1_INC_EXC; |
c04148e7 | 136 | |
1925a470 MP |
137 | if (config->mode & ETM_MODE_CYCACC) |
138 | config->ctrl |= ETMCR_CYC_ACC; | |
c04148e7 | 139 | else |
1925a470 | 140 | config->ctrl &= ~ETMCR_CYC_ACC; |
c04148e7 | 141 | |
1925a470 | 142 | if (config->mode & ETM_MODE_STALL) { |
c04148e7 MP |
143 | if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) { |
144 | dev_warn(drvdata->dev, "stall mode not supported\n"); | |
145 | ret = -EINVAL; | |
146 | goto err_unlock; | |
147 | } | |
1925a470 | 148 | config->ctrl |= ETMCR_STALL_MODE; |
c04148e7 | 149 | } else |
1925a470 | 150 | config->ctrl &= ~ETMCR_STALL_MODE; |
c04148e7 | 151 | |
1925a470 | 152 | if (config->mode & ETM_MODE_TIMESTAMP) { |
c04148e7 MP |
153 | if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) { |
154 | dev_warn(drvdata->dev, "timestamp not supported\n"); | |
155 | ret = -EINVAL; | |
156 | goto err_unlock; | |
157 | } | |
1925a470 | 158 | config->ctrl |= ETMCR_TIMESTAMP_EN; |
c04148e7 | 159 | } else |
1925a470 | 160 | config->ctrl &= ~ETMCR_TIMESTAMP_EN; |
c04148e7 | 161 | |
1925a470 MP |
162 | if (config->mode & ETM_MODE_CTXID) |
163 | config->ctrl |= ETMCR_CTXID_SIZE; | |
c04148e7 | 164 | else |
1925a470 | 165 | config->ctrl &= ~ETMCR_CTXID_SIZE; |
2127154d MP |
166 | |
167 | if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER)) | |
168 | etm_config_trace_mode(config); | |
169 | ||
c04148e7 MP |
170 | spin_unlock(&drvdata->spinlock); |
171 | ||
172 | return size; | |
173 | ||
174 | err_unlock: | |
175 | spin_unlock(&drvdata->spinlock); | |
176 | return ret; | |
177 | } | |
178 | static DEVICE_ATTR_RW(mode); | |
179 | ||
180 | static ssize_t trigger_event_show(struct device *dev, | |
181 | struct device_attribute *attr, char *buf) | |
182 | { | |
183 | unsigned long val; | |
184 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 185 | struct etm_config *config = &drvdata->config; |
c04148e7 | 186 | |
1925a470 | 187 | val = config->trigger_event; |
c04148e7 MP |
188 | return sprintf(buf, "%#lx\n", val); |
189 | } | |
190 | ||
191 | static ssize_t trigger_event_store(struct device *dev, | |
192 | struct device_attribute *attr, | |
193 | const char *buf, size_t size) | |
194 | { | |
195 | int ret; | |
196 | unsigned long val; | |
197 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 198 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
199 | |
200 | ret = kstrtoul(buf, 16, &val); | |
201 | if (ret) | |
202 | return ret; | |
203 | ||
1925a470 | 204 | config->trigger_event = val & ETM_EVENT_MASK; |
c04148e7 MP |
205 | |
206 | return size; | |
207 | } | |
208 | static DEVICE_ATTR_RW(trigger_event); | |
209 | ||
210 | static ssize_t enable_event_show(struct device *dev, | |
211 | struct device_attribute *attr, char *buf) | |
212 | { | |
213 | unsigned long val; | |
214 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 215 | struct etm_config *config = &drvdata->config; |
c04148e7 | 216 | |
1925a470 | 217 | val = config->enable_event; |
c04148e7 MP |
218 | return sprintf(buf, "%#lx\n", val); |
219 | } | |
220 | ||
221 | static ssize_t enable_event_store(struct device *dev, | |
222 | struct device_attribute *attr, | |
223 | const char *buf, size_t size) | |
224 | { | |
225 | int ret; | |
226 | unsigned long val; | |
227 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 228 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
229 | |
230 | ret = kstrtoul(buf, 16, &val); | |
231 | if (ret) | |
232 | return ret; | |
233 | ||
1925a470 | 234 | config->enable_event = val & ETM_EVENT_MASK; |
c04148e7 MP |
235 | |
236 | return size; | |
237 | } | |
238 | static DEVICE_ATTR_RW(enable_event); | |
239 | ||
240 | static ssize_t fifofull_level_show(struct device *dev, | |
241 | struct device_attribute *attr, char *buf) | |
242 | { | |
243 | unsigned long val; | |
244 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 245 | struct etm_config *config = &drvdata->config; |
c04148e7 | 246 | |
1925a470 | 247 | val = config->fifofull_level; |
c04148e7 MP |
248 | return sprintf(buf, "%#lx\n", val); |
249 | } | |
250 | ||
251 | static ssize_t fifofull_level_store(struct device *dev, | |
252 | struct device_attribute *attr, | |
253 | const char *buf, size_t size) | |
254 | { | |
255 | int ret; | |
256 | unsigned long val; | |
257 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 258 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
259 | |
260 | ret = kstrtoul(buf, 16, &val); | |
261 | if (ret) | |
262 | return ret; | |
263 | ||
1925a470 | 264 | config->fifofull_level = val; |
c04148e7 MP |
265 | |
266 | return size; | |
267 | } | |
268 | static DEVICE_ATTR_RW(fifofull_level); | |
269 | ||
270 | static ssize_t addr_idx_show(struct device *dev, | |
271 | struct device_attribute *attr, char *buf) | |
272 | { | |
273 | unsigned long val; | |
274 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 275 | struct etm_config *config = &drvdata->config; |
c04148e7 | 276 | |
1925a470 | 277 | val = config->addr_idx; |
c04148e7 MP |
278 | return sprintf(buf, "%#lx\n", val); |
279 | } | |
280 | ||
281 | static ssize_t addr_idx_store(struct device *dev, | |
282 | struct device_attribute *attr, | |
283 | const char *buf, size_t size) | |
284 | { | |
285 | int ret; | |
286 | unsigned long val; | |
287 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 288 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
289 | |
290 | ret = kstrtoul(buf, 16, &val); | |
291 | if (ret) | |
292 | return ret; | |
293 | ||
294 | if (val >= drvdata->nr_addr_cmp) | |
295 | return -EINVAL; | |
296 | ||
297 | /* | |
298 | * Use spinlock to ensure index doesn't change while it gets | |
299 | * dereferenced multiple times within a spinlock block elsewhere. | |
300 | */ | |
301 | spin_lock(&drvdata->spinlock); | |
1925a470 | 302 | config->addr_idx = val; |
c04148e7 MP |
303 | spin_unlock(&drvdata->spinlock); |
304 | ||
305 | return size; | |
306 | } | |
307 | static DEVICE_ATTR_RW(addr_idx); | |
308 | ||
309 | static ssize_t addr_single_show(struct device *dev, | |
310 | struct device_attribute *attr, char *buf) | |
311 | { | |
312 | u8 idx; | |
313 | unsigned long val; | |
314 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 315 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
316 | |
317 | spin_lock(&drvdata->spinlock); | |
1925a470 MP |
318 | idx = config->addr_idx; |
319 | if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || | |
320 | config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) { | |
c04148e7 MP |
321 | spin_unlock(&drvdata->spinlock); |
322 | return -EINVAL; | |
323 | } | |
324 | ||
1925a470 | 325 | val = config->addr_val[idx]; |
c04148e7 MP |
326 | spin_unlock(&drvdata->spinlock); |
327 | ||
328 | return sprintf(buf, "%#lx\n", val); | |
329 | } | |
330 | ||
331 | static ssize_t addr_single_store(struct device *dev, | |
332 | struct device_attribute *attr, | |
333 | const char *buf, size_t size) | |
334 | { | |
335 | u8 idx; | |
336 | int ret; | |
337 | unsigned long val; | |
338 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 339 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
340 | |
341 | ret = kstrtoul(buf, 16, &val); | |
342 | if (ret) | |
343 | return ret; | |
344 | ||
345 | spin_lock(&drvdata->spinlock); | |
1925a470 MP |
346 | idx = config->addr_idx; |
347 | if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || | |
348 | config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) { | |
c04148e7 MP |
349 | spin_unlock(&drvdata->spinlock); |
350 | return -EINVAL; | |
351 | } | |
352 | ||
1925a470 MP |
353 | config->addr_val[idx] = val; |
354 | config->addr_type[idx] = ETM_ADDR_TYPE_SINGLE; | |
c04148e7 MP |
355 | spin_unlock(&drvdata->spinlock); |
356 | ||
357 | return size; | |
358 | } | |
359 | static DEVICE_ATTR_RW(addr_single); | |
360 | ||
361 | static ssize_t addr_range_show(struct device *dev, | |
362 | struct device_attribute *attr, char *buf) | |
363 | { | |
364 | u8 idx; | |
365 | unsigned long val1, val2; | |
366 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 367 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
368 | |
369 | spin_lock(&drvdata->spinlock); | |
1925a470 | 370 | idx = config->addr_idx; |
c04148e7 MP |
371 | if (idx % 2 != 0) { |
372 | spin_unlock(&drvdata->spinlock); | |
373 | return -EPERM; | |
374 | } | |
1925a470 MP |
375 | if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE && |
376 | config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) || | |
377 | (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE && | |
378 | config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) { | |
c04148e7 MP |
379 | spin_unlock(&drvdata->spinlock); |
380 | return -EPERM; | |
381 | } | |
382 | ||
1925a470 MP |
383 | val1 = config->addr_val[idx]; |
384 | val2 = config->addr_val[idx + 1]; | |
c04148e7 MP |
385 | spin_unlock(&drvdata->spinlock); |
386 | ||
387 | return sprintf(buf, "%#lx %#lx\n", val1, val2); | |
388 | } | |
389 | ||
390 | static ssize_t addr_range_store(struct device *dev, | |
391 | struct device_attribute *attr, | |
392 | const char *buf, size_t size) | |
393 | { | |
394 | u8 idx; | |
395 | unsigned long val1, val2; | |
396 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 397 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
398 | |
399 | if (sscanf(buf, "%lx %lx", &val1, &val2) != 2) | |
400 | return -EINVAL; | |
401 | /* Lower address comparator cannot have a higher address value */ | |
402 | if (val1 > val2) | |
403 | return -EINVAL; | |
404 | ||
405 | spin_lock(&drvdata->spinlock); | |
1925a470 | 406 | idx = config->addr_idx; |
c04148e7 MP |
407 | if (idx % 2 != 0) { |
408 | spin_unlock(&drvdata->spinlock); | |
409 | return -EPERM; | |
410 | } | |
1925a470 MP |
411 | if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE && |
412 | config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) || | |
413 | (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE && | |
414 | config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) { | |
c04148e7 MP |
415 | spin_unlock(&drvdata->spinlock); |
416 | return -EPERM; | |
417 | } | |
418 | ||
1925a470 MP |
419 | config->addr_val[idx] = val1; |
420 | config->addr_type[idx] = ETM_ADDR_TYPE_RANGE; | |
421 | config->addr_val[idx + 1] = val2; | |
422 | config->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE; | |
423 | config->enable_ctrl1 |= (1 << (idx/2)); | |
c04148e7 MP |
424 | spin_unlock(&drvdata->spinlock); |
425 | ||
426 | return size; | |
427 | } | |
428 | static DEVICE_ATTR_RW(addr_range); | |
429 | ||
430 | static ssize_t addr_start_show(struct device *dev, | |
431 | struct device_attribute *attr, char *buf) | |
432 | { | |
433 | u8 idx; | |
434 | unsigned long val; | |
435 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 436 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
437 | |
438 | spin_lock(&drvdata->spinlock); | |
1925a470 MP |
439 | idx = config->addr_idx; |
440 | if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || | |
441 | config->addr_type[idx] == ETM_ADDR_TYPE_START)) { | |
c04148e7 MP |
442 | spin_unlock(&drvdata->spinlock); |
443 | return -EPERM; | |
444 | } | |
445 | ||
1925a470 | 446 | val = config->addr_val[idx]; |
c04148e7 MP |
447 | spin_unlock(&drvdata->spinlock); |
448 | ||
449 | return sprintf(buf, "%#lx\n", val); | |
450 | } | |
451 | ||
452 | static ssize_t addr_start_store(struct device *dev, | |
453 | struct device_attribute *attr, | |
454 | const char *buf, size_t size) | |
455 | { | |
456 | u8 idx; | |
457 | int ret; | |
458 | unsigned long val; | |
459 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 460 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
461 | |
462 | ret = kstrtoul(buf, 16, &val); | |
463 | if (ret) | |
464 | return ret; | |
465 | ||
466 | spin_lock(&drvdata->spinlock); | |
1925a470 MP |
467 | idx = config->addr_idx; |
468 | if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || | |
469 | config->addr_type[idx] == ETM_ADDR_TYPE_START)) { | |
c04148e7 MP |
470 | spin_unlock(&drvdata->spinlock); |
471 | return -EPERM; | |
472 | } | |
473 | ||
1925a470 MP |
474 | config->addr_val[idx] = val; |
475 | config->addr_type[idx] = ETM_ADDR_TYPE_START; | |
476 | config->startstop_ctrl |= (1 << idx); | |
477 | config->enable_ctrl1 |= BIT(25); | |
c04148e7 MP |
478 | spin_unlock(&drvdata->spinlock); |
479 | ||
480 | return size; | |
481 | } | |
482 | static DEVICE_ATTR_RW(addr_start); | |
483 | ||
484 | static ssize_t addr_stop_show(struct device *dev, | |
485 | struct device_attribute *attr, char *buf) | |
486 | { | |
487 | u8 idx; | |
488 | unsigned long val; | |
489 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 490 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
491 | |
492 | spin_lock(&drvdata->spinlock); | |
1925a470 MP |
493 | idx = config->addr_idx; |
494 | if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || | |
495 | config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) { | |
c04148e7 MP |
496 | spin_unlock(&drvdata->spinlock); |
497 | return -EPERM; | |
498 | } | |
499 | ||
1925a470 | 500 | val = config->addr_val[idx]; |
c04148e7 MP |
501 | spin_unlock(&drvdata->spinlock); |
502 | ||
503 | return sprintf(buf, "%#lx\n", val); | |
504 | } | |
505 | ||
506 | static ssize_t addr_stop_store(struct device *dev, | |
507 | struct device_attribute *attr, | |
508 | const char *buf, size_t size) | |
509 | { | |
510 | u8 idx; | |
511 | int ret; | |
512 | unsigned long val; | |
513 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 514 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
515 | |
516 | ret = kstrtoul(buf, 16, &val); | |
517 | if (ret) | |
518 | return ret; | |
519 | ||
520 | spin_lock(&drvdata->spinlock); | |
1925a470 MP |
521 | idx = config->addr_idx; |
522 | if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE || | |
523 | config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) { | |
c04148e7 MP |
524 | spin_unlock(&drvdata->spinlock); |
525 | return -EPERM; | |
526 | } | |
527 | ||
1925a470 MP |
528 | config->addr_val[idx] = val; |
529 | config->addr_type[idx] = ETM_ADDR_TYPE_STOP; | |
530 | config->startstop_ctrl |= (1 << (idx + 16)); | |
531 | config->enable_ctrl1 |= ETMTECR1_START_STOP; | |
c04148e7 MP |
532 | spin_unlock(&drvdata->spinlock); |
533 | ||
534 | return size; | |
535 | } | |
536 | static DEVICE_ATTR_RW(addr_stop); | |
537 | ||
538 | static ssize_t addr_acctype_show(struct device *dev, | |
539 | struct device_attribute *attr, char *buf) | |
540 | { | |
541 | unsigned long val; | |
542 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 543 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
544 | |
545 | spin_lock(&drvdata->spinlock); | |
1925a470 | 546 | val = config->addr_acctype[config->addr_idx]; |
c04148e7 MP |
547 | spin_unlock(&drvdata->spinlock); |
548 | ||
549 | return sprintf(buf, "%#lx\n", val); | |
550 | } | |
551 | ||
552 | static ssize_t addr_acctype_store(struct device *dev, | |
553 | struct device_attribute *attr, | |
554 | const char *buf, size_t size) | |
555 | { | |
556 | int ret; | |
557 | unsigned long val; | |
558 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 559 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
560 | |
561 | ret = kstrtoul(buf, 16, &val); | |
562 | if (ret) | |
563 | return ret; | |
564 | ||
565 | spin_lock(&drvdata->spinlock); | |
1925a470 | 566 | config->addr_acctype[config->addr_idx] = val; |
c04148e7 MP |
567 | spin_unlock(&drvdata->spinlock); |
568 | ||
569 | return size; | |
570 | } | |
571 | static DEVICE_ATTR_RW(addr_acctype); | |
572 | ||
573 | static ssize_t cntr_idx_show(struct device *dev, | |
574 | struct device_attribute *attr, char *buf) | |
575 | { | |
576 | unsigned long val; | |
577 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 578 | struct etm_config *config = &drvdata->config; |
c04148e7 | 579 | |
1925a470 | 580 | val = config->cntr_idx; |
c04148e7 MP |
581 | return sprintf(buf, "%#lx\n", val); |
582 | } | |
583 | ||
584 | static ssize_t cntr_idx_store(struct device *dev, | |
585 | struct device_attribute *attr, | |
586 | const char *buf, size_t size) | |
587 | { | |
588 | int ret; | |
589 | unsigned long val; | |
590 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 591 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
592 | |
593 | ret = kstrtoul(buf, 16, &val); | |
594 | if (ret) | |
595 | return ret; | |
596 | ||
597 | if (val >= drvdata->nr_cntr) | |
598 | return -EINVAL; | |
599 | /* | |
600 | * Use spinlock to ensure index doesn't change while it gets | |
601 | * dereferenced multiple times within a spinlock block elsewhere. | |
602 | */ | |
603 | spin_lock(&drvdata->spinlock); | |
1925a470 | 604 | config->cntr_idx = val; |
c04148e7 MP |
605 | spin_unlock(&drvdata->spinlock); |
606 | ||
607 | return size; | |
608 | } | |
609 | static DEVICE_ATTR_RW(cntr_idx); | |
610 | ||
611 | static ssize_t cntr_rld_val_show(struct device *dev, | |
612 | struct device_attribute *attr, char *buf) | |
613 | { | |
614 | unsigned long val; | |
615 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 616 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
617 | |
618 | spin_lock(&drvdata->spinlock); | |
1925a470 | 619 | val = config->cntr_rld_val[config->cntr_idx]; |
c04148e7 MP |
620 | spin_unlock(&drvdata->spinlock); |
621 | ||
622 | return sprintf(buf, "%#lx\n", val); | |
623 | } | |
624 | ||
625 | static ssize_t cntr_rld_val_store(struct device *dev, | |
626 | struct device_attribute *attr, | |
627 | const char *buf, size_t size) | |
628 | { | |
629 | int ret; | |
630 | unsigned long val; | |
631 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 632 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
633 | |
634 | ret = kstrtoul(buf, 16, &val); | |
635 | if (ret) | |
636 | return ret; | |
637 | ||
638 | spin_lock(&drvdata->spinlock); | |
1925a470 | 639 | config->cntr_rld_val[config->cntr_idx] = val; |
c04148e7 MP |
640 | spin_unlock(&drvdata->spinlock); |
641 | ||
642 | return size; | |
643 | } | |
644 | static DEVICE_ATTR_RW(cntr_rld_val); | |
645 | ||
646 | static ssize_t cntr_event_show(struct device *dev, | |
647 | struct device_attribute *attr, char *buf) | |
648 | { | |
649 | unsigned long val; | |
650 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 651 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
652 | |
653 | spin_lock(&drvdata->spinlock); | |
1925a470 | 654 | val = config->cntr_event[config->cntr_idx]; |
c04148e7 MP |
655 | spin_unlock(&drvdata->spinlock); |
656 | ||
657 | return sprintf(buf, "%#lx\n", val); | |
658 | } | |
659 | ||
660 | static ssize_t cntr_event_store(struct device *dev, | |
661 | struct device_attribute *attr, | |
662 | const char *buf, size_t size) | |
663 | { | |
664 | int ret; | |
665 | unsigned long val; | |
666 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 667 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
668 | |
669 | ret = kstrtoul(buf, 16, &val); | |
670 | if (ret) | |
671 | return ret; | |
672 | ||
673 | spin_lock(&drvdata->spinlock); | |
1925a470 | 674 | config->cntr_event[config->cntr_idx] = val & ETM_EVENT_MASK; |
c04148e7 MP |
675 | spin_unlock(&drvdata->spinlock); |
676 | ||
677 | return size; | |
678 | } | |
679 | static DEVICE_ATTR_RW(cntr_event); | |
680 | ||
681 | static ssize_t cntr_rld_event_show(struct device *dev, | |
682 | struct device_attribute *attr, char *buf) | |
683 | { | |
684 | unsigned long val; | |
685 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 686 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
687 | |
688 | spin_lock(&drvdata->spinlock); | |
1925a470 | 689 | val = config->cntr_rld_event[config->cntr_idx]; |
c04148e7 MP |
690 | spin_unlock(&drvdata->spinlock); |
691 | ||
692 | return sprintf(buf, "%#lx\n", val); | |
693 | } | |
694 | ||
695 | static ssize_t cntr_rld_event_store(struct device *dev, | |
696 | struct device_attribute *attr, | |
697 | const char *buf, size_t size) | |
698 | { | |
699 | int ret; | |
700 | unsigned long val; | |
701 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 702 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
703 | |
704 | ret = kstrtoul(buf, 16, &val); | |
705 | if (ret) | |
706 | return ret; | |
707 | ||
708 | spin_lock(&drvdata->spinlock); | |
1925a470 | 709 | config->cntr_rld_event[config->cntr_idx] = val & ETM_EVENT_MASK; |
c04148e7 MP |
710 | spin_unlock(&drvdata->spinlock); |
711 | ||
712 | return size; | |
713 | } | |
714 | static DEVICE_ATTR_RW(cntr_rld_event); | |
715 | ||
716 | static ssize_t cntr_val_show(struct device *dev, | |
717 | struct device_attribute *attr, char *buf) | |
718 | { | |
719 | int i, ret = 0; | |
720 | u32 val; | |
721 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 722 | struct etm_config *config = &drvdata->config; |
c04148e7 | 723 | |
22fd532e | 724 | if (!local_read(&drvdata->mode)) { |
c04148e7 MP |
725 | spin_lock(&drvdata->spinlock); |
726 | for (i = 0; i < drvdata->nr_cntr; i++) | |
727 | ret += sprintf(buf, "counter %d: %x\n", | |
1925a470 | 728 | i, config->cntr_val[i]); |
c04148e7 MP |
729 | spin_unlock(&drvdata->spinlock); |
730 | return ret; | |
731 | } | |
732 | ||
733 | for (i = 0; i < drvdata->nr_cntr; i++) { | |
734 | val = etm_readl(drvdata, ETMCNTVRn(i)); | |
735 | ret += sprintf(buf, "counter %d: %x\n", i, val); | |
736 | } | |
737 | ||
738 | return ret; | |
739 | } | |
740 | ||
741 | static ssize_t cntr_val_store(struct device *dev, | |
742 | struct device_attribute *attr, | |
743 | const char *buf, size_t size) | |
744 | { | |
745 | int ret; | |
746 | unsigned long val; | |
747 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 748 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
749 | |
750 | ret = kstrtoul(buf, 16, &val); | |
751 | if (ret) | |
752 | return ret; | |
753 | ||
754 | spin_lock(&drvdata->spinlock); | |
1925a470 | 755 | config->cntr_val[config->cntr_idx] = val; |
c04148e7 MP |
756 | spin_unlock(&drvdata->spinlock); |
757 | ||
758 | return size; | |
759 | } | |
760 | static DEVICE_ATTR_RW(cntr_val); | |
761 | ||
762 | static ssize_t seq_12_event_show(struct device *dev, | |
763 | struct device_attribute *attr, char *buf) | |
764 | { | |
765 | unsigned long val; | |
766 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 767 | struct etm_config *config = &drvdata->config; |
c04148e7 | 768 | |
1925a470 | 769 | val = config->seq_12_event; |
c04148e7 MP |
770 | return sprintf(buf, "%#lx\n", val); |
771 | } | |
772 | ||
773 | static ssize_t seq_12_event_store(struct device *dev, | |
774 | struct device_attribute *attr, | |
775 | const char *buf, size_t size) | |
776 | { | |
777 | int ret; | |
778 | unsigned long val; | |
779 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 780 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
781 | |
782 | ret = kstrtoul(buf, 16, &val); | |
783 | if (ret) | |
784 | return ret; | |
785 | ||
1925a470 | 786 | config->seq_12_event = val & ETM_EVENT_MASK; |
c04148e7 MP |
787 | return size; |
788 | } | |
789 | static DEVICE_ATTR_RW(seq_12_event); | |
790 | ||
791 | static ssize_t seq_21_event_show(struct device *dev, | |
792 | struct device_attribute *attr, char *buf) | |
793 | { | |
794 | unsigned long val; | |
795 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 796 | struct etm_config *config = &drvdata->config; |
c04148e7 | 797 | |
1925a470 | 798 | val = config->seq_21_event; |
c04148e7 MP |
799 | return sprintf(buf, "%#lx\n", val); |
800 | } | |
801 | ||
802 | static ssize_t seq_21_event_store(struct device *dev, | |
803 | struct device_attribute *attr, | |
804 | const char *buf, size_t size) | |
805 | { | |
806 | int ret; | |
807 | unsigned long val; | |
808 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 809 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
810 | |
811 | ret = kstrtoul(buf, 16, &val); | |
812 | if (ret) | |
813 | return ret; | |
814 | ||
1925a470 | 815 | config->seq_21_event = val & ETM_EVENT_MASK; |
c04148e7 MP |
816 | return size; |
817 | } | |
818 | static DEVICE_ATTR_RW(seq_21_event); | |
819 | ||
820 | static ssize_t seq_23_event_show(struct device *dev, | |
821 | struct device_attribute *attr, char *buf) | |
822 | { | |
823 | unsigned long val; | |
824 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 825 | struct etm_config *config = &drvdata->config; |
c04148e7 | 826 | |
1925a470 | 827 | val = config->seq_23_event; |
c04148e7 MP |
828 | return sprintf(buf, "%#lx\n", val); |
829 | } | |
830 | ||
831 | static ssize_t seq_23_event_store(struct device *dev, | |
832 | struct device_attribute *attr, | |
833 | const char *buf, size_t size) | |
834 | { | |
835 | int ret; | |
836 | unsigned long val; | |
837 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 838 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
839 | |
840 | ret = kstrtoul(buf, 16, &val); | |
841 | if (ret) | |
842 | return ret; | |
843 | ||
1925a470 | 844 | config->seq_23_event = val & ETM_EVENT_MASK; |
c04148e7 MP |
845 | return size; |
846 | } | |
847 | static DEVICE_ATTR_RW(seq_23_event); | |
848 | ||
849 | static ssize_t seq_31_event_show(struct device *dev, | |
850 | struct device_attribute *attr, char *buf) | |
851 | { | |
852 | unsigned long val; | |
853 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 854 | struct etm_config *config = &drvdata->config; |
c04148e7 | 855 | |
1925a470 | 856 | val = config->seq_31_event; |
c04148e7 MP |
857 | return sprintf(buf, "%#lx\n", val); |
858 | } | |
859 | ||
860 | static ssize_t seq_31_event_store(struct device *dev, | |
861 | struct device_attribute *attr, | |
862 | const char *buf, size_t size) | |
863 | { | |
864 | int ret; | |
865 | unsigned long val; | |
866 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 867 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
868 | |
869 | ret = kstrtoul(buf, 16, &val); | |
870 | if (ret) | |
871 | return ret; | |
872 | ||
1925a470 | 873 | config->seq_31_event = val & ETM_EVENT_MASK; |
c04148e7 MP |
874 | return size; |
875 | } | |
876 | static DEVICE_ATTR_RW(seq_31_event); | |
877 | ||
878 | static ssize_t seq_32_event_show(struct device *dev, | |
879 | struct device_attribute *attr, char *buf) | |
880 | { | |
881 | unsigned long val; | |
882 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 883 | struct etm_config *config = &drvdata->config; |
c04148e7 | 884 | |
1925a470 | 885 | val = config->seq_32_event; |
c04148e7 MP |
886 | return sprintf(buf, "%#lx\n", val); |
887 | } | |
888 | ||
889 | static ssize_t seq_32_event_store(struct device *dev, | |
890 | struct device_attribute *attr, | |
891 | const char *buf, size_t size) | |
892 | { | |
893 | int ret; | |
894 | unsigned long val; | |
895 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 896 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
897 | |
898 | ret = kstrtoul(buf, 16, &val); | |
899 | if (ret) | |
900 | return ret; | |
901 | ||
1925a470 | 902 | config->seq_32_event = val & ETM_EVENT_MASK; |
c04148e7 MP |
903 | return size; |
904 | } | |
905 | static DEVICE_ATTR_RW(seq_32_event); | |
906 | ||
907 | static ssize_t seq_13_event_show(struct device *dev, | |
908 | struct device_attribute *attr, char *buf) | |
909 | { | |
910 | unsigned long val; | |
911 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 912 | struct etm_config *config = &drvdata->config; |
c04148e7 | 913 | |
1925a470 | 914 | val = config->seq_13_event; |
c04148e7 MP |
915 | return sprintf(buf, "%#lx\n", val); |
916 | } | |
917 | ||
918 | static ssize_t seq_13_event_store(struct device *dev, | |
919 | struct device_attribute *attr, | |
920 | const char *buf, size_t size) | |
921 | { | |
922 | int ret; | |
923 | unsigned long val; | |
924 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 925 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
926 | |
927 | ret = kstrtoul(buf, 16, &val); | |
928 | if (ret) | |
929 | return ret; | |
930 | ||
1925a470 | 931 | config->seq_13_event = val & ETM_EVENT_MASK; |
c04148e7 MP |
932 | return size; |
933 | } | |
934 | static DEVICE_ATTR_RW(seq_13_event); | |
935 | ||
936 | static ssize_t seq_curr_state_show(struct device *dev, | |
937 | struct device_attribute *attr, char *buf) | |
938 | { | |
939 | unsigned long val, flags; | |
940 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 941 | struct etm_config *config = &drvdata->config; |
c04148e7 | 942 | |
22fd532e | 943 | if (!local_read(&drvdata->mode)) { |
1925a470 | 944 | val = config->seq_curr_state; |
c04148e7 MP |
945 | goto out; |
946 | } | |
947 | ||
948 | pm_runtime_get_sync(drvdata->dev); | |
949 | spin_lock_irqsave(&drvdata->spinlock, flags); | |
950 | ||
951 | CS_UNLOCK(drvdata->base); | |
952 | val = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK); | |
953 | CS_LOCK(drvdata->base); | |
954 | ||
955 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | |
956 | pm_runtime_put(drvdata->dev); | |
957 | out: | |
958 | return sprintf(buf, "%#lx\n", val); | |
959 | } | |
960 | ||
961 | static ssize_t seq_curr_state_store(struct device *dev, | |
962 | struct device_attribute *attr, | |
963 | const char *buf, size_t size) | |
964 | { | |
965 | int ret; | |
966 | unsigned long val; | |
967 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 968 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
969 | |
970 | ret = kstrtoul(buf, 16, &val); | |
971 | if (ret) | |
972 | return ret; | |
973 | ||
974 | if (val > ETM_SEQ_STATE_MAX_VAL) | |
975 | return -EINVAL; | |
976 | ||
1925a470 | 977 | config->seq_curr_state = val; |
c04148e7 MP |
978 | |
979 | return size; | |
980 | } | |
981 | static DEVICE_ATTR_RW(seq_curr_state); | |
982 | ||
983 | static ssize_t ctxid_idx_show(struct device *dev, | |
984 | struct device_attribute *attr, char *buf) | |
985 | { | |
986 | unsigned long val; | |
987 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 988 | struct etm_config *config = &drvdata->config; |
c04148e7 | 989 | |
1925a470 | 990 | val = config->ctxid_idx; |
c04148e7 MP |
991 | return sprintf(buf, "%#lx\n", val); |
992 | } | |
993 | ||
994 | static ssize_t ctxid_idx_store(struct device *dev, | |
995 | struct device_attribute *attr, | |
996 | const char *buf, size_t size) | |
997 | { | |
998 | int ret; | |
999 | unsigned long val; | |
1000 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 1001 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
1002 | |
1003 | ret = kstrtoul(buf, 16, &val); | |
1004 | if (ret) | |
1005 | return ret; | |
1006 | ||
1007 | if (val >= drvdata->nr_ctxid_cmp) | |
1008 | return -EINVAL; | |
1009 | ||
1010 | /* | |
1011 | * Use spinlock to ensure index doesn't change while it gets | |
1012 | * dereferenced multiple times within a spinlock block elsewhere. | |
1013 | */ | |
1014 | spin_lock(&drvdata->spinlock); | |
1925a470 | 1015 | config->ctxid_idx = val; |
c04148e7 MP |
1016 | spin_unlock(&drvdata->spinlock); |
1017 | ||
1018 | return size; | |
1019 | } | |
1020 | static DEVICE_ATTR_RW(ctxid_idx); | |
1021 | ||
1022 | static ssize_t ctxid_pid_show(struct device *dev, | |
1023 | struct device_attribute *attr, char *buf) | |
1024 | { | |
1025 | unsigned long val; | |
1026 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 1027 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
1028 | |
1029 | spin_lock(&drvdata->spinlock); | |
1925a470 | 1030 | val = config->ctxid_vpid[config->ctxid_idx]; |
c04148e7 MP |
1031 | spin_unlock(&drvdata->spinlock); |
1032 | ||
1033 | return sprintf(buf, "%#lx\n", val); | |
1034 | } | |
1035 | ||
1036 | static ssize_t ctxid_pid_store(struct device *dev, | |
1037 | struct device_attribute *attr, | |
1038 | const char *buf, size_t size) | |
1039 | { | |
1040 | int ret; | |
1041 | unsigned long vpid, pid; | |
1042 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 1043 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
1044 | |
1045 | ret = kstrtoul(buf, 16, &vpid); | |
1046 | if (ret) | |
1047 | return ret; | |
1048 | ||
1049 | pid = coresight_vpid_to_pid(vpid); | |
1050 | ||
1051 | spin_lock(&drvdata->spinlock); | |
1925a470 MP |
1052 | config->ctxid_pid[config->ctxid_idx] = pid; |
1053 | config->ctxid_vpid[config->ctxid_idx] = vpid; | |
c04148e7 MP |
1054 | spin_unlock(&drvdata->spinlock); |
1055 | ||
1056 | return size; | |
1057 | } | |
1058 | static DEVICE_ATTR_RW(ctxid_pid); | |
1059 | ||
1060 | static ssize_t ctxid_mask_show(struct device *dev, | |
1061 | struct device_attribute *attr, char *buf) | |
1062 | { | |
1063 | unsigned long val; | |
1064 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 1065 | struct etm_config *config = &drvdata->config; |
c04148e7 | 1066 | |
1925a470 | 1067 | val = config->ctxid_mask; |
c04148e7 MP |
1068 | return sprintf(buf, "%#lx\n", val); |
1069 | } | |
1070 | ||
1071 | static ssize_t ctxid_mask_store(struct device *dev, | |
1072 | struct device_attribute *attr, | |
1073 | const char *buf, size_t size) | |
1074 | { | |
1075 | int ret; | |
1076 | unsigned long val; | |
1077 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 1078 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
1079 | |
1080 | ret = kstrtoul(buf, 16, &val); | |
1081 | if (ret) | |
1082 | return ret; | |
1083 | ||
1925a470 | 1084 | config->ctxid_mask = val; |
c04148e7 MP |
1085 | return size; |
1086 | } | |
1087 | static DEVICE_ATTR_RW(ctxid_mask); | |
1088 | ||
1089 | static ssize_t sync_freq_show(struct device *dev, | |
1090 | struct device_attribute *attr, char *buf) | |
1091 | { | |
1092 | unsigned long val; | |
1093 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 1094 | struct etm_config *config = &drvdata->config; |
c04148e7 | 1095 | |
1925a470 | 1096 | val = config->sync_freq; |
c04148e7 MP |
1097 | return sprintf(buf, "%#lx\n", val); |
1098 | } | |
1099 | ||
1100 | static ssize_t sync_freq_store(struct device *dev, | |
1101 | struct device_attribute *attr, | |
1102 | const char *buf, size_t size) | |
1103 | { | |
1104 | int ret; | |
1105 | unsigned long val; | |
1106 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 1107 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
1108 | |
1109 | ret = kstrtoul(buf, 16, &val); | |
1110 | if (ret) | |
1111 | return ret; | |
1112 | ||
1925a470 | 1113 | config->sync_freq = val & ETM_SYNC_MASK; |
c04148e7 MP |
1114 | return size; |
1115 | } | |
1116 | static DEVICE_ATTR_RW(sync_freq); | |
1117 | ||
1118 | static ssize_t timestamp_event_show(struct device *dev, | |
1119 | struct device_attribute *attr, char *buf) | |
1120 | { | |
1121 | unsigned long val; | |
1122 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 1123 | struct etm_config *config = &drvdata->config; |
c04148e7 | 1124 | |
1925a470 | 1125 | val = config->timestamp_event; |
c04148e7 MP |
1126 | return sprintf(buf, "%#lx\n", val); |
1127 | } | |
1128 | ||
1129 | static ssize_t timestamp_event_store(struct device *dev, | |
1130 | struct device_attribute *attr, | |
1131 | const char *buf, size_t size) | |
1132 | { | |
1133 | int ret; | |
1134 | unsigned long val; | |
1135 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1925a470 | 1136 | struct etm_config *config = &drvdata->config; |
c04148e7 MP |
1137 | |
1138 | ret = kstrtoul(buf, 16, &val); | |
1139 | if (ret) | |
1140 | return ret; | |
1141 | ||
1925a470 | 1142 | config->timestamp_event = val & ETM_EVENT_MASK; |
c04148e7 MP |
1143 | return size; |
1144 | } | |
1145 | static DEVICE_ATTR_RW(timestamp_event); | |
1146 | ||
1147 | static ssize_t cpu_show(struct device *dev, | |
1148 | struct device_attribute *attr, char *buf) | |
1149 | { | |
1150 | int val; | |
1151 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1152 | ||
1153 | val = drvdata->cpu; | |
1154 | return scnprintf(buf, PAGE_SIZE, "%d\n", val); | |
1155 | ||
1156 | } | |
1157 | static DEVICE_ATTR_RO(cpu); | |
1158 | ||
1159 | static ssize_t traceid_show(struct device *dev, | |
1160 | struct device_attribute *attr, char *buf) | |
1161 | { | |
1162 | unsigned long val; | |
1163 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1164 | ||
1165 | val = etm_get_trace_id(drvdata); | |
1166 | ||
1167 | return sprintf(buf, "%#lx\n", val); | |
1168 | } | |
1169 | ||
1170 | static ssize_t traceid_store(struct device *dev, | |
1171 | struct device_attribute *attr, | |
1172 | const char *buf, size_t size) | |
1173 | { | |
1174 | int ret; | |
1175 | unsigned long val; | |
1176 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | |
1177 | ||
1178 | ret = kstrtoul(buf, 16, &val); | |
1179 | if (ret) | |
1180 | return ret; | |
1181 | ||
1182 | drvdata->traceid = val & ETM_TRACEID_MASK; | |
1183 | return size; | |
1184 | } | |
1185 | static DEVICE_ATTR_RW(traceid); | |
1186 | ||
1187 | static struct attribute *coresight_etm_attrs[] = { | |
1188 | &dev_attr_nr_addr_cmp.attr, | |
1189 | &dev_attr_nr_cntr.attr, | |
1190 | &dev_attr_nr_ctxid_cmp.attr, | |
1191 | &dev_attr_etmsr.attr, | |
1192 | &dev_attr_reset.attr, | |
1193 | &dev_attr_mode.attr, | |
1194 | &dev_attr_trigger_event.attr, | |
1195 | &dev_attr_enable_event.attr, | |
1196 | &dev_attr_fifofull_level.attr, | |
1197 | &dev_attr_addr_idx.attr, | |
1198 | &dev_attr_addr_single.attr, | |
1199 | &dev_attr_addr_range.attr, | |
1200 | &dev_attr_addr_start.attr, | |
1201 | &dev_attr_addr_stop.attr, | |
1202 | &dev_attr_addr_acctype.attr, | |
1203 | &dev_attr_cntr_idx.attr, | |
1204 | &dev_attr_cntr_rld_val.attr, | |
1205 | &dev_attr_cntr_event.attr, | |
1206 | &dev_attr_cntr_rld_event.attr, | |
1207 | &dev_attr_cntr_val.attr, | |
1208 | &dev_attr_seq_12_event.attr, | |
1209 | &dev_attr_seq_21_event.attr, | |
1210 | &dev_attr_seq_23_event.attr, | |
1211 | &dev_attr_seq_31_event.attr, | |
1212 | &dev_attr_seq_32_event.attr, | |
1213 | &dev_attr_seq_13_event.attr, | |
1214 | &dev_attr_seq_curr_state.attr, | |
1215 | &dev_attr_ctxid_idx.attr, | |
1216 | &dev_attr_ctxid_pid.attr, | |
1217 | &dev_attr_ctxid_mask.attr, | |
1218 | &dev_attr_sync_freq.attr, | |
1219 | &dev_attr_timestamp_event.attr, | |
1220 | &dev_attr_traceid.attr, | |
1221 | &dev_attr_cpu.attr, | |
1222 | NULL, | |
1223 | }; | |
1224 | ||
154f3520 | 1225 | #define coresight_etm3x_simple_func(name, offset) \ |
3224dcc5 | 1226 | coresight_simple_func(struct etm_drvdata, NULL, name, offset) |
154f3520 MP |
1227 | |
1228 | coresight_etm3x_simple_func(etmccr, ETMCCR); | |
1229 | coresight_etm3x_simple_func(etmccer, ETMCCER); | |
1230 | coresight_etm3x_simple_func(etmscr, ETMSCR); | |
1231 | coresight_etm3x_simple_func(etmidr, ETMIDR); | |
1232 | coresight_etm3x_simple_func(etmcr, ETMCR); | |
1233 | coresight_etm3x_simple_func(etmtraceidr, ETMTRACEIDR); | |
1234 | coresight_etm3x_simple_func(etmteevr, ETMTEEVR); | |
1235 | coresight_etm3x_simple_func(etmtssvr, ETMTSSCR); | |
1236 | coresight_etm3x_simple_func(etmtecr1, ETMTECR1); | |
1237 | coresight_etm3x_simple_func(etmtecr2, ETMTECR2); | |
c04148e7 MP |
1238 | |
1239 | static struct attribute *coresight_etm_mgmt_attrs[] = { | |
1240 | &dev_attr_etmccr.attr, | |
1241 | &dev_attr_etmccer.attr, | |
1242 | &dev_attr_etmscr.attr, | |
1243 | &dev_attr_etmidr.attr, | |
1244 | &dev_attr_etmcr.attr, | |
1245 | &dev_attr_etmtraceidr.attr, | |
1246 | &dev_attr_etmteevr.attr, | |
1247 | &dev_attr_etmtssvr.attr, | |
1248 | &dev_attr_etmtecr1.attr, | |
1249 | &dev_attr_etmtecr2.attr, | |
1250 | NULL, | |
1251 | }; | |
1252 | ||
1253 | static const struct attribute_group coresight_etm_group = { | |
1254 | .attrs = coresight_etm_attrs, | |
1255 | }; | |
1256 | ||
1257 | static const struct attribute_group coresight_etm_mgmt_group = { | |
1258 | .attrs = coresight_etm_mgmt_attrs, | |
1259 | .name = "mgmt", | |
1260 | }; | |
1261 | ||
1262 | const struct attribute_group *coresight_etm_groups[] = { | |
1263 | &coresight_etm_group, | |
1264 | &coresight_etm_mgmt_group, | |
1265 | NULL, | |
1266 | }; |