[Intel-gfx] Maintainer-review fluff (was: Re: [PATCH 01/12] drm/i915: plumb VM into object operations)

Daniel Vetter daniel at ffwll.ch
Fri Jul 26 11:51:00 CEST 2013


HI all,

So Ben&I had a bit a private discussion and one thing I've explained a bit
more in detail is what kind of review I'm doing as maintainer. I've
figured this is generally useful. We've also discussed a bit that for
developers without their own lab it would be nice if QA could test random
branches on their set of machines. But imo that'll take quite a while,
there's lots of other stuff to improve in QA land first. Anyway, here's
it:

Now an explanation for why this freaked me out, which is essentially an
explanation of what I do when I do maintainer reviews:

Probably the most important question I ask myself when reading a patch is
"if a regression would bisect to this, and the bisect is the only useful
piece of evidence, would I stand a chance to understand it?".  Your patch
is big, has the appearance of doing a few unrelated things and could very
well hide a bug which would take me an awful lot of time to spot. So imo
the answer for your patch is a clear "no".

I've merged a few such patches in the past  where I've had a similar hunch
and regretted it almost always. I've also sometimes split-up the patch
while applying, but that approach doesn't scale any more with our rather
big team.

The second thing I try to figure out is whether the patch author is indeed
the local expert on the topic at hand now. With our team size and patch
flow I don't stand a chance if I try to understand everything to the last
detail. Instead I try to assess this through the proxy of convincing
myself the the patch submitter understands stuff much better than I do. I
tend to check that by asking random questions, proposing alternative
approaches and also by rating code/patch clarity. The obj_set_color
double-loop very much gave me the impression that you didn't have a clear
idea about how exactly this should work, so that  hunk trigger this
maintainer hunch.

I admit that this is all rather fluffy and very much an inexact science,
but it's the only tools I have as a maintainer. The alternative of doing
shit myself or checking everything myself in-depth just doesnt scale.

Cheers, Daniel


On Mon, Jul 22, 2013 at 4:08 AM, Ben Widawsky <ben at bwidawsk.net> wrote:
> This patch was formerly known as:
> "drm/i915: Create VMAs (part 3) - plumbing"
>
> This patch adds a VM argument, bind/unbind, and the object
> offset/size/color getters/setters. It preserves the old ggtt helper
> functions because things still need, and will continue to need them.
>
> Some code will still need to be ported over after this.
>
> v2: Fix purge to pick an object and unbind all vmas
> This was doable because of the global bound list change.
>
> v3: With the commit to actually pin/unpin pages in place, there is no
> longer a need to check if unbind succeeded before calling put_pages().
> Make put_pages only BUG() after checking pin count.
>
> v4: Rebased on top of the new hangcheck work by Mika
> plumbed eb_destroy also
> Many checkpatch related fixes
>
> v5: Very large rebase
>
> v6:
> Change BUG_ON to WARN_ON (Daniel)
> Rename vm to ggtt in preallocate stolen, since it is always ggtt when
> dealing with stolen memory. (Daniel)
> list_for_each will short-circuit already (Daniel)
> remove superflous space (Daniel)
> Use per object list of vmas (Daniel)
> Make obj_bound_any() use obj_bound for each vm (Ben)
> s/bind_to_gtt/bind_to_vm/ (Ben)
>
> Fixed up the inactive shrinker. As Daniel noticed the code could
> potentially count the same object multiple times. While it's not
> possible in the current case, since 1 object can only ever be bound into
> 1 address space thus far - we may as well try to get something more
> future proof in place now. With a prep patch before this to switch over
> to using the bound list + inactive check, we're now able to carry that
> forward for every address space an object is bound into.
>
> Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c        |  29 ++-
>  drivers/gpu/drm/i915/i915_dma.c            |   4 -
>  drivers/gpu/drm/i915/i915_drv.h            | 107 +++++----
>  drivers/gpu/drm/i915/i915_gem.c            | 337 +++++++++++++++++++++--------
>  drivers/gpu/drm/i915/i915_gem_context.c    |   9 +-
>  drivers/gpu/drm/i915/i915_gem_evict.c      |  51 +++--
>  drivers/gpu/drm/i915/i915_gem_execbuffer.c |  85 +++++---
>  drivers/gpu/drm/i915/i915_gem_gtt.c        |  41 ++--
>  drivers/gpu/drm/i915/i915_gem_stolen.c     |  10 +-
>  drivers/gpu/drm/i915/i915_gem_tiling.c     |  10 +-
>  drivers/gpu/drm/i915/i915_trace.h          |  20 +-
>  drivers/gpu/drm/i915/intel_fb.c            |   1 -
>  drivers/gpu/drm/i915/intel_overlay.c       |   2 +-
>  drivers/gpu/drm/i915/intel_pm.c            |   2 +-
>  drivers/gpu/drm/i915/intel_ringbuffer.c    |  16 +-
>  15 files changed, 479 insertions(+), 245 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index be69807..f8e590f 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -92,6 +92,7 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj)
>  static void
>  describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
>  {
> +       struct i915_vma *vma;
>         seq_printf(m, "%pK: %s%s %8zdKiB %02x %02x %d %d %d%s%s%s",
>                    &obj->base,
>                    get_pin_flag(obj),
> @@ -111,9 +112,15 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
>                 seq_printf(m, " (pinned x %d)", obj->pin_count);
>         if (obj->fence_reg != I915_FENCE_REG_NONE)
>                 seq_printf(m, " (fence: %d)", obj->fence_reg);
> -       if (i915_gem_obj_ggtt_bound(obj))
> -               seq_printf(m, " (gtt offset: %08lx, size: %08x)",
> -                          i915_gem_obj_ggtt_offset(obj), (unsigned int)i915_gem_obj_ggtt_size(obj));
> +       list_for_each_entry(vma, &obj->vma_list, vma_link) {
> +               if (!i915_is_ggtt(vma->vm))
> +                       seq_puts(m, " (pp");
> +               else
> +                       seq_puts(m, " (g");
> +               seq_printf(m, "gtt offset: %08lx, size: %08lx)",
> +                          i915_gem_obj_offset(obj, vma->vm),
> +                          i915_gem_obj_size(obj, vma->vm));
> +       }
>         if (obj->stolen)
>                 seq_printf(m, " (stolen: %08lx)", obj->stolen->start);
>         if (obj->pin_mappable || obj->fault_mappable) {
> @@ -175,6 +182,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
>         return 0;
>  }
>
> +/* FIXME: Support multiple VM? */
>  #define count_objects(list, member) do { \
>         list_for_each_entry(obj, list, member) { \
>                 size += i915_gem_obj_ggtt_size(obj); \
> @@ -1781,18 +1789,21 @@ i915_drop_caches_set(void *data, u64 val)
>
>         if (val & DROP_BOUND) {
>                 list_for_each_entry_safe(obj, next, &vm->inactive_list,
> -                                        mm_list)
> -                       if (obj->pin_count == 0) {
> -                               ret = i915_gem_object_unbind(obj);
> -                               if (ret)
> -                                       goto unlock;
> -                       }
> +                                        mm_list) {
> +                       if (obj->pin_count)
> +                               continue;
> +
> +                       ret = i915_gem_object_unbind(obj, &dev_priv->gtt.base);
> +                       if (ret)
> +                               goto unlock;
> +               }
>         }
>
>         if (val & DROP_UNBOUND) {
>                 list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list,
>                                          global_list)
>                         if (obj->pages_pin_count == 0) {
> +                               /* FIXME: Do this for all vms? */
>                                 ret = i915_gem_object_put_pages(obj);
>                                 if (ret)
>                                         goto unlock;
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 1449d06..4650519 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1499,10 +1499,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>
>         i915_dump_device_info(dev_priv);
>
> -       INIT_LIST_HEAD(&dev_priv->vm_list);
> -       INIT_LIST_HEAD(&dev_priv->gtt.base.global_link);
> -       list_add(&dev_priv->gtt.base.global_link, &dev_priv->vm_list);
> -
>         if (i915_get_bridge_dev(dev)) {
>                 ret = -EIO;
>                 goto free_priv;
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 8b3167e..681cb41 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1379,52 +1379,6 @@ struct drm_i915_gem_object {
>
>  #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
>
> -/* This is a temporary define to help transition us to real VMAs. If you see
> - * this, you're either reviewing code, or bisecting it. */
> -static inline struct i915_vma *
> -__i915_gem_obj_to_vma(struct drm_i915_gem_object *obj)
> -{
> -       if (list_empty(&obj->vma_list))
> -               return NULL;
> -       return list_first_entry(&obj->vma_list, struct i915_vma, vma_link);
> -}
> -
> -/* Whether or not this object is currently mapped by the translation tables */
> -static inline bool
> -i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *o)
> -{
> -       struct i915_vma *vma = __i915_gem_obj_to_vma(o);
> -       if (vma == NULL)
> -               return false;
> -       return drm_mm_node_allocated(&vma->node);
> -}
> -
> -/* Offset of the first PTE pointing to this object */
> -static inline unsigned long
> -i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *o)
> -{
> -       BUG_ON(list_empty(&o->vma_list));
> -       return __i915_gem_obj_to_vma(o)->node.start;
> -}
> -
> -/* The size used in the translation tables may be larger than the actual size of
> - * the object on GEN2/GEN3 because of the way tiling is handled. See
> - * i915_gem_get_gtt_size() for more details.
> - */
> -static inline unsigned long
> -i915_gem_obj_ggtt_size(struct drm_i915_gem_object *o)
> -{
> -       BUG_ON(list_empty(&o->vma_list));
> -       return __i915_gem_obj_to_vma(o)->node.size;
> -}
> -
> -static inline void
> -i915_gem_obj_ggtt_set_color(struct drm_i915_gem_object *o,
> -                           enum i915_cache_level color)
> -{
> -       __i915_gem_obj_to_vma(o)->node.color = color;
> -}
> -
>  /**
>   * Request queue structure.
>   *
> @@ -1736,11 +1690,13 @@ struct i915_vma *i915_gem_vma_create(struct drm_i915_gem_object *obj,
>  void i915_gem_vma_destroy(struct i915_vma *vma);
>
>  int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
> +                                    struct i915_address_space *vm,
>                                      uint32_t alignment,
>                                      bool map_and_fenceable,
>                                      bool nonblocking);
>  void i915_gem_object_unpin(struct drm_i915_gem_object *obj);
> -int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj);
> +int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj,
> +                                       struct i915_address_space *vm);
>  int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
>  void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
>  void i915_gem_lastclose(struct drm_device *dev);
> @@ -1770,6 +1726,7 @@ int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
>  int i915_gem_object_sync(struct drm_i915_gem_object *obj,
>                          struct intel_ring_buffer *to);
>  void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
> +                                   struct i915_address_space *vm,
>                                     struct intel_ring_buffer *ring);
>
>  int i915_gem_dumb_create(struct drm_file *file_priv,
> @@ -1876,6 +1833,7 @@ i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size,
>                             int tiling_mode, bool fenced);
>
>  int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
> +                                   struct i915_address_space *vm,
>                                     enum i915_cache_level cache_level);
>
>  struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
> @@ -1886,6 +1844,56 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
>
>  void i915_gem_restore_fences(struct drm_device *dev);
>
> +unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
> +                                 struct i915_address_space *vm);
> +bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o);
> +bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
> +                       struct i915_address_space *vm);
> +unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
> +                               struct i915_address_space *vm);
> +void i915_gem_obj_set_color(struct drm_i915_gem_object *o,
> +                           struct i915_address_space *vm,
> +                           enum i915_cache_level color);
> +struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
> +                                    struct i915_address_space *vm);
> +/* Some GGTT VM helpers */
> +#define obj_to_ggtt(obj) \
> +       (&((struct drm_i915_private *)(obj)->base.dev->dev_private)->gtt.base)
> +static inline bool i915_is_ggtt(struct i915_address_space *vm)
> +{
> +       struct i915_address_space *ggtt =
> +               &((struct drm_i915_private *)(vm)->dev->dev_private)->gtt.base;
> +       return vm == ggtt;
> +}
> +
> +static inline bool i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *obj)
> +{
> +       return i915_gem_obj_bound(obj, obj_to_ggtt(obj));
> +}
> +
> +static inline unsigned long
> +i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *obj)
> +{
> +       return i915_gem_obj_offset(obj, obj_to_ggtt(obj));
> +}
> +
> +static inline unsigned long
> +i915_gem_obj_ggtt_size(struct drm_i915_gem_object *obj)
> +{
> +       return i915_gem_obj_size(obj, obj_to_ggtt(obj));
> +}
> +
> +static inline int __must_check
> +i915_gem_ggtt_pin(struct drm_i915_gem_object *obj,
> +                 uint32_t alignment,
> +                 bool map_and_fenceable,
> +                 bool nonblocking)
> +{
> +       return i915_gem_object_pin(obj, obj_to_ggtt(obj), alignment,
> +                                  map_and_fenceable, nonblocking);
> +}
> +#undef obj_to_ggtt
> +
>  /* i915_gem_context.c */
>  void i915_gem_context_init(struct drm_device *dev);
>  void i915_gem_context_fini(struct drm_device *dev);
> @@ -1922,6 +1930,7 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
>
>  void i915_gem_restore_gtt_mappings(struct drm_device *dev);
>  int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj);
> +/* FIXME: this is never okay with full PPGTT */
>  void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
>                                 enum i915_cache_level cache_level);
>  void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj);
> @@ -1938,7 +1947,9 @@ static inline void i915_gem_chipset_flush(struct drm_device *dev)
>
>
>  /* i915_gem_evict.c */
> -int __must_check i915_gem_evict_something(struct drm_device *dev, int min_size,
> +int __must_check i915_gem_evict_something(struct drm_device *dev,
> +                                         struct i915_address_space *vm,
> +                                         int min_size,
>                                           unsigned alignment,
>                                           unsigned cache_level,
>                                           bool mappable,
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 2283765..0111554 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -38,10 +38,12 @@
>
>  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 __must_check int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
> -                                                   unsigned alignment,
> -                                                   bool map_and_fenceable,
> -                                                   bool nonblocking);
> +static __must_check int
> +i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
> +                          struct i915_address_space *vm,
> +                          unsigned alignment,
> +                          bool map_and_fenceable,
> +                          bool nonblocking);
>  static int i915_gem_phys_pwrite(struct drm_device *dev,
>                                 struct drm_i915_gem_object *obj,
>                                 struct drm_i915_gem_pwrite *args,
> @@ -120,7 +122,7 @@ int i915_mutex_lock_interruptible(struct drm_device *dev)
>  static inline bool
>  i915_gem_object_is_inactive(struct drm_i915_gem_object *obj)
>  {
> -       return i915_gem_obj_ggtt_bound(obj) && !obj->active;
> +       return i915_gem_obj_bound_any(obj) && !obj->active;
>  }
>
>  int
> @@ -406,7 +408,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
>                  * anyway again before the next pread happens. */
>                 if (obj->cache_level == I915_CACHE_NONE)
>                         needs_clflush = 1;
> -               if (i915_gem_obj_ggtt_bound(obj)) {
> +               if (i915_gem_obj_bound_any(obj)) {
>                         ret = i915_gem_object_set_to_gtt_domain(obj, false);
>                         if (ret)
>                                 return ret;
> @@ -578,7 +580,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
>         char __user *user_data;
>         int page_offset, page_length, ret;
>
> -       ret = i915_gem_object_pin(obj, 0, true, true);
> +       ret = i915_gem_ggtt_pin(obj, 0, true, true);
>         if (ret)
>                 goto out;
>
> @@ -723,7 +725,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
>                  * right away and we therefore have to clflush anyway. */
>                 if (obj->cache_level == I915_CACHE_NONE)
>                         needs_clflush_after = 1;
> -               if (i915_gem_obj_ggtt_bound(obj)) {
> +               if (i915_gem_obj_bound_any(obj)) {
>                         ret = i915_gem_object_set_to_gtt_domain(obj, true);
>                         if (ret)
>                                 return ret;
> @@ -1332,7 +1334,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
>         }
>
>         /* Now bind it into the GTT if needed */
> -       ret = i915_gem_object_pin(obj, 0, true, false);
> +       ret = i915_gem_ggtt_pin(obj,  0, true, false);
>         if (ret)
>                 goto unlock;
>
> @@ -1654,11 +1656,11 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
>         if (obj->pages == NULL)
>                 return 0;
>
> -       BUG_ON(i915_gem_obj_ggtt_bound(obj));
> -
>         if (obj->pages_pin_count)
>                 return -EBUSY;
>
> +       BUG_ON(i915_gem_obj_bound_any(obj));
> +
>         /* ->put_pages might need to allocate memory for the bit17 swizzle
>          * array, hence protect them from being reaped by removing them from gtt
>          * lists early. */
> @@ -1678,7 +1680,6 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
>                   bool purgeable_only)
>  {
>         struct drm_i915_gem_object *obj, *next;
> -       struct i915_address_space *vm = &dev_priv->gtt.base;
>         long count = 0;
>
>         list_for_each_entry_safe(obj, next,
> @@ -1692,14 +1693,22 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
>                 }
>         }
>
> -       list_for_each_entry_safe(obj, next, &vm->inactive_list, mm_list) {
> -               if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) &&
> -                   i915_gem_object_unbind(obj) == 0 &&
> -                   i915_gem_object_put_pages(obj) == 0) {
> +       list_for_each_entry_safe(obj, next, &dev_priv->mm.bound_list,
> +                                global_list) {
> +               struct i915_vma *vma, *v;
> +
> +               if (!i915_gem_object_is_purgeable(obj) && purgeable_only)
> +                       continue;
> +
> +               list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link)
> +                       if (i915_gem_object_unbind(obj, vma->vm))
> +                               break;
> +
> +               if (!i915_gem_object_put_pages(obj))
>                         count += obj->base.size >> PAGE_SHIFT;
> -                       if (count >= target)
> -                               return count;
> -               }
> +
> +               if (count >= target)
> +                       return count;
>         }
>
>         return count;
> @@ -1859,11 +1868,11 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
>
>  void
>  i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
> +                              struct i915_address_space *vm,
>                                struct intel_ring_buffer *ring)
>  {
>         struct drm_device *dev = obj->base.dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> -       struct i915_address_space *vm = &dev_priv->gtt.base;
>         u32 seqno = intel_ring_get_seqno(ring);
>
>         BUG_ON(ring == NULL);
> @@ -1900,12 +1909,9 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
>  }
>
>  static void
> -i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
> +i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj,
> +                                struct i915_address_space *vm)
>  {
> -       struct drm_device *dev = obj->base.dev;
> -       struct drm_i915_private *dev_priv = dev->dev_private;
> -       struct i915_address_space *vm = &dev_priv->gtt.base;
> -
>         BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
>         BUG_ON(!obj->active);
>
> @@ -2105,10 +2111,11 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
>         spin_unlock(&file_priv->mm.lock);
>  }
>
> -static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj)
> +static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj,
> +                                   struct i915_address_space *vm)
>  {
> -       if (acthd >= i915_gem_obj_ggtt_offset(obj) &&
> -           acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size)
> +       if (acthd >= i915_gem_obj_offset(obj, vm) &&
> +           acthd < i915_gem_obj_offset(obj, vm) + obj->base.size)
>                 return true;
>
>         return false;
> @@ -2131,6 +2138,17 @@ static bool i915_head_inside_request(const u32 acthd_unmasked,
>         return false;
>  }
>
> +static struct i915_address_space *
> +request_to_vm(struct drm_i915_gem_request *request)
> +{
> +       struct drm_i915_private *dev_priv = request->ring->dev->dev_private;
> +       struct i915_address_space *vm;
> +
> +       vm = &dev_priv->gtt.base;
> +
> +       return vm;
> +}
> +
>  static bool i915_request_guilty(struct drm_i915_gem_request *request,
>                                 const u32 acthd, bool *inside)
>  {
> @@ -2138,9 +2156,9 @@ static bool i915_request_guilty(struct drm_i915_gem_request *request,
>          * pointing inside the ring, matches the batch_obj address range.
>          * However this is extremely unlikely.
>          */
> -
>         if (request->batch_obj) {
> -               if (i915_head_inside_object(acthd, request->batch_obj)) {
> +               if (i915_head_inside_object(acthd, request->batch_obj,
> +                                           request_to_vm(request))) {
>                         *inside = true;
>                         return true;
>                 }
> @@ -2160,17 +2178,21 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring,
>  {
>         struct i915_ctx_hang_stats *hs = NULL;
>         bool inside, guilty;
> +       unsigned long offset = 0;
>
>         /* Innocent until proven guilty */
>         guilty = false;
>
> +       if (request->batch_obj)
> +               offset = i915_gem_obj_offset(request->batch_obj,
> +                                            request_to_vm(request));
> +
>         if (ring->hangcheck.action != wait &&
>             i915_request_guilty(request, acthd, &inside)) {
>                 DRM_ERROR("%s hung %s bo (0x%lx ctx %d) at 0x%x\n",
>                           ring->name,
>                           inside ? "inside" : "flushing",
> -                         request->batch_obj ?
> -                         i915_gem_obj_ggtt_offset(request->batch_obj) : 0,
> +                         offset,
>                           request->ctx ? request->ctx->id : 0,
>                           acthd);
>
> @@ -2227,13 +2249,15 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
>         }
>
>         while (!list_empty(&ring->active_list)) {
> +               struct i915_address_space *vm;
>                 struct drm_i915_gem_object *obj;
>
>                 obj = list_first_entry(&ring->active_list,
>                                        struct drm_i915_gem_object,
>                                        ring_list);
>
> -               i915_gem_object_move_to_inactive(obj);
> +               list_for_each_entry(vm, &dev_priv->vm_list, global_link)
> +                       i915_gem_object_move_to_inactive(obj, vm);
>         }
>  }
>
> @@ -2261,7 +2285,7 @@ void i915_gem_restore_fences(struct drm_device *dev)
>  void i915_gem_reset(struct drm_device *dev)
>  {
>         struct drm_i915_private *dev_priv = dev->dev_private;
> -       struct i915_address_space *vm = &dev_priv->gtt.base;
> +       struct i915_address_space *vm;
>         struct drm_i915_gem_object *obj;
>         struct intel_ring_buffer *ring;
>         int i;
> @@ -2272,8 +2296,9 @@ void i915_gem_reset(struct drm_device *dev)
>         /* Move everything out of the GPU domains to ensure we do any
>          * necessary invalidation upon reuse.
>          */
> -       list_for_each_entry(obj, &vm->inactive_list, mm_list)
> -               obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
> +       list_for_each_entry(vm, &dev_priv->vm_list, global_link)
> +               list_for_each_entry(obj, &vm->inactive_list, mm_list)
> +                       obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
>
>         i915_gem_restore_fences(dev);
>  }
> @@ -2318,6 +2343,8 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
>          * by the ringbuffer to the flushing/inactive lists as appropriate.
>          */
>         while (!list_empty(&ring->active_list)) {
> +               struct drm_i915_private *dev_priv = ring->dev->dev_private;
> +               struct i915_address_space *vm;
>                 struct drm_i915_gem_object *obj;
>
>                 obj = list_first_entry(&ring->active_list,
> @@ -2327,7 +2354,8 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
>                 if (!i915_seqno_passed(seqno, obj->last_read_seqno))
>                         break;
>
> -               i915_gem_object_move_to_inactive(obj);
> +               list_for_each_entry(vm, &dev_priv->vm_list, global_link)
> +                       i915_gem_object_move_to_inactive(obj, vm);
>         }
>
>         if (unlikely(ring->trace_irq_seqno &&
> @@ -2573,13 +2601,14 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj)
>   * Unbinds an object from the GTT aperture.
>   */
>  int
> -i915_gem_object_unbind(struct drm_i915_gem_object *obj)
> +i915_gem_object_unbind(struct drm_i915_gem_object *obj,
> +                      struct i915_address_space *vm)
>  {
>         drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
>         struct i915_vma *vma;
>         int ret;
>
> -       if (!i915_gem_obj_ggtt_bound(obj))
> +       if (!i915_gem_obj_bound(obj, vm))
>                 return 0;
>
>         if (obj->pin_count)
> @@ -2602,7 +2631,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
>         if (ret)
>                 return ret;
>
> -       trace_i915_gem_object_unbind(obj);
> +       trace_i915_gem_object_unbind(obj, vm);
>
>         if (obj->has_global_gtt_mapping)
>                 i915_gem_gtt_unbind_object(obj);
> @@ -2617,7 +2646,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
>         /* Avoid an unnecessary call to unbind on rebind. */
>         obj->map_and_fenceable = true;
>
> -       vma = __i915_gem_obj_to_vma(obj);
> +       vma = i915_gem_obj_to_vma(obj, vm);
>         list_del(&vma->vma_link);
>         drm_mm_remove_node(&vma->node);
>         i915_gem_vma_destroy(vma);
> @@ -2764,6 +2793,7 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg,
>                      "object 0x%08lx not 512K or pot-size 0x%08x aligned\n",
>                      i915_gem_obj_ggtt_offset(obj), size);
>
> +
>                 pitch_val = obj->stride / 128;
>                 pitch_val = ffs(pitch_val) - 1;
>
> @@ -3049,24 +3079,26 @@ static void i915_gem_verify_gtt(struct drm_device *dev)
>   * Finds free space in the GTT aperture and binds the object there.
>   */
>  static int
> -i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
> -                           unsigned alignment,
> -                           bool map_and_fenceable,
> -                           bool nonblocking)
> +i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
> +                          struct i915_address_space *vm,
> +                          unsigned alignment,
> +                          bool map_and_fenceable,
> +                          bool nonblocking)
>  {
>         struct drm_device *dev = obj->base.dev;
>         drm_i915_private_t *dev_priv = dev->dev_private;
> -       struct i915_address_space *vm = &dev_priv->gtt.base;
>         u32 size, fence_size, fence_alignment, unfenced_alignment;
>         bool mappable, fenceable;
> -       size_t gtt_max = map_and_fenceable ?
> -               dev_priv->gtt.mappable_end : dev_priv->gtt.base.total;
> +       size_t gtt_max =
> +               map_and_fenceable ? dev_priv->gtt.mappable_end : vm->total;
>         struct i915_vma *vma;
>         int ret;
>
>         if (WARN_ON(!list_empty(&obj->vma_list)))
>                 return -EBUSY;
>
> +       BUG_ON(!i915_is_ggtt(vm));
> +
>         fence_size = i915_gem_get_gtt_size(dev,
>                                            obj->base.size,
>                                            obj->tiling_mode);
> @@ -3105,19 +3137,21 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
>
>         i915_gem_object_pin_pages(obj);
>
> -       vma = i915_gem_vma_create(obj, &dev_priv->gtt.base);
> +       /* For now we only ever use 1 vma per object */
> +       WARN_ON(!list_empty(&obj->vma_list));
> +
> +       vma = i915_gem_vma_create(obj, vm);
>         if (IS_ERR(vma)) {
>                 i915_gem_object_unpin_pages(obj);
>                 return PTR_ERR(vma);
>         }
>
>  search_free:
> -       ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm,
> -                                                 &vma->node,
> +       ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
>                                                   size, alignment,
>                                                   obj->cache_level, 0, gtt_max);
>         if (ret) {
> -               ret = i915_gem_evict_something(dev, size, alignment,
> +               ret = i915_gem_evict_something(dev, vm, size, alignment,
>                                                obj->cache_level,
>                                                map_and_fenceable,
>                                                nonblocking);
> @@ -3138,18 +3172,25 @@ search_free:
>
>         list_move_tail(&obj->global_list, &dev_priv->mm.bound_list);
>         list_add_tail(&obj->mm_list, &vm->inactive_list);
> -       list_add(&vma->vma_link, &obj->vma_list);
> +
> +       /* Keep GGTT vmas first to make debug easier */
> +       if (i915_is_ggtt(vm))
> +               list_add(&vma->vma_link, &obj->vma_list);
> +       else
> +               list_add_tail(&vma->vma_link, &obj->vma_list);
>
>         fenceable =
> +               i915_is_ggtt(vm) &&
>                 i915_gem_obj_ggtt_size(obj) == fence_size &&
>                 (i915_gem_obj_ggtt_offset(obj) & (fence_alignment - 1)) == 0;
>
> -       mappable = i915_gem_obj_ggtt_offset(obj) + obj->base.size <=
> -               dev_priv->gtt.mappable_end;
> +       mappable =
> +               i915_is_ggtt(vm) &&
> +               vma->node.start + obj->base.size <= dev_priv->gtt.mappable_end;
>
>         obj->map_and_fenceable = mappable && fenceable;
>
> -       trace_i915_gem_object_bind(obj, map_and_fenceable);
> +       trace_i915_gem_object_bind(obj, vm, map_and_fenceable);
>         i915_gem_verify_gtt(dev);
>         return 0;
>
> @@ -3253,7 +3294,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
>         int ret;
>
>         /* Not valid to be called on unbound objects. */
> -       if (!i915_gem_obj_ggtt_bound(obj))
> +       if (!i915_gem_obj_bound_any(obj))
>                 return -EINVAL;
>
>         if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
> @@ -3299,11 +3340,12 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
>  }
>
>  int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
> +                                   struct i915_address_space *vm,
>                                     enum i915_cache_level cache_level)
>  {
>         struct drm_device *dev = obj->base.dev;
>         drm_i915_private_t *dev_priv = dev->dev_private;
> -       struct i915_vma *vma = __i915_gem_obj_to_vma(obj);
> +       struct i915_vma *vma = i915_gem_obj_to_vma(obj, vm);
>         int ret;
>
>         if (obj->cache_level == cache_level)
> @@ -3315,12 +3357,12 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
>         }
>
>         if (vma && !i915_gem_valid_gtt_space(dev, &vma->node, cache_level)) {
> -               ret = i915_gem_object_unbind(obj);
> +               ret = i915_gem_object_unbind(obj, vm);
>                 if (ret)
>                         return ret;
>         }
>
> -       if (i915_gem_obj_ggtt_bound(obj)) {
> +       list_for_each_entry(vma, &obj->vma_list, vma_link) {
>                 ret = i915_gem_object_finish_gpu(obj);
>                 if (ret)
>                         return ret;
> @@ -3343,7 +3385,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
>                         i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
>                                                obj, cache_level);
>
> -               i915_gem_obj_ggtt_set_color(obj, cache_level);
> +               i915_gem_obj_set_color(obj, vma->vm, cache_level);
>         }
>
>         if (cache_level == I915_CACHE_NONE) {
> @@ -3403,6 +3445,7 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
>                                struct drm_file *file)
>  {
>         struct drm_i915_gem_caching *args = data;
> +       struct drm_i915_private *dev_priv;
>         struct drm_i915_gem_object *obj;
>         enum i915_cache_level level;
>         int ret;
> @@ -3427,8 +3470,10 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
>                 ret = -ENOENT;
>                 goto unlock;
>         }
> +       dev_priv = obj->base.dev->dev_private;
>
> -       ret = i915_gem_object_set_cache_level(obj, level);
> +       /* FIXME: Add interface for specific VM? */
> +       ret = i915_gem_object_set_cache_level(obj, &dev_priv->gtt.base, level);
>
>         drm_gem_object_unreference(&obj->base);
>  unlock:
> @@ -3446,6 +3491,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
>                                      u32 alignment,
>                                      struct intel_ring_buffer *pipelined)
>  {
> +       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
>         u32 old_read_domains, old_write_domain;
>         int ret;
>
> @@ -3464,7 +3510,8 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
>          * of uncaching, which would allow us to flush all the LLC-cached data
>          * with that bit in the PTE to main memory with just one PIPE_CONTROL.
>          */
> -       ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE);
> +       ret = i915_gem_object_set_cache_level(obj, &dev_priv->gtt.base,
> +                                             I915_CACHE_NONE);
>         if (ret)
>                 return ret;
>
> @@ -3472,7 +3519,7 @@ 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_object_pin(obj, alignment, true, false);
> +       ret = i915_gem_ggtt_pin(obj, alignment, true, false);
>         if (ret)
>                 return ret;
>
> @@ -3615,6 +3662,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
>
>  int
>  i915_gem_object_pin(struct drm_i915_gem_object *obj,
> +                   struct i915_address_space *vm,
>                     uint32_t alignment,
>                     bool map_and_fenceable,
>                     bool nonblocking)
> @@ -3624,28 +3672,31 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
>         if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
>                 return -EBUSY;
>
> -       if (i915_gem_obj_ggtt_bound(obj)) {
> -               if ((alignment && i915_gem_obj_ggtt_offset(obj) & (alignment - 1)) ||
> +       WARN_ON(map_and_fenceable && !i915_is_ggtt(vm));
> +
> +       if (i915_gem_obj_bound(obj, vm)) {
> +               if ((alignment &&
> +                    i915_gem_obj_offset(obj, vm) & (alignment - 1)) ||
>                     (map_and_fenceable && !obj->map_and_fenceable)) {
>                         WARN(obj->pin_count,
>                              "bo is already pinned with incorrect alignment:"
>                              " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
>                              " obj->map_and_fenceable=%d\n",
> -                            i915_gem_obj_ggtt_offset(obj), alignment,
> +                            i915_gem_obj_offset(obj, vm), alignment,
>                              map_and_fenceable,
>                              obj->map_and_fenceable);
> -                       ret = i915_gem_object_unbind(obj);
> +                       ret = i915_gem_object_unbind(obj, vm);
>                         if (ret)
>                                 return ret;
>                 }
>         }
>
> -       if (!i915_gem_obj_ggtt_bound(obj)) {
> +       if (!i915_gem_obj_bound(obj, vm)) {
>                 struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
>
> -               ret = i915_gem_object_bind_to_gtt(obj, alignment,
> -                                                 map_and_fenceable,
> -                                                 nonblocking);
> +               ret = i915_gem_object_bind_to_vm(obj, vm, alignment,
> +                                                map_and_fenceable,
> +                                                nonblocking);
>                 if (ret)
>                         return ret;
>
> @@ -3666,7 +3717,7 @@ void
>  i915_gem_object_unpin(struct drm_i915_gem_object *obj)
>  {
>         BUG_ON(obj->pin_count == 0);
> -       BUG_ON(!i915_gem_obj_ggtt_bound(obj));
> +       BUG_ON(!i915_gem_obj_bound_any(obj));
>
>         if (--obj->pin_count == 0)
>                 obj->pin_mappable = false;
> @@ -3704,7 +3755,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
>         }
>
>         if (obj->user_pin_count == 0) {
> -               ret = i915_gem_object_pin(obj, args->alignment, true, false);
> +               ret = i915_gem_ggtt_pin(obj, args->alignment, true, false);
>                 if (ret)
>                         goto out;
>         }
> @@ -3937,6 +3988,7 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
>         struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
>         struct drm_device *dev = obj->base.dev;
>         drm_i915_private_t *dev_priv = dev->dev_private;
> +       struct i915_vma *vma, *next;
>
>         trace_i915_gem_object_destroy(obj);
>
> @@ -3944,15 +3996,21 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
>                 i915_gem_detach_phys_object(dev, obj);
>
>         obj->pin_count = 0;
> -       if (WARN_ON(i915_gem_object_unbind(obj) == -ERESTARTSYS)) {
> -               bool was_interruptible;
> +       /* NB: 0 or 1 elements */
> +       WARN_ON(!list_empty(&obj->vma_list) &&
> +               !list_is_singular(&obj->vma_list));
> +       list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) {
> +               int ret = i915_gem_object_unbind(obj, vma->vm);
> +               if (WARN_ON(ret == -ERESTARTSYS)) {
> +                       bool was_interruptible;
>
> -               was_interruptible = dev_priv->mm.interruptible;
> -               dev_priv->mm.interruptible = false;
> +                       was_interruptible = dev_priv->mm.interruptible;
> +                       dev_priv->mm.interruptible = false;
>
> -               WARN_ON(i915_gem_object_unbind(obj));
> +                       WARN_ON(i915_gem_object_unbind(obj, vma->vm));
>
> -               dev_priv->mm.interruptible = was_interruptible;
> +                       dev_priv->mm.interruptible = was_interruptible;
> +               }
>         }
>
>         /* Stolen objects don't hold a ref, but do hold pin count. Fix that up
> @@ -4319,6 +4377,16 @@ init_ring_lists(struct intel_ring_buffer *ring)
>         INIT_LIST_HEAD(&ring->request_list);
>  }
>
> +static void i915_init_vm(struct drm_i915_private *dev_priv,
> +                        struct i915_address_space *vm)
> +{
> +       vm->dev = dev_priv->dev;
> +       INIT_LIST_HEAD(&vm->active_list);
> +       INIT_LIST_HEAD(&vm->inactive_list);
> +       INIT_LIST_HEAD(&vm->global_link);
> +       list_add(&vm->global_link, &dev_priv->vm_list);
> +}
> +
>  void
>  i915_gem_load(struct drm_device *dev)
>  {
> @@ -4331,8 +4399,9 @@ i915_gem_load(struct drm_device *dev)
>                                   SLAB_HWCACHE_ALIGN,
>                                   NULL);
>
> -       INIT_LIST_HEAD(&dev_priv->gtt.base.active_list);
> -       INIT_LIST_HEAD(&dev_priv->gtt.base.inactive_list);
> +       INIT_LIST_HEAD(&dev_priv->vm_list);
> +       i915_init_vm(dev_priv, &dev_priv->gtt.base);
> +
>         INIT_LIST_HEAD(&dev_priv->mm.unbound_list);
>         INIT_LIST_HEAD(&dev_priv->mm.bound_list);
>         INIT_LIST_HEAD(&dev_priv->mm.fence_list);
> @@ -4603,9 +4672,8 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
>                              struct drm_i915_private,
>                              mm.inactive_shrinker);
>         struct drm_device *dev = dev_priv->dev;
> -       struct i915_address_space *vm = &dev_priv->gtt.base;
>         struct drm_i915_gem_object *obj;
> -       int nr_to_scan = sc->nr_to_scan;
> +       int nr_to_scan;
>         bool unlock = true;
>         int cnt;
>
> @@ -4619,6 +4687,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
>                 unlock = false;
>         }
>
> +       nr_to_scan = sc->nr_to_scan;
>         if (nr_to_scan) {
>                 nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan);
>                 if (nr_to_scan > 0)
> @@ -4632,11 +4701,109 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
>         list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
>                 if (obj->pages_pin_count == 0)
>                         cnt += obj->base.size >> PAGE_SHIFT;
> -       list_for_each_entry(obj, &vm->inactive_list, mm_list)
> +
> +       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
> +               if (obj->active)
> +                       continue;
> +
> +               i915_gem_object_flush_gtt_write_domain(obj);
> +               i915_gem_object_flush_cpu_write_domain(obj);
> +               /* FIXME: Can't assume global gtt */
> +               i915_gem_object_move_to_inactive(obj, &dev_priv->gtt.base);
> +
>                 if (obj->pin_count == 0 && obj->pages_pin_count == 0)
>                         cnt += obj->base.size >> PAGE_SHIFT;
> +       }
>
>         if (unlock)
>                 mutex_unlock(&dev->struct_mutex);
>         return cnt;
>  }
> +
> +/* All the new VM stuff */
> +unsigned long i915_gem_obj_offset(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;
> +
> +       if (vm == &dev_priv->mm.aliasing_ppgtt->base)
> +               vm = &dev_priv->gtt.base;
> +
> +       BUG_ON(list_empty(&o->vma_list));
> +       list_for_each_entry(vma, &o->vma_list, vma_link) {
> +               if (vma->vm == vm)
> +                       return vma->node.start;
> +
> +       }
> +       return -1;
> +}
> +
> +bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
> +                       struct i915_address_space *vm)
> +{
> +       struct i915_vma *vma;
> +
> +       list_for_each_entry(vma, &o->vma_list, vma_link)
> +               if (vma->vm == vm)
> +                       return true;
> +
> +       return false;
> +}
> +
> +bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o)
> +{
> +       struct drm_i915_private *dev_priv = o->base.dev->dev_private;
> +       struct i915_address_space *vm;
> +
> +       list_for_each_entry(vm, &dev_priv->vm_list, global_link)
> +               if (i915_gem_obj_bound(o, vm))
> +                       return true;
> +
> +       return false;
> +}
> +
> +unsigned long i915_gem_obj_size(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;
> +
> +       if (vm == &dev_priv->mm.aliasing_ppgtt->base)
> +               vm = &dev_priv->gtt.base;
> +
> +       BUG_ON(list_empty(&o->vma_list));
> +
> +       list_for_each_entry(vma, &o->vma_list, vma_link)
> +               if (vma->vm == vm)
> +                       return vma->node.size;
> +
> +       return 0;
> +}
> +
> +void i915_gem_obj_set_color(struct drm_i915_gem_object *o,
> +                           struct i915_address_space *vm,
> +                           enum i915_cache_level color)
> +{
> +       struct i915_vma *vma;
> +       BUG_ON(list_empty(&o->vma_list));
> +       list_for_each_entry(vma, &o->vma_list, vma_link) {
> +               if (vma->vm == vm) {
> +                       vma->node.color = color;
> +                       return;
> +               }
> +       }
> +
> +       WARN(1, "Couldn't set color for VM %p\n", vm);
> +}
> +
> +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)
> +                       return vma;
> +
> +       return NULL;
> +}
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
> index 2470206..873577d 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -155,6 +155,7 @@ create_hw_context(struct drm_device *dev,
>
>         if (INTEL_INFO(dev)->gen >= 7) {
>                 ret = i915_gem_object_set_cache_level(ctx->obj,
> +                                                     &dev_priv->gtt.base,
>                                                       I915_CACHE_LLC_MLC);
>                 /* Failure shouldn't ever happen this early */
>                 if (WARN_ON(ret))
> @@ -214,7 +215,7 @@ static int create_default_context(struct drm_i915_private *dev_priv)
>          * default context.
>          */
>         dev_priv->ring[RCS].default_context = ctx;
> -       ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false, false);
> +       ret = i915_gem_ggtt_pin(ctx->obj, CONTEXT_ALIGN, false, false);
>         if (ret) {
>                 DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret);
>                 goto err_destroy;
> @@ -391,6 +392,7 @@ mi_set_context(struct intel_ring_buffer *ring,
>  static int do_switch(struct i915_hw_context *to)
>  {
>         struct intel_ring_buffer *ring = to->ring;
> +       struct drm_i915_private *dev_priv = ring->dev->dev_private;
>         struct i915_hw_context *from = ring->last_context;
>         u32 hw_flags = 0;
>         int ret;
> @@ -400,7 +402,7 @@ static int do_switch(struct i915_hw_context *to)
>         if (from == to)
>                 return 0;
>
> -       ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false, false);
> +       ret = i915_gem_ggtt_pin(to->obj, CONTEXT_ALIGN, false, false);
>         if (ret)
>                 return ret;
>
> @@ -437,7 +439,8 @@ static int do_switch(struct i915_hw_context *to)
>          */
>         if (from != NULL) {
>                 from->obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
> -               i915_gem_object_move_to_active(from->obj, ring);
> +               i915_gem_object_move_to_active(from->obj, &dev_priv->gtt.base,
> +                                              ring);
>                 /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the
>                  * whole damn pipeline, we don't need to explicitly mark the
>                  * object dirty. The only exception is that the context must be
> diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
> index df61f33..32efdc0 100644
> --- a/drivers/gpu/drm/i915/i915_gem_evict.c
> +++ b/drivers/gpu/drm/i915/i915_gem_evict.c
> @@ -32,24 +32,21 @@
>  #include "i915_trace.h"
>
>  static bool
> -mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind)
> +mark_free(struct i915_vma *vma, struct list_head *unwind)
>  {
> -       struct i915_vma *vma = __i915_gem_obj_to_vma(obj);
> -
> -       if (obj->pin_count)
> +       if (vma->obj->pin_count)
>                 return false;
>
> -       list_add(&obj->exec_list, unwind);
> +       list_add(&vma->obj->exec_list, unwind);
>         return drm_mm_scan_add_block(&vma->node);
>  }
>
>  int
> -i915_gem_evict_something(struct drm_device *dev, int min_size,
> -                        unsigned alignment, unsigned cache_level,
> +i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm,
> +                        int min_size, unsigned alignment, unsigned cache_level,
>                          bool mappable, bool nonblocking)
>  {
>         drm_i915_private_t *dev_priv = dev->dev_private;
> -       struct i915_address_space *vm = &dev_priv->gtt.base;
>         struct list_head eviction_list, unwind_list;
>         struct i915_vma *vma;
>         struct drm_i915_gem_object *obj;
> @@ -81,16 +78,18 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
>          */
>
>         INIT_LIST_HEAD(&unwind_list);
> -       if (mappable)
> +       if (mappable) {
> +               BUG_ON(!i915_is_ggtt(vm));
>                 drm_mm_init_scan_with_range(&vm->mm, min_size,
>                                             alignment, cache_level, 0,
>                                             dev_priv->gtt.mappable_end);
> -       else
> +       } else
>                 drm_mm_init_scan(&vm->mm, min_size, alignment, cache_level);
>
>         /* First see if there is a large enough contiguous idle region... */
>         list_for_each_entry(obj, &vm->inactive_list, mm_list) {
> -               if (mark_free(obj, &unwind_list))
> +               struct i915_vma *vma = i915_gem_obj_to_vma(obj, vm);
> +               if (mark_free(vma, &unwind_list))
>                         goto found;
>         }
>
> @@ -99,7 +98,8 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
>
>         /* Now merge in the soon-to-be-expired objects... */
>         list_for_each_entry(obj, &vm->active_list, mm_list) {
> -               if (mark_free(obj, &unwind_list))
> +               struct i915_vma *vma = i915_gem_obj_to_vma(obj, vm);
> +               if (mark_free(vma, &unwind_list))
>                         goto found;
>         }
>
> @@ -109,7 +109,7 @@ none:
>                 obj = list_first_entry(&unwind_list,
>                                        struct drm_i915_gem_object,
>                                        exec_list);
> -               vma = __i915_gem_obj_to_vma(obj);
> +               vma = i915_gem_obj_to_vma(obj, vm);
>                 ret = drm_mm_scan_remove_block(&vma->node);
>                 BUG_ON(ret);
>
> @@ -130,7 +130,7 @@ found:
>                 obj = list_first_entry(&unwind_list,
>                                        struct drm_i915_gem_object,
>                                        exec_list);
> -               vma = __i915_gem_obj_to_vma(obj);
> +               vma = i915_gem_obj_to_vma(obj, vm);
>                 if (drm_mm_scan_remove_block(&vma->node)) {
>                         list_move(&obj->exec_list, &eviction_list);
>                         drm_gem_object_reference(&obj->base);
> @@ -145,7 +145,7 @@ found:
>                                        struct drm_i915_gem_object,
>                                        exec_list);
>                 if (ret == 0)
> -                       ret = i915_gem_object_unbind(obj);
> +                       ret = i915_gem_object_unbind(obj, vm);
>
>                 list_del_init(&obj->exec_list);
>                 drm_gem_object_unreference(&obj->base);
> @@ -158,13 +158,18 @@ int
>  i915_gem_evict_everything(struct drm_device *dev)
>  {
>         drm_i915_private_t *dev_priv = dev->dev_private;
> -       struct i915_address_space *vm = &dev_priv->gtt.base;
> +       struct i915_address_space *vm;
>         struct drm_i915_gem_object *obj, *next;
> -       bool lists_empty;
> +       bool lists_empty = true;
>         int ret;
>
> -       lists_empty = (list_empty(&vm->inactive_list) &&
> -                      list_empty(&vm->active_list));
> +       list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
> +               lists_empty = (list_empty(&vm->inactive_list) &&
> +                              list_empty(&vm->active_list));
> +               if (!lists_empty)
> +                       lists_empty = false;
> +       }
> +
>         if (lists_empty)
>                 return -ENOSPC;
>
> @@ -181,9 +186,11 @@ i915_gem_evict_everything(struct drm_device *dev)
>         i915_gem_retire_requests(dev);
>
>         /* Having flushed everything, unbind() should never raise an error */
> -       list_for_each_entry_safe(obj, next, &vm->inactive_list, mm_list)
> -               if (obj->pin_count == 0)
> -                       WARN_ON(i915_gem_object_unbind(obj));
> +       list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
> +               list_for_each_entry_safe(obj, next, &vm->inactive_list, mm_list)
> +                       if (obj->pin_count == 0)
> +                               WARN_ON(i915_gem_object_unbind(obj, vm));
> +       }
>
>         return 0;
>  }
> diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> index 1734825..819d8d8 100644
> --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> @@ -150,7 +150,7 @@ eb_get_object(struct eb_objects *eb, unsigned long handle)
>  }
>
>  static void
> -eb_destroy(struct eb_objects *eb)
> +eb_destroy(struct eb_objects *eb, struct i915_address_space *vm)
>  {
>         while (!list_empty(&eb->objects)) {
>                 struct drm_i915_gem_object *obj;
> @@ -174,7 +174,8 @@ static inline int use_cpu_reloc(struct drm_i915_gem_object *obj)
>  static int
>  i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
>                                    struct eb_objects *eb,
> -                                  struct drm_i915_gem_relocation_entry *reloc)
> +                                  struct drm_i915_gem_relocation_entry *reloc,
> +                                  struct i915_address_space *vm)
>  {
>         struct drm_device *dev = obj->base.dev;
>         struct drm_gem_object *target_obj;
> @@ -297,7 +298,8 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
>
>  static int
>  i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
> -                                   struct eb_objects *eb)
> +                                   struct eb_objects *eb,
> +                                   struct i915_address_space *vm)
>  {
>  #define N_RELOC(x) ((x) / sizeof(struct drm_i915_gem_relocation_entry))
>         struct drm_i915_gem_relocation_entry stack_reloc[N_RELOC(512)];
> @@ -321,7 +323,8 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
>                 do {
>                         u64 offset = r->presumed_offset;
>
> -                       ret = i915_gem_execbuffer_relocate_entry(obj, eb, r);
> +                       ret = i915_gem_execbuffer_relocate_entry(obj, eb, r,
> +                                                                vm);
>                         if (ret)
>                                 return ret;
>
> @@ -344,13 +347,15 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
>  static int
>  i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
>                                          struct eb_objects *eb,
> -                                        struct drm_i915_gem_relocation_entry *relocs)
> +                                        struct drm_i915_gem_relocation_entry *relocs,
> +                                        struct i915_address_space *vm)
>  {
>         const struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
>         int i, ret;
>
>         for (i = 0; i < entry->relocation_count; i++) {
> -               ret = i915_gem_execbuffer_relocate_entry(obj, eb, &relocs[i]);
> +               ret = i915_gem_execbuffer_relocate_entry(obj, eb, &relocs[i],
> +                                                        vm);
>                 if (ret)
>                         return ret;
>         }
> @@ -359,7 +364,8 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
>  }
>
>  static int
> -i915_gem_execbuffer_relocate(struct eb_objects *eb)
> +i915_gem_execbuffer_relocate(struct eb_objects *eb,
> +                            struct i915_address_space *vm)
>  {
>         struct drm_i915_gem_object *obj;
>         int ret = 0;
> @@ -373,7 +379,7 @@ i915_gem_execbuffer_relocate(struct eb_objects *eb)
>          */
>         pagefault_disable();
>         list_for_each_entry(obj, &eb->objects, exec_list) {
> -               ret = i915_gem_execbuffer_relocate_object(obj, eb);
> +               ret = i915_gem_execbuffer_relocate_object(obj, eb, vm);
>                 if (ret)
>                         break;
>         }
> @@ -395,6 +401,7 @@ need_reloc_mappable(struct drm_i915_gem_object *obj)
>  static int
>  i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj,
>                                    struct intel_ring_buffer *ring,
> +                                  struct i915_address_space *vm,
>                                    bool *need_reloc)
>  {
>         struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
> @@ -409,7 +416,8 @@ i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj,
>                 obj->tiling_mode != I915_TILING_NONE;
>         need_mappable = need_fence || need_reloc_mappable(obj);
>
> -       ret = i915_gem_object_pin(obj, entry->alignment, need_mappable, false);
> +       ret = i915_gem_object_pin(obj, vm, entry->alignment, need_mappable,
> +                                 false);
>         if (ret)
>                 return ret;
>
> @@ -436,8 +444,8 @@ i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj,
>                 obj->has_aliasing_ppgtt_mapping = 1;
>         }
>
> -       if (entry->offset != i915_gem_obj_ggtt_offset(obj)) {
> -               entry->offset = i915_gem_obj_ggtt_offset(obj);
> +       if (entry->offset != i915_gem_obj_offset(obj, vm)) {
> +               entry->offset = i915_gem_obj_offset(obj, vm);
>                 *need_reloc = true;
>         }
>
> @@ -458,7 +466,7 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj)
>  {
>         struct drm_i915_gem_exec_object2 *entry;
>
> -       if (!i915_gem_obj_ggtt_bound(obj))
> +       if (!i915_gem_obj_bound_any(obj))
>                 return;
>
>         entry = obj->exec_entry;
> @@ -475,6 +483,7 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj)
>  static int
>  i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
>                             struct list_head *objects,
> +                           struct i915_address_space *vm,
>                             bool *need_relocs)
>  {
>         struct drm_i915_gem_object *obj;
> @@ -529,32 +538,37 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
>                 list_for_each_entry(obj, objects, exec_list) {
>                         struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
>                         bool need_fence, need_mappable;
> +                       u32 obj_offset;
>
> -                       if (!i915_gem_obj_ggtt_bound(obj))
> +                       if (!i915_gem_obj_bound(obj, vm))
>                                 continue;
>
> +                       obj_offset = i915_gem_obj_offset(obj, vm);
>                         need_fence =
>                                 has_fenced_gpu_access &&
>                                 entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
>                                 obj->tiling_mode != I915_TILING_NONE;
>                         need_mappable = need_fence || need_reloc_mappable(obj);
>
> +                       BUG_ON((need_mappable || need_fence) &&
> +                              !i915_is_ggtt(vm));
> +
>                         if ((entry->alignment &&
> -                            i915_gem_obj_ggtt_offset(obj) & (entry->alignment - 1)) ||
> +                            obj_offset & (entry->alignment - 1)) ||
>                             (need_mappable && !obj->map_and_fenceable))
> -                               ret = i915_gem_object_unbind(obj);
> +                               ret = i915_gem_object_unbind(obj, vm);
>                         else
> -                               ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs);
> +                               ret = i915_gem_execbuffer_reserve_object(obj, ring, vm, need_relocs);
>                         if (ret)
>                                 goto err;
>                 }
>
>                 /* Bind fresh objects */
>                 list_for_each_entry(obj, objects, exec_list) {
> -                       if (i915_gem_obj_ggtt_bound(obj))
> +                       if (i915_gem_obj_bound(obj, vm))
>                                 continue;
>
> -                       ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs);
> +                       ret = i915_gem_execbuffer_reserve_object(obj, ring, vm, need_relocs);
>                         if (ret)
>                                 goto err;
>                 }
> @@ -578,7 +592,8 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
>                                   struct drm_file *file,
>                                   struct intel_ring_buffer *ring,
>                                   struct eb_objects *eb,
> -                                 struct drm_i915_gem_exec_object2 *exec)
> +                                 struct drm_i915_gem_exec_object2 *exec,
> +                                 struct i915_address_space *vm)
>  {
>         struct drm_i915_gem_relocation_entry *reloc;
>         struct drm_i915_gem_object *obj;
> @@ -662,14 +677,15 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
>                 goto err;
>
>         need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0;
> -       ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs);
> +       ret = i915_gem_execbuffer_reserve(ring, &eb->objects, vm, &need_relocs);
>         if (ret)
>                 goto err;
>
>         list_for_each_entry(obj, &eb->objects, exec_list) {
>                 int offset = obj->exec_entry - exec;
>                 ret = i915_gem_execbuffer_relocate_object_slow(obj, eb,
> -                                                              reloc + reloc_offset[offset]);
> +                                                              reloc + reloc_offset[offset],
> +                                                              vm);
>                 if (ret)
>                         goto err;
>         }
> @@ -770,6 +786,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
>
>  static void
>  i915_gem_execbuffer_move_to_active(struct list_head *objects,
> +                                  struct i915_address_space *vm,
>                                    struct intel_ring_buffer *ring)
>  {
>         struct drm_i915_gem_object *obj;
> @@ -784,7 +801,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
>                 obj->base.read_domains = obj->base.pending_read_domains;
>                 obj->fenced_gpu_access = obj->pending_fenced_gpu_access;
>
> -               i915_gem_object_move_to_active(obj, ring);
> +               i915_gem_object_move_to_active(obj, vm, ring);
>                 if (obj->base.write_domain) {
>                         obj->dirty = 1;
>                         obj->last_write_seqno = intel_ring_get_seqno(ring);
> @@ -838,7 +855,8 @@ static int
>  i915_gem_do_execbuffer(struct drm_device *dev, void *data,
>                        struct drm_file *file,
>                        struct drm_i915_gem_execbuffer2 *args,
> -                      struct drm_i915_gem_exec_object2 *exec)
> +                      struct drm_i915_gem_exec_object2 *exec,
> +                      struct i915_address_space *vm)
>  {
>         drm_i915_private_t *dev_priv = dev->dev_private;
>         struct eb_objects *eb;
> @@ -1000,17 +1018,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
>
>         /* Move the objects en-masse into the GTT, evicting if necessary. */
>         need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0;
> -       ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs);
> +       ret = i915_gem_execbuffer_reserve(ring, &eb->objects, vm, &need_relocs);
>         if (ret)
>                 goto err;
>
>         /* The objects are in their final locations, apply the relocations. */
>         if (need_relocs)
> -               ret = i915_gem_execbuffer_relocate(eb);
> +               ret = i915_gem_execbuffer_relocate(eb, vm);
>         if (ret) {
>                 if (ret == -EFAULT) {
>                         ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring,
> -                                                               eb, exec);
> +                                                               eb, exec, vm);
>                         BUG_ON(!mutex_is_locked(&dev->struct_mutex));
>                 }
>                 if (ret)
> @@ -1061,7 +1079,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
>                         goto err;
>         }
>
> -       exec_start = i915_gem_obj_ggtt_offset(batch_obj) + args->batch_start_offset;
> +       exec_start = i915_gem_obj_offset(batch_obj, vm) +
> +               args->batch_start_offset;
>         exec_len = args->batch_len;
>         if (cliprects) {
>                 for (i = 0; i < args->num_cliprects; i++) {
> @@ -1086,11 +1105,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
>
>         trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags);
>
> -       i915_gem_execbuffer_move_to_active(&eb->objects, ring);
> +       i915_gem_execbuffer_move_to_active(&eb->objects, vm, ring);
>         i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
>
>  err:
> -       eb_destroy(eb);
> +       eb_destroy(eb, vm);
>
>         mutex_unlock(&dev->struct_mutex);
>
> @@ -1107,6 +1126,7 @@ int
>  i915_gem_execbuffer(struct drm_device *dev, void *data,
>                     struct drm_file *file)
>  {
> +       struct drm_i915_private *dev_priv = dev->dev_private;
>         struct drm_i915_gem_execbuffer *args = data;
>         struct drm_i915_gem_execbuffer2 exec2;
>         struct drm_i915_gem_exec_object *exec_list = NULL;
> @@ -1162,7 +1182,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
>         exec2.flags = I915_EXEC_RENDER;
>         i915_execbuffer2_set_context_id(exec2, 0);
>
> -       ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list);
> +       ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list,
> +                                    &dev_priv->gtt.base);
>         if (!ret) {
>                 /* Copy the new buffer offsets back to the user's exec list. */
>                 for (i = 0; i < args->buffer_count; i++)
> @@ -1188,6 +1209,7 @@ int
>  i915_gem_execbuffer2(struct drm_device *dev, void *data,
>                      struct drm_file *file)
>  {
> +       struct drm_i915_private *dev_priv = dev->dev_private;
>         struct drm_i915_gem_execbuffer2 *args = data;
>         struct drm_i915_gem_exec_object2 *exec2_list = NULL;
>         int ret;
> @@ -1218,7 +1240,8 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
>                 return -EFAULT;
>         }
>
> -       ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list);
> +       ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list,
> +                                    &dev_priv->gtt.base);
>         if (!ret) {
>                 /* Copy the new buffer offsets back to the user's exec list. */
>                 ret = copy_to_user(to_user_ptr(args->buffers_ptr),
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index 3b639a9..44f3464 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> @@ -390,6 +390,8 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
>                             ppgtt->base.total);
>         }
>
> +       /* i915_init_vm(dev_priv, &ppgtt->base) */
> +
>         return ret;
>  }
>
> @@ -409,17 +411,22 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
>                             struct drm_i915_gem_object *obj,
>                             enum i915_cache_level cache_level)
>  {
> -       ppgtt->base.insert_entries(&ppgtt->base, obj->pages,
> -                                  i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
> -                                  cache_level);
> +       struct i915_address_space *vm = &ppgtt->base;
> +       unsigned long obj_offset = i915_gem_obj_offset(obj, vm);
> +
> +       vm->insert_entries(vm, obj->pages,
> +                          obj_offset >> PAGE_SHIFT,
> +                          cache_level);
>  }
>
>  void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
>                               struct drm_i915_gem_object *obj)
>  {
> -       ppgtt->base.clear_range(&ppgtt->base,
> -                               i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
> -                               obj->base.size >> PAGE_SHIFT);
> +       struct i915_address_space *vm = &ppgtt->base;
> +       unsigned long obj_offset = i915_gem_obj_offset(obj, vm);
> +
> +       vm->clear_range(vm, obj_offset >> PAGE_SHIFT,
> +                       obj->base.size >> PAGE_SHIFT);
>  }
>
>  extern int intel_iommu_gfx_mapped;
> @@ -470,6 +477,9 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
>                                        dev_priv->gtt.base.start / PAGE_SIZE,
>                                        dev_priv->gtt.base.total / PAGE_SIZE);
>
> +       if (dev_priv->mm.aliasing_ppgtt)
> +               gen6_write_pdes(dev_priv->mm.aliasing_ppgtt);
> +
>         list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
>                 i915_gem_clflush_object(obj);
>                 i915_gem_gtt_bind_object(obj, obj->cache_level);
> @@ -648,7 +658,8 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
>          * aperture.  One page should be enough to keep any prefetching inside
>          * of the aperture.
>          */
> -       drm_i915_private_t *dev_priv = dev->dev_private;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       struct i915_address_space *ggtt_vm = &dev_priv->gtt.base;
>         struct drm_mm_node *entry;
>         struct drm_i915_gem_object *obj;
>         unsigned long hole_start, hole_end;
> @@ -656,19 +667,19 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
>         BUG_ON(mappable_end > end);
>
>         /* Subtract the guard page ... */
> -       drm_mm_init(&dev_priv->gtt.base.mm, start, end - start - PAGE_SIZE);
> +       drm_mm_init(&ggtt_vm->mm, start, end - start - PAGE_SIZE);
>         if (!HAS_LLC(dev))
>                 dev_priv->gtt.base.mm.color_adjust = i915_gtt_color_adjust;
>
>         /* Mark any preallocated objects as occupied */
>         list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
> -               struct i915_vma *vma = __i915_gem_obj_to_vma(obj);
> +               struct i915_vma *vma = i915_gem_obj_to_vma(obj, ggtt_vm);
>                 int ret;
>                 DRM_DEBUG_KMS("reserving preallocated space: %lx + %zx\n",
>                               i915_gem_obj_ggtt_offset(obj), obj->base.size);
>
>                 WARN_ON(i915_gem_obj_ggtt_bound(obj));
> -               ret = drm_mm_reserve_node(&dev_priv->gtt.base.mm, &vma->node);
> +               ret = drm_mm_reserve_node(&ggtt_vm->mm, &vma->node);
>                 if (ret)
>                         DRM_DEBUG_KMS("Reservation failed\n");
>                 obj->has_global_gtt_mapping = 1;
> @@ -679,19 +690,15 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
>         dev_priv->gtt.base.total = end - start;
>
>         /* Clear any non-preallocated blocks */
> -       drm_mm_for_each_hole(entry, &dev_priv->gtt.base.mm,
> -                            hole_start, hole_end) {
> +       drm_mm_for_each_hole(entry, &ggtt_vm->mm, hole_start, hole_end) {
>                 const unsigned long count = (hole_end - hole_start) / PAGE_SIZE;
>                 DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
>                               hole_start, hole_end);
> -               dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
> -                                              hole_start / PAGE_SIZE,
> -                                              count);
> +               ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count);
>         }
>
>         /* And finally clear the reserved guard page */
> -       dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
> -                                      end / PAGE_SIZE - 1, 1);
> +       ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1);
>  }
>
>  static bool
> diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
> index 27ffb4c..000ffbd 100644
> --- a/drivers/gpu/drm/i915/i915_gem_stolen.c
> +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
> @@ -351,7 +351,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
>                                                u32 size)
>  {
>         struct drm_i915_private *dev_priv = dev->dev_private;
> -       struct i915_address_space *vm = &dev_priv->gtt.base;
> +       struct i915_address_space *ggtt = &dev_priv->gtt.base;
>         struct drm_i915_gem_object *obj;
>         struct drm_mm_node *stolen;
>         struct i915_vma *vma;
> @@ -394,7 +394,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
>         if (gtt_offset == I915_GTT_OFFSET_NONE)
>                 return obj;
>
> -       vma = i915_gem_vma_create(obj, &dev_priv->gtt.base);
> +       vma = i915_gem_vma_create(obj, ggtt);
>         if (IS_ERR(vma)) {
>                 ret = PTR_ERR(vma);
>                 goto err_out;
> @@ -407,8 +407,8 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
>          */
>         vma->node.start = gtt_offset;
>         vma->node.size = size;
> -       if (drm_mm_initialized(&dev_priv->gtt.base.mm)) {
> -               ret = drm_mm_reserve_node(&dev_priv->gtt.base.mm, &vma->node);
> +       if (drm_mm_initialized(&ggtt->mm)) {
> +               ret = drm_mm_reserve_node(&ggtt->mm, &vma->node);
>                 if (ret) {
>                         DRM_DEBUG_KMS("failed to allocate stolen GTT space\n");
>                         i915_gem_vma_destroy(vma);
> @@ -419,7 +419,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
>         obj->has_global_gtt_mapping = 1;
>
>         list_add_tail(&obj->global_list, &dev_priv->mm.bound_list);
> -       list_add_tail(&obj->mm_list, &vm->inactive_list);
> +       list_add_tail(&obj->mm_list, &ggtt->inactive_list);
>
>         return obj;
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
> index 92a8d27..808ca2a 100644
> --- a/drivers/gpu/drm/i915/i915_gem_tiling.c
> +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
> @@ -360,17 +360,19 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
>
>                 obj->map_and_fenceable =
>                         !i915_gem_obj_ggtt_bound(obj) ||
> -                       (i915_gem_obj_ggtt_offset(obj) + obj->base.size <= dev_priv->gtt.mappable_end &&
> +                       (i915_gem_obj_ggtt_offset(obj) +
> +                        obj->base.size <= dev_priv->gtt.mappable_end &&
>                          i915_gem_object_fence_ok(obj, args->tiling_mode));
>
>                 /* Rebind if we need a change of alignment */
>                 if (!obj->map_and_fenceable) {
> -                       u32 unfenced_alignment =
> +                       struct i915_address_space *ggtt = &dev_priv->gtt.base;
> +                       u32 unfenced_align =
>                                 i915_gem_get_gtt_alignment(dev, obj->base.size,
>                                                             args->tiling_mode,
>                                                             false);
> -                       if (i915_gem_obj_ggtt_offset(obj) & (unfenced_alignment - 1))
> -                               ret = i915_gem_object_unbind(obj);
> +                       if (i915_gem_obj_ggtt_offset(obj) & (unfenced_align - 1))
> +                               ret = i915_gem_object_unbind(obj, ggtt);
>                 }
>
>                 if (ret == 0) {
> diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
> index 7d283b5..3f019d3 100644
> --- a/drivers/gpu/drm/i915/i915_trace.h
> +++ b/drivers/gpu/drm/i915/i915_trace.h
> @@ -34,11 +34,13 @@ TRACE_EVENT(i915_gem_object_create,
>  );
>
>  TRACE_EVENT(i915_gem_object_bind,
> -           TP_PROTO(struct drm_i915_gem_object *obj, bool mappable),
> -           TP_ARGS(obj, mappable),
> +           TP_PROTO(struct drm_i915_gem_object *obj,
> +                    struct i915_address_space *vm, bool mappable),
> +           TP_ARGS(obj, vm, mappable),
>
>             TP_STRUCT__entry(
>                              __field(struct drm_i915_gem_object *, obj)
> +                            __field(struct i915_address_space *, vm)
>                              __field(u32, offset)
>                              __field(u32, size)
>                              __field(bool, mappable)
> @@ -46,8 +48,8 @@ TRACE_EVENT(i915_gem_object_bind,
>
>             TP_fast_assign(
>                            __entry->obj = obj;
> -                          __entry->offset = i915_gem_obj_ggtt_offset(obj);
> -                          __entry->size = i915_gem_obj_ggtt_size(obj);
> +                          __entry->offset = i915_gem_obj_offset(obj, vm);
> +                          __entry->size = i915_gem_obj_size(obj, vm);
>                            __entry->mappable = mappable;
>                            ),
>
> @@ -57,19 +59,21 @@ TRACE_EVENT(i915_gem_object_bind,
>  );
>
>  TRACE_EVENT(i915_gem_object_unbind,
> -           TP_PROTO(struct drm_i915_gem_object *obj),
> -           TP_ARGS(obj),
> +           TP_PROTO(struct drm_i915_gem_object *obj,
> +                    struct i915_address_space *vm),
> +           TP_ARGS(obj, vm),
>
>             TP_STRUCT__entry(
>                              __field(struct drm_i915_gem_object *, obj)
> +                            __field(struct i915_address_space *, vm)
>                              __field(u32, offset)
>                              __field(u32, size)
>                              ),
>
>             TP_fast_assign(
>                            __entry->obj = obj;
> -                          __entry->offset = i915_gem_obj_ggtt_offset(obj);
> -                          __entry->size = i915_gem_obj_ggtt_size(obj);
> +                          __entry->offset = i915_gem_obj_offset(obj, vm);
> +                          __entry->size = i915_gem_obj_size(obj, vm);
>                            ),
>
>             TP_printk("obj=%p, offset=%08x size=%x",
> diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
> index f3c97e0..b69cc63 100644
> --- a/drivers/gpu/drm/i915/intel_fb.c
> +++ b/drivers/gpu/drm/i915/intel_fb.c
> @@ -170,7 +170,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
>                       fb->width, fb->height,
>                       i915_gem_obj_ggtt_offset(obj), obj);
>
> -
>         mutex_unlock(&dev->struct_mutex);
>         vga_switcheroo_client_fb_set(dev->pdev, info);
>         return 0;
> diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
> index 2abb53e..22ccb7e 100644
> --- a/drivers/gpu/drm/i915/intel_overlay.c
> +++ b/drivers/gpu/drm/i915/intel_overlay.c
> @@ -1350,7 +1350,7 @@ void intel_setup_overlay(struct drm_device *dev)
>                 }
>                 overlay->flip_addr = reg_bo->phys_obj->handle->busaddr;
>         } else {
> -               ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true, false);
> +               ret = i915_gem_ggtt_pin(reg_bo, PAGE_SIZE, true, false);
>                 if (ret) {
>                         DRM_ERROR("failed to pin overlay register bo\n");
>                         goto out_free_bo;
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 008e0e0..0fb081c 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2860,7 +2860,7 @@ intel_alloc_context_page(struct drm_device *dev)
>                 return NULL;
>         }
>
> -       ret = i915_gem_object_pin(ctx, 4096, true, false);
> +       ret = i915_gem_ggtt_pin(ctx, 4096, true, false);
>         if (ret) {
>                 DRM_ERROR("failed to pin power context: %d\n", ret);
>                 goto err_unref;
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 8527ea0..88130a3 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -481,6 +481,7 @@ out:
>  static int
>  init_pipe_control(struct intel_ring_buffer *ring)
>  {
> +       struct drm_i915_private *dev_priv = ring->dev->dev_private;
>         struct pipe_control *pc;
>         struct drm_i915_gem_object *obj;
>         int ret;
> @@ -499,9 +500,10 @@ init_pipe_control(struct intel_ring_buffer *ring)
>                 goto err;
>         }
>
> -       i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
> +       i915_gem_object_set_cache_level(obj, &dev_priv->gtt.base,
> +                                       I915_CACHE_LLC);
>
> -       ret = i915_gem_object_pin(obj, 4096, true, false);
> +       ret = i915_gem_ggtt_pin(obj, 4096, true, false);
>         if (ret)
>                 goto err_unref;
>
> @@ -1212,6 +1214,7 @@ static void cleanup_status_page(struct intel_ring_buffer *ring)
>  static int init_status_page(struct intel_ring_buffer *ring)
>  {
>         struct drm_device *dev = ring->dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
>         struct drm_i915_gem_object *obj;
>         int ret;
>
> @@ -1222,9 +1225,10 @@ static int init_status_page(struct intel_ring_buffer *ring)
>                 goto err;
>         }
>
> -       i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
> +       i915_gem_object_set_cache_level(obj, &dev_priv->gtt.base,
> +                                       I915_CACHE_LLC);
>
> -       ret = i915_gem_object_pin(obj, 4096, true, false);
> +       ret = i915_gem_ggtt_pin(obj, 4096, true, false);
>         if (ret != 0) {
>                 goto err_unref;
>         }
> @@ -1307,7 +1311,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
>
>         ring->obj = obj;
>
> -       ret = i915_gem_object_pin(obj, PAGE_SIZE, true, false);
> +       ret = i915_gem_ggtt_pin(obj, PAGE_SIZE, true, false);
>         if (ret)
>                 goto err_unref;
>
> @@ -1828,7 +1832,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
>                         return -ENOMEM;
>                 }
>
> -               ret = i915_gem_object_pin(obj, 0, true, false);
> +               ret = i915_gem_ggtt_pin(obj, 0, true, false);
>                 if (ret != 0) {
>                         drm_gem_object_unreference(&obj->base);
>                         DRM_ERROR("Failed to ping batch bo\n");
> --
> 1.8.3.3
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch



More information about the Intel-gfx mailing list