drm/i915: Do not make assumptions on GGTT VMA sizes
[cascardo/linux.git] / drivers / gpu / drm / i915 / i915_gem.c
index 27ea6bd..18307df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2008 Intel Corporation
+ * Copyright © 2008-2015 Intel Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -29,9 +29,9 @@
 #include <drm/drm_vma_manager.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
+#include "i915_vgpu.h"
 #include "i915_trace.h"
 #include "intel_drv.h"
-#include <linux/oom.h>
 #include <linux/shmem_fs.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
@@ -52,15 +52,6 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
                                         struct drm_i915_fence_reg *fence,
                                         bool enable);
 
-static unsigned long i915_gem_shrinker_count(struct shrinker *shrinker,
-                                            struct shrink_control *sc);
-static unsigned long i915_gem_shrinker_scan(struct shrinker *shrinker,
-                                           struct shrink_control *sc);
-static int i915_gem_shrinker_oom(struct notifier_block *nb,
-                                unsigned long event,
-                                void *ptr);
-static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
-
 static bool cpu_cache_is_coherent(struct drm_device *dev,
                                  enum i915_cache_level level)
 {
@@ -350,7 +341,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
        struct drm_device *dev = obj->base.dev;
        void *vaddr = obj->phys_handle->vaddr + args->offset;
        char __user *user_data = to_user_ptr(args->data_ptr);
-       int ret;
+       int ret = 0;
 
        /* We manually control the domain here and pretend that it
         * remains coherent i.e. in the GTT domain, like shmem_pwrite.
@@ -359,6 +350,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
        if (ret)
                return ret;
 
+       intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU);
        if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
                unsigned long unwritten;
 
@@ -369,25 +361,30 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
                mutex_unlock(&dev->struct_mutex);
                unwritten = copy_from_user(vaddr, user_data, args->size);
                mutex_lock(&dev->struct_mutex);
-               if (unwritten)
-                       return -EFAULT;
+               if (unwritten) {
+                       ret = -EFAULT;
+                       goto out;
+               }
        }
 
        drm_clflush_virt_range(vaddr, args->size);
        i915_gem_chipset_flush(dev);
-       return 0;
+
+out:
+       intel_fb_obj_flush(obj, false);
+       return ret;
 }
 
 void *i915_gem_object_alloc(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       return kmem_cache_zalloc(dev_priv->slab, GFP_KERNEL);
+       return kmem_cache_zalloc(dev_priv->objects, GFP_KERNEL);
 }
 
 void i915_gem_object_free(struct drm_i915_gem_object *obj)
 {
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-       kmem_cache_free(dev_priv->slab, obj);
+       kmem_cache_free(dev_priv->objects, obj);
 }
 
 static int
@@ -809,6 +806,8 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
 
        offset = i915_gem_obj_ggtt_offset(obj) + args->offset;
 
+       intel_fb_obj_invalidate(obj, NULL, ORIGIN_GTT);
+
        while (remain > 0) {
                /* Operation in this page
                 *
@@ -829,7 +828,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
                if (fast_user_write(dev_priv->gtt.mappable, page_base,
                                    page_offset, user_data, page_length)) {
                        ret = -EFAULT;
-                       goto out_unpin;
+                       goto out_flush;
                }
 
                remain -= page_length;
@@ -837,6 +836,8 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
                offset += page_length;
        }
 
+out_flush:
+       intel_fb_obj_flush(obj, false);
 out_unpin:
        i915_gem_object_ggtt_unpin(obj);
 out:
@@ -951,6 +952,8 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
        if (ret)
                return ret;
 
+       intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU);
+
        i915_gem_object_pin_pages(obj);
 
        offset = args->offset;
@@ -1029,6 +1032,7 @@ out:
        if (needs_clflush_after)
                i915_gem_chipset_flush(dev);
 
+       intel_fb_obj_flush(obj, false);
        return ret;
 }
 
@@ -1177,12 +1181,27 @@ static bool missed_irq(struct drm_i915_private *dev_priv,
        return test_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings);
 }
 
-static bool can_wait_boost(struct drm_i915_file_private *file_priv)
+static int __i915_spin_request(struct drm_i915_gem_request *rq)
 {
-       if (file_priv == NULL)
-               return true;
+       unsigned long timeout;
+
+       if (i915_gem_request_get_ring(rq)->irq_refcount)
+               return -EBUSY;
+
+       timeout = jiffies + 1;
+       while (!need_resched()) {
+               if (i915_gem_request_completed(rq, true))
+                       return 0;
 
-       return !atomic_xchg(&file_priv->rps_wait_boost, true);
+               if (time_after_eq(jiffies, timeout))
+                       break;
+
+               cpu_relax_lowlatency();
+       }
+       if (i915_gem_request_completed(rq, false))
+               return 0;
+
+       return -EAGAIN;
 }
 
 /**
@@ -1226,20 +1245,23 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
        timeout_expire = timeout ?
                jiffies + nsecs_to_jiffies_timeout((u64)*timeout) : 0;
 
-       if (INTEL_INFO(dev)->gen >= 6 && ring->id == RCS && can_wait_boost(file_priv)) {
-               gen6_rps_boost(dev_priv);
-               if (file_priv)
-                       mod_delayed_work(dev_priv->wq,
-                                        &file_priv->mm.idle_work,
-                                        msecs_to_jiffies(100));
-       }
-
-       if (!irq_test_in_progress && WARN_ON(!ring->irq_get(ring)))
-               return -ENODEV;
+       if (INTEL_INFO(dev)->gen >= 6)
+               gen6_rps_boost(dev_priv, file_priv);
 
        /* Record current time in case interrupted by signal, or wedged */
        trace_i915_gem_request_wait_begin(req);
        before = ktime_get_raw_ns();
+
+       /* Optimistic spin for the next jiffie before touching IRQs */
+       ret = __i915_spin_request(req);
+       if (ret == 0)
+               goto out;
+
+       if (!irq_test_in_progress && WARN_ON(!ring->irq_get(ring))) {
+               ret = -ENODEV;
+               goto out;
+       }
+
        for (;;) {
                struct timer_list timer;
 
@@ -1288,14 +1310,15 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
                        destroy_timer_on_stack(&timer);
                }
        }
-       now = ktime_get_raw_ns();
-       trace_i915_gem_request_wait_end(req);
-
        if (!irq_test_in_progress)
                ring->irq_put(ring);
 
        finish_wait(&ring->irq_queue, &wait);
 
+out:
+       now = ktime_get_raw_ns();
+       trace_i915_gem_request_wait_end(req);
+
        if (timeout) {
                s64 tres = *timeout - (now - before);
 
@@ -1922,12 +1945,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
        return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
 }
 
-static inline int
-i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
-{
-       return obj->madv == I915_MADV_DONTNEED;
-}
-
 /* Immediately discard the backing storage */
 static void
 i915_gem_object_truncate(struct drm_i915_gem_object *obj)
@@ -2033,85 +2050,6 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
        return 0;
 }
 
-unsigned long
-i915_gem_shrink(struct drm_i915_private *dev_priv,
-               long target, unsigned flags)
-{
-       const struct {
-               struct list_head *list;
-               unsigned int bit;
-       } phases[] = {
-               { &dev_priv->mm.unbound_list, I915_SHRINK_UNBOUND },
-               { &dev_priv->mm.bound_list, I915_SHRINK_BOUND },
-               { NULL, 0 },
-       }, *phase;
-       unsigned long count = 0;
-
-       /*
-        * As we may completely rewrite the (un)bound list whilst unbinding
-        * (due to retiring requests) we have to strictly process only
-        * one element of the list at the time, and recheck the list
-        * on every iteration.
-        *
-        * In particular, we must hold a reference whilst removing the
-        * object as we may end up waiting for and/or retiring the objects.
-        * This might release the final reference (held by the active list)
-        * and result in the object being freed from under us. This is
-        * similar to the precautions the eviction code must take whilst
-        * removing objects.
-        *
-        * Also note that although these lists do not hold a reference to
-        * the object we can safely grab one here: The final object
-        * unreferencing and the bound_list are both protected by the
-        * dev->struct_mutex and so we won't ever be able to observe an
-        * object on the bound_list with a reference count equals 0.
-        */
-       for (phase = phases; phase->list; phase++) {
-               struct list_head still_in_list;
-
-               if ((flags & phase->bit) == 0)
-                       continue;
-
-               INIT_LIST_HEAD(&still_in_list);
-               while (count < target && !list_empty(phase->list)) {
-                       struct drm_i915_gem_object *obj;
-                       struct i915_vma *vma, *v;
-
-                       obj = list_first_entry(phase->list,
-                                              typeof(*obj), global_list);
-                       list_move_tail(&obj->global_list, &still_in_list);
-
-                       if (flags & I915_SHRINK_PURGEABLE &&
-                           !i915_gem_object_is_purgeable(obj))
-                               continue;
-
-                       drm_gem_object_reference(&obj->base);
-
-                       /* For the unbound phase, this should be a no-op! */
-                       list_for_each_entry_safe(vma, v,
-                                                &obj->vma_list, vma_link)
-                               if (i915_vma_unbind(vma))
-                                       break;
-
-                       if (i915_gem_object_put_pages(obj) == 0)
-                               count += obj->base.size >> PAGE_SHIFT;
-
-                       drm_gem_object_unreference(&obj->base);
-               }
-               list_splice(&still_in_list, phase->list);
-       }
-
-       return count;
-}
-
-static unsigned long
-i915_gem_shrink_all(struct drm_i915_private *dev_priv)
-{
-       i915_gem_evict_everything(dev_priv->dev);
-       return i915_gem_shrink(dev_priv, LONG_MAX,
-                              I915_SHRINK_BOUND | I915_SHRINK_UNBOUND);
-}
-
 static int
 i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
 {
@@ -2259,6 +2197,10 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
                return ret;
 
        list_add_tail(&obj->global_list, &dev_priv->mm.unbound_list);
+
+       obj->get_page.sg = obj->pages->sgl;
+       obj->get_page.last = 0;
+
        return 0;
 }
 
@@ -2458,10 +2400,11 @@ int __i915_add_request(struct intel_engine_cs *ring,
                ret = ring->add_request(ring);
                if (ret)
                        return ret;
+
+               request->tail = intel_ring_get_tail(ringbuf);
        }
 
        request->head = request_start;
-       request->tail = intel_ring_get_tail(ringbuf);
 
        /* Whilst this request exists, batch_obj will be on the
         * active_list, and so will hold the active reference. Only when this
@@ -2492,6 +2435,8 @@ int __i915_add_request(struct intel_engine_cs *ring,
                list_add_tail(&request->client_list,
                              &file_priv->mm.request_list);
                spin_unlock(&file_priv->mm.lock);
+
+               request->pid = get_pid(task_pid(current));
        }
 
        trace_i915_gem_request_add(request);
@@ -2499,7 +2444,6 @@ int __i915_add_request(struct intel_engine_cs *ring,
 
        i915_queue_hangcheck(ring->dev);
 
-       cancel_delayed_work_sync(&dev_priv->mm.idle_work);
        queue_delayed_work(dev_priv->wq,
                           &dev_priv->mm.retire_work,
                           round_jiffies_up_relative(HZ));
@@ -2572,6 +2516,8 @@ 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);
 }
 
@@ -2592,7 +2538,45 @@ void i915_gem_request_free(struct kref *req_ref)
                i915_gem_context_unreference(ctx);
        }
 
-       kfree(req);
+       kmem_cache_free(req->i915->requests, req);
+}
+
+int i915_gem_request_alloc(struct intel_engine_cs *ring,
+                          struct intel_context *ctx)
+{
+       struct drm_i915_private *dev_priv = to_i915(ring->dev);
+       struct drm_i915_gem_request *rq;
+       int ret;
+
+       if (ring->outstanding_lazy_request)
+               return 0;
+
+       rq = kmem_cache_zalloc(dev_priv->requests, GFP_KERNEL);
+       if (rq == NULL)
+               return -ENOMEM;
+
+       kref_init(&rq->ref);
+       rq->i915 = dev_priv;
+
+       ret = i915_gem_get_seqno(ring->dev, &rq->seqno);
+       if (ret) {
+               kfree(rq);
+               return ret;
+       }
+
+       rq->ring = ring;
+
+       if (i915.enable_execlists)
+               ret = intel_logical_ring_alloc_request_extras(rq, ctx);
+       else
+               ret = intel_ring_alloc_request_extras(rq);
+       if (ret) {
+               kfree(rq);
+               return ret;
+       }
+
+       ring->outstanding_lazy_request = rq;
+       return 0;
 }
 
 struct drm_i915_gem_request *
@@ -2654,7 +2638,6 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
                                struct drm_i915_gem_request,
                                execlist_link);
                list_del(&submit_req->execlist_link);
-               intel_runtime_pm_put(dev_priv);
 
                if (submit_req->ctx != ring->default_context)
                        intel_lr_context_unpin(ring, submit_req->ctx);
@@ -2744,7 +2727,6 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
         */
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
-               struct intel_ringbuffer *ringbuf;
 
                request = list_first_entry(&ring->request_list,
                                           struct drm_i915_gem_request,
@@ -2755,23 +2737,12 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
                trace_i915_gem_request_retire(request);
 
-               /* This is one of the few common intersection points
-                * between legacy ringbuffer submission and execlists:
-                * we need to tell them apart in order to find the correct
-                * ringbuffer to which the request belongs to.
-                */
-               if (i915.enable_execlists) {
-                       struct intel_context *ctx = request->ctx;
-                       ringbuf = ctx->engine[ring->id].ringbuf;
-               } else
-                       ringbuf = ring->buffer;
-
                /* 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.
                 */
-               ringbuf->last_retired_head = request->postfix;
+               request->ringbuf->last_retired_head = request->postfix;
 
                i915_gem_free_request(request);
        }
@@ -2856,8 +2827,25 @@ i915_gem_idle_work_handler(struct work_struct *work)
 {
        struct drm_i915_private *dev_priv =
                container_of(work, typeof(*dev_priv), mm.idle_work.work);
+       struct drm_device *dev = dev_priv->dev;
+       struct intel_engine_cs *ring;
+       int i;
 
-       intel_mark_idle(dev_priv->dev);
+       for_each_ring(ring, dev_priv, i)
+               if (!list_empty(&ring->request_list))
+                       return;
+
+       intel_mark_idle(dev);
+
+       if (mutex_trylock(&dev->struct_mutex)) {
+               struct intel_engine_cs *ring;
+               int i;
+
+               for_each_ring(ring, dev_priv, i)
+                       i915_gem_batch_pool_fini(&ring->batch_pool);
+
+               mutex_unlock(&dev->struct_mutex);
+       }
 }
 
 /**
@@ -2955,9 +2943,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        ret = __i915_wait_request(req, reset_counter, true,
                                  args->timeout_ns > 0 ? &args->timeout_ns : NULL,
                                  file->driver_priv);
-       mutex_lock(&dev->struct_mutex);
-       i915_gem_request_unreference(req);
-       mutex_unlock(&dev->struct_mutex);
+       i915_gem_request_unreference__unlocked(req);
        return ret;
 
 out:
@@ -3082,7 +3068,8 @@ int i915_vma_unbind(struct i915_vma *vma)
 
        trace_i915_vma_unbind(vma);
 
-       vma->unbind_vma(vma);
+       vma->vm->unbind_vma(vma);
+       vma->bound = 0;
 
        list_del_init(&vma->mm_list);
        if (i915_is_ggtt(vma->vm)) {
@@ -3511,14 +3498,15 @@ static bool i915_gem_valid_gtt_space(struct i915_vma *vma,
 }
 
 /**
- * Finds free space in the GTT aperture and binds the object there.
+ * Finds free space in the GTT aperture and binds the object or a view of it
+ * there.
  */
 static struct i915_vma *
 i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
                           struct i915_address_space *vm,
+                          const struct i915_ggtt_view *ggtt_view,
                           unsigned alignment,
-                          uint64_t flags,
-                          const struct i915_ggtt_view *view)
+                          uint64_t flags)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3530,33 +3518,60 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
        struct i915_vma *vma;
        int ret;
 
-       fence_size = i915_gem_get_gtt_size(dev,
-                                          obj->base.size,
-                                          obj->tiling_mode);
-       fence_alignment = i915_gem_get_gtt_alignment(dev,
-                                                    obj->base.size,
-                                                    obj->tiling_mode, true);
-       unfenced_alignment =
-               i915_gem_get_gtt_alignment(dev,
-                                          obj->base.size,
-                                          obj->tiling_mode, false);
+       if (i915_is_ggtt(vm)) {
+               u32 view_size;
+
+               if (WARN_ON(!ggtt_view))
+                       return ERR_PTR(-EINVAL);
+
+               view_size = i915_ggtt_view_size(obj, ggtt_view);
+
+               fence_size = i915_gem_get_gtt_size(dev,
+                                                  view_size,
+                                                  obj->tiling_mode);
+               fence_alignment = i915_gem_get_gtt_alignment(dev,
+                                                            view_size,
+                                                            obj->tiling_mode,
+                                                            true);
+               unfenced_alignment = i915_gem_get_gtt_alignment(dev,
+                                                               view_size,
+                                                               obj->tiling_mode,
+                                                               false);
+               size = flags & PIN_MAPPABLE ? fence_size : view_size;
+       } else {
+               fence_size = i915_gem_get_gtt_size(dev,
+                                                  obj->base.size,
+                                                  obj->tiling_mode);
+               fence_alignment = i915_gem_get_gtt_alignment(dev,
+                                                            obj->base.size,
+                                                            obj->tiling_mode,
+                                                            true);
+               unfenced_alignment =
+                       i915_gem_get_gtt_alignment(dev,
+                                                  obj->base.size,
+                                                  obj->tiling_mode,
+                                                  false);
+               size = flags & PIN_MAPPABLE ? fence_size : obj->base.size;
+       }
 
        if (alignment == 0)
                alignment = flags & PIN_MAPPABLE ? fence_alignment :
                                                unfenced_alignment;
        if (flags & PIN_MAPPABLE && alignment & (fence_alignment - 1)) {
-               DRM_DEBUG("Invalid object alignment requested %u\n", alignment);
+               DRM_DEBUG("Invalid object (view type=%u) alignment requested %u\n",
+                         ggtt_view ? ggtt_view->type : 0,
+                         alignment);
                return ERR_PTR(-EINVAL);
        }
 
-       size = flags & PIN_MAPPABLE ? fence_size : obj->base.size;
-
-       /* If the object is bigger than the entire aperture, reject it early
-        * before evicting everything in a vain attempt to find space.
+       /* If binding the object/GGTT view requires more space than the entire
+        * aperture has, reject it early before evicting everything in a vain
+        * attempt to find space.
         */
-       if (obj->base.size > end) {
-               DRM_DEBUG("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%lu\n",
-                         obj->base.size,
+       if (size > end) {
+               DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: size=%u > %s aperture=%lu\n",
+                         ggtt_view ? ggtt_view->type : 0,
+                         size,
                          flags & PIN_MAPPABLE ? "mappable" : "total",
                          end);
                return ERR_PTR(-E2BIG);
@@ -3568,7 +3583,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
 
        i915_gem_object_pin_pages(obj);
 
-       vma = i915_gem_obj_lookup_or_create_vma_view(obj, vm, view);
+       vma = ggtt_view ? i915_gem_obj_lookup_or_create_ggtt_vma(obj, ggtt_view) :
+                         i915_gem_obj_lookup_or_create_vma(obj, vm);
+
        if (IS_ERR(vma))
                goto err_unpin;
 
@@ -3599,8 +3616,7 @@ search_free:
                goto err_remove_node;
 
        trace_i915_vma_bind(vma, flags);
-       ret = i915_vma_bind(vma, obj->cache_level,
-                           flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
+       ret = i915_vma_bind(vma, obj->cache_level, flags);
        if (ret)
                goto err_finish_gtt;
 
@@ -3768,7 +3784,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
        }
 
        if (write)
-               intel_fb_obj_invalidate(obj, NULL);
+               intel_fb_obj_invalidate(obj, NULL, ORIGIN_GTT);
 
        trace_i915_gem_object_change_domain(obj,
                                            old_read_domains,
@@ -3826,7 +3842,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
                list_for_each_entry(vma, &obj->vma_list, vma_link)
                        if (drm_mm_node_allocated(&vma->node)) {
                                ret = i915_vma_bind(vma, cache_level,
-                                                   vma->bound & GLOBAL_BIND);
+                                                   PIN_UPDATE);
                                if (ret)
                                        return ret;
                        }
@@ -3851,17 +3867,10 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
 {
        struct drm_i915_gem_caching *args = data;
        struct drm_i915_gem_object *obj;
-       int ret;
-
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
 
        obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
-       if (&obj->base == NULL) {
-               ret = -ENOENT;
-               goto unlock;
-       }
+       if (&obj->base == NULL)
+               return -ENOENT;
 
        switch (obj->cache_level) {
        case I915_CACHE_LLC:
@@ -3878,10 +3887,8 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
                break;
        }
 
-       drm_gem_object_unreference(&obj->base);
-unlock:
-       mutex_unlock(&dev->struct_mutex);
-       return ret;
+       drm_gem_object_unreference_unlocked(&obj->base);
+       return 0;
 }
 
 int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
@@ -3924,24 +3931,6 @@ unlock:
        return ret;
 }
 
-static bool is_pin_display(struct drm_i915_gem_object *obj)
-{
-       struct i915_vma *vma;
-
-       vma = i915_gem_obj_to_ggtt(obj);
-       if (!vma)
-               return false;
-
-       /* There are 2 sources that pin objects:
-        *   1. The display engine (scanouts, sprites, cursors);
-        *   2. Reservations for execbuffer;
-        *
-        * We can ignore reservations as we hold the struct_mutex and
-        * are only called outside of the reservation path.
-        */
-       return vma->pin_count;
-}
-
 /*
  * Prepare buffer for display plane (scanout, cursors, etc).
  * Can be called from an uninterruptible phase (modesetting) and allows
@@ -3950,10 +3939,10 @@ static bool is_pin_display(struct drm_i915_gem_object *obj)
 int
 i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                     u32 alignment,
-                                    struct intel_engine_cs *pipelined)
+                                    struct intel_engine_cs *pipelined,
+                                    const struct i915_ggtt_view *view)
 {
        u32 old_read_domains, old_write_domain;
-       bool was_pin_display;
        int ret;
 
        if (pipelined != i915_gem_request_get_ring(obj->last_read_req)) {
@@ -3965,8 +3954,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
        /* Mark the pin_display early so that we account for the
         * display coherency whilst setting up the cache domains.
         */
-       was_pin_display = obj->pin_display;
-       obj->pin_display = true;
+       obj->pin_display++;
 
        /* The display engine is not coherent with the LLC cache on gen6.  As
         * a result, we make sure that the pinning that is about to occur is
@@ -3986,7 +3974,9 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
         * (e.g. libkms for the bootup splash), we have to ensure that we
         * always use map_and_fenceable for all scanout buffers.
         */
-       ret = i915_gem_obj_ggtt_pin(obj, alignment, PIN_MAPPABLE);
+       ret = i915_gem_object_ggtt_pin(obj, view, alignment,
+                                      view->type == I915_GGTT_VIEW_NORMAL ?
+                                      PIN_MAPPABLE : 0);
        if (ret)
                goto err_unpin_display;
 
@@ -4008,16 +3998,20 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
        return 0;
 
 err_unpin_display:
-       WARN_ON(was_pin_display != is_pin_display(obj));
-       obj->pin_display = was_pin_display;
+       obj->pin_display--;
        return ret;
 }
 
 void
-i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj)
+i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
+                                        const struct i915_ggtt_view *view)
 {
-       i915_gem_object_ggtt_unpin(obj);
-       obj->pin_display = is_pin_display(obj);
+       if (WARN_ON(obj->pin_display == 0))
+               return;
+
+       i915_gem_object_ggtt_unpin_view(obj, view);
+
+       obj->pin_display--;
 }
 
 int
@@ -4083,7 +4077,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
        }
 
        if (write)
-               intel_fb_obj_invalidate(obj, NULL);
+               intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU);
 
        trace_i915_gem_object_change_domain(obj,
                                            old_read_domains,
@@ -4139,9 +4133,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
        if (ret == 0)
                queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
 
-       mutex_lock(&dev->struct_mutex);
-       i915_gem_request_unreference(target);
-       mutex_unlock(&dev->struct_mutex);
+       i915_gem_request_unreference__unlocked(target);
 
        return ret;
 }
@@ -4165,12 +4157,12 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
        return false;
 }
 
-int
-i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
-                        struct i915_address_space *vm,
-                        uint32_t alignment,
-                        uint64_t flags,
-                        const struct i915_ggtt_view *view)
+static int
+i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
+                      struct i915_address_space *vm,
+                      const struct i915_ggtt_view *ggtt_view,
+                      uint32_t alignment,
+                      uint64_t flags)
 {
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
        struct i915_vma *vma;
@@ -4186,17 +4178,29 @@ i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
        if (WARN_ON((flags & (PIN_MAPPABLE | PIN_GLOBAL)) == PIN_MAPPABLE))
                return -EINVAL;
 
-       vma = i915_gem_obj_to_vma_view(obj, vm, view);
+       if (WARN_ON(i915_is_ggtt(vm) != !!ggtt_view))
+               return -EINVAL;
+
+       vma = ggtt_view ? i915_gem_obj_to_ggtt_view(obj, ggtt_view) :
+                         i915_gem_obj_to_vma(obj, vm);
+
+       if (IS_ERR(vma))
+               return PTR_ERR(vma);
+
        if (vma) {
                if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
                        return -EBUSY;
 
                if (i915_vma_misplaced(vma, alignment, flags)) {
+                       unsigned long offset;
+                       offset = ggtt_view ? i915_gem_obj_ggtt_offset_view(obj, ggtt_view) :
+                                            i915_gem_obj_offset(obj, vm);
                        WARN(vma->pin_count,
-                            "bo is already pinned with incorrect alignment:"
+                            "bo is already pinned in %s with incorrect alignment:"
                             " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
                             " obj->map_and_fenceable=%d\n",
-                            i915_gem_obj_offset_view(obj, vm, view->type),
+                            ggtt_view ? "ggtt" : "ppgtt",
+                            offset,
                             alignment,
                             !!(flags & PIN_MAPPABLE),
                             obj->map_and_fenceable);
@@ -4210,19 +4214,18 @@ i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
 
        bound = vma ? vma->bound : 0;
        if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
-               vma = i915_gem_object_bind_to_vm(obj, vm, alignment,
-                                                flags, view);
+               vma = i915_gem_object_bind_to_vm(obj, vm, ggtt_view, alignment,
+                                                flags);
                if (IS_ERR(vma))
                        return PTR_ERR(vma);
-       }
-
-       if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND)) {
-               ret = i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND);
+       } else {
+               ret = i915_vma_bind(vma, obj->cache_level, flags);
                if (ret)
                        return ret;
        }
 
-       if ((bound ^ vma->bound) & GLOBAL_BIND) {
+       if (ggtt_view && ggtt_view->type == I915_GGTT_VIEW_NORMAL &&
+           (bound ^ vma->bound) & GLOBAL_BIND) {
                bool mappable, fenceable;
                u32 fence_size, fence_alignment;
 
@@ -4237,32 +4240,53 @@ i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
                fenceable = (vma->node.size == fence_size &&
                             (vma->node.start & (fence_alignment - 1)) == 0);
 
-               mappable = (vma->node.start + obj->base.size <=
+               mappable = (vma->node.start + fence_size <=
                            dev_priv->gtt.mappable_end);
 
                obj->map_and_fenceable = mappable && fenceable;
-       }
 
-       WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable);
+               WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable);
+       }
 
        vma->pin_count++;
-       if (flags & PIN_MAPPABLE)
-               obj->pin_mappable |= true;
-
        return 0;
 }
 
+int
+i915_gem_object_pin(struct drm_i915_gem_object *obj,
+                   struct i915_address_space *vm,
+                   uint32_t alignment,
+                   uint64_t flags)
+{
+       return i915_gem_object_do_pin(obj, vm,
+                                     i915_is_ggtt(vm) ? &i915_ggtt_view_normal : NULL,
+                                     alignment, flags);
+}
+
+int
+i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
+                        const struct i915_ggtt_view *view,
+                        uint32_t alignment,
+                        uint64_t flags)
+{
+       if (WARN_ONCE(!view, "no view specified"))
+               return -EINVAL;
+
+       return i915_gem_object_do_pin(obj, i915_obj_to_ggtt(obj), view,
+                                     alignment, flags | PIN_GLOBAL);
+}
+
 void
-i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj)
+i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj,
+                               const struct i915_ggtt_view *view)
 {
-       struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
+       struct i915_vma *vma = i915_gem_obj_to_ggtt_view(obj, view);
 
        BUG_ON(!vma);
-       BUG_ON(vma->pin_count == 0);
-       BUG_ON(!i915_gem_obj_ggtt_bound(obj));
+       WARN_ON(vma->pin_count == 0);
+       WARN_ON(!i915_gem_obj_ggtt_bound_view(obj, view));
 
-       if (--vma->pin_count == 0)
-               obj->pin_mappable = false;
+       --vma->pin_count;
 }
 
 bool
@@ -4382,7 +4406,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
                obj->madv = args->madv;
 
        /* if the object is no longer attached, discard its backing storage */
-       if (i915_gem_object_is_purgeable(obj) && obj->pages == NULL)
+       if (obj->madv == I915_MADV_DONTNEED && obj->pages == NULL)
                i915_gem_object_truncate(obj);
 
        args->retained = obj->madv != __I915_MADV_PURGED;
@@ -4401,7 +4425,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
        INIT_LIST_HEAD(&obj->ring_list);
        INIT_LIST_HEAD(&obj->obj_exec_link);
        INIT_LIST_HEAD(&obj->vma_list);
-       INIT_LIST_HEAD(&obj->batch_pool_list);
+       INIT_LIST_HEAD(&obj->batch_pool_link);
 
        obj->ops = ops;
 
@@ -4557,15 +4581,33 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
        intel_runtime_pm_put(dev_priv);
 }
 
-struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
-                                         struct i915_address_space *vm,
-                                         const struct i915_ggtt_view *view)
+struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
+                                    struct i915_address_space *vm)
 {
        struct i915_vma *vma;
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (vma->vm == vm && vma->ggtt_view.type == view->type)
+       list_for_each_entry(vma, &obj->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
+               if (vma->vm == vm)
                        return vma;
+       }
+       return NULL;
+}
+
+struct i915_vma *i915_gem_obj_to_ggtt_view(struct drm_i915_gem_object *obj,
+                                          const struct i915_ggtt_view *view)
+{
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
+       struct i915_vma *vma;
 
+       if (WARN_ONCE(!view, "no view specified"))
+               return ERR_PTR(-EINVAL);
+
+       list_for_each_entry(vma, &obj->vma_list, vma_link)
+               if (vma->vm == ggtt &&
+                   i915_ggtt_view_equal(&vma->ggtt_view, view))
+                       return vma;
        return NULL;
 }
 
@@ -4585,7 +4627,7 @@ void i915_gem_vma_destroy(struct i915_vma *vma)
 
        list_del(&vma->vma_link);
 
-       kfree(vma);
+       kmem_cache_free(to_i915(vma->obj->base.dev)->vmas, vma);
 }
 
 static void
@@ -4612,10 +4654,6 @@ i915_gem_suspend(struct drm_device *dev)
 
        i915_gem_retire_requests(dev);
 
-       /* Under UMS, be paranoid and evict. */
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               i915_gem_evict_everything(dev);
-
        i915_gem_stop_ringbuffers(dev);
        mutex_unlock(&dev->struct_mutex);
 
@@ -4876,12 +4914,12 @@ int i915_gem_init(struct drm_device *dev)
        }
 
        if (!i915.enable_execlists) {
-               dev_priv->gt.do_execbuf = i915_gem_ringbuffer_submission;
+               dev_priv->gt.execbuf_submit = i915_gem_ringbuffer_submission;
                dev_priv->gt.init_rings = i915_gem_init_rings;
                dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer;
                dev_priv->gt.stop_ring = intel_stop_ring_buffer;
        } else {
-               dev_priv->gt.do_execbuf = intel_execlists_submission;
+               dev_priv->gt.execbuf_submit = intel_execlists_submission;
                dev_priv->gt.init_rings = intel_logical_rings_init;
                dev_priv->gt.cleanup_ring = intel_logical_ring_cleanup;
                dev_priv->gt.stop_ring = intel_logical_ring_stop;
@@ -4963,11 +5001,21 @@ i915_gem_load(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
-       dev_priv->slab =
+       dev_priv->objects =
                kmem_cache_create("i915_gem_object",
                                  sizeof(struct drm_i915_gem_object), 0,
                                  SLAB_HWCACHE_ALIGN,
                                  NULL);
+       dev_priv->vmas =
+               kmem_cache_create("i915_gem_vma",
+                                 sizeof(struct i915_vma), 0,
+                                 SLAB_HWCACHE_ALIGN,
+                                 NULL);
+       dev_priv->requests =
+               kmem_cache_create("i915_gem_request",
+                                 sizeof(struct drm_i915_gem_request), 0,
+                                 SLAB_HWCACHE_ALIGN,
+                                 NULL);
 
        INIT_LIST_HEAD(&dev_priv->vm_list);
        i915_init_vm(dev_priv, &dev_priv->gtt.base);
@@ -4986,18 +5034,8 @@ i915_gem_load(struct drm_device *dev)
                          i915_gem_idle_work_handler);
        init_waitqueue_head(&dev_priv->gpu_error.reset_queue);
 
-       /* On GEN3 we really need to make sure the ARB C3 LP bit is set */
-       if (!drm_core_check_feature(dev, DRIVER_MODESET) && IS_GEN3(dev)) {
-               I915_WRITE(MI_ARB_STATE,
-                          _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE));
-       }
-
        dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL;
 
-       /* Old X drivers will take 0-2 for front, back, depth buffers */
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               dev_priv->fence_reg_start = 3;
-
        if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev))
                dev_priv->num_fence_regs = 32;
        else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
@@ -5005,6 +5043,10 @@ i915_gem_load(struct drm_device *dev)
        else
                dev_priv->num_fence_regs = 8;
 
+       if (intel_vgpu_active(dev))
+               dev_priv->num_fence_regs =
+                               I915_READ(vgtif_reg(avail_rs.fence_num));
+
        /* Initialize fence registers to zero */
        INIT_LIST_HEAD(&dev_priv->mm.fence_list);
        i915_gem_restore_fences(dev);
@@ -5014,15 +5056,7 @@ i915_gem_load(struct drm_device *dev)
 
        dev_priv->mm.interruptible = true;
 
-       dev_priv->mm.shrinker.scan_objects = i915_gem_shrinker_scan;
-       dev_priv->mm.shrinker.count_objects = i915_gem_shrinker_count;
-       dev_priv->mm.shrinker.seeks = DEFAULT_SEEKS;
-       register_shrinker(&dev_priv->mm.shrinker);
-
-       dev_priv->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom;
-       register_oom_notifier(&dev_priv->mm.oom_notifier);
-
-       i915_gem_batch_pool_init(dev, &dev_priv->mm.batch_pool);
+       i915_gem_shrinker_init(dev_priv);
 
        mutex_init(&dev_priv->fb_tracking.lock);
 }
@@ -5031,8 +5065,6 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_i915_file_private *file_priv = file->driver_priv;
 
-       cancel_delayed_work_sync(&file_priv->mm.idle_work);
-
        /* Clean up our request list when the client is going away, so that
         * later retire_requests won't dereference our soon-to-be-gone
         * file_priv.
@@ -5048,15 +5080,12 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file)
                request->file_priv = NULL;
        }
        spin_unlock(&file_priv->mm.lock);
-}
-
-static void
-i915_gem_file_idle_work_handler(struct work_struct *work)
-{
-       struct drm_i915_file_private *file_priv =
-               container_of(work, typeof(*file_priv), mm.idle_work.work);
 
-       atomic_set(&file_priv->rps_wait_boost, false);
+       if (!list_empty(&file_priv->rps_boost)) {
+               mutex_lock(&to_i915(dev)->rps.hw_lock);
+               list_del(&file_priv->rps_boost);
+               mutex_unlock(&to_i915(dev)->rps.hw_lock);
+       }
 }
 
 int i915_gem_open(struct drm_device *dev, struct drm_file *file)
@@ -5073,11 +5102,10 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file)
        file->driver_priv = file_priv;
        file_priv->dev_priv = dev->dev_private;
        file_priv->file = file;
+       INIT_LIST_HEAD(&file_priv->rps_boost);
 
        spin_lock_init(&file_priv->mm.lock);
        INIT_LIST_HEAD(&file_priv->mm.request_list);
-       INIT_DELAYED_WORK(&file_priv->mm.idle_work,
-                         i915_gem_file_idle_work_handler);
 
        ret = i915_gem_context_open(dev, file);
        if (ret)
@@ -5112,106 +5140,70 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
        }
 }
 
-static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
-{
-       if (!mutex_is_locked(mutex))
-               return false;
-
-#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
-       return mutex->owner == task;
-#else
-       /* Since UP may be pre-empted, we cannot assume that we own the lock */
-       return false;
-#endif
-}
-
-static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock)
+/* All the new VM stuff */
+unsigned long
+i915_gem_obj_offset(struct drm_i915_gem_object *o,
+                   struct i915_address_space *vm)
 {
-       if (!mutex_trylock(&dev->struct_mutex)) {
-               if (!mutex_is_locked_by(&dev->struct_mutex, current))
-                       return false;
+       struct drm_i915_private *dev_priv = o->base.dev->dev_private;
+       struct i915_vma *vma;
 
-               if (to_i915(dev)->mm.shrinker_no_lock_stealing)
-                       return false;
+       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
 
-               *unlock = false;
-       } else
-               *unlock = true;
+       list_for_each_entry(vma, &o->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
+               if (vma->vm == vm)
+                       return vma->node.start;
+       }
 
-       return true;
+       WARN(1, "%s vma for this object not found.\n",
+            i915_is_ggtt(vm) ? "global" : "ppgtt");
+       return -1;
 }
 
-static int num_vma_bound(struct drm_i915_gem_object *obj)
+unsigned long
+i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
+                             const struct i915_ggtt_view *view)
 {
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(o);
        struct i915_vma *vma;
-       int count = 0;
 
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (drm_mm_node_allocated(&vma->node))
-                       count++;
-
-       return count;
-}
-
-static unsigned long
-i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(shrinker, struct drm_i915_private, mm.shrinker);
-       struct drm_device *dev = dev_priv->dev;
-       struct drm_i915_gem_object *obj;
-       unsigned long count;
-       bool unlock;
-
-       if (!i915_gem_shrinker_lock(dev, &unlock))
-               return 0;
-
-       count = 0;
-       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
-               if (obj->pages_pin_count == 0)
-                       count += obj->base.size >> PAGE_SHIFT;
-
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (!i915_gem_obj_is_pinned(obj) &&
-                   obj->pages_pin_count == num_vma_bound(obj))
-                       count += obj->base.size >> PAGE_SHIFT;
-       }
-
-       if (unlock)
-               mutex_unlock(&dev->struct_mutex);
+       list_for_each_entry(vma, &o->vma_list, vma_link)
+               if (vma->vm == ggtt &&
+                   i915_ggtt_view_equal(&vma->ggtt_view, view))
+                       return vma->node.start;
 
-       return count;
+       WARN(1, "global vma for this object not found. (view=%u)\n", view->type);
+       return -1;
 }
 
-/* All the new VM stuff */
-unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
-                                      struct i915_address_space *vm,
-                                      enum i915_ggtt_view_type view)
+bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
+                       struct i915_address_space *vm)
 {
-       struct drm_i915_private *dev_priv = o->base.dev->dev_private;
        struct i915_vma *vma;
 
-       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
-
        list_for_each_entry(vma, &o->vma_list, vma_link) {
-               if (vma->vm == vm && vma->ggtt_view.type == view)
-                       return vma->node.start;
-
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
+               if (vma->vm == vm && drm_mm_node_allocated(&vma->node))
+                       return true;
        }
-       WARN(1, "%s vma for this object not found.\n",
-            i915_is_ggtt(vm) ? "global" : "ppgtt");
-       return -1;
+
+       return false;
 }
 
-bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
-                            struct i915_address_space *vm,
-                            enum i915_ggtt_view_type view)
+bool i915_gem_obj_ggtt_bound_view(struct drm_i915_gem_object *o,
+                                 const struct i915_ggtt_view *view)
 {
+       struct i915_address_space *ggtt = i915_obj_to_ggtt(o);
        struct i915_vma *vma;
 
        list_for_each_entry(vma, &o->vma_list, vma_link)
-               if (vma->vm == vm &&
-                   vma->ggtt_view.type == view &&
+               if (vma->vm == ggtt &&
+                   i915_ggtt_view_equal(&vma->ggtt_view, view) &&
                    drm_mm_node_allocated(&vma->node))
                        return true;
 
@@ -5239,118 +5231,26 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
 
        BUG_ON(list_empty(&o->vma_list));
 
-       list_for_each_entry(vma, &o->vma_list, vma_link)
+       list_for_each_entry(vma, &o->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
+                       continue;
                if (vma->vm == vm)
                        return vma->node.size;
-
+       }
        return 0;
 }
 
-static unsigned long
-i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
+bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj)
 {
-       struct drm_i915_private *dev_priv =
-               container_of(shrinker, struct drm_i915_private, mm.shrinker);
-       struct drm_device *dev = dev_priv->dev;
-       unsigned long freed;
-       bool unlock;
-
-       if (!i915_gem_shrinker_lock(dev, &unlock))
-               return SHRINK_STOP;
-
-       freed = i915_gem_shrink(dev_priv,
-                               sc->nr_to_scan,
-                               I915_SHRINK_BOUND |
-                               I915_SHRINK_UNBOUND |
-                               I915_SHRINK_PURGEABLE);
-       if (freed < sc->nr_to_scan)
-               freed += i915_gem_shrink(dev_priv,
-                                        sc->nr_to_scan - freed,
-                                        I915_SHRINK_BOUND |
-                                        I915_SHRINK_UNBOUND);
-       if (unlock)
-               mutex_unlock(&dev->struct_mutex);
-
-       return freed;
-}
-
-static int
-i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(nb, struct drm_i915_private, mm.oom_notifier);
-       struct drm_device *dev = dev_priv->dev;
-       struct drm_i915_gem_object *obj;
-       unsigned long timeout = msecs_to_jiffies(5000) + 1;
-       unsigned long pinned, bound, unbound, freed_pages;
-       bool was_interruptible;
-       bool unlock;
-
-       while (!i915_gem_shrinker_lock(dev, &unlock) && --timeout) {
-               schedule_timeout_killable(1);
-               if (fatal_signal_pending(current))
-                       return NOTIFY_DONE;
-       }
-       if (timeout == 0) {
-               pr_err("Unable to purge GPU memory due lock contention.\n");
-               return NOTIFY_DONE;
-       }
-
-       was_interruptible = dev_priv->mm.interruptible;
-       dev_priv->mm.interruptible = false;
-
-       freed_pages = i915_gem_shrink_all(dev_priv);
-
-       dev_priv->mm.interruptible = was_interruptible;
-
-       /* Because we may be allocating inside our own driver, we cannot
-        * assert that there are no objects with pinned pages that are not
-        * being pointed to by hardware.
-        */
-       unbound = bound = pinned = 0;
-       list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
-               if (!obj->base.filp) /* not backed by a freeable object */
-                       continue;
-
-               if (obj->pages_pin_count)
-                       pinned += obj->base.size;
-               else
-                       unbound += obj->base.size;
-       }
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (!obj->base.filp)
+       struct i915_vma *vma;
+       list_for_each_entry(vma, &obj->vma_list, vma_link) {
+               if (i915_is_ggtt(vma->vm) &&
+                   vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
                        continue;
-
-               if (obj->pages_pin_count)
-                       pinned += obj->base.size;
-               else
-                       bound += obj->base.size;
+               if (vma->pin_count > 0)
+                       return true;
        }
-
-       if (unlock)
-               mutex_unlock(&dev->struct_mutex);
-
-       if (freed_pages || unbound || bound)
-               pr_info("Purging GPU memory, %lu bytes freed, %lu bytes still pinned.\n",
-                       freed_pages << PAGE_SHIFT, pinned);
-       if (unbound || bound)
-               pr_err("%lu and %lu bytes still available in the "
-                      "bound and unbound GPU page lists.\n",
-                      bound, unbound);
-
-       *(unsigned long *)ptr += freed_pages;
-       return NOTIFY_DONE;
+       return false;
 }
 
-struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
-{
-       struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
-       struct i915_vma *vma;
-
-       list_for_each_entry(vma, &obj->vma_list, vma_link)
-               if (vma->vm == ggtt &&
-                   vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
-                       return vma;
-
-       return NULL;
-}