diff options
Diffstat (limited to 'hifi/xaf/hifi-dpf/core/xf-shmem.c')
-rw-r--r-- | hifi/xaf/hifi-dpf/core/xf-shmem.c | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/hifi/xaf/hifi-dpf/core/xf-shmem.c b/hifi/xaf/hifi-dpf/core/xf-shmem.c new file mode 100644 index 00000000..15d3b1d9 --- /dev/null +++ b/hifi/xaf/hifi-dpf/core/xf-shmem.c @@ -0,0 +1,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; +} |