1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2012, The Linux Foundation. All rights reserved. |
4 | */ |
5 | |
6 | #include <linux/acpi.h> |
7 | #include <linux/types.h> |
8 | #include <linux/err.h> |
9 | #include <linux/slab.h> |
10 | #include <linux/clk.h> |
11 | #include <linux/of.h> |
12 | #include <linux/of_graph.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/amba/bus.h> |
15 | #include <linux/coresight.h> |
16 | #include <linux/cpumask.h> |
17 | #include <asm/smp_plat.h> |
18 | |
19 | #include "coresight-priv.h" |
20 | |
21 | /* |
22 | * Add an entry to the connection list and assign @conn's contents to it. |
23 | * |
24 | * If the output port is already assigned on this device, return -EINVAL |
25 | */ |
26 | struct coresight_connection * |
27 | coresight_add_out_conn(struct device *dev, |
28 | struct coresight_platform_data *pdata, |
29 | const struct coresight_connection *new_conn) |
30 | { |
31 | int i; |
32 | struct coresight_connection *conn; |
33 | |
34 | /* |
35 | * Warn on any existing duplicate output port. |
36 | */ |
37 | for (i = 0; i < pdata->nr_outconns; ++i) { |
38 | conn = pdata->out_conns[i]; |
39 | /* Output == -1 means ignore the port for example for helpers */ |
40 | if (conn->src_port != -1 && |
41 | conn->src_port == new_conn->src_port) { |
42 | dev_warn(dev, "Duplicate output port %d\n" , |
43 | conn->src_port); |
44 | return ERR_PTR(error: -EINVAL); |
45 | } |
46 | } |
47 | |
48 | pdata->nr_outconns++; |
49 | pdata->out_conns = |
50 | devm_krealloc_array(dev, p: pdata->out_conns, new_n: pdata->nr_outconns, |
51 | new_size: sizeof(*pdata->out_conns), GFP_KERNEL); |
52 | if (!pdata->out_conns) |
53 | return ERR_PTR(error: -ENOMEM); |
54 | |
55 | conn = devm_kmalloc(dev, size: sizeof(struct coresight_connection), |
56 | GFP_KERNEL); |
57 | if (!conn) |
58 | return ERR_PTR(error: -ENOMEM); |
59 | |
60 | /* |
61 | * Copy the new connection into the allocation, save the pointer to the |
62 | * end of the connection array and also return it in case it needs to be |
63 | * used right away. |
64 | */ |
65 | *conn = *new_conn; |
66 | pdata->out_conns[pdata->nr_outconns - 1] = conn; |
67 | return conn; |
68 | } |
69 | EXPORT_SYMBOL_GPL(coresight_add_out_conn); |
70 | |
71 | /* |
72 | * Add an input connection reference to @out_conn in the target's in_conns array |
73 | * |
74 | * @out_conn: Existing output connection to store as an input on the |
75 | * connection's remote device. |
76 | */ |
77 | int coresight_add_in_conn(struct coresight_connection *out_conn) |
78 | { |
79 | int i; |
80 | struct device *dev = out_conn->dest_dev->dev.parent; |
81 | struct coresight_platform_data *pdata = out_conn->dest_dev->pdata; |
82 | |
83 | for (i = 0; i < pdata->nr_inconns; ++i) |
84 | if (!pdata->in_conns[i]) { |
85 | pdata->in_conns[i] = out_conn; |
86 | return 0; |
87 | } |
88 | |
89 | pdata->nr_inconns++; |
90 | pdata->in_conns = |
91 | devm_krealloc_array(dev, p: pdata->in_conns, new_n: pdata->nr_inconns, |
92 | new_size: sizeof(*pdata->in_conns), GFP_KERNEL); |
93 | if (!pdata->in_conns) |
94 | return -ENOMEM; |
95 | pdata->in_conns[pdata->nr_inconns - 1] = out_conn; |
96 | return 0; |
97 | } |
98 | EXPORT_SYMBOL_GPL(coresight_add_in_conn); |
99 | |
100 | static struct device * |
101 | coresight_find_device_by_fwnode(struct fwnode_handle *fwnode) |
102 | { |
103 | struct device *dev = NULL; |
104 | |
105 | /* |
106 | * If we have a non-configurable replicator, it will be found on the |
107 | * platform bus. |
108 | */ |
109 | dev = bus_find_device_by_fwnode(bus: &platform_bus_type, fwnode); |
110 | if (dev) |
111 | return dev; |
112 | |
113 | /* |
114 | * We have a configurable component - circle through the AMBA bus |
115 | * looking for the device that matches the endpoint node. |
116 | */ |
117 | return bus_find_device_by_fwnode(bus: &amba_bustype, fwnode); |
118 | } |
119 | |
120 | /* |
121 | * Find a registered coresight device from a device fwnode. |
122 | * The node info is associated with the AMBA parent, but the |
123 | * csdev keeps a copy so iterate round the coresight bus to |
124 | * find the device. |
125 | */ |
126 | struct coresight_device * |
127 | coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode) |
128 | { |
129 | struct device *dev; |
130 | struct coresight_device *csdev = NULL; |
131 | |
132 | dev = bus_find_device_by_fwnode(bus: &coresight_bustype, fwnode: r_fwnode); |
133 | if (dev) { |
134 | csdev = to_coresight_device(dev); |
135 | put_device(dev); |
136 | } |
137 | return csdev; |
138 | } |
139 | EXPORT_SYMBOL_GPL(coresight_find_csdev_by_fwnode); |
140 | |
141 | #ifdef CONFIG_OF |
142 | static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep) |
143 | { |
144 | return of_property_read_bool(np: ep, propname: "slave-mode" ); |
145 | } |
146 | |
147 | static struct device_node *of_coresight_get_port_parent(struct device_node *ep) |
148 | { |
149 | struct device_node *parent = of_graph_get_port_parent(node: ep); |
150 | |
151 | /* |
152 | * Skip one-level up to the real device node, if we |
153 | * are using the new bindings. |
154 | */ |
155 | if (of_node_name_eq(np: parent, name: "in-ports" ) || |
156 | of_node_name_eq(np: parent, name: "out-ports" )) |
157 | parent = of_get_next_parent(node: parent); |
158 | |
159 | return parent; |
160 | } |
161 | |
162 | static inline struct device_node * |
163 | of_coresight_get_output_ports_node(const struct device_node *node) |
164 | { |
165 | return of_get_child_by_name(node, name: "out-ports" ); |
166 | } |
167 | |
168 | static int of_coresight_get_cpu(struct device *dev) |
169 | { |
170 | int cpu; |
171 | struct device_node *dn; |
172 | |
173 | if (!dev->of_node) |
174 | return -ENODEV; |
175 | |
176 | dn = of_parse_phandle(np: dev->of_node, phandle_name: "cpu" , index: 0); |
177 | if (!dn) |
178 | return -ENODEV; |
179 | |
180 | cpu = of_cpu_node_to_id(np: dn); |
181 | of_node_put(node: dn); |
182 | |
183 | return cpu; |
184 | } |
185 | |
186 | /* |
187 | * of_coresight_parse_endpoint : Parse the given output endpoint @ep |
188 | * and fill the connection information in @pdata->out_conns |
189 | * |
190 | * Parses the local port, remote device name and the remote port. |
191 | * |
192 | * Returns : |
193 | * 0 - If the parsing completed without any fatal errors. |
194 | * -Errno - Fatal error, abort the scanning. |
195 | */ |
196 | static int of_coresight_parse_endpoint(struct device *dev, |
197 | struct device_node *ep, |
198 | struct coresight_platform_data *pdata) |
199 | { |
200 | int ret = 0; |
201 | struct of_endpoint endpoint, rendpoint; |
202 | struct device_node *rparent = NULL; |
203 | struct device_node *rep = NULL; |
204 | struct device *rdev = NULL; |
205 | struct fwnode_handle *rdev_fwnode; |
206 | struct coresight_connection conn = {}; |
207 | struct coresight_connection *new_conn; |
208 | |
209 | do { |
210 | /* Parse the local port details */ |
211 | if (of_graph_parse_endpoint(node: ep, endpoint: &endpoint)) |
212 | break; |
213 | /* |
214 | * Get a handle on the remote endpoint and the device it is |
215 | * attached to. |
216 | */ |
217 | rep = of_graph_get_remote_endpoint(node: ep); |
218 | if (!rep) |
219 | break; |
220 | rparent = of_coresight_get_port_parent(ep: rep); |
221 | if (!rparent) |
222 | break; |
223 | if (of_graph_parse_endpoint(node: rep, endpoint: &rendpoint)) |
224 | break; |
225 | |
226 | rdev_fwnode = of_fwnode_handle(rparent); |
227 | /* If the remote device is not available, defer probing */ |
228 | rdev = coresight_find_device_by_fwnode(fwnode: rdev_fwnode); |
229 | if (!rdev) { |
230 | ret = -EPROBE_DEFER; |
231 | break; |
232 | } |
233 | |
234 | conn.src_port = endpoint.port; |
235 | /* |
236 | * Hold the refcount to the target device. This could be |
237 | * released via: |
238 | * 1) coresight_release_platform_data() if the probe fails or |
239 | * this device is unregistered. |
240 | * 2) While removing the target device via |
241 | * coresight_remove_match() |
242 | */ |
243 | conn.dest_fwnode = fwnode_handle_get(fwnode: rdev_fwnode); |
244 | conn.dest_port = rendpoint.port; |
245 | |
246 | new_conn = coresight_add_out_conn(dev, pdata, &conn); |
247 | if (IS_ERR_VALUE(new_conn)) { |
248 | fwnode_handle_put(fwnode: conn.dest_fwnode); |
249 | return PTR_ERR(ptr: new_conn); |
250 | } |
251 | /* Connection record updated */ |
252 | } while (0); |
253 | |
254 | of_node_put(node: rparent); |
255 | of_node_put(node: rep); |
256 | put_device(dev: rdev); |
257 | |
258 | return ret; |
259 | } |
260 | |
261 | static int of_get_coresight_platform_data(struct device *dev, |
262 | struct coresight_platform_data *pdata) |
263 | { |
264 | int ret = 0; |
265 | struct device_node *ep = NULL; |
266 | const struct device_node *parent = NULL; |
267 | bool legacy_binding = false; |
268 | struct device_node *node = dev->of_node; |
269 | |
270 | parent = of_coresight_get_output_ports_node(node); |
271 | /* |
272 | * If the DT uses obsoleted bindings, the ports are listed |
273 | * under the device and we need to filter out the input |
274 | * ports. |
275 | */ |
276 | if (!parent) { |
277 | /* |
278 | * Avoid warnings in of_graph_get_next_endpoint() |
279 | * if the device doesn't have any graph connections |
280 | */ |
281 | if (!of_graph_is_present(node)) |
282 | return 0; |
283 | legacy_binding = true; |
284 | parent = node; |
285 | dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n" ); |
286 | } |
287 | |
288 | /* Iterate through each output port to discover topology */ |
289 | while ((ep = of_graph_get_next_endpoint(parent, previous: ep))) { |
290 | /* |
291 | * Legacy binding mixes input/output ports under the |
292 | * same parent. So, skip the input ports if we are dealing |
293 | * with legacy binding, as they processed with their |
294 | * connected output ports. |
295 | */ |
296 | if (legacy_binding && of_coresight_legacy_ep_is_input(ep)) |
297 | continue; |
298 | |
299 | ret = of_coresight_parse_endpoint(dev, ep, pdata); |
300 | if (ret) |
301 | return ret; |
302 | } |
303 | |
304 | return 0; |
305 | } |
306 | #else |
307 | static inline int |
308 | of_get_coresight_platform_data(struct device *dev, |
309 | struct coresight_platform_data *pdata) |
310 | { |
311 | return -ENOENT; |
312 | } |
313 | |
314 | static inline int of_coresight_get_cpu(struct device *dev) |
315 | { |
316 | return -ENODEV; |
317 | } |
318 | #endif |
319 | |
320 | #ifdef CONFIG_ACPI |
321 | |
322 | #include <acpi/actypes.h> |
323 | #include <acpi/processor.h> |
324 | |
325 | /* ACPI Graph _DSD UUID : "ab02a46b-74c7-45a2-bd68-f7d344ef2153" */ |
326 | static const guid_t acpi_graph_uuid = GUID_INIT(0xab02a46b, 0x74c7, 0x45a2, |
327 | 0xbd, 0x68, 0xf7, 0xd3, |
328 | 0x44, 0xef, 0x21, 0x53); |
329 | /* Coresight ACPI Graph UUID : "3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd" */ |
330 | static const guid_t coresight_graph_uuid = GUID_INIT(0x3ecbc8b6, 0x1d0e, 0x4fb3, |
331 | 0x81, 0x07, 0xe6, 0x27, |
332 | 0xf8, 0x05, 0xc6, 0xcd); |
333 | #define ACPI_CORESIGHT_LINK_SLAVE 0 |
334 | #define ACPI_CORESIGHT_LINK_MASTER 1 |
335 | |
336 | static inline bool is_acpi_guid(const union acpi_object *obj) |
337 | { |
338 | return (obj->type == ACPI_TYPE_BUFFER) && (obj->buffer.length == 16); |
339 | } |
340 | |
341 | /* |
342 | * acpi_guid_matches - Checks if the given object is a GUID object and |
343 | * that it matches the supplied the GUID. |
344 | */ |
345 | static inline bool acpi_guid_matches(const union acpi_object *obj, |
346 | const guid_t *guid) |
347 | { |
348 | return is_acpi_guid(obj) && |
349 | guid_equal(u1: (guid_t *)obj->buffer.pointer, u2: guid); |
350 | } |
351 | |
352 | static inline bool is_acpi_dsd_graph_guid(const union acpi_object *obj) |
353 | { |
354 | return acpi_guid_matches(obj, guid: &acpi_graph_uuid); |
355 | } |
356 | |
357 | static inline bool is_acpi_coresight_graph_guid(const union acpi_object *obj) |
358 | { |
359 | return acpi_guid_matches(obj, guid: &coresight_graph_uuid); |
360 | } |
361 | |
362 | static inline bool is_acpi_coresight_graph(const union acpi_object *obj) |
363 | { |
364 | const union acpi_object *graphid, *guid, *links; |
365 | |
366 | if (obj->type != ACPI_TYPE_PACKAGE || |
367 | obj->package.count < 3) |
368 | return false; |
369 | |
370 | graphid = &obj->package.elements[0]; |
371 | guid = &obj->package.elements[1]; |
372 | links = &obj->package.elements[2]; |
373 | |
374 | if (graphid->type != ACPI_TYPE_INTEGER || |
375 | links->type != ACPI_TYPE_INTEGER) |
376 | return false; |
377 | |
378 | return is_acpi_coresight_graph_guid(obj: guid); |
379 | } |
380 | |
381 | /* |
382 | * acpi_validate_dsd_graph - Make sure the given _DSD graph conforms |
383 | * to the ACPI _DSD Graph specification. |
384 | * |
385 | * ACPI Devices Graph property has the following format: |
386 | * { |
387 | * Revision - Integer, must be 0 |
388 | * NumberOfGraphs - Integer, N indicating the following list. |
389 | * Graph[1], |
390 | * ... |
391 | * Graph[N] |
392 | * } |
393 | * |
394 | * And each Graph entry has the following format: |
395 | * { |
396 | * GraphID - Integer, identifying a graph the device belongs to. |
397 | * UUID - UUID identifying the specification that governs |
398 | * this graph. (e.g, see is_acpi_coresight_graph()) |
399 | * NumberOfLinks - Number "N" of connections on this node of the graph. |
400 | * Links[1] |
401 | * ... |
402 | * Links[N] |
403 | * } |
404 | * |
405 | * Where each "Links" entry has the following format: |
406 | * |
407 | * { |
408 | * SourcePortAddress - Integer |
409 | * DestinationPortAddress - Integer |
410 | * DestinationDeviceName - Reference to another device |
411 | * ( --- CoreSight specific extensions below ---) |
412 | * DirectionOfFlow - Integer 1 for output(master) |
413 | * 0 for input(slave) |
414 | * } |
415 | * |
416 | * e.g: |
417 | * For a Funnel device |
418 | * |
419 | * Device(MFUN) { |
420 | * ... |
421 | * |
422 | * Name (_DSD, Package() { |
423 | * // DSD Package contains tuples of { Proeprty_Type_UUID, Package() } |
424 | * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), //Std. Property UUID |
425 | * Package() { |
426 | * Package(2) { "property-name", <property-value> } |
427 | * }, |
428 | * |
429 | * ToUUID("ab02a46b-74c7-45a2-bd68-f7d344ef2153"), // ACPI Graph UUID |
430 | * Package() { |
431 | * 0, // Revision |
432 | * 1, // NumberOfGraphs. |
433 | * Package() { // Graph[0] Package |
434 | * 1, // GraphID |
435 | * // Coresight Graph UUID |
436 | * ToUUID("3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd"), |
437 | * 3, // NumberOfLinks aka ports |
438 | * // Link[0]: Output_0 -> Replicator:Input_0 |
439 | * Package () { 0, 0, \_SB_.RPL0, 1 }, |
440 | * // Link[1]: Input_0 <- Cluster0_Funnel0:Output_0 |
441 | * Package () { 0, 0, \_SB_.CLU0.FUN0, 0 }, |
442 | * // Link[2]: Input_1 <- Cluster1_Funnel0:Output_0 |
443 | * Package () { 1, 0, \_SB_.CLU1.FUN0, 0 }, |
444 | * } // End of Graph[0] Package |
445 | * |
446 | * }, // End of ACPI Graph Property |
447 | * }) |
448 | */ |
449 | static inline bool acpi_validate_dsd_graph(const union acpi_object *graph) |
450 | { |
451 | int i, n; |
452 | const union acpi_object *rev, *nr_graphs; |
453 | |
454 | /* The graph must contain at least the Revision and Number of Graphs */ |
455 | if (graph->package.count < 2) |
456 | return false; |
457 | |
458 | rev = &graph->package.elements[0]; |
459 | nr_graphs = &graph->package.elements[1]; |
460 | |
461 | if (rev->type != ACPI_TYPE_INTEGER || |
462 | nr_graphs->type != ACPI_TYPE_INTEGER) |
463 | return false; |
464 | |
465 | /* We only support revision 0 */ |
466 | if (rev->integer.value != 0) |
467 | return false; |
468 | |
469 | n = nr_graphs->integer.value; |
470 | /* CoreSight devices are only part of a single Graph */ |
471 | if (n != 1) |
472 | return false; |
473 | |
474 | /* Make sure the ACPI graph package has right number of elements */ |
475 | if (graph->package.count != (n + 2)) |
476 | return false; |
477 | |
478 | /* |
479 | * Each entry must be a graph package with at least 3 members : |
480 | * { GraphID, UUID, NumberOfLinks(n), Links[.],... } |
481 | */ |
482 | for (i = 2; i < n + 2; i++) { |
483 | const union acpi_object *obj = &graph->package.elements[i]; |
484 | |
485 | if (obj->type != ACPI_TYPE_PACKAGE || |
486 | obj->package.count < 3) |
487 | return false; |
488 | } |
489 | |
490 | return true; |
491 | } |
492 | |
493 | /* acpi_get_dsd_graph - Find the _DSD Graph property for the given device. */ |
494 | static const union acpi_object * |
495 | acpi_get_dsd_graph(struct acpi_device *adev, struct acpi_buffer *buf) |
496 | { |
497 | int i; |
498 | acpi_status status; |
499 | const union acpi_object *dsd; |
500 | |
501 | status = acpi_evaluate_object_typed(object: adev->handle, pathname: "_DSD" , NULL, |
502 | return_buffer: buf, ACPI_TYPE_PACKAGE); |
503 | if (ACPI_FAILURE(status)) |
504 | return NULL; |
505 | |
506 | dsd = buf->pointer; |
507 | |
508 | /* |
509 | * _DSD property consists tuples { Prop_UUID, Package() } |
510 | * Iterate through all the packages and find the Graph. |
511 | */ |
512 | for (i = 0; i + 1 < dsd->package.count; i += 2) { |
513 | const union acpi_object *guid, *package; |
514 | |
515 | guid = &dsd->package.elements[i]; |
516 | package = &dsd->package.elements[i + 1]; |
517 | |
518 | /* All _DSD elements must have a UUID and a Package */ |
519 | if (!is_acpi_guid(obj: guid) || package->type != ACPI_TYPE_PACKAGE) |
520 | break; |
521 | /* Skip the non-Graph _DSD packages */ |
522 | if (!is_acpi_dsd_graph_guid(obj: guid)) |
523 | continue; |
524 | if (acpi_validate_dsd_graph(graph: package)) |
525 | return package; |
526 | /* Invalid graph format, continue */ |
527 | dev_warn(&adev->dev, "Invalid Graph _DSD property\n" ); |
528 | } |
529 | |
530 | return NULL; |
531 | } |
532 | |
533 | static inline bool |
534 | acpi_validate_coresight_graph(const union acpi_object *cs_graph) |
535 | { |
536 | int nlinks; |
537 | |
538 | nlinks = cs_graph->package.elements[2].integer.value; |
539 | /* |
540 | * Graph must have the following fields : |
541 | * { GraphID, GraphUUID, NumberOfLinks, Links... } |
542 | */ |
543 | if (cs_graph->package.count != (nlinks + 3)) |
544 | return false; |
545 | /* The links are validated in acpi_coresight_parse_link() */ |
546 | return true; |
547 | } |
548 | |
549 | /* |
550 | * acpi_get_coresight_graph - Parse the device _DSD tables and find |
551 | * the Graph property matching the CoreSight Graphs. |
552 | * |
553 | * Returns the pointer to the CoreSight Graph Package when found. Otherwise |
554 | * returns NULL. |
555 | */ |
556 | static const union acpi_object * |
557 | acpi_get_coresight_graph(struct acpi_device *adev, struct acpi_buffer *buf) |
558 | { |
559 | const union acpi_object *graph_list, *graph; |
560 | int i, nr_graphs; |
561 | |
562 | graph_list = acpi_get_dsd_graph(adev, buf); |
563 | if (!graph_list) |
564 | return graph_list; |
565 | |
566 | nr_graphs = graph_list->package.elements[1].integer.value; |
567 | |
568 | for (i = 2; i < nr_graphs + 2; i++) { |
569 | graph = &graph_list->package.elements[i]; |
570 | if (!is_acpi_coresight_graph(obj: graph)) |
571 | continue; |
572 | if (acpi_validate_coresight_graph(cs_graph: graph)) |
573 | return graph; |
574 | /* Invalid graph format */ |
575 | break; |
576 | } |
577 | |
578 | return NULL; |
579 | } |
580 | |
581 | /* |
582 | * acpi_coresight_parse_link - Parse the given Graph connection |
583 | * of the device and populate the coresight_connection for an output |
584 | * connection. |
585 | * |
586 | * CoreSight Graph specification mandates that the direction of the data |
587 | * flow must be specified in the link. i.e, |
588 | * |
589 | * SourcePortAddress, // Integer |
590 | * DestinationPortAddress, // Integer |
591 | * DestinationDeviceName, // Reference to another device |
592 | * DirectionOfFlow, // 1 for output(master), 0 for input(slave) |
593 | * |
594 | * Returns the direction of the data flow [ Input(slave) or Output(master) ] |
595 | * upon success. |
596 | * Returns an negative error number otherwise. |
597 | */ |
598 | static int acpi_coresight_parse_link(struct acpi_device *adev, |
599 | const union acpi_object *link, |
600 | struct coresight_connection *conn) |
601 | { |
602 | int dir; |
603 | const union acpi_object *fields; |
604 | struct acpi_device *r_adev; |
605 | struct device *rdev; |
606 | |
607 | if (link->type != ACPI_TYPE_PACKAGE || |
608 | link->package.count != 4) |
609 | return -EINVAL; |
610 | |
611 | fields = link->package.elements; |
612 | |
613 | if (fields[0].type != ACPI_TYPE_INTEGER || |
614 | fields[1].type != ACPI_TYPE_INTEGER || |
615 | fields[2].type != ACPI_TYPE_LOCAL_REFERENCE || |
616 | fields[3].type != ACPI_TYPE_INTEGER) |
617 | return -EINVAL; |
618 | |
619 | r_adev = acpi_fetch_acpi_dev(handle: fields[2].reference.handle); |
620 | if (!r_adev) |
621 | return -ENODEV; |
622 | |
623 | dir = fields[3].integer.value; |
624 | if (dir == ACPI_CORESIGHT_LINK_MASTER) { |
625 | conn->src_port = fields[0].integer.value; |
626 | conn->dest_port = fields[1].integer.value; |
627 | rdev = coresight_find_device_by_fwnode(fwnode: &r_adev->fwnode); |
628 | if (!rdev) |
629 | return -EPROBE_DEFER; |
630 | /* |
631 | * Hold the refcount to the target device. This could be |
632 | * released via: |
633 | * 1) coresight_release_platform_data() if the probe fails or |
634 | * this device is unregistered. |
635 | * 2) While removing the target device via |
636 | * coresight_remove_match(). |
637 | */ |
638 | conn->dest_fwnode = fwnode_handle_get(fwnode: &r_adev->fwnode); |
639 | } else if (dir == ACPI_CORESIGHT_LINK_SLAVE) { |
640 | /* |
641 | * We are only interested in the port number |
642 | * for the input ports at this component. |
643 | * Store the port number in child_port. |
644 | */ |
645 | conn->dest_port = fields[0].integer.value; |
646 | } else { |
647 | /* Invalid direction */ |
648 | return -EINVAL; |
649 | } |
650 | |
651 | return dir; |
652 | } |
653 | |
654 | /* |
655 | * acpi_coresight_parse_graph - Parse the _DSD CoreSight graph |
656 | * connection information and populate the supplied coresight_platform_data |
657 | * instance. |
658 | */ |
659 | static int acpi_coresight_parse_graph(struct device *dev, |
660 | struct acpi_device *adev, |
661 | struct coresight_platform_data *pdata) |
662 | { |
663 | int ret = 0; |
664 | int i, nlinks; |
665 | const union acpi_object *graph; |
666 | struct coresight_connection conn, zero_conn = {}; |
667 | struct coresight_connection *new_conn; |
668 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; |
669 | |
670 | graph = acpi_get_coresight_graph(adev, buf: &buf); |
671 | /* |
672 | * There are no graph connections, which is fine for some components. |
673 | * e.g., ETE |
674 | */ |
675 | if (!graph) |
676 | goto free; |
677 | |
678 | nlinks = graph->package.elements[2].integer.value; |
679 | if (!nlinks) |
680 | goto free; |
681 | |
682 | for (i = 0; i < nlinks; i++) { |
683 | const union acpi_object *link = &graph->package.elements[3 + i]; |
684 | int dir; |
685 | |
686 | conn = zero_conn; |
687 | dir = acpi_coresight_parse_link(adev, link, conn: &conn); |
688 | if (dir < 0) { |
689 | ret = dir; |
690 | goto free; |
691 | } |
692 | |
693 | if (dir == ACPI_CORESIGHT_LINK_MASTER) { |
694 | new_conn = coresight_add_out_conn(dev, pdata, &conn); |
695 | if (IS_ERR(ptr: new_conn)) { |
696 | ret = PTR_ERR(ptr: new_conn); |
697 | goto free; |
698 | } |
699 | } |
700 | } |
701 | |
702 | free: |
703 | /* |
704 | * When ACPI fails to alloc a buffer, it will free the buffer |
705 | * created via ACPI_ALLOCATE_BUFFER and set to NULL. |
706 | * ACPI_FREE can handle NULL pointers, so free it directly. |
707 | */ |
708 | ACPI_FREE(buf.pointer); |
709 | return ret; |
710 | } |
711 | |
712 | /* |
713 | * acpi_handle_to_logical_cpuid - Map a given acpi_handle to the |
714 | * logical CPU id of the corresponding CPU device. |
715 | * |
716 | * Returns the logical CPU id when found. Otherwise returns >= nr_cpus_id. |
717 | */ |
718 | static int |
719 | acpi_handle_to_logical_cpuid(acpi_handle handle) |
720 | { |
721 | int i; |
722 | struct acpi_processor *pr; |
723 | |
724 | for_each_possible_cpu(i) { |
725 | pr = per_cpu(processors, i); |
726 | if (pr && pr->handle == handle) |
727 | break; |
728 | } |
729 | |
730 | return i; |
731 | } |
732 | |
733 | /* |
734 | * acpi_coresigh_get_cpu - Find the logical CPU id of the CPU associated |
735 | * with this coresight device. With ACPI bindings, the CoreSight components |
736 | * are listed as child device of the associated CPU. |
737 | * |
738 | * Returns the logical CPU id when found. Otherwise returns 0. |
739 | */ |
740 | static int acpi_coresight_get_cpu(struct device *dev) |
741 | { |
742 | int cpu; |
743 | acpi_handle cpu_handle; |
744 | acpi_status status; |
745 | struct acpi_device *adev = ACPI_COMPANION(dev); |
746 | |
747 | if (!adev) |
748 | return -ENODEV; |
749 | status = acpi_get_parent(object: adev->handle, out_handle: &cpu_handle); |
750 | if (ACPI_FAILURE(status)) |
751 | return -ENODEV; |
752 | |
753 | cpu = acpi_handle_to_logical_cpuid(handle: cpu_handle); |
754 | if (cpu >= nr_cpu_ids) |
755 | return -ENODEV; |
756 | return cpu; |
757 | } |
758 | |
759 | static int |
760 | acpi_get_coresight_platform_data(struct device *dev, |
761 | struct coresight_platform_data *pdata) |
762 | { |
763 | struct acpi_device *adev; |
764 | |
765 | adev = ACPI_COMPANION(dev); |
766 | if (!adev) |
767 | return -EINVAL; |
768 | |
769 | return acpi_coresight_parse_graph(dev, adev, pdata); |
770 | } |
771 | |
772 | #else |
773 | |
774 | static inline int |
775 | acpi_get_coresight_platform_data(struct device *dev, |
776 | struct coresight_platform_data *pdata) |
777 | { |
778 | return -ENOENT; |
779 | } |
780 | |
781 | static inline int acpi_coresight_get_cpu(struct device *dev) |
782 | { |
783 | return -ENODEV; |
784 | } |
785 | #endif |
786 | |
787 | int coresight_get_cpu(struct device *dev) |
788 | { |
789 | if (is_of_node(fwnode: dev->fwnode)) |
790 | return of_coresight_get_cpu(dev); |
791 | else if (is_acpi_device_node(fwnode: dev->fwnode)) |
792 | return acpi_coresight_get_cpu(dev); |
793 | return 0; |
794 | } |
795 | EXPORT_SYMBOL_GPL(coresight_get_cpu); |
796 | |
797 | struct coresight_platform_data * |
798 | coresight_get_platform_data(struct device *dev) |
799 | { |
800 | int ret = -ENOENT; |
801 | struct coresight_platform_data *pdata = NULL; |
802 | struct fwnode_handle *fwnode = dev_fwnode(dev); |
803 | |
804 | if (IS_ERR_OR_NULL(ptr: fwnode)) |
805 | goto error; |
806 | |
807 | pdata = devm_kzalloc(dev, size: sizeof(*pdata), GFP_KERNEL); |
808 | if (!pdata) { |
809 | ret = -ENOMEM; |
810 | goto error; |
811 | } |
812 | |
813 | if (is_of_node(fwnode)) |
814 | ret = of_get_coresight_platform_data(dev, pdata); |
815 | else if (is_acpi_device_node(fwnode)) |
816 | ret = acpi_get_coresight_platform_data(dev, pdata); |
817 | |
818 | if (!ret) |
819 | return pdata; |
820 | error: |
821 | if (!IS_ERR_OR_NULL(ptr: pdata)) |
822 | /* Cleanup the connection information */ |
823 | coresight_release_platform_data(NULL, dev, pdata); |
824 | return ERR_PTR(error: ret); |
825 | } |
826 | EXPORT_SYMBOL_GPL(coresight_get_platform_data); |
827 | |