Arg, and w/o word wrapping this time.

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index c23b3a9..5273ce0 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -871,6 +871,127 @@ static int i915_set_status_page(struct drm_device *dev, 
void *data,
        return 0;
 }
 
+bool
+i915_gem_flip_pending(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       unsigned long flags;
+       bool pending;
+
+       spin_lock_irqsave(&dev_priv->vblank_lock, flags);
+       pending = !list_empty(&obj_priv->vblank_head);
+       spin_unlock_irqrestore(&dev_priv->vblank_lock, flags);
+
+       return pending;
+}
+
+static int i915_gem_page_flip(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
+{
+       struct drm_i915_gem_page_flip *flip_data = data;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_mode_object *drm_obj;
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+       struct intel_framebuffer *intel_fb;
+       struct drm_framebuffer *old_fb;
+       struct drm_i915_gem_object *obj_priv;
+       unsigned long flags;
+       unsigned int pipe;
+       int ret = 0, seqno;
+       struct drm_crtc_helper_funcs *crtc_funcs;
+
+       if (!(drm_core_check_feature(dev, DRIVER_MODESET)))
+               return -ENODEV;
+
+       /*
+        * Reject unknown flags so future userspace knows what we (don't)
+        * support
+        */
+       if (flip_data->flags & (~I915_PAGE_FLIP_WAIT)) {
+               DRM_ERROR("bad page flip flags\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->struct_mutex);
+
+       /* Find the CRTC & FB ids */
+       drm_obj = drm_mode_object_find(dev, flip_data->crtc_id,
+                                  DRM_MODE_OBJECT_CRTC);
+       if (!drm_obj) {
+               DRM_DEBUG("unknown crtc %d\n", flip_data->crtc_id);
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       crtc = obj_to_crtc(drm_obj);
+       if (!crtc->enabled) {
+               DRM_ERROR("crtc %d not enabled\n", flip_data->crtc_id);
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       old_fb = crtc->fb;
+       intel_crtc = to_intel_crtc(crtc);
+       pipe = intel_crtc->pipe;
+
+       drm_obj = drm_mode_object_find(dev, flip_data->fb_id,
+                                      DRM_MODE_OBJECT_FB);
+       if (!drm_obj) {
+               DRM_DEBUG("unknown fb %d\n", flip_data->fb_id);
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       crtc->fb = obj_to_fb(drm_obj);
+       intel_fb = to_intel_framebuffer(crtc->fb);
+       obj_priv = intel_fb->obj->driver_private;
+
+       if (i915_gem_flip_pending(intel_fb->obj))
+               wait_for_completion(&obj_priv->vblank);
+
+       /* Sanity check tiling */
+       if (obj_priv->tiling_mode != I915_TILING_NONE &&
+           obj_priv->tiling_mode != I915_TILING_X) {
+               DRM_ERROR("can only flip non-tiled or X tiled pages\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       /* Get vblank ref for completion handling */
+       ret = drm_vblank_get(dev, pipe);
+       if (ret) {
+               DRM_ERROR("failed to take vblank ref\n");
+               goto out_unlock;
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+
+       crtc_funcs = crtc->helper_private;
+       crtc_funcs->mode_set_base(crtc, 0, 0, old_fb);
+       seqno = i915_add_request(dev, 0);
+
+       /*
+        * This is a bit racy; the flip above may have already happened
+        * by the time we get here.  If that happens, the new back buffer
+        * won't be available for rendering for one extra frame, since
+        * the vblank list won't have the object.
+        */
+       spin_lock_irqsave(&dev_priv->vblank_lock, flags);
+       list_add_tail(&obj_priv->vblank_head, &dev_priv->mm.vblank_list[pipe]);
+       obj_priv->flip_seqno = seqno;
+       spin_unlock_irqrestore(&dev_priv->vblank_lock, flags);
+
+       if (flip_data->flags & I915_PAGE_FLIP_WAIT)
+               wait_for_completion(&obj_priv->vblank);
+
+       return 0;
+
+out_unlock:
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
+}
+
 /**
  * i915_probe_agp - get AGP bootup configuration
  * @pdev: PCI device
@@ -1349,6 +1470,7 @@ struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0),
        DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0),
        DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, 
0),
+       DRM_IOCTL_DEF(DRM_I915_GEM_PAGE_FLIP, i915_gem_page_flip, 
DRM_AUTH|DRM_MASTER),
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index efcd610..9f40a13 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -162,6 +162,10 @@ typedef struct drm_i915_private {
        u32 hotplug_supported_mask;
        struct work_struct hotplug_work;
 
+       /** Protects vblank list */
+       spinlock_t vblank_lock;
+       struct work_struct vblank_work;
+
        int tex_lru_log_granularity;
        int allow_batchbuffer;
        struct mem_block *agp_heap;
@@ -341,6 +345,11 @@ typedef struct drm_i915_private {
                 */
                struct delayed_work retire_work;
 
+               /**
+                * List of objects waiting on vblank events (one per pipe)
+                */
+               struct list_head vblank_list[2];
+
                uint32_t next_gem_seqno;
 
                /**
@@ -392,6 +401,13 @@ struct drm_i915_gem_object {
        /** This object's place on the active/flushing/inactive lists */
        struct list_head list;
 
+       /** Object's place on the vblank list (protected by vblank_lock)*/
+       struct list_head vblank_head;
+       /** sequence number for flip (when it passes the flip is done),
+        *  protected by vblank lock
+        */
+       int flip_seqno;
+
        /**
         * This is set if the object is on the active or flushing lists
         * (has pending rendering), and is not set if it's on inactive (ready
@@ -462,6 +478,9 @@ struct drm_i915_gem_object {
        /** for phy allocated objects */
        struct drm_i915_gem_phys_object *phys_obj;
 
+       /** for page flips and other vblank related blocks */
+       struct completion vblank;
+
        /**
         * Used for checking the object doesn't appear more than once
         * in an execbuffer object list.
@@ -526,6 +545,7 @@ extern long i915_compat_ioctl(struct file *filp, unsigned 
int cmd,
 extern int i915_emit_box(struct drm_device *dev,
                         struct drm_clip_rect *boxes,
                         int i, int DR1, int DR4);
+extern bool i915_gem_flip_pending(struct drm_gem_object *obj);
 
 /* i915_irq.c */
 extern int i915_irq_emit(struct drm_device *dev, void *data,
@@ -637,6 +657,9 @@ void i915_gem_detach_phys_object(struct drm_device *dev,
 void i915_gem_free_all_phys_object(struct drm_device *dev);
 int i915_gem_object_get_pages(struct drm_gem_object *obj);
 void i915_gem_object_put_pages(struct drm_gem_object *obj);
+uint32_t i915_add_request(struct drm_device *dev, uint32_t flush_domains);
+int i915_seqno_passed(uint32_t seq1, uint32_t seq2);
+uint32_t i915_get_gem_seqno(struct drm_device *dev);
 
 /* i915_gem_tiling.c */
 void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 6f7d0e2..136dfa0 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1374,7 +1374,7 @@ i915_gem_object_move_to_inactive(struct drm_gem_object 
*obj)
  *
  * Returned sequence numbers are nonzero on success.
  */
-static uint32_t
+uint32_t
 i915_add_request(struct drm_device *dev, uint32_t flush_domains)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -1505,7 +1505,7 @@ out:
 /**
  * Returns true if seq1 is later than seq2.
  */
-static int
+int
 i915_seqno_passed(uint32_t seq1, uint32_t seq2)
 {
        return (int32_t)(seq1 - seq2) >= 0;
@@ -3116,6 +3116,26 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
        if (ret != 0)
                goto pre_mutex_err;
 
+       /* Look up object handles */
+       for (i = 0; i < args->buffer_count; i++) {
+               object_list[i] = drm_gem_object_lookup(dev, file_priv,
+                                                      exec_list[i].handle);
+               if (object_list[i] == NULL) {
+                       DRM_ERROR("Invalid object handle %d at index %d\n",
+                                  exec_list[i].handle, i);
+                       ret = -EBADF;
+                       mutex_lock(&dev->struct_mutex);
+                       goto err;
+               }
+
+               if (i915_gem_flip_pending(object_list[i])) {
+                       struct drm_i915_gem_object *obj_priv;
+
+                       obj_priv = object_list[i]->driver_private;
+                       wait_for_completion(&obj_priv->vblank);
+               }
+       }
+
        mutex_lock(&dev->struct_mutex);
 
        i915_verify_inactive(dev, __FILE__, __LINE__);
@@ -3134,17 +3154,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
                goto pre_mutex_err;
        }
 
-       /* Look up object handles */
+       /* Sanity check list for double entries */
        for (i = 0; i < args->buffer_count; i++) {
-               object_list[i] = drm_gem_object_lookup(dev, file_priv,
-                                                      exec_list[i].handle);
-               if (object_list[i] == NULL) {
-                       DRM_ERROR("Invalid object handle %d at index %d\n",
-                                  exec_list[i].handle, i);
-                       ret = -EBADF;
-                       goto err;
-               }
-
                obj_priv = object_list[i]->driver_private;
                if (obj_priv->in_execbuffer) {
                        DRM_ERROR("Object %p appears more than once in object 
list\n",
@@ -3581,6 +3592,9 @@ int i915_gem_init_object(struct drm_gem_object *obj)
        obj_priv->obj = obj;
        obj_priv->fence_reg = I915_FENCE_REG_NONE;
        INIT_LIST_HEAD(&obj_priv->list);
+       INIT_LIST_HEAD(&obj_priv->vblank_head);
+
+       init_completion(&obj_priv->vblank);
 
        return 0;
 }
@@ -3641,8 +3655,10 @@ int
 i915_gem_idle(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv, *tmp;
+       unsigned long irqflags;
        uint32_t seqno, cur_seqno, last_seqno;
-       int stuck, ret;
+       int stuck, ret, pipe;
 
        mutex_lock(&dev->struct_mutex);
 
@@ -3656,9 +3672,23 @@ i915_gem_idle(struct drm_device *dev)
         */
        dev_priv->mm.suspended = 1;
 
+       mutex_unlock(&dev->struct_mutex);
+
+       /* Wait for any outstanding flips */
+       spin_lock_irqsave(&dev_priv->vblank_lock, irqflags);
+       for (pipe = 0; pipe < 2; pipe++) {
+               list_for_each_entry_safe(obj_priv, tmp,
+                                        &dev_priv->mm.vblank_list[pipe],
+                                        vblank_head) {
+                       spin_unlock_irqrestore(&dev_priv->vblank_lock, 
irqflags);
+                       wait_for_completion(&obj_priv->vblank);
+                       spin_lock_irqsave(&dev_priv->vblank_lock, irqflags);
+               }
+       }
+       spin_unlock_irqrestore(&dev_priv->vblank_lock, irqflags);
+
        /* Cancel the retire work handler, wait for it to finish if running
         */
-       mutex_unlock(&dev->struct_mutex);
        cancel_delayed_work_sync(&dev_priv->mm.retire_work);
        mutex_lock(&dev->struct_mutex);
 
@@ -4025,9 +4055,12 @@ i915_gem_load(struct drm_device *dev)
        INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
        INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
        INIT_LIST_HEAD(&dev_priv->mm.request_list);
+       INIT_LIST_HEAD(&dev_priv->mm.vblank_list[0]);
+       INIT_LIST_HEAD(&dev_priv->mm.vblank_list[1]);
        INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
                          i915_gem_retire_work_handler);
        dev_priv->mm.next_gem_seqno = 1;
+       spin_lock_init(&dev_priv->vblank_lock);
 
        /* Old X drivers will take 0-2 for front, back, depth buffers */
        dev_priv->fence_reg_start = 3;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index ee7ce7b..94aee6b 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -196,6 +196,35 @@ static void i915_hotplug_work_func(struct work_struct 
*work)
        drm_sysfs_hotplug_event(dev);
 }
 
+static void i915_vblank_work_func(struct work_struct *work)
+{
+       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+                                                   vblank_work);
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_i915_gem_object *obj_priv, *tmp;
+       unsigned long irqflags;
+       int pipe, cur_seqno;
+
+       mutex_lock(&dev->struct_mutex);
+
+       spin_lock_irqsave(&dev_priv->vblank_lock, irqflags);
+       for (pipe = 0; pipe < 2; pipe++) {
+               list_for_each_entry_safe(obj_priv, tmp,
+                                        &dev_priv->mm.vblank_list[pipe],
+                                        vblank_head) {
+                       cur_seqno = i915_get_gem_seqno(dev);
+                       if (i915_seqno_passed(cur_seqno,
+                                             obj_priv->flip_seqno)) {
+                               list_del_init(&obj_priv->vblank_head);
+                               drm_vblank_put(dev, pipe);
+                               complete(&obj_priv->vblank);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&dev_priv->vblank_lock, irqflags);
+       mutex_unlock(&dev->struct_mutex);
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -292,6 +321,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                        drm_handle_vblank(dev, 1);
                }
 
+               if (vblank)
+                       schedule_work(&dev_priv->vblank_work);
+
                if ((pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
                    (iir & I915_ASLE_INTERRUPT))
                        opregion_asle_intr(dev);
@@ -563,6 +595,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
        I915_WRITE(IER, 0x0);
        (void) I915_READ(IER);
        INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+       INIT_WORK(&dev_priv->vblank_work, i915_vblank_work_func);
 }
 
 int i915_driver_irq_postinstall(struct drm_device *dev)
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index 67e3353..b022ba5 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -184,6 +184,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_GEM_GET_TILING        0x22
 #define DRM_I915_GEM_GET_APERTURE 0x23
 #define DRM_I915_GEM_MMAP_GTT  0x24
+#define DRM_I915_GEM_PAGE_FLIP 0x25
 
 #define DRM_IOCTL_I915_INIT            DRM_IOW( DRM_COMMAND_BASE + 
DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH           DRM_IO ( DRM_COMMAND_BASE + 
DRM_I915_FLUSH)
@@ -219,6 +220,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_SET_TILING  DRM_IOWR (DRM_COMMAND_BASE + 
DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling)
 #define DRM_IOCTL_I915_GEM_GET_TILING  DRM_IOWR (DRM_COMMAND_BASE + 
DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling)
 #define DRM_IOCTL_I915_GEM_GET_APERTURE        DRM_IOR  (DRM_COMMAND_BASE + 
DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture)
+#define DRM_IOCTL_I915_GEM_PAGE_FLIP   DRM_IOW (DRM_COMMAND_BASE + 
DRM_I915_GEM_PAGE_FLIP, struct drm_i915_gem_page_flip)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -654,4 +656,20 @@ struct drm_i915_gem_get_aperture {
        __u64 aper_available_size;
 };
 
+#define I915_PAGE_FLIP_WAIT (1<<0) /* block on page flip completion */
+
+struct drm_i915_gem_page_flip {
+       /** Handle of new front buffer */
+       uint32_t fb_id;
+       /**
+        * crtc to flip
+        */
+       uint32_t crtc_id;
+
+       /**
+        * page flip flags (wait on flip only for now)
+        */
+       uint32_t flags;
+};
+
 #endif                         /* _I915_DRM_H_ */

------------------------------------------------------------------------------
This SF.net email is sponsored by:
High Quality Requirements in a Collaborative Environment.
Download a free trial of Rational Requirements Composer Now!
http://p.sf.net/sfu/www-ibm-com
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to