at v6.4 560 lines 15 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2// 3// Copyright(c) 2022 Intel Corporation. All rights reserved. 4// 5// Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> 6// Peter Ujfalusi <peter.ujfalusi@linux.intel.com> 7// 8 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> 16#include "ops.h" 17#include "sof-client.h" 18#include "sof-priv.h" 19#include "ipc4-priv.h" 20 21/** 22 * struct sof_ipc_event_entry - IPC client event description 23 * @ipc_msg_type: IPC msg type of the event the client is interested 24 * @cdev: sof_client_dev of the requesting client 25 * @callback: Callback function of the client 26 * @list: item in SOF core client event list 27 */ 28struct sof_ipc_event_entry { 29 u32 ipc_msg_type; 30 struct sof_client_dev *cdev; 31 sof_client_event_callback callback; 32 struct list_head list; 33}; 34 35/** 36 * struct sof_state_event_entry - DSP panic event subscription entry 37 * @cdev: sof_client_dev of the requesting client 38 * @callback: Callback function of the client 39 * @list: item in SOF core client event list 40 */ 41struct sof_state_event_entry { 42 struct sof_client_dev *cdev; 43 sof_client_fw_state_callback callback; 44 struct list_head list; 45}; 46 47static void sof_client_auxdev_release(struct device *dev) 48{ 49 struct auxiliary_device *auxdev = to_auxiliary_dev(dev); 50 struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); 51 52 kfree(cdev->auxdev.dev.platform_data); 53 kfree(cdev); 54} 55 56static int sof_client_dev_add_data(struct sof_client_dev *cdev, const void *data, 57 size_t size) 58{ 59 void *d = NULL; 60 61 if (data) { 62 d = kmemdup(data, size, GFP_KERNEL); 63 if (!d) 64 return -ENOMEM; 65 } 66 67 cdev->auxdev.dev.platform_data = d; 68 return 0; 69} 70 71#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 72static int sof_register_ipc_flood_test(struct snd_sof_dev *sdev) 73{ 74 int ret = 0; 75 int i; 76 77 if (sdev->pdata->ipc_type != SOF_IPC) 78 return 0; 79 80 for (i = 0; i < CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM; i++) { 81 ret = sof_client_dev_register(sdev, "ipc_flood", i, NULL, 0); 82 if (ret < 0) 83 break; 84 } 85 86 if (ret) { 87 for (; i >= 0; --i) 88 sof_client_dev_unregister(sdev, "ipc_flood", i); 89 } 90 91 return ret; 92} 93 94static void sof_unregister_ipc_flood_test(struct snd_sof_dev *sdev) 95{ 96 int i; 97 98 for (i = 0; i < CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM; i++) 99 sof_client_dev_unregister(sdev, "ipc_flood", i); 100} 101#else 102static inline int sof_register_ipc_flood_test(struct snd_sof_dev *sdev) 103{ 104 return 0; 105} 106 107static inline void sof_unregister_ipc_flood_test(struct snd_sof_dev *sdev) {} 108#endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST */ 109 110#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) 111static int sof_register_ipc_msg_injector(struct snd_sof_dev *sdev) 112{ 113 return sof_client_dev_register(sdev, "msg_injector", 0, NULL, 0); 114} 115 116static void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev) 117{ 118 sof_client_dev_unregister(sdev, "msg_injector", 0); 119} 120#else 121static inline int sof_register_ipc_msg_injector(struct snd_sof_dev *sdev) 122{ 123 return 0; 124} 125 126static inline void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev) {} 127#endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR */ 128 129int sof_register_clients(struct snd_sof_dev *sdev) 130{ 131 int ret; 132 133 if (sdev->dspless_mode_selected) 134 return 0; 135 136 /* Register platform independent client devices */ 137 ret = sof_register_ipc_flood_test(sdev); 138 if (ret) { 139 dev_err(sdev->dev, "IPC flood test client registration failed\n"); 140 return ret; 141 } 142 143 ret = sof_register_ipc_msg_injector(sdev); 144 if (ret) { 145 dev_err(sdev->dev, "IPC message injector client registration failed\n"); 146 goto err_msg_injector; 147 } 148 149 /* Platform depndent client device registration */ 150 151 if (sof_ops(sdev) && sof_ops(sdev)->register_ipc_clients) 152 ret = sof_ops(sdev)->register_ipc_clients(sdev); 153 154 if (!ret) 155 return 0; 156 157 sof_unregister_ipc_msg_injector(sdev); 158 159err_msg_injector: 160 sof_unregister_ipc_flood_test(sdev); 161 162 return ret; 163} 164 165void sof_unregister_clients(struct snd_sof_dev *sdev) 166{ 167 if (sof_ops(sdev) && sof_ops(sdev)->unregister_ipc_clients) 168 sof_ops(sdev)->unregister_ipc_clients(sdev); 169 170 sof_unregister_ipc_msg_injector(sdev); 171 sof_unregister_ipc_flood_test(sdev); 172} 173 174int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, 175 const void *data, size_t size) 176{ 177 struct auxiliary_device *auxdev; 178 struct sof_client_dev *cdev; 179 int ret; 180 181 cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); 182 if (!cdev) 183 return -ENOMEM; 184 185 cdev->sdev = sdev; 186 auxdev = &cdev->auxdev; 187 auxdev->name = name; 188 auxdev->dev.parent = sdev->dev; 189 auxdev->dev.release = sof_client_auxdev_release; 190 auxdev->id = id; 191 192 ret = sof_client_dev_add_data(cdev, data, size); 193 if (ret < 0) 194 goto err_dev_add_data; 195 196 ret = auxiliary_device_init(auxdev); 197 if (ret < 0) { 198 dev_err(sdev->dev, "failed to initialize client dev %s.%d\n", name, id); 199 goto err_dev_init; 200 } 201 202 ret = auxiliary_device_add(&cdev->auxdev); 203 if (ret < 0) { 204 dev_err(sdev->dev, "failed to add client dev %s.%d\n", name, id); 205 /* 206 * sof_client_auxdev_release() will be invoked to free up memory 207 * allocations through put_device() 208 */ 209 auxiliary_device_uninit(&cdev->auxdev); 210 return ret; 211 } 212 213 /* add to list of SOF client devices */ 214 mutex_lock(&sdev->ipc_client_mutex); 215 list_add(&cdev->list, &sdev->ipc_client_list); 216 mutex_unlock(&sdev->ipc_client_mutex); 217 218 return 0; 219 220err_dev_init: 221 kfree(cdev->auxdev.dev.platform_data); 222 223err_dev_add_data: 224 kfree(cdev); 225 226 return ret; 227} 228EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, SND_SOC_SOF_CLIENT); 229 230void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id) 231{ 232 struct sof_client_dev *cdev; 233 234 mutex_lock(&sdev->ipc_client_mutex); 235 236 /* 237 * sof_client_auxdev_release() will be invoked to free up memory 238 * allocations through put_device() 239 */ 240 list_for_each_entry(cdev, &sdev->ipc_client_list, list) { 241 if (!strcmp(cdev->auxdev.name, name) && cdev->auxdev.id == id) { 242 list_del(&cdev->list); 243 auxiliary_device_delete(&cdev->auxdev); 244 auxiliary_device_uninit(&cdev->auxdev); 245 break; 246 } 247 } 248 249 mutex_unlock(&sdev->ipc_client_mutex); 250} 251EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, SND_SOC_SOF_CLIENT); 252 253int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, 254 void *reply_data, size_t reply_bytes) 255{ 256 if (cdev->sdev->pdata->ipc_type == SOF_IPC) { 257 struct sof_ipc_cmd_hdr *hdr = ipc_msg; 258 259 return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, hdr->size, 260 reply_data, reply_bytes); 261 } else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) { 262 struct sof_ipc4_msg *msg = ipc_msg; 263 264 return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, msg->data_size, 265 reply_data, reply_bytes); 266 } 267 268 return -EINVAL; 269} 270EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT); 271 272int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg, 273 bool set) 274{ 275 if (cdev->sdev->pdata->ipc_type == SOF_IPC) { 276 struct sof_ipc_cmd_hdr *hdr = ipc_msg; 277 278 return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg, hdr->size, 279 set); 280 } else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) { 281 struct sof_ipc4_msg *msg = ipc_msg; 282 283 return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg, 284 msg->data_size, set); 285 } 286 287 return -EINVAL; 288} 289EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, SND_SOC_SOF_CLIENT); 290 291#ifdef CONFIG_SND_SOC_SOF_INTEL_IPC4 292struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *uuid) 293{ 294 struct snd_sof_dev *sdev = c->sdev; 295 296 if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) 297 return sof_ipc4_find_module_by_uuid(sdev, uuid); 298 dev_err(sdev->dev, "Only supported with IPC4\n"); 299 300 return NULL; 301} 302EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, SND_SOC_SOF_CLIENT); 303#endif 304 305int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state) 306{ 307 struct auxiliary_driver *adrv; 308 struct sof_client_dev *cdev; 309 310 mutex_lock(&sdev->ipc_client_mutex); 311 312 list_for_each_entry(cdev, &sdev->ipc_client_list, list) { 313 /* Skip devices without loaded driver */ 314 if (!cdev->auxdev.dev.driver) 315 continue; 316 317 adrv = to_auxiliary_drv(cdev->auxdev.dev.driver); 318 if (adrv->suspend) 319 adrv->suspend(&cdev->auxdev, state); 320 } 321 322 mutex_unlock(&sdev->ipc_client_mutex); 323 324 return 0; 325} 326EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, SND_SOC_SOF_CLIENT); 327 328int sof_resume_clients(struct snd_sof_dev *sdev) 329{ 330 struct auxiliary_driver *adrv; 331 struct sof_client_dev *cdev; 332 333 mutex_lock(&sdev->ipc_client_mutex); 334 335 list_for_each_entry(cdev, &sdev->ipc_client_list, list) { 336 /* Skip devices without loaded driver */ 337 if (!cdev->auxdev.dev.driver) 338 continue; 339 340 adrv = to_auxiliary_drv(cdev->auxdev.dev.driver); 341 if (adrv->resume) 342 adrv->resume(&cdev->auxdev); 343 } 344 345 mutex_unlock(&sdev->ipc_client_mutex); 346 347 return 0; 348} 349EXPORT_SYMBOL_NS_GPL(sof_resume_clients, SND_SOC_SOF_CLIENT); 350 351struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev) 352{ 353 return cdev->sdev->debugfs_root; 354} 355EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, SND_SOC_SOF_CLIENT); 356 357/* DMA buffer allocation in client drivers must use the core SOF device */ 358struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev) 359{ 360 return cdev->sdev->dev; 361} 362EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, SND_SOC_SOF_CLIENT); 363 364const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev) 365{ 366 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 367 368 return &sdev->fw_ready.version; 369} 370EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, SND_SOC_SOF_CLIENT); 371 372size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev) 373{ 374 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 375 376 return sdev->ipc->max_payload_size; 377} 378EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, SND_SOC_SOF_CLIENT); 379 380enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev) 381{ 382 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 383 384 return sdev->pdata->ipc_type; 385} 386EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, SND_SOC_SOF_CLIENT); 387 388/* module refcount management of SOF core */ 389int sof_client_core_module_get(struct sof_client_dev *cdev) 390{ 391 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 392 393 if (!try_module_get(sdev->dev->driver->owner)) 394 return -ENODEV; 395 396 return 0; 397} 398EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, SND_SOC_SOF_CLIENT); 399 400void sof_client_core_module_put(struct sof_client_dev *cdev) 401{ 402 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 403 404 module_put(sdev->dev->driver->owner); 405} 406EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, SND_SOC_SOF_CLIENT); 407 408/* IPC event handling */ 409void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf) 410{ 411 struct sof_ipc_event_entry *event; 412 u32 msg_type; 413 414 if (sdev->pdata->ipc_type == SOF_IPC) { 415 struct sof_ipc_cmd_hdr *hdr = msg_buf; 416 417 msg_type = hdr->cmd & SOF_GLB_TYPE_MASK; 418 } else if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { 419 struct sof_ipc4_msg *msg = msg_buf; 420 421 msg_type = SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary); 422 } else { 423 dev_dbg_once(sdev->dev, "Not supported IPC version: %d\n", 424 sdev->pdata->ipc_type); 425 return; 426 } 427 428 mutex_lock(&sdev->client_event_handler_mutex); 429 430 list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) { 431 if (event->ipc_msg_type == msg_type) 432 event->callback(event->cdev, msg_buf); 433 } 434 435 mutex_unlock(&sdev->client_event_handler_mutex); 436} 437 438int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, 439 u32 ipc_msg_type, 440 sof_client_event_callback callback) 441{ 442 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 443 struct sof_ipc_event_entry *event; 444 445 if (!callback) 446 return -EINVAL; 447 448 if (cdev->sdev->pdata->ipc_type == SOF_IPC) { 449 if (!(ipc_msg_type & SOF_GLB_TYPE_MASK)) 450 return -EINVAL; 451 } else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) { 452 if (!(ipc_msg_type & SOF_IPC4_NOTIFICATION_TYPE_MASK)) 453 return -EINVAL; 454 } else { 455 dev_warn(sdev->dev, "%s: Not supported IPC version: %d\n", 456 __func__, sdev->pdata->ipc_type); 457 return -EINVAL; 458 } 459 460 event = kmalloc(sizeof(*event), GFP_KERNEL); 461 if (!event) 462 return -ENOMEM; 463 464 event->ipc_msg_type = ipc_msg_type; 465 event->cdev = cdev; 466 event->callback = callback; 467 468 /* add to list of SOF client devices */ 469 mutex_lock(&sdev->client_event_handler_mutex); 470 list_add(&event->list, &sdev->ipc_rx_handler_list); 471 mutex_unlock(&sdev->client_event_handler_mutex); 472 473 return 0; 474} 475EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, SND_SOC_SOF_CLIENT); 476 477void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, 478 u32 ipc_msg_type) 479{ 480 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 481 struct sof_ipc_event_entry *event; 482 483 mutex_lock(&sdev->client_event_handler_mutex); 484 485 list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) { 486 if (event->cdev == cdev && event->ipc_msg_type == ipc_msg_type) { 487 list_del(&event->list); 488 kfree(event); 489 break; 490 } 491 } 492 493 mutex_unlock(&sdev->client_event_handler_mutex); 494} 495EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, SND_SOC_SOF_CLIENT); 496 497/*DSP state notification and query */ 498void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev) 499{ 500 struct sof_state_event_entry *event; 501 502 mutex_lock(&sdev->client_event_handler_mutex); 503 504 list_for_each_entry(event, &sdev->fw_state_handler_list, list) 505 event->callback(event->cdev, sdev->fw_state); 506 507 mutex_unlock(&sdev->client_event_handler_mutex); 508} 509 510int sof_client_register_fw_state_handler(struct sof_client_dev *cdev, 511 sof_client_fw_state_callback callback) 512{ 513 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 514 struct sof_state_event_entry *event; 515 516 if (!callback) 517 return -EINVAL; 518 519 event = kmalloc(sizeof(*event), GFP_KERNEL); 520 if (!event) 521 return -ENOMEM; 522 523 event->cdev = cdev; 524 event->callback = callback; 525 526 /* add to list of SOF client devices */ 527 mutex_lock(&sdev->client_event_handler_mutex); 528 list_add(&event->list, &sdev->fw_state_handler_list); 529 mutex_unlock(&sdev->client_event_handler_mutex); 530 531 return 0; 532} 533EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, SND_SOC_SOF_CLIENT); 534 535void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev) 536{ 537 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 538 struct sof_state_event_entry *event; 539 540 mutex_lock(&sdev->client_event_handler_mutex); 541 542 list_for_each_entry(event, &sdev->fw_state_handler_list, list) { 543 if (event->cdev == cdev) { 544 list_del(&event->list); 545 kfree(event); 546 break; 547 } 548 } 549 550 mutex_unlock(&sdev->client_event_handler_mutex); 551} 552EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, SND_SOC_SOF_CLIENT); 553 554enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev) 555{ 556 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 557 558 return sdev->fw_state; 559} 560EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, SND_SOC_SOF_CLIENT);