summaryrefslogtreecommitdiff
path: root/drivers/char/adsprpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/adsprpc.c')
-rw-r--r--drivers/char/adsprpc.c114
1 files changed, 79 insertions, 35 deletions
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 69bfaa0bc6f4..1662707f0d1a 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -298,7 +299,8 @@ struct fastrpc_mmap {
int uncached;
int secure;
uintptr_t attr;
- bool is_filemap; /*flag to indicate map used in process init*/
+ bool is_filemap; /* flag to indicate map used in process init */
+ unsigned int ctx_refs; /* Indicates reference count for context map */
};
struct fastrpc_perf {
@@ -334,6 +336,7 @@ struct fastrpc_file {
struct fastrpc_perf perf;
struct dentry *debugfs_file;
struct mutex map_mutex;
+ struct mutex internal_map_mutex;
char *debug_buf;
/* Identifies the device (MINOR_NUM_DEV / MINOR_NUM_SECURE_DEV) */
int dev_minor;
@@ -473,9 +476,7 @@ static void fastrpc_mmap_add(struct fastrpc_mmap *map)
} else {
struct fastrpc_file *fl = map->fl;
- spin_lock(&fl->hlock);
hlist_add_head(&map->hn, &fl->maps);
- spin_unlock(&fl->hlock);
}
}
@@ -506,21 +507,17 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va,
}
spin_unlock(&me->hlock);
} else {
- spin_lock(&fl->hlock);
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
if (va >= map->va &&
va + len <= map->va + map->len &&
map->fd == fd) {
- if (map->refs + 1 == INT_MAX) {
- spin_unlock(&fl->hlock);
+ if (map->refs + 1 == INT_MAX)
return -ETOOMANYREFS;
- }
map->refs++;
match = map;
break;
}
}
- spin_unlock(&fl->hlock);
}
if (match) {
*ppmap = match;
@@ -560,7 +557,7 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
hlist_for_each_entry_safe(map, n, &me->maps, hn) {
if (map->refs == 1 && map->raddr == va &&
map->raddr + map->len == va + len &&
- /*Remove map if not used in process initialization*/
+ /* Remove map if not used in process initialization */
!map->is_filemap) {
match = map;
hlist_del_init(&map->hn);
@@ -572,18 +569,17 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
*ppmap = match;
return 0;
}
- spin_lock(&fl->hlock);
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
- if (map->refs == 1 && map->raddr == va &&
+ /* Remove if only one reference map and no context map */
+ if (map->refs == 1 && !map->ctx_refs && map->raddr == va &&
map->raddr + map->len == va + len &&
- /*Remove map if not used in process initialization*/
+ /* Remove map if not used in process initialization */
!map->is_filemap) {
match = map;
hlist_del_init(&map->hn);
break;
}
}
- spin_unlock(&fl->hlock);
if (match) {
*ppmap = match;
return 0;
@@ -614,17 +610,13 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map)
}
if (map->flags == ADSP_MMAP_HEAP_ADDR ||
map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
- spin_lock(&me->hlock);
map->refs--;
- if (!map->refs)
+ if (!map->refs && !map->ctx_refs)
hlist_del_init(&map->hn);
- spin_unlock(&me->hlock);
} else {
- spin_lock(&fl->hlock);
map->refs--;
- if (!map->refs)
+ if (!map->refs && !map->ctx_refs)
hlist_del_init(&map->hn);
- spin_unlock(&fl->hlock);
}
if (map->refs > 0)
return;
@@ -716,6 +708,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, unsigned attr,
map->fd = fd;
map->attr = attr;
map->is_filemap = false;
+ map->ctx_refs = 0;
if (mflags == ADSP_MMAP_HEAP_ADDR ||
mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
DEFINE_DMA_ATTRS(rh_attrs);
@@ -1133,8 +1126,13 @@ static void context_free(struct smq_invoke_ctx *ctx)
spin_lock(&ctx->fl->hlock);
hlist_del_init(&ctx->hn);
spin_unlock(&ctx->fl->hlock);
- for (i = 0; i < nbufs; ++i)
+ mutex_lock(&ctx->fl->map_mutex);
+ for (i = 0; i < nbufs; ++i) {
+ if (ctx->maps[i] && ctx->maps[i]->ctx_refs)
+ ctx->maps[i]->ctx_refs--;
fastrpc_mmap_free(ctx->maps[i]);
+ }
+ mutex_unlock(&ctx->fl->map_mutex);
fastrpc_buf_free(ctx->buf, 1);
fastrpc_buf_free(ctx->lbuf, 1);
ctx->magic = 0;
@@ -1274,10 +1272,14 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
uintptr_t buf = (uintptr_t)lpra[i].buf.pv;
size_t len = lpra[i].buf.len;
+ mutex_lock(&ctx->fl->map_mutex);
if (ctx->fds[i] && (ctx->fds[i] != -1))
fastrpc_mmap_create(ctx->fl, ctx->fds[i],
ctx->attrs[i], buf, len,
mflags, &ctx->maps[i]);
+ if (ctx->maps[i])
+ ctx->maps[i]->ctx_refs++;
+ mutex_unlock(&ctx->fl->map_mutex);
ipage += 1;
}
metalen = copylen = (size_t)&ipage[0];
@@ -1494,7 +1496,11 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
if (err)
goto bail;
} else {
+ mutex_lock(&ctx->fl->map_mutex);
+ if (ctx->maps[i]->ctx_refs)
+ ctx->maps[i]->ctx_refs--;
fastrpc_mmap_free(ctx->maps[i]);
+ mutex_unlock(&ctx->fl->map_mutex);
ctx->maps[i] = NULL;
}
}
@@ -1903,10 +1909,12 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
init->filelen))
goto bail;
if (init->filelen) {
+ mutex_lock(&fl->map_mutex);
VERIFY(err, !fastrpc_mmap_create(fl, init->filefd, 0,
init->file, init->filelen, mflags, &file));
if (file)
file->is_filemap = true;
+ mutex_unlock(&fl->map_mutex);
if (err)
goto bail;
}
@@ -1996,9 +2004,11 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
inbuf.pageslen = 0;
if (!me->staticpd_flags) {
inbuf.pageslen = 1;
+ mutex_lock(&fl->map_mutex);
VERIFY(err, !fastrpc_mmap_create(fl, -1, 0, init->mem,
init->memlen, ADSP_MMAP_REMOTE_HEAP_ADDR,
&mem));
+ mutex_unlock(&fl->map_mutex);
if (err)
goto bail;
phys = mem->phys;
@@ -2050,10 +2060,15 @@ bail:
if (mem->flags == ADSP_MMAP_REMOTE_HEAP_ADDR)
hyp_assign_phys(mem->phys, (uint64_t)mem->size,
destVM, 1, srcVM, hlosVMperm, 1);
+ mutex_lock(&fl->map_mutex);
fastrpc_mmap_free(mem);
+ mutex_unlock(&fl->map_mutex);
}
- if (file)
+ if (file) {
+ mutex_lock(&fl->map_mutex);
fastrpc_mmap_free(file);
+ mutex_unlock(&fl->map_mutex);
+ }
return err;
}
@@ -2309,7 +2324,7 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
struct fastrpc_buf *rbuf = NULL, *free = NULL;
struct hlist_node *n;
- mutex_lock(&fl->map_mutex);
+ mutex_lock(&fl->internal_map_mutex);
spin_lock(&fl->hlock);
hlist_for_each_entry_safe(rbuf, n, &fl->remote_bufs, hn_rem) {
if (rbuf->raddr && (rbuf->flags == ADSP_MMAP_ADD_PAGES)) {
@@ -2328,11 +2343,13 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
if (err)
goto bail;
fastrpc_buf_free(rbuf, 0);
- mutex_unlock(&fl->map_mutex);
+ mutex_unlock(&fl->internal_map_mutex);
return err;
}
+ mutex_lock(&fl->map_mutex);
VERIFY(err, !fastrpc_mmap_remove(fl, ud->vaddrout, ud->size, &map));
+ mutex_unlock(&fl->map_mutex);
if (err)
goto bail;
if (map) {
@@ -2340,12 +2357,17 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
map->phys, map->size, map->flags));
if (err)
goto bail;
+ mutex_lock(&fl->map_mutex);
fastrpc_mmap_free(map);
+ mutex_unlock(&fl->map_mutex);
}
bail:
- if (err && map)
+ if (err && map) {
+ mutex_lock(&fl->map_mutex);
fastrpc_mmap_add(map);
- mutex_unlock(&fl->map_mutex);
+ mutex_unlock(&fl->map_mutex);
+ }
+ mutex_unlock(&fl->internal_map_mutex);
return err;
}
@@ -2358,7 +2380,7 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl,
uintptr_t raddr = 0;
int err = 0;
- mutex_lock(&fl->map_mutex);
+ mutex_lock(&fl->internal_map_mutex);
if (ud->flags == ADSP_MMAP_ADD_PAGES) {
DEFINE_DMA_ATTRS(dma_attr);
@@ -2385,9 +2407,11 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl,
} else {
uintptr_t va_to_dsp;
+ mutex_lock(&fl->map_mutex);
VERIFY(err, !fastrpc_mmap_create(fl, ud->fd, 0,
(uintptr_t)ud->vaddrin, ud->size,
ud->flags, &map));
+ mutex_unlock(&fl->map_mutex);
if (err)
goto bail;
@@ -2404,9 +2428,16 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl,
}
ud->vaddrout = raddr;
bail:
- if (err && map)
- fastrpc_mmap_free(map);
- mutex_unlock(&fl->map_mutex);
+ if (err) {
+ if (map) {
+ mutex_lock(&fl->map_mutex);
+ fastrpc_mmap_free(map);
+ mutex_unlock(&fl->map_mutex);
+ }
+ if (!IS_ERR_OR_NULL(rbuf))
+ fastrpc_buf_free(rbuf, 0);
+ }
+ mutex_unlock(&fl->internal_map_mutex);
return err;
}
@@ -2562,8 +2593,8 @@ static void fastrpc_session_free(struct fastrpc_channel_ctx *chan,
static int fastrpc_file_free(struct fastrpc_file *fl)
{
- struct hlist_node *n;
- struct fastrpc_mmap *map = NULL;
+ struct hlist_node *n = NULL;
+ struct fastrpc_mmap *map = NULL, *lmap = NULL;
int cid;
if (!fl)
@@ -2587,9 +2618,18 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
fastrpc_buf_free(fl->init_mem, 0);
fastrpc_context_list_dtor(fl);
fastrpc_cached_buf_list_free(fl);
- hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
- fastrpc_mmap_free(map);
- }
+ mutex_lock(&fl->map_mutex);
+ do {
+ lmap = NULL;
+ hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
+ hlist_del_init(&map->hn);
+ lmap = map;
+ break;
+ }
+ fastrpc_mmap_free(lmap);
+ } while (lmap);
+ mutex_unlock(&fl->map_mutex);
+
if (fl->ssrcount == fl->apps->channel[cid].ssrcount)
kref_put_mutex(&fl->apps->channel[cid].kref,
fastrpc_channel_close, &fl->apps->smd_mutex);
@@ -2600,6 +2640,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
bail:
fastrpc_remote_buf_list_free(fl);
mutex_destroy(&fl->map_mutex);
+ mutex_destroy(&fl->internal_map_mutex);
kfree(fl);
return 0;
}
@@ -2611,7 +2652,6 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
if (fl) {
if (fl->debugfs_file != NULL)
debugfs_remove(fl->debugfs_file);
-
fastrpc_file_free(fl);
file->private_data = NULL;
}
@@ -2914,6 +2954,7 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer,
map->secure, map->attr);
}
mutex_unlock(&fl->map_mutex);
+ spin_lock(&fl->hlock);
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"\n%s %s %s\n", title,
" LIST OF PENDING SMQCONTEXTS ", title);
@@ -3025,8 +3066,10 @@ static int fastrpc_channel_open(struct fastrpc_file *fl)
}
if (cid == 0 && me->channel[cid].ssrcount !=
me->channel[cid].prevssrcount) {
+ mutex_lock(&fl->map_mutex);
if (fastrpc_mmap_remove_ssr(fl))
pr_err("ADSPRPC: SSR: Failed to unmap remote heap\n");
+ mutex_unlock(&fl->map_mutex);
me->channel[cid].prevssrcount =
me->channel[cid].ssrcount;
}
@@ -3091,6 +3134,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
fl->debugfs_file = debugfs_file;
memset(&fl->perf, 0, sizeof(fl->perf));
filp->private_data = fl;
+ mutex_init(&fl->internal_map_mutex);
mutex_init(&fl->map_mutex);
spin_lock(&me->hlock);
hlist_add_head(&fl->hn, &me->drivers);