at v6.13 16 kB view raw
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 */ 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_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 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_TYPE_3) 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 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 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_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} 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 (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} 323EXPORT_SYMBOL_NS_GPL(sof_client_ipc_rx_message, "SND_SOC_SOF_CLIENT"); 324 325int 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} 342EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, "SND_SOC_SOF_CLIENT"); 343 344#ifdef CONFIG_SND_SOC_SOF_IPC4 345struct 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} 355EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, "SND_SOC_SOF_CLIENT"); 356#endif 357 358int 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} 379EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, "SND_SOC_SOF_CLIENT"); 380 381int 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} 402EXPORT_SYMBOL_NS_GPL(sof_resume_clients, "SND_SOC_SOF_CLIENT"); 403 404struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev) 405{ 406 return cdev->sdev->debugfs_root; 407} 408EXPORT_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 */ 411struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev) 412{ 413 return cdev->sdev->dev; 414} 415EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, "SND_SOC_SOF_CLIENT"); 416 417const 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} 423EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, "SND_SOC_SOF_CLIENT"); 424 425size_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} 431EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, "SND_SOC_SOF_CLIENT"); 432 433enum 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} 439EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, "SND_SOC_SOF_CLIENT"); 440 441/* module refcount management of SOF core */ 442int 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} 451EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, "SND_SOC_SOF_CLIENT"); 452 453void 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} 459EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, "SND_SOC_SOF_CLIENT"); 460 461/* IPC event handling */ 462void 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 491int 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} 528EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, "SND_SOC_SOF_CLIENT"); 529 530void 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} 548EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, "SND_SOC_SOF_CLIENT"); 549 550/*DSP state notification and query */ 551void 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 563int 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} 586EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, "SND_SOC_SOF_CLIENT"); 587 588void 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} 605EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, "SND_SOC_SOF_CLIENT"); 606 607enum 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} 613EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, "SND_SOC_SOF_CLIENT");