829 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 -EINVAL25 */26struct coresight_connection *27coresight_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(-EINVAL);45 }46 }47 48 pdata->nr_outconns++;49 pdata->out_conns =50 devm_krealloc_array(dev, pdata->out_conns, pdata->nr_outconns,51 sizeof(*pdata->out_conns), GFP_KERNEL);52 if (!pdata->out_conns)53 return ERR_PTR(-ENOMEM);54 55 conn = devm_kmalloc(dev, sizeof(struct coresight_connection),56 GFP_KERNEL);57 if (!conn)58 return ERR_PTR(-ENOMEM);59 60 /*61 * Copy the new connection into the allocation, save the pointer to the62 * end of the connection array and also return it in case it needs to be63 * used right away.64 */65 *conn = *new_conn;66 pdata->out_conns[pdata->nr_outconns - 1] = conn;67 return conn;68}69EXPORT_SYMBOL_GPL(coresight_add_out_conn);70 71/*72 * Add an input connection reference to @out_conn in the target's in_conns array73 *74 * @out_conn: Existing output connection to store as an input on the75 * connection's remote device.76 */77int 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, pdata->in_conns, pdata->nr_inconns,92 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}98EXPORT_SYMBOL_GPL(coresight_add_in_conn);99 100static struct device *101coresight_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 the107 * platform bus.108 */109 dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode);110 if (dev)111 return dev;112 113 /*114 * We have a configurable component - circle through the AMBA bus115 * looking for the device that matches the endpoint node.116 */117 return bus_find_device_by_fwnode(&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 the123 * csdev keeps a copy so iterate round the coresight bus to124 * find the device.125 */126struct coresight_device *127coresight_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(&coresight_bustype, r_fwnode);133 if (dev) {134 csdev = to_coresight_device(dev);135 put_device(dev);136 }137 return csdev;138}139EXPORT_SYMBOL_GPL(coresight_find_csdev_by_fwnode);140 141#ifdef CONFIG_OF142static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)143{144 return of_property_read_bool(ep, "slave-mode");145}146 147static struct device_node *of_coresight_get_port_parent(struct device_node *ep)148{149 struct device_node *parent = of_graph_get_port_parent(ep);150 151 /*152 * Skip one-level up to the real device node, if we153 * are using the new bindings.154 */155 if (of_node_name_eq(parent, "in-ports") ||156 of_node_name_eq(parent, "out-ports"))157 parent = of_get_next_parent(parent);158 159 return parent;160}161 162static inline struct device_node *163of_coresight_get_output_ports_node(const struct device_node *node)164{165 return of_get_child_by_name(node, "out-ports");166}167 168static 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(dev->of_node, "cpu", 0);177 if (!dn)178 return -ENODEV;179 180 cpu = of_cpu_node_to_id(dn);181 of_node_put(dn);182 183 return cpu;184}185 186/*187 * of_coresight_parse_endpoint : Parse the given output endpoint @ep188 * and fill the connection information in @pdata->out_conns189 *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 */196static 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(ep, &endpoint))212 break;213 /*214 * Get a handle on the remote endpoint and the device it is215 * attached to.216 */217 rep = of_graph_get_remote_endpoint(ep);218 if (!rep)219 break;220 rparent = of_coresight_get_port_parent(rep);221 if (!rparent)222 break;223 if (of_graph_parse_endpoint(rep, &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(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 be237 * released via:238 * 1) coresight_release_platform_data() if the probe fails or239 * this device is unregistered.240 * 2) While removing the target device via241 * coresight_remove_match()242 */243 conn.dest_fwnode = fwnode_handle_get(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(conn.dest_fwnode);249 return PTR_ERR(new_conn);250 }251 /* Connection record updated */252 } while (0);253 254 of_node_put(rparent);255 of_node_put(rep);256 put_device(rdev);257 258 return ret;259}260 261static 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 listed273 * under the device and we need to filter out the input274 * ports.275 */276 if (!parent) {277 /*278 * Avoid warnings in for_each_endpoint_of_node()279 * if the device doesn't have any graph connections280 */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 for_each_endpoint_of_node(parent, ep) {290 /*291 * Legacy binding mixes input/output ports under the292 * same parent. So, skip the input ports if we are dealing293 * with legacy binding, as they processed with their294 * 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 of_node_put(ep);302 return ret;303 }304 }305 306 return 0;307}308#else309static inline int310of_get_coresight_platform_data(struct device *dev,311 struct coresight_platform_data *pdata)312{313 return -ENOENT;314}315 316static inline int of_coresight_get_cpu(struct device *dev)317{318 return -ENODEV;319}320#endif321 322#ifdef CONFIG_ACPI323 324#include <acpi/actypes.h>325#include <acpi/processor.h>326 327/* ACPI Graph _DSD UUID : "ab02a46b-74c7-45a2-bd68-f7d344ef2153" */328static const guid_t acpi_graph_uuid = GUID_INIT(0xab02a46b, 0x74c7, 0x45a2,329 0xbd, 0x68, 0xf7, 0xd3,330 0x44, 0xef, 0x21, 0x53);331/* Coresight ACPI Graph UUID : "3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd" */332static const guid_t coresight_graph_uuid = GUID_INIT(0x3ecbc8b6, 0x1d0e, 0x4fb3,333 0x81, 0x07, 0xe6, 0x27,334 0xf8, 0x05, 0xc6, 0xcd);335#define ACPI_CORESIGHT_LINK_SLAVE 0336#define ACPI_CORESIGHT_LINK_MASTER 1337 338static inline bool is_acpi_guid(const union acpi_object *obj)339{340 return (obj->type == ACPI_TYPE_BUFFER) && (obj->buffer.length == 16);341}342 343/*344 * acpi_guid_matches - Checks if the given object is a GUID object and345 * that it matches the supplied the GUID.346 */347static inline bool acpi_guid_matches(const union acpi_object *obj,348 const guid_t *guid)349{350 return is_acpi_guid(obj) &&351 guid_equal((guid_t *)obj->buffer.pointer, guid);352}353 354static inline bool is_acpi_dsd_graph_guid(const union acpi_object *obj)355{356 return acpi_guid_matches(obj, &acpi_graph_uuid);357}358 359static inline bool is_acpi_coresight_graph_guid(const union acpi_object *obj)360{361 return acpi_guid_matches(obj, &coresight_graph_uuid);362}363 364static inline bool is_acpi_coresight_graph(const union acpi_object *obj)365{366 const union acpi_object *graphid, *guid, *links;367 368 if (obj->type != ACPI_TYPE_PACKAGE ||369 obj->package.count < 3)370 return false;371 372 graphid = &obj->package.elements[0];373 guid = &obj->package.elements[1];374 links = &obj->package.elements[2];375 376 if (graphid->type != ACPI_TYPE_INTEGER ||377 links->type != ACPI_TYPE_INTEGER)378 return false;379 380 return is_acpi_coresight_graph_guid(guid);381}382 383/*384 * acpi_validate_dsd_graph - Make sure the given _DSD graph conforms385 * to the ACPI _DSD Graph specification.386 *387 * ACPI Devices Graph property has the following format:388 * {389 * Revision - Integer, must be 0390 * NumberOfGraphs - Integer, N indicating the following list.391 * Graph[1],392 * ...393 * Graph[N]394 * }395 *396 * And each Graph entry has the following format:397 * {398 * GraphID - Integer, identifying a graph the device belongs to.399 * UUID - UUID identifying the specification that governs400 * this graph. (e.g, see is_acpi_coresight_graph())401 * NumberOfLinks - Number "N" of connections on this node of the graph.402 * Links[1]403 * ...404 * Links[N]405 * }406 *407 * Where each "Links" entry has the following format:408 *409 * {410 * SourcePortAddress - Integer411 * DestinationPortAddress - Integer412 * DestinationDeviceName - Reference to another device413 * ( --- CoreSight specific extensions below ---)414 * DirectionOfFlow - Integer 1 for output(master)415 * 0 for input(slave)416 * }417 *418 * e.g:419 * For a Funnel device420 *421 * Device(MFUN) {422 * ...423 *424 * Name (_DSD, Package() {425 * // DSD Package contains tuples of { Proeprty_Type_UUID, Package() }426 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), //Std. Property UUID427 * Package() {428 * Package(2) { "property-name", <property-value> }429 * },430 *431 * ToUUID("ab02a46b-74c7-45a2-bd68-f7d344ef2153"), // ACPI Graph UUID432 * Package() {433 * 0, // Revision434 * 1, // NumberOfGraphs.435 * Package() { // Graph[0] Package436 * 1, // GraphID437 * // Coresight Graph UUID438 * ToUUID("3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd"),439 * 3, // NumberOfLinks aka ports440 * // Link[0]: Output_0 -> Replicator:Input_0441 * Package () { 0, 0, \_SB_.RPL0, 1 },442 * // Link[1]: Input_0 <- Cluster0_Funnel0:Output_0443 * Package () { 0, 0, \_SB_.CLU0.FUN0, 0 },444 * // Link[2]: Input_1 <- Cluster1_Funnel0:Output_0445 * Package () { 1, 0, \_SB_.CLU1.FUN0, 0 },446 * } // End of Graph[0] Package447 *448 * }, // End of ACPI Graph Property449 * })450 */451static inline bool acpi_validate_dsd_graph(const union acpi_object *graph)452{453 int i, n;454 const union acpi_object *rev, *nr_graphs;455 456 /* The graph must contain at least the Revision and Number of Graphs */457 if (graph->package.count < 2)458 return false;459 460 rev = &graph->package.elements[0];461 nr_graphs = &graph->package.elements[1];462 463 if (rev->type != ACPI_TYPE_INTEGER ||464 nr_graphs->type != ACPI_TYPE_INTEGER)465 return false;466 467 /* We only support revision 0 */468 if (rev->integer.value != 0)469 return false;470 471 n = nr_graphs->integer.value;472 /* CoreSight devices are only part of a single Graph */473 if (n != 1)474 return false;475 476 /* Make sure the ACPI graph package has right number of elements */477 if (graph->package.count != (n + 2))478 return false;479 480 /*481 * Each entry must be a graph package with at least 3 members :482 * { GraphID, UUID, NumberOfLinks(n), Links[.],... }483 */484 for (i = 2; i < n + 2; i++) {485 const union acpi_object *obj = &graph->package.elements[i];486 487 if (obj->type != ACPI_TYPE_PACKAGE ||488 obj->package.count < 3)489 return false;490 }491 492 return true;493}494 495/* acpi_get_dsd_graph - Find the _DSD Graph property for the given device. */496static const union acpi_object *497acpi_get_dsd_graph(struct acpi_device *adev, struct acpi_buffer *buf)498{499 int i;500 acpi_status status;501 const union acpi_object *dsd;502 503 status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL,504 buf, ACPI_TYPE_PACKAGE);505 if (ACPI_FAILURE(status))506 return NULL;507 508 dsd = buf->pointer;509 510 /*511 * _DSD property consists tuples { Prop_UUID, Package() }512 * Iterate through all the packages and find the Graph.513 */514 for (i = 0; i + 1 < dsd->package.count; i += 2) {515 const union acpi_object *guid, *package;516 517 guid = &dsd->package.elements[i];518 package = &dsd->package.elements[i + 1];519 520 /* All _DSD elements must have a UUID and a Package */521 if (!is_acpi_guid(guid) || package->type != ACPI_TYPE_PACKAGE)522 break;523 /* Skip the non-Graph _DSD packages */524 if (!is_acpi_dsd_graph_guid(guid))525 continue;526 if (acpi_validate_dsd_graph(package))527 return package;528 /* Invalid graph format, continue */529 dev_warn(&adev->dev, "Invalid Graph _DSD property\n");530 }531 532 return NULL;533}534 535static inline bool536acpi_validate_coresight_graph(const union acpi_object *cs_graph)537{538 int nlinks;539 540 nlinks = cs_graph->package.elements[2].integer.value;541 /*542 * Graph must have the following fields :543 * { GraphID, GraphUUID, NumberOfLinks, Links... }544 */545 if (cs_graph->package.count != (nlinks + 3))546 return false;547 /* The links are validated in acpi_coresight_parse_link() */548 return true;549}550 551/*552 * acpi_get_coresight_graph - Parse the device _DSD tables and find553 * the Graph property matching the CoreSight Graphs.554 *555 * Returns the pointer to the CoreSight Graph Package when found. Otherwise556 * returns NULL.557 */558static const union acpi_object *559acpi_get_coresight_graph(struct acpi_device *adev, struct acpi_buffer *buf)560{561 const union acpi_object *graph_list, *graph;562 int i, nr_graphs;563 564 graph_list = acpi_get_dsd_graph(adev, buf);565 if (!graph_list)566 return graph_list;567 568 nr_graphs = graph_list->package.elements[1].integer.value;569 570 for (i = 2; i < nr_graphs + 2; i++) {571 graph = &graph_list->package.elements[i];572 if (!is_acpi_coresight_graph(graph))573 continue;574 if (acpi_validate_coresight_graph(graph))575 return graph;576 /* Invalid graph format */577 break;578 }579 580 return NULL;581}582 583/*584 * acpi_coresight_parse_link - Parse the given Graph connection585 * of the device and populate the coresight_connection for an output586 * connection.587 *588 * CoreSight Graph specification mandates that the direction of the data589 * flow must be specified in the link. i.e,590 *591 * SourcePortAddress, // Integer592 * DestinationPortAddress, // Integer593 * DestinationDeviceName, // Reference to another device594 * DirectionOfFlow, // 1 for output(master), 0 for input(slave)595 *596 * Returns the direction of the data flow [ Input(slave) or Output(master) ]597 * upon success.598 * Returns an negative error number otherwise.599 */600static int acpi_coresight_parse_link(struct acpi_device *adev,601 const union acpi_object *link,602 struct coresight_connection *conn)603{604 int dir;605 const union acpi_object *fields;606 struct acpi_device *r_adev;607 struct device *rdev;608 609 if (link->type != ACPI_TYPE_PACKAGE ||610 link->package.count != 4)611 return -EINVAL;612 613 fields = link->package.elements;614 615 if (fields[0].type != ACPI_TYPE_INTEGER ||616 fields[1].type != ACPI_TYPE_INTEGER ||617 fields[2].type != ACPI_TYPE_LOCAL_REFERENCE ||618 fields[3].type != ACPI_TYPE_INTEGER)619 return -EINVAL;620 621 r_adev = acpi_fetch_acpi_dev(fields[2].reference.handle);622 if (!r_adev)623 return -ENODEV;624 625 dir = fields[3].integer.value;626 if (dir == ACPI_CORESIGHT_LINK_MASTER) {627 conn->src_port = fields[0].integer.value;628 conn->dest_port = fields[1].integer.value;629 rdev = coresight_find_device_by_fwnode(&r_adev->fwnode);630 if (!rdev)631 return -EPROBE_DEFER;632 /*633 * Hold the refcount to the target device. This could be634 * released via:635 * 1) coresight_release_platform_data() if the probe fails or636 * this device is unregistered.637 * 2) While removing the target device via638 * coresight_remove_match().639 */640 conn->dest_fwnode = fwnode_handle_get(&r_adev->fwnode);641 } else if (dir == ACPI_CORESIGHT_LINK_SLAVE) {642 /*643 * We are only interested in the port number644 * for the input ports at this component.645 * Store the port number in child_port.646 */647 conn->dest_port = fields[0].integer.value;648 } else {649 /* Invalid direction */650 return -EINVAL;651 }652 653 return dir;654}655 656/*657 * acpi_coresight_parse_graph - Parse the _DSD CoreSight graph658 * connection information and populate the supplied coresight_platform_data659 * instance.660 */661static int acpi_coresight_parse_graph(struct device *dev,662 struct acpi_device *adev,663 struct coresight_platform_data *pdata)664{665 int ret = 0;666 int i, nlinks;667 const union acpi_object *graph;668 struct coresight_connection conn, zero_conn = {};669 struct coresight_connection *new_conn;670 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };671 672 graph = acpi_get_coresight_graph(adev, &buf);673 /*674 * There are no graph connections, which is fine for some components.675 * e.g., ETE676 */677 if (!graph)678 goto free;679 680 nlinks = graph->package.elements[2].integer.value;681 if (!nlinks)682 goto free;683 684 for (i = 0; i < nlinks; i++) {685 const union acpi_object *link = &graph->package.elements[3 + i];686 int dir;687 688 conn = zero_conn;689 dir = acpi_coresight_parse_link(adev, link, &conn);690 if (dir < 0) {691 ret = dir;692 goto free;693 }694 695 if (dir == ACPI_CORESIGHT_LINK_MASTER) {696 new_conn = coresight_add_out_conn(dev, pdata, &conn);697 if (IS_ERR(new_conn)) {698 ret = PTR_ERR(new_conn);699 goto free;700 }701 }702 }703 704free:705 /*706 * When ACPI fails to alloc a buffer, it will free the buffer707 * created via ACPI_ALLOCATE_BUFFER and set to NULL.708 * ACPI_FREE can handle NULL pointers, so free it directly.709 */710 ACPI_FREE(buf.pointer);711 return ret;712}713 714/*715 * acpi_handle_to_logical_cpuid - Map a given acpi_handle to the716 * logical CPU id of the corresponding CPU device.717 *718 * Returns the logical CPU id when found. Otherwise returns >= nr_cpus_id.719 */720static int721acpi_handle_to_logical_cpuid(acpi_handle handle)722{723 int i;724 struct acpi_processor *pr;725 726 for_each_possible_cpu(i) {727 pr = per_cpu(processors, i);728 if (pr && pr->handle == handle)729 break;730 }731 732 return i;733}734 735/*736 * acpi_coresigh_get_cpu - Find the logical CPU id of the CPU associated737 * with this coresight device. With ACPI bindings, the CoreSight components738 * are listed as child device of the associated CPU.739 *740 * Returns the logical CPU id when found. Otherwise returns 0.741 */742static int acpi_coresight_get_cpu(struct device *dev)743{744 int cpu;745 acpi_handle cpu_handle;746 acpi_status status;747 struct acpi_device *adev = ACPI_COMPANION(dev);748 749 if (!adev)750 return -ENODEV;751 status = acpi_get_parent(adev->handle, &cpu_handle);752 if (ACPI_FAILURE(status))753 return -ENODEV;754 755 cpu = acpi_handle_to_logical_cpuid(cpu_handle);756 if (cpu >= nr_cpu_ids)757 return -ENODEV;758 return cpu;759}760 761static int762acpi_get_coresight_platform_data(struct device *dev,763 struct coresight_platform_data *pdata)764{765 struct acpi_device *adev;766 767 adev = ACPI_COMPANION(dev);768 if (!adev)769 return -EINVAL;770 771 return acpi_coresight_parse_graph(dev, adev, pdata);772}773 774#else775 776static inline int777acpi_get_coresight_platform_data(struct device *dev,778 struct coresight_platform_data *pdata)779{780 return -ENOENT;781}782 783static inline int acpi_coresight_get_cpu(struct device *dev)784{785 return -ENODEV;786}787#endif788 789int coresight_get_cpu(struct device *dev)790{791 if (is_of_node(dev->fwnode))792 return of_coresight_get_cpu(dev);793 else if (is_acpi_device_node(dev->fwnode))794 return acpi_coresight_get_cpu(dev);795 return 0;796}797EXPORT_SYMBOL_GPL(coresight_get_cpu);798 799struct coresight_platform_data *800coresight_get_platform_data(struct device *dev)801{802 int ret = -ENOENT;803 struct coresight_platform_data *pdata = NULL;804 struct fwnode_handle *fwnode = dev_fwnode(dev);805 806 if (IS_ERR_OR_NULL(fwnode))807 goto error;808 809 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);810 if (!pdata) {811 ret = -ENOMEM;812 goto error;813 }814 815 if (is_of_node(fwnode))816 ret = of_get_coresight_platform_data(dev, pdata);817 else if (is_acpi_device_node(fwnode))818 ret = acpi_get_coresight_platform_data(dev, pdata);819 820 if (!ret)821 return pdata;822error:823 if (!IS_ERR_OR_NULL(pdata))824 /* Cleanup the connection information */825 coresight_release_platform_data(NULL, dev, pdata);826 return ERR_PTR(ret);827}828EXPORT_SYMBOL_GPL(coresight_get_platform_data);829