Subject: Re: [PATCH v4 4/6] coresight: Expose device connections via sysfs

From: Mathieu Poirier <[email-masked]>
Date: Fri, 14 Feb 2020 15:31:11 -0700

Hi Mike,

On Tue, Feb 11, 2020 at 10:58:06AM +0000, Mike Leach wrote:
> From: Suzuki K Poulose <[email-masked]>
> 
> Coresight device connections are a bit complicated and is not
> exposed currently to the user. One has to look at the platform
> descriptions (DT bindings or ACPI bindings) to make an understanding.
> Given the new naming scheme, it will be helpful to have this information
> to choose the appropriate devices for tracing. This patch exposes
> the device connections via links in the sysfs directories.
> 
> e.g, for a connection devA[OutputPort_X] -> devB[InputPort_Y]
> is represented as two symlinks:
> 
>   /sys/bus/coresight/.../devA/out:X -> /sys/bus/coresight/.../devB
>   /sys/bus/coresight/.../devB/in:Y  -> /sys/bus/coresight/.../devA
> 
> Cc: Mathieu Poirier <[email-masked]>
> Signed-off-by: Suzuki K Poulose <[email-masked]>
> 
> Revised to use the generic sysfs links functions & link structures.
> Provides a connections sysfs group to hold the links.
> 
> Co-developed-by: Mike Leach <[email-masked]>
> Signed-off-by: Mike Leach <[email-masked]>

Because this patch is "From:" Suzuki, this should be:

Co-developed-by: Suzuki K Poulose <[email-masked]>
Signed-off-by: Mike Leach <[email-masked]>

You can expand on Suzuki's contribution or the modifications you've done to it
in the changelog.

With the above:

Reviewed-by: Mathieu Poirier <[email-masked]>

> ---
>  drivers/hwtracing/coresight/coresight-priv.h  |  5 ++
>  drivers/hwtra cing/coresight/coresight-sysfs.c | 80 +++++++++++++++++++
>  drivers/hwtracing/coresight/coresight.c       | 46 ++++++++---
>  include/linux/coresight.h                     |  2 +
>  4 files changed, 121 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
> index a4a658d46045..5a36f0f50899 100644
> --- a/drivers/hwtracing/coresight/coresight-priv.h
> +++ b/drivers/hwtracing/coresight/coresight-priv.h
> @@ -157,6 +157,11 @@ int coresight_add_sysfs_link(struct coresight_sysfs_link *info);
>  void coresight_remove_sysfs_link(struct coresight_sysfs_link *info);
>  int coresight_create_conns_sysfs_group(struct coresight_device *csdev);
>  void coresight_remove_conns_sysfs_group(struct coresight_device *csdev);
> +int coresight_make_links(struct coresight_device *orig,
> +			 struct coresight_connection *conn,
> +			 struct coresight_device *target);
> +void coresight_remove_links(struct coresight_device *orig,
> +			    struct coresight_connection *conn);
>  
>  #ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
>  extern int etm_readl_cp14(u32 off, unsigned int *val);
> diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
> index 17d565941e5e..0f18332b9f19 100644
> --- a/drivers/hwtracing/coresight/coresight-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-sysfs.c
> @@ -122,3 +122,83 @@ void coresight_remove_sysfs_link(struct coresight_sysfs_link *info)
>  	info->orig->nr_links--;
>  	info->target->nr_links--;
>  }
> +
> +/*
> + * coresight_make_links: Make a link for a connection from a @orig
> + * device to @target, represented by @conn.
> + *
> + *   e.g, for devOrig[output_X] -> devTarget[input_Y] is represented
> + *   as two symbolic links :
> + *
> + *	/sys/.../devOrig/out:X	-> /sys/.../devTarget/
> + *	/sys/.../devTarget/in:Y	-> /sys/.../devOrig/
> + *
> + * The link names are allocated for a device where it appears. i.e, the
> + * "out" link on the master and "in" link on the slave device.
> + * The link info is stored in the connection record for avoiding
> + * the reconstruction of names for removal.
> + */
> +int coresight_make_links(struct coresight_device *orig,
> +			 struct coresight_connection *conn,
> +			 struct coresight_device *target)
> +{
> +	int ret = -ENOMEM;
> +	char *outs = NULL, *ins = NULL;
> +	struct coresight_sysfs_link *link = NULL;
> +
> +	do {
> +		outs = devm_kasprintf(&orig->dev, GFP_KERNEL,
> +				      "out:%d", conn->outport);
> +		if (!outs)
> +			break;
> +		ins = devm_kasprintf(&target->dev, GFP_KERNEL,
> +				     "in:%d", conn->child_port);
> +		if (!ins)
> +			break;
> +		link = devm_kzalloc(&orig->dev,
> +				    sizeof(struct coresight_sysfs_link),
> +				    GFP_KERNEL);
> +		if (!link)
> +			break;
> +
> +		link->orig = orig;
> +		link->target = target;
> +		link->orig_name = outs;
> +		link->target_name = ins;
> +
> +		ret = coresight_add_sysfs_link(link);
> +		if (ret)
> +			break;
> +
> +		conn->link = link;
> +
> +		/*
> +		 * Install the device connection. This also indicates that
> +		 * the links are operational on both ends.
> +		 */
> +		conn->child_dev = target;
> +		return 0;
> +	} while (0);
> +
> +	return ret;
> +}
> +
> +/*
> + * coresight_remove_links: Remove the sysfs links for a given connection @conn,
> + * from @orig device to @target device. See coresight_make_links() for more
> + * details.
> + */
> +void coresight_remove_links(struct coresight_device *orig,
> +			    struct coresight_connection *conn)
> +{
> +	if (!orig || !conn->link)
> +		return;
> +
> +	coresight_remove_sysfs_link(conn->link);
> +
> +	devm_kfree(&conn->child_dev->dev, conn->link->target_name);
> +	devm_kfree(&orig->dev, conn->link->orig_name);
> +	devm_kfree(&orig->dev, conn->link);
> +	conn->link = NULL;
> +	conn->child_dev = NULL;
> +}
> diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
> index 07f66a3968f1..4f10cfa9dc18 100644
> --- a/drivers/hwtracing/coresight/coresight.c
> +++ b/drivers/hwtracing/coresight/coresight.c
> @@ -1031,7 +1031,7 @@ static void coresight_device_release(struct device *dev)
>  
>  static int coresight_orphan_match(struct device *dev, void *data)
>  {
> -	int i;
> +	int i, ret = 0;
>  	bool still_orphan = false;
>  	struct coresight_device *csdev, *i_csdev;
>  	struct coresight_connection *conn;
> @@ -1056,19 +1056,23 @@ static int coresight_orphan_match(struct device *dev, void *data)
>  		/* We have found at least one orphan connection */
>  		if (conn->child_dev == NULL) {
>  			/* Does it match this newly added device? */
> -			if (conn->child_fwnode == csdev->dev.fwnode)
> -				conn->child_dev = csdev;
> -			else
> +			if (conn->child_fwnode == csdev->dev.fwnode) {
> +				ret = coresight_make_links(i_csdev,
> +							   conn, csdev);
> +				if (ret)
> +					return ret;
> +			} else {
>  				/* This component still has an orphan */
>  				still_orphan = true;
> +			}
>  		}
>  	}
>  
>  	i_csdev->orphan = still_orphan;
>  
>  	/*
> -	 * Returning '0' ensures that all known component on the
> -	 * bus will be checked.
> +	 * Returning '0' in case we didn't encounter any error,
> +	 * ensures that all known component on the bus will be checked.
>  	 */
>  	return 0;
>  }
> @@ -1082,15 +1086,21 @@ static int coresight_fixup_orphan_conns(struct coresight_device *csdev)
>  
>  static int coresight_fixup_device_conns(struct coresight_device *csdev)
>  {
> -	int i;
> +	int i, ret = 0;
>  
>  	for (i = 0; i < csdev->pdata->nr_outport; i++) {
>  		struct coresight_connection *conn = &csdev->pdata->conns[i];
>  
>  		conn->child_dev =
>  			coresight_find_csdev_by_fwnode(conn->child_fwnode);
> -		if (!conn->child_dev)
> +		if (conn->child_dev) {
> +			ret = coresight_make_links(csdev, conn,
> +						   conn->child_dev);
> +			if (ret)
> +				break;
> +		} else {
>  			csdev->orphan = true;
> +		}
>  	}
>  
>  	return 0;
> @@ -1121,7 +1131,7 @@ static int coresight_remove_match(struct device *dev, void *data)
>  
>  		if (csdev->dev.fwnode == conn->child_fwnode) {
>  			iterator->orphan = true;
> -			conn->child_dev = NULL;
> +			coresight_remove_links(iterator, conn);
>  			/*
>  			 * Drop the reference to the handle for the remote
>  			 * device acquired in parsing the connections from
> @@ -1215,13 +1225,23 @@ void coresight_release_platform_data(struct coresight_device *csdev,
>  				     struct coresight_platform_data *pdata)
>  {
>  	int i;
> +	struct coresight_connection *conns = pdata->conns;
>  
>  	for (i = 0; i < pdata->nr_outport; i++) {
> -		if (pdata->conns[i].child_fwnode) {
> -			fwnode_handle_put(pdata->conns[i].child_fwnode);
> +		/* If we have made the links, remove them now */
> +		if (csdev && conns[i].child_dev)
> +			coresight_remove_links(csdev, &conns[i]);
> +		/*
> +		 * Drop the refcount and clear the handle as this device
> +		 * is going away
> +		 */
> +		if (conns[i].child_fwnode) {
> +			fwnode_handle_put(conns[i].child_fwnode);
>  			pdata->conns[i].child_fwnode = NULL;
>  		}
>  	}
> +	if (csdev)
> +		coresight_remove_conns_sysfs_group(csdev);
>  }
>  
>  struct coresight_device *coresight_register(struct coresight_desc *desc)
> @@ -1303,7 +1323,9 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
>  
>  	mutex_lock(&coresight_mutex);
>  
> -	ret = coresight_fixup_device_conns(csdev);
> +	ret = coresight_create_conns_sysfs_group(csdev);
> +	if (!ret)
> +		ret = coresight_fixup_device_conns(csdev);
>  	if (!ret)
>  		ret = coresight_fixup_orphan_conns(csdev);
>  	if (!ret)
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index a2ec25e02ca9..ccd17304d7bd 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -140,12 +140,14 @@ struct coresight_desc {
>   * @chid_fwnode: remote component's fwnode handle.
>   * @child_dev:	a @coresight_device representation of the component
>  		connected to @outport.
> + * @link: Representation of the connection as a sysfs link.
>   */
>  struct coresight_connection {
>  	int outport;
>  	int child_port;
>  	struct fwnode_handle *child_fwnode;
>  	struct coresight_device *child_dev;
> +	struct coresight_sysfs_link *link;
>  };
>  
>  /**
> -- 
> 2.17.1
> 

_______________________________________________
linux-arm-kernel mailing list
[email-masked]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel