#define FASTRPC_INIT_HANDLE 1
#define FASTRPC_CTXID_MASK (0xFF0)
#define INIT_FILELEN_MAX (64 * 1024 * 1024)
-#define INIT_MEMLEN_MAX (8 * 1024 * 1024)
#define FASTRPC_DEVICE_NAME "fastrpc"
/* Retrives number of input buffers from the scalars parameter */
struct idr ctx_idr;
struct list_head users;
struct miscdevice miscdev;
+ struct kref refcount;
};
struct fastrpc_user {
buf->virt = dma_alloc_coherent(dev, buf->size, (dma_addr_t *)&buf->phys,
GFP_KERNEL);
- if (!buf->virt)
+ if (!buf->virt) {
+ mutex_destroy(&buf->lock);
+ kfree(buf);
return -ENOMEM;
+ }
if (fl->sctx && fl->sctx->sid)
buf->phys += ((u64)fl->sctx->sid << 32);
return 0;
}
+static void fastrpc_channel_ctx_free(struct kref *ref)
+{
+ struct fastrpc_channel_ctx *cctx;
+
+ cctx = container_of(ref, struct fastrpc_channel_ctx, refcount);
+
+ kfree(cctx);
+}
+
+static void fastrpc_channel_ctx_get(struct fastrpc_channel_ctx *cctx)
+{
+ kref_get(&cctx->refcount);
+}
+
+static void fastrpc_channel_ctx_put(struct fastrpc_channel_ctx *cctx)
+{
+ kref_put(&cctx->refcount, fastrpc_channel_ctx_free);
+}
+
static void fastrpc_context_free(struct kref *ref)
{
struct fastrpc_invoke_ctx *ctx;
kfree(ctx->maps);
kfree(ctx->olaps);
kfree(ctx);
+
+ fastrpc_channel_ctx_put(cctx);
}
static void fastrpc_context_get(struct fastrpc_invoke_ctx *ctx)
fastrpc_get_buff_overlaps(ctx);
}
+ /* Released in fastrpc_context_put() */
+ fastrpc_channel_ctx_get(cctx);
+
ctx->sc = sc;
ctx->retval = -1;
ctx->pid = current->pid;
spin_lock(&user->lock);
list_del(&ctx->node);
spin_unlock(&user->lock);
+ fastrpc_channel_ctx_put(cctx);
kfree(ctx->maps);
kfree(ctx->olaps);
kfree(ctx);
FASTRPC_PHYS(buffer->phys), buffer->size);
if (ret < 0) {
dev_err(buffer->dev, "failed to get scatterlist from DMA API\n");
+ kfree(a);
return -EINVAL;
}
mutex_lock(&buffer->lock);
list_del(&a->node);
mutex_unlock(&buffer->lock);
+ sg_free_table(&a->sgt);
kfree(a);
}
if (!fl->sctx)
return -EINVAL;
+ if (!fl->cctx->rpdev)
+ return -EPIPE;
+
ctx = fastrpc_context_alloc(fl, kernel, sc, args);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
}
fastrpc_session_free(cctx, fl->sctx);
+ fastrpc_channel_ctx_put(cctx);
mutex_destroy(&fl->mutex);
kfree(fl);
if (!fl)
return -ENOMEM;
+ /* Released in fastrpc_device_release() */
+ fastrpc_channel_ctx_get(cctx);
+
filp->private_data = fl;
spin_lock_init(&fl->lock);
mutex_init(&fl->mutex);
return 0;
}
-static int fastrpc_dmabuf_free(struct fastrpc_user *fl, char __user *argp)
-{
- struct dma_buf *buf;
- int info;
-
- if (copy_from_user(&info, argp, sizeof(info)))
- return -EFAULT;
-
- buf = dma_buf_get(info);
- if (IS_ERR_OR_NULL(buf))
- return -EINVAL;
- /*
- * one for the last get and other for the ALLOC_DMA_BUFF ioctl
- */
- dma_buf_put(buf);
- dma_buf_put(buf);
-
- return 0;
-}
-
static int fastrpc_dmabuf_alloc(struct fastrpc_user *fl, char __user *argp)
{
struct fastrpc_alloc_dma_buf bp;
return -EFAULT;
}
- get_dma_buf(buf->dmabuf);
-
return 0;
}
case FASTRPC_IOCTL_INIT_CREATE:
err = fastrpc_init_create_process(fl, argp);
break;
- case FASTRPC_IOCTL_FREE_DMA_BUFF:
- err = fastrpc_dmabuf_free(fl, argp);
- break;
case FASTRPC_IOCTL_ALLOC_DMA_BUFF:
err = fastrpc_dmabuf_alloc(fl, argp);
break;
int i, err, domain_id = -1;
const char *domain;
- data = devm_kzalloc(rdev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
err = of_property_read_string(rdev->of_node, "label", &domain);
if (err) {
dev_info(rdev, "FastRPC Domain not specified in DT\n");
return -EINVAL;
}
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
data->miscdev.minor = MISC_DYNAMIC_MINOR;
data->miscdev.name = kasprintf(GFP_KERNEL, "fastrpc-%s",
domains[domain_id]);
if (err)
return err;
+ kref_init(&data->refcount);
+
dev_set_drvdata(&rpdev->dev, data);
dma_set_mask_and_coherent(rdev, DMA_BIT_MASK(32));
INIT_LIST_HEAD(&data->users);
misc_deregister(&cctx->miscdev);
of_platform_depopulate(&rpdev->dev);
- kfree(cctx);
+
+ cctx->rpdev = NULL;
+ fastrpc_channel_ctx_put(cctx);
}
static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,