]> Pileus Git - ~andy/linux/blobdiff - drivers/gpu/drm/i915/i915_gem_gtt.c
drm/i915: Update rules for writing through the LLC with the cpu
[~andy/linux] / drivers / gpu / drm / i915 / i915_gem_gtt.c
index 5101ab6869b47eef37b5be33e9b4786bc862beca..c9420c280cf00838989d5af48acfb3cedcf3bc21 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+#define GEN6_PPGTT_PD_ENTRIES 512
+#define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t))
+
 /* PPGTT stuff */
 #define GEN6_GTT_ADDR_ENCODE(addr)     ((addr) | (((addr) >> 28) & 0xff0))
+#define HSW_GTT_ADDR_ENCODE(addr)      ((addr) | (((addr) >> 28) & 0x7f0))
 
 #define GEN6_PDE_VALID                 (1 << 0)
 /* gen6+ has bit 11-4 for physical addr bit 39-32 */
 #define GEN6_PTE_UNCACHED              (1 << 1)
 #define HSW_PTE_UNCACHED               (0)
 #define GEN6_PTE_CACHE_LLC             (2 << 1)
-#define GEN6_PTE_CACHE_LLC_MLC         (3 << 1)
+#define GEN7_PTE_CACHE_L3_LLC          (3 << 1)
 #define GEN6_PTE_ADDR_ENCODE(addr)     GEN6_GTT_ADDR_ENCODE(addr)
+#define HSW_PTE_ADDR_ENCODE(addr)      HSW_GTT_ADDR_ENCODE(addr)
 
-static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
-                                     dma_addr_t addr,
-                                     enum i915_cache_level level)
+/* Cacheability Control is a 4-bit value. The low three bits are stored in *
+ * bits 3:1 of the PTE, while the fourth bit is stored in bit 11 of the PTE.
+ */
+#define HSW_CACHEABILITY_CONTROL(bits) ((((bits) & 0x7) << 1) | \
+                                        (((bits) & 0x8) << (11 - 3)))
+#define HSW_WB_LLC_AGE3                        HSW_CACHEABILITY_CONTROL(0x2)
+#define HSW_WB_LLC_AGE0                        HSW_CACHEABILITY_CONTROL(0x3)
+#define HSW_WB_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0xb)
+
+static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
+                                    enum i915_cache_level level)
 {
        gen6_gtt_pte_t pte = GEN6_PTE_VALID;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
 
        switch (level) {
-       case I915_CACHE_LLC_MLC:
-               pte |= GEN6_PTE_CACHE_LLC_MLC;
+       case I915_CACHE_L3_LLC:
+       case I915_CACHE_LLC:
+               pte |= GEN6_PTE_CACHE_LLC;
+               break;
+       case I915_CACHE_NONE:
+               pte |= GEN6_PTE_UNCACHED;
+               break;
+       default:
+               WARN_ON(1);
+       }
+
+       return pte;
+}
+
+static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
+                                    enum i915_cache_level level)
+{
+       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       pte |= GEN6_PTE_ADDR_ENCODE(addr);
+
+       switch (level) {
+       case I915_CACHE_L3_LLC:
+               pte |= GEN7_PTE_CACHE_L3_LLC;
                break;
        case I915_CACHE_LLC:
                pte |= GEN6_PTE_CACHE_LLC;
@@ -60,7 +94,7 @@ static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
                pte |= GEN6_PTE_UNCACHED;
                break;
        default:
-               BUG();
+               WARN_ON(1);
        }
 
        return pte;
@@ -69,8 +103,7 @@ static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
 #define BYT_PTE_WRITEABLE              (1 << 1)
 #define BYT_PTE_SNOOPED_BY_CPU_CACHES  (1 << 2)
 
-static gen6_gtt_pte_t byt_pte_encode(struct drm_device *dev,
-                                    dma_addr_t addr,
+static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
                                     enum i915_cache_level level)
 {
        gen6_gtt_pte_t pte = GEN6_PTE_VALID;
@@ -87,22 +120,33 @@ static gen6_gtt_pte_t byt_pte_encode(struct drm_device *dev,
        return pte;
 }
 
-static gen6_gtt_pte_t hsw_pte_encode(struct drm_device *dev,
-                                    dma_addr_t addr,
+static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
                                     enum i915_cache_level level)
 {
        gen6_gtt_pte_t pte = GEN6_PTE_VALID;
-       pte |= GEN6_PTE_ADDR_ENCODE(addr);
+       pte |= HSW_PTE_ADDR_ENCODE(addr);
 
        if (level != I915_CACHE_NONE)
-               pte |= GEN6_PTE_CACHE_LLC;
+               pte |= HSW_WB_LLC_AGE3;
+
+       return pte;
+}
+
+static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
+                                     enum i915_cache_level level)
+{
+       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       pte |= HSW_PTE_ADDR_ENCODE(addr);
+
+       if (level != I915_CACHE_NONE)
+               pte |= HSW_WB_ELLC_LLC_AGE0;
 
        return pte;
 }
 
 static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
 {
-       struct drm_i915_private *dev_priv = ppgtt->dev->dev_private;
+       struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
        gen6_gtt_pte_t __iomem *pd_addr;
        uint32_t pd_entry;
        int i;
@@ -181,18 +225,18 @@ static int gen6_ppgtt_enable(struct drm_device *dev)
 }
 
 /* PPGTT support for Sandybdrige/Gen6 and later */
-static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
+static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
                                   unsigned first_entry,
                                   unsigned num_entries)
 {
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(vm, struct i915_hw_ppgtt, base);
        gen6_gtt_pte_t *pt_vaddr, scratch_pte;
        unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
        unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        unsigned last_pte, i;
 
-       scratch_pte = ppgtt->pte_encode(ppgtt->dev,
-                                       ppgtt->scratch_page_dma_addr,
-                                       I915_CACHE_LLC);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC);
 
        while (num_entries) {
                last_pte = first_pte + num_entries;
@@ -212,11 +256,13 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
        }
 }
 
-static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
+static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                                      struct sg_table *pages,
                                      unsigned first_entry,
                                      enum i915_cache_level cache_level)
 {
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(vm, struct i915_hw_ppgtt, base);
        gen6_gtt_pte_t *pt_vaddr;
        unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
        unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES;
@@ -227,8 +273,7 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
                dma_addr_t page_addr;
 
                page_addr = sg_page_iter_dma_address(&sg_iter);
-               pt_vaddr[act_pte] = ppgtt->pte_encode(ppgtt->dev, page_addr,
-                                                     cache_level);
+               pt_vaddr[act_pte] = vm->pte_encode(page_addr, cache_level);
                if (++act_pte == I915_PPGTT_PT_ENTRIES) {
                        kunmap_atomic(pt_vaddr);
                        act_pt++;
@@ -240,13 +285,17 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
        kunmap_atomic(pt_vaddr);
 }
 
-static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
+static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
 {
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(vm, struct i915_hw_ppgtt, base);
        int i;
 
+       drm_mm_takedown(&ppgtt->base.mm);
+
        if (ppgtt->pt_dma_addr) {
                for (i = 0; i < ppgtt->num_pd_entries; i++)
-                       pci_unmap_page(ppgtt->dev->pdev,
+                       pci_unmap_page(ppgtt->base.dev->pdev,
                                       ppgtt->pt_dma_addr[i],
                                       4096, PCI_DMA_BIDIRECTIONAL);
        }
@@ -260,7 +309,7 @@ static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
 
 static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 {
-       struct drm_device *dev = ppgtt->dev;
+       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned first_pd_entry_in_global_pt;
        int i;
@@ -271,18 +320,13 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
         * now. */
        first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt);
 
-       if (IS_HASWELL(dev)) {
-               ppgtt->pte_encode = hsw_pte_encode;
-       } else if (IS_VALLEYVIEW(dev)) {
-               ppgtt->pte_encode = byt_pte_encode;
-       } else {
-               ppgtt->pte_encode = gen6_pte_encode;
-       }
-       ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
+       ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode;
+       ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES;
        ppgtt->enable = gen6_ppgtt_enable;
-       ppgtt->clear_range = gen6_ppgtt_clear_range;
-       ppgtt->insert_entries = gen6_ppgtt_insert_entries;
-       ppgtt->cleanup = gen6_ppgtt_cleanup;
+       ppgtt->base.clear_range = gen6_ppgtt_clear_range;
+       ppgtt->base.insert_entries = gen6_ppgtt_insert_entries;
+       ppgtt->base.cleanup = gen6_ppgtt_cleanup;
+       ppgtt->base.scratch = dev_priv->gtt.base.scratch;
        ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries,
                                  GFP_KERNEL);
        if (!ppgtt->pt_pages)
@@ -313,8 +357,8 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
                ppgtt->pt_dma_addr[i] = pt_addr;
        }
 
-       ppgtt->clear_range(ppgtt, 0,
-                          ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES);
+       ppgtt->base.clear_range(&ppgtt->base, 0,
+                               ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES);
 
        ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t);
 
@@ -347,8 +391,7 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
        if (!ppgtt)
                return -ENOMEM;
 
-       ppgtt->dev = dev;
-       ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma;
+       ppgtt->base.dev = dev;
 
        if (INTEL_INFO(dev)->gen < 8)
                ret = gen6_ppgtt_init(ppgtt);
@@ -357,8 +400,11 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
 
        if (ret)
                kfree(ppgtt);
-       else
+       else {
                dev_priv->mm.aliasing_ppgtt = ppgtt;
+               drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
+                           ppgtt->base.total);
+       }
 
        return ret;
 }
@@ -371,7 +417,7 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
        if (!ppgtt)
                return;
 
-       ppgtt->cleanup(ppgtt);
+       ppgtt->base.cleanup(&ppgtt->base);
        dev_priv->mm.aliasing_ppgtt = NULL;
 }
 
@@ -379,17 +425,17 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
                            struct drm_i915_gem_object *obj,
                            enum i915_cache_level cache_level)
 {
-       ppgtt->insert_entries(ppgtt, obj->pages,
-                             obj->gtt_space->start >> PAGE_SHIFT,
-                             cache_level);
+       ppgtt->base.insert_entries(&ppgtt->base, obj->pages,
+                                  i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
+                                  cache_level);
 }
 
 void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
                              struct drm_i915_gem_object *obj)
 {
-       ppgtt->clear_range(ppgtt,
-                          obj->gtt_space->start >> PAGE_SHIFT,
-                          obj->base.size >> PAGE_SHIFT);
+       ppgtt->base.clear_range(&ppgtt->base,
+                               i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
+                               obj->base.size >> PAGE_SHIFT);
 }
 
 extern int intel_iommu_gfx_mapped;
@@ -436,11 +482,12 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
        struct drm_i915_gem_object *obj;
 
        /* First fill our portion of the GTT with scratch pages */
-       dev_priv->gtt.gtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE,
-                                     dev_priv->gtt.total / PAGE_SIZE);
+       dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
+                                      dev_priv->gtt.base.start / PAGE_SIZE,
+                                      dev_priv->gtt.base.total / PAGE_SIZE);
 
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               i915_gem_clflush_object(obj);
+               i915_gem_clflush_object(obj, obj->pin_display);
                i915_gem_gtt_bind_object(obj, obj->cache_level);
        }
 
@@ -466,12 +513,12 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
  * within the global GTT as well as accessible by the GPU through the GMADR
  * mapped BAR (dev_priv->mm.gtt->gtt).
  */
-static void gen6_ggtt_insert_entries(struct drm_device *dev,
+static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
                                     struct sg_table *st,
                                     unsigned int first_entry,
                                     enum i915_cache_level level)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = vm->dev->dev_private;
        gen6_gtt_pte_t __iomem *gtt_entries =
                (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
@@ -480,8 +527,7 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
 
        for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
                addr = sg_page_iter_dma_address(&sg_iter);
-               iowrite32(dev_priv->gtt.pte_encode(dev, addr, level),
-                         &gtt_entries[i]);
+               iowrite32(vm->pte_encode(addr, level), &gtt_entries[i]);
                i++;
        }
 
@@ -492,8 +538,8 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
         * hardware should work, we must keep this posting read for paranoia.
         */
        if (i != 0)
-               WARN_ON(readl(&gtt_entries[i-1])
-                       != dev_priv->gtt.pte_encode(dev, addr, level));
+               WARN_ON(readl(&gtt_entries[i-1]) !=
+                       vm->pte_encode(addr, level));
 
        /* This next bit makes the above posting read even more important. We
         * want to flush the TLBs only after we're certain all the PTE updates
@@ -503,11 +549,11 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
        POSTING_READ(GFX_FLSH_CNTL_GEN6);
 }
 
-static void gen6_ggtt_clear_range(struct drm_device *dev,
+static void gen6_ggtt_clear_range(struct i915_address_space *vm,
                                  unsigned int first_entry,
                                  unsigned int num_entries)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = vm->dev->dev_private;
        gen6_gtt_pte_t scratch_pte, __iomem *gtt_base =
                (gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
        const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
@@ -518,16 +564,14 @@ static void gen6_ggtt_clear_range(struct drm_device *dev,
                 first_entry, num_entries, max_entries))
                num_entries = max_entries;
 
-       scratch_pte = dev_priv->gtt.pte_encode(dev,
-                                              dev_priv->gtt.scratch_page_dma,
-                                              I915_CACHE_LLC);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC);
        for (i = 0; i < num_entries; i++)
                iowrite32(scratch_pte, &gtt_base[i]);
        readl(gtt_base);
 }
 
 
-static void i915_ggtt_insert_entries(struct drm_device *dev,
+static void i915_ggtt_insert_entries(struct i915_address_space *vm,
                                     struct sg_table *st,
                                     unsigned int pg_start,
                                     enum i915_cache_level cache_level)
@@ -539,7 +583,7 @@ static void i915_ggtt_insert_entries(struct drm_device *dev,
 
 }
 
-static void i915_ggtt_clear_range(struct drm_device *dev,
+static void i915_ggtt_clear_range(struct i915_address_space *vm,
                                  unsigned int first_entry,
                                  unsigned int num_entries)
 {
@@ -552,10 +596,11 @@ void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT;
 
-       dev_priv->gtt.gtt_insert_entries(dev, obj->pages,
-                                        obj->gtt_space->start >> PAGE_SHIFT,
-                                        cache_level);
+       dev_priv->gtt.base.insert_entries(&dev_priv->gtt.base, obj->pages,
+                                         entry,
+                                         cache_level);
 
        obj->has_global_gtt_mapping = 1;
 }
@@ -564,10 +609,11 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT;
 
-       dev_priv->gtt.gtt_clear_range(obj->base.dev,
-                                     obj->gtt_space->start >> PAGE_SHIFT,
-                                     obj->base.size >> PAGE_SHIFT);
+       dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
+                                      entry,
+                                      obj->base.size >> PAGE_SHIFT);
 
        obj->has_global_gtt_mapping = 0;
 }
@@ -618,7 +664,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;
@@ -626,37 +673,38 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
        BUG_ON(mappable_end > end);
 
        /* Subtract the guard page ... */
-       drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE);
+       drm_mm_init(&ggtt_vm->mm, start, end - start - PAGE_SIZE);
        if (!HAS_LLC(dev))
-               dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust;
+               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) {
-               DRM_DEBUG_KMS("reserving preallocated space: %x + %zx\n",
-                             obj->gtt_offset, obj->base.size);
-
-               BUG_ON(obj->gtt_space != I915_GTT_RESERVED);
-               obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space,
-                                                    obj->gtt_offset,
-                                                    obj->base.size,
-                                                    false);
+               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(&ggtt_vm->mm, &vma->node);
+               if (ret)
+                       DRM_DEBUG_KMS("Reservation failed\n");
                obj->has_global_gtt_mapping = 1;
+               list_add(&vma->vma_link, &obj->vma_list);
        }
 
-       dev_priv->gtt.start = start;
-       dev_priv->gtt.total = end - start;
+       dev_priv->gtt.base.start = start;
+       dev_priv->gtt.base.total = end - start;
 
        /* Clear any non-preallocated blocks */
-       drm_mm_for_each_hole(entry, &dev_priv->mm.gtt_space,
-                            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.gtt_clear_range(dev, hole_start / PAGE_SIZE,
-                                             (hole_end-hole_start) / PAGE_SIZE);
+               ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count);
        }
 
        /* And finally clear the reserved guard page */
-       dev_priv->gtt.gtt_clear_range(dev, end / PAGE_SIZE - 1, 1);
+       ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1);
 }
 
 static bool
@@ -679,7 +727,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long gtt_size, mappable_size;
 
-       gtt_size = dev_priv->gtt.total;
+       gtt_size = dev_priv->gtt.base.total;
        mappable_size = dev_priv->gtt.mappable_end;
 
        if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
@@ -688,7 +736,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
                if (INTEL_INFO(dev)->gen <= 7) {
                        /* PPGTT pdes are stolen from global gtt ptes, so shrink the
                         * aperture accordingly when using aliasing ppgtt. */
-                       gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+                       gtt_size -= GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE;
                }
 
                i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
@@ -698,8 +746,8 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
                        return;
 
                DRM_ERROR("Aliased PPGTT setup failed %d\n", ret);
-               drm_mm_takedown(&dev_priv->mm.gtt_space);
-               gtt_size += I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+               drm_mm_takedown(&dev_priv->gtt.base.mm);
+               gtt_size += GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE;
        }
        i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 }
@@ -724,8 +772,8 @@ static int setup_scratch_page(struct drm_device *dev)
 #else
        dma_addr = page_to_phys(page);
 #endif
-       dev_priv->gtt.scratch_page = page;
-       dev_priv->gtt.scratch_page_dma = dma_addr;
+       dev_priv->gtt.base.scratch.page = page;
+       dev_priv->gtt.base.scratch.addr = dma_addr;
 
        return 0;
 }
@@ -733,11 +781,13 @@ static int setup_scratch_page(struct drm_device *dev)
 static void teardown_scratch_page(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       set_pages_wb(dev_priv->gtt.scratch_page, 1);
-       pci_unmap_page(dev->pdev, dev_priv->gtt.scratch_page_dma,
+       struct page *page = dev_priv->gtt.base.scratch.page;
+
+       set_pages_wb(page, 1);
+       pci_unmap_page(dev->pdev, dev_priv->gtt.base.scratch.addr,
                       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-       put_page(dev_priv->gtt.scratch_page);
-       __free_page(dev_priv->gtt.scratch_page);
+       put_page(page);
+       __free_page(page);
 }
 
 static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl)
@@ -800,17 +850,18 @@ static int gen6_gmch_probe(struct drm_device *dev,
        if (ret)
                DRM_ERROR("Scratch setup failed\n");
 
-       dev_priv->gtt.gtt_clear_range = gen6_ggtt_clear_range;
-       dev_priv->gtt.gtt_insert_entries = gen6_ggtt_insert_entries;
+       dev_priv->gtt.base.clear_range = gen6_ggtt_clear_range;
+       dev_priv->gtt.base.insert_entries = gen6_ggtt_insert_entries;
 
        return ret;
 }
 
-static void gen6_gmch_remove(struct drm_device *dev)
+static void gen6_gmch_remove(struct i915_address_space *vm)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       iounmap(dev_priv->gtt.gsm);
-       teardown_scratch_page(dev_priv->dev);
+
+       struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base);
+       iounmap(gtt->gsm);
+       teardown_scratch_page(vm->dev);
 }
 
 static int i915_gmch_probe(struct drm_device *dev,
@@ -831,13 +882,13 @@ static int i915_gmch_probe(struct drm_device *dev,
        intel_gtt_get(gtt_total, stolen, mappable_base, mappable_end);
 
        dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev);
-       dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range;
-       dev_priv->gtt.gtt_insert_entries = i915_ggtt_insert_entries;
+       dev_priv->gtt.base.clear_range = i915_ggtt_clear_range;
+       dev_priv->gtt.base.insert_entries = i915_ggtt_insert_entries;
 
        return 0;
 }
 
-static void i915_gmch_remove(struct drm_device *dev)
+static void i915_gmch_remove(struct i915_address_space *vm)
 {
        intel_gmch_remove();
 }
@@ -849,34 +900,35 @@ int i915_gem_gtt_init(struct drm_device *dev)
        int ret;
 
        if (INTEL_INFO(dev)->gen <= 5) {
-               dev_priv->gtt.gtt_probe = i915_gmch_probe;
-               dev_priv->gtt.gtt_remove = i915_gmch_remove;
+               gtt->gtt_probe = i915_gmch_probe;
+               gtt->base.cleanup = i915_gmch_remove;
        } else {
-               dev_priv->gtt.gtt_probe = gen6_gmch_probe;
-               dev_priv->gtt.gtt_remove = gen6_gmch_remove;
-               if (IS_HASWELL(dev)) {
-                       dev_priv->gtt.pte_encode = hsw_pte_encode;
-               } else if (IS_VALLEYVIEW(dev)) {
-                       dev_priv->gtt.pte_encode = byt_pte_encode;
-               } else {
-                       dev_priv->gtt.pte_encode = gen6_pte_encode;
-               }
+               gtt->gtt_probe = gen6_gmch_probe;
+               gtt->base.cleanup = gen6_gmch_remove;
+               if (IS_HASWELL(dev) && dev_priv->ellc_size)
+                       gtt->base.pte_encode = iris_pte_encode;
+               else if (IS_HASWELL(dev))
+                       gtt->base.pte_encode = hsw_pte_encode;
+               else if (IS_VALLEYVIEW(dev))
+                       gtt->base.pte_encode = byt_pte_encode;
+               else if (INTEL_INFO(dev)->gen >= 7)
+                       gtt->base.pte_encode = ivb_pte_encode;
+               else
+                       gtt->base.pte_encode = snb_pte_encode;
        }
 
-       ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total,
-                                    &dev_priv->gtt.stolen_size,
-                                    &gtt->mappable_base,
-                                    &gtt->mappable_end);
+       ret = gtt->gtt_probe(dev, &gtt->base.total, &gtt->stolen_size,
+                            &gtt->mappable_base, &gtt->mappable_end);
        if (ret)
                return ret;
 
+       gtt->base.dev = dev;
+
        /* GMADR is the PCI mmio aperture into the global GTT. */
        DRM_INFO("Memory usable by graphics device = %zdM\n",
-                dev_priv->gtt.total >> 20);
-       DRM_DEBUG_DRIVER("GMADR size = %ldM\n",
-                        dev_priv->gtt.mappable_end >> 20);
-       DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n",
-                        dev_priv->gtt.stolen_size >> 20);
+                gtt->base.total >> 20);
+       DRM_DEBUG_DRIVER("GMADR size = %ldM\n", gtt->mappable_end >> 20);
+       DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", gtt->stolen_size >> 20);
 
        return 0;
 }