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