drm/i915: Missed dropped VMA conversion
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_gem_gtt.c
index 5704d6437c646d775ec8adc68a1343c779f7ce7f..c1d04a36688f21c3d47d9a55ff05d7d57f715a67 100644 (file)
@@ -59,6 +59,7 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
 #define HSW_WB_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0xb)
 #define HSW_WT_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0x6)
 
+#define GEN8_PTES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_gtt_pte_t))
 #define GEN8_PDES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t))
 #define GEN8_LEGACY_PDPS               4
 
@@ -80,6 +81,19 @@ static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
        return pte;
 }
 
+static inline gen8_ppgtt_pde_t gen8_pde_encode(struct drm_device *dev,
+                                            dma_addr_t addr,
+                                            enum i915_cache_level level)
+{
+       gen8_ppgtt_pde_t pde = _PAGE_PRESENT | _PAGE_RW;
+       pde |= addr;
+       if (level != I915_CACHE_NONE)
+               pde |= PPAT_CACHED_PDE_INDEX;
+       else
+               pde |= PPAT_UNCACHED_INDEX;
+       return pde;
+}
+
 static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
                                     enum i915_cache_level level,
                                     bool valid)
@@ -181,12 +195,135 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
        return pte;
 }
 
+/* Broadwell Page Directory Pointer Descriptors */
+static int gen8_write_pdp(struct intel_ring_buffer *ring, unsigned entry,
+                          uint64_t val)
+{
+       int ret;
+
+       BUG_ON(entry >= 4);
+
+       ret = intel_ring_begin(ring, 6);
+       if (ret)
+               return ret;
+
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+       intel_ring_emit(ring, GEN8_RING_PDP_UDW(ring, entry));
+       intel_ring_emit(ring, (u32)(val >> 32));
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+       intel_ring_emit(ring, GEN8_RING_PDP_LDW(ring, entry));
+       intel_ring_emit(ring, (u32)(val));
+       intel_ring_advance(ring);
+
+       return 0;
+}
+
+static int gen8_ppgtt_enable(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+       int i, j, ret;
+
+       /* bit of a hack to find the actual last used pd */
+       int used_pd = ppgtt->num_pd_entries / GEN8_PDES_PER_PAGE;
+
+       for_each_ring(ring, dev_priv, j) {
+               I915_WRITE(RING_MODE_GEN7(ring),
+                          _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+       }
+
+       for (i = used_pd - 1; i >= 0; i--) {
+               dma_addr_t addr = ppgtt->pd_dma_addr[i];
+               for_each_ring(ring, dev_priv, j) {
+                       ret = gen8_write_pdp(ring, i, addr);
+                       if (ret)
+                               goto err_out;
+               }
+       }
+       return 0;
+
+err_out:
+       for_each_ring(ring, dev_priv, j)
+               I915_WRITE(RING_MODE_GEN7(ring),
+                          _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE));
+       return ret;
+}
+
+static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
+                                  unsigned first_entry,
+                                  unsigned num_entries,
+                                  bool use_scratch)
+{
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(vm, struct i915_hw_ppgtt, base);
+       gen8_gtt_pte_t *pt_vaddr, scratch_pte;
+       unsigned act_pt = first_entry / GEN8_PTES_PER_PAGE;
+       unsigned first_pte = first_entry % GEN8_PTES_PER_PAGE;
+       unsigned last_pte, i;
+
+       scratch_pte = gen8_pte_encode(ppgtt->base.scratch.addr,
+                                     I915_CACHE_LLC, use_scratch);
+
+       while (num_entries) {
+               struct page *page_table = &ppgtt->gen8_pt_pages[act_pt];
+
+               last_pte = first_pte + num_entries;
+               if (last_pte > GEN8_PTES_PER_PAGE)
+                       last_pte = GEN8_PTES_PER_PAGE;
+
+               pt_vaddr = kmap_atomic(page_table);
+
+               for (i = first_pte; i < last_pte; i++)
+                       pt_vaddr[i] = scratch_pte;
+
+               kunmap_atomic(pt_vaddr);
+
+               num_entries -= last_pte - first_pte;
+               first_pte = 0;
+               act_pt++;
+       }
+}
+
+static void gen8_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);
+       gen8_gtt_pte_t *pt_vaddr;
+       unsigned act_pt = first_entry / GEN8_PTES_PER_PAGE;
+       unsigned act_pte = first_entry % GEN8_PTES_PER_PAGE;
+       struct sg_page_iter sg_iter;
+
+       pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]);
+       for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
+               dma_addr_t page_addr;
+
+               page_addr = sg_dma_address(sg_iter.sg) +
+                               (sg_iter.sg_pgoffset << PAGE_SHIFT);
+               pt_vaddr[act_pte] = gen8_pte_encode(page_addr, cache_level,
+                                                   true);
+               if (++act_pte == GEN8_PTES_PER_PAGE) {
+                       kunmap_atomic(pt_vaddr);
+                       act_pt++;
+                       pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]);
+                       act_pte = 0;
+
+               }
+       }
+       kunmap_atomic(pt_vaddr);
+}
+
 static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
        int i, j;
 
+       drm_mm_takedown(&vm->mm);
+
        for (i = 0; i < ppgtt->num_pd_pages ; i++) {
                if (ppgtt->pd_dma_addr[i]) {
                        pci_unmap_page(ppgtt->base.dev->pdev,
@@ -206,8 +343,8 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
                kfree(ppgtt->gen8_pt_dma_addr[i]);
        }
 
-       __free_pages(ppgtt->gen8_pt_pages, ppgtt->num_pt_pages << PAGE_SHIFT);
-       __free_pages(ppgtt->pd_pages, ppgtt->num_pd_pages << PAGE_SHIFT);
+       __free_pages(ppgtt->gen8_pt_pages, get_order(ppgtt->num_pt_pages << PAGE_SHIFT));
+       __free_pages(ppgtt->pd_pages, get_order(ppgtt->num_pd_pages << PAGE_SHIFT));
 }
 
 /**
@@ -246,9 +383,12 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
        ppgtt->num_pd_pages = 1 << get_order(max_pdp << PAGE_SHIFT);
        ppgtt->num_pt_pages = 1 << get_order(num_pt_pages << PAGE_SHIFT);
        ppgtt->num_pd_entries = max_pdp * GEN8_PDES_PER_PAGE;
-       ppgtt->base.clear_range = NULL;
-       ppgtt->base.insert_entries = NULL;
+       ppgtt->enable = gen8_ppgtt_enable;
+       ppgtt->base.clear_range = gen8_ppgtt_clear_range;
+       ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
        ppgtt->base.cleanup = gen8_ppgtt_cleanup;
+       ppgtt->base.start = 0;
+       ppgtt->base.total = ppgtt->num_pt_pages * GEN8_PTES_PER_PAGE * PAGE_SIZE;
 
        BUG_ON(ppgtt->num_pd_pages > GEN8_LEGACY_PDPS);
 
@@ -285,13 +425,31 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
                }
        }
 
+       /* For now, the PPGTT helper functions all require that the PDEs are
+        * plugged in correctly. So we do that now/here. For aliasing PPGTT, we
+        * will never need to touch the PDEs again */
+       for (i = 0; i < max_pdp; i++) {
+               gen8_ppgtt_pde_t *pd_vaddr;
+               pd_vaddr = kmap_atomic(&ppgtt->pd_pages[i]);
+               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
+                       dma_addr_t addr = ppgtt->gen8_pt_dma_addr[i][j];
+                       pd_vaddr[j] = gen8_pde_encode(ppgtt->base.dev, addr,
+                                                     I915_CACHE_LLC);
+               }
+               kunmap_atomic(pd_vaddr);
+       }
+
+       ppgtt->base.clear_range(&ppgtt->base, 0,
+                               ppgtt->num_pd_entries * GEN8_PTES_PER_PAGE,
+                               true);
+
        DRM_DEBUG_DRIVER("Allocated %d pages for page directories (%d wasted)\n",
                         ppgtt->num_pd_pages, ppgtt->num_pd_pages - max_pdp);
        DRM_DEBUG_DRIVER("Allocated %d pages for page tables (%lld wasted)\n",
                         ppgtt->num_pt_pages,
                         (ppgtt->num_pt_pages - num_pt_pages) +
                         size % (1<<30));
-       return -ENOSYS; /* Not ready yet */
+       return 0;
 
 err_out:
        ppgtt->base.cleanup(&ppgtt->base);
@@ -482,6 +640,8 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
        ppgtt->base.insert_entries = gen6_ppgtt_insert_entries;
        ppgtt->base.cleanup = gen6_ppgtt_cleanup;
        ppgtt->base.scratch = dev_priv->gtt.base.scratch;
+       ppgtt->base.start = 0;
+       ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE;
        ppgtt->pt_pages = kcalloc(ppgtt->num_pd_entries, sizeof(struct page *),
                                  GFP_KERNEL);
        if (!ppgtt->pt_pages)
@@ -976,7 +1136,6 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
                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.base.start = start;
@@ -1034,7 +1193,8 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
 
                DRM_ERROR("Aliased PPGTT setup failed %d\n", ret);
                drm_mm_takedown(&dev_priv->gtt.base.mm);
-               gtt_size += GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE;
+               if (INTEL_INFO(dev)->gen < 8)
+                       gtt_size += GEN6_PPGTT_PD_ENTRIES*PAGE_SIZE;
        }
        i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 }
@@ -1090,6 +1250,11 @@ static inline unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl)
        bdw_gmch_ctl &= BDW_GMCH_GGMS_MASK;
        if (bdw_gmch_ctl)
                bdw_gmch_ctl = 1 << bdw_gmch_ctl;
+       if (bdw_gmch_ctl > 4) {
+               WARN_ON(!i915_preliminary_hw_support);
+               return 4<<20;
+       }
+
        return bdw_gmch_ctl << 20;
 }
 
This page took 0.034052 seconds and 5 git commands to generate.