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 */ 28 struct 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 */ 41 struct sof_state_event_entry { 42 struct sof_client_dev *cdev; 43 sof_client_fw_state_callback callback; 44 struct list_head list; 45 }; 46 47 static 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 56 static 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) 72 static 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 94 static 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 102 static inline int sof_register_ipc_flood_test(struct snd_sof_dev *sdev) 103 { 104 return 0; 105 } 106 107 static 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) 111 static 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 116 static void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev) 117 { 118 sof_client_dev_unregister(sdev, "msg_injector", 0); 119 } 120 #else 121 static inline int sof_register_ipc_msg_injector(struct snd_sof_dev *sdev) 122 { 123 return 0; 124 } 125 126 static inline void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev) {} 127 #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR */ 128 129 int 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 159 err_msg_injector: 160 sof_unregister_ipc_flood_test(sdev); 161 162 return ret; 163 } 164 165 void 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 174 int 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 220 err_dev_init: 221 kfree(cdev->auxdev.dev.platform_data); 222 223 err_dev_add_data: 224 kfree(cdev); 225 226 return ret; 227 } 228 EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, SND_SOC_SOF_CLIENT); 229 230 void 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 } 251 EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, SND_SOC_SOF_CLIENT); 252 253 int 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 } 270 EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT); 271 272 int 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 } 289 EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, SND_SOC_SOF_CLIENT); 290 291 #ifdef CONFIG_SND_SOC_SOF_INTEL_IPC4 292 struct 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 } 302 EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, SND_SOC_SOF_CLIENT); 303 #endif 304 305 int 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 } 326 EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, SND_SOC_SOF_CLIENT); 327 328 int 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 } 349 EXPORT_SYMBOL_NS_GPL(sof_resume_clients, SND_SOC_SOF_CLIENT); 350 351 struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev) 352 { 353 return cdev->sdev->debugfs_root; 354 } 355 EXPORT_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 */ 358 struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev) 359 { 360 return cdev->sdev->dev; 361 } 362 EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, SND_SOC_SOF_CLIENT); 363 364 const 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 } 370 EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, SND_SOC_SOF_CLIENT); 371 372 size_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 } 378 EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, SND_SOC_SOF_CLIENT); 379 380 enum 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 } 386 EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, SND_SOC_SOF_CLIENT); 387 388 /* module refcount management of SOF core */ 389 int 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 } 398 EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, SND_SOC_SOF_CLIENT); 399 400 void 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 } 406 EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, SND_SOC_SOF_CLIENT); 407 408 /* IPC event handling */ 409 void 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 438 int 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 } 475 EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, SND_SOC_SOF_CLIENT); 476 477 void 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 } 495 EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, SND_SOC_SOF_CLIENT); 496 497 /*DSP state notification and query */ 498 void 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 510 int 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 } 533 EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, SND_SOC_SOF_CLIENT); 534 535 void 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 } 552 EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, SND_SOC_SOF_CLIENT); 553 554 enum 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 } 560 EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, SND_SOC_SOF_CLIENT); 561