sof-client-probes-ipc4.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. //
  3. // Copyright(c) 2019-2022 Intel Corporation
  4. //
  5. // Author: Jyri Sarha <jyri.sarha@intel.com>
  6. //
  7. #include <sound/soc.h>
  8. #include <sound/sof/ipc4/header.h>
  9. #include <uapi/sound/sof/header.h>
  10. #include "sof-priv.h"
  11. #include "ipc4-priv.h"
  12. #include "sof-client.h"
  13. #include "sof-client-probes.h"
  14. enum sof_ipc4_dma_type {
  15. SOF_IPC4_DMA_HDA_HOST_OUTPUT = 0,
  16. SOF_IPC4_DMA_HDA_HOST_INPUT = 1,
  17. SOF_IPC4_DMA_HDA_LINK_OUTPUT = 8,
  18. SOF_IPC4_DMA_HDA_LINK_INPUT = 9,
  19. SOF_IPC4_DMA_DMIC_LINK_INPUT = 11,
  20. SOF_IPC4_DMA_I2S_LINK_OUTPUT = 12,
  21. SOF_IPC4_DMA_I2S_LINK_INPUT = 13,
  22. };
  23. enum sof_ipc4_probe_runtime_param {
  24. SOF_IPC4_PROBE_INJECTION_DMA = 1,
  25. SOF_IPC4_PROBE_INJECTION_DMA_DETACH,
  26. SOF_IPC4_PROBE_POINTS,
  27. SOF_IPC4_PROBE_POINTS_DISCONNECT,
  28. };
  29. struct sof_ipc4_probe_gtw_cfg {
  30. u32 node_id;
  31. u32 dma_buffer_size;
  32. } __packed __aligned(4);
  33. #define SOF_IPC4_PROBE_NODE_ID_INDEX(x) ((x) & GENMASK(7, 0))
  34. #define SOF_IPC4_PROBE_NODE_ID_TYPE(x) (((x) << 8) & GENMASK(12, 8))
  35. struct sof_ipc4_probe_cfg {
  36. struct sof_ipc4_base_module_cfg base;
  37. struct sof_ipc4_probe_gtw_cfg gtw_cfg;
  38. } __packed __aligned(4);
  39. enum sof_ipc4_probe_type {
  40. SOF_IPC4_PROBE_TYPE_INPUT = 0,
  41. SOF_IPC4_PROBE_TYPE_OUTPUT,
  42. SOF_IPC4_PROBE_TYPE_INTERNAL
  43. };
  44. struct sof_ipc4_probe_point {
  45. u32 point_id;
  46. u32 purpose;
  47. u32 stream_tag;
  48. } __packed __aligned(4);
  49. #define INVALID_PIPELINE_ID 0xFF
  50. /**
  51. * sof_ipc4_probe_get_module_info - Get IPC4 module info for probe module
  52. * @cdev: SOF client device
  53. * @return: Pointer to IPC4 probe module info
  54. *
  55. * Look up the IPC4 probe module info based on the hard coded uuid and
  56. * store the value for the future calls.
  57. */
  58. static struct sof_man4_module *sof_ipc4_probe_get_module_info(struct sof_client_dev *cdev)
  59. {
  60. struct sof_probes_priv *priv = cdev->data;
  61. struct device *dev = &cdev->auxdev.dev;
  62. static const guid_t probe_uuid =
  63. GUID_INIT(0x7CAD0808, 0xAB10, 0xCD23,
  64. 0xEF, 0x45, 0x12, 0xAB, 0x34, 0xCD, 0x56, 0xEF);
  65. if (!priv->ipc_priv) {
  66. struct sof_ipc4_fw_module *fw_module =
  67. sof_client_ipc4_find_module(cdev, &probe_uuid);
  68. if (!fw_module) {
  69. dev_err(dev, "%s: no matching uuid found", __func__);
  70. return NULL;
  71. }
  72. priv->ipc_priv = &fw_module->man4_module_entry;
  73. }
  74. return (struct sof_man4_module *)priv->ipc_priv;
  75. }
  76. /**
  77. * ipc4_probes_init - initialize data probing
  78. * @cdev: SOF client device
  79. * @stream_tag: Extractor stream tag
  80. * @buffer_size: DMA buffer size to set for extractor
  81. * @return: 0 on success, negative error code on error
  82. *
  83. * Host chooses whether extraction is supported or not by providing
  84. * valid stream tag to DSP. Once specified, stream described by that
  85. * tag will be tied to DSP for extraction for the entire lifetime of
  86. * probe.
  87. *
  88. * Probing is initialized only once and each INIT request must be
  89. * matched by DEINIT call.
  90. */
  91. static int ipc4_probes_init(struct sof_client_dev *cdev, u32 stream_tag,
  92. size_t buffer_size)
  93. {
  94. struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
  95. struct sof_ipc4_msg msg;
  96. struct sof_ipc4_probe_cfg cfg;
  97. if (!mentry)
  98. return -ENODEV;
  99. memset(&cfg, '\0', sizeof(cfg));
  100. cfg.gtw_cfg.node_id = SOF_IPC4_PROBE_NODE_ID_INDEX(stream_tag - 1) |
  101. SOF_IPC4_PROBE_NODE_ID_TYPE(SOF_IPC4_DMA_HDA_HOST_INPUT);
  102. cfg.gtw_cfg.dma_buffer_size = buffer_size;
  103. msg.primary = mentry->id;
  104. msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
  105. msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
  106. msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
  107. msg.extension = SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(INVALID_PIPELINE_ID);
  108. msg.extension |= SOF_IPC4_MOD_EXT_CORE_ID(0);
  109. msg.extension |= SOF_IPC4_MOD_EXT_PARAM_SIZE(sizeof(cfg) / sizeof(uint32_t));
  110. msg.data_size = sizeof(cfg);
  111. msg.data_ptr = &cfg;
  112. return sof_client_ipc_tx_message_no_reply(cdev, &msg);
  113. }
  114. /**
  115. * ipc4_probes_deinit - cleanup after data probing
  116. * @cdev: SOF client device
  117. * @return: 0 on success, negative error code on error
  118. *
  119. * Host sends DEINIT request to free previously initialized probe
  120. * on DSP side once it is no longer needed. DEINIT only when there
  121. * are no probes connected and with all injectors detached.
  122. */
  123. static int ipc4_probes_deinit(struct sof_client_dev *cdev)
  124. {
  125. struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
  126. struct sof_ipc4_msg msg;
  127. if (!mentry)
  128. return -ENODEV;
  129. msg.primary = mentry->id;
  130. msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_DELETE_INSTANCE);
  131. msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
  132. msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
  133. msg.extension = SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(INVALID_PIPELINE_ID);
  134. msg.extension |= SOF_IPC4_MOD_EXT_CORE_ID(0);
  135. msg.data_size = 0;
  136. msg.data_ptr = NULL;
  137. return sof_client_ipc_tx_message_no_reply(cdev, &msg);
  138. }
  139. /**
  140. * ipc4_probes_points_info - retrieve list of active probe points
  141. * @cdev: SOF client device
  142. * @desc: Returned list of active probes
  143. * @num_desc: Returned count of active probes
  144. * @return: 0 on success, negative error code on error
  145. *
  146. * Dummy implementation returning empty list of probes.
  147. */
  148. static int ipc4_probes_points_info(struct sof_client_dev *cdev,
  149. struct sof_probe_point_desc **desc,
  150. size_t *num_desc)
  151. {
  152. /* TODO: Firmware side implementation needed first */
  153. *desc = NULL;
  154. *num_desc = 0;
  155. return 0;
  156. }
  157. /**
  158. * ipc4_probes_points_add - connect specified probes
  159. * @cdev: SOF client device
  160. * @desc: List of probe points to connect
  161. * @num_desc: Number of elements in @desc
  162. * @return: 0 on success, negative error code on error
  163. *
  164. * Translates the generic probe point presentation to an IPC4
  165. * message to dynamically connect the provided set of endpoints.
  166. */
  167. static int ipc4_probes_points_add(struct sof_client_dev *cdev,
  168. struct sof_probe_point_desc *desc,
  169. size_t num_desc)
  170. {
  171. struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
  172. struct sof_ipc4_probe_point *points;
  173. struct sof_ipc4_msg msg;
  174. int i, ret;
  175. if (!mentry)
  176. return -ENODEV;
  177. /* The sof_probe_point_desc and sof_ipc4_probe_point structs
  178. * are of same size and even the integers are the same in the
  179. * same order, and similar meaning, but since there is no
  180. * performance issue I wrote the conversion explicitly open for
  181. * future development.
  182. */
  183. points = kcalloc(num_desc, sizeof(*points), GFP_KERNEL);
  184. if (!points)
  185. return -ENOMEM;
  186. for (i = 0; i < num_desc; i++) {
  187. points[i].point_id = desc[i].buffer_id;
  188. points[i].purpose = desc[i].purpose;
  189. points[i].stream_tag = desc[i].stream_tag;
  190. }
  191. msg.primary = mentry->id;
  192. msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
  193. msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
  194. msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_PROBE_POINTS);
  195. msg.data_size = sizeof(*points) * num_desc;
  196. msg.data_ptr = points;
  197. ret = sof_client_ipc_set_get_data(cdev, &msg, true);
  198. kfree(points);
  199. return ret;
  200. }
  201. /**
  202. * ipc4_probes_points_remove - disconnect specified probes
  203. * @cdev: SOF client device
  204. * @buffer_id: List of probe points to disconnect
  205. * @num_buffer_id: Number of elements in @desc
  206. * @return: 0 on success, negative error code on error
  207. *
  208. * Converts the generic buffer_id to IPC4 probe_point_id and remove
  209. * the probe points with an IPC4 for message.
  210. */
  211. static int ipc4_probes_points_remove(struct sof_client_dev *cdev,
  212. unsigned int *buffer_id, size_t num_buffer_id)
  213. {
  214. struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
  215. struct sof_ipc4_msg msg;
  216. u32 *probe_point_ids;
  217. int i, ret;
  218. if (!mentry)
  219. return -ENODEV;
  220. probe_point_ids = kcalloc(num_buffer_id, sizeof(*probe_point_ids),
  221. GFP_KERNEL);
  222. if (!probe_point_ids)
  223. return -ENOMEM;
  224. for (i = 0; i < num_buffer_id; i++)
  225. probe_point_ids[i] = buffer_id[i];
  226. msg.primary = mentry->id;
  227. msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
  228. msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
  229. msg.extension =
  230. SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_PROBE_POINTS_DISCONNECT);
  231. msg.data_size = num_buffer_id * sizeof(*probe_point_ids);
  232. msg.data_ptr = probe_point_ids;
  233. ret = sof_client_ipc_set_get_data(cdev, &msg, true);
  234. kfree(probe_point_ids);
  235. return ret;
  236. }
  237. const struct sof_probes_ipc_ops ipc4_probe_ops = {
  238. .init = ipc4_probes_init,
  239. .deinit = ipc4_probes_deinit,
  240. .points_info = ipc4_probes_points_info,
  241. .points_add = ipc4_probes_points_add,
  242. .points_remove = ipc4_probes_points_remove,
  243. };