You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
687 lines
21 KiB
687 lines
21 KiB
/*******************************************************************************
|
|
* 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.
|
|
|
|
******************************************************************************/
|
|
|
|
#define MODULE_TAG PROXY
|
|
|
|
/*******************************************************************************
|
|
* Includes
|
|
******************************************************************************/
|
|
|
|
#include "xf.h"
|
|
|
|
/*******************************************************************************
|
|
* Tracing configuration
|
|
******************************************************************************/
|
|
|
|
TRACE_TAG(INIT, 1);
|
|
TRACE_TAG(CMD, 1);
|
|
TRACE_TAG(EXEC, 1);
|
|
TRACE_TAG(RSP, 1);
|
|
TRACE_TAG(REG, 1);
|
|
TRACE_TAG(MEM, 1);
|
|
TRACE_TAG(GRAPH, 1);
|
|
TRACE_TAG(BUFFER, 1);
|
|
|
|
/*******************************************************************************
|
|
* Internal functions definitions
|
|
******************************************************************************/
|
|
|
|
/* ...execute proxy command synchronously */
|
|
static inline int xf_proxy_cmd_exec(xf_proxy_t *proxy, xf_user_msg_t *msg)
|
|
{
|
|
xf_proxy_msg_t m;
|
|
|
|
/* ...send command to remote proxy */
|
|
m.id = msg->id, m.opcode = msg->opcode, m.length = msg->length;
|
|
|
|
/* ...translate address */
|
|
XF_CHK_ERR((m.address = xf_proxy_b2a(proxy, msg->buffer)) != XF_PROXY_BADADDR, -EINVAL);
|
|
|
|
/* ...pass command to remote proxy */
|
|
XF_CHK_API(xf_ipc_send(&proxy->ipc, &m, msg->buffer));
|
|
|
|
/* ...wait for response reception indication from proxy thread */
|
|
XF_CHK_API(xf_proxy_response_get(proxy, &m));
|
|
|
|
/* ...copy parameters */
|
|
msg->id = m.id, msg->opcode = m.opcode, msg->length = m.length;
|
|
|
|
/* ...translate address back to virtual space */
|
|
XF_CHK_ERR((msg->buffer = xf_proxy_a2b(proxy, m.address)) != (void *)-1, -EBADFD);
|
|
|
|
TRACE(EXEC, _b("proxy[%p]: command done: [%08x:%p:%u]"), proxy, msg->opcode, msg->buffer, msg->length);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
/* ...pass command to remote DSP */
|
|
static inline int xf_proxy_cmd(xf_proxy_t *proxy, xf_handle_t *handle, xf_user_msg_t *m)
|
|
{
|
|
xf_proxy_msg_t msg;
|
|
|
|
/* ...set session-id of the message */
|
|
msg.id = __XF_MSG_ID(__XF_AP_CLIENT(proxy->core, handle->client), m->id);
|
|
msg.opcode = m->opcode;
|
|
msg.length = m->length;
|
|
|
|
/* ...translate buffer pointer to shared address */
|
|
XF_CHK_ERR((msg.address = xf_proxy_b2a(proxy, m->buffer)) != XF_PROXY_BADADDR, -EINVAL);
|
|
|
|
/* ...submit command message to IPC layer */
|
|
return XF_CHK_API(xf_ipc_send(&proxy->ipc, &msg, m->buffer));
|
|
}
|
|
#endif /* 0 */
|
|
|
|
/* ...allocate local client-id number */
|
|
static inline u32 xf_client_alloc(xf_proxy_t *proxy, xf_handle_t *handle)
|
|
{
|
|
u32 client;
|
|
|
|
if ((client = proxy->cmap[0].next) != 0)
|
|
{
|
|
/* ...pop client from free clients list */
|
|
proxy->cmap[0].next = proxy->cmap[client].next;
|
|
|
|
/* ...put client handle into association map */
|
|
handle->client = client, proxy->cmap[client].handle = handle;
|
|
}
|
|
|
|
return client;
|
|
}
|
|
|
|
/* ...recycle local client-id number */
|
|
static inline void xf_client_free(xf_proxy_t *proxy, xf_handle_t *handle)
|
|
{
|
|
u32 client = handle->client;
|
|
|
|
/* ...push client into head of the free clients list */
|
|
proxy->cmap[client].next = proxy->cmap[0].next;
|
|
|
|
/* ...adjust head of free clients */
|
|
proxy->cmap[0].next = client;
|
|
}
|
|
|
|
/* ...lookup client basing on its local id */
|
|
static inline xf_handle_t * xf_client_lookup(xf_proxy_t *proxy, u32 client)
|
|
{
|
|
/* ...client index must be in proper range */
|
|
BUG(client >= XF_CFG_PROXY_MAX_CLIENTS, _x("Invalid client index: %u"), client);
|
|
|
|
/* ...check if client index is small */
|
|
if (proxy->cmap[client].next < XF_CFG_PROXY_MAX_CLIENTS)
|
|
return NULL;
|
|
else
|
|
return proxy->cmap[client].handle;
|
|
}
|
|
|
|
/* ...create new client on remote core */
|
|
static inline int xf_client_register(xf_proxy_t *proxy, xf_handle_t *handle, xf_id_t id, u32 core)
|
|
{
|
|
void *b = xf_handle_aux(handle);
|
|
xf_user_msg_t msg;
|
|
|
|
/* ...set session-id: source is local proxy, destination is remote proxy */
|
|
msg.id = __XF_MSG_ID(__XF_AP_PROXY(proxy->core), __XF_DSP_PROXY(core));
|
|
msg.opcode = XF_REGISTER;
|
|
msg.buffer = b;
|
|
msg.length = strlen(id) + 1;
|
|
|
|
/* ...copy component identifier */
|
|
strncpy(b, id, xf_buffer_length(handle->aux));
|
|
|
|
/* ...execute command synchronously */
|
|
XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg));
|
|
|
|
/* ...check operation is successfull */
|
|
XF_CHK_ERR(msg.opcode == (u32) XF_REGISTER, -EFAULT);
|
|
|
|
/* ...save received component global client-id */
|
|
handle->id = XF_MSG_SRC(msg.id);
|
|
|
|
TRACE(REG, _b("[%p]=[%s:%u:%u]"), handle, id, XF_PORT_CORE(handle->id), XF_PORT_CLIENT(handle->id));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ...unregister client from remote proxy */
|
|
static inline int xf_client_unregister(xf_proxy_t *proxy, xf_handle_t *handle)
|
|
{
|
|
xf_user_msg_t msg;
|
|
|
|
/* ...make sure the client is consistent */
|
|
BUG(proxy->cmap[handle->client].handle != handle, _x("Invalid handle: %p"), handle);
|
|
|
|
/* ...set message parameters */
|
|
msg.id = __XF_MSG_ID(__XF_AP_PROXY(proxy->core), handle->id);
|
|
msg.opcode = XF_UNREGISTER;
|
|
msg.buffer = NULL;
|
|
msg.length = 0;
|
|
|
|
/* ...synchronously execute command on remote proxy */
|
|
XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg));
|
|
|
|
/* ...opcode must be XF_UNREGISTER - tbd */
|
|
BUG(msg.opcode != XF_UNREGISTER, _x("Invalid opcode: %X"), msg.opcode);
|
|
|
|
TRACE(REG, _b("%p[%u:%u] unregistered"), handle, XF_PORT_CORE(handle->id), XF_PORT_CLIENT(handle->id));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ...allocate shared buffer */
|
|
static inline int xf_proxy_buffer_alloc(xf_proxy_t *proxy, u32 length, void **buffer)
|
|
{
|
|
u32 core = proxy->core;
|
|
xf_user_msg_t msg;
|
|
|
|
/* ...prepare command parameters */
|
|
msg.id = __XF_MSG_ID(__XF_AP_PROXY(core), __XF_DSP_PROXY(core));
|
|
msg.opcode = XF_ALLOC;
|
|
msg.length = length;
|
|
msg.buffer = NULL;
|
|
|
|
/* ...synchronously execute command on remote proxy */
|
|
XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg));
|
|
|
|
/* ...check if response is valid */
|
|
XF_CHK_ERR(msg.opcode == XF_ALLOC, -EBADFD);
|
|
|
|
/* ...check if allocation is successful */
|
|
XF_CHK_ERR(msg.buffer != NULL, -ENOMEM);
|
|
|
|
/* ...save output parameter */
|
|
*buffer = msg.buffer;
|
|
|
|
TRACE(MEM, _b("proxy-%u: allocated [%p:%u]"), core, *buffer, length);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ...free shared AP-DSP memory */
|
|
static inline int xf_proxy_buffer_free(xf_proxy_t *proxy, void *buffer, u32 length)
|
|
{
|
|
u32 core = proxy->core;
|
|
xf_user_msg_t msg;
|
|
|
|
/* ...prepare command parameters */
|
|
msg.id = __XF_MSG_ID(__XF_AP_PROXY(core), __XF_DSP_PROXY(core));
|
|
msg.opcode = XF_FREE;
|
|
msg.length = length;
|
|
msg.buffer = buffer;
|
|
|
|
/* ...synchronously execute command on remote proxy */
|
|
XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg));
|
|
|
|
/* ...check if response is valid */
|
|
XF_CHK_ERR(msg.opcode == XF_FREE, -EBADFD);
|
|
|
|
TRACE(MEM, _b("proxy-%u: free [%p:%u]"), core, buffer, length);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Proxy interface asynchronous receiving thread
|
|
******************************************************************************/
|
|
|
|
static void * xf_proxy_thread(void *arg)
|
|
{
|
|
xf_proxy_t *proxy = arg;
|
|
xf_handle_t *client;
|
|
int r;
|
|
|
|
/* ...start polling thread */
|
|
while (1)
|
|
{
|
|
xf_proxy_msg_t m;
|
|
xf_user_msg_t msg;
|
|
|
|
/* ...wait for response from remote proxy (infinite timeout) */
|
|
if ((r = xf_ipc_wait(&proxy->ipc, 0)) < 0)
|
|
break;
|
|
|
|
/* ...retrieve all responses received */
|
|
while ((r = xf_ipc_recv(&proxy->ipc, &m, &msg.buffer)) == sizeof(m))
|
|
{
|
|
/* ...make sure we have proper core identifier of SHMEM interface */
|
|
BUG(XF_MSG_DST_CORE(m.id) != proxy->core, _x("Invalid session-id: %X (core=%u)"), m.id, proxy->core);
|
|
|
|
/* ...make sure translation is successful */
|
|
BUG(msg.buffer == (void *)-1, _x("Invalid buffer address: %08x"), m.address);
|
|
|
|
/* ...retrieve information fields */
|
|
msg.id = XF_MSG_SRC(m.id), msg.opcode = m.opcode, msg.length = m.length;
|
|
|
|
TRACE(RSP, _b("R[%08x]:(%08x,%u,%08x)"), m.id, m.opcode, m.length, m.address);
|
|
|
|
/* ...lookup component basing on destination port specification */
|
|
if (XF_AP_CLIENT(m.id) == 0)
|
|
{
|
|
/* ...put proxy response to local IPC queue */
|
|
xf_proxy_response_put(proxy, &m);
|
|
}
|
|
else if ((client = xf_client_lookup(proxy, XF_AP_CLIENT(m.id))) != NULL)
|
|
{
|
|
/* ...client is found; invoke its response callback (must be non-blocking) */
|
|
client->response(client, &msg);
|
|
}
|
|
else
|
|
{
|
|
/* ...client has been disconnected already; drop message */
|
|
TRACE(RSP, _b("Client look-up failed - drop message"));
|
|
}
|
|
}
|
|
|
|
/* ...if result code is negative; terminate thread operation */
|
|
if (r < 0)
|
|
{
|
|
TRACE(ERROR, _x("abnormal proxy[%p] thread termination: %d"), proxy, r);
|
|
break;
|
|
}
|
|
}
|
|
|
|
TRACE(INIT, _b("IPC proxy[%p] thread terminated: %d"), proxy, r);
|
|
|
|
return (void *)(intptr_t)r;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* HiFi proxy API
|
|
******************************************************************************/
|
|
|
|
/* ...open HiFi proxy */
|
|
int xf_proxy_init(xf_proxy_t *proxy, u32 core, void *p_shmem)
|
|
{
|
|
u32 i;
|
|
int r;
|
|
|
|
/* ...initialize proxy lock */
|
|
__xf_lock_init(&proxy->lock);
|
|
|
|
/* ...open proxy IPC interface */
|
|
XF_CHK_API(xf_ipc_open(&proxy->ipc, core, p_shmem));
|
|
|
|
/* ...save proxy core - hmm, too much core identifiers - tbd */
|
|
proxy->core = core;
|
|
|
|
/* ...line-up all clients into single-linked list */
|
|
for (i = 0; i < XF_CFG_PROXY_MAX_CLIENTS - 1; i++)
|
|
{
|
|
proxy->cmap[i].next = i + 1;
|
|
}
|
|
|
|
/* ...tail of the list points back to head (list terminator) */
|
|
proxy->cmap[i].next = 0;
|
|
|
|
/* ...initialize thread attributes (joinable, with minimal stack) */
|
|
if ((r = __xf_thread_create(&proxy->thread, xf_proxy_thread, proxy)) < 0)
|
|
{
|
|
TRACE(ERROR, _x("Failed to create polling thread: %d"), r);
|
|
xf_ipc_close(&proxy->ipc, core);
|
|
return r;
|
|
}
|
|
|
|
TRACE(INIT, _b("proxy-%u[%p] opened"), core, proxy);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ...close proxy handle */
|
|
void xf_proxy_close(xf_proxy_t *proxy)
|
|
{
|
|
u32 core = proxy->core;
|
|
|
|
/* ...terminate proxy thread */
|
|
__xf_thread_destroy(&proxy->thread);
|
|
|
|
/* ...close proxy IPC interface */
|
|
xf_ipc_close(&proxy->ipc, core);
|
|
|
|
TRACE(INIT, _b("proxy-%u[%p] closed"), core, proxy);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* HiFi component API
|
|
******************************************************************************/
|
|
|
|
/* ...open component handle */
|
|
int xf_open(xf_proxy_t *proxy, xf_handle_t *handle, xf_id_t id, u32 core, xf_response_cb response)
|
|
{
|
|
int r;
|
|
|
|
/* ...retrieve auxiliary control buffer from proxy - need I */
|
|
XF_CHK_ERR(handle->aux = xf_buffer_get(proxy->aux), -EBUSY);
|
|
|
|
/* ...initialize IPC data */
|
|
XF_CHK_API(xf_ipc_data_init(&handle->ipc));
|
|
|
|
/* ...register client in interlocked fashion */
|
|
xf_proxy_lock(proxy);
|
|
|
|
/* ...allocate local client */
|
|
if (xf_client_alloc(proxy, handle) == 0)
|
|
{
|
|
TRACE(ERROR, _x("client allocation failed"));
|
|
r = -EBUSY;
|
|
}
|
|
else if ((r = xf_client_register(proxy, handle, id, core)) < 0)
|
|
{
|
|
TRACE(ERROR, _x("client registering failed"));
|
|
xf_client_free(proxy, handle);
|
|
}
|
|
|
|
xf_proxy_unlock(proxy);
|
|
|
|
/* ...if failed, release buffer handle */
|
|
if (r < 0)
|
|
{
|
|
/* ...operation failed; return buffer back to proxy pool */
|
|
xf_buffer_put(handle->aux), handle->aux = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* ...operation completed successfully; assign handle data */
|
|
handle->response = response;
|
|
handle->proxy = proxy;
|
|
|
|
TRACE(INIT, _b("component[%p]:(id=%s,core=%u) created"), handle, id, core);
|
|
}
|
|
|
|
return XF_CHK_API(r);
|
|
}
|
|
|
|
/* ...close component handle */
|
|
void xf_close(xf_handle_t *handle)
|
|
{
|
|
xf_proxy_t *proxy = handle->proxy;
|
|
|
|
/* ...do I need to take component lock here? guess no - tbd */
|
|
|
|
/* ...buffers and stuff? - tbd */
|
|
|
|
/* ...acquire global proxy lock */
|
|
xf_proxy_lock(proxy);
|
|
|
|
/* ...unregister component from remote DSP proxy (ignore result code) */
|
|
(void) xf_client_unregister(proxy, handle);
|
|
|
|
/* ...recycle client-id afterwards */
|
|
xf_client_free(proxy, handle);
|
|
|
|
/* ...release global proxy lock */
|
|
xf_proxy_unlock(proxy);
|
|
|
|
/* ...destroy IPC data */
|
|
xf_ipc_data_destroy(&handle->ipc);
|
|
|
|
/* ...clear handle data */
|
|
xf_buffer_put(handle->aux), handle->aux = NULL;
|
|
|
|
/* ...wipe out proxy pointer */
|
|
handle->proxy = NULL;
|
|
|
|
TRACE(INIT, _b("component[%p] destroyed"), handle);
|
|
}
|
|
|
|
/* ...port binding function */
|
|
int xf_route(xf_handle_t *src, u32 src_port, xf_handle_t *dst, u32 dst_port, u32 num, u32 size, u32 align)
|
|
{
|
|
xf_proxy_t *proxy = src->proxy;
|
|
xf_buffer_t *b;
|
|
xf_route_port_msg_t *m;
|
|
xf_user_msg_t msg;
|
|
|
|
/* ...validity checks - proxy pointers are same */
|
|
XF_CHK_ERR(proxy == dst->proxy, -EINVAL);
|
|
|
|
/* ...buffer data is valid */
|
|
XF_CHK_ERR(num && size && xf_is_power_of_two(align), -EINVAL);
|
|
|
|
/* ...get control buffer */
|
|
XF_CHK_ERR(b = xf_buffer_get(proxy->aux), -EBUSY);
|
|
|
|
/* ...get message buffer */
|
|
m = xf_buffer_data(b);
|
|
|
|
/* ...fill-in message parameters */
|
|
//m->src = __XF_PORT_SPEC2(src->id, src_port);
|
|
m->dst = __XF_PORT_SPEC2(dst->id, dst_port);
|
|
m->alloc_number = num;
|
|
m->alloc_size = size;
|
|
m->alloc_align = align;
|
|
|
|
/* ...set command parameters */
|
|
msg.id = __XF_MSG_ID(__XF_AP_PROXY(proxy->core), __XF_PORT_SPEC2(src->id, src_port));
|
|
msg.opcode = XF_ROUTE;
|
|
msg.length = sizeof(*m);
|
|
msg.buffer = m;
|
|
|
|
/* ...synchronously execute command on remote DSP */
|
|
XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg));
|
|
|
|
/* ...return buffer to proxy */
|
|
xf_buffer_put(b);
|
|
|
|
/* ...check result is successfull */
|
|
XF_CHK_ERR(msg.opcode == (u32) XF_ROUTE, -ENOMEM);
|
|
|
|
/* ...port binding completed */
|
|
TRACE(GRAPH, _b("[%p]:%u bound to [%p]:%u"), src, src_port, dst, dst_port);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ...port unbinding function */
|
|
int xf_unroute(xf_handle_t *src, u32 src_port)
|
|
{
|
|
xf_proxy_t *proxy = src->proxy;
|
|
xf_buffer_t *b;
|
|
xf_unroute_port_msg_t *m;
|
|
xf_user_msg_t msg;
|
|
int r;
|
|
|
|
/* ...get control buffer */
|
|
XF_CHK_ERR(b = xf_buffer_get(proxy->aux), -EBUSY);
|
|
|
|
/* ...get message buffer */
|
|
m = xf_buffer_data(b);
|
|
|
|
/* ...fill-in message parameters */
|
|
//m->src = __XF_PORT_SPEC2(src->id, src_port);
|
|
|
|
/* ...set command parameters */
|
|
msg.id = __XF_MSG_ID(__XF_AP_PROXY(proxy->core), __XF_PORT_SPEC2(src->id, src_port));
|
|
msg.opcode = XF_UNROUTE;
|
|
msg.length = sizeof(*m);
|
|
msg.buffer = m;
|
|
|
|
/* ...synchronously execute command on remote DSP */
|
|
if ((r = xf_proxy_cmd_exec(proxy, &msg)) != 0)
|
|
{
|
|
TRACE(ERROR, _x("Command failed: %d"), r);
|
|
goto out;
|
|
}
|
|
else if (msg.opcode != (u32) XF_UNROUTE)
|
|
{
|
|
TRACE(ERROR, _x("Port unbinding failed"));
|
|
r = -EBADFD;
|
|
goto out;
|
|
}
|
|
|
|
/* ...port binding completed */
|
|
TRACE(GRAPH, _b("[%p]:%u unbound"), src, src_port);
|
|
|
|
out:
|
|
/* ...return buffer to proxy */
|
|
xf_buffer_put(b);
|
|
|
|
return r;
|
|
}
|
|
|
|
/* ...send a command message to component */
|
|
int xf_command(xf_handle_t *handle, u32 port, u32 opcode, void *buffer, u32 length)
|
|
{
|
|
xf_proxy_t *proxy = handle->proxy;
|
|
xf_proxy_msg_t msg;
|
|
|
|
/* ...fill-in message parameters */
|
|
msg.id = __XF_MSG_ID(__XF_AP_CLIENT(proxy->core, handle->client), __XF_PORT_SPEC2(handle->id, port));
|
|
msg.opcode = opcode;
|
|
msg.length = length;
|
|
XF_CHK_ERR((msg.address = xf_proxy_b2a(proxy, buffer)) != XF_PROXY_BADADDR, -EINVAL);
|
|
|
|
TRACE(CMD, _b("[%p]:[%08x]:(%08x,%u,%p)"), handle, msg.id, opcode, length, buffer);
|
|
|
|
/* ...pass command to IPC layer */
|
|
return XF_CHK_API(xf_ipc_send(&proxy->ipc, &msg, buffer));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Buffer pool API
|
|
******************************************************************************/
|
|
|
|
/* ...allocate buffer pool */
|
|
int xf_pool_alloc(xf_proxy_t *proxy, u32 number, u32 length, xf_pool_type_t type, xf_pool_t **pool, s32 id,
|
|
xaf_mem_malloc_fxn_t xaf_malloc, xaf_mem_free_fxn_t xaf_free)
|
|
{
|
|
xf_pool_t *p;
|
|
xf_buffer_t *b;
|
|
void *data;
|
|
int r;
|
|
|
|
/* ...unused arg */
|
|
(void) type;
|
|
|
|
/* ...basic validity checks; number of buffers is positive */
|
|
XF_CHK_ERR(number > 0, -EINVAL);
|
|
|
|
/* ...get properly aligned buffer length */
|
|
length = (length + XF_PROXY_ALIGNMENT - 1) & ~(XF_PROXY_ALIGNMENT - 1);
|
|
|
|
/* ...allocate data structure */
|
|
p = xaf_malloc(offset_of(xf_pool_t, buffer) + number * sizeof(xf_buffer_t), id);
|
|
XF_CHK_ERR(p, -ENOMEM);
|
|
|
|
/* ...issue memory pool allocation request to remote DSP */
|
|
xf_proxy_lock(proxy);
|
|
r = xf_proxy_buffer_alloc(proxy, number * length, &p->p);
|
|
xf_proxy_unlock(proxy);
|
|
|
|
/* ...if operation is failed, do cleanup */
|
|
if (r < 0)
|
|
{
|
|
TRACE(ERROR, _x("failed to allocate buffer: %d"), r);
|
|
xaf_free(p, id);
|
|
return r;
|
|
}
|
|
else
|
|
{
|
|
/* ...set pool parameters */
|
|
p->number = number, p->length = length;
|
|
p->proxy = proxy;
|
|
}
|
|
|
|
/* ...create individual buffers and link them into free list */
|
|
for (p->free = b = &p->buffer[0], data = p->p; number > 0; number--, b++)
|
|
{
|
|
/* ...set address of the buffer (no length there) */
|
|
b->address = data;
|
|
|
|
/* ...file buffer into the free list */
|
|
b->link.next = b + 1;
|
|
|
|
/* ...advance data pointer in contiguous buffer */
|
|
data = (unsigned char *) data + length;
|
|
}
|
|
|
|
/* ...terminate list of buffers (not too good - tbd) */
|
|
b[-1].link.next = NULL;
|
|
|
|
TRACE(BUFFER, _b("[%p]: pool[%p] created: %u * %u"), proxy, p, p->number, p->length);
|
|
|
|
/* ...return buffer pointer */
|
|
*pool = p;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ...buffer pool destruction */
|
|
void xf_pool_free(xf_pool_t *pool, s32 id, xaf_mem_free_fxn_t xaf_free)
|
|
{
|
|
xf_proxy_t *proxy = pool->proxy;
|
|
|
|
/* ...check buffers are all freed - tbd */
|
|
|
|
/* ...use global proxy lock for pool operations protection */
|
|
xf_proxy_lock(proxy);
|
|
|
|
/* ...release allocated buffer on remote DSP */
|
|
xf_proxy_buffer_free(proxy, pool->p, pool->length * pool->number);
|
|
|
|
/* ...release global proxy lock */
|
|
xf_proxy_unlock(proxy);
|
|
|
|
/* ...deallocate pool structure itself */
|
|
xaf_free(pool, id);
|
|
|
|
TRACE(BUFFER, _b("[%p]::pool[%p] destroyed"), proxy, pool);
|
|
}
|
|
|
|
/* ...get new buffer from a pool */
|
|
xf_buffer_t * xf_buffer_get(xf_pool_t *pool)
|
|
{
|
|
xf_buffer_t *b;
|
|
|
|
/* ...use global proxy lock for pool operations protection */
|
|
xf_proxy_lock(pool->proxy);
|
|
|
|
/* ...take buffer from a head of the free list */
|
|
if ((b = pool->free) != NULL)
|
|
{
|
|
/* ...advance free list head */
|
|
pool->free = b->link.next, b->link.pool = pool;
|
|
|
|
TRACE(BUFFER, _b("pool[%p]::get[%p]"), pool, b);
|
|
}
|
|
|
|
xf_proxy_unlock(pool->proxy);
|
|
|
|
return b;
|
|
}
|
|
|
|
/* ...return buffer back to pool */
|
|
void xf_buffer_put(xf_buffer_t *buffer)
|
|
{
|
|
xf_pool_t *pool = buffer->link.pool;
|
|
|
|
/* ...use global proxy lock for pool operations protection */
|
|
xf_proxy_lock(pool->proxy);
|
|
|
|
/* ...put buffer back to a pool */
|
|
buffer->link.next = pool->free, pool->free = buffer;
|
|
|
|
TRACE(BUFFER, _b("pool[%p]::put[%p]"), pool, buffer);
|
|
|
|
xf_proxy_unlock(pool->proxy);
|
|
}
|