[RFC][PATCH 2/4] drm: Add drm_flip helper

2012-09-12 Thread ville.syrj...@linux.intel.com
From: Ville Syrj?l? 

The drm_flip mechanism can be used to implement robust page flipping
support, and also to synchronize the flips on multiple hardware
scanout engines (eg. CRTCs and overlays).

Signed-off-by: Ville Syrj?l? 
---
 drivers/gpu/drm/Makefile   |2 +-
 drivers/gpu/drm/drm_flip.c |  374 
 include/drm/drm_flip.h |  244 +
 3 files changed, 619 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_flip.c
 create mode 100644 include/drm/drm_flip.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index f65f65e..72ce54a 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -12,7 +12,7 @@ drm-y   :=drm_auth.o drm_buffer.o drm_bufs.o 
drm_cache.o \
drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
drm_crtc.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \
-   drm_trace_points.o drm_global.o drm_prime.o
+   drm_trace_points.o drm_global.o drm_prime.o drm_flip.o

 drm-$(CONFIG_COMPAT) += drm_ioc32.o

diff --git a/drivers/gpu/drm/drm_flip.c b/drivers/gpu/drm/drm_flip.c
new file mode 100644
index 000..4e716a3
--- /dev/null
+++ b/drivers/gpu/drm/drm_flip.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Ville Syrj?l? 
+ */
+
+#include 
+
+static void drm_flip_driver_cleanup(struct work_struct *work)
+{
+   struct drm_flip *flip, *next;
+   struct drm_flip_driver *driver =
+   container_of(work, struct drm_flip_driver, cleanup_work);
+   LIST_HEAD(list);
+
+   spin_lock_irq(>lock);
+
+   list_cut_position(,
+ >cleanup_list,
+ driver->cleanup_list.prev);
+
+   spin_unlock_irq(>lock);
+
+   if (list_empty())
+   return;
+
+   list_for_each_entry_safe(flip, next, , list) {
+   struct drm_flip_helper *helper = flip->helper;
+
+   WARN_ON(!flip->finished);
+
+   helper->funcs->cleanup(flip);
+   }
+}
+
+static void drm_flip_driver_finish(struct work_struct *work)
+{
+   struct drm_flip *flip, *next;
+   struct drm_flip_driver *driver =
+   container_of(work, struct drm_flip_driver, finish_work);
+   LIST_HEAD(list);
+   bool need_cleanup = false;
+
+   spin_lock_irq(>lock);
+
+   list_cut_position(,
+ >finish_list,
+ driver->finish_list.prev);
+
+   spin_unlock_irq(>lock);
+
+   if (list_empty())
+   return;
+
+   list_for_each_entry_safe(flip, next, , list) {
+   struct drm_flip_helper *helper = flip->helper;
+
+   helper->funcs->finish(flip);
+
+   spin_lock_irq(>lock);
+
+   flip->finished = true;
+
+   /*
+* It's possible that drm_flip_set_scanout() was called after we
+* pulled this flip from finish_list, in which case the flip
+* could be in need of cleanup, but not on cleanup_list.
+*/
+   if (flip == helper->scanout_flip) {
+   list_del_init(>list);
+   } else {
+   need_cleanup = true;
+   list_move_tail(>list, >cleanup_list);
+   }
+
+   spin_unlock_irq(>lock);
+   }
+
+   if (need_cleanup)
+   queue_work(driver->wq, >cleanup_work);
+}
+
+static bool drm_flip_set_scanout(struct drm_flip_helper *helper,
+struct drm_flip *flip)
+{
+   struct drm_flip_driver *driver = helper->driver;
+   struct drm_flip *old = helper->scanout_flip;
+
+   

[RFC][PATCH 2/4] drm: Add drm_flip helper

2012-09-12 Thread ville . syrjala
From: Ville Syrjälä ville.syrj...@linux.intel.com

The drm_flip mechanism can be used to implement robust page flipping
support, and also to synchronize the flips on multiple hardware
scanout engines (eg. CRTCs and overlays).

Signed-off-by: Ville Syrjälä ville.syrj...@linux.intel.com
---
 drivers/gpu/drm/Makefile   |2 +-
 drivers/gpu/drm/drm_flip.c |  374 
 include/drm/drm_flip.h |  244 +
 3 files changed, 619 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_flip.c
 create mode 100644 include/drm/drm_flip.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index f65f65e..72ce54a 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -12,7 +12,7 @@ drm-y   :=drm_auth.o drm_buffer.o drm_bufs.o 
drm_cache.o \
drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
drm_crtc.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \
-   drm_trace_points.o drm_global.o drm_prime.o
+   drm_trace_points.o drm_global.o drm_prime.o drm_flip.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 
diff --git a/drivers/gpu/drm/drm_flip.c b/drivers/gpu/drm/drm_flip.c
new file mode 100644
index 000..4e716a3
--- /dev/null
+++ b/drivers/gpu/drm/drm_flip.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the Software),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Ville Syrjälä ville.syrj...@linux.intel.com
+ */
+
+#include drm/drm_flip.h
+
+static void drm_flip_driver_cleanup(struct work_struct *work)
+{
+   struct drm_flip *flip, *next;
+   struct drm_flip_driver *driver =
+   container_of(work, struct drm_flip_driver, cleanup_work);
+   LIST_HEAD(list);
+
+   spin_lock_irq(driver-lock);
+
+   list_cut_position(list,
+ driver-cleanup_list,
+ driver-cleanup_list.prev);
+
+   spin_unlock_irq(driver-lock);
+
+   if (list_empty(list))
+   return;
+
+   list_for_each_entry_safe(flip, next, list, list) {
+   struct drm_flip_helper *helper = flip-helper;
+
+   WARN_ON(!flip-finished);
+
+   helper-funcs-cleanup(flip);
+   }
+}
+
+static void drm_flip_driver_finish(struct work_struct *work)
+{
+   struct drm_flip *flip, *next;
+   struct drm_flip_driver *driver =
+   container_of(work, struct drm_flip_driver, finish_work);
+   LIST_HEAD(list);
+   bool need_cleanup = false;
+
+   spin_lock_irq(driver-lock);
+
+   list_cut_position(list,
+ driver-finish_list,
+ driver-finish_list.prev);
+
+   spin_unlock_irq(driver-lock);
+
+   if (list_empty(list))
+   return;
+
+   list_for_each_entry_safe(flip, next, list, list) {
+   struct drm_flip_helper *helper = flip-helper;
+
+   helper-funcs-finish(flip);
+
+   spin_lock_irq(driver-lock);
+
+   flip-finished = true;
+
+   /*
+* It's possible that drm_flip_set_scanout() was called after we
+* pulled this flip from finish_list, in which case the flip
+* could be in need of cleanup, but not on cleanup_list.
+*/
+   if (flip == helper-scanout_flip) {
+   list_del_init(flip-list);
+   } else {
+   need_cleanup = true;
+   list_move_tail(flip-list, driver-cleanup_list);
+   }
+
+   spin_unlock_irq(driver-lock);
+   }
+
+   if (need_cleanup)
+   queue_work(driver-wq, driver-cleanup_work);
+}
+
+static bool drm_flip_set_scanout(struct drm_flip_helper *helper,
+struct