Commit ae7f2b5a authored by James Clark's avatar James Clark Committed by Suzuki K Poulose
Browse files

coresight: Make refcount a property of the connection



This removes the need to do an additional lookup for the total number
of ports used and also removes the need to allocate an array of
refcounts which is just another representation of a connection array.

This was only used for link type devices, for regular devices a single
refcount on the coresight device is used.

There is a both an input and output refcount in case two link type
devices are connected together so that they don't overwrite each other's
counts.

Reviewed-by: default avatarMike Leach <mike.leach@linaro.org>
Signed-off-by: default avatarJames Clark <james.clark@arm.com>
Signed-off-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20230425143542.2305069-11-james.clark@arm.com
parent e3f4e687
Loading
Loading
Loading
Loading
+40 −76
Original line number Diff line number Diff line
@@ -112,40 +112,24 @@ struct coresight_device *coresight_get_percpu_sink(int cpu)
}
EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);

static int coresight_find_link_inport(struct coresight_device *csdev,
				      struct coresight_device *parent)
static struct coresight_connection *
coresight_find_out_connection(struct coresight_device *src_dev,
			      struct coresight_device *dest_dev)
{
	int i;
	struct coresight_connection *conn;

	for (i = 0; i < parent->pdata->nr_outconns; i++) {
		conn = parent->pdata->out_conns[i];
		if (conn->dest_dev == csdev)
			return conn->dest_port;
	for (i = 0; i < src_dev->pdata->nr_outconns; i++) {
		conn = src_dev->pdata->out_conns[i];
		if (conn->dest_dev == dest_dev)
			return conn;
	}

	dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n",
		dev_name(&parent->dev), dev_name(&csdev->dev));
	dev_err(&src_dev->dev,
		"couldn't find output connection, src_dev: %s, dest_dev: %s\n",
		dev_name(&src_dev->dev), dev_name(&dest_dev->dev));

	return -ENODEV;
}

static int coresight_find_link_outport(struct coresight_device *csdev,
				       struct coresight_device *child)
{
	int i;
	struct coresight_connection *conn;

	for (i = 0; i < csdev->pdata->nr_outconns; i++) {
		conn = csdev->pdata->out_conns[i];
		if (conn->dest_dev == child)
			return conn->src_port;
	}

	dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n",
		dev_name(&csdev->dev), dev_name(&child->dev));

	return -ENODEV;
	return ERR_PTR(-ENODEV);
}

static inline u32 coresight_read_claim_tags(struct coresight_device *csdev)
@@ -352,24 +336,24 @@ static int coresight_enable_link(struct coresight_device *csdev,
{
	int ret = 0;
	int link_subtype;
	int inport, outport;
	struct coresight_connection *inconn, *outconn;

	if (!parent || !child)
		return -EINVAL;

	inport = coresight_find_link_inport(csdev, parent);
	outport = coresight_find_link_outport(csdev, child);
	inconn = coresight_find_out_connection(parent, csdev);
	outconn = coresight_find_out_connection(csdev, child);
	link_subtype = csdev->subtype.link_subtype;

	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && inport < 0)
		return inport;
	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0)
		return outport;
	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && IS_ERR(inconn))
		return PTR_ERR(inconn);
	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn))
		return PTR_ERR(outconn);

	if (link_ops(csdev)->enable) {
		ret = coresight_control_assoc_ectdev(csdev, true);
		if (!ret) {
			ret = link_ops(csdev)->enable(csdev, inport, outport);
			ret = link_ops(csdev)->enable(csdev, inconn, outconn);
			if (ret)
				coresight_control_assoc_ectdev(csdev, false);
		}
@@ -385,33 +369,36 @@ static void coresight_disable_link(struct coresight_device *csdev,
				   struct coresight_device *parent,
				   struct coresight_device *child)
{
	int i, nr_conns;
	int i;
	int link_subtype;
	int inport, outport;
	struct coresight_connection *inconn, *outconn;

	if (!parent || !child)
		return;

	inport = coresight_find_link_inport(csdev, parent);
	outport = coresight_find_link_outport(csdev, child);
	inconn = coresight_find_out_connection(parent, csdev);
	outconn = coresight_find_out_connection(csdev, child);
	link_subtype = csdev->subtype.link_subtype;

	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
		nr_conns = csdev->pdata->high_inport;
	} else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
		nr_conns = csdev->pdata->high_outport;
	} else {
		nr_conns = 1;
	}

	if (link_ops(csdev)->disable) {
		link_ops(csdev)->disable(csdev, inport, outport);
		link_ops(csdev)->disable(csdev, inconn, outconn);
		coresight_control_assoc_ectdev(csdev, false);
	}

	for (i = 0; i < nr_conns; i++)
		if (atomic_read(&csdev->refcnt[i]) != 0)
	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
		for (i = 0; i < csdev->pdata->nr_inconns; i++)
			if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) !=
			    0)
				return;
	} else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
		for (i = 0; i < csdev->pdata->nr_outconns; i++)
			if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) !=
			    0)
				return;
	} else {
		if (atomic_read(&csdev->refcnt) != 0)
			return;
	}

	csdev->enable = false;
}
@@ -435,7 +422,7 @@ static int coresight_enable_source(struct coresight_device *csdev,
		csdev->enable = true;
	}

	atomic_inc(csdev->refcnt);
	atomic_inc(&csdev->refcnt);

	return 0;
}
@@ -450,7 +437,7 @@ static int coresight_enable_source(struct coresight_device *csdev,
 */
static bool coresight_disable_source(struct coresight_device *csdev)
{
	if (atomic_dec_return(csdev->refcnt) == 0) {
	if (atomic_dec_return(&csdev->refcnt) == 0) {
		if (source_ops(csdev)->disable)
			source_ops(csdev)->disable(csdev, NULL);
		coresight_control_assoc_ectdev(csdev, false);
@@ -1094,7 +1081,7 @@ int coresight_enable(struct coresight_device *csdev)
		 * source is already enabled.
		 */
		if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
			atomic_inc(csdev->refcnt);
			atomic_inc(&csdev->refcnt);
		goto out;
	}

@@ -1308,7 +1295,6 @@ static void coresight_device_release(struct device *dev)
	struct coresight_device *csdev = to_coresight_device(dev);

	fwnode_handle_put(csdev->dev.fwnode);
	kfree(csdev->refcnt);
	kfree(csdev);
}

@@ -1537,9 +1523,6 @@ void coresight_release_platform_data(struct coresight_device *csdev,
struct coresight_device *coresight_register(struct coresight_desc *desc)
{
	int ret;
	int link_subtype;
	int nr_refcnts = 1;
	atomic_t *refcnts = NULL;
	struct coresight_device *csdev;
	bool registered = false;

@@ -1549,25 +1532,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
		goto err_out;
	}

	if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
	    desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
		link_subtype = desc->subtype.link_subtype;

		if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
			nr_refcnts = desc->pdata->high_inport;
		else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
			nr_refcnts = desc->pdata->high_outport;
	}

	refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
	if (!refcnts) {
		ret = -ENOMEM;
		kfree(csdev);
		goto err_out;
	}

	csdev->refcnt = refcnts;

	csdev->pdata = desc->pdata;

	csdev->type = desc->type;
+5 −5
Original line number Diff line number Diff line
@@ -163,7 +163,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
		drvdata->mode = CS_MODE_SYSFS;
	}

	atomic_inc(csdev->refcnt);
	atomic_inc(&csdev->refcnt);
out:
	spin_unlock_irqrestore(&drvdata->spinlock, flags);
	return ret;
@@ -199,7 +199,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
	 * use for this session.
	 */
	if (drvdata->pid == pid) {
		atomic_inc(csdev->refcnt);
		atomic_inc(&csdev->refcnt);
		goto out;
	}

@@ -217,7 +217,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
		/* Associate with monitored process. */
		drvdata->pid = pid;
		drvdata->mode = CS_MODE_PERF;
		atomic_inc(csdev->refcnt);
		atomic_inc(&csdev->refcnt);
	}

out:
@@ -356,7 +356,7 @@ static int etb_disable(struct coresight_device *csdev)

	spin_lock_irqsave(&drvdata->spinlock, flags);

	if (atomic_dec_return(csdev->refcnt)) {
	if (atomic_dec_return(&csdev->refcnt)) {
		spin_unlock_irqrestore(&drvdata->spinlock, flags);
		return -EBUSY;
	}
@@ -447,7 +447,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
	spin_lock_irqsave(&drvdata->spinlock, flags);

	/* Don't do anything if another tracer is using this sink */
	if (atomic_read(csdev->refcnt) != 1)
	if (atomic_read(&csdev->refcnt) != 1)
		goto out;

	__etb_disable_hw(drvdata);
+15 −11
Original line number Diff line number Diff line
@@ -74,8 +74,9 @@ static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
	return rc;
}

static int funnel_enable(struct coresight_device *csdev, int inport,
			 int outport)
static int funnel_enable(struct coresight_device *csdev,
			 struct coresight_connection *in,
			 struct coresight_connection *out)
{
	int rc = 0;
	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -83,18 +84,19 @@ static int funnel_enable(struct coresight_device *csdev, int inport,
	bool first_enable = false;

	spin_lock_irqsave(&drvdata->spinlock, flags);
	if (atomic_read(&csdev->refcnt[inport]) == 0) {
	if (atomic_read(&in->dest_refcnt) == 0) {
		if (drvdata->base)
			rc = dynamic_funnel_enable_hw(drvdata, inport);
			rc = dynamic_funnel_enable_hw(drvdata, in->dest_port);
		if (!rc)
			first_enable = true;
	}
	if (!rc)
		atomic_inc(&csdev->refcnt[inport]);
		atomic_inc(&in->dest_refcnt);
	spin_unlock_irqrestore(&drvdata->spinlock, flags);

	if (first_enable)
		dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", inport);
		dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n",
			in->dest_port);
	return rc;
}

@@ -117,23 +119,25 @@ static void dynamic_funnel_disable_hw(struct funnel_drvdata *drvdata,
	CS_LOCK(drvdata->base);
}

static void funnel_disable(struct coresight_device *csdev, int inport,
			   int outport)
static void funnel_disable(struct coresight_device *csdev,
			   struct coresight_connection *in,
			   struct coresight_connection *out)
{
	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
	unsigned long flags;
	bool last_disable = false;

	spin_lock_irqsave(&drvdata->spinlock, flags);
	if (atomic_dec_return(&csdev->refcnt[inport]) == 0) {
	if (atomic_dec_return(&in->dest_refcnt) == 0) {
		if (drvdata->base)
			dynamic_funnel_disable_hw(drvdata, inport);
			dynamic_funnel_disable_hw(drvdata, in->dest_port);
		last_disable = true;
	}
	spin_unlock_irqrestore(&drvdata->spinlock, flags);

	if (last_disable)
		dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport);
		dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n",
			in->dest_port);
}

static const struct coresight_ops_link funnel_link_ops = {
+6 −103
Original line number Diff line number Diff line
@@ -146,41 +146,6 @@ static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
	return of_property_read_bool(ep, "slave-mode");
}

static void of_coresight_get_ports_legacy(const struct device_node *node,
					  int *nr_inconns, int *nr_outconns)
{
	struct device_node *ep = NULL;
	struct of_endpoint endpoint;
	int in = 0, out = 0;

	/*
	 * Avoid warnings in of_graph_get_next_endpoint()
	 * if the device doesn't have any graph connections
	 */
	if (!of_graph_is_present(node))
		return;
	do {
		ep = of_graph_get_next_endpoint(node, ep);
		if (!ep)
			break;

		if (of_graph_parse_endpoint(ep, &endpoint))
			continue;

		if (of_coresight_legacy_ep_is_input(ep)) {
			in = (endpoint.port + 1 > in) ?
				endpoint.port + 1 : in;
		} else {
			out = (endpoint.port + 1) > out ?
				endpoint.port + 1 : out;
		}

	} while (ep);

	*nr_inconns = in;
	*nr_outconns = out;
}

static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
{
	struct device_node *parent = of_graph_get_port_parent(ep);
@@ -196,59 +161,12 @@ static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
	return parent;
}

static inline struct device_node *
of_coresight_get_input_ports_node(const struct device_node *node)
{
	return of_get_child_by_name(node, "in-ports");
}

static inline struct device_node *
of_coresight_get_output_ports_node(const struct device_node *node)
{
	return of_get_child_by_name(node, "out-ports");
}

static inline int
of_coresight_count_ports(struct device_node *port_parent)
{
	int i = 0;
	struct device_node *ep = NULL;
	struct of_endpoint endpoint;

	while ((ep = of_graph_get_next_endpoint(port_parent, ep))) {
		/* Defer error handling to parsing */
		if (of_graph_parse_endpoint(ep, &endpoint))
			continue;
		if (endpoint.port + 1 > i)
			i = endpoint.port + 1;
	}

	return i;
}

static void of_coresight_get_ports(const struct device_node *node,
				   int *nr_inconns, int *nr_outconns)
{
	struct device_node *input_ports = NULL, *output_ports = NULL;

	input_ports = of_coresight_get_input_ports_node(node);
	output_ports = of_coresight_get_output_ports_node(node);

	if (input_ports || output_ports) {
		if (input_ports) {
			*nr_inconns = of_coresight_count_ports(input_ports);
			of_node_put(input_ports);
		}
		if (output_ports) {
			*nr_outconns = of_coresight_count_ports(output_ports);
			of_node_put(output_ports);
		}
	} else {
		/* Fall back to legacy DT bindings parsing */
		of_coresight_get_ports_legacy(node, nr_inconns, nr_outconns);
	}
}

static int of_coresight_get_cpu(struct device *dev)
{
	int cpu;
@@ -351,13 +269,6 @@ static int of_get_coresight_platform_data(struct device *dev,
	bool legacy_binding = false;
	struct device_node *node = dev->of_node;

	/* Get the number of input and output port for this component */
	of_coresight_get_ports(node, &pdata->high_inport, &pdata->high_outport);

	/* If there are no output connections, we are done */
	if (!pdata->high_outport)
		return 0;

	parent = of_coresight_get_output_ports_node(node);
	/*
	 * If the DT uses obsoleted bindings, the ports are listed
@@ -365,6 +276,12 @@ static int of_get_coresight_platform_data(struct device *dev,
	 * ports.
	 */
	if (!parent) {
		/*
		 * Avoid warnings in of_graph_get_next_endpoint()
		 * if the device doesn't have any graph connections
		 */
		if (!of_graph_is_present(node))
			return 0;
		legacy_binding = true;
		parent = node;
		dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
@@ -751,7 +668,6 @@ static int acpi_coresight_parse_graph(struct device *dev,
	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 (!graph)
		return -ENOENT;
@@ -770,22 +686,9 @@ static int acpi_coresight_parse_graph(struct device *dev,
			return dir;

		if (dir == ACPI_CORESIGHT_LINK_MASTER) {
			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->high_inport == conn.dest_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 (conn.dest_port >= pdata->high_inport)
				pdata->high_inport = conn.dest_port + 1;
		}
	}

+13 −10
Original line number Diff line number Diff line
@@ -114,8 +114,9 @@ static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,
	return rc;
}

static int replicator_enable(struct coresight_device *csdev, int inport,
			     int outport)
static int replicator_enable(struct coresight_device *csdev,
			     struct coresight_connection *in,
			     struct coresight_connection *out)
{
	int rc = 0;
	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -123,15 +124,15 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
	bool first_enable = false;

	spin_lock_irqsave(&drvdata->spinlock, flags);
	if (atomic_read(&csdev->refcnt[outport]) == 0) {
	if (atomic_read(&out->src_refcnt) == 0) {
		if (drvdata->base)
			rc = dynamic_replicator_enable(drvdata, inport,
						       outport);
			rc = dynamic_replicator_enable(drvdata, in->dest_port,
						       out->src_port);
		if (!rc)
			first_enable = true;
	}
	if (!rc)
		atomic_inc(&csdev->refcnt[outport]);
		atomic_inc(&out->src_refcnt);
	spin_unlock_irqrestore(&drvdata->spinlock, flags);

	if (first_enable)
@@ -168,17 +169,19 @@ static void dynamic_replicator_disable(struct replicator_drvdata *drvdata,
	CS_LOCK(drvdata->base);
}

static void replicator_disable(struct coresight_device *csdev, int inport,
			       int outport)
static void replicator_disable(struct coresight_device *csdev,
			       struct coresight_connection *in,
			       struct coresight_connection *out)
{
	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
	unsigned long flags;
	bool last_disable = false;

	spin_lock_irqsave(&drvdata->spinlock, flags);
	if (atomic_dec_return(&csdev->refcnt[outport]) == 0) {
	if (atomic_dec_return(&out->src_refcnt) == 0) {
		if (drvdata->base)
			dynamic_replicator_disable(drvdata, inport, outport);
			dynamic_replicator_disable(drvdata, in->dest_port,
						   out->src_port);
		last_disable = true;
	}
	spin_unlock_irqrestore(&drvdata->spinlock, flags);
Loading