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