coresight.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  2. *
  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. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include <linux/init.h>
  15. #include <linux/types.h>
  16. #include <linux/device.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/io.h>
  19. #include <linux/err.h>
  20. #include <linux/export.h>
  21. #include <linux/slab.h>
  22. #include <linux/semaphore.h>
  23. #include <linux/clk.h>
  24. #include <linux/coresight.h>
  25. #include "coresight-priv.h"
  26. #define NO_SINK (-1)
  27. static int curr_sink = NO_SINK;
  28. static LIST_HEAD(coresight_orph_conns);
  29. static LIST_HEAD(coresight_devs);
  30. static DEFINE_SEMAPHORE(coresight_mutex);
  31. static int coresight_find_link_inport(struct coresight_device *csdev)
  32. {
  33. int i;
  34. struct coresight_device *parent;
  35. struct coresight_connection *conn;
  36. parent = container_of(csdev->path_link.next, struct coresight_device,
  37. path_link);
  38. for (i = 0; i < parent->nr_conns; i++) {
  39. conn = &parent->conns[i];
  40. if (conn->child_dev == csdev)
  41. return conn->child_port;
  42. }
  43. pr_err("coresight: couldn't find inport, parent: %d, child: %d\n",
  44. parent->id, csdev->id);
  45. return 0;
  46. }
  47. static int coresight_find_link_outport(struct coresight_device *csdev)
  48. {
  49. int i;
  50. struct coresight_device *child;
  51. struct coresight_connection *conn;
  52. child = container_of(csdev->path_link.prev, struct coresight_device,
  53. path_link);
  54. for (i = 0; i < csdev->nr_conns; i++) {
  55. conn = &csdev->conns[i];
  56. if (conn->child_dev == child)
  57. return conn->outport;
  58. }
  59. pr_err("coresight: couldn't find outport, parent: %d, child: %d\n",
  60. csdev->id, child->id);
  61. return 0;
  62. }
  63. static int coresight_enable_sink(struct coresight_device *csdev)
  64. {
  65. int ret;
  66. if (csdev->refcnt.sink_refcnt == 0) {
  67. if (csdev->ops->sink_ops->enable) {
  68. ret = csdev->ops->sink_ops->enable(csdev);
  69. if (ret)
  70. goto err;
  71. csdev->enable = true;
  72. }
  73. }
  74. csdev->refcnt.sink_refcnt++;
  75. return 0;
  76. err:
  77. return ret;
  78. }
  79. static void coresight_disable_sink(struct coresight_device *csdev)
  80. {
  81. if (csdev->refcnt.sink_refcnt == 1) {
  82. if (csdev->ops->sink_ops->disable) {
  83. csdev->ops->sink_ops->disable(csdev);
  84. csdev->enable = false;
  85. }
  86. }
  87. csdev->refcnt.sink_refcnt--;
  88. }
  89. static int coresight_enable_link(struct coresight_device *csdev)
  90. {
  91. int ret;
  92. int link_subtype;
  93. int refport, inport, outport;
  94. inport = coresight_find_link_inport(csdev);
  95. outport = coresight_find_link_outport(csdev);
  96. link_subtype = csdev->subtype.link_subtype;
  97. if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
  98. refport = inport;
  99. else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
  100. refport = outport;
  101. else
  102. refport = 0;
  103. if (csdev->refcnt.link_refcnts[refport] == 0) {
  104. if (csdev->ops->link_ops->enable) {
  105. ret = csdev->ops->link_ops->enable(csdev, inport,
  106. outport);
  107. if (ret)
  108. goto err;
  109. csdev->enable = true;
  110. }
  111. }
  112. csdev->refcnt.link_refcnts[refport]++;
  113. return 0;
  114. err:
  115. return ret;
  116. }
  117. static void coresight_disable_link(struct coresight_device *csdev)
  118. {
  119. int link_subtype;
  120. int refport, inport, outport;
  121. inport = coresight_find_link_inport(csdev);
  122. outport = coresight_find_link_outport(csdev);
  123. link_subtype = csdev->subtype.link_subtype;
  124. if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
  125. refport = inport;
  126. else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
  127. refport = outport;
  128. else
  129. refport = 0;
  130. if (csdev->refcnt.link_refcnts[refport] == 1) {
  131. if (csdev->ops->link_ops->disable) {
  132. csdev->ops->link_ops->disable(csdev, inport, outport);
  133. csdev->enable = false;
  134. }
  135. }
  136. csdev->refcnt.link_refcnts[refport]--;
  137. }
  138. static int coresight_enable_source(struct coresight_device *csdev)
  139. {
  140. int ret;
  141. if (csdev->refcnt.source_refcnt == 0) {
  142. if (csdev->ops->source_ops->enable) {
  143. ret = csdev->ops->source_ops->enable(csdev);
  144. if (ret)
  145. goto err;
  146. csdev->enable = true;
  147. }
  148. }
  149. csdev->refcnt.source_refcnt++;
  150. return 0;
  151. err:
  152. return ret;
  153. }
  154. static void coresight_disable_source(struct coresight_device *csdev)
  155. {
  156. if (csdev->refcnt.source_refcnt == 1) {
  157. if (csdev->ops->source_ops->disable) {
  158. csdev->ops->source_ops->disable(csdev);
  159. csdev->enable = false;
  160. }
  161. }
  162. csdev->refcnt.source_refcnt--;
  163. }
  164. static struct list_head *coresight_build_path(struct coresight_device *csdev,
  165. struct list_head *path)
  166. {
  167. int i;
  168. struct list_head *p;
  169. struct coresight_connection *conn;
  170. if (!csdev)
  171. return NULL;
  172. if (csdev->id == curr_sink) {
  173. list_add_tail(&csdev->path_link, path);
  174. return path;
  175. }
  176. for (i = 0; i < csdev->nr_conns; i++) {
  177. conn = &csdev->conns[i];
  178. p = coresight_build_path(conn->child_dev, path);
  179. if (p) {
  180. list_add_tail(&csdev->path_link, p);
  181. return p;
  182. }
  183. }
  184. return NULL;
  185. }
  186. static void coresight_release_path(struct list_head *path)
  187. {
  188. struct coresight_device *cd, *temp;
  189. list_for_each_entry_safe(cd, temp, path, path_link)
  190. list_del(&cd->path_link);
  191. }
  192. static int coresight_enable_path(struct list_head *path, bool incl_source)
  193. {
  194. int ret = 0;
  195. struct coresight_device *cd;
  196. list_for_each_entry(cd, path, path_link) {
  197. if (cd == list_first_entry(path, struct coresight_device,
  198. path_link)) {
  199. ret = coresight_enable_sink(cd);
  200. } else if (list_is_last(&cd->path_link, path)) {
  201. if (incl_source)
  202. ret = coresight_enable_source(cd);
  203. } else {
  204. ret = coresight_enable_link(cd);
  205. }
  206. if (ret)
  207. goto err;
  208. }
  209. return 0;
  210. err:
  211. list_for_each_entry_continue_reverse(cd, path, path_link) {
  212. if (cd == list_first_entry(path, struct coresight_device,
  213. path_link)) {
  214. coresight_disable_sink(cd);
  215. } else if (list_is_last(&cd->path_link, path)) {
  216. if (incl_source)
  217. coresight_disable_source(cd);
  218. } else {
  219. coresight_disable_link(cd);
  220. }
  221. }
  222. return ret;
  223. }
  224. static void coresight_disable_path(struct list_head *path, bool incl_source)
  225. {
  226. struct coresight_device *cd;
  227. list_for_each_entry(cd, path, path_link) {
  228. if (cd == list_first_entry(path, struct coresight_device,
  229. path_link)) {
  230. coresight_disable_sink(cd);
  231. } else if (list_is_last(&cd->path_link, path)) {
  232. if (incl_source)
  233. coresight_disable_source(cd);
  234. } else {
  235. coresight_disable_link(cd);
  236. }
  237. }
  238. }
  239. static int coresight_switch_sink(struct coresight_device *csdev)
  240. {
  241. int ret, prev_sink;
  242. LIST_HEAD(path);
  243. struct coresight_device *cd, *err_cd;
  244. if (IS_ERR_OR_NULL(csdev))
  245. return -EINVAL;
  246. down(&coresight_mutex);
  247. if (csdev->id == curr_sink)
  248. goto out;
  249. list_for_each_entry(cd, &coresight_devs, dev_link) {
  250. if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
  251. coresight_build_path(cd, &path);
  252. coresight_disable_path(&path, false);
  253. coresight_release_path(&path);
  254. }
  255. }
  256. prev_sink = curr_sink;
  257. curr_sink = csdev->id;
  258. list_for_each_entry(cd, &coresight_devs, dev_link) {
  259. if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
  260. if (!coresight_build_path(cd, &path)) {
  261. ret = -EINVAL;
  262. pr_err("coresight: build path failed\n");
  263. goto err;
  264. }
  265. ret = coresight_enable_path(&path, false);
  266. coresight_release_path(&path);
  267. if (ret)
  268. goto err;
  269. }
  270. }
  271. out:
  272. up(&coresight_mutex);
  273. return 0;
  274. err:
  275. err_cd = cd;
  276. list_for_each_entry_continue_reverse(cd, &coresight_devs, dev_link) {
  277. if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
  278. coresight_build_path(cd, &path);
  279. coresight_disable_path(&path, true);
  280. coresight_release_path(&path);
  281. }
  282. }
  283. cd = err_cd;
  284. /* This should be an enabled source, so we can disable it directly */
  285. coresight_disable_source(cd);
  286. list_for_each_entry_continue(cd, &coresight_devs, dev_link) {
  287. if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable)
  288. coresight_disable_source(cd);
  289. }
  290. curr_sink = prev_sink;
  291. up(&coresight_mutex);
  292. pr_err("coresight: sink switch failed, sources disabled; try again\n");
  293. return ret;
  294. }
  295. int coresight_enable(struct coresight_device *csdev)
  296. {
  297. int ret;
  298. LIST_HEAD(path);
  299. if (IS_ERR_OR_NULL(csdev))
  300. return -EINVAL;
  301. down(&coresight_mutex);
  302. if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
  303. ret = -EINVAL;
  304. pr_err("coresight: wrong device type in %s\n", __func__);
  305. goto err;
  306. }
  307. if (csdev->enable)
  308. goto out;
  309. if (!coresight_build_path(csdev, &path)) {
  310. ret = -EINVAL;
  311. pr_err("coresight: build path failed\n");
  312. goto err;
  313. }
  314. ret = coresight_enable_path(&path, true);
  315. coresight_release_path(&path);
  316. if (ret)
  317. goto err;
  318. out:
  319. up(&coresight_mutex);
  320. return 0;
  321. err:
  322. up(&coresight_mutex);
  323. pr_err("coresight: enable failed\n");
  324. return ret;
  325. }
  326. EXPORT_SYMBOL(coresight_enable);
  327. void coresight_disable(struct coresight_device *csdev)
  328. {
  329. LIST_HEAD(path);
  330. if (IS_ERR_OR_NULL(csdev))
  331. return;
  332. down(&coresight_mutex);
  333. if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
  334. pr_err("coresight: wrong device type in %s\n", __func__);
  335. goto out;
  336. }
  337. if (!csdev->enable)
  338. goto out;
  339. coresight_build_path(csdev, &path);
  340. coresight_disable_path(&path, true);
  341. coresight_release_path(&path);
  342. out:
  343. up(&coresight_mutex);
  344. }
  345. EXPORT_SYMBOL(coresight_disable);
  346. void coresight_abort(void)
  347. {
  348. struct coresight_device *cd;
  349. if (down_trylock(&coresight_mutex)) {
  350. pr_err("coresight: abort could not be processed\n");
  351. return;
  352. }
  353. if (curr_sink == NO_SINK)
  354. goto out;
  355. list_for_each_entry(cd, &coresight_devs, dev_link) {
  356. if (cd->id == curr_sink) {
  357. if (cd->enable && cd->ops->sink_ops->abort) {
  358. cd->ops->sink_ops->abort(cd);
  359. cd->enable = false;
  360. }
  361. }
  362. }
  363. out:
  364. up(&coresight_mutex);
  365. }
  366. EXPORT_SYMBOL(coresight_abort);
  367. static ssize_t coresight_show_type(struct device *dev,
  368. struct device_attribute *attr, char *buf)
  369. {
  370. return snprintf(buf, PAGE_SIZE, "%s\n", dev->type->name);
  371. }
  372. static struct device_attribute coresight_dev_attrs[] = {
  373. __ATTR(type, S_IRUGO, coresight_show_type, NULL),
  374. { },
  375. };
  376. struct bus_type coresight_bus_type = {
  377. .name = "coresight",
  378. .dev_attrs = coresight_dev_attrs,
  379. };
  380. static ssize_t coresight_show_curr_sink(struct device *dev,
  381. struct device_attribute *attr,
  382. char *buf)
  383. {
  384. struct coresight_device *csdev = to_coresight_device(dev);
  385. return scnprintf(buf, PAGE_SIZE, "%u\n",
  386. csdev->id == curr_sink ? 1 : 0);
  387. }
  388. static ssize_t coresight_store_curr_sink(struct device *dev,
  389. struct device_attribute *attr,
  390. const char *buf, size_t size)
  391. {
  392. int ret = 0;
  393. unsigned long val;
  394. struct coresight_device *csdev = to_coresight_device(dev);
  395. if (sscanf(buf, "%lx", &val) != 1)
  396. return -EINVAL;
  397. if (val)
  398. ret = coresight_switch_sink(csdev);
  399. else
  400. ret = -EINVAL;
  401. if (ret)
  402. return ret;
  403. return size;
  404. }
  405. static DEVICE_ATTR(curr_sink, S_IRUGO | S_IWUSR, coresight_show_curr_sink,
  406. coresight_store_curr_sink);
  407. static ssize_t coresight_show_enable(struct device *dev,
  408. struct device_attribute *attr, char *buf)
  409. {
  410. struct coresight_device *csdev = to_coresight_device(dev);
  411. return scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->enable);
  412. }
  413. static ssize_t coresight_store_enable(struct device *dev,
  414. struct device_attribute *attr,
  415. const char *buf, size_t size)
  416. {
  417. int ret = 0;
  418. unsigned long val;
  419. struct coresight_device *csdev = to_coresight_device(dev);
  420. if (sscanf(buf, "%lx", &val) != 1)
  421. return -EINVAL;
  422. if (val)
  423. ret = coresight_enable(csdev);
  424. else
  425. coresight_disable(csdev);
  426. if (ret)
  427. return ret;
  428. return size;
  429. }
  430. static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, coresight_show_enable,
  431. coresight_store_enable);
  432. static struct attribute *coresight_attrs_sink[] = {
  433. &dev_attr_curr_sink.attr,
  434. NULL,
  435. };
  436. static struct attribute_group coresight_attr_grp_sink = {
  437. .attrs = coresight_attrs_sink,
  438. };
  439. static const struct attribute_group *coresight_attr_grps_sink[] = {
  440. &coresight_attr_grp_sink,
  441. NULL,
  442. };
  443. static struct attribute *coresight_attrs_source[] = {
  444. &dev_attr_enable.attr,
  445. NULL,
  446. };
  447. static struct attribute_group coresight_attr_grp_source = {
  448. .attrs = coresight_attrs_source,
  449. };
  450. static const struct attribute_group *coresight_attr_grps_source[] = {
  451. &coresight_attr_grp_source,
  452. NULL,
  453. };
  454. static struct device_type coresight_dev_type[] = {
  455. {
  456. .name = "none",
  457. },
  458. {
  459. .name = "sink",
  460. .groups = coresight_attr_grps_sink,
  461. },
  462. {
  463. .name = "link",
  464. },
  465. {
  466. .name = "linksink",
  467. .groups = coresight_attr_grps_sink,
  468. },
  469. {
  470. .name = "source",
  471. .groups = coresight_attr_grps_source,
  472. },
  473. };
  474. static void coresight_device_release(struct device *dev)
  475. {
  476. struct coresight_device *csdev = to_coresight_device(dev);
  477. kfree(csdev);
  478. }
  479. static void coresight_fixup_orphan_conns(struct coresight_device *csdev)
  480. {
  481. struct coresight_connection *conn, *temp;
  482. list_for_each_entry_safe(conn, temp, &coresight_orph_conns, link) {
  483. if (conn->child_id == csdev->id) {
  484. conn->child_dev = csdev;
  485. list_del(&conn->link);
  486. }
  487. }
  488. }
  489. static void coresight_fixup_device_conns(struct coresight_device *csdev)
  490. {
  491. int i;
  492. struct coresight_device *cd;
  493. bool found;
  494. for (i = 0; i < csdev->nr_conns; i++) {
  495. found = false;
  496. list_for_each_entry(cd, &coresight_devs, dev_link) {
  497. if (csdev->conns[i].child_id == cd->id) {
  498. csdev->conns[i].child_dev = cd;
  499. found = true;
  500. break;
  501. }
  502. }
  503. if (!found)
  504. list_add_tail(&csdev->conns[i].link,
  505. &coresight_orph_conns);
  506. }
  507. }
  508. struct coresight_device *coresight_register(struct coresight_desc *desc)
  509. {
  510. int i;
  511. int ret;
  512. int link_subtype;
  513. int nr_refcnts;
  514. int *refcnts = NULL;
  515. struct coresight_device *csdev;
  516. struct coresight_connection *conns;
  517. if (IS_ERR_OR_NULL(desc))
  518. return ERR_PTR(-EINVAL);
  519. csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
  520. if (!csdev) {
  521. ret = -ENOMEM;
  522. goto err_kzalloc_csdev;
  523. }
  524. csdev->id = desc->pdata->id;
  525. if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
  526. desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
  527. link_subtype = desc->subtype.link_subtype;
  528. if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
  529. nr_refcnts = desc->pdata->nr_inports;
  530. else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
  531. nr_refcnts = desc->pdata->nr_outports;
  532. else
  533. nr_refcnts = 1;
  534. refcnts = kzalloc(sizeof(*refcnts) * nr_refcnts, GFP_KERNEL);
  535. if (!refcnts) {
  536. ret = -ENOMEM;
  537. goto err_kzalloc_refcnts;
  538. }
  539. csdev->refcnt.link_refcnts = refcnts;
  540. }
  541. csdev->nr_conns = desc->pdata->nr_outports;
  542. conns = kzalloc(sizeof(*conns) * csdev->nr_conns, GFP_KERNEL);
  543. if (!conns) {
  544. ret = -ENOMEM;
  545. goto err_kzalloc_conns;
  546. }
  547. for (i = 0; i < csdev->nr_conns; i++) {
  548. conns[i].outport = desc->pdata->outports[i];
  549. conns[i].child_id = desc->pdata->child_ids[i];
  550. conns[i].child_port = desc->pdata->child_ports[i];
  551. }
  552. csdev->conns = conns;
  553. csdev->type = desc->type;
  554. csdev->subtype = desc->subtype;
  555. csdev->ops = desc->ops;
  556. csdev->owner = desc->owner;
  557. csdev->dev.type = &coresight_dev_type[desc->type];
  558. csdev->dev.groups = desc->groups;
  559. csdev->dev.parent = desc->dev;
  560. csdev->dev.bus = &coresight_bus_type;
  561. csdev->dev.release = coresight_device_release;
  562. dev_set_name(&csdev->dev, "%s", desc->pdata->name);
  563. down(&coresight_mutex);
  564. if (desc->pdata->default_sink) {
  565. if (curr_sink == NO_SINK) {
  566. curr_sink = csdev->id;
  567. } else {
  568. ret = -EINVAL;
  569. goto err_default_sink;
  570. }
  571. }
  572. coresight_fixup_device_conns(csdev);
  573. ret = device_register(&csdev->dev);
  574. if (ret)
  575. goto err_dev_reg;
  576. coresight_fixup_orphan_conns(csdev);
  577. list_add_tail(&csdev->dev_link, &coresight_devs);
  578. up(&coresight_mutex);
  579. return csdev;
  580. err_dev_reg:
  581. put_device(&csdev->dev);
  582. err_default_sink:
  583. up(&coresight_mutex);
  584. kfree(conns);
  585. err_kzalloc_conns:
  586. kfree(refcnts);
  587. err_kzalloc_refcnts:
  588. kfree(csdev);
  589. err_kzalloc_csdev:
  590. return ERR_PTR(ret);
  591. }
  592. EXPORT_SYMBOL(coresight_register);
  593. void coresight_unregister(struct coresight_device *csdev)
  594. {
  595. if (IS_ERR_OR_NULL(csdev))
  596. return;
  597. if (get_device(&csdev->dev)) {
  598. device_unregister(&csdev->dev);
  599. put_device(&csdev->dev);
  600. }
  601. }
  602. EXPORT_SYMBOL(coresight_unregister);
  603. static int __init coresight_init(void)
  604. {
  605. return bus_register(&coresight_bus_type);
  606. }
  607. core_initcall(coresight_init);
  608. static void __exit coresight_exit(void)
  609. {
  610. bus_unregister(&coresight_bus_type);
  611. }
  612. module_exit(coresight_exit);
  613. MODULE_LICENSE("GPL v2");