blob: e237fb7523bdca02549e77e19fb7e7d0e0587f21 [file] [log] [blame]
Pratik Patela20572b2012-12-02 20:33:50 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Pratik Patel74929432011-12-26 12:03:41 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/types.h>
17#include <linux/device.h>
18#include <linux/platform_device.h>
19#include <linux/io.h>
20#include <linux/err.h>
Pratik Patelbf3e77442012-03-18 18:30:43 -070021#include <linux/export.h>
Pratik Patelb84ef9d2012-05-24 14:01:43 -070022#include <linux/slab.h>
Pratik Patel0a7edd32012-06-08 09:31:55 -070023#include <linux/semaphore.h>
Pratik Patel27086d92012-05-17 23:21:43 -070024#include <linux/clk.h>
Pratik Patel1746b8f2012-06-02 21:11:41 -070025#include <linux/coresight.h>
Pratik Patel74929432011-12-26 12:03:41 -080026
Pratik Patel1746b8f2012-06-02 21:11:41 -070027#include "coresight-priv.h"
Pratik Patel74929432011-12-26 12:03:41 -080028
Pratik Patel0a7edd32012-06-08 09:31:55 -070029#define NO_SINK (-1)
Pratik Patel1403f2a2012-03-21 10:10:00 -070030
Pratik Patel0a7edd32012-06-08 09:31:55 -070031static int curr_sink = NO_SINK;
Pratik Patel6fb38342012-06-03 14:51:38 -070032static LIST_HEAD(coresight_orph_conns);
Pratik Patel6fb38342012-06-03 14:51:38 -070033static LIST_HEAD(coresight_devs);
Pratik Patel0a7edd32012-06-08 09:31:55 -070034static DEFINE_SEMAPHORE(coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -070035
Pratik Patel0a7edd32012-06-08 09:31:55 -070036static int coresight_find_link_inport(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -070037{
38 int i;
Pratik Patel0a7edd32012-06-08 09:31:55 -070039 struct coresight_device *parent;
Pratik Patel6fb38342012-06-03 14:51:38 -070040 struct coresight_connection *conn;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070041
Pratik Patel0a7edd32012-06-08 09:31:55 -070042 parent = container_of(csdev->path_link.next, struct coresight_device,
43 path_link);
44 for (i = 0; i < parent->nr_conns; i++) {
45 conn = &parent->conns[i];
46 if (conn->child_dev == csdev)
47 return conn->child_port;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070048 }
Pratik Patel0a7edd32012-06-08 09:31:55 -070049
50 pr_err("coresight: couldn't find inport, parent: %d, child: %d\n",
51 parent->id, csdev->id);
Pratik Patelb84ef9d2012-05-24 14:01:43 -070052 return 0;
Pratik Patel0a7edd32012-06-08 09:31:55 -070053}
54
55static int coresight_find_link_outport(struct coresight_device *csdev)
56{
57 int i;
58 struct coresight_device *child;
59 struct coresight_connection *conn;
60
61 child = container_of(csdev->path_link.prev, struct coresight_device,
62 path_link);
63 for (i = 0; i < csdev->nr_conns; i++) {
64 conn = &csdev->conns[i];
65 if (conn->child_dev == child)
66 return conn->outport;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070067 }
Pratik Patel0a7edd32012-06-08 09:31:55 -070068
69 pr_err("coresight: couldn't find outport, parent: %d, child: %d\n",
70 csdev->id, child->id);
71 return 0;
72}
73
74static int coresight_enable_sink(struct coresight_device *csdev)
75{
76 int ret;
77
78 if (csdev->refcnt.sink_refcnt == 0) {
79 if (csdev->ops->sink_ops->enable) {
80 ret = csdev->ops->sink_ops->enable(csdev);
81 if (ret)
82 goto err;
83 csdev->enable = true;
84 }
85 }
86 csdev->refcnt.sink_refcnt++;
87
88 return 0;
89err:
90 return ret;
91}
92
93static void coresight_disable_sink(struct coresight_device *csdev)
94{
95 if (csdev->refcnt.sink_refcnt == 1) {
96 if (csdev->ops->sink_ops->disable) {
97 csdev->ops->sink_ops->disable(csdev);
98 csdev->enable = false;
99 }
100 }
101 csdev->refcnt.sink_refcnt--;
102}
103
104static int coresight_enable_link(struct coresight_device *csdev)
105{
106 int ret;
107 int link_subtype;
108 int refport, inport, outport;
109
110 inport = coresight_find_link_inport(csdev);
111 outport = coresight_find_link_outport(csdev);
112
113 link_subtype = csdev->subtype.link_subtype;
114 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
115 refport = inport;
116 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
117 refport = outport;
118 else
119 refport = 0;
120
121 if (csdev->refcnt.link_refcnts[refport] == 0) {
122 if (csdev->ops->link_ops->enable) {
123 ret = csdev->ops->link_ops->enable(csdev, inport,
124 outport);
125 if (ret)
126 goto err;
127 csdev->enable = true;
128 }
129 }
130 csdev->refcnt.link_refcnts[refport]++;
131
132 return 0;
133err:
134 return ret;
135}
136
137static void coresight_disable_link(struct coresight_device *csdev)
138{
139 int link_subtype;
140 int refport, inport, outport;
141
142 inport = coresight_find_link_inport(csdev);
143 outport = coresight_find_link_outport(csdev);
144
145 link_subtype = csdev->subtype.link_subtype;
146 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
147 refport = inport;
148 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
149 refport = outport;
150 else
151 refport = 0;
152
153 if (csdev->refcnt.link_refcnts[refport] == 1) {
154 if (csdev->ops->link_ops->disable) {
155 csdev->ops->link_ops->disable(csdev, inport, outport);
156 csdev->enable = false;
157 }
158 }
159 csdev->refcnt.link_refcnts[refport]--;
160}
161
162static int coresight_enable_source(struct coresight_device *csdev)
163{
164 int ret;
165
166 if (csdev->refcnt.source_refcnt == 0) {
167 if (csdev->ops->source_ops->enable) {
168 ret = csdev->ops->source_ops->enable(csdev);
169 if (ret)
170 goto err;
171 csdev->enable = true;
172 }
173 }
174 csdev->refcnt.source_refcnt++;
175
176 return 0;
177err:
178 return ret;
179}
180
181static void coresight_disable_source(struct coresight_device *csdev)
182{
183 if (csdev->refcnt.source_refcnt == 1) {
184 if (csdev->ops->source_ops->disable) {
185 csdev->ops->source_ops->disable(csdev);
186 csdev->enable = false;
187 }
188 }
189 csdev->refcnt.source_refcnt--;
190}
191
192static struct list_head *coresight_build_path(struct coresight_device *csdev,
193 struct list_head *path)
194{
195 int i;
196 struct list_head *p;
197 struct coresight_connection *conn;
198
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800199 if (!csdev)
200 return NULL;
201
Pratik Patel0a7edd32012-06-08 09:31:55 -0700202 if (csdev->id == curr_sink) {
203 list_add_tail(&csdev->path_link, path);
204 return path;
205 }
206
207 for (i = 0; i < csdev->nr_conns; i++) {
208 conn = &csdev->conns[i];
209 p = coresight_build_path(conn->child_dev, path);
210 if (p) {
211 list_add_tail(&csdev->path_link, p);
212 return p;
213 }
214 }
215 return NULL;
216}
217
218static void coresight_release_path(struct list_head *path)
219{
220 struct coresight_device *cd, *temp;
221
222 list_for_each_entry_safe(cd, temp, path, path_link)
223 list_del(&cd->path_link);
224}
225
226static int coresight_enable_path(struct list_head *path, bool incl_source)
227{
228 int ret = 0;
229 struct coresight_device *cd;
230
231 list_for_each_entry(cd, path, path_link) {
232 if (cd == list_first_entry(path, struct coresight_device,
233 path_link)) {
234 ret = coresight_enable_sink(cd);
235 } else if (list_is_last(&cd->path_link, path)) {
236 if (incl_source)
237 ret = coresight_enable_source(cd);
238 } else {
239 ret = coresight_enable_link(cd);
240 }
241 if (ret)
242 goto err;
243 }
244 return 0;
245err:
246 list_for_each_entry_continue_reverse(cd, path, path_link) {
247 if (cd == list_first_entry(path, struct coresight_device,
248 path_link)) {
249 coresight_disable_sink(cd);
250 } else if (list_is_last(&cd->path_link, path)) {
251 if (incl_source)
252 coresight_disable_source(cd);
253 } else {
254 coresight_disable_link(cd);
255 }
256 }
257 return ret;
258}
259
260static void coresight_disable_path(struct list_head *path, bool incl_source)
261{
262 struct coresight_device *cd;
263
264 list_for_each_entry(cd, path, path_link) {
265 if (cd == list_first_entry(path, struct coresight_device,
266 path_link)) {
267 coresight_disable_sink(cd);
268 } else if (list_is_last(&cd->path_link, path)) {
269 if (incl_source)
270 coresight_disable_source(cd);
271 } else {
272 coresight_disable_link(cd);
273 }
274 }
275}
276
277static int coresight_switch_sink(struct coresight_device *csdev)
278{
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800279 int ret, prev_sink;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700280 LIST_HEAD(path);
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800281 struct coresight_device *cd, *err_cd;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700282
283 if (IS_ERR_OR_NULL(csdev))
284 return -EINVAL;
285
286 down(&coresight_mutex);
287 if (csdev->id == curr_sink)
288 goto out;
289
290 list_for_each_entry(cd, &coresight_devs, dev_link) {
291 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
292 coresight_build_path(cd, &path);
293 coresight_disable_path(&path, false);
294 coresight_release_path(&path);
295 }
296 }
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800297 prev_sink = curr_sink;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700298 curr_sink = csdev->id;
299 list_for_each_entry(cd, &coresight_devs, dev_link) {
300 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800301 if (!coresight_build_path(cd, &path)) {
302 ret = -EINVAL;
303 pr_err("coresight: build path failed\n");
304 goto err;
305 }
Pratik Patel0a7edd32012-06-08 09:31:55 -0700306 ret = coresight_enable_path(&path, false);
307 coresight_release_path(&path);
308 if (ret)
309 goto err;
310 }
311 }
312out:
313 up(&coresight_mutex);
314 return 0;
315err:
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800316 err_cd = cd;
317 list_for_each_entry_continue_reverse(cd, &coresight_devs, dev_link) {
318 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
319 coresight_build_path(cd, &path);
320 coresight_disable_path(&path, true);
321 coresight_release_path(&path);
322 }
323 }
324 cd = err_cd;
325 /* This should be an enabled source, so we can disable it directly */
326 coresight_disable_source(cd);
327 list_for_each_entry_continue(cd, &coresight_devs, dev_link) {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700328 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable)
329 coresight_disable_source(cd);
330 }
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800331 curr_sink = prev_sink;
332 up(&coresight_mutex);
Pratik Patel0a7edd32012-06-08 09:31:55 -0700333 pr_err("coresight: sink switch failed, sources disabled; try again\n");
334 return ret;
335}
336
337int coresight_enable(struct coresight_device *csdev)
338{
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800339 int ret;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700340 LIST_HEAD(path);
341
342 if (IS_ERR_OR_NULL(csdev))
343 return -EINVAL;
344
345 down(&coresight_mutex);
346 if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
347 ret = -EINVAL;
348 pr_err("coresight: wrong device type in %s\n", __func__);
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800349 goto err;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700350 }
351 if (csdev->enable)
352 goto out;
353
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800354 if (!coresight_build_path(csdev, &path)) {
355 ret = -EINVAL;
356 pr_err("coresight: build path failed\n");
357 goto err;
358 }
Pratik Patel0a7edd32012-06-08 09:31:55 -0700359 ret = coresight_enable_path(&path, true);
360 coresight_release_path(&path);
361 if (ret)
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800362 goto err;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700363out:
364 up(&coresight_mutex);
Pratik Patel6a3d1ae2013-01-26 18:55:48 -0800365 return 0;
366err:
367 up(&coresight_mutex);
368 pr_err("coresight: enable failed\n");
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700369 return ret;
370}
Pratik Patel394783a2013-04-22 11:12:14 -0700371EXPORT_SYMBOL(coresight_enable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700372
Pratik Patel0a7edd32012-06-08 09:31:55 -0700373void coresight_disable(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700374{
Pratik Patel0a7edd32012-06-08 09:31:55 -0700375 LIST_HEAD(path);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700376
Pratik Patel0a7edd32012-06-08 09:31:55 -0700377 if (IS_ERR_OR_NULL(csdev))
378 return;
379
380 down(&coresight_mutex);
381 if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
382 pr_err("coresight: wrong device type in %s\n", __func__);
383 goto out;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700384 }
Pratik Patel0a7edd32012-06-08 09:31:55 -0700385 if (!csdev->enable)
386 goto out;
387
388 coresight_build_path(csdev, &path);
389 coresight_disable_path(&path, true);
390 coresight_release_path(&path);
391out:
392 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700393}
Pratik Patel394783a2013-04-22 11:12:14 -0700394EXPORT_SYMBOL(coresight_disable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700395
Pratik Patelcf7d0452012-07-02 13:57:20 -0700396void coresight_abort(void)
397{
398 struct coresight_device *cd;
399
400 if (down_trylock(&coresight_mutex)) {
401 pr_err("coresight: abort could not be processed\n");
402 return;
403 }
404 if (curr_sink == NO_SINK)
405 goto out;
406
407 list_for_each_entry(cd, &coresight_devs, dev_link) {
408 if (cd->id == curr_sink) {
Pratik Patel00474562012-09-26 12:39:29 -0700409 if (cd->enable && cd->ops->sink_ops->abort) {
Pratik Patelcf7d0452012-07-02 13:57:20 -0700410 cd->ops->sink_ops->abort(cd);
Pratik Patel00474562012-09-26 12:39:29 -0700411 cd->enable = false;
412 }
Pratik Patelcf7d0452012-07-02 13:57:20 -0700413 }
414 }
415out:
416 up(&coresight_mutex);
417}
Pratik Patel394783a2013-04-22 11:12:14 -0700418EXPORT_SYMBOL(coresight_abort);
Pratik Patelcf7d0452012-07-02 13:57:20 -0700419
Pratik Patel6fb38342012-06-03 14:51:38 -0700420static ssize_t coresight_show_type(struct device *dev,
421 struct device_attribute *attr, char *buf)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700422{
423 return snprintf(buf, PAGE_SIZE, "%s\n", dev->type->name);
424}
425
Pratik Patel6fb38342012-06-03 14:51:38 -0700426static struct device_attribute coresight_dev_attrs[] = {
427 __ATTR(type, S_IRUGO, coresight_show_type, NULL),
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700428 { },
429};
430
Pratik Patel6fb38342012-06-03 14:51:38 -0700431struct bus_type coresight_bus_type = {
432 .name = "coresight",
433 .dev_attrs = coresight_dev_attrs,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700434};
435
Pratik Patel0a7edd32012-06-08 09:31:55 -0700436static ssize_t coresight_show_curr_sink(struct device *dev,
437 struct device_attribute *attr,
438 char *buf)
439{
440 struct coresight_device *csdev = to_coresight_device(dev);
441
442 return scnprintf(buf, PAGE_SIZE, "%u\n",
443 csdev->id == curr_sink ? 1 : 0);
444}
445
446static ssize_t coresight_store_curr_sink(struct device *dev,
447 struct device_attribute *attr,
448 const char *buf, size_t size)
449{
450 int ret = 0;
451 unsigned long val;
452 struct coresight_device *csdev = to_coresight_device(dev);
453
454 if (sscanf(buf, "%lx", &val) != 1)
455 return -EINVAL;
456
457 if (val)
458 ret = coresight_switch_sink(csdev);
459 else
460 ret = -EINVAL;
461
462 if (ret)
463 return ret;
464 return size;
465}
466static DEVICE_ATTR(curr_sink, S_IRUGO | S_IWUSR, coresight_show_curr_sink,
467 coresight_store_curr_sink);
468
Pratik Patel6fb38342012-06-03 14:51:38 -0700469static ssize_t coresight_show_enable(struct device *dev,
470 struct device_attribute *attr, char *buf)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700471{
Pratik Patel6fb38342012-06-03 14:51:38 -0700472 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700473
474 return scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->enable);
475}
476
Pratik Patel6fb38342012-06-03 14:51:38 -0700477static ssize_t coresight_store_enable(struct device *dev,
478 struct device_attribute *attr,
479 const char *buf, size_t size)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700480{
481 int ret = 0;
482 unsigned long val;
Pratik Patel6fb38342012-06-03 14:51:38 -0700483 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700484
485 if (sscanf(buf, "%lx", &val) != 1)
486 return -EINVAL;
487
488 if (val)
Pratik Patel0a7edd32012-06-08 09:31:55 -0700489 ret = coresight_enable(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700490 else
Pratik Patel0a7edd32012-06-08 09:31:55 -0700491 coresight_disable(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700492
493 if (ret)
494 return ret;
495 return size;
496}
Pratik Patel6fb38342012-06-03 14:51:38 -0700497static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, coresight_show_enable,
498 coresight_store_enable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700499
Pratik Patel0a7edd32012-06-08 09:31:55 -0700500static struct attribute *coresight_attrs_sink[] = {
501 &dev_attr_curr_sink.attr,
502 NULL,
503};
504
505static struct attribute_group coresight_attr_grp_sink = {
506 .attrs = coresight_attrs_sink,
507};
508
509static const struct attribute_group *coresight_attr_grps_sink[] = {
510 &coresight_attr_grp_sink,
511 NULL,
512};
513
514static struct attribute *coresight_attrs_source[] = {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700515 &dev_attr_enable.attr,
516 NULL,
517};
518
Pratik Patel0a7edd32012-06-08 09:31:55 -0700519static struct attribute_group coresight_attr_grp_source = {
520 .attrs = coresight_attrs_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700521};
522
Pratik Patel0a7edd32012-06-08 09:31:55 -0700523static const struct attribute_group *coresight_attr_grps_source[] = {
524 &coresight_attr_grp_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700525 NULL,
526};
527
Pratik Patel0a7edd32012-06-08 09:31:55 -0700528static struct device_type coresight_dev_type[] = {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700529 {
Pratik Patelb8bb4032012-07-22 23:09:11 -0700530 .name = "none",
531 },
532 {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700533 .name = "sink",
534 .groups = coresight_attr_grps_sink,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700535 },
536 {
537 .name = "link",
538 },
539 {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700540 .name = "linksink",
541 .groups = coresight_attr_grps_sink,
542 },
543 {
544 .name = "source",
545 .groups = coresight_attr_grps_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700546 },
547};
548
Pratik Patel6fb38342012-06-03 14:51:38 -0700549static void coresight_device_release(struct device *dev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700550{
Pratik Patel6fb38342012-06-03 14:51:38 -0700551 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700552 kfree(csdev);
553}
554
Pratik Patel6fb38342012-06-03 14:51:38 -0700555static void coresight_fixup_orphan_conns(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700556{
Pratik Patel6fb38342012-06-03 14:51:38 -0700557 struct coresight_connection *conn, *temp;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700558
Pratik Patel6fb38342012-06-03 14:51:38 -0700559 list_for_each_entry_safe(conn, temp, &coresight_orph_conns, link) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700560 if (conn->child_id == csdev->id) {
561 conn->child_dev = csdev;
562 list_del(&conn->link);
563 }
564 }
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700565}
566
Pratik Patel6fb38342012-06-03 14:51:38 -0700567static void coresight_fixup_device_conns(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700568{
569 int i;
Pratik Patel6fb38342012-06-03 14:51:38 -0700570 struct coresight_device *cd;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700571 bool found;
572
573 for (i = 0; i < csdev->nr_conns; i++) {
574 found = false;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700575 list_for_each_entry(cd, &coresight_devs, dev_link) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700576 if (csdev->conns[i].child_id == cd->id) {
577 csdev->conns[i].child_dev = cd;
578 found = true;
579 break;
580 }
581 }
Pratik Patel0a7edd32012-06-08 09:31:55 -0700582 if (!found)
Pratik Patel6fb38342012-06-03 14:51:38 -0700583 list_add_tail(&csdev->conns[i].link,
584 &coresight_orph_conns);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700585 }
586}
587
Pratik Patel6fb38342012-06-03 14:51:38 -0700588struct coresight_device *coresight_register(struct coresight_desc *desc)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700589{
590 int i;
591 int ret;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700592 int link_subtype;
593 int nr_refcnts;
594 int *refcnts = NULL;
Pratik Patel6fb38342012-06-03 14:51:38 -0700595 struct coresight_device *csdev;
596 struct coresight_connection *conns;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700597
Pratik Patela20572b2012-12-02 20:33:50 -0800598 if (IS_ERR_OR_NULL(desc))
599 return ERR_PTR(-EINVAL);
600
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700601 csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
602 if (!csdev) {
603 ret = -ENOMEM;
604 goto err_kzalloc_csdev;
605 }
606
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700607 csdev->id = desc->pdata->id;
608
Pratik Patel0a7edd32012-06-08 09:31:55 -0700609 if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
610 desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
611 link_subtype = desc->subtype.link_subtype;
612 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
613 nr_refcnts = desc->pdata->nr_inports;
614 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
615 nr_refcnts = desc->pdata->nr_outports;
616 else
617 nr_refcnts = 1;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700618
Pratik Patel0a7edd32012-06-08 09:31:55 -0700619 refcnts = kzalloc(sizeof(*refcnts) * nr_refcnts, GFP_KERNEL);
620 if (!refcnts) {
621 ret = -ENOMEM;
622 goto err_kzalloc_refcnts;
623 }
624 csdev->refcnt.link_refcnts = refcnts;
625 }
626
627 csdev->nr_conns = desc->pdata->nr_outports;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700628 conns = kzalloc(sizeof(*conns) * csdev->nr_conns, GFP_KERNEL);
629 if (!conns) {
630 ret = -ENOMEM;
631 goto err_kzalloc_conns;
632 }
633 for (i = 0; i < csdev->nr_conns; i++) {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700634 conns[i].outport = desc->pdata->outports[i];
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700635 conns[i].child_id = desc->pdata->child_ids[i];
636 conns[i].child_port = desc->pdata->child_ports[i];
637 }
638 csdev->conns = conns;
639
Pratik Patel0a7edd32012-06-08 09:31:55 -0700640 csdev->type = desc->type;
641 csdev->subtype = desc->subtype;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700642 csdev->ops = desc->ops;
643 csdev->owner = desc->owner;
644
Pratik Patel6fb38342012-06-03 14:51:38 -0700645 csdev->dev.type = &coresight_dev_type[desc->type];
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700646 csdev->dev.groups = desc->groups;
647 csdev->dev.parent = desc->dev;
Pratik Patel6fb38342012-06-03 14:51:38 -0700648 csdev->dev.bus = &coresight_bus_type;
649 csdev->dev.release = coresight_device_release;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700650 dev_set_name(&csdev->dev, "%s", desc->pdata->name);
651
Pratik Patel0a7edd32012-06-08 09:31:55 -0700652 down(&coresight_mutex);
653 if (desc->pdata->default_sink) {
654 if (curr_sink == NO_SINK) {
655 curr_sink = csdev->id;
656 } else {
657 ret = -EINVAL;
658 goto err_default_sink;
659 }
660 }
661
Pratik Patel6fb38342012-06-03 14:51:38 -0700662 coresight_fixup_device_conns(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700663 ret = device_register(&csdev->dev);
664 if (ret)
665 goto err_dev_reg;
Pratik Patel6fb38342012-06-03 14:51:38 -0700666 coresight_fixup_orphan_conns(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700667
Pratik Patel0a7edd32012-06-08 09:31:55 -0700668 list_add_tail(&csdev->dev_link, &coresight_devs);
669 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700670
671 return csdev;
672err_dev_reg:
673 put_device(&csdev->dev);
Pratik Patel0a7edd32012-06-08 09:31:55 -0700674err_default_sink:
675 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700676 kfree(conns);
677err_kzalloc_conns:
Pratik Patel0a7edd32012-06-08 09:31:55 -0700678 kfree(refcnts);
679err_kzalloc_refcnts:
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700680 kfree(csdev);
681err_kzalloc_csdev:
682 return ERR_PTR(ret);
683}
Pratik Patel394783a2013-04-22 11:12:14 -0700684EXPORT_SYMBOL(coresight_register);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700685
Pratik Patel6fb38342012-06-03 14:51:38 -0700686void coresight_unregister(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700687{
688 if (IS_ERR_OR_NULL(csdev))
689 return;
690
691 if (get_device(&csdev->dev)) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700692 device_unregister(&csdev->dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700693 put_device(&csdev->dev);
694 }
695}
Pratik Patel394783a2013-04-22 11:12:14 -0700696EXPORT_SYMBOL(coresight_unregister);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700697
Pratik Patel6fb38342012-06-03 14:51:38 -0700698static int __init coresight_init(void)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700699{
Pratik Patel6fb38342012-06-03 14:51:38 -0700700 return bus_register(&coresight_bus_type);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700701}
Pratik Patel365b2022013-02-01 16:08:15 -0800702core_initcall(coresight_init);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700703
Pratik Patel6fb38342012-06-03 14:51:38 -0700704static void __exit coresight_exit(void)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700705{
Pratik Patel6fb38342012-06-03 14:51:38 -0700706 bus_unregister(&coresight_bus_type);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700707}
Pratik Patel6fb38342012-06-03 14:51:38 -0700708module_exit(coresight_exit);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700709
710MODULE_LICENSE("GPL v2");