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