diff options
Diffstat (limited to 'sound/soc/sof/sof-client.c')
| -rw-r--r-- | sound/soc/sof/sof-client.c | 179 |
1 files changed, 118 insertions, 61 deletions
diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 284de96e779c..2dbfc7699c73 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2022 Intel Corporation. All rights reserved. +// Copyright(c) 2022 Intel Corporation // // Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> // Peter Ujfalusi <peter.ujfalusi@linux.intel.com> @@ -45,13 +45,30 @@ struct sof_state_event_entry { struct list_head list; }; +/** + * struct sof_client_dev_entry - client device entry for internal management use + * @sdev: pointer to SOF core device struct + * @list: item in SOF core client dev list + * @client_dev: SOF client device + */ +struct sof_client_dev_entry { + struct snd_sof_dev *sdev; + struct list_head list; + + struct sof_client_dev client_dev; +}; + +#define cdev_to_centry(cdev) \ + container_of(cdev, struct sof_client_dev_entry, client_dev) + static void sof_client_auxdev_release(struct device *dev) { struct auxiliary_device *auxdev = to_auxiliary_dev(dev); struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); + struct sof_client_dev_entry *centry = cdev_to_centry(cdev); kfree(cdev->auxdev.dev.platform_data); - kfree(cdev); + kfree(centry); } static int sof_client_dev_add_data(struct sof_client_dev *cdev, const void *data, @@ -75,7 +92,7 @@ static int sof_register_ipc_flood_test(struct snd_sof_dev *sdev) int ret = 0; int i; - if (sdev->pdata->ipc_type != SOF_IPC) + if (sdev->pdata->ipc_type != SOF_IPC_TYPE_3) return 0; for (i = 0; i < CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM; i++) { @@ -131,7 +148,7 @@ static inline void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev) {} static int sof_register_ipc_kernel_injector(struct snd_sof_dev *sdev) { /* Only IPC3 supported right now */ - if (sdev->pdata->ipc_type != SOF_IPC) + if (sdev->pdata->ipc_type != SOF_IPC_TYPE_3) return 0; return sof_client_dev_register(sdev, "kernel_injector", 0, NULL, 0); @@ -176,7 +193,7 @@ int sof_register_clients(struct snd_sof_dev *sdev) goto err_kernel_injector; } - /* Platform depndent client device registration */ + /* Platform dependent client device registration */ if (sof_ops(sdev) && sof_ops(sdev)->register_ipc_clients) ret = sof_ops(sdev)->register_ipc_clients(sdev); @@ -208,15 +225,18 @@ void sof_unregister_clients(struct snd_sof_dev *sdev) int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, const void *data, size_t size) { + struct sof_client_dev_entry *centry; struct auxiliary_device *auxdev; struct sof_client_dev *cdev; int ret; - cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); - if (!cdev) + centry = kzalloc(sizeof(*centry), GFP_KERNEL); + if (!centry) return -ENOMEM; - cdev->sdev = sdev; + cdev = ¢ry->client_dev; + + centry->sdev = sdev; auxdev = &cdev->auxdev; auxdev->name = name; auxdev->dev.parent = sdev->dev; @@ -246,7 +266,7 @@ int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, /* add to list of SOF client devices */ mutex_lock(&sdev->ipc_client_mutex); - list_add(&cdev->list, &sdev->ipc_client_list); + list_add(¢ry->list, &sdev->ipc_client_list); mutex_unlock(&sdev->ipc_client_mutex); return 0; @@ -255,15 +275,15 @@ err_dev_init: kfree(cdev->auxdev.dev.platform_data); err_dev_add_data: - kfree(cdev); + kfree(centry); return ret; } -EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, "SND_SOC_SOF_CLIENT"); void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id) { - struct sof_client_dev *cdev; + struct sof_client_dev_entry *centry; mutex_lock(&sdev->ipc_client_mutex); @@ -271,9 +291,11 @@ void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 i * sof_client_auxdev_release() will be invoked to free up memory * allocations through put_device() */ - list_for_each_entry(cdev, &sdev->ipc_client_list, list) { + list_for_each_entry(centry, &sdev->ipc_client_list, list) { + struct sof_client_dev *cdev = ¢ry->client_dev; + if (!strcmp(cdev->auxdev.name, name) && cdev->auxdev.id == id) { - list_del(&cdev->list); + list_del(¢ry->list); auxiliary_device_delete(&cdev->auxdev); auxiliary_device_uninit(&cdev->auxdev); break; @@ -282,86 +304,107 @@ void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 i mutex_unlock(&sdev->ipc_client_mutex); } -EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, "SND_SOC_SOF_CLIENT"); int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, void *reply_data, size_t reply_bytes) { - if (cdev->sdev->pdata->ipc_type == SOF_IPC) { + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { struct sof_ipc_cmd_hdr *hdr = ipc_msg; - return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, hdr->size, + return sof_ipc_tx_message(sdev->ipc, ipc_msg, hdr->size, reply_data, reply_bytes); - } else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) { + } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { struct sof_ipc4_msg *msg = ipc_msg; - return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, msg->data_size, + return sof_ipc_tx_message(sdev->ipc, ipc_msg, msg->data_size, reply_data, reply_bytes); } return -EINVAL; } -EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, "SND_SOC_SOF_CLIENT"); int sof_client_ipc_rx_message(struct sof_client_dev *cdev, void *ipc_msg, void *msg_buf) { - if (cdev->sdev->pdata->ipc_type == SOF_IPC) { + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_IPC3) && + sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { struct sof_ipc_cmd_hdr *hdr = ipc_msg; if (hdr->size < sizeof(hdr)) { - dev_err(cdev->sdev->dev, "The received message size is invalid\n"); + dev_err(sdev->dev, "The received message size is invalid\n"); return -EINVAL; } - sof_ipc3_do_rx_work(cdev->sdev, ipc_msg, msg_buf); + sof_ipc3_do_rx_work(sdev, ipc_msg, msg_buf); return 0; } return -EOPNOTSUPP; } -EXPORT_SYMBOL_NS_GPL(sof_client_ipc_rx_message, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_ipc_rx_message, "SND_SOC_SOF_CLIENT"); int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg, bool set) { - if (cdev->sdev->pdata->ipc_type == SOF_IPC) { + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { struct sof_ipc_cmd_hdr *hdr = ipc_msg; - return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg, hdr->size, - set); - } else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) { + return sof_ipc_set_get_data(sdev->ipc, ipc_msg, hdr->size, set); + } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { struct sof_ipc4_msg *msg = ipc_msg; - return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg, - msg->data_size, set); + return sof_ipc_set_get_data(sdev->ipc, ipc_msg, msg->data_size, + set); } return -EINVAL; } -EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, "SND_SOC_SOF_CLIENT"); -#ifdef CONFIG_SND_SOC_SOF_INTEL_IPC4 +#ifdef CONFIG_SND_SOC_SOF_IPC4 struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *uuid) { - struct snd_sof_dev *sdev = c->sdev; + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(c); - if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) return sof_ipc4_find_module_by_uuid(sdev, uuid); dev_err(sdev->dev, "Only supported with IPC4\n"); return NULL; } -EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, "SND_SOC_SOF_CLIENT"); + +struct snd_sof_widget *sof_client_ipc4_find_swidget_by_id(struct sof_client_dev *cdev, + u32 module_id, int instance_id) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) + return sof_ipc4_find_swidget_by_ids(sdev, module_id, instance_id); + dev_err(sdev->dev, "Only supported with IPC4\n"); + + return NULL; +} +EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_swidget_by_id, "SND_SOC_SOF_CLIENT"); #endif int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state) { - struct auxiliary_driver *adrv; - struct sof_client_dev *cdev; + const struct auxiliary_driver *adrv; + struct sof_client_dev_entry *centry; mutex_lock(&sdev->ipc_client_mutex); - list_for_each_entry(cdev, &sdev->ipc_client_list, list) { + list_for_each_entry(centry, &sdev->ipc_client_list, list) { + struct sof_client_dev *cdev = ¢ry->client_dev; + /* Skip devices without loaded driver */ if (!cdev->auxdev.dev.driver) continue; @@ -375,16 +418,18 @@ int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state) return 0; } -EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, "SND_SOC_SOF_CLIENT"); int sof_resume_clients(struct snd_sof_dev *sdev) { - struct auxiliary_driver *adrv; - struct sof_client_dev *cdev; + const struct auxiliary_driver *adrv; + struct sof_client_dev_entry *centry; mutex_lock(&sdev->ipc_client_mutex); - list_for_each_entry(cdev, &sdev->ipc_client_list, list) { + list_for_each_entry(centry, &sdev->ipc_client_list, list) { + struct sof_client_dev *cdev = ¢ry->client_dev; + /* Skip devices without loaded driver */ if (!cdev->auxdev.dev.driver) continue; @@ -398,20 +443,24 @@ int sof_resume_clients(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS_GPL(sof_resume_clients, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_resume_clients, "SND_SOC_SOF_CLIENT"); struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev) { - return cdev->sdev->debugfs_root; + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + return sdev->debugfs_root; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, "SND_SOC_SOF_CLIENT"); /* DMA buffer allocation in client drivers must use the core SOF device */ struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev) { - return cdev->sdev->dev; + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + return sdev->dev; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, "SND_SOC_SOF_CLIENT"); const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev) { @@ -419,7 +468,7 @@ const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev return &sdev->fw_ready.version; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, "SND_SOC_SOF_CLIENT"); size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev) { @@ -427,7 +476,7 @@ size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev) return sdev->ipc->max_payload_size; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, "SND_SOC_SOF_CLIENT"); enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev) { @@ -435,7 +484,7 @@ enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev) return sdev->pdata->ipc_type; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, "SND_SOC_SOF_CLIENT"); /* module refcount management of SOF core */ int sof_client_core_module_get(struct sof_client_dev *cdev) @@ -447,7 +496,7 @@ int sof_client_core_module_get(struct sof_client_dev *cdev) return 0; } -EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, "SND_SOC_SOF_CLIENT"); void sof_client_core_module_put(struct sof_client_dev *cdev) { @@ -455,7 +504,7 @@ void sof_client_core_module_put(struct sof_client_dev *cdev) module_put(sdev->dev->driver->owner); } -EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, "SND_SOC_SOF_CLIENT"); /* IPC event handling */ void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf) @@ -463,11 +512,11 @@ void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf) struct sof_ipc_event_entry *event; u32 msg_type; - if (sdev->pdata->ipc_type == SOF_IPC) { + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { struct sof_ipc_cmd_hdr *hdr = msg_buf; msg_type = hdr->cmd & SOF_GLB_TYPE_MASK; - } else if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { + } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { struct sof_ipc4_msg *msg = msg_buf; msg_type = SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary); @@ -497,10 +546,10 @@ int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, if (!callback) return -EINVAL; - if (cdev->sdev->pdata->ipc_type == SOF_IPC) { + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { if (!(ipc_msg_type & SOF_GLB_TYPE_MASK)) return -EINVAL; - } else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) { + } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { if (!(ipc_msg_type & SOF_IPC4_NOTIFICATION_TYPE_MASK)) return -EINVAL; } else { @@ -524,7 +573,7 @@ int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, return 0; } -EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, "SND_SOC_SOF_CLIENT"); void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, u32 ipc_msg_type) @@ -544,7 +593,7 @@ void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, mutex_unlock(&sdev->client_event_handler_mutex); } -EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, "SND_SOC_SOF_CLIENT"); /*DSP state notification and query */ void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev) @@ -582,7 +631,7 @@ int sof_client_register_fw_state_handler(struct sof_client_dev *cdev, return 0; } -EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, "SND_SOC_SOF_CLIENT"); void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev) { @@ -601,7 +650,7 @@ void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev) mutex_unlock(&sdev->client_event_handler_mutex); } -EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, "SND_SOC_SOF_CLIENT"); enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev) { @@ -609,4 +658,12 @@ enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev) return sdev->fw_state; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, "SND_SOC_SOF_CLIENT"); + +struct snd_sof_dev *sof_client_dev_to_sof_dev(struct sof_client_dev *cdev) +{ + struct sof_client_dev_entry *centry = cdev_to_centry(cdev); + + return centry->sdev; +} +EXPORT_SYMBOL_NS_GPL(sof_client_dev_to_sof_dev, "SND_SOC_SOF_CLIENT"); |
