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