video: tegra: nvavp: Add a clock request ioctl
Hyung Taek Ryoo [Fri, 11 May 2012 18:19:00 +0000 (11:19 -0700)]
Add nvavp_force_clock_stay_on ioctl which provides way for user-mode driver
to request the VDE/BSEV clocks. This change is to fix a hang during DRM
session close. The AVP driver may have already turned
the clocks off since playback was paused prior to session teardown. This
situation can cause the OTF driver on secure side to hang if the VDE/BSEV
clocks are not explicitly enabled prior to calling session terminate.

Bug 960130
Bug 961015
Bug 979102

Change-Id: I3c09a6766f50a01ed04fbfd03e723ad9e978909f
Reviewed-on: http://git-master/r/102024
Reviewed-by: Prajakta Gudadhe <pgudadhe@nvidia.com>
Tested-by: Prajakta Gudadhe <pgudadhe@nvidia.com>

drivers/media/video/tegra/nvavp/nvavp_dev.c
include/linux/tegra_nvavp.h

index 14e4dc2..4627c51 100644 (file)
@@ -127,6 +127,7 @@ struct nvavp_clientctx {
        struct nvmap_handle_ref *gather_mem;
        int num_relocs;
        struct nvavp_info *nvavp;
+       u32 clk_reqs;
 };
 
 static struct clk *nvavp_clk_get(struct nvavp_info *nvavp, int id)
@@ -1039,6 +1040,38 @@ static int nvavp_wake_avp_ioctl(struct file *filp, unsigned int cmd,
        return 0;
 }
 
+static int nvavp_force_clock_stay_on_ioctl(struct file *filp, unsigned int cmd,
+                                                       unsigned long arg)
+{
+       struct nvavp_clientctx *clientctx = filp->private_data;
+       struct nvavp_info *nvavp = clientctx->nvavp;
+       struct nvavp_clock_stay_on_state_args clock;
+
+       if (copy_from_user(&clock, (void __user *)arg,
+                          sizeof(struct nvavp_clock_stay_on_state_args)))
+               return -EFAULT;
+
+       dev_dbg(&nvavp->nvhost_dev->dev, "%s: state=%d\n",
+               __func__, clock.state);
+
+       if (clock.state != NVAVP_CLOCK_STAY_ON_DISABLED &&
+           clock.state !=  NVAVP_CLOCK_STAY_ON_ENABLED) {
+               dev_err(&nvavp->nvhost_dev->dev, "%s: invalid argument=%d\n",
+                       __func__, clock.state);
+               return -EINVAL;
+       }
+
+       mutex_lock(&nvavp->open_lock);
+       if (clock.state) {
+               if (clientctx->clk_reqs++ == 0)
+                       nvavp_clks_enable(nvavp);
+       } else {
+               if (--clientctx->clk_reqs == 0)
+                       nvavp_clks_disable(nvavp);
+       }
+       mutex_unlock(&nvavp->open_lock);
+       return 0;
+}
 
 static int tegra_nvavp_open(struct inode *inode, struct file *filp)
 {
@@ -1092,6 +1125,10 @@ static int tegra_nvavp_release(struct inode *inode, struct file *filp)
                goto out;
        }
 
+       /* if this client had any requests, drop our clk ref */
+       if (clientctx->clk_reqs)
+               nvavp_clks_disable(nvavp);
+
        if (nvavp->refcount > 0)
                nvavp->refcount--;
        if (!nvavp->refcount)
@@ -1133,6 +1170,9 @@ static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd,
        case NVAVP_IOCTL_WAKE_AVP:
                ret = nvavp_wake_avp_ioctl(filp, cmd, arg);
                break;
+       case NVAVP_IOCTL_FORCE_CLOCK_STAY_ON:
+               ret = nvavp_force_clock_stay_on_ioctl(filp, cmd, arg);
+               break;
        default:
                ret = -EINVAL;
                break;
index 9710544..6774d0e 100644 (file)
@@ -64,6 +64,15 @@ struct nvavp_clock_args {
        __u32 rate;
 };
 
+enum nvavp_clock_stay_on_state {
+       NVAVP_CLOCK_STAY_ON_DISABLED = 0,
+       NVAVP_CLOCK_STAY_ON_ENABLED
+};
+
+struct nvavp_clock_stay_on_state_args {
+       enum nvavp_clock_stay_on_state  state;
+};
+
 #define NVAVP_IOCTL_MAGIC              'n'
 
 #define NVAVP_IOCTL_SET_NVMAP_FD       _IOW(NVAVP_IOCTL_MAGIC, 0x60, \
@@ -78,8 +87,10 @@ struct nvavp_clock_args {
                                        struct nvavp_clock_args)
 #define NVAVP_IOCTL_WAKE_AVP           _IOR(NVAVP_IOCTL_MAGIC, 0x66, \
                                        __u32)
+#define NVAVP_IOCTL_FORCE_CLOCK_STAY_ON        _IOW(NVAVP_IOCTL_MAGIC, 0x67, \
+                                       struct nvavp_clock_stay_on_state_args)
 
 #define NVAVP_IOCTL_MIN_NR             _IOC_NR(NVAVP_IOCTL_SET_NVMAP_FD)
-#define NVAVP_IOCTL_MAX_NR             _IOC_NR(NVAVP_IOCTL_WAKE_AVP)
+#define NVAVP_IOCTL_MAX_NR             _IOC_NR(NVAVP_IOCTL_FORCE_CLOCK_STAY_ON)
 
 #endif /* __LINUX_TEGRA_NVAVP_H */