Merge tag 'drm-intel-gt-next-2023-04-06' of git://anongit.freedesktop.org/drm/drm...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / gt / intel_ggtt.c
index 842e69c7b21e4917fa17c579c9e93b6bbaecad7c..3c7f1ed92f5bb449a8001028203865aaf5b3a546 100644 (file)
@@ -291,6 +291,27 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
        ggtt->invalidate(ggtt);
 }
 
+static void gen8_ggtt_clear_range(struct i915_address_space *vm,
+                                 u64 start, u64 length)
+{
+       struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
+       unsigned int first_entry = start / I915_GTT_PAGE_SIZE;
+       unsigned int num_entries = length / I915_GTT_PAGE_SIZE;
+       const gen8_pte_t scratch_pte = vm->scratch[0]->encode;
+       gen8_pte_t __iomem *gtt_base =
+               (gen8_pte_t __iomem *)ggtt->gsm + first_entry;
+       const int max_entries = ggtt_total_entries(ggtt) - first_entry;
+       int i;
+
+       if (WARN(num_entries > max_entries,
+                "First entry = %d; Num entries = %d (max=%d)\n",
+                first_entry, num_entries, max_entries))
+               num_entries = max_entries;
+
+       for (i = 0; i < num_entries; i++)
+               gen8_set_pte(&gtt_base[i], scratch_pte);
+}
+
 static void gen6_ggtt_insert_page(struct i915_address_space *vm,
                                  dma_addr_t addr,
                                  u64 offset,
@@ -551,8 +572,12 @@ static int init_ggtt(struct i915_ggtt *ggtt)
                 * paths, and we trust that 0 will remain reserved. However,
                 * the only likely reason for failure to insert is a driver
                 * bug, which we expect to cause other failures...
+                *
+                * Since CPU can perform speculative reads on error capture
+                * (write-combining allows it) add scratch page after error
+                * capture to avoid DMAR errors.
                 */
-               ggtt->error_capture.size = I915_GTT_PAGE_SIZE;
+               ggtt->error_capture.size = 2 * I915_GTT_PAGE_SIZE;
                ggtt->error_capture.color = I915_COLOR_UNEVICTABLE;
                if (drm_mm_reserve_node(&ggtt->vm.mm, &ggtt->error_capture))
                        drm_mm_insert_node_in_range(&ggtt->vm.mm,
@@ -562,11 +587,15 @@ static int init_ggtt(struct i915_ggtt *ggtt)
                                                    0, ggtt->mappable_end,
                                                    DRM_MM_INSERT_LOW);
        }
-       if (drm_mm_node_allocated(&ggtt->error_capture))
+       if (drm_mm_node_allocated(&ggtt->error_capture)) {
+               u64 start = ggtt->error_capture.start;
+               u64 size = ggtt->error_capture.size;
+
+               ggtt->vm.scratch_range(&ggtt->vm, start, size);
                drm_dbg(&ggtt->vm.i915->drm,
                        "Reserved GGTT:[%llx, %llx] for use by error capture\n",
-                       ggtt->error_capture.start,
-                       ggtt->error_capture.start + ggtt->error_capture.size);
+                       start, start + size);
+       }
 
        /*
         * The upper portion of the GuC address space has a sizeable hole
@@ -919,6 +948,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
        ggtt->vm.cleanup = gen6_gmch_remove;
        ggtt->vm.insert_page = gen8_ggtt_insert_page;
        ggtt->vm.clear_range = nop_clear_range;
+       ggtt->vm.scratch_range = gen8_ggtt_clear_range;
 
        ggtt->vm.insert_entries = gen8_ggtt_insert_entries;
 
@@ -1082,6 +1112,7 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt)
        ggtt->vm.clear_range = nop_clear_range;
        if (!HAS_FULL_PPGTT(i915))
                ggtt->vm.clear_range = gen6_ggtt_clear_range;
+       ggtt->vm.scratch_range = gen6_ggtt_clear_range;
        ggtt->vm.insert_page = gen6_ggtt_insert_page;
        ggtt->vm.insert_entries = gen6_ggtt_insert_entries;
        ggtt->vm.cleanup = gen6_gmch_remove;
@@ -1257,6 +1288,10 @@ void i915_ggtt_resume(struct i915_ggtt *ggtt)
 
        flush = i915_ggtt_resume_vm(&ggtt->vm);
 
+       if (drm_mm_node_allocated(&ggtt->error_capture))
+               ggtt->vm.scratch_range(&ggtt->vm, ggtt->error_capture.start,
+                                      ggtt->error_capture.size);
+
        ggtt->invalidate(ggtt);
 
        if (flush)