Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 //
0003 // Copyright(c) 2022 Intel Corporation. All rights reserved.
0004 //
0005 // Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
0006 //      Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
0007 //
0008 
0009 #include <linux/debugfs.h>
0010 #include <linux/errno.h>
0011 #include <linux/list.h>
0012 #include <linux/module.h>
0013 #include <linux/mutex.h>
0014 #include <linux/slab.h>
0015 #include <sound/sof/ipc4/header.h>
0016 #include "ops.h"
0017 #include "sof-client.h"
0018 #include "sof-priv.h"
0019 
0020 /**
0021  * struct sof_ipc_event_entry - IPC client event description
0022  * @ipc_msg_type:   IPC msg type of the event the client is interested
0023  * @cdev:       sof_client_dev of the requesting client
0024  * @callback:       Callback function of the client
0025  * @list:       item in SOF core client event list
0026  */
0027 struct sof_ipc_event_entry {
0028     u32 ipc_msg_type;
0029     struct sof_client_dev *cdev;
0030     sof_client_event_callback callback;
0031     struct list_head list;
0032 };
0033 
0034 /**
0035  * struct sof_state_event_entry - DSP panic event subscription entry
0036  * @cdev:       sof_client_dev of the requesting client
0037  * @callback:       Callback function of the client
0038  * @list:       item in SOF core client event list
0039  */
0040 struct sof_state_event_entry {
0041     struct sof_client_dev *cdev;
0042     sof_client_fw_state_callback callback;
0043     struct list_head list;
0044 };
0045 
0046 static void sof_client_auxdev_release(struct device *dev)
0047 {
0048     struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
0049     struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
0050 
0051     kfree(cdev->auxdev.dev.platform_data);
0052     kfree(cdev);
0053 }
0054 
0055 static int sof_client_dev_add_data(struct sof_client_dev *cdev, const void *data,
0056                    size_t size)
0057 {
0058     void *d = NULL;
0059 
0060     if (data) {
0061         d = kmemdup(data, size, GFP_KERNEL);
0062         if (!d)
0063             return -ENOMEM;
0064     }
0065 
0066     cdev->auxdev.dev.platform_data = d;
0067     return 0;
0068 }
0069 
0070 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
0071 static int sof_register_ipc_flood_test(struct snd_sof_dev *sdev)
0072 {
0073     int ret = 0;
0074     int i;
0075 
0076     if (sdev->pdata->ipc_type != SOF_IPC)
0077         return 0;
0078 
0079     for (i = 0; i < CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM; i++) {
0080         ret = sof_client_dev_register(sdev, "ipc_flood", i, NULL, 0);
0081         if (ret < 0)
0082             break;
0083     }
0084 
0085     if (ret) {
0086         for (; i >= 0; --i)
0087             sof_client_dev_unregister(sdev, "ipc_flood", i);
0088     }
0089 
0090     return ret;
0091 }
0092 
0093 static void sof_unregister_ipc_flood_test(struct snd_sof_dev *sdev)
0094 {
0095     int i;
0096 
0097     for (i = 0; i < CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM; i++)
0098         sof_client_dev_unregister(sdev, "ipc_flood", i);
0099 }
0100 #else
0101 static inline int sof_register_ipc_flood_test(struct snd_sof_dev *sdev)
0102 {
0103     return 0;
0104 }
0105 
0106 static inline void sof_unregister_ipc_flood_test(struct snd_sof_dev *sdev) {}
0107 #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST */
0108 
0109 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR)
0110 static int sof_register_ipc_msg_injector(struct snd_sof_dev *sdev)
0111 {
0112     return sof_client_dev_register(sdev, "msg_injector", 0, NULL, 0);
0113 }
0114 
0115 static void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev)
0116 {
0117     sof_client_dev_unregister(sdev, "msg_injector", 0);
0118 }
0119 #else
0120 static inline int sof_register_ipc_msg_injector(struct snd_sof_dev *sdev)
0121 {
0122     return 0;
0123 }
0124 
0125 static inline void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev) {}
0126 #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR */
0127 
0128 int sof_register_clients(struct snd_sof_dev *sdev)
0129 {
0130     int ret;
0131 
0132     /* Register platform independent client devices */
0133     ret = sof_register_ipc_flood_test(sdev);
0134     if (ret) {
0135         dev_err(sdev->dev, "IPC flood test client registration failed\n");
0136         return ret;
0137     }
0138 
0139     ret = sof_register_ipc_msg_injector(sdev);
0140     if (ret) {
0141         dev_err(sdev->dev, "IPC message injector client registration failed\n");
0142         goto err_msg_injector;
0143     }
0144 
0145     /* Platform depndent client device registration */
0146 
0147     if (sof_ops(sdev) && sof_ops(sdev)->register_ipc_clients)
0148         ret = sof_ops(sdev)->register_ipc_clients(sdev);
0149 
0150     if (!ret)
0151         return 0;
0152 
0153     sof_unregister_ipc_msg_injector(sdev);
0154 
0155 err_msg_injector:
0156     sof_unregister_ipc_flood_test(sdev);
0157 
0158     return ret;
0159 }
0160 
0161 void sof_unregister_clients(struct snd_sof_dev *sdev)
0162 {
0163     if (sof_ops(sdev) && sof_ops(sdev)->unregister_ipc_clients)
0164         sof_ops(sdev)->unregister_ipc_clients(sdev);
0165 
0166     sof_unregister_ipc_msg_injector(sdev);
0167     sof_unregister_ipc_flood_test(sdev);
0168 }
0169 
0170 int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id,
0171                 const void *data, size_t size)
0172 {
0173     struct auxiliary_device *auxdev;
0174     struct sof_client_dev *cdev;
0175     int ret;
0176 
0177     cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
0178     if (!cdev)
0179         return -ENOMEM;
0180 
0181     cdev->sdev = sdev;
0182     auxdev = &cdev->auxdev;
0183     auxdev->name = name;
0184     auxdev->dev.parent = sdev->dev;
0185     auxdev->dev.release = sof_client_auxdev_release;
0186     auxdev->id = id;
0187 
0188     ret = sof_client_dev_add_data(cdev, data, size);
0189     if (ret < 0)
0190         goto err_dev_add_data;
0191 
0192     ret = auxiliary_device_init(auxdev);
0193     if (ret < 0) {
0194         dev_err(sdev->dev, "failed to initialize client dev %s.%d\n", name, id);
0195         goto err_dev_init;
0196     }
0197 
0198     ret = auxiliary_device_add(&cdev->auxdev);
0199     if (ret < 0) {
0200         dev_err(sdev->dev, "failed to add client dev %s.%d\n", name, id);
0201         /*
0202          * sof_client_auxdev_release() will be invoked to free up memory
0203          * allocations through put_device()
0204          */
0205         auxiliary_device_uninit(&cdev->auxdev);
0206         return ret;
0207     }
0208 
0209     /* add to list of SOF client devices */
0210     mutex_lock(&sdev->ipc_client_mutex);
0211     list_add(&cdev->list, &sdev->ipc_client_list);
0212     mutex_unlock(&sdev->ipc_client_mutex);
0213 
0214     return 0;
0215 
0216 err_dev_init:
0217     kfree(cdev->auxdev.dev.platform_data);
0218 
0219 err_dev_add_data:
0220     kfree(cdev);
0221 
0222     return ret;
0223 }
0224 EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, SND_SOC_SOF_CLIENT);
0225 
0226 void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id)
0227 {
0228     struct sof_client_dev *cdev;
0229 
0230     mutex_lock(&sdev->ipc_client_mutex);
0231 
0232     /*
0233      * sof_client_auxdev_release() will be invoked to free up memory
0234      * allocations through put_device()
0235      */
0236     list_for_each_entry(cdev, &sdev->ipc_client_list, list) {
0237         if (!strcmp(cdev->auxdev.name, name) && cdev->auxdev.id == id) {
0238             list_del(&cdev->list);
0239             auxiliary_device_delete(&cdev->auxdev);
0240             auxiliary_device_uninit(&cdev->auxdev);
0241             break;
0242         }
0243     }
0244 
0245     mutex_unlock(&sdev->ipc_client_mutex);
0246 }
0247 EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, SND_SOC_SOF_CLIENT);
0248 
0249 int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg,
0250                   void *reply_data, size_t reply_bytes)
0251 {
0252     if (cdev->sdev->pdata->ipc_type == SOF_IPC) {
0253         struct sof_ipc_cmd_hdr *hdr = ipc_msg;
0254 
0255         return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, hdr->size,
0256                       reply_data, reply_bytes);
0257     } else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
0258         struct sof_ipc4_msg *msg = ipc_msg;
0259 
0260         return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, msg->data_size,
0261                       reply_data, reply_bytes);
0262     }
0263 
0264     return -EINVAL;
0265 }
0266 EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT);
0267 
0268 int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state)
0269 {
0270     struct auxiliary_driver *adrv;
0271     struct sof_client_dev *cdev;
0272 
0273     mutex_lock(&sdev->ipc_client_mutex);
0274 
0275     list_for_each_entry(cdev, &sdev->ipc_client_list, list) {
0276         /* Skip devices without loaded driver */
0277         if (!cdev->auxdev.dev.driver)
0278             continue;
0279 
0280         adrv = to_auxiliary_drv(cdev->auxdev.dev.driver);
0281         if (adrv->suspend)
0282             adrv->suspend(&cdev->auxdev, state);
0283     }
0284 
0285     mutex_unlock(&sdev->ipc_client_mutex);
0286 
0287     return 0;
0288 }
0289 EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, SND_SOC_SOF_CLIENT);
0290 
0291 int sof_resume_clients(struct snd_sof_dev *sdev)
0292 {
0293     struct auxiliary_driver *adrv;
0294     struct sof_client_dev *cdev;
0295 
0296     mutex_lock(&sdev->ipc_client_mutex);
0297 
0298     list_for_each_entry(cdev, &sdev->ipc_client_list, list) {
0299         /* Skip devices without loaded driver */
0300         if (!cdev->auxdev.dev.driver)
0301             continue;
0302 
0303         adrv = to_auxiliary_drv(cdev->auxdev.dev.driver);
0304         if (adrv->resume)
0305             adrv->resume(&cdev->auxdev);
0306     }
0307 
0308     mutex_unlock(&sdev->ipc_client_mutex);
0309 
0310     return 0;
0311 }
0312 EXPORT_SYMBOL_NS_GPL(sof_resume_clients, SND_SOC_SOF_CLIENT);
0313 
0314 struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev)
0315 {
0316     return cdev->sdev->debugfs_root;
0317 }
0318 EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, SND_SOC_SOF_CLIENT);
0319 
0320 /* DMA buffer allocation in client drivers must use the core SOF device */
0321 struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev)
0322 {
0323     return cdev->sdev->dev;
0324 }
0325 EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, SND_SOC_SOF_CLIENT);
0326 
0327 const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev)
0328 {
0329     struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
0330 
0331     return &sdev->fw_ready.version;
0332 }
0333 EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, SND_SOC_SOF_CLIENT);
0334 
0335 size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev)
0336 {
0337     struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
0338 
0339     return sdev->ipc->max_payload_size;
0340 }
0341 EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, SND_SOC_SOF_CLIENT);
0342 
0343 enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev)
0344 {
0345     struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
0346 
0347     return sdev->pdata->ipc_type;
0348 }
0349 EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, SND_SOC_SOF_CLIENT);
0350 
0351 /* module refcount management of SOF core */
0352 int sof_client_core_module_get(struct sof_client_dev *cdev)
0353 {
0354     struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
0355 
0356     if (!try_module_get(sdev->dev->driver->owner))
0357         return -ENODEV;
0358 
0359     return 0;
0360 }
0361 EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, SND_SOC_SOF_CLIENT);
0362 
0363 void sof_client_core_module_put(struct sof_client_dev *cdev)
0364 {
0365     struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
0366 
0367     module_put(sdev->dev->driver->owner);
0368 }
0369 EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, SND_SOC_SOF_CLIENT);
0370 
0371 /* IPC event handling */
0372 void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf)
0373 {
0374     struct sof_ipc_event_entry *event;
0375     u32 msg_type;
0376 
0377     if (sdev->pdata->ipc_type == SOF_IPC) {
0378         struct sof_ipc_cmd_hdr *hdr = msg_buf;
0379 
0380         msg_type = hdr->cmd & SOF_GLB_TYPE_MASK;
0381     } else if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
0382         struct sof_ipc4_msg *msg = msg_buf;
0383 
0384         msg_type = SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary);
0385     } else {
0386         dev_dbg_once(sdev->dev, "Not supported IPC version: %d\n",
0387                  sdev->pdata->ipc_type);
0388         return;
0389     }
0390 
0391     mutex_lock(&sdev->client_event_handler_mutex);
0392 
0393     list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) {
0394         if (event->ipc_msg_type == msg_type)
0395             event->callback(event->cdev, msg_buf);
0396     }
0397 
0398     mutex_unlock(&sdev->client_event_handler_mutex);
0399 }
0400 
0401 int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev,
0402                        u32 ipc_msg_type,
0403                        sof_client_event_callback callback)
0404 {
0405     struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
0406     struct sof_ipc_event_entry *event;
0407 
0408     if (!callback)
0409         return -EINVAL;
0410 
0411     if (cdev->sdev->pdata->ipc_type == SOF_IPC) {
0412         if (!(ipc_msg_type & SOF_GLB_TYPE_MASK))
0413             return -EINVAL;
0414     } else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
0415         if (!(ipc_msg_type & SOF_IPC4_NOTIFICATION_TYPE_MASK))
0416             return -EINVAL;
0417     } else {
0418         dev_warn(sdev->dev, "%s: Not supported IPC version: %d\n",
0419              __func__, sdev->pdata->ipc_type);
0420         return -EINVAL;
0421     }
0422 
0423     event = kmalloc(sizeof(*event), GFP_KERNEL);
0424     if (!event)
0425         return -ENOMEM;
0426 
0427     event->ipc_msg_type = ipc_msg_type;
0428     event->cdev = cdev;
0429     event->callback = callback;
0430 
0431     /* add to list of SOF client devices */
0432     mutex_lock(&sdev->client_event_handler_mutex);
0433     list_add(&event->list, &sdev->ipc_rx_handler_list);
0434     mutex_unlock(&sdev->client_event_handler_mutex);
0435 
0436     return 0;
0437 }
0438 EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, SND_SOC_SOF_CLIENT);
0439 
0440 void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev,
0441                       u32 ipc_msg_type)
0442 {
0443     struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
0444     struct sof_ipc_event_entry *event;
0445 
0446     mutex_lock(&sdev->client_event_handler_mutex);
0447 
0448     list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) {
0449         if (event->cdev == cdev && event->ipc_msg_type == ipc_msg_type) {
0450             list_del(&event->list);
0451             kfree(event);
0452             break;
0453         }
0454     }
0455 
0456     mutex_unlock(&sdev->client_event_handler_mutex);
0457 }
0458 EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, SND_SOC_SOF_CLIENT);
0459 
0460 /*DSP state notification and query */
0461 void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev)
0462 {
0463     struct sof_state_event_entry *event;
0464 
0465     mutex_lock(&sdev->client_event_handler_mutex);
0466 
0467     list_for_each_entry(event, &sdev->fw_state_handler_list, list)
0468         event->callback(event->cdev, sdev->fw_state);
0469 
0470     mutex_unlock(&sdev->client_event_handler_mutex);
0471 }
0472 
0473 int sof_client_register_fw_state_handler(struct sof_client_dev *cdev,
0474                      sof_client_fw_state_callback callback)
0475 {
0476     struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
0477     struct sof_state_event_entry *event;
0478 
0479     if (!callback)
0480         return -EINVAL;
0481 
0482     event = kmalloc(sizeof(*event), GFP_KERNEL);
0483     if (!event)
0484         return -ENOMEM;
0485 
0486     event->cdev = cdev;
0487     event->callback = callback;
0488 
0489     /* add to list of SOF client devices */
0490     mutex_lock(&sdev->client_event_handler_mutex);
0491     list_add(&event->list, &sdev->fw_state_handler_list);
0492     mutex_unlock(&sdev->client_event_handler_mutex);
0493 
0494     return 0;
0495 }
0496 EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, SND_SOC_SOF_CLIENT);
0497 
0498 void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev)
0499 {
0500     struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
0501     struct sof_state_event_entry *event;
0502 
0503     mutex_lock(&sdev->client_event_handler_mutex);
0504 
0505     list_for_each_entry(event, &sdev->fw_state_handler_list, list) {
0506         if (event->cdev == cdev) {
0507             list_del(&event->list);
0508             kfree(event);
0509             break;
0510         }
0511     }
0512 
0513     mutex_unlock(&sdev->client_event_handler_mutex);
0514 }
0515 EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, SND_SOC_SOF_CLIENT);
0516 
0517 enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev)
0518 {
0519     struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
0520 
0521     return sdev->fw_state;
0522 }
0523 EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, SND_SOC_SOF_CLIENT);