summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorDaniel Baluta <daniel.baluta@nxp.com>2018-10-04 16:34:29 +0300
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:51:56 +0800
commit17aa1ae7609a2dbb1e705fb6b4766451662afc49 (patch)
treebaa4cd1a9a2ea7cd9070c68a4b0aff03e0518058 /sound/soc
parent1aeb3e481a292ae78906e5cb0f4f0d8b57f05ad3 (diff)
MLK-18497-4: ASoC: fsl: dsp: Add message buffer pool API
Memory is allocated to clients from memory pools. A memory pool allocation is requested to DSP framework via XF_ALLOC command and freed via XF_FREE. Memory pool allocation API offers two functions: * xf_pool_alloc, allocate a number of buffers of given length * xf_pool_free, free memory area allocated for a pool. Once a buffer pool is allocated users can handle buffers using the following API: * xf_buffer_get(pool), gets a buffer from a pool * xf_buffer_put(buf), puts back a buffer into its pool Reviewed-by: Cosmin-Gabriel Samoila <cosmin.samoila@nxp.com> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/fsl/Makefile2
-rw-r--r--sound/soc/fsl/fsl_dsp.h3
-rw-r--r--sound/soc/fsl/fsl_dsp_pool.c150
-rw-r--r--sound/soc/fsl/fsl_dsp_pool.h113
-rw-r--r--sound/soc/fsl/fsl_dsp_proxy.h3
5 files changed, 270 insertions, 1 deletions
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 <linux/slab.h>
+
+#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 <linux/types.h>
+#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 {