]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: host: Support external syncpt cbs
authorArto Merilainen <amerilainen@nvidia.com>
Wed, 5 Mar 2014 13:33:54 +0000 (15:33 +0200)
committerArto Merilainen <amerilainen@nvidia.com>
Tue, 25 Mar 2014 12:39:31 +0000 (05:39 -0700)
This far the nvhost driver has published interface for waiting
syncpoint values synchronously, however, we have need to do similar
waiting asynchronously (i.e. trigger event when certain syncpoint
value has been reached). This patch adds public function
nvhost_intr_register_notifier() that allows registering callbacks.

Change-Id: I3e8a12fad229b264a2ace5bb7f4726e17c90f112
Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-on: http://git-master/r/378342
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
drivers/video/tegra/host/nvhost_intr.c
drivers/video/tegra/host/nvhost_intr.h
include/linux/nvhost.h

index 850d141b6a388e8f0824910a74fcfad38aa41dec..ad41f31d3f7d24eb55a948c5cf86608e849f0937 100644 (file)
@@ -49,6 +49,12 @@ struct nvhost_waitlist {
        int count;
 };
 
+struct nvhost_waitlist_external_notifier {
+       struct nvhost_master *master;
+       void (*callback)(void *, int);
+       void *private_data;
+};
+
 enum waitlist_state {
        WLS_PENDING,
        WLS_REMOVED,
@@ -172,6 +178,18 @@ static void action_wakeup(struct nvhost_waitlist *waiter)
        wake_up(wq);
 }
 
+static void action_notify(struct nvhost_waitlist *waiter)
+{
+       struct nvhost_waitlist_external_notifier *notifier = waiter->data;
+       struct nvhost_master *master = notifier->master;
+
+       notifier->callback(notifier->private_data, waiter->count);
+
+       nvhost_module_idle_mult(master->dev, waiter->count);
+       kfree(notifier);
+       waiter->data = NULL;
+}
+
 static void action_wakeup_interruptible(struct nvhost_waitlist *waiter)
 {
        wait_queue_head_t *wq = waiter->data;
@@ -195,6 +213,7 @@ static action_handler action_handlers[NVHOST_INTR_ACTION_COUNT] = {
        action_signal_sync_pt,
        action_wakeup,
        action_wakeup_interruptible,
+       action_notify,
 };
 
 static void run_handlers(struct list_head completed[NVHOST_INTR_ACTION_COUNT])
@@ -347,6 +366,53 @@ void *nvhost_intr_alloc_waiter()
                        GFP_KERNEL|__GFP_REPEAT);
 }
 
+int nvhost_intr_register_notifier(struct platform_device *pdev,
+                                 u32 id, u32 thresh,
+                                 void (*callback)(void *, int),
+                                 void *private_data)
+{
+       struct nvhost_waitlist *waiter;
+       struct nvhost_waitlist_external_notifier *notifier;
+       struct nvhost_master *master = nvhost_get_host(pdev);
+       int err = 0;
+
+       if (!callback)
+               return -EINVAL;
+
+       waiter = kzalloc(sizeof(*waiter), GFP_KERNEL | __GFP_REPEAT);
+       if (!waiter) {
+               err = -ENOMEM;
+               goto err_alloc_waiter;
+       }
+       notifier = kzalloc(sizeof(*notifier), GFP_KERNEL | __GFP_REPEAT);
+       if (!notifier) {
+               err = -ENOMEM;
+               goto err_alloc_notifier;
+       }
+
+       notifier->master = master;
+       notifier->callback = callback;
+       notifier->private_data = private_data;
+
+       /* make sure host1x stays on */
+       nvhost_module_busy(master->dev);
+
+       err = nvhost_intr_add_action(&master->intr,
+                                    id, thresh,
+                                    NVHOST_INTR_ACTION_NOTIFY,
+                                    notifier,
+                                    waiter,
+                                    NULL);
+
+       return err;
+
+err_alloc_notifier:
+       kfree(waiter);
+err_alloc_waiter:
+       return err;
+}
+EXPORT_SYMBOL(nvhost_intr_register_notifier);
+
 void nvhost_intr_put_ref(struct nvhost_intr *intr, u32 id, void *ref)
 {
        struct nvhost_waitlist *waiter = ref;
index 0f7b7507bff4ad9aa7f65e0371cb19a7ded0e3c7..b7ef9d9b8004db379c66ccae213ce543430c1849 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Tegra Graphics Host Interrupt Management
  *
- * Copyright (c) 2010-2013, NVIDIA Corporation.  All rights reserved.
+ * Copyright (c) 2010-2014, 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,
@@ -59,6 +59,13 @@ enum nvhost_intr_action {
         */
        NVHOST_INTR_ACTION_WAKEUP_INTERRUPTIBLE,
 
+       /**
+        * Notify some external function about completion
+        * 'data' holds pointer to an internal structure that holds a
+        * function pointer and the stored private data
+        */
+       NVHOST_INTR_ACTION_NOTIFY,
+
        NVHOST_INTR_ACTION_COUNT
 };
 
index 48b1ce177a2a238b6ba86737fb5f7bd04d16f433..ab6eb9d7ae7feca5c67080dc0d1735565b293083 100644 (file)
@@ -278,6 +278,12 @@ int nvhost_syncpt_wait_timeout_ext(struct platform_device *dev, u32 id, u32 thre
 int nvhost_syncpt_create_fence_single_ext(struct platform_device *dev,
        u32 id, u32 thresh, const char *name, int *fence_fd);
 
+/* public host1x interrupt management APIs */
+int nvhost_intr_register_notifier(struct platform_device *pdev,
+                                 u32 id, u32 thresh,
+                                 void (*callback)(void *, int),
+                                 void *private_data);
+
 #ifdef CONFIG_TEGRA_GK20A
 int nvhost_vpr_info_fetch(void);
 #else