diff options
Diffstat (limited to 'drivers/media/platform/tegra/nvavp/nvavp_dev.c')
-rw-r--r-- | drivers/media/platform/tegra/nvavp/nvavp_dev.c | 87 |
1 files changed, 69 insertions, 18 deletions
diff --git a/drivers/media/platform/tegra/nvavp/nvavp_dev.c b/drivers/media/platform/tegra/nvavp/nvavp_dev.c index 843ea338c949..25dee33ea9aa 100644 --- a/drivers/media/platform/tegra/nvavp/nvavp_dev.c +++ b/drivers/media/platform/tegra/nvavp/nvavp_dev.c @@ -1,7 +1,7 @@ /* * drivers/media/video/tegra/nvavp/nvavp_dev.c * - * Copyright (c) 2011-2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved. * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any @@ -135,6 +135,7 @@ struct nvavp_info { int mbox_from_avp_pend_irq; struct mutex open_lock; + struct mutex submit_lock; int refcount; int video_initialized; int video_refcnt; @@ -871,6 +872,7 @@ static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr, u32 wordcount = 0; u32 index, value = -1; int ret = 0; + u32 max_index = 0; mutex_lock(&nvavp->open_lock); nvavp_runtime_get(nvavp); @@ -885,7 +887,9 @@ static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr, mutex_lock(&channel_info->pushbuffer_lock); /* check for pushbuffer wrapping */ - if (channel_info->pushbuf_index >= channel_info->pushbuf_fence) + max_index = channel_info->pushbuf_fence; + max_index = ext_ucode_flag ? max_index : max_index - (sizeof(u32) * 4); + if (channel_info->pushbuf_index >= max_index) channel_info->pushbuf_index = 0; if (!ext_ucode_flag) { @@ -1518,24 +1522,31 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd, syncpt.id = NVSYNCPT_INVALID; syncpt.value = 0; + mutex_lock(&nvavp->submit_lock); if (_IOC_DIR(cmd) & _IOC_WRITE) { if (copy_from_user(&hdr, (void __user *)arg, - sizeof(struct nvavp_pushbuffer_submit_hdr))) + sizeof(struct nvavp_pushbuffer_submit_hdr))) { + mutex_unlock(&nvavp->submit_lock); return -EFAULT; + } } - if (!hdr.cmdbuf.mem) + if (!hdr.cmdbuf.mem) { + mutex_unlock(&nvavp->submit_lock); return 0; + } if (hdr.num_relocs > NVAVP_MAX_RELOCATION_COUNT) { dev_err(&nvavp->nvhost_dev->dev, "invalid num_relocs %d\n", hdr.num_relocs); + mutex_unlock(&nvavp->submit_lock); return -EINVAL; } if (copy_from_user(clientctx->relocs, (void __user *)hdr.relocs, sizeof(struct nvavp_reloc) * hdr.num_relocs)) { + mutex_unlock(&nvavp->submit_lock); return -EFAULT; } @@ -1543,6 +1554,7 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd, if (IS_ERR(cmdbuf_dmabuf)) { dev_err(&nvavp->nvhost_dev->dev, "invalid cmd buffer handle %08x\n", hdr.cmdbuf.mem); + mutex_unlock(&nvavp->submit_lock); return PTR_ERR(cmdbuf_dmabuf); } @@ -1679,6 +1691,7 @@ err_dmabuf_map: dma_buf_detach(cmdbuf_dmabuf, cmdbuf_attach); err_dmabuf_attach: dma_buf_put(cmdbuf_dmabuf); + mutex_unlock(&nvavp->submit_lock); return ret; } @@ -1692,19 +1705,26 @@ static int nvavp_pushbuffer_submit_compat_ioctl(struct file *filp, struct nvavp_pushbuffer_submit_hdr_v32 hdr_v32; struct nvavp_pushbuffer_submit_hdr __user *user_hdr; int ret = 0; + mutex_lock(&nvavp->submit_lock); if (_IOC_DIR(cmd) & _IOC_WRITE) { if (copy_from_user(&hdr_v32, (void __user *)arg, - sizeof(struct nvavp_pushbuffer_submit_hdr_v32))) + sizeof(struct nvavp_pushbuffer_submit_hdr_v32))) { + mutex_unlock(&nvavp->submit_lock); return -EFAULT; + } } - if (!hdr_v32.cmdbuf.mem) + if (!hdr_v32.cmdbuf.mem) { + mutex_unlock(&nvavp->submit_lock); return 0; + } user_hdr = compat_alloc_user_space(sizeof(*user_hdr)); - if (!access_ok(VERIFY_WRITE, user_hdr, sizeof(*user_hdr))) + if (!access_ok(VERIFY_WRITE, user_hdr, sizeof(*user_hdr))) { + mutex_unlock(&nvavp->submit_lock); return -EFAULT; + } if (__put_user(hdr_v32.cmdbuf.mem, &user_hdr->cmdbuf.mem) || __put_user(hdr_v32.cmdbuf.offset, &user_hdr->cmdbuf.offset) @@ -1714,21 +1734,29 @@ static int nvavp_pushbuffer_submit_compat_ioctl(struct file *filp, || __put_user(hdr_v32.num_relocs, &user_hdr->num_relocs) || __put_user((void __user *)(unsigned long)hdr_v32.syncpt, &user_hdr->syncpt) - || __put_user(hdr_v32.flags, &user_hdr->flags)) + || __put_user(hdr_v32.flags, &user_hdr->flags)) { + mutex_unlock(&nvavp->submit_lock); return -EFAULT; + } + mutex_unlock(&nvavp->submit_lock); ret = nvavp_pushbuffer_submit_ioctl(filp, cmd, (unsigned long)user_hdr); if (ret) return ret; - if (__get_user(hdr_v32.syncpt, &user_hdr->syncpt)) + mutex_lock(&nvavp->submit_lock); + if (__get_user(hdr_v32.syncpt, (uintptr_t *)&user_hdr->syncpt)) + { + mutex_unlock(&nvavp->submit_lock); return -EFAULT; + } if (copy_to_user((void __user *)arg, &hdr_v32, sizeof(struct nvavp_pushbuffer_submit_hdr_v32))) { ret = -EFAULT; } + mutex_unlock(&nvavp->submit_lock); return ret; } #endif @@ -2009,10 +2037,17 @@ out: static int tegra_nvavp_video_release(struct inode *inode, struct file *filp) { - struct nvavp_clientctx *clientctx = filp->private_data; - struct nvavp_info *nvavp = clientctx->nvavp; + struct nvavp_clientctx *clientctx; + struct nvavp_info *nvavp; int ret = 0; + clientctx = filp->private_data; + if (!clientctx) + return ret; + nvavp = clientctx->nvavp; + if (!nvavp) + return ret; + mutex_lock(&nvavp->open_lock); filp->private_data = NULL; ret = tegra_nvavp_release(clientctx, NVAVP_VIDEO_CHANNEL); @@ -2025,10 +2060,17 @@ static int tegra_nvavp_video_release(struct inode *inode, struct file *filp) static int tegra_nvavp_audio_release(struct inode *inode, struct file *filp) { - struct nvavp_clientctx *clientctx = filp->private_data; - struct nvavp_info *nvavp = clientctx->nvavp; + struct nvavp_clientctx *clientctx; + struct nvavp_info *nvavp; int ret = 0; + clientctx = filp->private_data; + if (!clientctx) + return ret; + nvavp = clientctx->nvavp; + if (!nvavp) + return ret; + mutex_lock(&nvavp->open_lock); filp->private_data = NULL; ret = tegra_nvavp_release(clientctx, NVAVP_AUDIO_CHANNEL); @@ -2040,9 +2082,15 @@ static int tegra_nvavp_audio_release(struct inode *inode, int tegra_nvavp_audio_client_release(nvavp_clientctx_t client) { struct nvavp_clientctx *clientctx = client; - struct nvavp_info *nvavp = clientctx->nvavp; + struct nvavp_info *nvavp; int ret = 0; + if (!clientctx) + return ret; + nvavp = clientctx->nvavp; + if (!nvavp) + return ret; + mutex_lock(&nvavp->open_lock); ret = tegra_nvavp_release(clientctx, NVAVP_AUDIO_CHANNEL); mutex_unlock(&nvavp->open_lock); @@ -2084,10 +2132,8 @@ nvavp_channel_open(struct file *filp, struct nvavp_channel_open_args *arg) return err; } - fd_install(fd, file); - - nonseekable_open(file->f_inode, filp); mutex_lock(&nvavp->open_lock); + err = tegra_nvavp_open(nvavp, (struct nvavp_clientctx **)&file->private_data, clientctx->channel_id); @@ -2097,9 +2143,13 @@ nvavp_channel_open(struct file *filp, struct nvavp_channel_open_args *arg) mutex_unlock(&nvavp->open_lock); return err; } - mutex_unlock(&nvavp->open_lock); arg->channel_fd = fd; + + nonseekable_open(file->f_inode, filp); + fd_install(fd, file); + + mutex_unlock(&nvavp->open_lock); return err; } @@ -2380,6 +2430,7 @@ static int tegra_nvavp_probe(struct platform_device *ndev) nvavp->mbox_from_avp_pend_irq = irq; mutex_init(&nvavp->open_lock); + mutex_init(&nvavp->submit_lock); for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++) mutex_init(&nvavp->channel_info[channel_id].pushbuffer_lock); |