Commit | Line | Data |
---|---|---|
ad0dfdfd MP |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (c) 2012, The Linux Foundation. All rights reserved. | |
a06ae860 PP |
4 | */ |
5 | ||
6 | #include <linux/kernel.h> | |
a06ae860 PP |
7 | #include <linux/init.h> |
8 | #include <linux/types.h> | |
9 | #include <linux/device.h> | |
10 | #include <linux/io.h> | |
11 | #include <linux/err.h> | |
12 | #include <linux/export.h> | |
13 | #include <linux/slab.h> | |
22644392 | 14 | #include <linux/stringhash.h> |
a06ae860 PP |
15 | #include <linux/mutex.h> |
16 | #include <linux/clk.h> | |
17 | #include <linux/coresight.h> | |
18 | #include <linux/of_platform.h> | |
19 | #include <linux/delay.h> | |
5da5325f | 20 | #include <linux/pm_runtime.h> |
a06ae860 | 21 | |
bb8e370b | 22 | #include "coresight-etm-perf.h" |
a06ae860 PP |
23 | #include "coresight-priv.h" |
24 | ||
25 | static DEFINE_MUTEX(coresight_mutex); | |
26 | ||
b3e94405 MP |
27 | /** |
28 | * struct coresight_node - elements of a path, from source to sink | |
29 | * @csdev: Address of an element. | |
30 | * @link: hook to the list. | |
31 | */ | |
32 | struct coresight_node { | |
33 | struct coresight_device *csdev; | |
34 | struct list_head link; | |
35 | }; | |
36 | ||
37 | /* | |
38 | * When operating Coresight drivers from the sysFS interface, only a single | |
39 | * path can exist from a tracer (associated to a CPU) to a sink. | |
40 | */ | |
a685d683 MP |
41 | static DEFINE_PER_CPU(struct list_head *, tracer_path); |
42 | ||
43 | /* | |
44 | * As of this writing only a single STM can be found in CS topologies. Since | |
45 | * there is no way to know if we'll ever see more and what kind of | |
46 | * configuration they will enact, for the time being only define a single path | |
47 | * for STM. | |
48 | */ | |
49 | static struct list_head *stm_path; | |
b3e94405 | 50 | |
0c3fc4d5 MP |
51 | /* |
52 | * When losing synchronisation a new barrier packet needs to be inserted at the | |
53 | * beginning of the data collected in a buffer. That way the decoder knows that | |
54 | * it needs to look for another sync sequence. | |
55 | */ | |
6f755e85 | 56 | const u32 barrier_pkt[4] = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff}; |
0c3fc4d5 | 57 | |
a06ae860 PP |
58 | static int coresight_id_match(struct device *dev, void *data) |
59 | { | |
60 | int trace_id, i_trace_id; | |
61 | struct coresight_device *csdev, *i_csdev; | |
62 | ||
63 | csdev = data; | |
64 | i_csdev = to_coresight_device(dev); | |
65 | ||
66 | /* | |
67 | * No need to care about oneself and components that are not | |
68 | * sources or not enabled | |
69 | */ | |
70 | if (i_csdev == csdev || !i_csdev->enable || | |
71 | i_csdev->type != CORESIGHT_DEV_TYPE_SOURCE) | |
72 | return 0; | |
73 | ||
74 | /* Get the source ID for both compoment */ | |
75 | trace_id = source_ops(csdev)->trace_id(csdev); | |
76 | i_trace_id = source_ops(i_csdev)->trace_id(i_csdev); | |
77 | ||
78 | /* All you need is one */ | |
79 | if (trace_id == i_trace_id) | |
80 | return 1; | |
81 | ||
82 | return 0; | |
83 | } | |
84 | ||
85 | static int coresight_source_is_unique(struct coresight_device *csdev) | |
86 | { | |
87 | int trace_id = source_ops(csdev)->trace_id(csdev); | |
88 | ||
89 | /* this shouldn't happen */ | |
90 | if (trace_id < 0) | |
91 | return 0; | |
92 | ||
93 | return !bus_for_each_dev(&coresight_bustype, NULL, | |
94 | csdev, coresight_id_match); | |
95 | } | |
96 | ||
b3e94405 MP |
97 | static int coresight_find_link_inport(struct coresight_device *csdev, |
98 | struct coresight_device *parent) | |
a06ae860 PP |
99 | { |
100 | int i; | |
a06ae860 PP |
101 | struct coresight_connection *conn; |
102 | ||
a06ae860 PP |
103 | for (i = 0; i < parent->nr_outport; i++) { |
104 | conn = &parent->conns[i]; | |
105 | if (conn->child_dev == csdev) | |
106 | return conn->child_port; | |
107 | } | |
108 | ||
109 | dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n", | |
110 | dev_name(&parent->dev), dev_name(&csdev->dev)); | |
111 | ||
fe470f5f | 112 | return -ENODEV; |
a06ae860 PP |
113 | } |
114 | ||
b3e94405 MP |
115 | static int coresight_find_link_outport(struct coresight_device *csdev, |
116 | struct coresight_device *child) | |
a06ae860 PP |
117 | { |
118 | int i; | |
a06ae860 PP |
119 | struct coresight_connection *conn; |
120 | ||
a06ae860 PP |
121 | for (i = 0; i < csdev->nr_outport; i++) { |
122 | conn = &csdev->conns[i]; | |
123 | if (conn->child_dev == child) | |
124 | return conn->outport; | |
125 | } | |
126 | ||
127 | dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n", | |
128 | dev_name(&csdev->dev), dev_name(&child->dev)); | |
129 | ||
fe470f5f | 130 | return -ENODEV; |
a06ae860 PP |
131 | } |
132 | ||
2478a6ae SP |
133 | static inline u32 coresight_read_claim_tags(void __iomem *base) |
134 | { | |
135 | return readl_relaxed(base + CORESIGHT_CLAIMCLR); | |
136 | } | |
137 | ||
138 | static inline bool coresight_is_claimed_self_hosted(void __iomem *base) | |
139 | { | |
140 | return coresight_read_claim_tags(base) == CORESIGHT_CLAIM_SELF_HOSTED; | |
141 | } | |
142 | ||
143 | static inline bool coresight_is_claimed_any(void __iomem *base) | |
144 | { | |
145 | return coresight_read_claim_tags(base) != 0; | |
146 | } | |
147 | ||
148 | static inline void coresight_set_claim_tags(void __iomem *base) | |
149 | { | |
150 | writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMSET); | |
151 | isb(); | |
152 | } | |
153 | ||
154 | static inline void coresight_clear_claim_tags(void __iomem *base) | |
155 | { | |
156 | writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMCLR); | |
157 | isb(); | |
158 | } | |
159 | ||
160 | /* | |
161 | * coresight_claim_device_unlocked : Claim the device for self-hosted usage | |
162 | * to prevent an external tool from touching this device. As per PSCI | |
163 | * standards, section "Preserving the execution context" => "Debug and Trace | |
164 | * save and Restore", DBGCLAIM[1] is reserved for Self-hosted debug/trace and | |
165 | * DBGCLAIM[0] is reserved for external tools. | |
166 | * | |
167 | * Called with CS_UNLOCKed for the component. | |
168 | * Returns : 0 on success | |
169 | */ | |
170 | int coresight_claim_device_unlocked(void __iomem *base) | |
171 | { | |
172 | if (coresight_is_claimed_any(base)) | |
173 | return -EBUSY; | |
174 | ||
175 | coresight_set_claim_tags(base); | |
176 | if (coresight_is_claimed_self_hosted(base)) | |
177 | return 0; | |
178 | /* There was a race setting the tags, clean up and fail */ | |
179 | coresight_clear_claim_tags(base); | |
180 | return -EBUSY; | |
181 | } | |
182 | ||
183 | int coresight_claim_device(void __iomem *base) | |
184 | { | |
185 | int rc; | |
186 | ||
187 | CS_UNLOCK(base); | |
188 | rc = coresight_claim_device_unlocked(base); | |
189 | CS_LOCK(base); | |
190 | ||
191 | return rc; | |
192 | } | |
193 | ||
194 | /* | |
195 | * coresight_disclaim_device_unlocked : Clear the claim tags for the device. | |
196 | * Called with CS_UNLOCKed for the component. | |
197 | */ | |
198 | void coresight_disclaim_device_unlocked(void __iomem *base) | |
199 | { | |
200 | ||
201 | if (coresight_is_claimed_self_hosted(base)) | |
202 | coresight_clear_claim_tags(base); | |
203 | else | |
204 | /* | |
205 | * The external agent may have not honoured our claim | |
206 | * and has manipulated it. Or something else has seriously | |
207 | * gone wrong in our driver. | |
208 | */ | |
209 | WARN_ON_ONCE(1); | |
210 | } | |
211 | ||
212 | void coresight_disclaim_device(void __iomem *base) | |
213 | { | |
214 | CS_UNLOCK(base); | |
215 | coresight_disclaim_device_unlocked(base); | |
216 | CS_LOCK(base); | |
217 | } | |
218 | ||
3d6e8935 SP |
219 | static int coresight_enable_sink(struct coresight_device *csdev, |
220 | u32 mode, void *data) | |
a06ae860 PP |
221 | { |
222 | int ret; | |
223 | ||
c71369de SP |
224 | /* |
225 | * We need to make sure the "new" session is compatible with the | |
226 | * existing "mode" of operation. | |
227 | */ | |
228 | if (sink_ops(csdev)->enable) { | |
3d6e8935 | 229 | ret = sink_ops(csdev)->enable(csdev, mode, data); |
c71369de SP |
230 | if (ret) |
231 | return ret; | |
a06ae860 PP |
232 | csdev->enable = true; |
233 | } | |
234 | ||
235 | atomic_inc(csdev->refcnt); | |
236 | ||
237 | return 0; | |
238 | } | |
239 | ||
240 | static void coresight_disable_sink(struct coresight_device *csdev) | |
241 | { | |
242 | if (atomic_dec_return(csdev->refcnt) == 0) { | |
243 | if (sink_ops(csdev)->disable) { | |
244 | sink_ops(csdev)->disable(csdev); | |
245 | csdev->enable = false; | |
246 | } | |
247 | } | |
248 | } | |
249 | ||
b3e94405 MP |
250 | static int coresight_enable_link(struct coresight_device *csdev, |
251 | struct coresight_device *parent, | |
252 | struct coresight_device *child) | |
a06ae860 PP |
253 | { |
254 | int ret; | |
255 | int link_subtype; | |
256 | int refport, inport, outport; | |
257 | ||
b3e94405 MP |
258 | if (!parent || !child) |
259 | return -EINVAL; | |
260 | ||
261 | inport = coresight_find_link_inport(csdev, parent); | |
262 | outport = coresight_find_link_outport(csdev, child); | |
a06ae860 PP |
263 | link_subtype = csdev->subtype.link_subtype; |
264 | ||
265 | if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) | |
266 | refport = inport; | |
267 | else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) | |
268 | refport = outport; | |
269 | else | |
270 | refport = 0; | |
271 | ||
fe470f5f SP |
272 | if (refport < 0) |
273 | return refport; | |
274 | ||
a06ae860 PP |
275 | if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { |
276 | if (link_ops(csdev)->enable) { | |
277 | ret = link_ops(csdev)->enable(csdev, inport, outport); | |
b9866bb1 SP |
278 | if (ret) { |
279 | atomic_dec(&csdev->refcnt[refport]); | |
a06ae860 | 280 | return ret; |
b9866bb1 | 281 | } |
a06ae860 PP |
282 | } |
283 | } | |
284 | ||
285 | csdev->enable = true; | |
286 | ||
287 | return 0; | |
288 | } | |
289 | ||
b3e94405 MP |
290 | static void coresight_disable_link(struct coresight_device *csdev, |
291 | struct coresight_device *parent, | |
292 | struct coresight_device *child) | |
a06ae860 PP |
293 | { |
294 | int i, nr_conns; | |
295 | int link_subtype; | |
296 | int refport, inport, outport; | |
297 | ||
b3e94405 MP |
298 | if (!parent || !child) |
299 | return; | |
300 | ||
301 | inport = coresight_find_link_inport(csdev, parent); | |
302 | outport = coresight_find_link_outport(csdev, child); | |
a06ae860 PP |
303 | link_subtype = csdev->subtype.link_subtype; |
304 | ||
305 | if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) { | |
306 | refport = inport; | |
307 | nr_conns = csdev->nr_inport; | |
308 | } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) { | |
309 | refport = outport; | |
310 | nr_conns = csdev->nr_outport; | |
311 | } else { | |
312 | refport = 0; | |
313 | nr_conns = 1; | |
314 | } | |
315 | ||
316 | if (atomic_dec_return(&csdev->refcnt[refport]) == 0) { | |
317 | if (link_ops(csdev)->disable) | |
318 | link_ops(csdev)->disable(csdev, inport, outport); | |
319 | } | |
320 | ||
321 | for (i = 0; i < nr_conns; i++) | |
322 | if (atomic_read(&csdev->refcnt[i]) != 0) | |
323 | return; | |
324 | ||
325 | csdev->enable = false; | |
326 | } | |
327 | ||
22fd532e | 328 | static int coresight_enable_source(struct coresight_device *csdev, u32 mode) |
a06ae860 PP |
329 | { |
330 | int ret; | |
331 | ||
332 | if (!coresight_source_is_unique(csdev)) { | |
333 | dev_warn(&csdev->dev, "traceID %d not unique\n", | |
334 | source_ops(csdev)->trace_id(csdev)); | |
335 | return -EINVAL; | |
336 | } | |
337 | ||
338 | if (!csdev->enable) { | |
339 | if (source_ops(csdev)->enable) { | |
882d5e11 | 340 | ret = source_ops(csdev)->enable(csdev, NULL, mode); |
a06ae860 PP |
341 | if (ret) |
342 | return ret; | |
343 | } | |
344 | csdev->enable = true; | |
345 | } | |
346 | ||
347 | atomic_inc(csdev->refcnt); | |
348 | ||
349 | return 0; | |
350 | } | |
351 | ||
f73f20e1 SP |
352 | /** |
353 | * coresight_disable_source - Drop the reference count by 1 and disable | |
354 | * the device if there are no users left. | |
355 | * | |
356 | * @csdev - The coresight device to disable | |
357 | * | |
358 | * Returns true if the device has been disabled. | |
359 | */ | |
360 | static bool coresight_disable_source(struct coresight_device *csdev) | |
a06ae860 PP |
361 | { |
362 | if (atomic_dec_return(csdev->refcnt) == 0) { | |
f73f20e1 | 363 | if (source_ops(csdev)->disable) |
68905d73 | 364 | source_ops(csdev)->disable(csdev, NULL); |
f73f20e1 | 365 | csdev->enable = false; |
a06ae860 | 366 | } |
f73f20e1 | 367 | return !csdev->enable; |
a06ae860 PP |
368 | } |
369 | ||
b9866bb1 SP |
370 | /* |
371 | * coresight_disable_path_from : Disable components in the given path beyond | |
372 | * @nd in the list. If @nd is NULL, all the components, except the SOURCE are | |
373 | * disabled. | |
374 | */ | |
375 | static void coresight_disable_path_from(struct list_head *path, | |
376 | struct coresight_node *nd) | |
a06ae860 | 377 | { |
dc2c4ef1 | 378 | u32 type; |
b3e94405 MP |
379 | struct coresight_device *csdev, *parent, *child; |
380 | ||
b9866bb1 SP |
381 | if (!nd) |
382 | nd = list_first_entry(path, struct coresight_node, link); | |
383 | ||
384 | list_for_each_entry_continue(nd, path, link) { | |
b3e94405 | 385 | csdev = nd->csdev; |
dc2c4ef1 MP |
386 | type = csdev->type; |
387 | ||
388 | /* | |
389 | * ETF devices are tricky... They can be a link or a sink, | |
390 | * depending on how they are configured. If an ETF has been | |
391 | * "activated" it will be configured as a sink, otherwise | |
392 | * go ahead with the link configuration. | |
393 | */ | |
394 | if (type == CORESIGHT_DEV_TYPE_LINKSINK) | |
395 | type = (csdev == coresight_get_sink(path)) ? | |
396 | CORESIGHT_DEV_TYPE_SINK : | |
397 | CORESIGHT_DEV_TYPE_LINK; | |
398 | ||
399 | switch (type) { | |
b3e94405 | 400 | case CORESIGHT_DEV_TYPE_SINK: |
b3e94405 MP |
401 | coresight_disable_sink(csdev); |
402 | break; | |
403 | case CORESIGHT_DEV_TYPE_SOURCE: | |
b9866bb1 SP |
404 | /* |
405 | * We skip the first node in the path assuming that it | |
406 | * is the source. So we don't expect a source device in | |
407 | * the middle of a path. | |
408 | */ | |
409 | WARN_ON(1); | |
b3e94405 MP |
410 | break; |
411 | case CORESIGHT_DEV_TYPE_LINK: | |
412 | parent = list_prev_entry(nd, link)->csdev; | |
413 | child = list_next_entry(nd, link)->csdev; | |
414 | coresight_disable_link(csdev, parent, child); | |
415 | break; | |
416 | default: | |
417 | break; | |
a06ae860 | 418 | } |
a06ae860 | 419 | } |
b3e94405 | 420 | } |
a06ae860 | 421 | |
b9866bb1 SP |
422 | void coresight_disable_path(struct list_head *path) |
423 | { | |
424 | coresight_disable_path_from(path, NULL); | |
425 | } | |
426 | ||
3d6e8935 | 427 | int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data) |
b3e94405 MP |
428 | { |
429 | ||
430 | int ret = 0; | |
dc2c4ef1 | 431 | u32 type; |
b3e94405 MP |
432 | struct coresight_node *nd; |
433 | struct coresight_device *csdev, *parent, *child; | |
434 | ||
435 | list_for_each_entry_reverse(nd, path, link) { | |
436 | csdev = nd->csdev; | |
dc2c4ef1 MP |
437 | type = csdev->type; |
438 | ||
439 | /* | |
440 | * ETF devices are tricky... They can be a link or a sink, | |
441 | * depending on how they are configured. If an ETF has been | |
442 | * "activated" it will be configured as a sink, otherwise | |
443 | * go ahead with the link configuration. | |
444 | */ | |
445 | if (type == CORESIGHT_DEV_TYPE_LINKSINK) | |
446 | type = (csdev == coresight_get_sink(path)) ? | |
447 | CORESIGHT_DEV_TYPE_SINK : | |
448 | CORESIGHT_DEV_TYPE_LINK; | |
449 | ||
450 | switch (type) { | |
b3e94405 | 451 | case CORESIGHT_DEV_TYPE_SINK: |
3d6e8935 | 452 | ret = coresight_enable_sink(csdev, mode, sink_data); |
c71369de SP |
453 | /* |
454 | * Sink is the first component turned on. If we | |
455 | * failed to enable the sink, there are no components | |
456 | * that need disabling. Disabling the path here | |
457 | * would mean we could disrupt an existing session. | |
458 | */ | |
b3e94405 | 459 | if (ret) |
c71369de | 460 | goto out; |
b3e94405 MP |
461 | break; |
462 | case CORESIGHT_DEV_TYPE_SOURCE: | |
463 | /* sources are enabled from either sysFS or Perf */ | |
464 | break; | |
465 | case CORESIGHT_DEV_TYPE_LINK: | |
466 | parent = list_prev_entry(nd, link)->csdev; | |
467 | child = list_next_entry(nd, link)->csdev; | |
468 | ret = coresight_enable_link(csdev, parent, child); | |
469 | if (ret) | |
470 | goto err; | |
471 | break; | |
472 | default: | |
473 | goto err; | |
a06ae860 PP |
474 | } |
475 | } | |
476 | ||
b3e94405 | 477 | out: |
a06ae860 | 478 | return ret; |
b3e94405 | 479 | err: |
b9866bb1 | 480 | coresight_disable_path_from(path, nd); |
b3e94405 | 481 | goto out; |
a06ae860 PP |
482 | } |
483 | ||
b6404e21 MP |
484 | struct coresight_device *coresight_get_sink(struct list_head *path) |
485 | { | |
486 | struct coresight_device *csdev; | |
487 | ||
488 | if (!path) | |
489 | return NULL; | |
490 | ||
491 | csdev = list_last_entry(path, struct coresight_node, link)->csdev; | |
492 | if (csdev->type != CORESIGHT_DEV_TYPE_SINK && | |
493 | csdev->type != CORESIGHT_DEV_TYPE_LINKSINK) | |
494 | return NULL; | |
495 | ||
496 | return csdev; | |
497 | } | |
498 | ||
d52c9750 MP |
499 | static int coresight_enabled_sink(struct device *dev, void *data) |
500 | { | |
501 | bool *reset = data; | |
502 | struct coresight_device *csdev = to_coresight_device(dev); | |
503 | ||
504 | if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || | |
505 | csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && | |
506 | csdev->activated) { | |
507 | /* | |
508 | * Now that we have a handle on the sink for this session, | |
509 | * disable the sysFS "enable_sink" flag so that possible | |
510 | * concurrent perf session that wish to use another sink don't | |
511 | * trip on it. Doing so has no ramification for the current | |
512 | * session. | |
513 | */ | |
514 | if (*reset) | |
515 | csdev->activated = false; | |
516 | ||
517 | return 1; | |
518 | } | |
519 | ||
520 | return 0; | |
521 | } | |
522 | ||
523 | /** | |
524 | * coresight_get_enabled_sink - returns the first enabled sink found on the bus | |
525 | * @deactivate: Whether the 'enable_sink' flag should be reset | |
526 | * | |
527 | * When operated from perf the deactivate parameter should be set to 'true'. | |
528 | * That way the "enabled_sink" flag of the sink that was selected can be reset, | |
529 | * allowing for other concurrent perf sessions to choose a different sink. | |
530 | * | |
531 | * When operated from sysFS users have full control and as such the deactivate | |
532 | * parameter should be set to 'false', hence mandating users to explicitly | |
533 | * clear the flag. | |
534 | */ | |
535 | struct coresight_device *coresight_get_enabled_sink(bool deactivate) | |
536 | { | |
537 | struct device *dev = NULL; | |
538 | ||
539 | dev = bus_find_device(&coresight_bustype, NULL, &deactivate, | |
540 | coresight_enabled_sink); | |
541 | ||
542 | return dev ? to_coresight_device(dev) : NULL; | |
543 | } | |
544 | ||
22644392 MP |
545 | static int coresight_sink_by_id(struct device *dev, void *data) |
546 | { | |
547 | struct coresight_device *csdev = to_coresight_device(dev); | |
548 | unsigned long hash; | |
549 | ||
550 | if (csdev->type == CORESIGHT_DEV_TYPE_SINK || | |
551 | csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) { | |
552 | ||
553 | if (!csdev->ea) | |
554 | return 0; | |
555 | /* | |
556 | * See function etm_perf_add_symlink_sink() to know where | |
557 | * this comes from. | |
558 | */ | |
559 | hash = (unsigned long)csdev->ea->var; | |
560 | ||
561 | if ((u32)hash == *(u32 *)data) | |
562 | return 1; | |
563 | } | |
564 | ||
565 | return 0; | |
566 | } | |
567 | ||
568 | /** | |
569 | * coresight_get_sink_by_id - returns the sink that matches the id | |
570 | * @id: Id of the sink to match | |
571 | * | |
572 | * The name of a sink is unique, whether it is found on the AMBA bus or | |
573 | * otherwise. As such the hash of that name can easily be used to identify | |
574 | * a sink. | |
575 | */ | |
576 | struct coresight_device *coresight_get_sink_by_id(u32 id) | |
577 | { | |
578 | struct device *dev = NULL; | |
579 | ||
580 | dev = bus_find_device(&coresight_bustype, NULL, &id, | |
581 | coresight_sink_by_id); | |
582 | ||
583 | return dev ? to_coresight_device(dev) : NULL; | |
584 | } | |
585 | ||
8a091d84 SP |
586 | /* |
587 | * coresight_grab_device - Power up this device and any of the helper | |
588 | * devices connected to it for trace operation. Since the helper devices | |
589 | * don't appear on the trace path, they should be handled along with the | |
590 | * the master device. | |
591 | */ | |
592 | static void coresight_grab_device(struct coresight_device *csdev) | |
593 | { | |
594 | int i; | |
595 | ||
596 | for (i = 0; i < csdev->nr_outport; i++) { | |
597 | struct coresight_device *child = csdev->conns[i].child_dev; | |
598 | ||
599 | if (child && child->type == CORESIGHT_DEV_TYPE_HELPER) | |
600 | pm_runtime_get_sync(child->dev.parent); | |
601 | } | |
602 | pm_runtime_get_sync(csdev->dev.parent); | |
603 | } | |
604 | ||
605 | /* | |
606 | * coresight_drop_device - Release this device and any of the helper | |
607 | * devices connected to it. | |
608 | */ | |
609 | static void coresight_drop_device(struct coresight_device *csdev) | |
610 | { | |
611 | int i; | |
612 | ||
613 | pm_runtime_put(csdev->dev.parent); | |
614 | for (i = 0; i < csdev->nr_outport; i++) { | |
615 | struct coresight_device *child = csdev->conns[i].child_dev; | |
616 | ||
617 | if (child && child->type == CORESIGHT_DEV_TYPE_HELPER) | |
618 | pm_runtime_put(child->dev.parent); | |
619 | } | |
620 | } | |
621 | ||
b3e94405 MP |
622 | /** |
623 | * _coresight_build_path - recursively build a path from a @csdev to a sink. | |
624 | * @csdev: The device to start from. | |
625 | * @path: The list to add devices to. | |
626 | * | |
627 | * The tree of Coresight device is traversed until an activated sink is | |
628 | * found. From there the sink is added to the list along with all the | |
629 | * devices that led to that point - the end result is a list from source | |
630 | * to sink. In that list the source is the first device and the sink the | |
631 | * last one. | |
632 | */ | |
633 | static int _coresight_build_path(struct coresight_device *csdev, | |
d52c9750 | 634 | struct coresight_device *sink, |
b3e94405 | 635 | struct list_head *path) |
a06ae860 | 636 | { |
b3e94405 MP |
637 | int i; |
638 | bool found = false; | |
639 | struct coresight_node *node; | |
b3e94405 MP |
640 | |
641 | /* An activated sink has been found. Enqueue the element */ | |
d52c9750 | 642 | if (csdev == sink) |
b3e94405 MP |
643 | goto out; |
644 | ||
645 | /* Not a sink - recursively explore each port found on this element */ | |
646 | for (i = 0; i < csdev->nr_outport; i++) { | |
ec48a1d9 SP |
647 | struct coresight_device *child_dev = csdev->conns[i].child_dev; |
648 | ||
d52c9750 MP |
649 | if (child_dev && |
650 | _coresight_build_path(child_dev, sink, path) == 0) { | |
b3e94405 MP |
651 | found = true; |
652 | break; | |
a06ae860 PP |
653 | } |
654 | } | |
655 | ||
b3e94405 MP |
656 | if (!found) |
657 | return -ENODEV; | |
658 | ||
659 | out: | |
660 | /* | |
661 | * A path from this element to a sink has been found. The elements | |
662 | * leading to the sink are already enqueued, all that is left to do | |
5da5325f MP |
663 | * is tell the PM runtime core we need this element and add a node |
664 | * for it. | |
b3e94405 MP |
665 | */ |
666 | node = kzalloc(sizeof(struct coresight_node), GFP_KERNEL); | |
667 | if (!node) | |
668 | return -ENOMEM; | |
669 | ||
8a091d84 | 670 | coresight_grab_device(csdev); |
b3e94405 MP |
671 | node->csdev = csdev; |
672 | list_add(&node->link, path); | |
673 | ||
a06ae860 PP |
674 | return 0; |
675 | } | |
676 | ||
d52c9750 MP |
677 | struct list_head *coresight_build_path(struct coresight_device *source, |
678 | struct coresight_device *sink) | |
a06ae860 | 679 | { |
b3e94405 | 680 | struct list_head *path; |
5014e904 | 681 | int rc; |
a06ae860 | 682 | |
d52c9750 MP |
683 | if (!sink) |
684 | return ERR_PTR(-EINVAL); | |
685 | ||
b3e94405 MP |
686 | path = kzalloc(sizeof(struct list_head), GFP_KERNEL); |
687 | if (!path) | |
8e67cdbc | 688 | return ERR_PTR(-ENOMEM); |
a06ae860 | 689 | |
b3e94405 MP |
690 | INIT_LIST_HEAD(path); |
691 | ||
d52c9750 | 692 | rc = _coresight_build_path(source, sink, path); |
5014e904 | 693 | if (rc) { |
b3e94405 | 694 | kfree(path); |
5014e904 | 695 | return ERR_PTR(rc); |
a06ae860 PP |
696 | } |
697 | ||
b3e94405 MP |
698 | return path; |
699 | } | |
a06ae860 | 700 | |
b3e94405 MP |
701 | /** |
702 | * coresight_release_path - release a previously built path. | |
703 | * @path: the path to release. | |
704 | * | |
705 | * Go through all the elements of a path and 1) removed it from the list and | |
706 | * 2) free the memory allocated for each node. | |
707 | */ | |
708 | void coresight_release_path(struct list_head *path) | |
709 | { | |
5da5325f | 710 | struct coresight_device *csdev; |
b3e94405 | 711 | struct coresight_node *nd, *next; |
a06ae860 | 712 | |
b3e94405 | 713 | list_for_each_entry_safe(nd, next, path, link) { |
5da5325f MP |
714 | csdev = nd->csdev; |
715 | ||
8a091d84 | 716 | coresight_drop_device(csdev); |
b3e94405 MP |
717 | list_del(&nd->link); |
718 | kfree(nd); | |
719 | } | |
720 | ||
721 | kfree(path); | |
722 | path = NULL; | |
a06ae860 PP |
723 | } |
724 | ||
a685d683 MP |
725 | /** coresight_validate_source - make sure a source has the right credentials |
726 | * @csdev: the device structure for a source. | |
727 | * @function: the function this was called from. | |
728 | * | |
729 | * Assumes the coresight_mutex is held. | |
730 | */ | |
731 | static int coresight_validate_source(struct coresight_device *csdev, | |
732 | const char *function) | |
733 | { | |
734 | u32 type, subtype; | |
735 | ||
736 | type = csdev->type; | |
737 | subtype = csdev->subtype.source_subtype; | |
738 | ||
739 | if (type != CORESIGHT_DEV_TYPE_SOURCE) { | |
740 | dev_err(&csdev->dev, "wrong device type in %s\n", function); | |
741 | return -EINVAL; | |
742 | } | |
743 | ||
744 | if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC && | |
745 | subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) { | |
746 | dev_err(&csdev->dev, "wrong device subtype in %s\n", function); | |
747 | return -EINVAL; | |
748 | } | |
749 | ||
750 | return 0; | |
751 | } | |
752 | ||
a06ae860 PP |
753 | int coresight_enable(struct coresight_device *csdev) |
754 | { | |
a685d683 | 755 | int cpu, ret = 0; |
d52c9750 | 756 | struct coresight_device *sink; |
b3e94405 | 757 | struct list_head *path; |
022aa1a8 SP |
758 | enum coresight_dev_subtype_source subtype; |
759 | ||
760 | subtype = csdev->subtype.source_subtype; | |
a06ae860 PP |
761 | |
762 | mutex_lock(&coresight_mutex); | |
a685d683 MP |
763 | |
764 | ret = coresight_validate_source(csdev, __func__); | |
765 | if (ret) | |
a06ae860 | 766 | goto out; |
a685d683 | 767 | |
022aa1a8 SP |
768 | if (csdev->enable) { |
769 | /* | |
770 | * There could be multiple applications driving the software | |
771 | * source. So keep the refcount for each such user when the | |
772 | * source is already enabled. | |
773 | */ | |
774 | if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) | |
775 | atomic_inc(csdev->refcnt); | |
a06ae860 | 776 | goto out; |
022aa1a8 | 777 | } |
a06ae860 | 778 | |
d52c9750 MP |
779 | /* |
780 | * Search for a valid sink for this session but don't reset the | |
781 | * "enable_sink" flag in sysFS. Users get to do that explicitly. | |
782 | */ | |
783 | sink = coresight_get_enabled_sink(false); | |
784 | if (!sink) { | |
785 | ret = -EINVAL; | |
786 | goto out; | |
787 | } | |
788 | ||
789 | path = coresight_build_path(csdev, sink); | |
5014e904 | 790 | if (IS_ERR(path)) { |
b3e94405 | 791 | pr_err("building path(s) failed\n"); |
5014e904 | 792 | ret = PTR_ERR(path); |
a06ae860 PP |
793 | goto out; |
794 | } | |
795 | ||
3d6e8935 | 796 | ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL); |
b3e94405 MP |
797 | if (ret) |
798 | goto err_path; | |
799 | ||
22fd532e | 800 | ret = coresight_enable_source(csdev, CS_MODE_SYSFS); |
b3e94405 MP |
801 | if (ret) |
802 | goto err_source; | |
803 | ||
022aa1a8 | 804 | switch (subtype) { |
a685d683 MP |
805 | case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: |
806 | /* | |
807 | * When working from sysFS it is important to keep track | |
808 | * of the paths that were created so that they can be | |
809 | * undone in 'coresight_disable()'. Since there can only | |
810 | * be a single session per tracer (when working from sysFS) | |
811 | * a per-cpu variable will do just fine. | |
812 | */ | |
813 | cpu = source_ops(csdev)->cpu_id(csdev); | |
814 | per_cpu(tracer_path, cpu) = path; | |
815 | break; | |
816 | case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: | |
817 | stm_path = path; | |
818 | break; | |
819 | default: | |
820 | /* We can't be here */ | |
821 | break; | |
822 | } | |
b3e94405 | 823 | |
a06ae860 PP |
824 | out: |
825 | mutex_unlock(&coresight_mutex); | |
826 | return ret; | |
b3e94405 MP |
827 | |
828 | err_source: | |
829 | coresight_disable_path(path); | |
830 | ||
831 | err_path: | |
832 | coresight_release_path(path); | |
833 | goto out; | |
a06ae860 PP |
834 | } |
835 | EXPORT_SYMBOL_GPL(coresight_enable); | |
836 | ||
837 | void coresight_disable(struct coresight_device *csdev) | |
838 | { | |
a685d683 MP |
839 | int cpu, ret; |
840 | struct list_head *path = NULL; | |
a06ae860 PP |
841 | |
842 | mutex_lock(&coresight_mutex); | |
a685d683 MP |
843 | |
844 | ret = coresight_validate_source(csdev, __func__); | |
845 | if (ret) | |
a06ae860 | 846 | goto out; |
a685d683 | 847 | |
f73f20e1 | 848 | if (!csdev->enable || !coresight_disable_source(csdev)) |
a06ae860 PP |
849 | goto out; |
850 | ||
a685d683 MP |
851 | switch (csdev->subtype.source_subtype) { |
852 | case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: | |
853 | cpu = source_ops(csdev)->cpu_id(csdev); | |
854 | path = per_cpu(tracer_path, cpu); | |
855 | per_cpu(tracer_path, cpu) = NULL; | |
856 | break; | |
857 | case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: | |
858 | path = stm_path; | |
859 | stm_path = NULL; | |
860 | break; | |
861 | default: | |
862 | /* We can't be here */ | |
863 | break; | |
864 | } | |
865 | ||
b3e94405 MP |
866 | coresight_disable_path(path); |
867 | coresight_release_path(path); | |
a06ae860 PP |
868 | |
869 | out: | |
870 | mutex_unlock(&coresight_mutex); | |
871 | } | |
872 | EXPORT_SYMBOL_GPL(coresight_disable); | |
873 | ||
874 | static ssize_t enable_sink_show(struct device *dev, | |
875 | struct device_attribute *attr, char *buf) | |
876 | { | |
877 | struct coresight_device *csdev = to_coresight_device(dev); | |
878 | ||
e8dc27d0 | 879 | return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->activated); |
a06ae860 PP |
880 | } |
881 | ||
882 | static ssize_t enable_sink_store(struct device *dev, | |
883 | struct device_attribute *attr, | |
884 | const char *buf, size_t size) | |
885 | { | |
886 | int ret; | |
887 | unsigned long val; | |
888 | struct coresight_device *csdev = to_coresight_device(dev); | |
889 | ||
890 | ret = kstrtoul(buf, 10, &val); | |
891 | if (ret) | |
892 | return ret; | |
893 | ||
894 | if (val) | |
895 | csdev->activated = true; | |
896 | else | |
897 | csdev->activated = false; | |
898 | ||
899 | return size; | |
900 | ||
901 | } | |
902 | static DEVICE_ATTR_RW(enable_sink); | |
903 | ||
904 | static ssize_t enable_source_show(struct device *dev, | |
905 | struct device_attribute *attr, char *buf) | |
906 | { | |
907 | struct coresight_device *csdev = to_coresight_device(dev); | |
908 | ||
e8dc27d0 | 909 | return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->enable); |
a06ae860 PP |
910 | } |
911 | ||
912 | static ssize_t enable_source_store(struct device *dev, | |
913 | struct device_attribute *attr, | |
914 | const char *buf, size_t size) | |
915 | { | |
916 | int ret = 0; | |
917 | unsigned long val; | |
918 | struct coresight_device *csdev = to_coresight_device(dev); | |
919 | ||
920 | ret = kstrtoul(buf, 10, &val); | |
921 | if (ret) | |
922 | return ret; | |
923 | ||
924 | if (val) { | |
925 | ret = coresight_enable(csdev); | |
926 | if (ret) | |
927 | return ret; | |
928 | } else { | |
929 | coresight_disable(csdev); | |
930 | } | |
931 | ||
932 | return size; | |
933 | } | |
934 | static DEVICE_ATTR_RW(enable_source); | |
935 | ||
936 | static struct attribute *coresight_sink_attrs[] = { | |
937 | &dev_attr_enable_sink.attr, | |
938 | NULL, | |
939 | }; | |
940 | ATTRIBUTE_GROUPS(coresight_sink); | |
941 | ||
942 | static struct attribute *coresight_source_attrs[] = { | |
943 | &dev_attr_enable_source.attr, | |
944 | NULL, | |
945 | }; | |
946 | ATTRIBUTE_GROUPS(coresight_source); | |
947 | ||
948 | static struct device_type coresight_dev_type[] = { | |
949 | { | |
950 | .name = "none", | |
951 | }, | |
952 | { | |
953 | .name = "sink", | |
954 | .groups = coresight_sink_groups, | |
955 | }, | |
956 | { | |
957 | .name = "link", | |
958 | }, | |
959 | { | |
960 | .name = "linksink", | |
961 | .groups = coresight_sink_groups, | |
962 | }, | |
963 | { | |
964 | .name = "source", | |
965 | .groups = coresight_source_groups, | |
966 | }, | |
8a091d84 SP |
967 | { |
968 | .name = "helper", | |
969 | }, | |
a06ae860 PP |
970 | }; |
971 | ||
972 | static void coresight_device_release(struct device *dev) | |
973 | { | |
974 | struct coresight_device *csdev = to_coresight_device(dev); | |
975 | ||
fae54158 MP |
976 | kfree(csdev->conns); |
977 | kfree(csdev->refcnt); | |
a06ae860 PP |
978 | kfree(csdev); |
979 | } | |
980 | ||
981 | static int coresight_orphan_match(struct device *dev, void *data) | |
982 | { | |
983 | int i; | |
984 | bool still_orphan = false; | |
985 | struct coresight_device *csdev, *i_csdev; | |
986 | struct coresight_connection *conn; | |
987 | ||
988 | csdev = data; | |
989 | i_csdev = to_coresight_device(dev); | |
990 | ||
991 | /* No need to check oneself */ | |
992 | if (csdev == i_csdev) | |
993 | return 0; | |
994 | ||
995 | /* Move on to another component if no connection is orphan */ | |
996 | if (!i_csdev->orphan) | |
997 | return 0; | |
998 | /* | |
999 | * Circle throuch all the connection of that component. If we find | |
1000 | * an orphan connection whose name matches @csdev, link it. | |
1001 | */ | |
d786a47d | 1002 | for (i = 0; i < i_csdev->nr_outport; i++) { |
a06ae860 PP |
1003 | conn = &i_csdev->conns[i]; |
1004 | ||
1005 | /* We have found at least one orphan connection */ | |
1006 | if (conn->child_dev == NULL) { | |
1007 | /* Does it match this newly added device? */ | |
b8392153 SH |
1008 | if (conn->child_name && |
1009 | !strcmp(dev_name(&csdev->dev), conn->child_name)) { | |
a06ae860 | 1010 | conn->child_dev = csdev; |
22394bc5 KX |
1011 | } else { |
1012 | /* This component still has an orphan */ | |
1013 | still_orphan = true; | |
1014 | } | |
a06ae860 PP |
1015 | } |
1016 | } | |
1017 | ||
1018 | i_csdev->orphan = still_orphan; | |
1019 | ||
1020 | /* | |
1021 | * Returning '0' ensures that all known component on the | |
1022 | * bus will be checked. | |
1023 | */ | |
1024 | return 0; | |
1025 | } | |
1026 | ||
1027 | static void coresight_fixup_orphan_conns(struct coresight_device *csdev) | |
1028 | { | |
1029 | /* | |
1030 | * No need to check for a return value as orphan connection(s) | |
1031 | * are hooked-up with each newly added component. | |
1032 | */ | |
1033 | bus_for_each_dev(&coresight_bustype, NULL, | |
ff874227 | 1034 | csdev, coresight_orphan_match); |
a06ae860 PP |
1035 | } |
1036 | ||
1037 | ||
a06ae860 PP |
1038 | static void coresight_fixup_device_conns(struct coresight_device *csdev) |
1039 | { | |
1040 | int i; | |
a06ae860 PP |
1041 | |
1042 | for (i = 0; i < csdev->nr_outport; i++) { | |
26cf91f4 LW |
1043 | struct coresight_connection *conn = &csdev->conns[i]; |
1044 | struct device *dev = NULL; | |
a06ae860 | 1045 | |
26cf91f4 LW |
1046 | if (conn->child_name) |
1047 | dev = bus_find_device_by_name(&coresight_bustype, NULL, | |
1048 | conn->child_name); | |
a06ae860 PP |
1049 | if (dev) { |
1050 | conn->child_dev = to_coresight_device(dev); | |
f2dfab35 MP |
1051 | /* and put reference from 'bus_find_device()' */ |
1052 | put_device(dev); | |
a06ae860 PP |
1053 | } else { |
1054 | csdev->orphan = true; | |
1055 | conn->child_dev = NULL; | |
1056 | } | |
1057 | } | |
1058 | } | |
1059 | ||
ad725aee MP |
1060 | static int coresight_remove_match(struct device *dev, void *data) |
1061 | { | |
1062 | int i; | |
1063 | struct coresight_device *csdev, *iterator; | |
1064 | struct coresight_connection *conn; | |
1065 | ||
1066 | csdev = data; | |
1067 | iterator = to_coresight_device(dev); | |
1068 | ||
1069 | /* No need to check oneself */ | |
1070 | if (csdev == iterator) | |
1071 | return 0; | |
1072 | ||
1073 | /* | |
1074 | * Circle throuch all the connection of that component. If we find | |
1075 | * a connection whose name matches @csdev, remove it. | |
1076 | */ | |
1077 | for (i = 0; i < iterator->nr_outport; i++) { | |
1078 | conn = &iterator->conns[i]; | |
1079 | ||
1080 | if (conn->child_dev == NULL) | |
1081 | continue; | |
1082 | ||
1083 | if (!strcmp(dev_name(&csdev->dev), conn->child_name)) { | |
1084 | iterator->orphan = true; | |
1085 | conn->child_dev = NULL; | |
1086 | /* No need to continue */ | |
1087 | break; | |
1088 | } | |
1089 | } | |
1090 | ||
1091 | /* | |
1092 | * Returning '0' ensures that all known component on the | |
1093 | * bus will be checked. | |
1094 | */ | |
1095 | return 0; | |
1096 | } | |
1097 | ||
1098 | static void coresight_remove_conns(struct coresight_device *csdev) | |
1099 | { | |
1100 | bus_for_each_dev(&coresight_bustype, NULL, | |
1101 | csdev, coresight_remove_match); | |
1102 | } | |
1103 | ||
a06ae860 PP |
1104 | /** |
1105 | * coresight_timeout - loop until a bit has changed to a specific state. | |
1106 | * @addr: base address of the area of interest. | |
1107 | * @offset: address of a register, starting from @addr. | |
1108 | * @position: the position of the bit of interest. | |
1109 | * @value: the value the bit should have. | |
1110 | * | |
1111 | * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if | |
1112 | * TIMEOUT_US has elapsed, which ever happens first. | |
1113 | */ | |
1114 | ||
1115 | int coresight_timeout(void __iomem *addr, u32 offset, int position, int value) | |
1116 | { | |
1117 | int i; | |
1118 | u32 val; | |
1119 | ||
1120 | for (i = TIMEOUT_US; i > 0; i--) { | |
1121 | val = __raw_readl(addr + offset); | |
1122 | /* waiting on the bit to go from 0 to 1 */ | |
1123 | if (value) { | |
1124 | if (val & BIT(position)) | |
1125 | return 0; | |
1126 | /* waiting on the bit to go from 1 to 0 */ | |
1127 | } else { | |
1128 | if (!(val & BIT(position))) | |
1129 | return 0; | |
1130 | } | |
1131 | ||
1132 | /* | |
1133 | * Delay is arbitrary - the specification doesn't say how long | |
1134 | * we are expected to wait. Extra check required to make sure | |
1135 | * we don't wait needlessly on the last iteration. | |
1136 | */ | |
1137 | if (i - 1) | |
1138 | udelay(1); | |
1139 | } | |
1140 | ||
1141 | return -EAGAIN; | |
1142 | } | |
1143 | ||
1144 | struct bus_type coresight_bustype = { | |
1145 | .name = "coresight", | |
1146 | }; | |
1147 | ||
1148 | static int __init coresight_init(void) | |
1149 | { | |
1150 | return bus_register(&coresight_bustype); | |
1151 | } | |
1152 | postcore_initcall(coresight_init); | |
1153 | ||
1154 | struct coresight_device *coresight_register(struct coresight_desc *desc) | |
1155 | { | |
a06ae860 PP |
1156 | int ret; |
1157 | int link_subtype; | |
1158 | int nr_refcnts = 1; | |
1159 | atomic_t *refcnts = NULL; | |
1160 | struct coresight_device *csdev; | |
a06ae860 PP |
1161 | |
1162 | csdev = kzalloc(sizeof(*csdev), GFP_KERNEL); | |
1163 | if (!csdev) { | |
1164 | ret = -ENOMEM; | |
fac253e5 | 1165 | goto err_out; |
a06ae860 PP |
1166 | } |
1167 | ||
1168 | if (desc->type == CORESIGHT_DEV_TYPE_LINK || | |
1169 | desc->type == CORESIGHT_DEV_TYPE_LINKSINK) { | |
1170 | link_subtype = desc->subtype.link_subtype; | |
1171 | ||
1172 | if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) | |
1173 | nr_refcnts = desc->pdata->nr_inport; | |
1174 | else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) | |
1175 | nr_refcnts = desc->pdata->nr_outport; | |
1176 | } | |
1177 | ||
1178 | refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL); | |
1179 | if (!refcnts) { | |
1180 | ret = -ENOMEM; | |
fac253e5 | 1181 | goto err_free_csdev; |
a06ae860 PP |
1182 | } |
1183 | ||
1184 | csdev->refcnt = refcnts; | |
1185 | ||
1186 | csdev->nr_inport = desc->pdata->nr_inport; | |
1187 | csdev->nr_outport = desc->pdata->nr_outport; | |
a06ae860 | 1188 | |
c2c72941 | 1189 | csdev->conns = desc->pdata->conns; |
a06ae860 PP |
1190 | |
1191 | csdev->type = desc->type; | |
1192 | csdev->subtype = desc->subtype; | |
1193 | csdev->ops = desc->ops; | |
1194 | csdev->orphan = false; | |
1195 | ||
1196 | csdev->dev.type = &coresight_dev_type[desc->type]; | |
1197 | csdev->dev.groups = desc->groups; | |
1198 | csdev->dev.parent = desc->dev; | |
1199 | csdev->dev.release = coresight_device_release; | |
1200 | csdev->dev.bus = &coresight_bustype; | |
1201 | dev_set_name(&csdev->dev, "%s", desc->pdata->name); | |
1202 | ||
1203 | ret = device_register(&csdev->dev); | |
a7082daa AY |
1204 | if (ret) { |
1205 | put_device(&csdev->dev); | |
fac253e5 SP |
1206 | /* |
1207 | * All resources are free'd explicitly via | |
1208 | * coresight_device_release(), triggered from put_device(). | |
1209 | */ | |
1210 | goto err_out; | |
a7082daa | 1211 | } |
a06ae860 | 1212 | |
bb8e370b MP |
1213 | if (csdev->type == CORESIGHT_DEV_TYPE_SINK || |
1214 | csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) { | |
1215 | ret = etm_perf_add_symlink_sink(csdev); | |
1216 | ||
1217 | if (ret) { | |
1218 | device_unregister(&csdev->dev); | |
1219 | /* | |
1220 | * As with the above, all resources are free'd | |
1221 | * explicitly via coresight_device_release() triggered | |
1222 | * from put_device(), which is in turn called from | |
1223 | * function device_unregister(). | |
1224 | */ | |
1225 | goto err_out; | |
1226 | } | |
1227 | } | |
1228 | ||
a06ae860 PP |
1229 | mutex_lock(&coresight_mutex); |
1230 | ||
1231 | coresight_fixup_device_conns(csdev); | |
1232 | coresight_fixup_orphan_conns(csdev); | |
1233 | ||
1234 | mutex_unlock(&coresight_mutex); | |
1235 | ||
1236 | return csdev; | |
1237 | ||
fac253e5 | 1238 | err_free_csdev: |
a06ae860 | 1239 | kfree(csdev); |
fac253e5 | 1240 | err_out: |
a06ae860 PP |
1241 | return ERR_PTR(ret); |
1242 | } | |
1243 | EXPORT_SYMBOL_GPL(coresight_register); | |
1244 | ||
1245 | void coresight_unregister(struct coresight_device *csdev) | |
1246 | { | |
bb8e370b | 1247 | etm_perf_del_symlink_sink(csdev); |
ad725aee MP |
1248 | /* Remove references of that device in the topology */ |
1249 | coresight_remove_conns(csdev); | |
a06ae860 | 1250 | device_unregister(&csdev->dev); |
a06ae860 PP |
1251 | } |
1252 | EXPORT_SYMBOL_GPL(coresight_unregister); |