summaryrefslogtreecommitdiff
path: root/hifi/xaf/hifi-dpf/core/xf-shmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'hifi/xaf/hifi-dpf/core/xf-shmem.c')
-rw-r--r--hifi/xaf/hifi-dpf/core/xf-shmem.c350
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;
+}