probe.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
  2. //
  3. // This file is provided under a dual BSD/GPLv2 license. When using or
  4. // redistributing this file, you may do so under either license.
  5. //
  6. // Copyright(c) 2019-2020 Intel Corporation. All rights reserved.
  7. //
  8. // Author: Cezary Rojewski <cezary.rojewski@intel.com>
  9. //
  10. #include "sof-priv.h"
  11. #include "probe.h"
  12. /**
  13. * sof_ipc_probe_init - initialize data probing
  14. * @sdev: SOF sound device
  15. * @stream_tag: Extractor stream tag
  16. * @buffer_size: DMA buffer size to set for extractor
  17. *
  18. * Host chooses whether extraction is supported or not by providing
  19. * valid stream tag to DSP. Once specified, stream described by that
  20. * tag will be tied to DSP for extraction for the entire lifetime of
  21. * probe.
  22. *
  23. * Probing is initialized only once and each INIT request must be
  24. * matched by DEINIT call.
  25. */
  26. int sof_ipc_probe_init(struct snd_sof_dev *sdev,
  27. u32 stream_tag, size_t buffer_size)
  28. {
  29. struct sof_ipc_probe_dma_add_params *msg;
  30. struct sof_ipc_reply reply;
  31. size_t size = struct_size(msg, dma, 1);
  32. int ret;
  33. msg = kmalloc(size, GFP_KERNEL);
  34. if (!msg)
  35. return -ENOMEM;
  36. msg->hdr.size = size;
  37. msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT;
  38. msg->num_elems = 1;
  39. msg->dma[0].stream_tag = stream_tag;
  40. msg->dma[0].dma_buffer_size = buffer_size;
  41. ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
  42. &reply, sizeof(reply));
  43. kfree(msg);
  44. return ret;
  45. }
  46. EXPORT_SYMBOL(sof_ipc_probe_init);
  47. /**
  48. * sof_ipc_probe_deinit - cleanup after data probing
  49. * @sdev: SOF sound device
  50. *
  51. * Host sends DEINIT request to free previously initialized probe
  52. * on DSP side once it is no longer needed. DEINIT only when there
  53. * are no probes connected and with all injectors detached.
  54. */
  55. int sof_ipc_probe_deinit(struct snd_sof_dev *sdev)
  56. {
  57. struct sof_ipc_cmd_hdr msg;
  58. struct sof_ipc_reply reply;
  59. msg.size = sizeof(msg);
  60. msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT;
  61. return sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size,
  62. &reply, sizeof(reply));
  63. }
  64. EXPORT_SYMBOL(sof_ipc_probe_deinit);
  65. static int sof_ipc_probe_info(struct snd_sof_dev *sdev, unsigned int cmd,
  66. void **params, size_t *num_params)
  67. {
  68. struct sof_ipc_probe_info_params msg = {{{0}}};
  69. struct sof_ipc_probe_info_params *reply;
  70. size_t bytes;
  71. int ret;
  72. *params = NULL;
  73. *num_params = 0;
  74. reply = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
  75. if (!reply)
  76. return -ENOMEM;
  77. msg.rhdr.hdr.size = sizeof(msg);
  78. msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd;
  79. ret = sof_ipc_tx_message(sdev->ipc, msg.rhdr.hdr.cmd, &msg,
  80. msg.rhdr.hdr.size, reply, SOF_IPC_MSG_MAX_SIZE);
  81. if (ret < 0 || reply->rhdr.error < 0)
  82. goto exit;
  83. if (!reply->num_elems)
  84. goto exit;
  85. if (cmd == SOF_IPC_PROBE_DMA_INFO)
  86. bytes = sizeof(reply->dma[0]);
  87. else
  88. bytes = sizeof(reply->desc[0]);
  89. bytes *= reply->num_elems;
  90. *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL);
  91. if (!*params) {
  92. ret = -ENOMEM;
  93. goto exit;
  94. }
  95. *num_params = reply->num_elems;
  96. exit:
  97. kfree(reply);
  98. return ret;
  99. }
  100. /**
  101. * sof_ipc_probe_dma_info - retrieve list of active injection dmas
  102. * @sdev: SOF sound device
  103. * @dma: Returned list of active dmas
  104. * @num_dma: Returned count of active dmas
  105. *
  106. * Host sends DMA_INFO request to obtain list of injection dmas it
  107. * can use to transfer data over with.
  108. *
  109. * Note that list contains only injection dmas as there is only one
  110. * extractor (dma) and it is always assigned on probing init.
  111. * DSP knows exactly where data from extraction probes is going to,
  112. * which is not the case for injection where multiple streams
  113. * could be engaged.
  114. */
  115. int sof_ipc_probe_dma_info(struct snd_sof_dev *sdev,
  116. struct sof_probe_dma **dma, size_t *num_dma)
  117. {
  118. return sof_ipc_probe_info(sdev, SOF_IPC_PROBE_DMA_INFO,
  119. (void **)dma, num_dma);
  120. }
  121. EXPORT_SYMBOL(sof_ipc_probe_dma_info);
  122. /**
  123. * sof_ipc_probe_dma_add - attach to specified dmas
  124. * @sdev: SOF sound device
  125. * @dma: List of streams (dmas) to attach to
  126. * @num_dma: Number of elements in @dma
  127. *
  128. * Contrary to extraction, injection streams are never assigned
  129. * on init. Before attempting any data injection, host is responsible
  130. * for specifying streams which will be later used to transfer data
  131. * to connected probe points.
  132. */
  133. int sof_ipc_probe_dma_add(struct snd_sof_dev *sdev,
  134. struct sof_probe_dma *dma, size_t num_dma)
  135. {
  136. struct sof_ipc_probe_dma_add_params *msg;
  137. struct sof_ipc_reply reply;
  138. size_t size = struct_size(msg, dma, num_dma);
  139. int ret;
  140. msg = kmalloc(size, GFP_KERNEL);
  141. if (!msg)
  142. return -ENOMEM;
  143. msg->hdr.size = size;
  144. msg->num_elems = num_dma;
  145. msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DMA_ADD;
  146. memcpy(&msg->dma[0], dma, size - sizeof(*msg));
  147. ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
  148. &reply, sizeof(reply));
  149. kfree(msg);
  150. return ret;
  151. }
  152. EXPORT_SYMBOL(sof_ipc_probe_dma_add);
  153. /**
  154. * sof_ipc_probe_dma_remove - detach from specified dmas
  155. * @sdev: SOF sound device
  156. * @stream_tag: List of stream tags to detach from
  157. * @num_stream_tag: Number of elements in @stream_tag
  158. *
  159. * Host sends DMA_REMOVE request to free previously attached stream
  160. * from being occupied for injection. Each detach operation should
  161. * match equivalent DMA_ADD. Detach only when all probes tied to
  162. * given stream have been disconnected.
  163. */
  164. int sof_ipc_probe_dma_remove(struct snd_sof_dev *sdev,
  165. unsigned int *stream_tag, size_t num_stream_tag)
  166. {
  167. struct sof_ipc_probe_dma_remove_params *msg;
  168. struct sof_ipc_reply reply;
  169. size_t size = struct_size(msg, stream_tag, num_stream_tag);
  170. int ret;
  171. msg = kmalloc(size, GFP_KERNEL);
  172. if (!msg)
  173. return -ENOMEM;
  174. msg->hdr.size = size;
  175. msg->num_elems = num_stream_tag;
  176. msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DMA_REMOVE;
  177. memcpy(&msg->stream_tag[0], stream_tag, size - sizeof(*msg));
  178. ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
  179. &reply, sizeof(reply));
  180. kfree(msg);
  181. return ret;
  182. }
  183. EXPORT_SYMBOL(sof_ipc_probe_dma_remove);
  184. /**
  185. * sof_ipc_probe_points_info - retrieve list of active probe points
  186. * @sdev: SOF sound device
  187. * @desc: Returned list of active probes
  188. * @num_desc: Returned count of active probes
  189. *
  190. * Host sends PROBE_POINT_INFO request to obtain list of active probe
  191. * points, valid for disconnection when given probe is no longer
  192. * required.
  193. */
  194. int sof_ipc_probe_points_info(struct snd_sof_dev *sdev,
  195. struct sof_probe_point_desc **desc, size_t *num_desc)
  196. {
  197. return sof_ipc_probe_info(sdev, SOF_IPC_PROBE_POINT_INFO,
  198. (void **)desc, num_desc);
  199. }
  200. EXPORT_SYMBOL(sof_ipc_probe_points_info);
  201. /**
  202. * sof_ipc_probe_points_add - connect specified probes
  203. * @sdev: SOF sound device
  204. * @desc: List of probe points to connect
  205. * @num_desc: Number of elements in @desc
  206. *
  207. * Dynamically connects to provided set of endpoints. Immediately
  208. * after connection is established, host must be prepared to
  209. * transfer data from or to target stream given the probing purpose.
  210. *
  211. * Each probe point should be removed using PROBE_POINT_REMOVE
  212. * request when no longer needed.
  213. */
  214. int sof_ipc_probe_points_add(struct snd_sof_dev *sdev,
  215. struct sof_probe_point_desc *desc, size_t num_desc)
  216. {
  217. struct sof_ipc_probe_point_add_params *msg;
  218. struct sof_ipc_reply reply;
  219. size_t size = struct_size(msg, desc, num_desc);
  220. int ret;
  221. msg = kmalloc(size, GFP_KERNEL);
  222. if (!msg)
  223. return -ENOMEM;
  224. msg->hdr.size = size;
  225. msg->num_elems = num_desc;
  226. msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD;
  227. memcpy(&msg->desc[0], desc, size - sizeof(*msg));
  228. ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
  229. &reply, sizeof(reply));
  230. kfree(msg);
  231. return ret;
  232. }
  233. EXPORT_SYMBOL(sof_ipc_probe_points_add);
  234. /**
  235. * sof_ipc_probe_points_remove - disconnect specified probes
  236. * @sdev: SOF sound device
  237. * @buffer_id: List of probe points to disconnect
  238. * @num_buffer_id: Number of elements in @desc
  239. *
  240. * Removes previously connected probes from list of active probe
  241. * points and frees all resources on DSP side.
  242. */
  243. int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev,
  244. unsigned int *buffer_id, size_t num_buffer_id)
  245. {
  246. struct sof_ipc_probe_point_remove_params *msg;
  247. struct sof_ipc_reply reply;
  248. size_t size = struct_size(msg, buffer_id, num_buffer_id);
  249. int ret;
  250. msg = kmalloc(size, GFP_KERNEL);
  251. if (!msg)
  252. return -ENOMEM;
  253. msg->hdr.size = size;
  254. msg->num_elems = num_buffer_id;
  255. msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE;
  256. memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg));
  257. ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size,
  258. &reply, sizeof(reply));
  259. kfree(msg);
  260. return ret;
  261. }
  262. EXPORT_SYMBOL(sof_ipc_probe_points_remove);