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