drm/i915: Inline feature detection into sanitize_enable_ppgtt
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_gem_gtt.c
index 8b3cde7033640e2450ab0b911c5cedb39172a003..90c9bf6e71b7f9ea40161b7d2e74793d6da67bef 100644 (file)
 static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv);
 static void chv_setup_private_ppat(struct drm_i915_private *dev_priv);
 
-bool intel_enable_ppgtt(struct drm_device *dev, bool full)
+static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
 {
-       if (i915.enable_ppgtt == 0)
-               return false;
-
-       if (i915.enable_ppgtt == 1 && full)
-               return false;
+       bool has_aliasing_ppgtt;
+       bool has_full_ppgtt;
 
-       return true;
-}
+       has_aliasing_ppgtt = INTEL_INFO(dev)->gen >= 6;
+       has_full_ppgtt = INTEL_INFO(dev)->gen >= 7;
+       if (IS_GEN8(dev))
+               has_full_ppgtt = false; /* XXX why? */
 
-static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
-{
-       if (enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev))
+       if (enable_ppgtt == 0 || !has_aliasing_ppgtt)
                return 0;
 
        if (enable_ppgtt == 1)
                return 1;
 
-       if (enable_ppgtt == 2 && HAS_PPGTT(dev))
+       if (enable_ppgtt == 2 && has_full_ppgtt)
                return 2;
 
 #ifdef CONFIG_INTEL_IOMMU
@@ -63,7 +60,14 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
        }
 #endif
 
-       return HAS_ALIASING_PPGTT(dev) ? 1 : 0;
+       /* Early VLV doesn't have this */
+       if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) &&
+           dev->pdev->revision < 0xb) {
+               DRM_DEBUG_DRIVER("disabling PPGTT on pre-B3 step VLV\n");
+               return 0;
+       }
+
+       return has_full_ppgtt ? 2 : has_aliasing_ppgtt ? 1 : 0;
 }
 
 
@@ -71,7 +75,6 @@ static void ppgtt_bind_vma(struct i915_vma *vma,
                           enum i915_cache_level cache_level,
                           u32 flags);
 static void ppgtt_unbind_vma(struct i915_vma *vma);
-static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt);
 
 static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
                                             enum i915_cache_level level,
@@ -110,7 +113,7 @@ static inline gen8_ppgtt_pde_t gen8_pde_encode(struct drm_device *dev,
 
 static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
                                     enum i915_cache_level level,
-                                    bool valid)
+                                    bool valid, u32 unused)
 {
        gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
@@ -132,7 +135,7 @@ static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
 
 static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
                                     enum i915_cache_level level,
-                                    bool valid)
+                                    bool valid, u32 unused)
 {
        gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
@@ -156,7 +159,7 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
 
 static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
                                     enum i915_cache_level level,
-                                    bool valid)
+                                    bool valid, u32 flags)
 {
        gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
@@ -164,7 +167,8 @@ static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
        /* Mark the page as writeable.  Other platforms don't have a
         * setting for read-only/writable, so this matches that behavior.
         */
-       pte |= BYT_PTE_WRITEABLE;
+       if (!(flags & PTE_READ_ONLY))
+               pte |= BYT_PTE_WRITEABLE;
 
        if (level != I915_CACHE_NONE)
                pte |= BYT_PTE_SNOOPED_BY_CPU_CACHES;
@@ -174,7 +178,7 @@ static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
 
 static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
                                     enum i915_cache_level level,
-                                    bool valid)
+                                    bool valid, u32 unused)
 {
        gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
@@ -187,7 +191,7 @@ static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
 
 static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
                                      enum i915_cache_level level,
-                                     bool valid)
+                                     bool valid, u32 unused)
 {
        gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
@@ -208,19 +212,12 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
 
 /* Broadwell Page Directory Pointer Descriptors */
 static int gen8_write_pdp(struct intel_engine_cs *ring, unsigned entry,
-                          uint64_t val, bool synchronous)
+                          uint64_t val)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
        int ret;
 
        BUG_ON(entry >= 4);
 
-       if (synchronous) {
-               I915_WRITE(GEN8_RING_PDP_UDW(ring, entry), val >> 32);
-               I915_WRITE(GEN8_RING_PDP_LDW(ring, entry), (u32)val);
-               return 0;
-       }
-
        ret = intel_ring_begin(ring, 6);
        if (ret)
                return ret;
@@ -237,8 +234,7 @@ static int gen8_write_pdp(struct intel_engine_cs *ring, unsigned entry,
 }
 
 static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
-                         struct intel_engine_cs *ring,
-                         bool synchronous)
+                         struct intel_engine_cs *ring)
 {
        int i, ret;
 
@@ -247,7 +243,7 @@ static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
 
        for (i = used_pd - 1; i >= 0; i--) {
                dma_addr_t addr = ppgtt->pd_dma_addr[i];
-               ret = gen8_write_pdp(ring, i, addr, synchronous);
+               ret = gen8_write_pdp(ring, i, addr);
                if (ret)
                        return ret;
        }
@@ -301,7 +297,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
 static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
                                      struct sg_table *pages,
                                      uint64_t start,
-                                     enum i915_cache_level cache_level)
+                                     enum i915_cache_level cache_level, u32 unused)
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
@@ -395,9 +391,6 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
 
-       list_del(&vm->global_link);
-       drm_mm_takedown(&vm->mm);
-
        gen8_ppgtt_unmap_pages(ppgtt);
        gen8_ppgtt_free(ppgtt);
 }
@@ -607,7 +600,6 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
                kunmap_atomic(pd_vaddr);
        }
 
-       ppgtt->enable = gen8_ppgtt_enable;
        ppgtt->switch_mm = gen8_mm_switch;
        ppgtt->base.clear_range = gen8_ppgtt_clear_range;
        ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
@@ -639,7 +631,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
        uint32_t pd_entry;
        int pte, pde;
 
-       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0);
 
        pd_addr = (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm +
                ppgtt->pd_offset / sizeof(gen6_gtt_pte_t);
@@ -716,29 +708,10 @@ static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt)
 }
 
 static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
-                        struct intel_engine_cs *ring,
-                        bool synchronous)
+                        struct intel_engine_cs *ring)
 {
-       struct drm_device *dev = ppgtt->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       /* If we're in reset, we can assume the GPU is sufficiently idle to
-        * manually frob these bits. Ideally we could use the ring functions,
-        * except our error handling makes it quite difficult (can't use
-        * intel_ring_begin, ring->flush, or intel_ring_advance)
-        *
-        * FIXME: We should try not to special case reset
-        */
-       if (synchronous ||
-           i915_reset_in_progress(&dev_priv->gpu_error)) {
-               WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
-               I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
-               I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
-               POSTING_READ(RING_PP_DIR_BASE(ring));
-               return 0;
-       }
-
        /* NB: TLBs must be flushed and invalidated before a switch */
        ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
        if (ret)
@@ -760,29 +733,10 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
 }
 
 static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
-                         struct intel_engine_cs *ring,
-                         bool synchronous)
+                         struct intel_engine_cs *ring)
 {
-       struct drm_device *dev = ppgtt->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       /* If we're in reset, we can assume the GPU is sufficiently idle to
-        * manually frob these bits. Ideally we could use the ring functions,
-        * except our error handling makes it quite difficult (can't use
-        * intel_ring_begin, ring->flush, or intel_ring_advance)
-        *
-        * FIXME: We should try not to special case reset
-        */
-       if (synchronous ||
-           i915_reset_in_progress(&dev_priv->gpu_error)) {
-               WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
-               I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
-               I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
-               POSTING_READ(RING_PP_DIR_BASE(ring));
-               return 0;
-       }
-
        /* NB: TLBs must be flushed and invalidated before a switch */
        ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
        if (ret)
@@ -811,14 +765,11 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
 }
 
 static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
-                         struct intel_engine_cs *ring,
-                         bool synchronous)
+                         struct intel_engine_cs *ring)
 {
        struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (!synchronous)
-               return 0;
 
        I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
        I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
@@ -828,39 +779,20 @@ static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
        return 0;
 }
 
-static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+static void gen8_ppgtt_enable(struct drm_device *dev)
 {
-       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_engine_cs *ring;
-       int j, ret;
+       int j;
 
        for_each_ring(ring, dev_priv, j) {
                I915_WRITE(RING_MODE_GEN7(ring),
                           _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
-               /* We promise to do a switch later with FULL PPGTT. If this is
-                * aliasing, this is the one and only switch we'll do */
-               if (USES_FULL_PPGTT(dev))
-                       continue;
-
-               ret = ppgtt->switch_mm(ppgtt, ring, true);
-               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 int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+static void gen7_ppgtt_enable(struct drm_device *dev)
 {
-       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_engine_cs *ring;
        uint32_t ecochk, ecobits;
@@ -879,31 +811,16 @@ static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
        I915_WRITE(GAM_ECOCHK, ecochk);
 
        for_each_ring(ring, dev_priv, i) {
-               int ret;
                /* GFX_MODE is per-ring on gen7+ */
                I915_WRITE(RING_MODE_GEN7(ring),
                           _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
-               /* We promise to do a switch later with FULL PPGTT. If this is
-                * aliasing, this is the one and only switch we'll do */
-               if (USES_FULL_PPGTT(dev))
-                       continue;
-
-               ret = ppgtt->switch_mm(ppgtt, ring, true);
-               if (ret)
-                       return ret;
        }
-
-       return 0;
 }
 
-static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+static void gen6_ppgtt_enable(struct drm_device *dev)
 {
-       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_engine_cs *ring;
        uint32_t ecochk, gab_ctl, ecobits;
-       int i;
 
        ecobits = I915_READ(GAC_ECO_BITS);
        I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT |
@@ -916,14 +833,6 @@ static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
        I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B);
 
        I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
-       for_each_ring(ring, dev_priv, i) {
-               int ret = ppgtt->switch_mm(ppgtt, ring, true);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
 }
 
 /* PPGTT support for Sandybdrige/Gen6 and later */
@@ -941,7 +850,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
        unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        unsigned last_pte, i;
 
-       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0);
 
        while (num_entries) {
                last_pte = first_pte + num_entries;
@@ -964,7 +873,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
 static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                                      struct sg_table *pages,
                                      uint64_t start,
-                                     enum i915_cache_level cache_level)
+                                     enum i915_cache_level cache_level, u32 flags)
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
@@ -981,7 +890,8 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
 
                pt_vaddr[act_pte] =
                        vm->pte_encode(sg_page_iter_dma_address(&sg_iter),
-                                      cache_level, true);
+                                      cache_level, true, flags);
+
                if (++act_pte == I915_PPGTT_PT_ENTRIES) {
                        kunmap_atomic(pt_vaddr);
                        pt_vaddr = NULL;
@@ -1020,8 +930,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
 
-       list_del(&vm->global_link);
-       drm_mm_takedown(&ppgtt->base.mm);
        drm_mm_remove_node(&ppgtt->node);
 
        gen6_ppgtt_unmap_pages(ppgtt);
@@ -1142,13 +1050,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 
        ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode;
        if (IS_GEN6(dev)) {
-               ppgtt->enable = gen6_ppgtt_enable;
                ppgtt->switch_mm = gen6_mm_switch;
        } else if (IS_HASWELL(dev)) {
-               ppgtt->enable = gen7_ppgtt_enable;
                ppgtt->switch_mm = hsw_mm_switch;
        } else if (IS_GEN7(dev)) {
-               ppgtt->enable = gen7_ppgtt_enable;
                ppgtt->switch_mm = gen7_mm_switch;
        } else
                BUG();
@@ -1179,47 +1084,126 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
                         ppgtt->node.size >> 20,
                         ppgtt->node.start / PAGE_SIZE);
 
+       gen6_write_pdes(ppgtt);
+       DRM_DEBUG("Adding PPGTT at offset %x\n",
+                 ppgtt->pd_offset << 10);
+
        return 0;
 }
 
-int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
+static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret = 0;
 
        ppgtt->base.dev = dev;
        ppgtt->base.scratch = dev_priv->gtt.base.scratch;
 
        if (INTEL_INFO(dev)->gen < 8)
-               ret = gen6_ppgtt_init(ppgtt);
+               return gen6_ppgtt_init(ppgtt);
        else if (IS_GEN8(dev))
-               ret = gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
+               return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
        else
                BUG();
+}
+int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = 0;
 
-       if (!ret) {
-               struct drm_i915_private *dev_priv = dev->dev_private;
+       ret = __hw_ppgtt_init(dev, ppgtt);
+       if (ret == 0) {
                kref_init(&ppgtt->ref);
                drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
                            ppgtt->base.total);
                i915_init_vm(dev_priv, &ppgtt->base);
-               if (INTEL_INFO(dev)->gen < 8) {
-                       gen6_write_pdes(ppgtt);
-                       DRM_DEBUG("Adding PPGTT at offset %x\n",
-                                 ppgtt->pd_offset << 10);
+       }
+
+       return ret;
+}
+
+int i915_ppgtt_init_hw(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring;
+       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+       int i, ret = 0;
+
+       /* In the case of execlists, PPGTT is enabled by the context descriptor
+        * and the PDPs are contained within the context itself.  We don't
+        * need to do anything here. */
+       if (i915.enable_execlists)
+               return 0;
+
+       if (!USES_PPGTT(dev))
+               return 0;
+
+       if (IS_GEN6(dev))
+               gen6_ppgtt_enable(dev);
+       else if (IS_GEN7(dev))
+               gen7_ppgtt_enable(dev);
+       else if (INTEL_INFO(dev)->gen >= 8)
+               gen8_ppgtt_enable(dev);
+       else
+               WARN_ON(1);
+
+       if (ppgtt) {
+               for_each_ring(ring, dev_priv, i) {
+                       ret = ppgtt->switch_mm(ppgtt, ring);
+                       if (ret != 0)
+                               return ret;
                }
        }
 
        return ret;
 }
+struct i915_hw_ppgtt *
+i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv)
+{
+       struct i915_hw_ppgtt *ppgtt;
+       int ret;
+
+       ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+       if (!ppgtt)
+               return ERR_PTR(-ENOMEM);
+
+       ret = i915_ppgtt_init(dev, ppgtt);
+       if (ret) {
+               kfree(ppgtt);
+               return ERR_PTR(ret);
+       }
+
+       ppgtt->file_priv = fpriv;
+
+       return ppgtt;
+}
+
+void  i915_ppgtt_release(struct kref *kref)
+{
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(kref, struct i915_hw_ppgtt, ref);
+
+       /* vmas should already be unbound */
+       WARN_ON(!list_empty(&ppgtt->base.active_list));
+       WARN_ON(!list_empty(&ppgtt->base.inactive_list));
+
+       list_del(&ppgtt->base.global_link);
+       drm_mm_takedown(&ppgtt->base.mm);
+
+       ppgtt->base.cleanup(&ppgtt->base);
+       kfree(ppgtt);
+}
 
 static void
 ppgtt_bind_vma(struct i915_vma *vma,
               enum i915_cache_level cache_level,
               u32 flags)
 {
+       /* Currently applicable only to VLV */
+       if (vma->obj->gt_ro)
+               flags |= PTE_READ_ONLY;
+
        vma->vm->insert_entries(vma->vm, vma->obj->pages, vma->node.start,
-                               cache_level);
+                               cache_level, flags);
 }
 
 static void ppgtt_unbind_vma(struct i915_vma *vma)
@@ -1394,7 +1378,7 @@ static inline void gen8_set_pte(void __iomem *addr, gen8_gtt_pte_t pte)
 static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
                                     struct sg_table *st,
                                     uint64_t start,
-                                    enum i915_cache_level level)
+                                    enum i915_cache_level level, u32 unused)
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
@@ -1402,7 +1386,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
                (gen8_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
        struct sg_page_iter sg_iter;
-       dma_addr_t addr = 0;
+       dma_addr_t addr = 0; /* shut up gcc */
 
        for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
                addr = sg_dma_address(sg_iter.sg) +
@@ -1440,7 +1424,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
 static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
                                     struct sg_table *st,
                                     uint64_t start,
-                                    enum i915_cache_level level)
+                                    enum i915_cache_level level, u32 flags)
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
@@ -1448,11 +1432,11 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
                (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
        struct sg_page_iter sg_iter;
-       dma_addr_t addr;
+       dma_addr_t addr = 0;
 
        for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
                addr = sg_page_iter_dma_address(&sg_iter);
-               iowrite32(vm->pte_encode(addr, level, true), &gtt_entries[i]);
+               iowrite32(vm->pte_encode(addr, level, true, flags), &gtt_entries[i]);
                i++;
        }
 
@@ -1462,9 +1446,10 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
         * of NUMA access patterns. Therefore, even with the way we assume
         * hardware should work, we must keep this posting read for paranoia.
         */
-       if (i != 0)
-               WARN_ON(readl(&gtt_entries[i-1]) !=
-                       vm->pte_encode(addr, level, true));
+       if (i != 0) {
+               unsigned long gtt = readl(&gtt_entries[i-1]);
+               WARN_ON(gtt != vm->pte_encode(addr, level, true, flags));
+       }
 
        /* 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
@@ -1518,7 +1503,7 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
                 first_entry, num_entries, max_entries))
                num_entries = max_entries;
 
-       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, use_scratch);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, use_scratch, 0);
 
        for (i = 0; i < num_entries; i++)
                iowrite32(scratch_pte, &gtt_base[i]);
@@ -1567,6 +1552,10 @@ static void ggtt_bind_vma(struct i915_vma *vma,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj = vma->obj;
 
+       /* Currently applicable only to VLV */
+       if (obj->gt_ro)
+               flags |= PTE_READ_ONLY;
+
        /* If there is no aliasing PPGTT, or the caller needs a global mapping,
         * or we have a global mapping already but the cacheability flags have
         * changed, set the global PTEs.
@@ -1583,7 +1572,7 @@ static void ggtt_bind_vma(struct i915_vma *vma,
                    (cache_level != obj->cache_level)) {
                        vma->vm->insert_entries(vma->vm, obj->pages,
                                                vma->node.start,
-                                               cache_level);
+                                               cache_level, flags);
                        obj->has_global_gtt_mapping = 1;
                }
        }
@@ -1595,7 +1584,7 @@ static void ggtt_bind_vma(struct i915_vma *vma,
                appgtt->base.insert_entries(&appgtt->base,
                                            vma->obj->pages,
                                            vma->node.start,
-                                           cache_level);
+                                           cache_level, flags);
                vma->obj->has_aliasing_ppgtt_mapping = 1;
        }
 }
@@ -1657,10 +1646,10 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node,
        }
 }
 
-void i915_gem_setup_global_gtt(struct drm_device *dev,
-                              unsigned long start,
-                              unsigned long mappable_end,
-                              unsigned long end)
+int i915_gem_setup_global_gtt(struct drm_device *dev,
+                             unsigned long start,
+                             unsigned long mappable_end,
+                             unsigned long end)
 {
        /* Let GEM Manage all of the aperture.
         *
@@ -1676,6 +1665,7 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
        struct drm_mm_node *entry;
        struct drm_i915_gem_object *obj;
        unsigned long hole_start, hole_end;
+       int ret;
 
        BUG_ON(mappable_end > end);
 
@@ -1687,14 +1677,16 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
        /* 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, 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");
+               if (ret) {
+                       DRM_DEBUG_KMS("Reservation failed: %i\n", ret);
+                       return ret;
+               }
                obj->has_global_gtt_mapping = 1;
        }
 
@@ -1711,6 +1703,22 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
 
        /* And finally clear the reserved guard page */
        ggtt_vm->clear_range(ggtt_vm, end - PAGE_SIZE, PAGE_SIZE, true);
+
+       if (USES_PPGTT(dev) && !USES_FULL_PPGTT(dev)) {
+               struct i915_hw_ppgtt *ppgtt;
+
+               ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+               if (!ppgtt)
+                       return -ENOMEM;
+
+               ret = __hw_ppgtt_init(dev, ppgtt);
+               if (ret != 0)
+                       return ret;
+
+               dev_priv->mm.aliasing_ppgtt = ppgtt;
+       }
+
+       return 0;
 }
 
 void i915_gem_init_global_gtt(struct drm_device *dev)
@@ -1724,6 +1732,25 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
        i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 }
 
+void i915_global_gtt_cleanup(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
+
+       if (dev_priv->mm.aliasing_ppgtt) {
+               struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+
+               ppgtt->base.cleanup(&ppgtt->base);
+       }
+
+       if (drm_mm_initialized(&vm->mm)) {
+               drm_mm_takedown(&vm->mm);
+               list_del(&vm->global_link);
+       }
+
+       vm->cleanup(vm);
+}
+
 static int setup_scratch_page(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1733,7 +1760,6 @@ static int setup_scratch_page(struct drm_device *dev)
        page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
        if (page == NULL)
                return -ENOMEM;
-       get_page(page);
        set_pages_uc(page, 1);
 
 #ifdef CONFIG_INTEL_IOMMU
@@ -1758,7 +1784,6 @@ static void teardown_scratch_page(struct drm_device *dev)
        set_pages_wb(page, 1);
        pci_unmap_page(dev->pdev, dev_priv->gtt.base.scratch.addr,
                       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-       put_page(page);
        __free_page(page);
 }
 
@@ -1992,10 +2017,6 @@ static void gen6_gmch_remove(struct i915_address_space *vm)
 
        struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base);
 
-       if (drm_mm_initialized(&vm->mm)) {
-               drm_mm_takedown(&vm->mm);
-               list_del(&vm->global_link);
-       }
        iounmap(gtt->gsm);
        teardown_scratch_page(vm->dev);
 }
@@ -2028,10 +2049,6 @@ static int i915_gmch_probe(struct drm_device *dev,
 
 static void i915_gmch_remove(struct i915_address_space *vm)
 {
-       if (drm_mm_initialized(&vm->mm)) {
-               drm_mm_takedown(&vm->mm);
-               list_del(&vm->global_link);
-       }
        intel_gmch_remove();
 }
 
@@ -2130,8 +2147,10 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
        /* Keep GGTT vmas first to make debug easier */
        if (i915_is_ggtt(vm))
                list_add(&vma->vma_link, &obj->vma_list);
-       else
+       else {
                list_add_tail(&vma->vma_link, &obj->vma_list);
+               i915_ppgtt_get(i915_vm_to_ppgtt(vm));
+       }
 
        return vma;
 }
This page took 0.040632 seconds and 5 git commands to generate.