]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: host: interface for error notify
authorShridhar Rasal <srasal@nvidia.com>
Fri, 11 Apr 2014 10:17:31 +0000 (15:47 +0530)
committerTerje Bergstrom <tbergstrom@nvidia.com>
Tue, 15 Apr 2014 07:18:38 +0000 (00:18 -0700)
Implement interface to notify user space when errors.

Bug 1469448

Change-Id: Id59e312ed69dcd11672ca5d1c2b71fde21972b94
Signed-off-by: Shridhar Rasal <srasal@nvidia.com>
Reviewed-on: http://git-master/r/395164
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
drivers/video/tegra/host/bus_client.c
drivers/video/tegra/host/host1x/host1x_cdma.c
drivers/video/tegra/host/nvhost_channel.c
drivers/video/tegra/host/nvhost_channel.h
include/linux/nvhost.h

index b429edd95425cc3c686d8c5239ec70385e8e21b3..4c7c4eca1a0775bdb59bf5d3f1d4c6a1c87faa43 100644 (file)
@@ -272,6 +272,72 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
        return __nvhost_channelopen(inode, NULL, filp);
 }
 
+void nvhost_set_notifier(struct nvhost_channel *ch, __u32 error)
+{
+       if (ch->error_notifier_ref) {
+               struct timespec time_data;
+               u64 nsec;
+               getnstimeofday(&time_data);
+               nsec = ((u64)time_data.tv_sec) * 1000000000u +
+                               (u64)time_data.tv_nsec;
+               ch->error_notifier->time_stamp.nanoseconds[0] =
+                               (u32)nsec;
+               ch->error_notifier->time_stamp.nanoseconds[1] =
+                               (u32)(nsec >> 32);
+               ch->error_notifier->info32 = error;
+               ch->error_notifier->status = 0xffff;
+               dev_err(&ch->dev->dev, "error notifier set to %d\n", error);
+       }
+}
+
+void nvhost_free_error_notifiers(struct nvhost_channel *ch)
+{
+       if (ch->error_notifier_ref) {
+               dma_buf_vunmap(ch->error_notifier_ref, ch->error_notifier_va);
+               dma_buf_put(ch->error_notifier_ref);
+               ch->error_notifier_ref = 0;
+               ch->error_notifier = 0;
+               ch->error_notifier_va = 0;
+       }
+}
+
+static int nvhost_init_error_notifier(struct nvhost_channel *ch,
+               struct nvhost_set_error_notifier *args) {
+       void *va;
+
+       struct dma_buf *dmabuf;
+       if (!args->mem) {
+               dev_err(&ch->dev->dev, "invalid memory handle\n");
+               return -EINVAL;
+       }
+
+       dmabuf = dma_buf_get(args->mem);
+
+       if (ch->error_notifier_ref)
+               nvhost_free_error_notifiers(ch);
+
+       if (IS_ERR(dmabuf)) {
+               dev_err(&ch->dev->dev, "Invalid handle: %d\n", args->mem);
+               return -EINVAL;
+       }
+
+       /* map handle */
+       va = dma_buf_vmap(dmabuf);
+       if (!va) {
+               dma_buf_put(dmabuf);
+               dev_err(&ch->dev->dev, "Cannot map notifier handle\n");
+               return -ENOMEM;
+       }
+
+       /* set channel notifiers pointer */
+       ch->error_notifier_ref = dmabuf;
+       ch->error_notifier = va + args->offset;
+       ch->error_notifier_va = va;
+       memset(ch->error_notifier, 0, sizeof(struct nvhost_notification));
+       return 0;
+
+}
+
 static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
                struct nvhost_submit_args *args)
 {
@@ -844,6 +910,10 @@ static long nvhost_channelctl(struct file *filp,
        case NVHOST_IOCTL_CHANNEL_SUBMIT:
                err = nvhost_ioctl_channel_submit(priv, (void *)buf);
                break;
+       case NVHOST_IOCTL_CHANNEL_SET_ERROR_NOTIFIER:
+               err = nvhost_init_error_notifier(priv->ch,
+                       (struct nvhost_set_error_notifier *)buf);
+               break;
        case NVHOST_IOCTL_CHANNEL_SET_TIMEOUT_EX:
        {
                u32 timeout =
index 84e33c2dee6501d3ceb181cff33d76180e03effb..8851248eabc82a08a1dcb9310be0029d436f8e2b 100644 (file)
@@ -481,6 +481,12 @@ static void cdma_timeout_handler(struct work_struct *work)
                return;
        }
 
+       /* set notifier to userspace about submit timeout */
+       if (ch->error_notifier) {
+               nvhost_set_notifier(ch,
+                       NVHOST_CHANNEL_SUBMIT_TIMEOUT);
+       }
+
        if (nvhost_debug_force_timeout_dump ||
                cdma->timeout.timeout_debug_dump)
                nvhost_debug_dump_locked(cdma_to_dev(cdma), ch->chid);
index 615f2643702ad2c14ee8f0e0896e1d7705ce8b6c..33e93520301762907dcb10ee7bbfcfba443f1a2c 100644 (file)
@@ -159,6 +159,8 @@ int nvhost_channel_unmap(struct nvhost_channel *ch)
                mutex_unlock(&host->chlist_mutex);
                return 0;
        }
+       if (ch->error_notifier_ref)
+               nvhost_free_error_notifiers(ch);
 
        dev_dbg(&ch->dev->dev, "channel %d un-mapped\n", ch->chid);
 
index d2f304baa79662e7cb45f773ff598434bfd27742..04796e8d99e4ef637904acd1134a1ebbaaf73e98 100644 (file)
@@ -65,6 +65,11 @@ struct nvhost_channel {
        struct nvhost_as *as;
 
        struct list_head list;
+
+       /* error notificatiers used channel submit timeout */
+       struct dma_buf *error_notifier_ref;
+       struct nvhost_notification *error_notifier;
+       void *error_notifier_va;
 };
 
 #define channel_op(ch)         (ch->ops)
@@ -77,8 +82,9 @@ int nvhost_channel_list_free(struct nvhost_master *host);
 struct nvhost_channel *nvhost_check_channel(struct nvhost_device_data *pdata);
 int nvhost_channel_init(struct nvhost_channel *ch,
        struct nvhost_master *dev);
-
 int nvhost_channel_submit(struct nvhost_job *job);
+void nvhost_set_notifier(struct nvhost_channel *ch, __u32 error);
+void nvhost_free_error_notifiers(struct nvhost_channel *ch);
 
 void nvhost_getchannel(struct nvhost_channel *ch);
 void nvhost_putchannel(struct nvhost_channel *ch);
index aac701d57038330c37bc692d76bdbb60bac7e232..98223bfd2c9963382d772d91089f5a85a94a45ed 100644 (file)
@@ -102,6 +102,7 @@ struct nvhost_notification {
 #define        NVHOST_CHANNEL_FIFO_ERROR_MMU_ERR_FLT   31
        __u16 info16;   /* info returned depends on method 000c-000d */
        __u16 status;   /* user sets bit 15, NV sets status 000e-000f */
+#define        NVHOST_CHANNEL_SUBMIT_TIMEOUT           1
 };
 
 struct nvhost_clock {