1 /*******************************************************************************
2 * Copyright (C) 2018 Cadence Design Systems, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to use this Software with Cadence processor cores only and
7 * not with any other processors and platforms, subject to
8 * the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included
11 * in all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 ******************************************************************************/
22
23 /*******************************************************************************
24 * xf-shmem.c
25 *
26 * DSP shared memory interface implementation
27 *
28 ******************************************************************************/
29
30 #define MODULE_TAG SHMEM
31
32 /*******************************************************************************
33 * Includes
34 ******************************************************************************/
35
36 #include "xf.h"
37
38 /*******************************************************************************
39 * Tracing tags
40 ******************************************************************************/
41
42 /* ...general initialization sequence */
43 TRACE_TAG(INIT, 1);
44
45 /* ...interface status change */
46 TRACE_TAG(EXEC, 0);
47
48 /* ...command reception */
49 TRACE_TAG(CMD, 1);
50
51 /* ...response generation */
52 TRACE_TAG(RSP, 1);
53
54 #ifdef XAF_PROFILE_DSP
55 #include "xa_profiler.h"
56 #endif
57 /*******************************************************************************
58 * Local constants definitions
59 ******************************************************************************/
60
61 /* ...local interface status change flag */
62 #define XF_PROXY_STATUS_LOCAL (1 << 0)
63
64 /* ...remote status change notification flag */
65 #define XF_PROXY_STATUS_REMOTE (1 << 1)
66
67 /*******************************************************************************
68 * Internal helpers
69 ******************************************************************************/
70
71 /* ...put message into proxy queue */
xf_msg_proxy_put(xf_message_t * m)72 static inline void xf_msg_proxy_put(xf_message_t *m)
73 {
74 u32 dst = XF_MSG_DST_CORE(m->id);
75 u32 src = XF_MSG_SRC_CORE(m->id);
76 xf_core_rw_data_t *rw = XF_CORE_RW_DATA(dst);
77 int first;
78
79 /* ...get an access to shared rw-memory (we are running on "source" core) */
80 xf_mutex_lock(src);
81
82 /* ...assure memory coherency if needed */
83 if (XF_REMOTE_IPC_NON_COHERENT)
84 {
85 /* ...invalidate rw-shared memory region */
86 XF_PROXY_INVALIDATE(rw, sizeof(*rw));
87
88 /* ...put message into shared queue */
89 first = xf_msg_enqueue(&rw->remote, m);
90
91 /* ...flush both message and shared queue data */
92 XF_PROXY_FLUSH(rw, sizeof(*rw)), XF_PROXY_FLUSH(m, sizeof(*m));
93 }
94 else
95 {
96 /* ...no memory coherency concerns; just place a message in the queue */
97 first = xf_msg_enqueue(&rw->remote, m);
98 }
99
100 /* ...release rw-memory region lock */
101 xf_mutex_unlock(src);
102
103 /* ...assert IPI interrupt on target ("destination") core if needed */
104 if (first && (dst ^ src))
105 {
106 xf_ipi_assert(dst);
107 }
108 }
109
110 /* ...retrieve message from proxy queue */
xf_msg_proxy_get(u32 core)111 static inline xf_message_t * xf_msg_proxy_get(u32 core)
112 {
113 xf_core_rw_data_t *rw = XF_CORE_RW_DATA(core);
114 xf_message_t *m;
115
116 /* ...retrieve message from queue in atomic fashion */
117 xf_mutex_lock(core);
118
119 /* ...assure memory coherency if needed */
120 if (XF_REMOTE_IPC_NON_COHERENT)
121 {
122 /* ...invalidate rw-memory */
123 XF_PROXY_INVALIDATE(rw, sizeof(*rw));
124
125 /* ...dequeue message from response queue */
126 m = xf_msg_dequeue(&rw->remote);
127
128 /* ...flush rw memory */
129 XF_PROXY_FLUSH(rw, sizeof(*rw));
130
131 /* ...invalidate message data if found */
132 (m ? XF_PROXY_INVALIDATE(m, sizeof(*m)) : 0);
133 }
134 else
135 {
136 /* ...just dequeue message from response queue */
137 m = xf_msg_dequeue(&rw->remote);
138 }
139
140 /* ...release the rw-lock */
141 xf_mutex_unlock(core);
142
143 return m;
144 }
145
146 /*******************************************************************************
147 * Internal functions definitions
148 ******************************************************************************/
149
150 /* ...retrieve all incoming commands from shared memory ring-buffer */
xf_shmem_process_input(u32 core)151 static u32 xf_shmem_process_input(u32 core)
152 {
153 xf_message_t *m;
154 u32 read_idx;
155 u32 write_idx;
156 u32 status = 0;
157
158 /* ...get current value of write pointer */
159 read_idx = XF_PROXY_READ(core, cmd_read_idx);
160 write_idx = XF_PROXY_READ(core, cmd_write_idx);
161
162 TRACE(EXEC, _b("Command queue: write = %x / read = %x"), write_idx, read_idx);
163
164 /* ...process all committed commands */
165 while (!XF_QUEUE_EMPTY(read_idx, write_idx))
166 {
167 xf_proxy_message_t *command;
168
169 /* ...allocate message; the call should not fail */
170 if ((m = xf_msg_pool_get(&XF_CORE_RO_DATA(core)->pool)) == NULL)
171 break;
172
173 /* ...if queue was full, set global proxy update flag */
174 if (XF_QUEUE_FULL(read_idx, write_idx))
175 status |= XF_PROXY_STATUS_REMOTE | XF_PROXY_STATUS_LOCAL;
176 else
177 status |= XF_PROXY_STATUS_LOCAL;
178
179 /* ...get oldest not processed command */
180 command = XF_PROXY_COMMAND(core, XF_QUEUE_IDX(read_idx));
181
182 /* ...synchronize memory contents */
183 XF_PROXY_INVALIDATE(command, sizeof(*command));
184
185 /* ...fill message parameters */
186 m->id = command->session_id;
187 m->opcode = command->opcode;
188 m->length = command->length;
189 m->buffer = xf_ipc_a2b(core, command->address);
190 TRACE(CMD, _b("C[%x]:(%x,%u,%p)"), m->id, m->opcode, m->length, m->buffer);
191
192 /* ...invalidate message buffer contents as required - not here - tbd */
193 (XF_OPCODE_CDATA(m->opcode) ? XF_PROXY_INVALIDATE(m->buffer, m->length) : 0);
194
195 /* ...advance local reading index copy */
196 read_idx = XF_QUEUE_ADVANCE_IDX(read_idx);
197
198 /* ...update shadow copy of reading index */
199 XF_PROXY_WRITE(core, cmd_read_idx, read_idx);
200
201 /* ...and schedule message execution on proper core */
202 xf_msg_submit(m);
203 }
204
205 return status;
206 }
207
208 /* ...send out all pending outgoing responses to the shared memory ring-buffer */
xf_shmem_process_output(u32 core)209 static u32 xf_shmem_process_output(u32 core)
210 {
211 xf_message_t *m;
212 u32 read_idx;
213 u32 write_idx;
214 u32 status = 0;
215
216 /* ...get current value of peer read pointer */
217 write_idx = XF_PROXY_READ(core, rsp_write_idx);
218 read_idx = XF_PROXY_READ(core, rsp_read_idx);
219
220 TRACE(EXEC, _b("Response queue: write = %08X / read = %08X"), write_idx, read_idx);
221
222 /* ...while we have response messages and there's space to write out one */
223 while (!XF_QUEUE_FULL(read_idx, write_idx))
224 {
225 xf_proxy_message_t *response;
226
227 /* ...remove message from internal queue */
228 if ((m = xf_msg_proxy_get(core)) == NULL)
229 break;
230
231 /* ...notify remote interface each time we send it a message (only if it was empty?) */
232 status = XF_PROXY_STATUS_REMOTE | XF_PROXY_STATUS_LOCAL;
233
234 #if 0
235 /* ...need to decide on best strategy - tbd */
236 if (XF_QUEUE_EMPTY(read_idx, write_idx))
237 status |= XF_PROXY_STATUS_REMOTE | XF_PROXY_STATUS_LOCAL;
238 else
239 status |= XF_PROXY_STATUS_LOCAL;
240 #endif
241
242 /* ...flush message buffer contents to main memory as required - too late - different core - tbd */
243 (XF_OPCODE_RDATA(m->opcode) ? XF_PROXY_FLUSH(m->buffer, m->length) : 0);
244
245 /* ...find place in a queue for next response */
246 response = XF_PROXY_RESPONSE(core, XF_QUEUE_IDX(write_idx));
247
248 /* ...put the response message fields */
249 response->session_id = m->id;
250 response->opcode = m->opcode;
251 response->length = m->length;
252 response->address = xf_ipc_b2a(core, m->buffer);
253 /* ...flush the content of the caches to main memory */
254 XF_PROXY_FLUSH(response, sizeof(*response));
255
256 #ifdef XAF_PROFILE_DSP
257 if((m->opcode == XF_FILL_THIS_BUFFER))
258 {
259 if((m->length != 0) && (m->length != 20))
260 {
261 prof.g_output_bytes += (unsigned long)m->length;
262 }
263 else if (m->length == 20)
264 {
265 /* Profiler re-initialization */
266 INIT_XA_PROFILER(prof,"DSP core");
267
268 /* update stream params on re-init */
269 xf_start_msg_t *sm = (xf_start_msg_t *)m->buffer;
270 prof.sample_rate = sm->sample_rate;
271 prof.channels = sm->channels;
272 prof.pcm_width = sm->pcm_width;
273 }
274 }
275 #endif
276 TRACE(RSP, _b("R[%x]:(%x,%u,%p)"), m->id, m->opcode, m->length, m->buffer);
277
278 /* ...return message back to the pool */
279 xf_msg_pool_put(&XF_CORE_RO_DATA(core)->pool, m);
280
281 /* ...advance local writing index copy */
282 write_idx = XF_QUEUE_ADVANCE_IDX(write_idx);
283
284 /* ...update shared copy of queue write pointer */
285 XF_PROXY_WRITE(core, rsp_write_idx, write_idx);
286 }
287
288 /* ...return interface status change flags */
289 return status;
290 }
291
292 /*******************************************************************************
293 * Entry points
294 ******************************************************************************/
295
296 /* ...process local/remote shared memory interface status change */
xf_shmem_process_queues(u32 core)297 void xf_shmem_process_queues(u32 core)
298 {
299 u32 status;
300
301 do
302 {
303 /* ...acknowledge/clear any pending incoming interrupt */
304 XF_PROXY_SYNC_PEER(core);
305
306 /* ...send out pending response messages (frees message buffers, so do it first) */
307 status = xf_shmem_process_output(core);
308
309 /* ...receive and forward incoming command messages (allocates message buffers) */
310 status |= xf_shmem_process_input(core);
311
312 /* ...assert remote mailbox interrupt if global update bit is set */
313 if (status & XF_PROXY_STATUS_REMOTE)
314 {
315 XF_PROXY_NOTIFY_PEER(core);
316 }
317 }
318 while (status);
319 }
320
321 /* ...completion callback for message originating from remote proxy */
xf_msg_proxy_complete(xf_message_t * m)322 void xf_msg_proxy_complete(xf_message_t *m)
323 {
324 /* ...place message into proxy response queue */
325 xf_msg_proxy_put(m);
326 }
327
328 /* ...initialize shared memory interface (DSP side) */
xf_shmem_init(u32 core)329 int xf_shmem_init(u32 core)
330 {
331 xf_core_rw_data_t *rw = XF_CORE_RW_DATA(core);
332 xf_core_ro_data_t *ro = XF_CORE_RO_DATA(core);
333
334 /* ...initialize local/remote message queues */
335 xf_msg_queue_init(&rw->local);
336 xf_msg_queue_init(&rw->remote);
337
338 /* ...initialize global message list */
339 XF_CHK_API(xf_msg_pool_init(&ro->pool, XF_CFG_MESSAGE_POOL_SIZE, core));
340
341 /* ...flush memory content as needed */
342 (XF_REMOTE_IPC_NON_COHERENT ? XF_PROXY_FLUSH(rw, sizeof(*rw)) : 0);
343
344 /* ...system-specific initialization of IPC layer */
345 XF_CHK_API(xf_ipc_init(core));
346
347 TRACE(INIT, _b("SHMEM-%u subsystem initialized"), core);
348
349 return 0;
350 }
351