A list of cached buffer is maintained which will get reused when
needed and this buffer list will get freed during device release.
Co-developed-by: Anandu Krishnan E <quic_anane@xxxxxxxxxxx>
Signed-off-by: Anandu Krishnan E <quic_anane@xxxxxxxxxxx>
Signed-off-by: Ekansh Gupta <quic_ekangupt@xxxxxxxxxxx>
---
drivers/misc/fastrpc.c | 133 +++++++++++++++++++++++++++++++++++++-------
include/uapi/misc/fastrpc.h | 8 +++
2 files changed, 122 insertions(+), 19 deletions(-)
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 30d4d04..a961a66 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -41,6 +41,10 @@
#define INIT_FILE_NAMELEN_MAX (128)
#define FASTRPC_DEVICE_NAME "fastrpc"
+/* Maximum buffers cached in cached buffer list */
+#define FASTRPC_MAX_CACHED_BUFS (32)
+#define FASTRPC_MAX_CACHE_BUF_SIZE (8*1024*1024)
+
/* Add memory to static PD pool, protection thru XPU */
#define ADSP_MMAP_HEAP_ADDR 4
/* MAP static DMA buffer on DSP User PD */
@@ -195,6 +199,7 @@ struct fastrpc_buf {
struct dma_buf *dmabuf;
struct device *dev;
void *virt;
+ u32 type;
u64 phys;
u64 size;
/* Lock for dma buf attachments */
@@ -293,6 +298,7 @@ struct fastrpc_user {
struct list_head maps;
struct list_head pending;
struct list_head mmaps;
+ struct list_head cached_bufs;
struct fastrpc_channel_ctx *cctx;
struct fastrpc_session_ctx *sctx;
@@ -300,6 +306,8 @@ struct fastrpc_user {
int tgid;
int pd;
+ /* total cached buffers */
+ u32 num_cached_buf;
bool is_secure_dev;
/* Lock for lists */
spinlock_t lock;
@@ -391,17 +399,95 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
return ret;
}
-static void fastrpc_buf_free(struct fastrpc_buf *buf)
+static void __fastrpc_buf_free(struct fastrpc_buf *buf)
{
dma_free_coherent(buf->dev, buf->size, buf->virt,
FASTRPC_PHYS(buf->phys));
kfree(buf);
}
+static void fastrpc_cached_buf_list_add(struct fastrpc_buf *buf)
+{
+ struct fastrpc_user *fl = buf->fl;
+
+ if (buf->size < FASTRPC_MAX_CACHE_BUF_SIZE) {
+ spin_lock(&fl->lock);
+ if (fl->num_cached_buf > FASTRPC_MAX_CACHED_BUFS) {
+ spin_unlock(&fl->lock);
+ goto skip_buf_cache;
+ }
+
+ list_add_tail(&buf->node, &fl->cached_bufs);
+ fl->num_cached_buf++;
+ buf->type = -1;
+ spin_unlock(&fl->lock);
+ }
+ return;
+
+skip_buf_cache:
+ __fastrpc_buf_free(buf);
+}
+
+static void fastrpc_buf_free(struct fastrpc_buf *buf, bool cache)
+{
+ if (cache)
+ fastrpc_cached_buf_list_add(buf);
+ else
+ __fastrpc_buf_free(buf);
+}
+
+static inline bool fastrpc_get_cached_buf(struct fastrpc_user *fl,
+ size_t size, int buf_type, struct fastrpc_buf **obuf)
+{
+ bool found = false;
+ struct fastrpc_buf *buf, *n, *cbuf = NULL;
+
+ if (buf_type == USER_BUF)
+ return found;
+
+ /* find the smallest buffer that fits in the cache */
+ spin_lock(&fl->lock);
+ list_for_each_entry_safe(buf, n, &fl->cached_bufs, node) {
+ if (buf->size >= size && (!cbuf || cbuf->size > buf->size))
+ cbuf = buf;
+ }
+ if (cbuf) {
+ list_del_init(&cbuf->node);
+ fl->num_cached_buf--;
+ }
+ spin_unlock(&fl->lock);
+ if (cbuf) {
+ cbuf->type = buf_type;
+ *obuf = cbuf;
+ found = true;
+ }
+
+ return found;
+}
+
+static void fastrpc_cached_buf_list_free(struct fastrpc_user *fl)
+{
+ struct fastrpc_buf *buf, *n, *free;
+
+ do {
+ free = NULL;
+ spin_lock(&fl->lock);
+ list_for_each_entry_safe(buf, n, &fl->cached_bufs, node) {
+ list_del(&buf->node);
+ fl->num_cached_buf--;
+ free = buf;
+ break;
+ }
+ spin_unlock(&fl->lock);
+ if (free)
+ fastrpc_buf_free(free, false);
+ } while (free);
+}
+
static int __fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
u64 size, struct fastrpc_buf **obuf)
{
- struct fastrpc_buf *buf;
+ struct fastrpc_buf *buf = NULL;
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
@@ -432,16 +518,23 @@ static int __fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
}
static int fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
- u64 size, struct fastrpc_buf **obuf)
+ u64 size, u32 buf_type, struct fastrpc_buf **obuf)
{
int ret;
struct fastrpc_buf *buf;
+ if (fastrpc_get_cached_buf(fl, size, buf_type, obuf))
+ return 0;
ret = __fastrpc_buf_alloc(fl, dev, size, obuf);
- if (ret)
- return ret;
+ if (ret == -ENOMEM) {
+ fastrpc_cached_buf_list_free(fl);
+ ret = __fastrpc_buf_alloc(fl, dev, size, obuf);
+ if (ret)
+ return ret;
+ }
buf = *obuf;
+ buf->type = buf_type;
if (fl->sctx && fl->sctx->sid)
buf->phys += ((u64)fl->sctx->sid << 32);
@@ -490,7 +583,7 @@ static void fastrpc_context_free(struct kref *ref)
fastrpc_map_put(ctx->maps[i]);
if (ctx->buf)
- fastrpc_buf_free(ctx->buf);
+ fastrpc_buf_free(ctx->buf, true);
spin_lock_irqsave(&cctx->lock, flags);
idr_remove(&cctx->ctx_idr, ctx->ctxid >> 4);
@@ -674,7 +767,7 @@ static void fastrpc_release(struct dma_buf *dmabuf)
{
struct fastrpc_buf *buffer = dmabuf->priv;
- fastrpc_buf_free(buffer);
+ fastrpc_buf_free(buffer, false);
}
static int fastrpc_dma_buf_attach(struct dma_buf *dmabuf,
@@ -951,7 +1044,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
ctx->msg_sz = pkt_size;
- err = fastrpc_buf_alloc(ctx->fl, dev, pkt_size, &ctx->buf);
+ err = fastrpc_buf_alloc(ctx->fl, dev, pkt_size, METADATA_BUF, &ctx->buf);
if (err)
return err;
@@ -1334,7 +1427,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err);
}
err_map:
- fastrpc_buf_free(fl->cctx->remote_heap);
+ fastrpc_buf_free(fl->cctx->remote_heap, false);
err_name:
kfree(name);
err:
@@ -1403,7 +1496,7 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
memlen = ALIGN(max(INIT_FILELEN_MAX, (int)init.filelen * 4),
1024 * 1024);
err = fastrpc_buf_alloc(fl, fl->sctx->dev, memlen,
- &imem);
+ INITMEM_BUF, &imem);
if (err)
goto err_alloc;
@@ -1450,7 +1543,7 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
err_invoke:
fl->init_mem = NULL;
- fastrpc_buf_free(imem);
+ fastrpc_buf_free(imem, false);
err_alloc:
fastrpc_map_put(map);
err:
@@ -1521,7 +1614,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
spin_unlock_irqrestore(&cctx->lock, flags);
if (fl->init_mem)
- fastrpc_buf_free(fl->init_mem);
+ fastrpc_buf_free(fl->init_mem, false);
list_for_each_entry_safe(ctx, n, &fl->pending, node) {
list_del(&ctx->node);
@@ -1533,9 +1626,10 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
list_del(&buf->node);
- fastrpc_buf_free(buf);
+ fastrpc_buf_free(buf, false);
}
+ fastrpc_cached_buf_list_free(fl);
fastrpc_session_free(cctx, fl->sctx);
fastrpc_channel_ctx_put(cctx);
@@ -1570,6 +1664,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
INIT_LIST_HEAD(&fl->maps);
INIT_LIST_HEAD(&fl->mmaps);
INIT_LIST_HEAD(&fl->user);
+ INIT_LIST_HEAD(&fl->cached_bufs);
fl->tgid = current->tgid;
fl->cctx = cctx;
fl->is_secure_dev = fdevice->secure;
@@ -1600,7 +1695,7 @@ static int fastrpc_dmabuf_alloc(struct fastrpc_user *fl, char __user *argp)
if (copy_from_user(&bp, argp, sizeof(bp)))
return -EFAULT;
- err = fastrpc_buf_alloc(fl, fl->sctx->dev, bp.size, &buf);
+ err = fastrpc_buf_alloc(fl, fl->sctx->dev, bp.size, USER_BUF, &buf);
if (err)
return err;
exp_info.ops = &fastrpc_dma_buf_ops;
@@ -1610,7 +1705,7 @@ static int fastrpc_dmabuf_alloc(struct fastrpc_user *fl, char __user *argp)
buf->dmabuf = dma_buf_export(&exp_info);
if (IS_ERR(buf->dmabuf)) {
err = PTR_ERR(buf->dmabuf);
- fastrpc_buf_free(buf);
+ fastrpc_buf_free(buf, false);
return err;
}
@@ -1805,7 +1900,7 @@ static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *
spin_lock(&fl->lock);
list_del(&buf->node);
spin_unlock(&fl->lock);
- fastrpc_buf_free(buf);
+ fastrpc_buf_free(buf, false);
} else {
dev_err(dev, "unmmap\tpt 0x%09lx ERROR\n", buf->raddr);
}
@@ -1866,7 +1961,7 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
return -EINVAL;
}
- err = fastrpc_buf_alloc(fl, fl->sctx->dev, req.size, &buf);
+ err = fastrpc_buf_alloc(fl, fl->sctx->dev, req.size, USER_BUF, &buf);
if (err) {
dev_err(dev, "failed to allocate buffer\n");
return err;
@@ -1935,7 +2030,7 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
err_assign:
fastrpc_req_munmap_impl(fl, buf);
err_invoke:
- fastrpc_buf_free(buf);
+ fastrpc_buf_free(buf, false);
return err;
}
@@ -2380,7 +2475,7 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
list_del(&buf->node);
if (cctx->remote_heap)
- fastrpc_buf_free(cctx->remote_heap);
+ fastrpc_buf_free(cctx->remote_heap, false);
of_platform_depopulate(&rpdev->dev);
diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
index f33d914..91c7c4f 100644
--- a/include/uapi/misc/fastrpc.h
+++ b/include/uapi/misc/fastrpc.h
@@ -64,6 +64,14 @@ enum fastrpc_proc_attr {
FASTRPC_MODE_PRIVILEGED = (1 << 6),
};
+ /* Types of fastrpc DMA bufs sent to DSP */
+ enum fastrpc_buf_type {
+ METADATA_BUF,
+ COPYDATA_BUF,
+ INITMEM_BUF,
+ USER_BUF,
+};
+
/* Fastrpc attribute for memory protection of buffers */
#define FASTRPC_ATTR_SECUREMAP (1)