video: tegra: dc: disuse notifier
Ilan Aelion [Fri, 10 Aug 2012 19:53:10 +0000 (13:53 -0600)]
Due to issues with rcu notifiers on secureos, modifying dc flip
notifications to use a simple callback instead.

Bug 1028850

Change-Id: Iebf2a6d64d7316e3df2b88444201f9f9a29698c5
Signed-off-by: Ilan Aelion <iaelion@nvidia.com>
Reviewed-on: http://git-master/r/123103
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Jon Mayo <jmayo@nvidia.com>
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-by: Nitin Kumbhar <nkumbhar@nvidia.com>

arch/arm/mach-tegra/include/mach/dc.h
drivers/misc/tegra-throughput.c
drivers/video/tegra/dc/ext/dev.c

index 92b0e07..5a861a4 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/pm.h>
 #include <linux/types.h>
 #include <drm/drm_fixed.h>
-#include <linux/notifier.h>
 
 #define TEGRA_MAX_DC           2
 #define DC_N_WINDOWS           3
@@ -646,8 +645,8 @@ struct tegra_dc_edid {
 struct tegra_dc_edid *tegra_dc_get_edid(struct tegra_dc *dc);
 void tegra_dc_put_edid(struct tegra_dc_edid *edid);
 
-int tegra_dc_register_flip_notifier(struct notifier_block *nb);
-int tegra_dc_unregister_flip_notifier(struct notifier_block *nb);
+int tegra_dc_set_flip_callback(void (*callback)(void));
+int tegra_dc_unset_flip_callback(void);
 int tegra_dc_get_panel_sync_rate(void);
 
 #endif
index 13b1c47..f361335 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <linux/kthread.h>
 #include <linux/ktime.h>
-#include <linux/notifier.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -46,12 +45,10 @@ static void set_throughput_hint(struct work_struct *work)
        nvhost_scale3d_set_throughput_hint(throughput_hint);
 }
 
-static int throughput_flip_notifier(struct notifier_block *nb,
-                                            unsigned long val,
-                                            void *data)
+static int throughput_flip_callback(void)
 {
-       /* only register flips when a single display is active */
-       if (val != 1 || multiple_app_disable)
+       /* only register flips when a single app is active */
+       if (multiple_app_disable)
                return NOTIFY_DONE;
        else {
                long timediff;
@@ -66,7 +63,7 @@ static int throughput_flip_notifier(struct notifier_block *nb,
                                last_frame_time = (unsigned short) timediff;
 
                        if (last_frame_time == 0) {
-                               pr_warn("%s: notifications %lld nsec apart\n",
+                               pr_warn("%s: flips %lld nsec apart\n",
                                        __func__, now.tv64 - last_flip.tv64);
                                return NOTIFY_DONE;
                        }
@@ -83,10 +80,6 @@ static int throughput_flip_notifier(struct notifier_block *nb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block throughput_flip_nb = {
-       .notifier_call = throughput_flip_notifier,
-};
-
 static int sync_rate;
 static int throughput_active_app_count;
 
@@ -105,17 +98,15 @@ static void reset_target_frame_time(void)
                __func__, sync_rate, target_frame_time);
 }
 
-static int notifier_initialized;
+static int callback_initialized;
 
 static int throughput_open(struct inode *inode, struct file *file)
 {
-       int need_init = 0;
-
        spin_lock(&lock);
 
-       if (!notifier_initialized) {
-               notifier_initialized = 1;
-               need_init = 1;
+       if (!callback_initialized) {
+               callback_initialized = 1;
+               tegra_dc_set_flip_callback(throughput_flip_callback);
        }
 
        throughput_active_app_count++;
@@ -124,8 +115,6 @@ static int throughput_open(struct inode *inode, struct file *file)
 
        spin_unlock(&lock);
 
-       if (need_init)
-               tegra_dc_register_flip_notifier(&throughput_flip_nb);
 
        pr_debug("throughput_open node %p file %p\n", inode, file);
 
@@ -134,23 +123,18 @@ static int throughput_open(struct inode *inode, struct file *file)
 
 static int throughput_release(struct inode *inode, struct file *file)
 {
-       int need_deinit = 0;
-
        spin_lock(&lock);
 
        throughput_active_app_count--;
        if (throughput_active_app_count == 0) {
                reset_target_frame_time();
                multiple_app_disable = 0;
-               notifier_initialized = 0;
-               need_deinit = 1;
+               callback_initialized = 0;
+               tegra_dc_unset_flip_callback();
        }
 
        spin_unlock(&lock);
 
-       if (need_deinit)
-               tegra_dc_unregister_flip_notifier(&throughput_flip_nb);
-
        pr_debug("throughput_release node %p file %p\n", inode, file);
 
        return 0;
index 966dbe1..6a17fd8 100644 (file)
@@ -275,31 +275,40 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
        return 0;
 }
 
-static struct srcu_notifier_head tegra_dc_flip_notifier_list;
-static bool init_tegra_dc_flip_notifier_list_called;
-static int __init init_tegra_dc_flip_notifier_list(void)
+static void (*flip_callback)(void);
+static spinlock_t flip_callback_lock;
+static bool init_tegra_dc_flip_callback_called;
+
+static int __init init_tegra_dc_flip_callback(void)
 {
-       srcu_init_notifier_head(&tegra_dc_flip_notifier_list);
-       init_tegra_dc_flip_notifier_list_called = true;
+       spin_lock_init(&flip_callback_lock);
+       init_tegra_dc_flip_callback_called = true;
        return 0;
 }
 
-pure_initcall(init_tegra_dc_flip_notifier_list);
+pure_initcall(init_tegra_dc_flip_callback);
 
-int tegra_dc_register_flip_notifier(struct notifier_block *nb)
+int tegra_dc_set_flip_callback(void (*callback)(void))
 {
-       WARN_ON(!init_tegra_dc_flip_notifier_list_called);
+       WARN_ON(!init_tegra_dc_flip_callback_called);
+
+       spin_lock(&flip_callback_lock);
+       flip_callback = callback;
+       spin_unlock(&flip_callback_lock);
 
-       return srcu_notifier_chain_register(
-                       &tegra_dc_flip_notifier_list, nb);
+       return 0;
 }
-EXPORT_SYMBOL(tegra_dc_register_flip_notifier);
+EXPORT_SYMBOL(tegra_dc_set_flip_callback);
 
-int tegra_dc_unregister_flip_notifier(struct notifier_block *nb)
+int tegra_dc_unset_flip_callback()
 {
-       return srcu_notifier_chain_unregister(&tegra_dc_flip_notifier_list, nb);
+       spin_lock(&flip_callback_lock);
+       flip_callback = NULL;
+       spin_unlock(&flip_callback_lock);
+
+       return 0;
 }
-EXPORT_SYMBOL(tegra_dc_unregister_flip_notifier);
+EXPORT_SYMBOL(tegra_dc_unset_flip_callback);
 
 static void tegra_dc_ext_flip_worker(struct work_struct *work)
 {
@@ -354,9 +363,12 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
                tegra_dc_update_windows(wins, nr_win);
                /* TODO: implement swapinterval here */
                tegra_dc_sync_windows(wins, nr_win);
-               if (!tegra_dc_has_multiple_dc())
-                       srcu_notifier_call_chain(&tegra_dc_flip_notifier_list,
-                                                1UL, NULL);
+               if (!tegra_dc_has_multiple_dc()) {
+                       spin_lock(&flip_callback_lock);
+                       if (flip_callback)
+                               flip_callback();
+                       spin_unlock(&flip_callback_lock);
+               }
        }
 
        for (i = 0; i < DC_N_WINDOWS; i++) {