1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2022 Intel Corporation 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 */ 29 struct 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 */ 42 struct sof_state_event_entry { 43 struct sof_client_dev *cdev; 44 sof_client_fw_state_callback callback; 45 struct list_head list; 46 }; 47 48 static 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 57 static 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) 73 static 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_TYPE_3) 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 95 static 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 103 static inline int sof_register_ipc_flood_test(struct snd_sof_dev *sdev) 104 { 105 return 0; 106 } 107 108 static 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) 112 static 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 117 static void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev) 118 { 119 sof_client_dev_unregister(sdev, "msg_injector", 0); 120 } 121 #else 122 static inline int sof_register_ipc_msg_injector(struct snd_sof_dev *sdev) 123 { 124 return 0; 125 } 126 127 static 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) 131 static 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_TYPE_3) 135 return 0; 136 137 return sof_client_dev_register(sdev, "kernel_injector", 0, NULL, 0); 138 } 139 140 static void sof_unregister_ipc_kernel_injector(struct snd_sof_dev *sdev) 141 { 142 sof_client_dev_unregister(sdev, "kernel_injector", 0); 143 } 144 #else 145 static inline int sof_register_ipc_kernel_injector(struct snd_sof_dev *sdev) 146 { 147 return 0; 148 } 149 150 static inline void sof_unregister_ipc_kernel_injector(struct snd_sof_dev *sdev) {} 151 #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_KERNEL_INJECTOR */ 152 153 int 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 dependent 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 189 err_kernel_injector: 190 sof_unregister_ipc_msg_injector(sdev); 191 192 err_msg_injector: 193 sof_unregister_ipc_flood_test(sdev); 194 195 return ret; 196 } 197 198 void 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 208 int 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 254 err_dev_init: 255 kfree(cdev->auxdev.dev.platform_data); 256 257 err_dev_add_data: 258 kfree(cdev); 259 260 return ret; 261 } 262 EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, SND_SOC_SOF_CLIENT); 263 264 void 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 } 285 EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, SND_SOC_SOF_CLIENT); 286 287 int 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_TYPE_3) { 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_IPC_TYPE_4) { 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 } 304 EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT); 305 306 int sof_client_ipc_rx_message(struct sof_client_dev *cdev, void *ipc_msg, void *msg_buf) 307 { 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; 311 312 if (hdr->size < sizeof(hdr)) { 313 dev_err(cdev->sdev->dev, "The received message size is invalid\n"); 314 return -EINVAL; 315 } 316 317 sof_ipc3_do_rx_work(cdev->sdev, ipc_msg, msg_buf); 318 return 0; 319 } 320 321 return -EOPNOTSUPP; 322 } 323 EXPORT_SYMBOL_NS_GPL(sof_client_ipc_rx_message, SND_SOC_SOF_CLIENT); 324 325 int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg, 326 bool set) 327 { 328 if (cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { 329 struct sof_ipc_cmd_hdr *hdr = ipc_msg; 330 331 return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg, hdr->size, 332 set); 333 } else if (cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { 334 struct sof_ipc4_msg *msg = ipc_msg; 335 336 return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg, 337 msg->data_size, set); 338 } 339 340 return -EINVAL; 341 } 342 EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, SND_SOC_SOF_CLIENT); 343 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) 346 { 347 struct snd_sof_dev *sdev = c->sdev; 348 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"); 352 353 return NULL; 354 } 355 EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, SND_SOC_SOF_CLIENT); 356 #endif 357 358 int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state) 359 { 360 const struct auxiliary_driver *adrv; 361 struct sof_client_dev *cdev; 362 363 mutex_lock(&sdev->ipc_client_mutex); 364 365 list_for_each_entry(cdev, &sdev->ipc_client_list, list) { 366 /* Skip devices without loaded driver */ 367 if (!cdev->auxdev.dev.driver) 368 continue; 369 370 adrv = to_auxiliary_drv(cdev->auxdev.dev.driver); 371 if (adrv->suspend) 372 adrv->suspend(&cdev->auxdev, state); 373 } 374 375 mutex_unlock(&sdev->ipc_client_mutex); 376 377 return 0; 378 } 379 EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, SND_SOC_SOF_CLIENT); 380 381 int sof_resume_clients(struct snd_sof_dev *sdev) 382 { 383 const struct auxiliary_driver *adrv; 384 struct sof_client_dev *cdev; 385 386 mutex_lock(&sdev->ipc_client_mutex); 387 388 list_for_each_entry(cdev, &sdev->ipc_client_list, list) { 389 /* Skip devices without loaded driver */ 390 if (!cdev->auxdev.dev.driver) 391 continue; 392 393 adrv = to_auxiliary_drv(cdev->auxdev.dev.driver); 394 if (adrv->resume) 395 adrv->resume(&cdev->auxdev); 396 } 397 398 mutex_unlock(&sdev->ipc_client_mutex); 399 400 return 0; 401 } 402 EXPORT_SYMBOL_NS_GPL(sof_resume_clients, SND_SOC_SOF_CLIENT); 403 404 struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev) 405 { 406 return cdev->sdev->debugfs_root; 407 } 408 EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, SND_SOC_SOF_CLIENT); 409 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) 412 { 413 return cdev->sdev->dev; 414 } 415 EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, SND_SOC_SOF_CLIENT); 416 417 const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev) 418 { 419 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 420 421 return &sdev->fw_ready.version; 422 } 423 EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, SND_SOC_SOF_CLIENT); 424 425 size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev) 426 { 427 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 428 429 return sdev->ipc->max_payload_size; 430 } 431 EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, SND_SOC_SOF_CLIENT); 432 433 enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev) 434 { 435 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 436 437 return sdev->pdata->ipc_type; 438 } 439 EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, SND_SOC_SOF_CLIENT); 440 441 /* module refcount management of SOF core */ 442 int sof_client_core_module_get(struct sof_client_dev *cdev) 443 { 444 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 445 446 if (!try_module_get(sdev->dev->driver->owner)) 447 return -ENODEV; 448 449 return 0; 450 } 451 EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, SND_SOC_SOF_CLIENT); 452 453 void sof_client_core_module_put(struct sof_client_dev *cdev) 454 { 455 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 456 457 module_put(sdev->dev->driver->owner); 458 } 459 EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, SND_SOC_SOF_CLIENT); 460 461 /* IPC event handling */ 462 void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf) 463 { 464 struct sof_ipc_event_entry *event; 465 u32 msg_type; 466 467 if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { 468 struct sof_ipc_cmd_hdr *hdr = msg_buf; 469 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; 473 474 msg_type = SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary); 475 } else { 476 dev_dbg_once(sdev->dev, "Not supported IPC version: %d\n", 477 sdev->pdata->ipc_type); 478 return; 479 } 480 481 mutex_lock(&sdev->client_event_handler_mutex); 482 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); 486 } 487 488 mutex_unlock(&sdev->client_event_handler_mutex); 489 } 490 491 int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, 492 u32 ipc_msg_type, 493 sof_client_event_callback callback) 494 { 495 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 496 struct sof_ipc_event_entry *event; 497 498 if (!callback) 499 return -EINVAL; 500 501 if (cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { 502 if (!(ipc_msg_type & SOF_GLB_TYPE_MASK)) 503 return -EINVAL; 504 } else if (cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { 505 if (!(ipc_msg_type & SOF_IPC4_NOTIFICATION_TYPE_MASK)) 506 return -EINVAL; 507 } else { 508 dev_warn(sdev->dev, "%s: Not supported IPC version: %d\n", 509 __func__, sdev->pdata->ipc_type); 510 return -EINVAL; 511 } 512 513 event = kmalloc(sizeof(*event), GFP_KERNEL); 514 if (!event) 515 return -ENOMEM; 516 517 event->ipc_msg_type = ipc_msg_type; 518 event->cdev = cdev; 519 event->callback = callback; 520 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); 525 526 return 0; 527 } 528 EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, SND_SOC_SOF_CLIENT); 529 530 void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, 531 u32 ipc_msg_type) 532 { 533 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 534 struct sof_ipc_event_entry *event; 535 536 mutex_lock(&sdev->client_event_handler_mutex); 537 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); 541 kfree(event); 542 break; 543 } 544 } 545 546 mutex_unlock(&sdev->client_event_handler_mutex); 547 } 548 EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, SND_SOC_SOF_CLIENT); 549 550 /*DSP state notification and query */ 551 void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev) 552 { 553 struct sof_state_event_entry *event; 554 555 mutex_lock(&sdev->client_event_handler_mutex); 556 557 list_for_each_entry(event, &sdev->fw_state_handler_list, list) 558 event->callback(event->cdev, sdev->fw_state); 559 560 mutex_unlock(&sdev->client_event_handler_mutex); 561 } 562 563 int sof_client_register_fw_state_handler(struct sof_client_dev *cdev, 564 sof_client_fw_state_callback callback) 565 { 566 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 567 struct sof_state_event_entry *event; 568 569 if (!callback) 570 return -EINVAL; 571 572 event = kmalloc(sizeof(*event), GFP_KERNEL); 573 if (!event) 574 return -ENOMEM; 575 576 event->cdev = cdev; 577 event->callback = callback; 578 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); 583 584 return 0; 585 } 586 EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, SND_SOC_SOF_CLIENT); 587 588 void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev) 589 { 590 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 591 struct sof_state_event_entry *event; 592 593 mutex_lock(&sdev->client_event_handler_mutex); 594 595 list_for_each_entry(event, &sdev->fw_state_handler_list, list) { 596 if (event->cdev == cdev) { 597 list_del(&event->list); 598 kfree(event); 599 break; 600 } 601 } 602 603 mutex_unlock(&sdev->client_event_handler_mutex); 604 } 605 EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, SND_SOC_SOF_CLIENT); 606 607 enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev) 608 { 609 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 610 611 return sdev->fw_state; 612 } 613 EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, SND_SOC_SOF_CLIENT); 614
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.