summaryrefslogtreecommitdiff
path: root/drivers/misc/fastrpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/fastrpc.c')
-rw-r--r--drivers/misc/fastrpc.c107
1 files changed, 68 insertions, 39 deletions
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 1080f9acf70a..f3a49384586d 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -310,6 +310,8 @@ struct fastrpc_user {
spinlock_t lock;
/* lock for allocations */
struct mutex mutex;
+ /* Reference count */
+ struct kref refcount;
};
/* Extract SMMU PA from consolidated IOVA */
@@ -386,7 +388,7 @@ static int fastrpc_map_get(struct fastrpc_map *map)
static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
- struct fastrpc_map **ppmap)
+ struct fastrpc_map **ppmap, bool take_ref)
{
struct fastrpc_map *map = NULL;
struct dma_buf *buf;
@@ -401,6 +403,12 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
if (map->fd != fd || map->buf != buf)
continue;
+ if (take_ref) {
+ ret = fastrpc_map_get(map);
+ if (ret)
+ break;
+ }
+
*ppmap = map;
ret = 0;
break;
@@ -497,15 +505,57 @@ static void fastrpc_channel_ctx_put(struct fastrpc_channel_ctx *cctx)
kref_put(&cctx->refcount, fastrpc_channel_ctx_free);
}
+static void fastrpc_context_put(struct fastrpc_invoke_ctx *ctx);
+
+static void fastrpc_user_free(struct kref *ref)
+{
+ struct fastrpc_user *fl = container_of(ref, struct fastrpc_user, refcount);
+ struct fastrpc_invoke_ctx *ctx, *n;
+ struct fastrpc_map *map, *m;
+ struct fastrpc_buf *buf, *b;
+
+ if (fl->init_mem)
+ fastrpc_buf_free(fl->init_mem);
+
+ list_for_each_entry_safe(ctx, n, &fl->pending, node) {
+ list_del(&ctx->node);
+ fastrpc_context_put(ctx);
+ }
+
+ list_for_each_entry_safe(map, m, &fl->maps, node)
+ fastrpc_map_put(map);
+
+ list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
+ list_del(&buf->node);
+ fastrpc_buf_free(buf);
+ }
+
+ fastrpc_channel_ctx_put(fl->cctx);
+ mutex_destroy(&fl->mutex);
+ kfree(fl);
+}
+
+static void fastrpc_user_get(struct fastrpc_user *fl)
+{
+ kref_get(&fl->refcount);
+}
+
+static void fastrpc_user_put(struct fastrpc_user *fl)
+{
+ kref_put(&fl->refcount, fastrpc_user_free);
+}
+
static void fastrpc_context_free(struct kref *ref)
{
struct fastrpc_invoke_ctx *ctx;
struct fastrpc_channel_ctx *cctx;
+ struct fastrpc_user *fl;
unsigned long flags;
int i;
ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount);
cctx = ctx->cctx;
+ fl = ctx->fl;
for (i = 0; i < ctx->nbufs; i++)
fastrpc_map_put(ctx->maps[i]);
@@ -521,6 +571,8 @@ static void fastrpc_context_free(struct kref *ref)
kfree(ctx->olaps);
kfree(ctx);
+ /* Release the reference taken in fastrpc_context_alloc() */
+ fastrpc_user_put(fl);
fastrpc_channel_ctx_put(cctx);
}
@@ -628,6 +680,8 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
/* Released in fastrpc_context_put() */
fastrpc_channel_ctx_get(cctx);
+ /* Take a reference to user, released in fastrpc_context_free() */
+ fastrpc_user_get(user);
ctx->sc = sc;
ctx->retval = -1;
@@ -658,6 +712,7 @@ err_idr:
spin_lock(&user->lock);
list_del(&ctx->node);
spin_unlock(&user->lock);
+ fastrpc_user_put(user);
fastrpc_channel_ctx_put(cctx);
kfree(ctx->maps);
kfree(ctx->olaps);
@@ -871,19 +926,10 @@ get_err:
static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
u64 len, u32 attr, struct fastrpc_map **ppmap)
{
- struct fastrpc_session_ctx *sess = fl->sctx;
- int err = 0;
-
- if (!fastrpc_map_lookup(fl, fd, ppmap)) {
- if (!fastrpc_map_get(*ppmap))
- return 0;
- dev_dbg(sess->dev, "%s: Failed to get map fd=%d\n",
- __func__, fd);
- }
-
- err = fastrpc_map_attach(fl, fd, len, attr, ppmap);
+ if (!fastrpc_map_lookup(fl, fd, ppmap, true))
+ return 0;
- return err;
+ return fastrpc_map_attach(fl, fd, len, attr, ppmap);
}
/*
@@ -1041,7 +1087,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
pages[i].addr = ctx->maps[i]->dma_addr;
mmap_read_lock(current->mm);
- vma = find_vma(current->mm, ctx->args[i].ptr);
+ vma = vma_lookup(current->mm, ctx->args[i].ptr);
if (vma)
pages[i].addr += (ctx->args[i].ptr & PAGE_MASK) -
vma->vm_start;
@@ -1153,7 +1199,7 @@ cleanup_fdlist:
for (i = 0; i < FASTRPC_MAX_FDLIST; i++) {
if (!fdlist[i])
break;
- if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap))
+ if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false))
fastrpc_map_put(mmap);
}
@@ -1579,9 +1625,6 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
{
struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data;
struct fastrpc_channel_ctx *cctx = fl->cctx;
- struct fastrpc_invoke_ctx *ctx, *n;
- struct fastrpc_map *map, *m;
- struct fastrpc_buf *buf, *b;
unsigned long flags;
fastrpc_release_current_dsp_process(fl);
@@ -1590,28 +1633,10 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
list_del(&fl->user);
spin_unlock_irqrestore(&cctx->lock, flags);
- if (fl->init_mem)
- fastrpc_buf_free(fl->init_mem);
-
- list_for_each_entry_safe(ctx, n, &fl->pending, node) {
- list_del(&ctx->node);
- fastrpc_context_put(ctx);
- }
-
- list_for_each_entry_safe(map, m, &fl->maps, node)
- fastrpc_map_put(map);
-
- list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
- list_del(&buf->node);
- fastrpc_buf_free(buf);
- }
-
fastrpc_session_free(cctx, fl->sctx);
- fastrpc_channel_ctx_put(cctx);
-
- mutex_destroy(&fl->mutex);
- kfree(fl);
file->private_data = NULL;
+ /* Release the reference taken in fastrpc_device_open */
+ fastrpc_user_put(fl);
return 0;
}
@@ -1655,6 +1680,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
spin_lock_irqsave(&cctx->lock, flags);
list_add_tail(&fl->user, &cctx->users);
spin_unlock_irqrestore(&cctx->lock, flags);
+ kref_init(&fl->refcount);
return 0;
}
@@ -2431,7 +2457,6 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
kref_init(&data->refcount);
- dev_set_drvdata(&rpdev->dev, data);
rdev->dma_mask = &data->dma_mask;
dma_set_mask_and_coherent(rdev, DMA_BIT_MASK(32));
INIT_LIST_HEAD(&data->users);
@@ -2440,6 +2465,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
idr_init(&data->ctx_idr);
data->domain_id = domain_id;
data->rpdev = rpdev;
+ dev_set_drvdata(&rpdev->dev, data);
err = of_platform_populate(rdev->of_node, NULL, NULL, rdev);
if (err)
@@ -2513,6 +2539,9 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
if (len < sizeof(*rsp))
return -EINVAL;
+ if (!cctx)
+ return -ENODEV;
+
ctxid = ((rsp->ctx & FASTRPC_CTXID_MASK) >> 4);
spin_lock_irqsave(&cctx->lock, flags);