diff options
Diffstat (limited to 'hifi/xaf/hifi-dpf/core/xf-core.c')
-rw-r--r-- | hifi/xaf/hifi-dpf/core/xf-core.c | 709 |
1 files changed, 709 insertions, 0 deletions
diff --git a/hifi/xaf/hifi-dpf/core/xf-core.c b/hifi/xaf/hifi-dpf/core/xf-core.c new file mode 100644 index 00000000..95bca129 --- /dev/null +++ b/hifi/xaf/hifi-dpf/core/xf-core.c @@ -0,0 +1,709 @@ +/******************************************************************************* +* 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-core.c + * + * DSP processing framework core + * + ******************************************************************************/ + +#define MODULE_TAG CORE + +/******************************************************************************* + * Includes + ******************************************************************************/ + +#include "xf.h" + +/******************************************************************************* + * Tracing tags + ******************************************************************************/ + +/* ...general initialization sequence */ +TRACE_TAG(INIT, 1); + +/* ...message dispatching */ +TRACE_TAG(DISP, 1); + +/* ...client registration procedures */ +TRACE_TAG(REG, 1); + +/* ...ports routing/unrouting */ +TRACE_TAG(ROUTE, 1); + +#ifdef XAF_PROFILE_DSP +/* ... MCPS/profile info */ +#include "xa_profiler.h" +#endif +/******************************************************************************* + * Internal helpers + ******************************************************************************/ + +/* ...translate client-id into component handle */ +static inline xf_component_t * xf_client_lookup(xf_core_data_t *cd, u32 client) +{ + xf_cmap_link_t *link = &cd->cmap[client]; + + /* ...if link pointer is less than XF_CFG_MAX_CLIENTS, it is a free descriptor */ + return (link->next > XF_CFG_MAX_CLIENTS ? link->c : NULL); +} + +/* ...allocate client-id */ +static inline u32 xf_client_alloc(xf_core_data_t *cd) +{ + u32 client = cd->free; + + /* ...advance list head to next free id */ + (client < XF_CFG_MAX_CLIENTS ? cd->free = cd->cmap[client].next : 0); + + return client; +} + +/* ...recycle client-id */ +static inline void xf_client_free(xf_core_data_t *cd, u32 client) +{ + /* ...put client into the head of the free id list */ + cd->cmap[client].next = cd->free, cd->free = client; +} + +/******************************************************************************* + * Process commands to a proxy + ******************************************************************************/ + +/* ...register new client */ +static int xf_proxy_register(u32 core, xf_message_t *m) +{ + xf_core_data_t *cd = XF_CORE_DATA(core); + u32 src = XF_MSG_SRC(m->id); + u32 client; + xf_component_t *component; + + /* ...allocate new client-id */ + XF_CHK_ERR((client = xf_client_alloc(cd)) != XF_CFG_MAX_CLIENTS, -EBUSY); + + /* ...create component via class factory */ + if ((component = xf_component_factory(core, m->buffer, m->length)) == NULL) + { + TRACE(ERROR, _x("Component creation failed")); + + /* ...recycle client-id */ + xf_client_free(cd, client); + + /* ...return generic out-of-memory code always (tbd) */ + return -ENOMEM; + } + + /* ...register component in a map */ + cd->cmap[client].c = component; + + /* ...set component "default" port specification ("destination") */ + component->id = __XF_PORT_SPEC(core, client, 0); + + /* ...adjust session-id to include newly created component-id */ + m->id = __XF_MSG_ID(src, component->id); + + /* ...do system-specific registration of component within IPC layer */ + xf_ipc_component_addref(m->id); + + TRACE(REG, _b("registered client: %u:%u (%s)"), core, client, (xf_id_t)m->buffer); + + /* ...and return success to remote proxy (zero-length output) */ + xf_response_ok(m); + + return 0; +} + +/* ...shared buffer allocation request */ +static int xf_proxy_alloc(u32 core, xf_message_t *m) +{ + /* ...command is valid only if shared memory interface for core is specified */ + XF_CHK_ERR(xf_shmem_enabled(core), -EPERM); + + /* ...allocate shared memory buffer (system-specific function; may fail) */ + xf_shmem_alloc(core, m); + + /* ...pass result to remote proxy (on success buffer is non-null) */ + xf_response(m); + + return 0; +} + +/* ...shared buffer freeing request */ +static int xf_proxy_free(u32 core, xf_message_t *m) +{ + /* ...command is valid only if shared memory interface for core is specified */ + XF_CHK_ERR(xf_shmem_enabled(core), -EPERM); + + /* ...pass buffer freeing request to system-specific function */ + xf_shmem_free(core, m); + + /* ...return success to remote proxy (function never fails) */ + xf_response(m); + + return 0; +} + +#if 0 +/* ...port routing command processing */ +static int xf_proxy_route(u32 core, xf_message_t *m) +{ + xf_route_port_msg_t *cmd = m->buffer; + u32 src = cmd->src; + u32 dst = cmd->dst; + xf_component_t *component; + xf_output_port_t *port; + + /* ...source component must reside on the local core */ + XF_CHK_ERR(XF_MSG_SRC_CORE(src) == core, -EINVAL); + + /* ...make sure the "src" component is valid ("dst" may reside on other core) */ + if ((component = xf_client_lookup(XF_CORE_DATA(core), XF_PORT_CLIENT(src))) == NULL) + { + TRACE(ERROR, _x("Source port lookup failed: %x"), src); + return -ENOENT; + } + else if (!component->port || !(port = component->port(component, XF_PORT_ID(src)))) + { + TRACE(ERROR, _b("Source port doesn't exist: %x"), src); + return -ENOENT; + } + else if (xf_output_port_routed(port)) + { + TRACE(ERROR, _b("Source port is already routed: %x"), src); + return -EBUSY; + } + + /* ...route output port with source port set as destination */ + XF_CHK_API(xf_output_port_route(port, __XF_MSG_ID(dst, src), cmd->alloc_number, cmd->alloc_size, cmd->alloc_align)); + + TRACE(ROUTE, _b("Ports routed: %03x -> %03x"), src, dst); + + /* ...invoke component data-processing function directly (ignore errors? - tbd) */ + component->entry(component, NULL); + + /* ...return success result code (no output attached) */ + xf_response_ok(m); + + return 0; +} + +/* ...disconnect ports */ +static int xf_proxy_unroute(u32 core, xf_message_t *m) +{ + xf_unroute_port_msg_t *cmd = m->buffer; + u32 src = cmd->src; + xf_component_t *component; + xf_output_port_t *port; + + /* ...source component must reside on the local core */ + XF_CHK_ERR(XF_MSG_SRC_CORE(src) == core, -EINVAL); + + /* ...lookup source (output) port */ + if ((component = xf_client_lookup(XF_CORE_DATA(core), XF_PORT_CLIENT(src))) == NULL) + { + TRACE(ERROR, _b("Source port lookup failed: %x"), src); + return -ENOENT; + } + else if (!component->port || !(port = component->port(component, XF_PORT_ID(src)))) + { + TRACE(ERROR, _b("Source port doesn't exist: %x"), src); + return -ENOENT; + } + else if (!xf_output_port_routed(port)) + { + /* ...port is not routed; satisfy immediately */ + goto done; + } + else if (!xf_output_port_idle(port)) + { + TRACE(ERROR, _b("Source port is not idle: %x"), src); + return -EBUSY; + } + + /* ...unroute port (call must succeed) */ + xf_output_port_unroute(port); + + /* ...we cannot satisfy the command now, and need to propagate it to a sink - tbd */ + //return 0; + +done: + /* ...pass success result code to caller */ + xf_response_ok(m); + + return 0; +} +#endif + +/* ...fill-this-buffer command processing */ +static int xf_proxy_output(u32 core, xf_message_t *m) +{ + /* ...determine destination "client" */ + switch (XF_MSG_SRC_CLIENT(m->id)) + { +#if XF_TRACE_REMOTE + case 0: + /* ...destination is a tracer facility; submit buffer to tracer */ + xf_trace_submit(core, m); + return 0; +#endif + + default: + /* ...unrecognized destination; return general failure response */ + return XF_CHK_ERR(0, -EINVAL); + } +} + +/* ...flush command processing */ +static int xf_proxy_flush(u32 core, xf_message_t *m) +{ + /* ...determine destination "client" */ + switch (XF_MSG_SRC_CLIENT(m->id)) + { +#if XF_TRACE_REMOTE + case 0: + /* ...destination is a tracer facility; flush current buffer */ + xf_trace_flush(core, m); + return 0; +#endif + + default: + /* ...unrecognized destination; return general failure response */ + return XF_CHK_ERR(0, -EINVAL); + } +} + +/* ...proxy command processing table */ +static int (* const xf_proxy_cmd[])(u32, xf_message_t *) = +{ + [XF_OPCODE_TYPE(XF_REGISTER)] = xf_proxy_register, + [XF_OPCODE_TYPE(XF_ALLOC)] = xf_proxy_alloc, + [XF_OPCODE_TYPE(XF_FREE)] = xf_proxy_free, +#if 0 + [XF_OPCODE_TYPE(XF_ROUTE)] = xf_proxy_route, + [XF_OPCODE_TYPE(XF_UNROUTE)] = xf_proxy_unroute, +#endif + [XF_OPCODE_TYPE(XF_FILL_THIS_BUFFER)] = xf_proxy_output, + [XF_OPCODE_TYPE(XF_FLUSH)] = xf_proxy_flush, +}; + +/* ...total number of commands supported */ +#define XF_PROXY_CMD_NUM (sizeof(xf_proxy_cmd) / sizeof(xf_proxy_cmd[0])) + +/* ...process commands to a proxy */ +static void xf_proxy_command(u32 core, xf_message_t *m) +{ + u32 opcode = m->opcode; + int res; + + /* ...dispatch command to proper hook */ + if (XF_OPCODE_TYPE(opcode) < XF_PROXY_CMD_NUM) + { + if ((res = xf_proxy_cmd[XF_OPCODE_TYPE(opcode)](core, m)) >= 0) + { + /* ...command processed successfully; do nothing */ + return; + } + } + else + { + TRACE(ERROR, _x("invalid opcode: %x"), opcode); + } + + /* ...command processing failed; return generic failure response */ + xf_response_err(m); +} + +/******************************************************************************* + * Message completion helper + ******************************************************************************/ + +/* ...put message into local IPC command queue on remote core (src != dst) */ +static inline void xf_msg_local_ipc_put(u32 src, u32 dst, xf_message_t *m) +{ + xf_core_rw_data_t *rw = XF_CORE_RW_DATA(dst); + int first; + + /* ...flush message payload if needed */ + if (XF_LOCAL_IPC_NON_COHERENT) + { + /* ...it may be a command with output payload only - tbd */ + XF_PROXY_FLUSH(m->buffer, m->length); + } + + /* ...acquire mutex to target rw-data (running on source core) */ + xf_mutex_lock(src); + + /* ...assure memory coherency as needed */ + if (XF_LOCAL_IPC_NON_COHERENT) + { + /* ...invalidate local queue data */ + XF_PROXY_INVALIDATE(&rw->local, sizeof(rw->local)); + + /* ...place message into queue */ + first = xf_msg_enqueue(&rw->local, m); + + /* ...flush both queue and message data */ + XF_PROXY_FLUSH(&rw->local, sizeof(rw->local)), XF_PROXY_FLUSH(m, sizeof(*m)); + } + else + { + /* ...just enqueue the message */ + first = xf_msg_enqueue(&rw->local, m); + } + + /* ...release global rw-memory access lock */ + xf_mutex_unlock(src); + + /* ...signal IPI interrupt on destination core as needed */ + (first ? xf_ipi_assert(dst), 1 : 0); +} + +/* ...dequeue message from core-specific dispatch queue */ +static inline xf_message_t * xf_msg_local_ipc_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); + + /* ...process memory coherency as required */ + if (XF_LOCAL_IPC_NON_COHERENT) + { + /* ...inavlidate local rw-data */ + XF_PROXY_INVALIDATE(&rw->local, sizeof(rw->local)); + + /* ...get message from the queue */ + if ((m = xf_msg_dequeue(&rw->local)) != NULL) + { + /* ...flush rw-queue data */ + XF_PROXY_FLUSH(&rw->local, sizeof(rw->local)); + } + } + else + { + /* ...just dequeue message from the queue */ + m = xf_msg_dequeue(&rw->local); + } + + /* ...release rw-memory access lock */ + xf_mutex_unlock(core); + + /* ...invalidate message header and data as needed */ + if (XF_LOCAL_IPC_NON_COHERENT && m != NULL) + { + /* ...invalidate message header */ + XF_PROXY_INVALIDATE(m, sizeof(*m)); + + /* ...and data if needed (it may not be always needed - tbd) */ + (m->length ? XF_PROXY_INVALIDATE(m->buffer, m->length) : 0); + } + + /* ...return message */ + return m; +} + +/* ...retrieve message from local queue (protected from ISR) */ +static inline int xf_msg_local_put(u32 core, xf_message_t *m) +{ + xf_core_data_t *cd = XF_CORE_DATA(core); + int first; + u32 status; + + /* ...use interrupt masking protocol to protect message queue */ + status = xf_isr_disable(core); + first = xf_msg_enqueue(&cd->queue, m); + xf_isr_restore(core, status); + + return first; +} + +/* ...retrieve message from local queue (protected from ISR) */ +static inline xf_message_t * xf_msg_local_get(u32 core) +{ + xf_core_data_t *cd = XF_CORE_DATA(core); + xf_message_t *m; + u32 status; + + /* ...use interrupt masking protocol to protect message queue */ + status = xf_isr_disable(core); + m = xf_msg_dequeue(&cd->queue); + xf_isr_restore(core, status); + + return m; +} + +/* ...retrieve message from local queue (protected from ISR) */ +static inline xf_message_t * xf_msg_local_response_get(u32 core) +{ + xf_core_data_t *cd = XF_CORE_DATA(core); + xf_message_t *m; + u32 status; + + /* ...use interrupt masking protocol to protect message queue */ + status = xf_isr_disable(core); + m = xf_msg_dequeue(&cd->response); + xf_isr_restore(core, status); + + return m; +} + +/* ...call component data processing function */ +static inline void xf_core_process(xf_component_t *component) +{ + u32 id = component->id; + + /* ...client look-up successfull */ + TRACE(DISP, _b("core[%u]::client[%u]::process"), XF_PORT_CORE(id), XF_PORT_CLIENT(id)); + + /* ...call data-processing interface */ + if (component->entry(component, NULL) < 0) + { + TRACE(ERROR, _b("execution error (ignored)")); + } +} + +/* ...dispatch message queue execution */ +static inline void xf_core_dispatch(xf_core_data_t *cd, u32 core, xf_message_t *m) +{ + u32 client; + xf_component_t *component; + + /* ...do client-id/component lookup */ + if (XF_MSG_DST_PROXY(m->id)) + { + TRACE(DISP, _b("core[%u]::proxy-cmd(id=%x, opcode=%x)"), core, m->id, m->opcode); + + /* ...process message addressed to proxy */ + xf_proxy_command(core, m); + + /* ...do not like this return statement... - tbd */ + return; + } + + /* ...message goes to local component */ + client = XF_MSG_DST_CLIENT(m->id); + + /* ...check if client is alive */ + if ((component = xf_client_lookup(cd, client)) != NULL) + { + /* ...client look-up successfull */ + TRACE(DISP, _b("core[%u]::client[%u]::cmd(id=%x, opcode=%x)"), core, client, m->id, m->opcode); + + /* ...pass message to component entry point */ + if (component->entry(component, m) < 0) + { + /* ...call component destructor */ + if (component->exit(component, m) == 0) + { + /* ...component cleanup completed; recycle component-id */ + xf_client_free(cd, client); + + /* ...do system-specific deregistration of component within IPC layer */ + xf_ipc_component_rmref(__XF_PORT_SPEC(core, client, 0)); + } + } + } + else + { + TRACE(DISP, _b("Discard message id=%x - client %u:%u not registered"), m->id, core, client); + + /* ...complete message with general failure response */ + xf_response_err(m); + } +} + +/******************************************************************************* + * Entry points + ******************************************************************************/ + +/* ...submit message for instant execution on some core */ +void xf_msg_submit(xf_message_t *m) +{ + u32 src = XF_MSG_SRC_CORE(m->id); + u32 dst = XF_MSG_DST_CORE(m->id); + + /* ...check if message shall go through local IPC layer */ + if (src ^ dst) + { + /* ...put message into local IPC queue */ + xf_msg_local_ipc_put(src, dst, m); + } + else + { + /* ...message is addressed to same core */ + xf_msg_local_put(src, m); + } +} + +/* ...complete message and pass response to a caller */ +void xf_msg_complete(xf_message_t *m) +{ + u32 src = XF_MSG_SRC(m->id); + u32 dst = XF_MSG_DST(m->id); + + /* ...swap src/dst specifiers */ + m->id = __XF_MSG_ID(dst, src); + + /* ...check if message goes to remote IPC layer */ + if (XF_MSG_DST_PROXY(m->id)) + { + /* ...return message to proxy */ + xf_msg_proxy_complete(m); + } + else + { + /* ...destination is within DSP cluster; check if that is a data buffer */ + switch (m->opcode) + { + case XF_EMPTY_THIS_BUFFER: + /* ...emptied buffer goes back to the output port */ + m->opcode = XF_FILL_THIS_BUFFER; + break; + + case XF_FILL_THIS_BUFFER: + /* ...filled buffer is passed to the input port */ + m->opcode = XF_EMPTY_THIS_BUFFER; + break; + } + + /* ...submit message for execution */ + xf_msg_submit(m); + } +} + +/* ...initialize per-core framework data */ +int xf_core_init(u32 core) +{ + xf_core_data_t *cd = XF_CORE_DATA(core); + xf_cmap_link_t *link; + u32 i; + + /* ...create list of free client descriptors */ + for (link = &cd->cmap[i = 0]; i < XF_CFG_MAX_CLIENTS; i++, link++) + { + link->next = i + 1; + } + + /* ...set head of free clients list */ + cd->free = 0; + + /* ...initialize local queue scheduler */ + xf_sched_init(&cd->sched); + + /* ...initialize IPI subsystem */ + XF_CHK_API(xf_ipi_init(core)); + + /* ...initialize shared read-write memory */ + XF_CHK_API(xf_shmem_enabled(core) ? xf_shmem_init(core) : 0); + + /* ...initialize scratch memory */ + XF_CHK_ERR(cd->scratch = xf_scratch_mem_init(core), -ENOMEM); + + /* ...okay... it's all good */ + TRACE(INIT, _b("core-%u initialized"), core); + + return 0; +} + +/* ...core executive loop function */ +void xf_core_service(u32 core) +{ + xf_core_data_t *cd = &xf_core_data[core]; + u32 status; + xf_message_t *m; + xf_task_t *t; + +#ifdef XAF_PROFILE_DSP + START_TIME_XA_PROFILER(prof); +#endif + do + { + /* ...clear local status change */ + status = 0; + + /* ...if core is servicing shared memory with AP, do it first - actually, they all need to support it */ + if (xf_shmem_enabled(core)) + { + /* ...process all commands */ + xf_shmem_process_queues(core); + } + + /* ...check if we have a backlog message placed into interim queue */ + while ((m = xf_msg_local_ipc_get(core)) || (m = xf_msg_local_get(core))) + { + /* ...dispatch message execution */ + xf_core_dispatch(cd, core, m); + + /* ...set local status change */ + status = 1; + } + + /* ...check if we have pending responses (submitted from ISR) we need to process */ + while ((m = xf_msg_local_response_get(core)) != NULL) + { + /* ...call completion handler on current stack */ + xf_msg_complete(m); + + /* ...set local status change */ + status = 1; + + } + + /* ...if scheduler queue is empty, break the loop and pause the core */ + if ((t = xf_sched_get(&cd->sched)) != NULL) + { + /* ...data-processing execution (ignore internal errors) */ + xf_core_process((xf_component_t *)t); + + /* ...set local status change */ + status = 1; + } + } + while (status); + +#ifdef XAF_PROFILE_DSP + STOP_TIME_XA_PROFILER(prof); + + if(prof.g_output_bytes) + { + unsigned long output_samples = prof.g_output_bytes; + output_samples >>= (prof.channels == 2 ? 1 : 0); + output_samples >>= (prof.pcm_width == 24 ? 2 : 1); + + COMPUTE_MHZ_XA_PROFILER(prof, output_samples, prof.sample_rate, 0); + + prof.g_output_bytes = prof.cycles = 0; /* reset counters */ + } +#endif + +} + +/* ...global data initialization function */ +int xf_global_init(void) +{ + /* ...what global data we have to initialize? - tbd */ + TRACE(INIT, _b("Global data initialized")); + + return 0; +} |