#include <linux/pci.h>
 #include <linux/dma-buf.h>
 
+#define RQ_BUG_ON(expr)
+
 static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj);
 static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj);
 static void
-i915_gem_object_retire(struct drm_i915_gem_object *obj);
-
+i915_gem_object_retire__write(struct drm_i915_gem_object *obj);
+static void
+i915_gem_object_retire__read(struct drm_i915_gem_object *obj, int ring);
 static void i915_gem_write_fence(struct drm_device *dev, int reg,
                                 struct drm_i915_gem_object *obj);
 static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
                ret = i915_gem_object_wait_rendering(obj, true);
                if (ret)
                        return ret;
-
-               i915_gem_object_retire(obj);
        }
 
        ret = i915_gem_object_get_pages(obj);
                ret = i915_gem_object_wait_rendering(obj, false);
                if (ret)
                        return ret;
-
-               i915_gem_object_retire(obj);
        }
        /* Same trick applies to invalidate partially written cachelines read
         * before writing. */
 
        WARN(!intel_irqs_enabled(dev_priv), "IRQs disabled");
 
+       if (list_empty(&req->list))
+               return 0;
+
        if (i915_gem_request_completed(req, true))
                return 0;
 
        return ret;
 }
 
+static inline void
+i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
+{
+       struct drm_i915_file_private *file_priv = request->file_priv;
+
+       if (!file_priv)
+               return;
+
+       spin_lock(&file_priv->mm.lock);
+       list_del(&request->client_list);
+       request->file_priv = NULL;
+       spin_unlock(&file_priv->mm.lock);
+}
+
+static void i915_gem_request_retire(struct drm_i915_gem_request *request)
+{
+       trace_i915_gem_request_retire(request);
+
+       /* We know the GPU must have read the request to have
+        * sent us the seqno + interrupt, so use the position
+        * of tail of the request to update the last known position
+        * of the GPU head.
+        *
+        * Note this requires that we are always called in request
+        * completion order.
+        */
+       request->ringbuf->last_retired_head = request->postfix;
+
+       list_del_init(&request->list);
+       i915_gem_request_remove_from_client(request);
+
+       put_pid(request->pid);
+
+       i915_gem_request_unreference(request);
+}
+
+static void
+__i915_gem_request_retire__upto(struct drm_i915_gem_request *req)
+{
+       struct intel_engine_cs *engine = req->ring;
+       struct drm_i915_gem_request *tmp;
+
+       lockdep_assert_held(&engine->dev->struct_mutex);
+
+       if (list_empty(&req->list))
+               return;
+
+       do {
+               tmp = list_first_entry(&engine->request_list,
+                                      typeof(*tmp), list);
+
+               i915_gem_request_retire(tmp);
+       } while (tmp != req);
+
+       WARN_ON(i915_verify_lists(engine->dev));
+}
+
 /**
  * Waits for a request to be signaled, and cleans up the
  * request and object lists appropriately for that event.
        struct drm_device *dev;
        struct drm_i915_private *dev_priv;
        bool interruptible;
-       unsigned reset_counter;
        int ret;
 
        BUG_ON(req == NULL);
        if (ret)
                return ret;
 
-       reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
-       i915_gem_request_reference(req);
-       ret = __i915_wait_request(req, reset_counter,
+       ret = __i915_wait_request(req,
+                                 atomic_read(&dev_priv->gpu_error.reset_counter),
                                  interruptible, NULL, NULL);
-       i915_gem_request_unreference(req);
-       return ret;
-}
-
-static int
-i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj)
-{
-       if (!obj->active)
-               return 0;
-
-       /* Manually manage the write flush as we may have not yet
-        * retired the buffer.
-        *
-        * Note that the last_write_req is always the earlier of
-        * the two (read/write) requests, so if we haved successfully waited,
-        * we know we have passed the last write.
-        */
-       i915_gem_request_assign(&obj->last_write_req, NULL);
+       if (ret)
+               return ret;
 
+       __i915_gem_request_retire__upto(req);
        return 0;
 }
 
 i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
                               bool readonly)
 {
-       struct drm_i915_gem_request *req;
-       int ret;
+       int ret, i;
 
-       req = readonly ? obj->last_write_req : obj->last_read_req;
-       if (!req)
+       if (!obj->active)
                return 0;
 
-       ret = i915_wait_request(req);
-       if (ret)
-               return ret;
+       if (readonly) {
+               if (obj->last_write_req != NULL) {
+                       ret = i915_wait_request(obj->last_write_req);
+                       if (ret)
+                               return ret;
+
+                       i = obj->last_write_req->ring->id;
+                       if (obj->last_read_req[i] == obj->last_write_req)
+                               i915_gem_object_retire__read(obj, i);
+                       else
+                               i915_gem_object_retire__write(obj);
+               }
+       } else {
+               for (i = 0; i < I915_NUM_RINGS; i++) {
+                       if (obj->last_read_req[i] == NULL)
+                               continue;
+
+                       ret = i915_wait_request(obj->last_read_req[i]);
+                       if (ret)
+                               return ret;
+
+                       i915_gem_object_retire__read(obj, i);
+               }
+               RQ_BUG_ON(obj->active);
+       }
+
+       return 0;
+}
+
+static void
+i915_gem_object_retire_request(struct drm_i915_gem_object *obj,
+                              struct drm_i915_gem_request *req)
+{
+       int ring = req->ring->id;
+
+       if (obj->last_read_req[ring] == req)
+               i915_gem_object_retire__read(obj, ring);
+       else if (obj->last_write_req == req)
+               i915_gem_object_retire__write(obj);
 
-       return i915_gem_object_wait_rendering__tail(obj);
+       __i915_gem_request_retire__upto(req);
 }
 
 /* A nonblocking variant of the above wait. This is a highly dangerous routine
                                            struct drm_i915_file_private *file_priv,
                                            bool readonly)
 {
-       struct drm_i915_gem_request *req;
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_request *requests[I915_NUM_RINGS];
        unsigned reset_counter;
-       int ret;
+       int ret, i, n = 0;
 
        BUG_ON(!mutex_is_locked(&dev->struct_mutex));
        BUG_ON(!dev_priv->mm.interruptible);
 
-       req = readonly ? obj->last_write_req : obj->last_read_req;
-       if (!req)
+       if (!obj->active)
                return 0;
 
        ret = i915_gem_check_wedge(&dev_priv->gpu_error, true);
        if (ret)
                return ret;
 
-       ret = i915_gem_check_olr(req);
-       if (ret)
-               return ret;
-
        reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
-       i915_gem_request_reference(req);
+
+       if (readonly) {
+               struct drm_i915_gem_request *req;
+
+               req = obj->last_write_req;
+               if (req == NULL)
+                       return 0;
+
+               ret = i915_gem_check_olr(req);
+               if (ret)
+                       goto err;
+
+               requests[n++] = i915_gem_request_reference(req);
+       } else {
+               for (i = 0; i < I915_NUM_RINGS; i++) {
+                       struct drm_i915_gem_request *req;
+
+                       req = obj->last_read_req[i];
+                       if (req == NULL)
+                               continue;
+
+                       ret = i915_gem_check_olr(req);
+                       if (ret)
+                               goto err;
+
+                       requests[n++] = i915_gem_request_reference(req);
+               }
+       }
+
        mutex_unlock(&dev->struct_mutex);
-       ret = __i915_wait_request(req, reset_counter, true, NULL, file_priv);
+       for (i = 0; ret == 0 && i < n; i++)
+               ret = __i915_wait_request(requests[i], reset_counter, true,
+                                         NULL, file_priv);
        mutex_lock(&dev->struct_mutex);
-       i915_gem_request_unreference(req);
-       if (ret)
-               return ret;
 
-       return i915_gem_object_wait_rendering__tail(obj);
+err:
+       for (i = 0; i < n; i++) {
+               if (ret == 0)
+                       i915_gem_object_retire_request(obj, requests[i]);
+               i915_gem_request_unreference(requests[i]);
+       }
+
+       return ret;
 }
 
 /**
        return 0;
 }
 
-static void
-i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
-                              struct intel_engine_cs *ring)
+void i915_vma_move_to_active(struct i915_vma *vma,
+                            struct intel_engine_cs *ring)
 {
-       struct drm_i915_gem_request *req;
-       struct intel_engine_cs *old_ring;
-
-       BUG_ON(ring == NULL);
-
-       req = intel_ring_get_request(ring);
-       old_ring = i915_gem_request_get_ring(obj->last_read_req);
-
-       if (old_ring != ring && obj->last_write_req) {
-               /* Keep the request relative to the current ring */
-               i915_gem_request_assign(&obj->last_write_req, req);
-       }
+       struct drm_i915_gem_object *obj = vma->obj;
 
        /* Add a reference if we're newly entering the active list. */
-       if (!obj->active) {
+       if (obj->active == 0)
                drm_gem_object_reference(&obj->base);
-               obj->active = 1;
-       }
+       obj->active |= intel_ring_flag(ring);
 
-       list_move_tail(&obj->ring_list, &ring->active_list);
+       list_move_tail(&obj->ring_list[ring->id], &ring->active_list);
+       i915_gem_request_assign(&obj->last_read_req[ring->id],
+                               intel_ring_get_request(ring));
 
-       i915_gem_request_assign(&obj->last_read_req, req);
+       list_move_tail(&vma->mm_list, &vma->vm->active_list);
 }
 
-void i915_vma_move_to_active(struct i915_vma *vma,
-                            struct intel_engine_cs *ring)
+static void
+i915_gem_object_retire__write(struct drm_i915_gem_object *obj)
 {
-       list_move_tail(&vma->mm_list, &vma->vm->active_list);
-       return i915_gem_object_move_to_active(vma->obj, ring);
+       RQ_BUG_ON(obj->last_write_req == NULL);
+       RQ_BUG_ON(!(obj->active & intel_ring_flag(obj->last_write_req->ring)));
+
+       i915_gem_request_assign(&obj->last_write_req, NULL);
+       intel_fb_obj_flush(obj, true);
 }
 
 static void
-i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
+i915_gem_object_retire__read(struct drm_i915_gem_object *obj, int ring)
 {
        struct i915_vma *vma;
 
-       BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
-       BUG_ON(!obj->active);
+       RQ_BUG_ON(obj->last_read_req[ring] == NULL);
+       RQ_BUG_ON(!(obj->active & (1 << ring)));
+
+       list_del_init(&obj->ring_list[ring]);
+       i915_gem_request_assign(&obj->last_read_req[ring], NULL);
+
+       if (obj->last_write_req && obj->last_write_req->ring->id == ring)
+               i915_gem_object_retire__write(obj);
+
+       obj->active &= ~(1 << ring);
+       if (obj->active)
+               return;
 
        list_for_each_entry(vma, &obj->vma_list, vma_link) {
                if (!list_empty(&vma->mm_list))
                        list_move_tail(&vma->mm_list, &vma->vm->inactive_list);
        }
 
-       intel_fb_obj_flush(obj, true);
-
-       list_del_init(&obj->ring_list);
-
-       i915_gem_request_assign(&obj->last_read_req, NULL);
-       i915_gem_request_assign(&obj->last_write_req, NULL);
-       obj->base.write_domain = 0;
-
        i915_gem_request_assign(&obj->last_fenced_req, NULL);
-
-       obj->active = 0;
        drm_gem_object_unreference(&obj->base);
-
-       WARN_ON(i915_verify_lists(dev));
-}
-
-static void
-i915_gem_object_retire(struct drm_i915_gem_object *obj)
-{
-       if (obj->last_read_req == NULL)
-               return;
-
-       if (i915_gem_request_completed(obj->last_read_req, true))
-               i915_gem_object_move_to_inactive(obj);
 }
 
 static int
        return 0;
 }
 
-static inline void
-i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
-{
-       struct drm_i915_file_private *file_priv = request->file_priv;
-
-       if (!file_priv)
-               return;
-
-       spin_lock(&file_priv->mm.lock);
-       list_del(&request->client_list);
-       request->file_priv = NULL;
-       spin_unlock(&file_priv->mm.lock);
-}
-
 static bool i915_context_is_banned(struct drm_i915_private *dev_priv,
                                   const struct intel_context *ctx)
 {
        }
 }
 
-static void i915_gem_free_request(struct drm_i915_gem_request *request)
-{
-       list_del(&request->list);
-       i915_gem_request_remove_from_client(request);
-
-       put_pid(request->pid);
-
-       i915_gem_request_unreference(request);
-}
-
 void i915_gem_request_free(struct kref *req_ref)
 {
        struct drm_i915_gem_request *req = container_of(req_ref,
 
                obj = list_first_entry(&ring->active_list,
                                       struct drm_i915_gem_object,
-                                      ring_list);
+                                      ring_list[ring->id]);
 
-               i915_gem_object_move_to_inactive(obj);
+               i915_gem_object_retire__read(obj, ring->id);
        }
 
        /*
                                           struct drm_i915_gem_request,
                                           list);
 
-               i915_gem_free_request(request);
+               i915_gem_request_retire(request);
        }
 
        /* This may not have been flushed before the reset, so clean it now */
        i915_gem_context_reset(dev);
 
        i915_gem_restore_fences(dev);
+
+       WARN_ON(i915_verify_lists(dev));
 }
 
 /**
 void
 i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 {
-       if (list_empty(&ring->request_list))
-               return;
-
        WARN_ON(i915_verify_lists(ring->dev));
 
+       if (list_empty(&ring->active_list))
+               return;
+
        /* Retire requests first as we use it above for the early return.
         * If we retire requests last, we may use a later seqno and so clear
         * the requests lists without clearing the active list, leading to
                if (!i915_gem_request_completed(request, true))
                        break;
 
-               trace_i915_gem_request_retire(request);
-
-               /* We know the GPU must have read the request to have
-                * sent us the seqno + interrupt, so use the position
-                * of tail of the request to update the last known position
-                * of the GPU head.
-                */
-               request->ringbuf->last_retired_head = request->postfix;
-
-               i915_gem_free_request(request);
+               i915_gem_request_retire(request);
        }
 
        /* Move any buffers on the active list that are no longer referenced
 
                obj = list_first_entry(&ring->active_list,
                                      struct drm_i915_gem_object,
-                                     ring_list);
+                                     ring_list[ring->id]);
 
-               if (!i915_gem_request_completed(obj->last_read_req, true))
+               if (!list_empty(&obj->last_read_req[ring->id]->list))
                        break;
 
-               i915_gem_object_move_to_inactive(obj);
+               i915_gem_object_retire__read(obj, ring->id);
        }
 
        if (unlikely(ring->trace_irq_req &&
 static int
 i915_gem_object_flush_active(struct drm_i915_gem_object *obj)
 {
-       struct intel_engine_cs *ring;
-       int ret;
+       int ret, i;
+
+       if (!obj->active)
+               return 0;
 
-       if (obj->active) {
-               ring = i915_gem_request_get_ring(obj->last_read_req);
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               struct drm_i915_gem_request *req;
 
-               ret = i915_gem_check_olr(obj->last_read_req);
+               req = obj->last_read_req[i];
+               if (req == NULL)
+                       continue;
+
+               if (list_empty(&req->list))
+                       goto retire;
+
+               ret = i915_gem_check_olr(req);
                if (ret)
                        return ret;
 
-               i915_gem_retire_requests_ring(ring);
+               if (i915_gem_request_completed(req, true)) {
+                       __i915_gem_request_retire__upto(req);
+retire:
+                       i915_gem_object_retire__read(obj, i);
+               }
        }
 
        return 0;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_wait *args = data;
        struct drm_i915_gem_object *obj;
-       struct drm_i915_gem_request *req;
+       struct drm_i915_gem_request *req[I915_NUM_RINGS];
        unsigned reset_counter;
-       int ret = 0;
+       int i, n = 0;
+       int ret;
 
        if (args->flags != 0)
                return -EINVAL;
        if (ret)
                goto out;
 
-       if (!obj->active || !obj->last_read_req)
+       if (!obj->active)
                goto out;
 
-       req = obj->last_read_req;
-
        /* Do this after OLR check to make sure we make forward progress polling
         * on this IOCTL with a timeout == 0 (like busy ioctl)
         */
 
        drm_gem_object_unreference(&obj->base);
        reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
-       i915_gem_request_reference(req);
+
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               if (obj->last_read_req[i] == NULL)
+                       continue;
+
+               req[n++] = i915_gem_request_reference(obj->last_read_req[i]);
+       }
+
        mutex_unlock(&dev->struct_mutex);
 
-       ret = __i915_wait_request(req, reset_counter, true,
-                                 args->timeout_ns > 0 ? &args->timeout_ns : NULL,
-                                 file->driver_priv);
-       i915_gem_request_unreference__unlocked(req);
+       for (i = 0; i < n; i++) {
+               if (ret == 0)
+                       ret = __i915_wait_request(req[i], reset_counter, true,
+                                                 args->timeout_ns > 0 ? &args->timeout_ns : NULL,
+                                                 file->driver_priv);
+               i915_gem_request_unreference__unlocked(req[i]);
+       }
        return ret;
 
 out:
        return ret;
 }
 
+static int
+__i915_gem_object_sync(struct drm_i915_gem_object *obj,
+                      struct intel_engine_cs *to,
+                      struct drm_i915_gem_request *req)
+{
+       struct intel_engine_cs *from;
+       int ret;
+
+       from = i915_gem_request_get_ring(req);
+       if (to == from)
+               return 0;
+
+       if (i915_gem_request_completed(req, true))
+               return 0;
+
+       ret = i915_gem_check_olr(req);
+       if (ret)
+               return ret;
+
+       if (!i915_semaphore_is_enabled(obj->base.dev)) {
+               ret = __i915_wait_request(req,
+                                         atomic_read(&to_i915(obj->base.dev)->gpu_error.reset_counter),
+                                         to_i915(obj->base.dev)->mm.interruptible, NULL, NULL);
+               if (ret)
+                       return ret;
+
+               i915_gem_object_retire_request(obj, req);
+       } else {
+               int idx = intel_ring_sync_index(from, to);
+               u32 seqno = i915_gem_request_get_seqno(req);
+
+               if (seqno <= from->semaphore.sync_seqno[idx])
+                       return 0;
+
+               trace_i915_gem_ring_sync_to(from, to, req);
+               ret = to->semaphore.sync_to(to, from, seqno);
+               if (ret)
+                       return ret;
+
+               /* We use last_read_req because sync_to()
+                * might have just caused seqno wrap under
+                * the radar.
+                */
+               from->semaphore.sync_seqno[idx] =
+                       i915_gem_request_get_seqno(obj->last_read_req[from->id]);
+       }
+
+       return 0;
+}
+
 /**
  * i915_gem_object_sync - sync an object to a ring.
  *
  *
  * This code is meant to abstract object synchronization with the GPU.
  * Calling with NULL implies synchronizing the object with the CPU
- * rather than a particular GPU ring.
+ * rather than a particular GPU ring. Conceptually we serialise writes
+ * between engines inside the GPU. We only allow on engine to write
+ * into a buffer at any time, but multiple readers. To ensure each has
+ * a coherent view of memory, we must:
+ *
+ * - If there is an outstanding write request to the object, the new
+ *   request must wait for it to complete (either CPU or in hw, requests
+ *   on the same ring will be naturally ordered).
+ *
+ * - If we are a write request (pending_write_domain is set), the new
+ *   request must wait for outstanding read requests to complete.
  *
  * Returns 0 if successful, else propagates up the lower layer error.
  */
 i915_gem_object_sync(struct drm_i915_gem_object *obj,
                     struct intel_engine_cs *to)
 {
-       struct intel_engine_cs *from;
-       u32 seqno;
-       int ret, idx;
+       const bool readonly = obj->base.pending_write_domain == 0;
+       struct drm_i915_gem_request *req[I915_NUM_RINGS];
+       int ret, i, n;
 
-       from = i915_gem_request_get_ring(obj->last_read_req);
-
-       if (from == NULL || to == from)
-               return 0;
-
-       if (to == NULL || !i915_semaphore_is_enabled(obj->base.dev))
-               return i915_gem_object_wait_rendering(obj, false);
-
-       idx = intel_ring_sync_index(from, to);
-
-       seqno = i915_gem_request_get_seqno(obj->last_read_req);
-       /* Optimization: Avoid semaphore sync when we are sure we already
-        * waited for an object with higher seqno */
-       if (seqno <= from->semaphore.sync_seqno[idx])
+       if (!obj->active)
                return 0;
 
-       ret = i915_gem_check_olr(obj->last_read_req);
-       if (ret)
-               return ret;
+       if (to == NULL)
+               return i915_gem_object_wait_rendering(obj, readonly);
 
-       trace_i915_gem_ring_sync_to(from, to, obj->last_read_req);
-       ret = to->semaphore.sync_to(to, from, seqno);
-       if (!ret)
-               /* We use last_read_req because sync_to()
-                * might have just caused seqno wrap under
-                * the radar.
-                */
-               from->semaphore.sync_seqno[idx] =
-                               i915_gem_request_get_seqno(obj->last_read_req);
+       n = 0;
+       if (readonly) {
+               if (obj->last_write_req)
+                       req[n++] = obj->last_write_req;
+       } else {
+               for (i = 0; i < I915_NUM_RINGS; i++)
+                       if (obj->last_read_req[i])
+                               req[n++] = obj->last_read_req[i];
+       }
+       for (i = 0; i < n; i++) {
+               ret = __i915_gem_object_sync(obj, to, req[i]);
+               if (ret)
+                       return ret;
+       }
 
-       return ret;
+       return 0;
 }
 
 static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj)
        /* Since the unbound list is global, only move to that list if
         * no more VMAs exist. */
        if (list_empty(&obj->vma_list)) {
-               /* Throw away the active reference before
-                * moving to the unbound list. */
-               i915_gem_object_retire(obj);
-
                i915_gem_gtt_finish_object(obj);
                list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
        }
                        return ret;
        }
 
+       WARN_ON(i915_verify_lists(dev));
        return 0;
 }
 
        if (ret)
                return ret;
 
-       i915_gem_object_retire(obj);
-
        /* Flush and acquire obj->pages so that we are coherent through
         * direct access in memory with previous cached writes through
         * shmemfs and that our cache domain tracking remains valid.
        u32 old_read_domains, old_write_domain;
        int ret;
 
-       if (pipelined != i915_gem_request_get_ring(obj->last_read_req)) {
-               ret = i915_gem_object_sync(obj, pipelined);
-               if (ret)
-                       return ret;
-       }
+       ret = i915_gem_object_sync(obj, pipelined);
+       if (ret)
+               return ret;
 
        /* Mark the pin_display early so that we account for the
         * display coherency whilst setting up the cache domains.
        if (ret)
                return ret;
 
-       i915_gem_object_retire(obj);
        i915_gem_object_flush_gtt_write_domain(obj);
 
        old_write_domain = obj->base.write_domain;
         * necessary flushes here.
         */
        ret = i915_gem_object_flush_active(obj);
+       if (ret)
+               goto unref;
 
-       args->busy = obj->active;
-       if (obj->last_read_req) {
-               struct intel_engine_cs *ring;
-               BUILD_BUG_ON(I915_NUM_RINGS > 16);
-               ring = i915_gem_request_get_ring(obj->last_read_req);
-               args->busy |= intel_ring_flag(ring) << 16;
-       }
+       BUILD_BUG_ON(I915_NUM_RINGS > 16);
+       args->busy = obj->active << 16;
+       if (obj->last_write_req)
+               args->busy |= obj->last_write_req->ring->id;
 
+unref:
        drm_gem_object_unreference(&obj->base);
 unlock:
        mutex_unlock(&dev->struct_mutex);
 void i915_gem_object_init(struct drm_i915_gem_object *obj,
                          const struct drm_i915_gem_object_ops *ops)
 {
+       int i;
+
        INIT_LIST_HEAD(&obj->global_list);
-       INIT_LIST_HEAD(&obj->ring_list);
+       for (i = 0; i < I915_NUM_RINGS; i++)
+               INIT_LIST_HEAD(&obj->ring_list[i]);
        INIT_LIST_HEAD(&obj->obj_exec_link);
        INIT_LIST_HEAD(&obj->vma_list);
        INIT_LIST_HEAD(&obj->batch_pool_link);