diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2017-11-29 14:56:42 +0100 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2017-11-29 14:56:42 +0100 |
commit | 2eecc3c4c63955c3d5860b44422dccd229ec7043 (patch) | |
tree | a3256780705eb959d17dd4c4a622a89f1001d90d /drivers/media/platform | |
parent | 9a315efc7e2646e75e8cc9d1d79e508589ad2202 (diff) | |
parent | b271e8fa67a6d9c4600274a25636cfe00fdd1b68 (diff) |
Merge tag 'tegra-l4t-r21.6' into toradex_tk1_l4t_r21.6
Merge NVIDIA's latest Linux for Tegra aka L4T R21.6 Linux kernel changes
from git://nv-tegra.nvidia.com/linux-3.10.git commit:
b271e8fa67a6d9c4600274a25636cfe00fdd1b68
Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Acked-by: Dominik Sliwa <dominik.sliwa@toradex.com>
Diffstat (limited to 'drivers/media/platform')
-rw-r--r-- | drivers/media/platform/tegra/cam_dev/imx135.c | 6 | ||||
-rw-r--r-- | drivers/media/platform/tegra/cam_dev/of_camera.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/tegra/cam_dev/virtual.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/tegra/camera.c | 85 | ||||
-rw-r--r-- | drivers/media/platform/tegra/nvavp/nvavp_dev.c | 87 |
5 files changed, 149 insertions, 37 deletions
diff --git a/drivers/media/platform/tegra/cam_dev/imx135.c b/drivers/media/platform/tegra/cam_dev/imx135.c index eaa085637aa4..7dd3e9bd61be 100644 --- a/drivers/media/platform/tegra/cam_dev/imx135.c +++ b/drivers/media/platform/tegra/cam_dev/imx135.c @@ -4,7 +4,7 @@ * the virtual PCL driver to handle some special features (hardware resources, * sequences, etc.). * - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -42,11 +42,11 @@ struct imx135_info { }; static int imx135_update( - struct camera_device *cdev, struct cam_update *upd, int num) + struct camera_device *cdev, struct cam_update *upd, u32 num) { /* struct imx135_info *info = dev_get_drvdata(cdev->dev); */ int err = 0; - int idx; + u32 idx; dev_dbg(cdev->dev, "%s %d\n", __func__, num); mutex_lock(&cdev->mutex); diff --git a/drivers/media/platform/tegra/cam_dev/of_camera.c b/drivers/media/platform/tegra/cam_dev/of_camera.c index 460ca1a844e8..f293b9a27cd0 100644 --- a/drivers/media/platform/tegra/cam_dev/of_camera.c +++ b/drivers/media/platform/tegra/cam_dev/of_camera.c @@ -1,7 +1,7 @@ /* * debugfs.c * - * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved. * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -222,7 +222,7 @@ int of_camera_get_property(struct camera_info *cam, unsigned long arg) } /* sanity check */ - if (!param.sizeofvalue) { + if (!param.sizeofvalue || param.sizeofvalue > INT_MAX) { dev_err(cam->dev, "%s invalid property name length %d\n", __func__, param.sizeofvalue); return -EBADF; diff --git a/drivers/media/platform/tegra/cam_dev/virtual.c b/drivers/media/platform/tegra/cam_dev/virtual.c index f08ad1563a73..d25becc1ec24 100644 --- a/drivers/media/platform/tegra/cam_dev/virtual.c +++ b/drivers/media/platform/tegra/cam_dev/virtual.c @@ -41,10 +41,10 @@ struct chip_config { }; static int virtual_update( - struct camera_device *cdev, struct cam_update *upd, int num) + struct camera_device *cdev, struct cam_update *upd, u32 num) { int err = 0; - int idx; + u32 idx; dev_dbg(cdev->dev, "%s %d\n", __func__, num); mutex_lock(&cdev->mutex); diff --git a/drivers/media/platform/tegra/camera.c b/drivers/media/platform/tegra/camera.c index 2542f4210de6..9017e7fcd2cc 100644 --- a/drivers/media/platform/tegra/camera.c +++ b/drivers/media/platform/tegra/camera.c @@ -1,7 +1,7 @@ /* * camera.c - generic camera device driver * - * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved. * * Contributors: * Charlie Huang <chahuang@nvidia.com> @@ -131,12 +131,12 @@ int camera_copy_user_params(unsigned long arg, struct nvc_param *prm) } #endif -int camera_get_params( +int __camera_get_params( struct camera_info *cam, unsigned long arg, int u_size, - struct nvc_param *prm, void **data) + struct nvc_param *prm, void **data, bool zero_size_ok) { void *buf; - unsigned size; + size_t size; #ifdef CONFIG_COMPAT memset(prm, 0, sizeof(*prm)); @@ -156,9 +156,14 @@ int camera_get_params( if (!data) return 0; + if (zero_size_ok && prm->sizeofvalue == 0) { + *data = ZERO_SIZE_PTR; + return 0; + } + size = prm->sizeofvalue * u_size; - buf = kzalloc(size, GFP_KERNEL); - if (!buf) { + buf = kcalloc(prm->sizeofvalue, u_size, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) { dev_err(cam->dev, "%s allocate memory failed!\n", __func__); return -ENOMEM; } @@ -173,6 +178,20 @@ int camera_get_params( return 0; } +static int camera_validate_p_i2c_table(struct camera_info *cam, + const struct nvc_param *params, + const struct camera_reg *p_i2c_table, const char *caller) +{ + u32 idx, last_idx = params->sizeofvalue / sizeof(p_i2c_table[0]); + + for (idx = 0; idx < last_idx; idx++) + if (p_i2c_table[idx].addr == CAMERA_TABLE_END) + return 0; + + dev_err(cam->dev, "%s: table is not properly terminated\n", caller); + return -EINVAL; +} + static int camera_seq_rd(struct camera_info *cam, unsigned long arg) { struct nvc_param params; @@ -184,6 +203,10 @@ static int camera_seq_rd(struct camera_info *cam, unsigned long arg) if (err) return err; + err = camera_validate_p_i2c_table(cam, ¶ms, p_i2c_table, __func__); + if (err) + goto seq_rd_end; + err = camera_dev_rd_table(cam->cdev, p_i2c_table); if (!err && copy_to_user(MAKE_USER_PTR(params.p_value), p_i2c_table, params.sizeofvalue)) { @@ -192,6 +215,7 @@ static int camera_seq_rd(struct camera_info *cam, unsigned long arg) err = -EINVAL; } +seq_rd_end: kfree(p_i2c_table); return err; } @@ -231,7 +255,7 @@ static int camera_seq_wr(struct camera_info *cam, unsigned long arg) } p_i2c_table = devm_kzalloc(cdev->dev, params.sizeofvalue, GFP_KERNEL); - if (p_i2c_table == NULL) { + if (ZERO_OR_NULL_PTR(p_i2c_table)) { dev_err(cam->dev, "%s devm_kzalloc err line %d\n", __func__, __LINE__); return -ENOMEM; @@ -246,6 +270,10 @@ static int camera_seq_wr(struct camera_info *cam, unsigned long arg) goto seq_wr_end; } + err = camera_validate_p_i2c_table(cam, ¶ms, p_i2c_table, __func__); + if (err) + goto seq_wr_end; + switch (params.param) { case CAMERA_SEQ_REGISTER_EXEC: case CAMERA_SEQ_REGISTER_ONLY: @@ -498,13 +526,13 @@ static int camera_new_device(struct camera_info *cam, unsigned long arg) next_dev->client->addr == dev_info.addr) { dev_dbg(cam_desc.dev, "%s: device already exists.\n", __func__); - camera_remove_device(new_dev, false); if (atomic_xchg(&next_dev->in_use, 1)) { dev_err(cam_desc.dev, "%s device %s BUSY\n", __func__, next_dev->name); err = -EBUSY; goto new_device_err; - } + } else + camera_remove_device(new_dev, false); new_dev = next_dev; goto new_device_done; } @@ -586,7 +614,8 @@ static int camera_update(struct camera_info *cam, unsigned long arg) return err; } - err = camera_get_params(cam, arg, sizeof(*upd), ¶m, (void **)&upd); + err = __camera_get_params(cam, arg, sizeof(*upd), ¶m, (void **)&upd, + true); if (err) return err; @@ -657,9 +686,20 @@ static int camera_layout_get(struct camera_info *cam, unsigned long arg) if (err) return err; + if (param.variant > MAX_PARAM_VARIANT) { + dev_err(cam->dev, "%s param variant is too large: %u\n", + __func__, param.variant); + return -EINVAL; + } + if (param.sizeofvalue > MAX_PARAM_SIZE_OF_VALUE) { + dev_err(cam->dev, "%s size of param value is too large: %u\n", + __func__, param.sizeofvalue); + return -EINVAL; + } + len = (int)cam_desc.size_layout - param.variant; if (len <= 0) { - dev_err(cam->dev, "%s invalid offset %d\n", + dev_err(cam->dev, "%s invalid offset %u\n", __func__, param.variant); err = -EINVAL; goto getlayout_end; @@ -838,31 +878,46 @@ static long camera_ioctl(struct file *file, break; case PCLLK_IOCTL_DEV_DEL: mutex_lock(cam_desc.d_mutex); + if (!cam->cdev) { + err = -ENODEV; + mutex_unlock(cam_desc.d_mutex); + break; + } list_del(&cam->cdev->list); - mutex_unlock(cam_desc.d_mutex); camera_remove_device(cam->cdev, true); + mutex_unlock(cam_desc.d_mutex); break; case PCLLK_IOCTL_DEV_FREE: err = camera_free_device(cam, arg); break; case PCLLK_IOCTL_SEQ_WR: + mutex_lock(cam_desc.d_mutex); err = camera_seq_wr(cam, arg); + mutex_unlock(cam_desc.d_mutex); break; case PCLLK_IOCTL_SEQ_RD: + mutex_lock(cam_desc.d_mutex); err = camera_seq_rd(cam, arg); + mutex_unlock(cam_desc.d_mutex); break; case PCLLK_IOCTL_PARAM_RD: /* err = camera_param_rd(cam, arg); */ break; case PCLLK_IOCTL_PWR_WR: /* This is a Guaranteed Level of Service (GLOS) call */ + mutex_lock(cam_desc.d_mutex); err = camera_dev_pwr_set(cam, arg); + mutex_unlock(cam_desc.d_mutex); break; case PCLLK_IOCTL_PWR_RD: + mutex_lock(cam_desc.d_mutex); err = camera_dev_pwr_get(cam, arg); + mutex_unlock(cam_desc.d_mutex); break; case PCLLK_IOCTL_UPDATE: + mutex_lock(cam_desc.d_mutex); err = camera_update(cam, arg); + mutex_unlock(cam_desc.d_mutex); break; case PCLLK_IOCTL_LAYOUT_WR: err = camera_layout_update(cam, arg); @@ -884,16 +939,22 @@ static long camera_ioctl(struct file *file, err = virtual_device_add(cam_desc.dev, arg); break; case PCLLK_IOCTL_32_SEQ_WR: + mutex_lock(cam_desc.d_mutex); err = camera_seq_wr(cam, arg); + mutex_unlock(cam_desc.d_mutex); break; case PCLLK_IOCTL_32_SEQ_RD: + mutex_lock(cam_desc.d_mutex); err = camera_seq_rd(cam, arg); + mutex_unlock(cam_desc.d_mutex); break; case PCLLK_IOCTL_32_PARAM_RD: /* err = camera_param_rd(cam, arg); */ break; case PCLLK_IOCTL_32_UPDATE: + mutex_lock(cam_desc.d_mutex); err = camera_update(cam, arg); + mutex_unlock(cam_desc.d_mutex); break; case PCLLK_IOCTL_32_LAYOUT_WR: err = camera_layout_update(cam, arg); 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); |