summaryrefslogtreecommitdiff
path: root/hifi/xaf/hifi-dpf/core/xf-shmem.c
blob: 15d3b1d926f5aed3afdf82ec793df8e567cf7093 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
/*******************************************************************************
* Copyright (C) 2018 Cadence Design Systems, Inc.
* 
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to use this Software with Cadence processor cores only and 
* not with any other processors and platforms, subject to
* the following conditions:
* 
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

******************************************************************************/

/*******************************************************************************
 * xf-shmem.c
 *
 * DSP shared memory interface implementation
 *
 ******************************************************************************/

#define MODULE_TAG                      SHMEM

/*******************************************************************************
 * Includes
 ******************************************************************************/

#include "xf.h"

/*******************************************************************************
 * Tracing tags
 ******************************************************************************/

/* ...general initialization sequence */
TRACE_TAG(INIT, 1);

/* ...interface status change */
TRACE_TAG(EXEC, 0);

/* ...command reception */
TRACE_TAG(CMD, 1);

/* ...response generation */
TRACE_TAG(RSP, 1);

#ifdef XAF_PROFILE_DSP
#include "xa_profiler.h"
#endif
/*******************************************************************************
 * Local constants definitions
 ******************************************************************************/

/* ...local interface status change flag */
#define XF_PROXY_STATUS_LOCAL           (1 << 0)

/* ...remote status change notification flag */
#define XF_PROXY_STATUS_REMOTE          (1 << 1)

/*******************************************************************************
 * Internal helpers
 ******************************************************************************/

/* ...put message into proxy queue */
static inline void xf_msg_proxy_put(xf_message_t *m)
{
    u32                 dst = XF_MSG_DST_CORE(m->id);
    u32                 src = XF_MSG_SRC_CORE(m->id);
    xf_core_rw_data_t  *rw = XF_CORE_RW_DATA(dst);
    int                 first;

    /* ...get an access to shared rw-memory (we are running on "source" core) */
    xf_mutex_lock(src);
    
    /* ...assure memory coherency if needed */
    if (XF_REMOTE_IPC_NON_COHERENT)
    {
        /* ...invalidate rw-shared memory region */
        XF_PROXY_INVALIDATE(rw, sizeof(*rw));
        
        /* ...put message into shared queue */
        first = xf_msg_enqueue(&rw->remote, m);

        /* ...flush both message and shared queue data */
        XF_PROXY_FLUSH(rw, sizeof(*rw)), XF_PROXY_FLUSH(m, sizeof(*m));
    }
    else
    {
        /* ...no memory coherency concerns; just place a message in the queue */
        first = xf_msg_enqueue(&rw->remote, m);
    }

    /* ...release rw-memory region lock */
    xf_mutex_unlock(src);

    /* ...assert IPI interrupt on target ("destination") core if needed */
    if (first && (dst ^ src))
    {
        xf_ipi_assert(dst);
    }
}

/* ...retrieve message from proxy queue */
static inline xf_message_t * xf_msg_proxy_get(u32 core)
{
    xf_core_rw_data_t  *rw = XF_CORE_RW_DATA(core);
    xf_message_t       *m;
    
    /* ...retrieve message from queue in atomic fashion */
    xf_mutex_lock(core);

    /* ...assure memory coherency if needed */
    if (XF_REMOTE_IPC_NON_COHERENT)
    {
        /* ...invalidate rw-memory */
        XF_PROXY_INVALIDATE(rw, sizeof(*rw));

        /* ...dequeue message from response queue */
        m = xf_msg_dequeue(&rw->remote);

        /* ...flush rw memory */
        XF_PROXY_FLUSH(rw, sizeof(*rw));

        /* ...invalidate message data if found */
        (m ? XF_PROXY_INVALIDATE(m, sizeof(*m)) : 0);
    }
    else
    {
        /* ...just dequeue message from response queue */
        m = xf_msg_dequeue(&rw->remote);
    }
    
    /* ...release the rw-lock */
    xf_mutex_unlock(core);

    return m;
}

/*******************************************************************************
 * Internal functions definitions
 ******************************************************************************/

/* ...retrieve all incoming commands from shared memory ring-buffer */
static u32 xf_shmem_process_input(u32 core)
{
    xf_message_t   *m;
    u32             read_idx;
    u32             write_idx;
    u32             status = 0;

    /* ...get current value of write pointer */
    read_idx = XF_PROXY_READ(core, cmd_read_idx);
    write_idx = XF_PROXY_READ(core, cmd_write_idx);

    TRACE(EXEC, _b("Command queue: write = %x / read = %x"), write_idx, read_idx);

    /* ...process all committed commands */
    while (!XF_QUEUE_EMPTY(read_idx, write_idx))
    {
        xf_proxy_message_t *command;

        /* ...allocate message; the call should not fail */
        if ((m = xf_msg_pool_get(&XF_CORE_RO_DATA(core)->pool)) == NULL)
            break;

        /* ...if queue was full, set global proxy update flag */
        if (XF_QUEUE_FULL(read_idx, write_idx))
            status |= XF_PROXY_STATUS_REMOTE | XF_PROXY_STATUS_LOCAL;
        else
            status |= XF_PROXY_STATUS_LOCAL;

        /* ...get oldest not processed command */
        command = XF_PROXY_COMMAND(core, XF_QUEUE_IDX(read_idx));

        /*  ...synchronize memory contents */
        XF_PROXY_INVALIDATE(command, sizeof(*command));

        /* ...fill message parameters */
        m->id = command->session_id;
        m->opcode = command->opcode;
        m->length = command->length;
        m->buffer = xf_ipc_a2b(core, command->address);
        TRACE(CMD, _b("C[%x]:(%x,%u,%p)"), m->id, m->opcode, m->length, m->buffer);

        /* ...invalidate message buffer contents as required - not here - tbd */
        (XF_OPCODE_CDATA(m->opcode) ? XF_PROXY_INVALIDATE(m->buffer, m->length) : 0);
        
        /* ...advance local reading index copy */
        read_idx = XF_QUEUE_ADVANCE_IDX(read_idx);

        /* ...update shadow copy of reading index */
        XF_PROXY_WRITE(core, cmd_read_idx, read_idx);

        /* ...and schedule message execution on proper core */
        xf_msg_submit(m);
    }

    return status;
}

/* ...send out all pending outgoing responses to the shared memory ring-buffer */
static u32 xf_shmem_process_output(u32 core)
{
    xf_message_t   *m;
    u32             read_idx;
    u32             write_idx;
    u32             status = 0;

    /* ...get current value of peer read pointer */
    write_idx = XF_PROXY_READ(core, rsp_write_idx);
    read_idx = XF_PROXY_READ(core, rsp_read_idx);

    TRACE(EXEC, _b("Response queue: write = %08X / read = %08X"), write_idx, read_idx);

    /* ...while we have response messages and there's space to write out one */
    while (!XF_QUEUE_FULL(read_idx, write_idx))
    {
        xf_proxy_message_t     *response;

        /* ...remove message from internal queue */
        if ((m = xf_msg_proxy_get(core)) == NULL)
            break;

        /* ...notify remote interface each time we send it a message (only if it was empty?) */
        status = XF_PROXY_STATUS_REMOTE | XF_PROXY_STATUS_LOCAL;

#if 0
        /* ...need to decide on best strategy - tbd */
        if (XF_QUEUE_EMPTY(read_idx, write_idx))
            status |= XF_PROXY_STATUS_REMOTE | XF_PROXY_STATUS_LOCAL;
        else
            status |= XF_PROXY_STATUS_LOCAL;
#endif

        /* ...flush message buffer contents to main memory as required - too late - different core - tbd */
        (XF_OPCODE_RDATA(m->opcode) ? XF_PROXY_FLUSH(m->buffer, m->length) : 0);

        /* ...find place in a queue for next response */
        response = XF_PROXY_RESPONSE(core, XF_QUEUE_IDX(write_idx));

        /* ...put the response message fields */
        response->session_id = m->id;
        response->opcode = m->opcode;
        response->length = m->length;
        response->address = xf_ipc_b2a(core, m->buffer);
        /* ...flush the content of the caches to main memory */
        XF_PROXY_FLUSH(response, sizeof(*response));

#ifdef XAF_PROFILE_DSP
        if((m->opcode == XF_FILL_THIS_BUFFER))
        {
            if((m->length != 0) && (m->length != 20))
            {
                prof.g_output_bytes += (unsigned long)m->length;
            }
            else if (m->length == 20)
            {
              /* Profiler re-initialization */
              INIT_XA_PROFILER(prof,"DSP core");

              /* update stream params on re-init */
              xf_start_msg_t *sm = (xf_start_msg_t *)m->buffer;
              prof.sample_rate = sm->sample_rate;
              prof.channels = sm->channels;
              prof.pcm_width = sm->pcm_width;
            }
        }
#endif
        TRACE(RSP, _b("R[%x]:(%x,%u,%p)"), m->id, m->opcode, m->length, m->buffer);

        /* ...return message back to the pool */
        xf_msg_pool_put(&XF_CORE_RO_DATA(core)->pool, m);

        /* ...advance local writing index copy */
        write_idx = XF_QUEUE_ADVANCE_IDX(write_idx);

        /* ...update shared copy of queue write pointer */
        XF_PROXY_WRITE(core, rsp_write_idx, write_idx);
    }

    /* ...return interface status change flags */
    return status;
}

/*******************************************************************************
 * Entry points
 ******************************************************************************/

/* ...process local/remote shared memory interface status change */
void xf_shmem_process_queues(u32 core)
{
    u32     status;

    do
    {
        /* ...acknowledge/clear any pending incoming interrupt */
        XF_PROXY_SYNC_PEER(core);

        /* ...send out pending response messages (frees message buffers, so do it first) */
        status = xf_shmem_process_output(core);

        /* ...receive and forward incoming command messages (allocates message buffers) */
        status |= xf_shmem_process_input(core);

        /* ...assert remote mailbox interrupt if global update bit is set */
        if (status & XF_PROXY_STATUS_REMOTE)
        {
            XF_PROXY_NOTIFY_PEER(core);
        }
    }
    while (status);
}

/* ...completion callback for message originating from remote proxy */
void xf_msg_proxy_complete(xf_message_t *m)
{
    /* ...place message into proxy response queue */
    xf_msg_proxy_put(m);
}

/* ...initialize shared memory interface (DSP side) */
int xf_shmem_init(u32 core)
{
    xf_core_rw_data_t  *rw = XF_CORE_RW_DATA(core);
    xf_core_ro_data_t  *ro = XF_CORE_RO_DATA(core);

    /* ...initialize local/remote message queues */
    xf_msg_queue_init(&rw->local);
    xf_msg_queue_init(&rw->remote);

    /* ...initialize global message list */
    XF_CHK_API(xf_msg_pool_init(&ro->pool, XF_CFG_MESSAGE_POOL_SIZE, core));

    /* ...flush memory content as needed */
    (XF_REMOTE_IPC_NON_COHERENT ? XF_PROXY_FLUSH(rw, sizeof(*rw)) : 0);

    /* ...system-specific initialization of IPC layer */
    XF_CHK_API(xf_ipc_init(core));

    TRACE(INIT, _b("SHMEM-%u subsystem initialized"), core);

    return 0;
}