diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index cb3ea47d507c..ef4d5494265b 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o snd-soc-fsl-audmix-objs := fsl_audmix.o snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o -snd-soc-fsl-dsp-objs := fsl_dsp.o fsl_dsp_proxy.o +snd-soc-fsl-dsp-objs := fsl_dsp.o fsl_dsp_proxy.o fsl_dsp_pool.o snd-soc-fsl-sai-objs := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index b4ab6fc1a9d4..95815fa23c33 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -37,6 +37,9 @@ struct xf_client { /* ...global structure pointer */ void *global; struct xf_message m; + + struct work_struct work; + struct completion compr_complete; }; union xf_client_link { diff --git a/sound/soc/fsl/fsl_dsp_pool.c b/sound/soc/fsl/fsl_dsp_pool.c new file mode 100644 index 000000000000..637454d97231 --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_pool.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Xtensa buffer pool API +// +// Copyright 2018 NXP +// Copyright (c) 2012-2013 by Tensilica Inc. + +#include + +#include "fsl_dsp_pool.h" +#include "fsl_dsp.h" + +/* ...allocate buffer pool */ +int xf_pool_alloc(struct xf_client *client, struct xf_proxy *proxy, + u32 number, u32 length, xf_pool_type_t type, + struct xf_pool **pool) +{ + struct xf_pool *p; + struct xf_buffer *b; + void *data; + struct xf_message msg; + struct xf_message *rmsg; + + /* ...basic sanity checks; number of buffers is positive */ + if (number <=0) + return -EINVAL; + + /* ...get properly aligned buffer length */ + length = ALIGN(length, XF_PROXY_ALIGNMENT); + + p = kzalloc(offsetof(struct xf_pool, buffer) + + number * sizeof(struct xf_buffer), GFP_KERNEL); + if(!p) + return -ENOMEM; + + /* ...prepare command parameters */ + msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_ALLOC; + msg.length = length * number; + msg.buffer = NULL; + msg.ret = 0; + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + if (IS_ERR(rmsg)) { + kfree(p); + return PTR_ERR(rmsg); + } + + p->p = rmsg->buffer; + /* TODO: review cleanup */ + /* xf_msg_free(proxy, rmsg); + * xf_unlock(&proxy->lock); */ + + /* ...if operation is failed, do cleanup */ + /* ...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 += length; + } + + /* ...terminate list of buffers (not too good - tbd) */ + b[-1].link.next = NULL; + + /* ...return buffer pointer */ + *pool = p; + + return 0; +} +/* ...buffer pool destruction */ +int xf_pool_free(struct xf_client *client, struct xf_pool *pool) +{ + struct xf_proxy *proxy; + struct xf_message msg; + struct xf_message *rmsg; + + /* ...basic sanity checks; pool is positive */ + if (pool == NULL) + return -EINVAL; + + /* ...get proxy pointer */ + if ((proxy = pool->proxy) == NULL) + return -EINVAL; + + /* ...prepare command parameters */ + msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_FREE; + msg.length = pool->length * pool->number; + msg.buffer = pool->p; + msg.ret = 0; + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + kfree(pool); + if (IS_ERR(rmsg)) + return PTR_ERR(rmsg); + + /* TODO: review cleanup */ + /* xf_msg_free(proxy, rmsg); + * xf_unlock(&proxy->lock); */ + + return 0; +} + +/* ...get new buffer from a pool */ +struct xf_buffer *xf_buffer_get(struct xf_pool *pool) +{ + struct xf_buffer *b; + + xf_lock(&pool->proxy->lock); + /* ...take buffer from a head of the free list */ + b = pool->free; + if (b) { + /* ...advance free list head */ + pool->free = b->link.next, b->link.pool = pool; + } + + xf_unlock(&pool->proxy->lock); + return b; +} + +/* ...return buffer back to pool */ +void xf_buffer_put(struct xf_buffer *buffer) +{ + struct xf_pool *pool = buffer->link.pool; + + xf_lock(&pool->proxy->lock); + /* ...use global proxy lock for pool operations protection */ + /* ...put buffer back to a pool */ + buffer->link.next = pool->free, pool->free = buffer; + + xf_unlock(&pool->proxy->lock); +} diff --git a/sound/soc/fsl/fsl_dsp_pool.h b/sound/soc/fsl/fsl_dsp_pool.h new file mode 100644 index 000000000000..4a56262faf7f --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_pool.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Xtensa buffer pool API header + * + * Copyright 2018 NXP + * Copyright (c) 2012-2013 by Tensilica Inc + */ +#ifndef FSL_DSP_POOL_H +#define FSL_DSP_POOL_H + +#include +#include "fsl_dsp_proxy.h" + +/* ...buffer pool type */ +typedef u32 xf_pool_type_t; + +/* ...previous declaration of struct */ +struct xf_buffer; +struct xf_pool; +struct xf_handle; +struct xf_message; +struct xf_client; + +/* ...response callback */ +typedef void (*xf_response_cb)(struct xf_handle *h, struct xf_message *msg); + +/* ...buffer pool type */ +enum xf_pool_type { + XF_POOL_AUX = 0, + XF_POOL_INPUT = 1, + XF_POOL_OUTPUT = 2 +}; + +/* ...buffer link pointer */ +union xf_buffer_link { + /* ...pointer to next free buffer in a pool (for free buffer) */ + struct xf_buffer *next; + /* ...reference to a buffer pool (for allocated buffer) */ + struct xf_pool *pool; +}; + +/* ...buffer descriptor */ +struct xf_buffer { + /* ...virtual address of contiguous buffer */ + void *address; + /* ...link pointer */ + union xf_buffer_link link; +}; + +/* ...buffer pool */ +struct xf_pool { + /* ...reference to proxy data */ + struct xf_proxy *proxy; + /* ...length of individual buffer in a pool */ + u32 length; + /* ...number of buffers in a pool */ + u32 number; + /* ...pointer to pool memory */ + void *p; + /* ...pointer to first free buffer in a pool */ + struct xf_buffer *free; + /* ...individual buffers */ + struct xf_buffer buffer[0]; +}; + +/* component handle */ +struct xf_handle { + /* ...reference to proxy data */ + struct xf_proxy *proxy; + /* ...auxiliary control buffer for control transactions */ + struct xf_buffer *aux; + /* ...global client-id of the component */ + u32 id; + /* ...local client number (think about merging into "id" field - tbd) */ + u32 client; + /* ...response processing hook */ + xf_response_cb response; +}; + +/* ...accessor to buffer data */ +static inline void *xf_buffer_data(struct xf_buffer *buffer) +{ + return buffer->address; +} + +/* ...length of buffer data */ +static inline size_t xf_buffer_length(struct xf_buffer *buffer) +{ + struct xf_pool *pool = buffer->link.pool; + + return (size_t)pool->length; +} + +/* ...component client-id (global scope) */ +static inline u32 xf_handle_id(struct xf_handle *handle) +{ + return handle->id; +} + +/* ...pointer to auxiliary buffer */ +static inline void *xf_handle_aux(struct xf_handle *handle) +{ + return xf_buffer_data(handle->aux); +} + +int xf_pool_alloc(struct xf_client *client, struct xf_proxy *proxy, u32 number, + u32 length, xf_pool_type_t type, struct xf_pool **pool); +int xf_pool_free(struct xf_client *client, struct xf_pool *pool); + +struct xf_buffer *xf_buffer_get(struct xf_pool *pool); +void xf_buffer_put(struct xf_buffer *buffer); + +#endif /* FSL_DSP_POOL_H */ diff --git a/sound/soc/fsl/fsl_dsp_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h index dc54dc2d00ef..78b033719eb8 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -309,6 +309,9 @@ struct xf_proxy { /* ...pointer to first free message in the pool */ struct xf_message *free; + + /* ...auxiliary buffer pool for clients */ + struct xf_pool *aux; }; union icm_header_t {