drm/i915/gtt: Read-only pages for insert_entries on bdw+
authorJon Bloomfield <jon.bloomfield@intel.com>
Mon, 6 Aug 2018 21:10:48 +0000 (14:10 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Nov 2019 18:13:32 +0000 (19:13 +0100)
commit 250f8c8140ac0a5e5acb91891d6813f12778b224 upstream.

Hook up the flags to allow read-only ppGTT mappings for gen8+

v2: Include a selftest to check that writes to a readonly PTE are
dropped
v3: Don't duplicate cpu_check() as we can just reuse it, and even worse
don't wholesale copy the theory-of-operation comment from igt_ctx_exec
without changing it to explain the intention behind the new test!
v4: Joonas really likes magic mystery values

Signed-off-by: Jon Bloomfield <jon.bloomfield@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Matthew Auld <matthew.william.auld@gmail.com>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180712185315.3288-2-chris@chris-wilson.co.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_gtt.h
drivers/gpu/drm/i915/intel_ringbuffer.c

index 272b03b4f1ec18a146fcf9697fef165a22ecec54..3a80446e4e3785d2dbfb3758463f28cfcf7d5b1d 100644 (file)
@@ -152,7 +152,8 @@ static int ppgtt_bind_vma(struct i915_vma *vma,
 {
        u32 pte_flags = 0;
 
-       /* Currently applicable only to VLV */
+       /* Applicable to VLV, and gen8+ */
+       pte_flags = 0;
        if (vma->obj->gt_ro)
                pte_flags |= PTE_READ_ONLY;
 
@@ -783,7 +784,8 @@ gen8_ppgtt_insert_pte_entries(struct i915_address_space *vm,
                              struct i915_page_directory_pointer *pdp,
                              struct sg_page_iter *sg_iter,
                              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);
@@ -803,7 +805,7 @@ gen8_ppgtt_insert_pte_entries(struct i915_address_space *vm,
 
                pt_vaddr[pte] =
                        gen8_pte_encode(sg_page_iter_dma_address(sg_iter),
-                                       cache_level, true, 0);
+                                       cache_level, true, flags);
                if (++pte == GEN8_PTES) {
                        kunmap_px(ppgtt, pt_vaddr);
                        pt_vaddr = NULL;
@@ -824,7 +826,7 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
                                      struct sg_table *pages,
                                      uint64_t start,
                                      enum i915_cache_level cache_level,
-                                     u32 unused)
+                                     u32 flags)
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
@@ -834,7 +836,7 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
 
        if (!USES_FULL_48BIT_PPGTT(vm->dev)) {
                gen8_ppgtt_insert_pte_entries(vm, &ppgtt->pdp, &sg_iter, start,
-                                             cache_level);
+                                             cache_level, flags);
        } else {
                struct i915_page_directory_pointer *pdp;
                uint64_t templ4, pml4e;
@@ -842,7 +844,7 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
 
                gen8_for_each_pml4e(pdp, &ppgtt->pml4, start, length, templ4, pml4e) {
                        gen8_ppgtt_insert_pte_entries(vm, pdp, &sg_iter,
-                                                     start, cache_level);
+                                                     start, cache_level, flags);
                }
        }
 }
@@ -1519,6 +1521,10 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
        ppgtt->base.clear_range = gen8_ppgtt_clear_range;
        ppgtt->base.unbind_vma = ppgtt_unbind_vma;
        ppgtt->base.bind_vma = ppgtt_bind_vma;
+
+       /* From bdw, there is support for read-only pages in the PPGTT */
+       ppgtt->base.has_read_only = true;
+
        ppgtt->debug_dump = gen8_dump_ppgtt;
 
        if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
@@ -2347,7 +2353,7 @@ static void gen8_set_pte(void __iomem *addr, gen8_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, u32 unused)
+                                    enum i915_cache_level level, u32 flags)
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        unsigned first_entry = start >> PAGE_SHIFT;
@@ -2361,7 +2367,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
                addr = sg_dma_address(sg_iter.sg) +
                        (sg_iter.sg_pgoffset << PAGE_SHIFT);
                gen8_set_pte(&gtt_entries[i],
-                            gen8_pte_encode(addr, level, true, 0));
+                            gen8_pte_encode(addr, level, true, flags));
                i++;
        }
 
@@ -2374,7 +2380,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
         */
        if (i != 0)
                WARN_ON(readq(&gtt_entries[i-1])
-                       != gen8_pte_encode(addr, level, true, 0));
+                       != gen8_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
@@ -2514,7 +2520,8 @@ static int ggtt_bind_vma(struct i915_vma *vma,
        if (ret)
                return ret;
 
-       /* Currently applicable only to VLV */
+       /* Applicable to VLV (gen8+ do not support RO in the GGTT) */
+       pte_flags = 0;
        if (obj->gt_ro)
                pte_flags |= PTE_READ_ONLY;
 
@@ -2657,6 +2664,9 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
        i915_address_space_init(ggtt_vm, dev_priv);
        ggtt_vm->total += PAGE_SIZE;
 
+       /* Only VLV supports read-only GGTT mappings */
+       ggtt_vm->has_read_only = IS_VALLEYVIEW(dev_priv);
+
        if (intel_vgpu_active(dev)) {
                ret = intel_vgt_balloon(dev);
                if (ret)
index a216397ead52f03e49a3f72244fb2c72443d526a..d36f2d77576a7016ba28a54a4aaadc51bb05bc9c 100644 (file)
@@ -307,6 +307,9 @@ struct i915_address_space {
         */
        struct list_head inactive_list;
 
+       /* Some systems support read-only mappings for GGTT and/or PPGTT */
+       bool has_read_only:1;
+
        /* FIXME: Need a more generic return type */
        gen6_pte_t (*pte_encode)(dma_addr_t addr,
                                 enum i915_cache_level level,
index 9d48443bca2e7542f8ce51f5b2ca1f4dbc4244a3..df6547f60a5cbf36aca75c160d20d09c76c7945c 100644 (file)
@@ -2058,6 +2058,8 @@ static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
 static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
                                      struct intel_ringbuffer *ringbuf)
 {
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        struct drm_i915_gem_object *obj;
 
        obj = NULL;
@@ -2068,8 +2070,12 @@ static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
        if (obj == NULL)
                return -ENOMEM;
 
-       /* mark ring buffers as read-only from GPU side by default */
-       obj->gt_ro = 1;
+       /*
+        * Mark ring buffers as read-only from GPU side (so no stray overwrites)
+        * if supported by the platform's GGTT.
+        */
+       if (vm->has_read_only)
+               obj->gt_ro = 1;
 
        ringbuf->obj = obj;