Merge tag 'mkp-scsi-postmerge' of git://git.kernel.org/pub/scm/linux/kernel/git/mkp...
[linux-2.6-microblaze.git] / drivers / misc / fastrpc.c
index 98603e2..1b1a794 100644 (file)
@@ -33,7 +33,6 @@
 #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 */
@@ -186,6 +185,7 @@ struct fastrpc_channel_ctx {
        struct idr ctx_idr;
        struct list_head users;
        struct miscdevice miscdev;
+       struct kref refcount;
 };
 
 struct fastrpc_user {
@@ -279,8 +279,11 @@ static int fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
 
        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);
@@ -290,6 +293,25 @@ static int fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
        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;
@@ -313,6 +335,8 @@ static void fastrpc_context_free(struct kref *ref)
        kfree(ctx->maps);
        kfree(ctx->olaps);
        kfree(ctx);
+
+       fastrpc_channel_ctx_put(cctx);
 }
 
 static void fastrpc_context_get(struct fastrpc_invoke_ctx *ctx)
@@ -419,6 +443,9 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
                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;
@@ -448,6 +475,7 @@ err_idr:
        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);
@@ -499,6 +527,7 @@ static int fastrpc_dma_buf_attach(struct dma_buf *dmabuf,
                              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;
        }
 
@@ -522,6 +551,7 @@ static void fastrpc_dma_buf_detatch(struct dma_buf *dmabuf,
        mutex_lock(&buffer->lock);
        list_del(&a->node);
        mutex_unlock(&buffer->lock);
+       sg_free_table(&a->sgt);
        kfree(a);
 }
 
@@ -884,6 +914,9 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
        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);
@@ -1120,6 +1153,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
        }
 
        fastrpc_session_free(cctx, fl->sctx);
+       fastrpc_channel_ctx_put(cctx);
 
        mutex_destroy(&fl->mutex);
        kfree(fl);
@@ -1138,6 +1172,9 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
        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);
@@ -1163,26 +1200,6 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
        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;
@@ -1218,8 +1235,6 @@ static int fastrpc_dmabuf_alloc(struct fastrpc_user *fl, char __user *argp)
                return -EFAULT;
        }
 
-       get_dma_buf(buf->dmabuf);
-
        return 0;
 }
 
@@ -1287,9 +1302,6 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
        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;
@@ -1395,10 +1407,6 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
        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");
@@ -1417,6 +1425,10 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
                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]);
@@ -1425,6 +1437,8 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
        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);
@@ -1459,7 +1473,9 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
 
        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,