static int i915_flush_ioctl(struct drm_device *dev, void *data,
                            struct drm_file *file_priv)
 {
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
+       int ret;
+
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       return i915_quiescent(dev);
+       mutex_lock(&dev->struct_mutex);
+       ret = i915_quiescent(dev);
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
 }
 
 static int i915_batchbuffer(struct drm_device *dev, void *data,
        DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
                  batch->start, batch->used, batch->num_cliprects);
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
                                                       batch->num_cliprects *
                                                       sizeof(struct drm_clip_rect)))
                return -EFAULT;
 
+       mutex_lock(&dev->struct_mutex);
        ret = i915_dispatch_batchbuffer(dev, batch);
+       mutex_unlock(&dev->struct_mutex);
 
        sarea_priv->last_dispatch = (int)hw_status[5];
        return ret;
        DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
                  cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (cmdbuf->num_cliprects &&
            DRM_VERIFYAREA_READ(cmdbuf->cliprects,
                return -EFAULT;
        }
 
+       mutex_lock(&dev->struct_mutex);
        ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
+       mutex_unlock(&dev->struct_mutex);
        if (ret) {
                DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
                return ret;
 static int i915_flip_bufs(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
 {
+       int ret;
+
        DRM_DEBUG("%s\n", __func__);
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       return i915_dispatch_flip(dev);
+       mutex_lock(&dev->struct_mutex);
+       ret = i915_dispatch_flip(dev);
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
 }
 
 static int i915_getparam(struct drm_device *dev, void *data,
 
                 */
                struct delayed_work retire_work;
 
+               /** Work task for vblank-related ring access */
+               struct work_struct vblank_work;
+
                uint32_t next_gem_seqno;
 
                /**
 void i915_user_irq_get(struct drm_device *dev);
 void i915_user_irq_put(struct drm_device *dev);
 
+extern void i915_gem_vblank_work_handler(struct work_struct *work);
 extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
 extern void i915_driver_irq_preinstall(struct drm_device * dev);
 extern int i915_driver_irq_postinstall(struct drm_device *dev);
 extern void opregion_asle_intr(struct drm_device *dev);
 extern void opregion_enable_asle(struct drm_device *dev);
 
+/**
+ * Lock test for when it's just for synchronization of ring access.
+ *
+ * In that case, we don't need to do it when GEM is initialized as nobody else
+ * has access to the ring.
+ */
+#define RING_LOCK_TEST_WITH_RETURN(dev, file_priv) do {                        \
+       if (((drm_i915_private_t *)dev->dev_private)->ring.ring_obj == NULL) \
+               LOCK_TEST_WITH_RETURN(dev, file_priv);                  \
+} while (0)
+
 #define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, (reg))
 #define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, (reg), (val))
 #define I915_READ16(reg)       DRM_READ16(dev_priv->mmio_map, (reg))
 
        INIT_LIST_HEAD(&dev_priv->mm.request_list);
        INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
                          i915_gem_retire_work_handler);
+       INIT_WORK(&dev_priv->mm.vblank_work,
+                 i915_gem_vblank_work_handler);
        dev_priv->mm.next_gem_seqno = 1;
 
        i915_gem_detect_bit_6_swizzle(dev);
 
        return count;
 }
 
+void
+i915_gem_vblank_work_handler(struct work_struct *work)
+{
+       drm_i915_private_t *dev_priv;
+       struct drm_device *dev;
+
+       dev_priv = container_of(work, drm_i915_private_t,
+                               mm.vblank_work);
+       dev = dev_priv->dev;
+
+       mutex_lock(&dev->struct_mutex);
+       i915_vblank_tasklet(dev);
+       mutex_unlock(&dev->struct_mutex);
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        if (iir & I915_ASLE_INTERRUPT)
                opregion_asle_intr(dev);
 
-       if (vblank && dev_priv->swaps_pending > 0)
-               drm_locked_tasklet(dev, i915_vblank_tasklet);
+       if (vblank && dev_priv->swaps_pending > 0) {
+               if (dev_priv->ring.ring_obj == NULL)
+                       drm_locked_tasklet(dev, i915_vblank_tasklet);
+               else
+                       schedule_work(&dev_priv->mm.vblank_work);
+       }
 
        return IRQ_HANDLED;
 }
        drm_i915_irq_emit_t *emit = data;
        int result;
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (!dev_priv) {
                DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
-
+       mutex_lock(&dev->struct_mutex);
        result = i915_emit_irq(dev);
+       mutex_unlock(&dev->struct_mutex);
 
        if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");