coresight: Add generic sysfs link creation functions

To allow the connections between coresight components to be represented
in sysfs, generic methods for creating sysfs links between two coresight
devices are added.

Signed-off-by: Mike Leach <mike.leach@linaro.org>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Link: https://lore.kernel.org/r/20200518180242.7916-4-mathieu.poirier@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Mike Leach 2020-05-18 12:02:22 -06:00 committed by Greg Kroah-Hartman
parent 68a5d5fccb
commit 8096152588
4 changed files with 150 additions and 1 deletions

View file

@ -2,7 +2,8 @@
#
# Makefile for CoreSight drivers.
#
obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o coresight-platform.o
obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o \
coresight-platform.o coresight-sysfs.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o \
coresight-tmc-etf.o \
coresight-tmc-etr.o

View file

@ -153,6 +153,10 @@ struct coresight_device *coresight_get_sink_by_id(u32 id);
struct list_head *coresight_build_path(struct coresight_device *csdev,
struct coresight_device *sink);
void coresight_release_path(struct list_head *path);
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);
#ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
extern int etm_readl_cp14(u32 off, unsigned int *val);

View file

@ -0,0 +1,124 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019, Linaro Limited, All rights reserved.
* Author: Mike Leach <mike.leach@linaro.org>
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include "coresight-priv.h"
/*
* Connections group - links attribute.
* Count of created links between coresight components in the group.
*/
static ssize_t nr_links_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct coresight_device *csdev = to_coresight_device(dev);
return sprintf(buf, "%d\n", csdev->nr_links);
}
static DEVICE_ATTR_RO(nr_links);
static struct attribute *coresight_conns_attrs[] = {
&dev_attr_nr_links.attr,
NULL,
};
static struct attribute_group coresight_conns_group = {
.attrs = coresight_conns_attrs,
.name = "connections",
};
/*
* Create connections group for CoreSight devices.
* This group will then be used to collate the sysfs links between
* devices.
*/
int coresight_create_conns_sysfs_group(struct coresight_device *csdev)
{
int ret = 0;
if (!csdev)
return -EINVAL;
ret = sysfs_create_group(&csdev->dev.kobj, &coresight_conns_group);
if (ret)
return ret;
csdev->has_conns_grp = true;
return ret;
}
void coresight_remove_conns_sysfs_group(struct coresight_device *csdev)
{
if (!csdev)
return;
if (csdev->has_conns_grp) {
sysfs_remove_group(&csdev->dev.kobj, &coresight_conns_group);
csdev->has_conns_grp = false;
}
}
int coresight_add_sysfs_link(struct coresight_sysfs_link *info)
{
int ret = 0;
if (!info)
return -EINVAL;
if (!info->orig || !info->target ||
!info->orig_name || !info->target_name)
return -EINVAL;
if (!info->orig->has_conns_grp || !info->target->has_conns_grp)
return -EINVAL;
/* first link orig->target */
ret = sysfs_add_link_to_group(&info->orig->dev.kobj,
coresight_conns_group.name,
&info->target->dev.kobj,
info->orig_name);
if (ret)
return ret;
/* second link target->orig */
ret = sysfs_add_link_to_group(&info->target->dev.kobj,
coresight_conns_group.name,
&info->orig->dev.kobj,
info->target_name);
/* error in second link - remove first - otherwise inc counts */
if (ret) {
sysfs_remove_link_from_group(&info->orig->dev.kobj,
coresight_conns_group.name,
info->orig_name);
} else {
info->orig->nr_links++;
info->target->nr_links++;
}
return ret;
}
void coresight_remove_sysfs_link(struct coresight_sysfs_link *info)
{
if (!info)
return;
if (!info->orig || !info->target ||
!info->orig_name || !info->target_name)
return;
sysfs_remove_link_from_group(&info->orig->dev.kobj,
coresight_conns_group.name,
info->orig_name);
sysfs_remove_link_from_group(&info->target->dev.kobj,
coresight_conns_group.name,
info->target_name);
info->orig->nr_links--;
info->target->nr_links--;
}

View file

@ -148,6 +148,20 @@ struct coresight_connection {
struct coresight_device *child_dev;
};
/**
* struct coresight_sysfs_link - representation of a connection in sysfs.
* @orig: Originating (master) coresight device for the link.
* @orig_name: Name to use for the link orig->target.
* @target: Target (slave) coresight device for the link.
* @target_name: Name to use for the link target->orig.
*/
struct coresight_sysfs_link {
struct coresight_device *orig;
const char *orig_name;
struct coresight_device *target;
const char *target_name;
};
/**
* struct coresight_device - representation of a device as used by the framework
* @pdata: Platform data with device connections associated to this device.
@ -165,6 +179,9 @@ struct coresight_connection {
* @ea: Device attribute for sink representation under PMU directory.
* @ect_dev: Associated cross trigger device. Not part of the trace data
* path or connections.
* @nr_links: number of sysfs links created to other components from this
* device. These will appear in the "connections" group.
* @has_conns_grp: Have added a "connections" group for sysfs links.
*/
struct coresight_device {
struct coresight_platform_data *pdata;
@ -180,6 +197,9 @@ struct coresight_device {
struct dev_ext_attribute *ea;
/* cross trigger handling */
struct coresight_device *ect_dev;
/* sysfs links between components */
int nr_links;
bool has_conns_grp;
};
/*