0001
0002
0003
0004
0005
0006
0007 #include <linux/device.h>
0008 #include <linux/kernel.h>
0009
0010 #include "coresight-priv.h"
0011
0012
0013
0014
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
0038
0039
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
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
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
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
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
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
0179
0180
0181 conn->child_dev = target;
0182 return 0;
0183 } while (0);
0184
0185 return ret;
0186 }
0187
0188
0189
0190
0191
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 }