sof-client-probes.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. //
  3. // Copyright(c) 2019-2022 Intel Corporation. All rights reserved.
  4. //
  5. // Author: Cezary Rojewski <[email protected]>
  6. //
  7. // SOF client support:
  8. // Ranjani Sridharan <[email protected]>
  9. // Peter Ujfalusi <[email protected]>
  10. //
  11. #include <linux/debugfs.h>
  12. #include <linux/module.h>
  13. #include <linux/pm_runtime.h>
  14. #include <linux/string_helpers.h>
  15. #include <sound/soc.h>
  16. #include <sound/sof/header.h>
  17. #include "sof-client.h"
  18. #include "sof-client-probes.h"
  19. #define SOF_PROBES_SUSPEND_DELAY_MS 3000
  20. /* only extraction supported for now */
  21. #define SOF_PROBES_NUM_DAI_LINKS 1
  22. #define SOF_PROBES_INVALID_NODE_ID UINT_MAX
  23. static bool __read_mostly sof_probes_enabled;
  24. module_param_named(enable, sof_probes_enabled, bool, 0444);
  25. MODULE_PARM_DESC(enable, "Enable SOF probes support");
  26. struct sof_probes_priv {
  27. struct dentry *dfs_points;
  28. struct dentry *dfs_points_remove;
  29. u32 extractor_stream_tag;
  30. struct snd_soc_card card;
  31. const struct sof_probes_host_ops *host_ops;
  32. };
  33. struct sof_probe_point_desc {
  34. unsigned int buffer_id;
  35. unsigned int purpose;
  36. unsigned int stream_tag;
  37. } __packed;
  38. struct sof_probe_dma {
  39. unsigned int stream_tag;
  40. unsigned int dma_buffer_size;
  41. } __packed;
  42. struct sof_ipc_probe_dma_add_params {
  43. struct sof_ipc_cmd_hdr hdr;
  44. unsigned int num_elems;
  45. struct sof_probe_dma dma[];
  46. } __packed;
  47. struct sof_ipc_probe_info_params {
  48. struct sof_ipc_reply rhdr;
  49. unsigned int num_elems;
  50. union {
  51. struct sof_probe_dma dma[0];
  52. struct sof_probe_point_desc desc[0];
  53. };
  54. } __packed;
  55. struct sof_ipc_probe_point_add_params {
  56. struct sof_ipc_cmd_hdr hdr;
  57. unsigned int num_elems;
  58. struct sof_probe_point_desc desc[];
  59. } __packed;
  60. struct sof_ipc_probe_point_remove_params {
  61. struct sof_ipc_cmd_hdr hdr;
  62. unsigned int num_elems;
  63. unsigned int buffer_id[];
  64. } __packed;
  65. /**
  66. * sof_probes_init - initialize data probing
  67. * @cdev: SOF client device
  68. * @stream_tag: Extractor stream tag
  69. * @buffer_size: DMA buffer size to set for extractor
  70. *
  71. * Host chooses whether extraction is supported or not by providing
  72. * valid stream tag to DSP. Once specified, stream described by that
  73. * tag will be tied to DSP for extraction for the entire lifetime of
  74. * probe.
  75. *
  76. * Probing is initialized only once and each INIT request must be
  77. * matched by DEINIT call.
  78. */
  79. static int sof_probes_init(struct sof_client_dev *cdev, u32 stream_tag,
  80. size_t buffer_size)
  81. {
  82. struct sof_ipc_probe_dma_add_params *msg;
  83. size_t size = struct_size(msg, dma, 1);
  84. struct sof_ipc_reply reply;
  85. int ret;
  86. msg = kmalloc(size, GFP_KERNEL);
  87. if (!msg)
  88. return -ENOMEM;
  89. msg->hdr.size = size;
  90. msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT;
  91. msg->num_elems = 1;
  92. msg->dma[0].stream_tag = stream_tag;
  93. msg->dma[0].dma_buffer_size = buffer_size;
  94. ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
  95. kfree(msg);
  96. return ret;
  97. }
  98. /**
  99. * sof_probes_deinit - cleanup after data probing
  100. * @cdev: SOF client device
  101. *
  102. * Host sends DEINIT request to free previously initialized probe
  103. * on DSP side once it is no longer needed. DEINIT only when there
  104. * are no probes connected and with all injectors detached.
  105. */
  106. static int sof_probes_deinit(struct sof_client_dev *cdev)
  107. {
  108. struct sof_ipc_cmd_hdr msg;
  109. struct sof_ipc_reply reply;
  110. msg.size = sizeof(msg);
  111. msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT;
  112. return sof_client_ipc_tx_message(cdev, &msg, &reply, sizeof(reply));
  113. }
  114. static int sof_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
  115. void **params, size_t *num_params)
  116. {
  117. size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev);
  118. struct sof_ipc_probe_info_params msg = {{{0}}};
  119. struct sof_ipc_probe_info_params *reply;
  120. size_t bytes;
  121. int ret;
  122. *params = NULL;
  123. *num_params = 0;
  124. reply = kzalloc(max_msg_size, GFP_KERNEL);
  125. if (!reply)
  126. return -ENOMEM;
  127. msg.rhdr.hdr.size = sizeof(msg);
  128. msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd;
  129. ret = sof_client_ipc_tx_message(cdev, &msg, reply, max_msg_size);
  130. if (ret < 0 || reply->rhdr.error < 0)
  131. goto exit;
  132. if (!reply->num_elems)
  133. goto exit;
  134. if (cmd == SOF_IPC_PROBE_DMA_INFO)
  135. bytes = sizeof(reply->dma[0]);
  136. else
  137. bytes = sizeof(reply->desc[0]);
  138. bytes *= reply->num_elems;
  139. *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL);
  140. if (!*params) {
  141. ret = -ENOMEM;
  142. goto exit;
  143. }
  144. *num_params = reply->num_elems;
  145. exit:
  146. kfree(reply);
  147. return ret;
  148. }
  149. /**
  150. * sof_probes_points_info - retrieve list of active probe points
  151. * @cdev: SOF client device
  152. * @desc: Returned list of active probes
  153. * @num_desc: Returned count of active probes
  154. *
  155. * Host sends PROBE_POINT_INFO request to obtain list of active probe
  156. * points, valid for disconnection when given probe is no longer
  157. * required.
  158. */
  159. static int sof_probes_points_info(struct sof_client_dev *cdev,
  160. struct sof_probe_point_desc **desc,
  161. size_t *num_desc)
  162. {
  163. return sof_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO,
  164. (void **)desc, num_desc);
  165. }
  166. /**
  167. * sof_probes_points_add - connect specified probes
  168. * @cdev: SOF client device
  169. * @desc: List of probe points to connect
  170. * @num_desc: Number of elements in @desc
  171. *
  172. * Dynamically connects to provided set of endpoints. Immediately
  173. * after connection is established, host must be prepared to
  174. * transfer data from or to target stream given the probing purpose.
  175. *
  176. * Each probe point should be removed using PROBE_POINT_REMOVE
  177. * request when no longer needed.
  178. */
  179. static int sof_probes_points_add(struct sof_client_dev *cdev,
  180. struct sof_probe_point_desc *desc,
  181. size_t num_desc)
  182. {
  183. struct sof_ipc_probe_point_add_params *msg;
  184. size_t size = struct_size(msg, desc, num_desc);
  185. struct sof_ipc_reply reply;
  186. int ret;
  187. msg = kmalloc(size, GFP_KERNEL);
  188. if (!msg)
  189. return -ENOMEM;
  190. msg->hdr.size = size;
  191. msg->num_elems = num_desc;
  192. msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD;
  193. memcpy(&msg->desc[0], desc, size - sizeof(*msg));
  194. ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
  195. kfree(msg);
  196. return ret;
  197. }
  198. /**
  199. * sof_probes_points_remove - disconnect specified probes
  200. * @cdev: SOF client device
  201. * @buffer_id: List of probe points to disconnect
  202. * @num_buffer_id: Number of elements in @desc
  203. *
  204. * Removes previously connected probes from list of active probe
  205. * points and frees all resources on DSP side.
  206. */
  207. static int sof_probes_points_remove(struct sof_client_dev *cdev,
  208. unsigned int *buffer_id, size_t num_buffer_id)
  209. {
  210. struct sof_ipc_probe_point_remove_params *msg;
  211. size_t size = struct_size(msg, buffer_id, num_buffer_id);
  212. struct sof_ipc_reply reply;
  213. int ret;
  214. msg = kmalloc(size, GFP_KERNEL);
  215. if (!msg)
  216. return -ENOMEM;
  217. msg->hdr.size = size;
  218. msg->num_elems = num_buffer_id;
  219. msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE;
  220. memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg));
  221. ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
  222. kfree(msg);
  223. return ret;
  224. }
  225. static int sof_probes_compr_startup(struct snd_compr_stream *cstream,
  226. struct snd_soc_dai *dai)
  227. {
  228. struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component);
  229. struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
  230. struct sof_probes_priv *priv = cdev->data;
  231. const struct sof_probes_host_ops *ops = priv->host_ops;
  232. int ret;
  233. if (sof_client_get_fw_state(cdev) == SOF_FW_CRASHED)
  234. return -ENODEV;
  235. ret = sof_client_core_module_get(cdev);
  236. if (ret)
  237. return ret;
  238. ret = ops->startup(cdev, cstream, dai, &priv->extractor_stream_tag);
  239. if (ret) {
  240. dev_err(dai->dev, "Failed to startup probe stream: %d\n", ret);
  241. priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
  242. sof_client_core_module_put(cdev);
  243. }
  244. return ret;
  245. }
  246. static int sof_probes_compr_shutdown(struct snd_compr_stream *cstream,
  247. struct snd_soc_dai *dai)
  248. {
  249. struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component);
  250. struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
  251. struct sof_probes_priv *priv = cdev->data;
  252. const struct sof_probes_host_ops *ops = priv->host_ops;
  253. struct sof_probe_point_desc *desc;
  254. size_t num_desc;
  255. int i, ret;
  256. /* disconnect all probe points */
  257. ret = sof_probes_points_info(cdev, &desc, &num_desc);
  258. if (ret < 0) {
  259. dev_err(dai->dev, "Failed to get probe points: %d\n", ret);
  260. goto exit;
  261. }
  262. for (i = 0; i < num_desc; i++)
  263. sof_probes_points_remove(cdev, &desc[i].buffer_id, 1);
  264. kfree(desc);
  265. exit:
  266. ret = sof_probes_deinit(cdev);
  267. if (ret < 0)
  268. dev_err(dai->dev, "Failed to deinit probe: %d\n", ret);
  269. priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
  270. snd_compr_free_pages(cstream);
  271. ret = ops->shutdown(cdev, cstream, dai);
  272. sof_client_core_module_put(cdev);
  273. return ret;
  274. }
  275. static int sof_probes_compr_set_params(struct snd_compr_stream *cstream,
  276. struct snd_compr_params *params,
  277. struct snd_soc_dai *dai)
  278. {
  279. struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component);
  280. struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
  281. struct snd_compr_runtime *rtd = cstream->runtime;
  282. struct sof_probes_priv *priv = cdev->data;
  283. const struct sof_probes_host_ops *ops = priv->host_ops;
  284. int ret;
  285. cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
  286. cstream->dma_buffer.dev.dev = sof_client_get_dma_dev(cdev);
  287. ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
  288. if (ret < 0)
  289. return ret;
  290. ret = ops->set_params(cdev, cstream, params, dai);
  291. if (ret)
  292. return ret;
  293. ret = sof_probes_init(cdev, priv->extractor_stream_tag, rtd->dma_bytes);
  294. if (ret < 0) {
  295. dev_err(dai->dev, "Failed to init probe: %d\n", ret);
  296. return ret;
  297. }
  298. return 0;
  299. }
  300. static int sof_probes_compr_trigger(struct snd_compr_stream *cstream, int cmd,
  301. struct snd_soc_dai *dai)
  302. {
  303. struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component);
  304. struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
  305. struct sof_probes_priv *priv = cdev->data;
  306. const struct sof_probes_host_ops *ops = priv->host_ops;
  307. return ops->trigger(cdev, cstream, cmd, dai);
  308. }
  309. static int sof_probes_compr_pointer(struct snd_compr_stream *cstream,
  310. struct snd_compr_tstamp *tstamp,
  311. struct snd_soc_dai *dai)
  312. {
  313. struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component);
  314. struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
  315. struct sof_probes_priv *priv = cdev->data;
  316. const struct sof_probes_host_ops *ops = priv->host_ops;
  317. return ops->pointer(cdev, cstream, tstamp, dai);
  318. }
  319. static const struct snd_soc_cdai_ops sof_probes_compr_ops = {
  320. .startup = sof_probes_compr_startup,
  321. .shutdown = sof_probes_compr_shutdown,
  322. .set_params = sof_probes_compr_set_params,
  323. .trigger = sof_probes_compr_trigger,
  324. .pointer = sof_probes_compr_pointer,
  325. };
  326. static int sof_probes_compr_copy(struct snd_soc_component *component,
  327. struct snd_compr_stream *cstream,
  328. char __user *buf, size_t count)
  329. {
  330. struct snd_compr_runtime *rtd = cstream->runtime;
  331. unsigned int offset, n;
  332. void *ptr;
  333. int ret;
  334. if (count > rtd->buffer_size)
  335. count = rtd->buffer_size;
  336. div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset);
  337. ptr = rtd->dma_area + offset;
  338. n = rtd->buffer_size - offset;
  339. if (count < n) {
  340. ret = copy_to_user(buf, ptr, count);
  341. } else {
  342. ret = copy_to_user(buf, ptr, n);
  343. ret += copy_to_user(buf + n, rtd->dma_area, count - n);
  344. }
  345. if (ret)
  346. return count - ret;
  347. return count;
  348. }
  349. static const struct snd_compress_ops sof_probes_compressed_ops = {
  350. .copy = sof_probes_compr_copy,
  351. };
  352. static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
  353. size_t count, loff_t *ppos)
  354. {
  355. struct sof_client_dev *cdev = file->private_data;
  356. struct sof_probes_priv *priv = cdev->data;
  357. struct device *dev = &cdev->auxdev.dev;
  358. struct sof_probe_point_desc *desc;
  359. int remaining, offset;
  360. size_t num_desc;
  361. char *buf;
  362. int i, ret, err;
  363. if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) {
  364. dev_warn(dev, "no extractor stream running\n");
  365. return -ENOENT;
  366. }
  367. buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
  368. if (!buf)
  369. return -ENOMEM;
  370. ret = pm_runtime_resume_and_get(dev);
  371. if (ret < 0 && ret != -EACCES) {
  372. dev_err_ratelimited(dev, "debugfs read failed to resume %d\n", ret);
  373. goto exit;
  374. }
  375. ret = sof_probes_points_info(cdev, &desc, &num_desc);
  376. if (ret < 0)
  377. goto pm_error;
  378. for (i = 0; i < num_desc; i++) {
  379. offset = strlen(buf);
  380. remaining = PAGE_SIZE - offset;
  381. ret = snprintf(buf + offset, remaining,
  382. "Id: %#010x Purpose: %u Node id: %#x\n",
  383. desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag);
  384. if (ret < 0 || ret >= remaining) {
  385. /* truncate the output buffer at the last full line */
  386. buf[offset] = '\0';
  387. break;
  388. }
  389. }
  390. ret = simple_read_from_buffer(to, count, ppos, buf, strlen(buf));
  391. kfree(desc);
  392. pm_error:
  393. pm_runtime_mark_last_busy(dev);
  394. err = pm_runtime_put_autosuspend(dev);
  395. if (err < 0)
  396. dev_err_ratelimited(dev, "debugfs read failed to idle %d\n", err);
  397. exit:
  398. kfree(buf);
  399. return ret;
  400. }
  401. static ssize_t
  402. sof_probes_dfs_points_write(struct file *file, const char __user *from,
  403. size_t count, loff_t *ppos)
  404. {
  405. struct sof_client_dev *cdev = file->private_data;
  406. struct sof_probes_priv *priv = cdev->data;
  407. struct device *dev = &cdev->auxdev.dev;
  408. struct sof_probe_point_desc *desc;
  409. u32 num_elems, *array;
  410. size_t bytes;
  411. int ret, err;
  412. if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) {
  413. dev_warn(dev, "no extractor stream running\n");
  414. return -ENOENT;
  415. }
  416. ret = parse_int_array_user(from, count, (int **)&array);
  417. if (ret < 0)
  418. return ret;
  419. num_elems = *array;
  420. bytes = sizeof(*array) * num_elems;
  421. if (bytes % sizeof(*desc)) {
  422. ret = -EINVAL;
  423. goto exit;
  424. }
  425. desc = (struct sof_probe_point_desc *)&array[1];
  426. ret = pm_runtime_resume_and_get(dev);
  427. if (ret < 0 && ret != -EACCES) {
  428. dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret);
  429. goto exit;
  430. }
  431. ret = sof_probes_points_add(cdev, desc, bytes / sizeof(*desc));
  432. if (!ret)
  433. ret = count;
  434. pm_runtime_mark_last_busy(dev);
  435. err = pm_runtime_put_autosuspend(dev);
  436. if (err < 0)
  437. dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
  438. exit:
  439. kfree(array);
  440. return ret;
  441. }
  442. static const struct file_operations sof_probes_points_fops = {
  443. .open = simple_open,
  444. .read = sof_probes_dfs_points_read,
  445. .write = sof_probes_dfs_points_write,
  446. .llseek = default_llseek,
  447. .owner = THIS_MODULE,
  448. };
  449. static ssize_t
  450. sof_probes_dfs_points_remove_write(struct file *file, const char __user *from,
  451. size_t count, loff_t *ppos)
  452. {
  453. struct sof_client_dev *cdev = file->private_data;
  454. struct sof_probes_priv *priv = cdev->data;
  455. struct device *dev = &cdev->auxdev.dev;
  456. int ret, err;
  457. u32 *array;
  458. if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) {
  459. dev_warn(dev, "no extractor stream running\n");
  460. return -ENOENT;
  461. }
  462. ret = parse_int_array_user(from, count, (int **)&array);
  463. if (ret < 0)
  464. return ret;
  465. ret = pm_runtime_resume_and_get(dev);
  466. if (ret < 0) {
  467. dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret);
  468. goto exit;
  469. }
  470. ret = sof_probes_points_remove(cdev, &array[1], array[0]);
  471. if (!ret)
  472. ret = count;
  473. pm_runtime_mark_last_busy(dev);
  474. err = pm_runtime_put_autosuspend(dev);
  475. if (err < 0)
  476. dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
  477. exit:
  478. kfree(array);
  479. return ret;
  480. }
  481. static const struct file_operations sof_probes_points_remove_fops = {
  482. .open = simple_open,
  483. .write = sof_probes_dfs_points_remove_write,
  484. .llseek = default_llseek,
  485. .owner = THIS_MODULE,
  486. };
  487. static struct snd_soc_dai_driver sof_probes_dai_drv[] = {
  488. {
  489. .name = "Probe Extraction CPU DAI",
  490. .compress_new = snd_soc_new_compress,
  491. .cops = &sof_probes_compr_ops,
  492. .capture = {
  493. .stream_name = "Probe Extraction",
  494. .channels_min = 1,
  495. .channels_max = 8,
  496. .rates = SNDRV_PCM_RATE_48000,
  497. .rate_min = 48000,
  498. .rate_max = 48000,
  499. },
  500. },
  501. };
  502. static const struct snd_soc_component_driver sof_probes_component = {
  503. .name = "sof-probes-component",
  504. .compress_ops = &sof_probes_compressed_ops,
  505. .module_get_upon_open = 1,
  506. .legacy_dai_naming = 1,
  507. };
  508. SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
  509. static int sof_probes_client_probe(struct auxiliary_device *auxdev,
  510. const struct auxiliary_device_id *id)
  511. {
  512. struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
  513. struct dentry *dfsroot = sof_client_get_debugfs_root(cdev);
  514. struct device *dev = &auxdev->dev;
  515. struct snd_soc_dai_link_component platform_component[] = {
  516. {
  517. .name = dev_name(dev),
  518. }
  519. };
  520. struct snd_soc_card *card;
  521. struct sof_probes_priv *priv;
  522. struct snd_soc_dai_link_component *cpus;
  523. struct sof_probes_host_ops *ops;
  524. struct snd_soc_dai_link *links;
  525. int ret;
  526. /* do not set up the probes support if it is not enabled */
  527. if (!sof_probes_enabled)
  528. return -ENXIO;
  529. /* only ipc3 is supported */
  530. if (sof_client_get_ipc_type(cdev) != SOF_IPC)
  531. return -ENXIO;
  532. if (!dev->platform_data) {
  533. dev_err(dev, "missing platform data\n");
  534. return -ENODEV;
  535. }
  536. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  537. if (!priv)
  538. return -ENOMEM;
  539. ops = dev->platform_data;
  540. if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger ||
  541. !ops->pointer) {
  542. dev_err(dev, "missing platform callback(s)\n");
  543. return -ENODEV;
  544. }
  545. priv->host_ops = ops;
  546. cdev->data = priv;
  547. /* register probes component driver and dai */
  548. ret = devm_snd_soc_register_component(dev, &sof_probes_component,
  549. sof_probes_dai_drv,
  550. ARRAY_SIZE(sof_probes_dai_drv));
  551. if (ret < 0) {
  552. dev_err(dev, "failed to register SOF probes DAI driver %d\n", ret);
  553. return ret;
  554. }
  555. /* set client data */
  556. priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
  557. /* create read-write probes_points debugfs entry */
  558. priv->dfs_points = debugfs_create_file("probe_points", 0644, dfsroot,
  559. cdev, &sof_probes_points_fops);
  560. /* create read-write probe_points_remove debugfs entry */
  561. priv->dfs_points_remove = debugfs_create_file("probe_points_remove", 0644,
  562. dfsroot, cdev,
  563. &sof_probes_points_remove_fops);
  564. links = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*links), GFP_KERNEL);
  565. cpus = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*cpus), GFP_KERNEL);
  566. if (!links || !cpus) {
  567. debugfs_remove(priv->dfs_points);
  568. debugfs_remove(priv->dfs_points_remove);
  569. return -ENOMEM;
  570. }
  571. /* extraction DAI link */
  572. links[0].name = "Compress Probe Capture";
  573. links[0].id = 0;
  574. links[0].cpus = &cpus[0];
  575. links[0].num_cpus = 1;
  576. links[0].cpus->dai_name = "Probe Extraction CPU DAI";
  577. links[0].codecs = dummy;
  578. links[0].num_codecs = 1;
  579. links[0].platforms = platform_component;
  580. links[0].num_platforms = ARRAY_SIZE(platform_component);
  581. links[0].nonatomic = 1;
  582. card = &priv->card;
  583. card->dev = dev;
  584. card->name = "sof-probes";
  585. card->owner = THIS_MODULE;
  586. card->num_links = SOF_PROBES_NUM_DAI_LINKS;
  587. card->dai_link = links;
  588. /* set idle_bias_off to prevent the core from resuming the card->dev */
  589. card->dapm.idle_bias_off = true;
  590. snd_soc_card_set_drvdata(card, cdev);
  591. ret = devm_snd_soc_register_card(dev, card);
  592. if (ret < 0) {
  593. debugfs_remove(priv->dfs_points);
  594. debugfs_remove(priv->dfs_points_remove);
  595. dev_err(dev, "Probes card register failed %d\n", ret);
  596. return ret;
  597. }
  598. /* enable runtime PM */
  599. pm_runtime_set_autosuspend_delay(dev, SOF_PROBES_SUSPEND_DELAY_MS);
  600. pm_runtime_use_autosuspend(dev);
  601. pm_runtime_enable(dev);
  602. pm_runtime_mark_last_busy(dev);
  603. pm_runtime_idle(dev);
  604. return 0;
  605. }
  606. static void sof_probes_client_remove(struct auxiliary_device *auxdev)
  607. {
  608. struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
  609. struct sof_probes_priv *priv = cdev->data;
  610. if (!sof_probes_enabled)
  611. return;
  612. pm_runtime_disable(&auxdev->dev);
  613. debugfs_remove(priv->dfs_points);
  614. debugfs_remove(priv->dfs_points_remove);
  615. }
  616. static const struct auxiliary_device_id sof_probes_client_id_table[] = {
  617. { .name = "snd_sof.hda-probes", },
  618. {},
  619. };
  620. MODULE_DEVICE_TABLE(auxiliary, sof_probes_client_id_table);
  621. /* driver name will be set based on KBUILD_MODNAME */
  622. static struct auxiliary_driver sof_probes_client_drv = {
  623. .probe = sof_probes_client_probe,
  624. .remove = sof_probes_client_remove,
  625. .id_table = sof_probes_client_id_table,
  626. };
  627. module_auxiliary_driver(sof_probes_client_drv);
  628. MODULE_DESCRIPTION("SOF Probes Client Driver");
  629. MODULE_LICENSE("GPL v2");
  630. MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);