#include <asm/smp_plat.h>
#include "coresight-priv.h"
+
/*
- * coresight_alloc_conns: Allocate connections record for each output
- * port from the device.
+ * Add an entry to the connection list and assign @conn's contents to it.
+ *
+ * If the output port is already assigned on this device, return -EINVAL
*/
-static int coresight_alloc_conns(struct device *dev,
- struct coresight_platform_data *pdata)
+struct coresight_connection *
+coresight_add_out_conn(struct device *dev,
+ struct coresight_platform_data *pdata,
+ const struct coresight_connection *new_conn)
{
- if (pdata->nr_outconns) {
- pdata->out_conns = devm_kcalloc(dev, pdata->nr_outconns,
- sizeof(*pdata->out_conns), GFP_KERNEL);
- if (!pdata->out_conns)
- return -ENOMEM;
+ int i;
+ struct coresight_connection *conn;
+
+ /*
+ * Warn on any existing duplicate output port.
+ */
+ for (i = 0; i < pdata->nr_outconns; ++i) {
+ conn = &pdata->out_conns[i];
+ /* Output == -1 means ignore the port for example for helpers */
+ if (conn->src_port != -1 &&
+ conn->src_port == new_conn->src_port) {
+ dev_warn(dev, "Duplicate output port %d\n",
+ conn->src_port);
+ return ERR_PTR(-EINVAL);
+ }
}
- return 0;
+ pdata->nr_outconns++;
+ pdata->out_conns =
+ devm_krealloc_array(dev, pdata->out_conns, pdata->nr_outconns,
+ sizeof(*pdata->out_conns), GFP_KERNEL);
+ if (!pdata->out_conns)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->out_conns[pdata->nr_outconns - 1] = *new_conn;
+ return &pdata->out_conns[pdata->nr_outconns - 1];
}
+EXPORT_SYMBOL_GPL(coresight_add_out_conn);
static struct device *
coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
struct device_node *rep = NULL;
struct device *rdev = NULL;
struct fwnode_handle *rdev_fwnode;
- struct coresight_connection *conn;
+ struct coresight_connection conn = {};
+ struct coresight_connection *new_conn;
do {
/* Parse the local port details */
break;
}
- conn = &pdata->out_conns[endpoint.port];
- if (conn->dest_fwnode) {
- dev_warn(dev, "Duplicate output port %d\n",
- endpoint.port);
- ret = -EINVAL;
- break;
- }
- conn->src_port = endpoint.port;
+ conn.src_port = endpoint.port;
/*
* Hold the refcount to the target device. This could be
* released via:
* 2) While removing the target device via
* coresight_remove_match()
*/
- conn->dest_fwnode = fwnode_handle_get(rdev_fwnode);
- conn->dest_port = rendpoint.port;
+ conn.dest_fwnode = fwnode_handle_get(rdev_fwnode);
+ conn.dest_port = rendpoint.port;
+
+ new_conn = coresight_add_out_conn(dev, pdata, &conn);
+ if (IS_ERR_VALUE(new_conn)) {
+ fwnode_handle_put(conn.dest_fwnode);
+ return PTR_ERR(new_conn);
+ }
/* Connection record updated */
} while (0);
struct device_node *node = dev->of_node;
/* Get the number of input and output port for this component */
- of_coresight_get_ports(node, &pdata->nr_inconns, &pdata->nr_outconns);
+ of_coresight_get_ports(node, &pdata->high_inport, &pdata->high_outport);
/* If there are no output connections, we are done */
- if (!pdata->nr_outconns)
+ if (!pdata->high_outport)
return 0;
- ret = coresight_alloc_conns(dev, pdata);
- if (ret)
- return ret;
-
parent = of_coresight_get_output_ports_node(node);
/*
* If the DT uses obsoleted bindings, the ports are listed
* connection information and populate the supplied coresight_platform_data
* instance.
*/
-static int acpi_coresight_parse_graph(struct acpi_device *adev,
+static int acpi_coresight_parse_graph(struct device *dev,
+ struct acpi_device *adev,
struct coresight_platform_data *pdata)
{
- int rc, i, nlinks;
+ int i, nlinks;
const union acpi_object *graph;
- struct coresight_connection *conns, *ptr;
+ struct coresight_connection conn, zero_conn = {};
+ struct coresight_connection *new_conn;
pdata->nr_inconns = pdata->nr_outconns = 0;
graph = acpi_get_coresight_graph(adev);
if (!nlinks)
return 0;
- /*
- * To avoid scanning the table twice (once for finding the number of
- * output links and then later for parsing the output links),
- * cache the links information in one go and then later copy
- * it to the pdata.
- */
- conns = devm_kcalloc(&adev->dev, nlinks, sizeof(*conns), GFP_KERNEL);
- if (!conns)
- return -ENOMEM;
- ptr = conns;
for (i = 0; i < nlinks; i++) {
const union acpi_object *link = &graph->package.elements[3 + i];
int dir;
- dir = acpi_coresight_parse_link(adev, link, ptr);
+ conn = zero_conn;
+ dir = acpi_coresight_parse_link(adev, link, &conn);
if (dir < 0)
return dir;
if (dir == ACPI_CORESIGHT_LINK_MASTER) {
- if (ptr->src_port >= pdata->nr_outconns)
- pdata->nr_outconns = ptr->src_port + 1;
- ptr++;
+ if (conn.src_port >= pdata->high_outport)
+ pdata->high_outport = conn.src_port + 1;
+ new_conn = coresight_add_out_conn(dev, pdata, &conn);
+ if (IS_ERR(new_conn))
+ return PTR_ERR(new_conn);
} else {
- WARN_ON(pdata->nr_inconns == ptr->dest_port + 1);
+ WARN_ON(pdata->high_inport == conn.dest_port + 1);
/*
* We do not track input port connections for a device.
* However we need the highest port number described,
* record for an output connection. Hence, do not move
* the ptr for input connections
*/
- if (ptr->dest_port >= pdata->nr_inconns)
- pdata->nr_inconns = ptr->dest_port + 1;
+ if (conn.dest_port >= pdata->high_inport)
+ pdata->high_inport = conn.dest_port + 1;
}
}
- rc = coresight_alloc_conns(&adev->dev, pdata);
- if (rc)
- return rc;
-
- /* Copy the connection information to the final location */
- for (i = 0; conns + i < ptr; i++) {
- int port = conns[i].src_port;
-
- /* Duplicate output port */
- WARN_ON(pdata->out_conns[port].dest_fwnode);
- pdata->out_conns[port] = conns[i];
- }
-
- devm_kfree(&adev->dev, conns);
return 0;
}
if (!adev)
return -EINVAL;
- return acpi_coresight_parse_graph(adev, pdata);
+ return acpi_coresight_parse_graph(dev, adev, pdata);
}
#else