coresight-remote-etm.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /* Copyright (c) 2013-2017, 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/sysfs.h>
  21. #include <linux/mutex.h>
  22. #include <linux/of.h>
  23. #include <linux/coresight.h>
  24. #include "coresight-qmi.h"
  25. #define REMOTE_ETM_TRACE_ID_START 192
  26. #ifdef CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE
  27. static int boot_enable = CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE;
  28. #else
  29. static int boot_enable;
  30. #endif
  31. module_param_named(
  32. boot_enable, boot_enable, int, 0444
  33. );
  34. struct remote_etm_drvdata {
  35. struct device *dev;
  36. struct coresight_device *csdev;
  37. struct mutex mutex;
  38. struct workqueue_struct *wq;
  39. struct qmi_handle *handle;
  40. struct work_struct work_svc_arrive;
  41. struct work_struct work_svc_exit;
  42. struct work_struct work_rcv_msg;
  43. struct notifier_block nb;
  44. uint32_t inst_id;
  45. struct delayed_work work_delay_enable;
  46. bool enable;
  47. int traceid;
  48. };
  49. static int remote_etm_enable(struct coresight_device *csdev,
  50. struct perf_event *event, u32 mode)
  51. {
  52. struct remote_etm_drvdata *drvdata =
  53. dev_get_drvdata(csdev->dev.parent);
  54. struct coresight_set_etm_req_msg_v01 req;
  55. struct coresight_set_etm_resp_msg_v01 resp = { { 0, 0 } };
  56. struct msg_desc req_desc, resp_desc;
  57. int ret;
  58. mutex_lock(&drvdata->mutex);
  59. /*
  60. * The QMI handle may be NULL in the following scenarios:
  61. * 1. QMI service is not present
  62. * 2. QMI service is present but attempt to enable remote ETM is earlier
  63. * than service is ready to handle request
  64. * 3. Connection between QMI client and QMI service failed
  65. *
  66. * Enable CoreSight without processing further QMI commands which
  67. * provides the option to enable remote ETM by other means.
  68. */
  69. if (!drvdata->handle) {
  70. dev_info(drvdata->dev,
  71. "%s: QMI service unavailable\n", __func__);
  72. ret = -EINVAL;
  73. goto err;
  74. }
  75. req.state = CORESIGHT_ETM_STATE_ENABLED_V01;
  76. req_desc.msg_id = CORESIGHT_QMI_SET_ETM_REQ_V01;
  77. req_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN;
  78. req_desc.ei_array = coresight_set_etm_req_msg_v01_ei;
  79. resp_desc.msg_id = CORESIGHT_QMI_SET_ETM_RESP_V01;
  80. resp_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN;
  81. resp_desc.ei_array = coresight_set_etm_resp_msg_v01_ei;
  82. ret = qmi_send_req_wait(drvdata->handle, &req_desc, &req, sizeof(req),
  83. &resp_desc, &resp, sizeof(resp), TIMEOUT_MS);
  84. if (ret < 0) {
  85. dev_err(drvdata->dev, "%s: QMI send req failed %d\n", __func__,
  86. ret);
  87. goto err;
  88. }
  89. if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
  90. dev_err(drvdata->dev, "%s: QMI request failed %d %d\n",
  91. __func__, resp.resp.result, resp.resp.error);
  92. ret = -EREMOTEIO;
  93. goto err;
  94. }
  95. drvdata->enable = true;
  96. mutex_unlock(&drvdata->mutex);
  97. dev_info(drvdata->dev, "Remote ETM tracing enabled\n");
  98. return 0;
  99. err:
  100. mutex_unlock(&drvdata->mutex);
  101. return ret;
  102. }
  103. static void remote_etm_disable(struct coresight_device *csdev,
  104. struct perf_event *event)
  105. {
  106. struct remote_etm_drvdata *drvdata =
  107. dev_get_drvdata(csdev->dev.parent);
  108. struct coresight_set_etm_req_msg_v01 req;
  109. struct coresight_set_etm_resp_msg_v01 resp = { { 0, 0 } };
  110. struct msg_desc req_desc, resp_desc;
  111. int ret;
  112. mutex_lock(&drvdata->mutex);
  113. if (!drvdata->handle) {
  114. dev_info(drvdata->dev,
  115. "%s: QMI service unavailable\n", __func__);
  116. goto err;
  117. }
  118. req.state = CORESIGHT_ETM_STATE_DISABLED_V01;
  119. req_desc.msg_id = CORESIGHT_QMI_SET_ETM_REQ_V01;
  120. req_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_REQ_MAX_LEN;
  121. req_desc.ei_array = coresight_set_etm_req_msg_v01_ei;
  122. resp_desc.msg_id = CORESIGHT_QMI_SET_ETM_RESP_V01;
  123. resp_desc.max_msg_len = CORESIGHT_QMI_SET_ETM_RESP_MAX_LEN;
  124. resp_desc.ei_array = coresight_set_etm_resp_msg_v01_ei;
  125. ret = qmi_send_req_wait(drvdata->handle, &req_desc, &req, sizeof(req),
  126. &resp_desc, &resp, sizeof(resp), TIMEOUT_MS);
  127. if (ret < 0) {
  128. dev_err(drvdata->dev, "%s: QMI send req failed %d\n", __func__,
  129. ret);
  130. goto err;
  131. }
  132. if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
  133. dev_err(drvdata->dev, "%s: QMI request failed %d %d\n",
  134. __func__, resp.resp.result, resp.resp.error);
  135. goto err;
  136. }
  137. drvdata->enable = false;
  138. mutex_unlock(&drvdata->mutex);
  139. dev_info(drvdata->dev, "Remote ETM tracing disabled\n");
  140. return;
  141. err:
  142. mutex_unlock(&drvdata->mutex);
  143. }
  144. static int remote_etm_trace_id(struct coresight_device *csdev)
  145. {
  146. struct remote_etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
  147. return drvdata->traceid;
  148. }
  149. static const struct coresight_ops_source remote_etm_source_ops = {
  150. .trace_id = remote_etm_trace_id,
  151. .enable = remote_etm_enable,
  152. .disable = remote_etm_disable,
  153. };
  154. static const struct coresight_ops remote_cs_ops = {
  155. .source_ops = &remote_etm_source_ops,
  156. };
  157. static void remote_etm_rcv_msg(struct work_struct *work)
  158. {
  159. struct remote_etm_drvdata *drvdata = container_of(work,
  160. struct remote_etm_drvdata,
  161. work_rcv_msg);
  162. if (qmi_recv_msg(drvdata->handle) < 0)
  163. dev_err(drvdata->dev, "%s: Error receiving QMI message\n",
  164. __func__);
  165. }
  166. static void remote_etm_notify(struct qmi_handle *handle,
  167. enum qmi_event_type event, void *notify_priv)
  168. {
  169. struct remote_etm_drvdata *drvdata =
  170. (struct remote_etm_drvdata *)notify_priv;
  171. switch (event) {
  172. case QMI_RECV_MSG:
  173. queue_work(drvdata->wq, &drvdata->work_rcv_msg);
  174. break;
  175. default:
  176. break;
  177. }
  178. }
  179. static void remote_delay_enable_handler(struct work_struct *work)
  180. {
  181. struct remote_etm_drvdata *drvdata = container_of(work,
  182. struct remote_etm_drvdata,
  183. work_delay_enable.work);
  184. coresight_enable(drvdata->csdev);
  185. }
  186. static void remote_etm_svc_arrive(struct work_struct *work)
  187. {
  188. struct remote_etm_drvdata *drvdata = container_of(work,
  189. struct remote_etm_drvdata,
  190. work_svc_arrive);
  191. drvdata->handle = qmi_handle_create(remote_etm_notify, drvdata);
  192. if (!drvdata->handle) {
  193. dev_err(drvdata->dev, "%s: QMI client handle alloc failed\n",
  194. __func__);
  195. return;
  196. }
  197. if (qmi_connect_to_service(drvdata->handle, CORESIGHT_QMI_SVC_ID,
  198. CORESIGHT_QMI_VERSION,
  199. drvdata->inst_id) < 0) {
  200. dev_err(drvdata->dev,
  201. "%s: Could not connect handle to service\n", __func__);
  202. qmi_handle_destroy(drvdata->handle);
  203. drvdata->handle = NULL;
  204. }
  205. mutex_lock(&drvdata->mutex);
  206. if (drvdata->inst_id < sizeof(int)*BITS_PER_BYTE
  207. && (boot_enable & BIT(drvdata->inst_id))) {
  208. if (!drvdata->enable)
  209. schedule_delayed_work(&drvdata->work_delay_enable,
  210. msecs_to_jiffies(TIMEOUT_MS));
  211. }
  212. mutex_unlock(&drvdata->mutex);
  213. }
  214. static void remote_etm_svc_exit(struct work_struct *work)
  215. {
  216. struct remote_etm_drvdata *drvdata = container_of(work,
  217. struct remote_etm_drvdata,
  218. work_svc_exit);
  219. qmi_handle_destroy(drvdata->handle);
  220. drvdata->handle = NULL;
  221. }
  222. static int remote_etm_svc_event_notify(struct notifier_block *this,
  223. unsigned long event,
  224. void *data)
  225. {
  226. struct remote_etm_drvdata *drvdata = container_of(this,
  227. struct remote_etm_drvdata,
  228. nb);
  229. switch (event) {
  230. case QMI_SERVER_ARRIVE:
  231. queue_work(drvdata->wq, &drvdata->work_svc_arrive);
  232. break;
  233. case QMI_SERVER_EXIT:
  234. queue_work(drvdata->wq, &drvdata->work_svc_exit);
  235. break;
  236. default:
  237. break;
  238. }
  239. return 0;
  240. }
  241. static int remote_etm_probe(struct platform_device *pdev)
  242. {
  243. struct device *dev = &pdev->dev;
  244. struct coresight_platform_data *pdata;
  245. struct remote_etm_drvdata *drvdata;
  246. struct coresight_desc *desc;
  247. int ret;
  248. static int traceid = REMOTE_ETM_TRACE_ID_START;
  249. pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
  250. if (IS_ERR(pdata))
  251. return PTR_ERR(pdata);
  252. pdev->dev.platform_data = pdata;
  253. drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
  254. if (!drvdata)
  255. return -ENOMEM;
  256. drvdata->dev = &pdev->dev;
  257. platform_set_drvdata(pdev, drvdata);
  258. desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
  259. if (!desc)
  260. return -ENOMEM;
  261. ret = of_property_read_u32(pdev->dev.of_node, "qcom,inst-id",
  262. &drvdata->inst_id);
  263. if (ret)
  264. return ret;
  265. mutex_init(&drvdata->mutex);
  266. drvdata->nb.notifier_call = remote_etm_svc_event_notify;
  267. drvdata->wq = create_singlethread_workqueue(dev_name(dev));
  268. if (!drvdata->wq)
  269. return -EFAULT;
  270. INIT_WORK(&drvdata->work_svc_arrive, remote_etm_svc_arrive);
  271. INIT_WORK(&drvdata->work_svc_exit, remote_etm_svc_exit);
  272. INIT_WORK(&drvdata->work_rcv_msg, remote_etm_rcv_msg);
  273. INIT_DELAYED_WORK(&drvdata->work_delay_enable,
  274. remote_delay_enable_handler);
  275. ret = qmi_svc_event_notifier_register(CORESIGHT_QMI_SVC_ID,
  276. CORESIGHT_QMI_VERSION,
  277. drvdata->inst_id,
  278. &drvdata->nb);
  279. if (ret < 0)
  280. goto err0;
  281. drvdata->traceid = traceid++;
  282. desc->type = CORESIGHT_DEV_TYPE_SOURCE;
  283. desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
  284. desc->ops = &remote_cs_ops;
  285. desc->pdata = pdev->dev.platform_data;
  286. desc->dev = &pdev->dev;
  287. drvdata->csdev = coresight_register(desc);
  288. if (IS_ERR(drvdata->csdev)) {
  289. ret = PTR_ERR(drvdata->csdev);
  290. goto err1;
  291. }
  292. dev_info(dev, "Remote ETM initialized\n");
  293. if (drvdata->inst_id >= sizeof(int)*BITS_PER_BYTE)
  294. dev_err(dev, "inst_id greater than boot_enable bit mask\n");
  295. else if (boot_enable & BIT(drvdata->inst_id))
  296. coresight_enable(drvdata->csdev);
  297. return 0;
  298. err1:
  299. qmi_svc_event_notifier_unregister(CORESIGHT_QMI_SVC_ID,
  300. CORESIGHT_QMI_VERSION,
  301. drvdata->inst_id,
  302. &drvdata->nb);
  303. err0:
  304. destroy_workqueue(drvdata->wq);
  305. return ret;
  306. }
  307. static int remote_etm_remove(struct platform_device *pdev)
  308. {
  309. struct remote_etm_drvdata *drvdata = platform_get_drvdata(pdev);
  310. coresight_unregister(drvdata->csdev);
  311. return 0;
  312. }
  313. static const struct of_device_id remote_etm_match[] = {
  314. {.compatible = "qcom,coresight-remote-etm"},
  315. {}
  316. };
  317. static struct platform_driver remote_etm_driver = {
  318. .probe = remote_etm_probe,
  319. .remove = remote_etm_remove,
  320. .driver = {
  321. .name = "coresight-remote-etm",
  322. .owner = THIS_MODULE,
  323. .of_match_table = remote_etm_match,
  324. },
  325. };
  326. int __init remote_etm_init(void)
  327. {
  328. return platform_driver_register(&remote_etm_driver);
  329. }
  330. module_init(remote_etm_init);
  331. void __exit remote_etm_exit(void)
  332. {
  333. platform_driver_unregister(&remote_etm_driver);
  334. }
  335. module_exit(remote_etm_exit);
  336. MODULE_LICENSE("GPL v2");
  337. MODULE_DESCRIPTION("CoreSight Remote ETM driver");