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