1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2022 Intel Corporation. All rights reserved.
4 //
5 // Author: Jaroslaw Stelter <jaroslaw.stelter@intel.com>
6 // Pawel Dobrowolski <pawelx.dobrowolski@intel.com>
7 //
8
9 /*
10 * 3-rd party modules do not have access to component device runtime data.
11 * System service API used by these modules require notification handling
12 * based on base FW message management. Therefore this code expose notification
13 * calls aligned with cAVS/ACE System service API requirements.
14 */
15 #include <rtos/sof.h>
16 #include <sof/list.h>
17 #include <sof/ipc/msg.h>
18 #include <sof/lib/memory.h>
19 #include <sof/lib_manager.h>
20
21 LOG_MODULE_DECLARE(lib_manager, LOG_LEVEL_INFO);
22
lib_notif_msg_init(uint32_t header,uint32_t size)23 struct ipc_msg *lib_notif_msg_init(uint32_t header, uint32_t size)
24 {
25 struct ipc_msg *msg = NULL;
26 struct ipc_lib_msg *msg_pool_elem;
27 struct ext_library *ext_lib = ext_lib_get();
28 struct ipc_lib_msg *lib_notif = ext_lib->lib_notif_pool;
29
30 /* If list not empty search for free notification handle */
31 if (lib_notif && !list_is_empty(&lib_notif->list)) {
32 struct list_item *list_elem;
33 /* Search for not used message handle */
34 list_for_item(list_elem, &lib_notif->list) {
35 msg_pool_elem = container_of(list_elem, struct ipc_lib_msg, list);
36 if (msg_pool_elem->msg && list_is_empty(&msg_pool_elem->msg->list)) {
37 msg = msg_pool_elem->msg;
38 break;
39 }
40 }
41 }
42
43 if (!msg) {
44 k_spinlock_key_t key;
45 /* No free element or list empty, create new handle */
46 if (ext_lib->lib_notif_count > LIB_MANAGER_LIB_NOTIX_MAX_COUNT) {
47 tr_dbg(&lib_manager_tr, "lib_nofig_msg_init() LIB_MANAGER_LIB_NOTIX_MAX_COUNT < %d",
48 ext_lib->lib_notif_count);
49 return NULL;
50 }
51
52 msg_pool_elem = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0,
53 SOF_MEM_CAPS_RAM, sizeof(*msg_pool_elem));
54 if (!msg_pool_elem)
55 return NULL;
56 msg = ipc_msg_init(header, SRAM_OUTBOX_SIZE);
57 if (!msg) {
58 rfree(msg_pool_elem);
59 return NULL;
60 }
61 msg_pool_elem->msg = msg;
62 ext_lib->lib_notif_count++;
63 list_init(&msg_pool_elem->list);
64 /* Check if there is no rece between modules on separate cores */
65 if (ext_lib->lib_notif_count > 1) {
66 key = k_spin_lock(&ext_lib->lock);
67 list_item_append(&msg_pool_elem->list, &lib_notif->list);
68 k_spin_unlock(&ext_lib->lock, key);
69 } else {
70 ext_lib->lib_notif_pool = msg_pool_elem;
71 }
72 }
73 /* Update header and size, since message handle can be reused */
74 msg->header = header;
75 msg->tx_size = size;
76 return msg;
77 }
78
lib_notif_msg_send(struct ipc_msg * msg)79 void lib_notif_msg_send(struct ipc_msg *msg)
80 {
81 ipc_msg_send(msg, msg->tx_data, false);
82 lib_notif_msg_clean(true);
83 }
84
lib_notif_msg_clean(bool leave_one_handle)85 void lib_notif_msg_clean(bool leave_one_handle)
86 {
87 struct list_item *list_elem, *list_tmp;
88 struct ipc_lib_msg *msg_pool_elem;
89 struct ext_library *ext_lib = ext_lib_get();
90 struct ipc_lib_msg *lib_notif = ext_lib->lib_notif_pool;
91
92 /* Free all unused elements except the last one */
93 list_for_item_safe(list_elem, list_tmp, &lib_notif->list) {
94 msg_pool_elem = container_of(list_elem, struct ipc_lib_msg, list);
95 assert(msg_pool_elem->msg);
96
97 if (list_is_empty(&msg_pool_elem->msg->list)) {
98 k_spinlock_key_t key;
99
100 key = k_spin_lock(&ext_lib->lock);
101 list_item_del(&msg_pool_elem->list);
102 k_spin_unlock(&ext_lib->lock, key);
103 ipc_msg_free(msg_pool_elem->msg);
104 rfree(msg_pool_elem);
105 ext_lib->lib_notif_count--;
106 }
107 }
108
109 /* Remove last handle - this should happen when there is no external libraries */
110 if (!leave_one_handle && (list_is_empty(&lib_notif->list))) {
111 k_spinlock_key_t key;
112
113 ipc_msg_free(lib_notif->msg);
114 key = k_spin_lock(&ext_lib->lock);
115 list_item_del(&lib_notif->list);
116 k_spin_unlock(&ext_lib->lock, key);
117 rfree(lib_notif);
118 ext_lib->lib_notif_pool = NULL;
119 ext_lib->lib_notif_count--;
120 }
121 }
122