1 // SPDX-License-Identifier: GPL-2.0-only
3 // Copyright(c) 2022 Intel Corporation
5 // Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
6 // Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
9 #include <linux/debugfs.h>
10 #include <linux/errno.h>
11 #include <linux/list.h>
12 #include <linux/module.h>
13 #include <linux/mutex.h>
14 #include <linux/slab.h>
15 #include <sound/sof/ipc4/header.h>
17 #include "sof-client.h"
19 #include "ipc3-priv.h"
20 #include "ipc4-priv.h"
23 * struct sof_ipc_event_entry - IPC client event description
24 * @ipc_msg_type: IPC msg type of the event the client is interested
25 * @cdev: sof_client_dev of the requesting client
26 * @callback: Callback function of the client
27 * @list: item in SOF core client event list
29 struct sof_ipc_event_entry
{
31 struct sof_client_dev
*cdev
;
32 sof_client_event_callback callback
;
33 struct list_head list
;
37 * struct sof_state_event_entry - DSP panic event subscription entry
38 * @cdev: sof_client_dev of the requesting client
39 * @callback: Callback function of the client
40 * @list: item in SOF core client event list
42 struct sof_state_event_entry
{
43 struct sof_client_dev
*cdev
;
44 sof_client_fw_state_callback callback
;
45 struct list_head list
;
48 static void sof_client_auxdev_release(struct device
*dev
)
50 struct auxiliary_device
*auxdev
= to_auxiliary_dev(dev
);
51 struct sof_client_dev
*cdev
= auxiliary_dev_to_sof_client_dev(auxdev
);
53 kfree(cdev
->auxdev
.dev
.platform_data
);
57 static int sof_client_dev_add_data(struct sof_client_dev
*cdev
, const void *data
,
63 d
= kmemdup(data
, size
, GFP_KERNEL
);
68 cdev
->auxdev
.dev
.platform_data
= d
;
72 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
73 static int sof_register_ipc_flood_test(struct snd_sof_dev
*sdev
)
78 if (sdev
->pdata
->ipc_type
!= SOF_IPC_TYPE_3
)
81 for (i
= 0; i
< CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM
; i
++) {
82 ret
= sof_client_dev_register(sdev
, "ipc_flood", i
, NULL
, 0);
89 sof_client_dev_unregister(sdev
, "ipc_flood", i
);
95 static void sof_unregister_ipc_flood_test(struct snd_sof_dev
*sdev
)
99 for (i
= 0; i
< CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM
; i
++)
100 sof_client_dev_unregister(sdev
, "ipc_flood", i
);
103 static inline int sof_register_ipc_flood_test(struct snd_sof_dev
*sdev
)
108 static inline void sof_unregister_ipc_flood_test(struct snd_sof_dev
*sdev
) {}
109 #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST */
111 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR)
112 static int sof_register_ipc_msg_injector(struct snd_sof_dev
*sdev
)
114 return sof_client_dev_register(sdev
, "msg_injector", 0, NULL
, 0);
117 static void sof_unregister_ipc_msg_injector(struct snd_sof_dev
*sdev
)
119 sof_client_dev_unregister(sdev
, "msg_injector", 0);
122 static inline int sof_register_ipc_msg_injector(struct snd_sof_dev
*sdev
)
127 static inline void sof_unregister_ipc_msg_injector(struct snd_sof_dev
*sdev
) {}
128 #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR */
130 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_KERNEL_INJECTOR)
131 static int sof_register_ipc_kernel_injector(struct snd_sof_dev
*sdev
)
133 /* Only IPC3 supported right now */
134 if (sdev
->pdata
->ipc_type
!= SOF_IPC_TYPE_3
)
137 return sof_client_dev_register(sdev
, "kernel_injector", 0, NULL
, 0);
140 static void sof_unregister_ipc_kernel_injector(struct snd_sof_dev
*sdev
)
142 sof_client_dev_unregister(sdev
, "kernel_injector", 0);
145 static inline int sof_register_ipc_kernel_injector(struct snd_sof_dev
*sdev
)
150 static inline void sof_unregister_ipc_kernel_injector(struct snd_sof_dev
*sdev
) {}
151 #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_KERNEL_INJECTOR */
153 int sof_register_clients(struct snd_sof_dev
*sdev
)
157 if (sdev
->dspless_mode_selected
)
160 /* Register platform independent client devices */
161 ret
= sof_register_ipc_flood_test(sdev
);
163 dev_err(sdev
->dev
, "IPC flood test client registration failed\n");
167 ret
= sof_register_ipc_msg_injector(sdev
);
169 dev_err(sdev
->dev
, "IPC message injector client registration failed\n");
170 goto err_msg_injector
;
173 ret
= sof_register_ipc_kernel_injector(sdev
);
175 dev_err(sdev
->dev
, "IPC kernel injector client registration failed\n");
176 goto err_kernel_injector
;
179 /* Platform dependent client device registration */
181 if (sof_ops(sdev
) && sof_ops(sdev
)->register_ipc_clients
)
182 ret
= sof_ops(sdev
)->register_ipc_clients(sdev
);
187 sof_unregister_ipc_kernel_injector(sdev
);
190 sof_unregister_ipc_msg_injector(sdev
);
193 sof_unregister_ipc_flood_test(sdev
);
198 void sof_unregister_clients(struct snd_sof_dev
*sdev
)
200 if (sof_ops(sdev
) && sof_ops(sdev
)->unregister_ipc_clients
)
201 sof_ops(sdev
)->unregister_ipc_clients(sdev
);
203 sof_unregister_ipc_kernel_injector(sdev
);
204 sof_unregister_ipc_msg_injector(sdev
);
205 sof_unregister_ipc_flood_test(sdev
);
208 int sof_client_dev_register(struct snd_sof_dev
*sdev
, const char *name
, u32 id
,
209 const void *data
, size_t size
)
211 struct auxiliary_device
*auxdev
;
212 struct sof_client_dev
*cdev
;
215 cdev
= kzalloc(sizeof(*cdev
), GFP_KERNEL
);
220 auxdev
= &cdev
->auxdev
;
222 auxdev
->dev
.parent
= sdev
->dev
;
223 auxdev
->dev
.release
= sof_client_auxdev_release
;
226 ret
= sof_client_dev_add_data(cdev
, data
, size
);
228 goto err_dev_add_data
;
230 ret
= auxiliary_device_init(auxdev
);
232 dev_err(sdev
->dev
, "failed to initialize client dev %s.%d\n", name
, id
);
236 ret
= auxiliary_device_add(&cdev
->auxdev
);
238 dev_err(sdev
->dev
, "failed to add client dev %s.%d\n", name
, id
);
240 * sof_client_auxdev_release() will be invoked to free up memory
241 * allocations through put_device()
243 auxiliary_device_uninit(&cdev
->auxdev
);
247 /* add to list of SOF client devices */
248 mutex_lock(&sdev
->ipc_client_mutex
);
249 list_add(&cdev
->list
, &sdev
->ipc_client_list
);
250 mutex_unlock(&sdev
->ipc_client_mutex
);
255 kfree(cdev
->auxdev
.dev
.platform_data
);
262 EXPORT_SYMBOL_NS_GPL(sof_client_dev_register
, "SND_SOC_SOF_CLIENT");
264 void sof_client_dev_unregister(struct snd_sof_dev
*sdev
, const char *name
, u32 id
)
266 struct sof_client_dev
*cdev
;
268 mutex_lock(&sdev
->ipc_client_mutex
);
271 * sof_client_auxdev_release() will be invoked to free up memory
272 * allocations through put_device()
274 list_for_each_entry(cdev
, &sdev
->ipc_client_list
, list
) {
275 if (!strcmp(cdev
->auxdev
.name
, name
) && cdev
->auxdev
.id
== id
) {
276 list_del(&cdev
->list
);
277 auxiliary_device_delete(&cdev
->auxdev
);
278 auxiliary_device_uninit(&cdev
->auxdev
);
283 mutex_unlock(&sdev
->ipc_client_mutex
);
285 EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister
, "SND_SOC_SOF_CLIENT");
287 int sof_client_ipc_tx_message(struct sof_client_dev
*cdev
, void *ipc_msg
,
288 void *reply_data
, size_t reply_bytes
)
290 if (cdev
->sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_3
) {
291 struct sof_ipc_cmd_hdr
*hdr
= ipc_msg
;
293 return sof_ipc_tx_message(cdev
->sdev
->ipc
, ipc_msg
, hdr
->size
,
294 reply_data
, reply_bytes
);
295 } else if (cdev
->sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_4
) {
296 struct sof_ipc4_msg
*msg
= ipc_msg
;
298 return sof_ipc_tx_message(cdev
->sdev
->ipc
, ipc_msg
, msg
->data_size
,
299 reply_data
, reply_bytes
);
304 EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message
, "SND_SOC_SOF_CLIENT");
306 int sof_client_ipc_rx_message(struct sof_client_dev
*cdev
, void *ipc_msg
, void *msg_buf
)
308 if (IS_ENABLED(CONFIG_SND_SOC_SOF_IPC3
) &&
309 cdev
->sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_3
) {
310 struct sof_ipc_cmd_hdr
*hdr
= ipc_msg
;
312 if (hdr
->size
< sizeof(hdr
)) {
313 dev_err(cdev
->sdev
->dev
, "The received message size is invalid\n");
317 sof_ipc3_do_rx_work(cdev
->sdev
, ipc_msg
, msg_buf
);
323 EXPORT_SYMBOL_NS_GPL(sof_client_ipc_rx_message
, "SND_SOC_SOF_CLIENT");
325 int sof_client_ipc_set_get_data(struct sof_client_dev
*cdev
, void *ipc_msg
,
328 if (cdev
->sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_3
) {
329 struct sof_ipc_cmd_hdr
*hdr
= ipc_msg
;
331 return sof_ipc_set_get_data(cdev
->sdev
->ipc
, ipc_msg
, hdr
->size
,
333 } else if (cdev
->sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_4
) {
334 struct sof_ipc4_msg
*msg
= ipc_msg
;
336 return sof_ipc_set_get_data(cdev
->sdev
->ipc
, ipc_msg
,
337 msg
->data_size
, set
);
342 EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data
, "SND_SOC_SOF_CLIENT");
344 #ifdef CONFIG_SND_SOC_SOF_IPC4
345 struct sof_ipc4_fw_module
*sof_client_ipc4_find_module(struct sof_client_dev
*c
, const guid_t
*uuid
)
347 struct snd_sof_dev
*sdev
= c
->sdev
;
349 if (sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_4
)
350 return sof_ipc4_find_module_by_uuid(sdev
, uuid
);
351 dev_err(sdev
->dev
, "Only supported with IPC4\n");
355 EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module
, "SND_SOC_SOF_CLIENT");
358 int sof_suspend_clients(struct snd_sof_dev
*sdev
, pm_message_t state
)
360 const struct auxiliary_driver
*adrv
;
361 struct sof_client_dev
*cdev
;
363 mutex_lock(&sdev
->ipc_client_mutex
);
365 list_for_each_entry(cdev
, &sdev
->ipc_client_list
, list
) {
366 /* Skip devices without loaded driver */
367 if (!cdev
->auxdev
.dev
.driver
)
370 adrv
= to_auxiliary_drv(cdev
->auxdev
.dev
.driver
);
372 adrv
->suspend(&cdev
->auxdev
, state
);
375 mutex_unlock(&sdev
->ipc_client_mutex
);
379 EXPORT_SYMBOL_NS_GPL(sof_suspend_clients
, "SND_SOC_SOF_CLIENT");
381 int sof_resume_clients(struct snd_sof_dev
*sdev
)
383 const struct auxiliary_driver
*adrv
;
384 struct sof_client_dev
*cdev
;
386 mutex_lock(&sdev
->ipc_client_mutex
);
388 list_for_each_entry(cdev
, &sdev
->ipc_client_list
, list
) {
389 /* Skip devices without loaded driver */
390 if (!cdev
->auxdev
.dev
.driver
)
393 adrv
= to_auxiliary_drv(cdev
->auxdev
.dev
.driver
);
395 adrv
->resume(&cdev
->auxdev
);
398 mutex_unlock(&sdev
->ipc_client_mutex
);
402 EXPORT_SYMBOL_NS_GPL(sof_resume_clients
, "SND_SOC_SOF_CLIENT");
404 struct dentry
*sof_client_get_debugfs_root(struct sof_client_dev
*cdev
)
406 return cdev
->sdev
->debugfs_root
;
408 EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root
, "SND_SOC_SOF_CLIENT");
410 /* DMA buffer allocation in client drivers must use the core SOF device */
411 struct device
*sof_client_get_dma_dev(struct sof_client_dev
*cdev
)
413 return cdev
->sdev
->dev
;
415 EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev
, "SND_SOC_SOF_CLIENT");
417 const struct sof_ipc_fw_version
*sof_client_get_fw_version(struct sof_client_dev
*cdev
)
419 struct snd_sof_dev
*sdev
= sof_client_dev_to_sof_dev(cdev
);
421 return &sdev
->fw_ready
.version
;
423 EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version
, "SND_SOC_SOF_CLIENT");
425 size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev
*cdev
)
427 struct snd_sof_dev
*sdev
= sof_client_dev_to_sof_dev(cdev
);
429 return sdev
->ipc
->max_payload_size
;
431 EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size
, "SND_SOC_SOF_CLIENT");
433 enum sof_ipc_type
sof_client_get_ipc_type(struct sof_client_dev
*cdev
)
435 struct snd_sof_dev
*sdev
= sof_client_dev_to_sof_dev(cdev
);
437 return sdev
->pdata
->ipc_type
;
439 EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type
, "SND_SOC_SOF_CLIENT");
441 /* module refcount management of SOF core */
442 int sof_client_core_module_get(struct sof_client_dev
*cdev
)
444 struct snd_sof_dev
*sdev
= sof_client_dev_to_sof_dev(cdev
);
446 if (!try_module_get(sdev
->dev
->driver
->owner
))
451 EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get
, "SND_SOC_SOF_CLIENT");
453 void sof_client_core_module_put(struct sof_client_dev
*cdev
)
455 struct snd_sof_dev
*sdev
= sof_client_dev_to_sof_dev(cdev
);
457 module_put(sdev
->dev
->driver
->owner
);
459 EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put
, "SND_SOC_SOF_CLIENT");
461 /* IPC event handling */
462 void sof_client_ipc_rx_dispatcher(struct snd_sof_dev
*sdev
, void *msg_buf
)
464 struct sof_ipc_event_entry
*event
;
467 if (sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_3
) {
468 struct sof_ipc_cmd_hdr
*hdr
= msg_buf
;
470 msg_type
= hdr
->cmd
& SOF_GLB_TYPE_MASK
;
471 } else if (sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_4
) {
472 struct sof_ipc4_msg
*msg
= msg_buf
;
474 msg_type
= SOF_IPC4_NOTIFICATION_TYPE_GET(msg
->primary
);
476 dev_dbg_once(sdev
->dev
, "Not supported IPC version: %d\n",
477 sdev
->pdata
->ipc_type
);
481 mutex_lock(&sdev
->client_event_handler_mutex
);
483 list_for_each_entry(event
, &sdev
->ipc_rx_handler_list
, list
) {
484 if (event
->ipc_msg_type
== msg_type
)
485 event
->callback(event
->cdev
, msg_buf
);
488 mutex_unlock(&sdev
->client_event_handler_mutex
);
491 int sof_client_register_ipc_rx_handler(struct sof_client_dev
*cdev
,
493 sof_client_event_callback callback
)
495 struct snd_sof_dev
*sdev
= sof_client_dev_to_sof_dev(cdev
);
496 struct sof_ipc_event_entry
*event
;
501 if (cdev
->sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_3
) {
502 if (!(ipc_msg_type
& SOF_GLB_TYPE_MASK
))
504 } else if (cdev
->sdev
->pdata
->ipc_type
== SOF_IPC_TYPE_4
) {
505 if (!(ipc_msg_type
& SOF_IPC4_NOTIFICATION_TYPE_MASK
))
508 dev_warn(sdev
->dev
, "%s: Not supported IPC version: %d\n",
509 __func__
, sdev
->pdata
->ipc_type
);
513 event
= kmalloc(sizeof(*event
), GFP_KERNEL
);
517 event
->ipc_msg_type
= ipc_msg_type
;
519 event
->callback
= callback
;
521 /* add to list of SOF client devices */
522 mutex_lock(&sdev
->client_event_handler_mutex
);
523 list_add(&event
->list
, &sdev
->ipc_rx_handler_list
);
524 mutex_unlock(&sdev
->client_event_handler_mutex
);
528 EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler
, "SND_SOC_SOF_CLIENT");
530 void sof_client_unregister_ipc_rx_handler(struct sof_client_dev
*cdev
,
533 struct snd_sof_dev
*sdev
= sof_client_dev_to_sof_dev(cdev
);
534 struct sof_ipc_event_entry
*event
;
536 mutex_lock(&sdev
->client_event_handler_mutex
);
538 list_for_each_entry(event
, &sdev
->ipc_rx_handler_list
, list
) {
539 if (event
->cdev
== cdev
&& event
->ipc_msg_type
== ipc_msg_type
) {
540 list_del(&event
->list
);
546 mutex_unlock(&sdev
->client_event_handler_mutex
);
548 EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler
, "SND_SOC_SOF_CLIENT");
550 /*DSP state notification and query */
551 void sof_client_fw_state_dispatcher(struct snd_sof_dev
*sdev
)
553 struct sof_state_event_entry
*event
;
555 mutex_lock(&sdev
->client_event_handler_mutex
);
557 list_for_each_entry(event
, &sdev
->fw_state_handler_list
, list
)
558 event
->callback(event
->cdev
, sdev
->fw_state
);
560 mutex_unlock(&sdev
->client_event_handler_mutex
);
563 int sof_client_register_fw_state_handler(struct sof_client_dev
*cdev
,
564 sof_client_fw_state_callback callback
)
566 struct snd_sof_dev
*sdev
= sof_client_dev_to_sof_dev(cdev
);
567 struct sof_state_event_entry
*event
;
572 event
= kmalloc(sizeof(*event
), GFP_KERNEL
);
577 event
->callback
= callback
;
579 /* add to list of SOF client devices */
580 mutex_lock(&sdev
->client_event_handler_mutex
);
581 list_add(&event
->list
, &sdev
->fw_state_handler_list
);
582 mutex_unlock(&sdev
->client_event_handler_mutex
);
586 EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler
, "SND_SOC_SOF_CLIENT");
588 void sof_client_unregister_fw_state_handler(struct sof_client_dev
*cdev
)
590 struct snd_sof_dev
*sdev
= sof_client_dev_to_sof_dev(cdev
);
591 struct sof_state_event_entry
*event
;
593 mutex_lock(&sdev
->client_event_handler_mutex
);
595 list_for_each_entry(event
, &sdev
->fw_state_handler_list
, list
) {
596 if (event
->cdev
== cdev
) {
597 list_del(&event
->list
);
603 mutex_unlock(&sdev
->client_event_handler_mutex
);
605 EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler
, "SND_SOC_SOF_CLIENT");
607 enum sof_fw_state
sof_client_get_fw_state(struct sof_client_dev
*cdev
)
609 struct snd_sof_dev
*sdev
= sof_client_dev_to_sof_dev(cdev
);
611 return sdev
->fw_state
;
613 EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state
, "SND_SOC_SOF_CLIENT");