Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2019, Linaro Limited, All rights reserved.
0004  * Author: Mike Leach <mike.leach@linaro.org>
0005  */
0006 
0007 #include <linux/device.h>
0008 #include <linux/kernel.h>
0009 
0010 #include "coresight-priv.h"
0011 
0012 /*
0013  * Connections group - links attribute.
0014  * Count of created links between coresight components in the group.
0015  */
0016 static ssize_t nr_links_show(struct device *dev,
0017                  struct device_attribute *attr,
0018                  char *buf)
0019 {
0020     struct coresight_device *csdev = to_coresight_device(dev);
0021 
0022     return sprintf(buf, "%d\n", csdev->nr_links);
0023 }
0024 static DEVICE_ATTR_RO(nr_links);
0025 
0026 static struct attribute *coresight_conns_attrs[] = {
0027     &dev_attr_nr_links.attr,
0028     NULL,
0029 };
0030 
0031 static struct attribute_group coresight_conns_group = {
0032     .attrs = coresight_conns_attrs,
0033     .name = "connections",
0034 };
0035 
0036 /*
0037  * Create connections group for CoreSight devices.
0038  * This group will then be used to collate the sysfs links between
0039  * devices.
0040  */
0041 int coresight_create_conns_sysfs_group(struct coresight_device *csdev)
0042 {
0043     int ret = 0;
0044 
0045     if (!csdev)
0046         return -EINVAL;
0047 
0048     ret = sysfs_create_group(&csdev->dev.kobj, &coresight_conns_group);
0049     if (ret)
0050         return ret;
0051 
0052     csdev->has_conns_grp = true;
0053     return ret;
0054 }
0055 
0056 void coresight_remove_conns_sysfs_group(struct coresight_device *csdev)
0057 {
0058     if (!csdev)
0059         return;
0060 
0061     if (csdev->has_conns_grp) {
0062         sysfs_remove_group(&csdev->dev.kobj, &coresight_conns_group);
0063         csdev->has_conns_grp = false;
0064     }
0065 }
0066 
0067 int coresight_add_sysfs_link(struct coresight_sysfs_link *info)
0068 {
0069     int ret = 0;
0070 
0071     if (!info)
0072         return -EINVAL;
0073     if (!info->orig || !info->target ||
0074         !info->orig_name || !info->target_name)
0075         return -EINVAL;
0076     if (!info->orig->has_conns_grp || !info->target->has_conns_grp)
0077         return -EINVAL;
0078 
0079     /* first link orig->target */
0080     ret = sysfs_add_link_to_group(&info->orig->dev.kobj,
0081                       coresight_conns_group.name,
0082                       &info->target->dev.kobj,
0083                       info->orig_name);
0084     if (ret)
0085         return ret;
0086 
0087     /* second link target->orig */
0088     ret = sysfs_add_link_to_group(&info->target->dev.kobj,
0089                       coresight_conns_group.name,
0090                       &info->orig->dev.kobj,
0091                       info->target_name);
0092 
0093     /* error in second link - remove first - otherwise inc counts */
0094     if (ret) {
0095         sysfs_remove_link_from_group(&info->orig->dev.kobj,
0096                          coresight_conns_group.name,
0097                          info->orig_name);
0098     } else {
0099         info->orig->nr_links++;
0100         info->target->nr_links++;
0101     }
0102 
0103     return ret;
0104 }
0105 EXPORT_SYMBOL_GPL(coresight_add_sysfs_link);
0106 
0107 void coresight_remove_sysfs_link(struct coresight_sysfs_link *info)
0108 {
0109     if (!info)
0110         return;
0111     if (!info->orig || !info->target ||
0112         !info->orig_name || !info->target_name)
0113         return;
0114 
0115     sysfs_remove_link_from_group(&info->orig->dev.kobj,
0116                      coresight_conns_group.name,
0117                      info->orig_name);
0118 
0119     sysfs_remove_link_from_group(&info->target->dev.kobj,
0120                      coresight_conns_group.name,
0121                      info->target_name);
0122 
0123     info->orig->nr_links--;
0124     info->target->nr_links--;
0125 }
0126 EXPORT_SYMBOL_GPL(coresight_remove_sysfs_link);
0127 
0128 /*
0129  * coresight_make_links: Make a link for a connection from a @orig
0130  * device to @target, represented by @conn.
0131  *
0132  *   e.g, for devOrig[output_X] -> devTarget[input_Y] is represented
0133  *   as two symbolic links :
0134  *
0135  *  /sys/.../devOrig/out:X  -> /sys/.../devTarget/
0136  *  /sys/.../devTarget/in:Y -> /sys/.../devOrig/
0137  *
0138  * The link names are allocated for a device where it appears. i.e, the
0139  * "out" link on the master and "in" link on the slave device.
0140  * The link info is stored in the connection record for avoiding
0141  * the reconstruction of names for removal.
0142  */
0143 int coresight_make_links(struct coresight_device *orig,
0144              struct coresight_connection *conn,
0145              struct coresight_device *target)
0146 {
0147     int ret = -ENOMEM;
0148     char *outs = NULL, *ins = NULL;
0149     struct coresight_sysfs_link *link = NULL;
0150 
0151     do {
0152         outs = devm_kasprintf(&orig->dev, GFP_KERNEL,
0153                       "out:%d", conn->outport);
0154         if (!outs)
0155             break;
0156         ins = devm_kasprintf(&target->dev, GFP_KERNEL,
0157                      "in:%d", conn->child_port);
0158         if (!ins)
0159             break;
0160         link = devm_kzalloc(&orig->dev,
0161                     sizeof(struct coresight_sysfs_link),
0162                     GFP_KERNEL);
0163         if (!link)
0164             break;
0165 
0166         link->orig = orig;
0167         link->target = target;
0168         link->orig_name = outs;
0169         link->target_name = ins;
0170 
0171         ret = coresight_add_sysfs_link(link);
0172         if (ret)
0173             break;
0174 
0175         conn->link = link;
0176 
0177         /*
0178          * Install the device connection. This also indicates that
0179          * the links are operational on both ends.
0180          */
0181         conn->child_dev = target;
0182         return 0;
0183     } while (0);
0184 
0185     return ret;
0186 }
0187 
0188 /*
0189  * coresight_remove_links: Remove the sysfs links for a given connection @conn,
0190  * from @orig device to @target device. See coresight_make_links() for more
0191  * details.
0192  */
0193 void coresight_remove_links(struct coresight_device *orig,
0194                 struct coresight_connection *conn)
0195 {
0196     if (!orig || !conn->link)
0197         return;
0198 
0199     coresight_remove_sysfs_link(conn->link);
0200 
0201     devm_kfree(&conn->child_dev->dev, conn->link->target_name);
0202     devm_kfree(&orig->dev, conn->link->orig_name);
0203     devm_kfree(&orig->dev, conn->link);
0204     conn->link = NULL;
0205     conn->child_dev = NULL;
0206 }