1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3  * Copyright (c) 2023 Intel Corporation
4  *
5  * Author: Krzysztof Frydryk <krzysztofx.frydryk@intel.com>
6  */
7 
8 #ifndef __SOF_LIB_AMS_H__
9 #define __SOF_LIB_AMS_H__
10 
11 #include <errno.h>
12 #include <rtos/task.h>
13 #include <ipc/topology.h>
14 #include <rtos/alloc.h>
15 #include <sof/coherent.h>
16 #include <sof/lib/uuid.h>
17 
18 /* Reserved value "does not exist" or "unassigned" value for msg types */
19 #define AMS_INVALID_MSG_TYPE 0
20 /* Reserved value "does not exist" or "unassigned" value for slots */
21 #define AMS_INVALID_SLOT 0xFF
22 /* Wildcard for module_id and instance_id values */
23 #define AMS_ANY_ID 0xFFFF
24 
25 /* max number of message UUIDs */
26 #define AMS_SERVICE_UUID_TABLE_SIZE 16
27 /* max number of async message routes */
28 #define AMS_ROUTING_TABLE_SIZE 16
29 /* Space allocated for async message content*/
30 #define AMS_MAX_MSG_SIZE 0x1000
31 
32 /* Size of slots message, module id and instance id */
33 #define AMS_SLOT_SIZE(msg) (AMS_MESSAGE_SIZE(msg) + sizeof(uint16_t) * 2)
34 #define AMS_MESSAGE_SIZE(msg) (sizeof(*msg) - sizeof(char) + (sizeof(char) * (msg->message_length)))
35 
36 /**
37  * \brief IXC message payload
38  *
39  * ams_message_payload - contains the actual Async Msg payload
40  */
41 struct ams_message_payload {
42 	/* Message IDs are assigned dynamically on new message entry creation
43 	 * For a new payload should be acquired by ams_get_message_type_id
44 	 */
45 	uint32_t message_type_id;
46 	/* Producers module ID */
47 	uint16_t producer_module_id;
48 	/* Producers instance ID */
49 	uint16_t producer_instance_id;
50 	/* Message length */
51 	uint32_t message_length;
52 	/* Message payload */
53 	uint8_t *message;
54 };
55 
56 struct ams_slot {
57 	uint16_t module_id;
58 	uint16_t instance_id;
59 	union {
60 		struct ams_message_payload msg;
61 		uint8_t msg_raw[AMS_MAX_MSG_SIZE];
62 	} u;
63 	uint32_t __aligned(PLATFORM_DCACHE_ALIGN) pad[];
64 };
65 
66 /**
67  * \brief ams_msg_callback_fn
68  *
69  * Each subscriber provides this handler function for each message ID
70  */
71 typedef void (*ams_msg_callback_fn)(const struct ams_message_payload *const ams_message_payload,
72 				    void *ctx);
73 
74 /**
75  * \brief Internal struct ams_consumer_entry
76  *
77  * Describes a single consumer's subscription to a single message.
78  * Array of 'ams_consumer_entry' structs forms AsyncMessageService's routing
79  * table which allows for message dispatch.
80  */
81 struct ams_consumer_entry {
82 	/* Message ID that will be routed via this entry */
83 	uint32_t message_type_id;
84 	/* Callback provided by the subscribed consumer */
85 	ams_msg_callback_fn consumer_callback;
86 	/* Additional context for consumer_callback (optional) */
87 	void *ctx;
88 	/* Subscribed consumer's Module ID */
89 	uint16_t consumer_module_id;
90 	/* Subscribed consumer's Module Instance ID */
91 	uint8_t consumer_instance_id;
92 	/* Subscribed consumer's Module core id. Saved to speed up routing */
93 	uint8_t consumer_core_id;
94 };
95 
96 struct ams_producer {
97 	/* Message ID that will be routed via this entry */
98 	uint32_t message_type_id;
99 	/* Subscribed producer's Module ID */
100 	uint16_t producer_module_id;
101 	/* Subscribed producer's Module Instance ID */
102 	uint8_t producer_instance_id;
103 };
104 
105 struct uuid_idx {
106 	uint32_t message_type_id;
107 	uint8_t message_uuid[UUID_SIZE];
108 };
109 
110 struct ams_shared_context {
111 	/* should be only used with ams_acquire/release function, not generic ones */
112 	struct coherent c;
113 
114 	uint32_t last_used_msg_id;
115 	struct ams_consumer_entry rt_table[AMS_ROUTING_TABLE_SIZE];
116 	struct ams_producer producer_table[AMS_ROUTING_TABLE_SIZE];
117 	struct uuid_idx uuid_table[AMS_SERVICE_UUID_TABLE_SIZE];
118 
119 	uint32_t slot_uses[CONFIG_CORE_COUNT];
120 	/* marks which core already processed slot */
121 	uint32_t slot_done[CONFIG_CORE_COUNT];
122 
123 	struct ams_slot slots[CONFIG_CORE_COUNT];
124 };
125 
126 struct ams_context {
127 	/* shared context must be always accessed with shared->c taken */
128 	struct ams_shared_context *shared;
129 };
130 
131 struct ams_task {
132 	struct task ams_task;
133 	struct async_message_service *ams;
134 	uint32_t pending_slots;
135 };
136 
137 struct async_message_service {
138 #if CONFIG_SMP
139 	struct ams_task ams_task;
140 #endif /* CONFIG_SMP */
141 	struct ams_context *ams_context;
142 };
143 
144 #if CONFIG_AMS
145 int ams_init(void);
146 
147 /**
148  * \brief Get Message Type ID
149  *
150  * assigns and returns a message type ID for specified message UUID.
151  * The value of message type ID is dynamically assigned and it will change between runs.
152  *
153  * \param[in] message_uuid UUID of message type
154  * \param[in] message_type_id Unique message type ID assigned by AMS
155  */
156 int ams_get_message_type_id(const uint8_t *message_uuid,
157 			    uint32_t *message_type_id);
158 
159 /**
160  * \brief Producer Register
161  *
162  * registers a producer of asynchronous messages of given message type.
163  * When a module instance calls this function,
164  * it informs the Asynchronous Messaging Service that it will be sending asynchronous messages.
165  *
166  * \param[in] message_type_id unique message type ID assigned during ams_get_message_type_id
167  * \param[in] module_id Module ID of module calling function
168  * \param[in] instance_id Instance ID of module calling function
169  */
170 int ams_register_producer(uint32_t message_type_id,
171 			  uint16_t module_id,
172 			  uint16_t instance_id);
173 
174 /**
175  * \brief Producer Unregister
176  *
177  * unregisters a producer of asynchronous messages of given type.
178  * When a module instance calls this function,
179  * it informs the Asynchronous Messaging Service
180  * that it will not be sending asynchronous messages anymore.
181  *
182  * \param[in] message_type_id unique message type ID assigned during ams_get_message_type_id
183  * \param[in] module_id Module ID of module calling function
184  * \param[in] instance_id Instance ID of module calling function
185  */
186 int ams_unregister_producer(uint32_t message_type_id,
187 			    uint16_t module_id,
188 			    uint16_t instance_id);
189 
190 /**
191  * \brief Register Consumer
192  *
193  * Registers a module instance as a consumer of specified message type.
194  * When specified message type is sent,
195  * a callback is called that was provided during registration process.
196  *
197  * The consumer callback is triggered when ams_send function was used to send a message
198  * and/or when ams_send_mi function with consumer's module ID and instance ID was used
199  * to send a message.
200  *
201  * \param[in] message_type_id unique message type ID assigned during ams_get_message_type_id
202  * \param[in] module_id Module ID of module calling function
203  * \param[in] instance_id Instance ID of module calling function
204  * \param[in] function callback that should be called when message is received
205  * \param[in] ctx Optional context that is passed to callback
206  */
207 int ams_register_consumer(uint32_t message_type_id,
208 			  uint16_t module_id,
209 			  uint16_t instance_id,
210 			  ams_msg_callback_fn function,
211 			  void *ctx);
212 
213 /**
214  * \brief Unegister Consumer
215  *
216  * Unregisters a consumer of specified message type
217  *
218  * \param[in] message_type_id unique message type ID assigned during ams_get_message_type_id
219  * \param[in] module_id Module ID of module calling function
220  * \param[in] instance_id Instance ID of module calling function
221  * \param[in] function callback that should be called when message is received
222  */
223 int ams_unregister_consumer(uint32_t message_type_id,
224 			    uint16_t module_id,
225 			    uint16_t instance_id,
226 			    ams_msg_callback_fn function);
227 
228 /**
229  * \brief Message Send
230  *
231  * Sends asynchronous message to all registered consumers by registered producer.
232  * The consumers registered on the same core may be called in context of a message producer
233  *
234  * \param[in] payload Message payload
235  */
236 int ams_send(const struct ams_message_payload *payload);
237 
238 /**
239  * \brief Message Send to Module Instance
240  *
241  * Sends asynchronous message to specified module instance.
242  * The consumer registered on the same core may be called in context of a message producer
243  *
244  * \param[in] payload Message payload
245  * \param[in] module_id Module ID of consumer that messages is sent to
246  * \param[in] instance_id Instance ID of consumer that messages is sent to
247  */
248 int ams_send_mi(const struct ams_message_payload *payload,
249 		uint16_t module_id, uint16_t instance_id);
250 
ams_ctx_get(void)251 static inline struct ams_shared_context *ams_ctx_get(void)
252 {
253 	return sof_get()->ams_shared_ctx;
254 }
255 #else
ams_init(void)256 static inline int ams_init(void) { return 0; }
ams_get_message_type_id(const uint8_t * message_uuid,uint32_t * message_type_id)257 static inline int ams_get_message_type_id(const uint8_t *message_uuid,
258 					  uint32_t *message_type_id) { return 0; }
259 
ams_register_producer(uint32_t message_type_id,uint16_t module_id,uint16_t instance_id)260 static inline int ams_register_producer(uint32_t message_type_id,
261 					uint16_t module_id,
262 					uint16_t instance_id) { return 0; }
263 
ams_unregister_producer(uint32_t message_type_id,uint16_t module_id,uint16_t instance_id)264 static inline int ams_unregister_producer(uint32_t message_type_id,
265 					  uint16_t module_id,
266 					  uint16_t instance_id) { return 0; }
267 
ams_register_consumer(uint32_t message_type_id,uint16_t module_id,uint16_t instance_id,ams_msg_callback_fn function,void * ctx)268 static inline int ams_register_consumer(uint32_t message_type_id,
269 					uint16_t module_id,
270 					uint16_t instance_id,
271 					ams_msg_callback_fn function,
272 					void *ctx) { return 0; }
273 
ams_unregister_consumer(uint32_t message_type_id,uint16_t module_id,uint16_t instance_id,ams_msg_callback_fn function)274 static inline int ams_unregister_consumer(uint32_t message_type_id,
275 					  uint16_t module_id,
276 					  uint16_t instance_id,
277 					  ams_msg_callback_fn function) { return 0; }
278 
ams_send(const struct ams_message_payload * payload)279 static inline int ams_send(const struct ams_message_payload *payload) { return 0; }
280 
ams_send_mi(const struct ams_message_payload * payload,uint16_t module_id,uint16_t instance_id)281 static inline int ams_send_mi(const struct ams_message_payload *payload, uint16_t module_id,
282 			      uint16_t instance_id) { return 0; }
283 
ams_ctx_get(void)284 static inline struct ams_shared_context *ams_ctx_get(void)
285 {
286 	return NULL;
287 }
288 
289 #endif /* CONFIG_AMS */
290 
291 #if CONFIG_SMP && CONFIG_AMS
292 int process_incoming_message(uint32_t slot);
293 #else
process_incoming_message(uint32_t slot)294 static inline int process_incoming_message(uint32_t slot) { return 0; }
295 #endif /* CONFIG_SMP && CONFIG_AMS */
296 
297 struct async_message_service **arch_ams_get(void);
298 
299 #endif /* __SOF_LIB_AMS_H__ */
300