static int acpi_coresight_parse_graph()

in coresight/coresight-platform.c [686:753]


static int acpi_coresight_parse_graph(struct acpi_device *adev,
				      struct coresight_platform_data *pdata)
{
	int rc, i, nlinks;
	const union acpi_object *graph;
	struct coresight_connection *conns, *ptr;

	pdata->nr_inport = pdata->nr_outport = 0;
	graph = acpi_get_coresight_graph(adev);
	if (!graph)
		return -ENOENT;

	nlinks = graph->package.elements[2].integer.value;
	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);
		if (dir < 0)
			return dir;

		if (dir == ACPI_CORESIGHT_LINK_MASTER) {
			if (ptr->outport >= pdata->nr_outport)
				pdata->nr_outport = ptr->outport + 1;
			ptr++;
		} else {
			WARN_ON(pdata->nr_inport == ptr->child_port + 1);
			/*
			 * We do not track input port connections for a device.
			 * However we need the highest port number described,
			 * which can be recorded now and reuse this connection
			 * record for an output connection. Hence, do not move
			 * the ptr for input connections
			 */
			if (ptr->child_port >= pdata->nr_inport)
				pdata->nr_inport = ptr->child_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].outport;

		/* Duplicate output port */
		WARN_ON(pdata->conns[port].child_fwnode);
		pdata->conns[port] = conns[i];
	}

	devm_kfree(&adev->dev, conns);
	return 0;
}