[PATCH 08/10] drm/i915/gtt: Recursive ppgtt clear for gen8
Chris Wilson
chris at chris-wilson.co.uk
Sat Jul 6 14:52:35 UTC 2019
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
drivers/gpu/drm/i915/i915_gem_gtt.c | 121 ++++++++++++----------------
1 file changed, 50 insertions(+), 71 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 2a541088f547..8725b4817ee0 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -922,93 +922,72 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
gen8_free_scratch(vm);
}
-/* Removes entries from a single page table, releasing it if it's empty.
- * Caller can use the return value to update higher-level entries.
- */
-static void gen8_ppgtt_clear_pt(const struct i915_address_space *vm,
- struct i915_page_table *pt,
- u64 start, u64 length)
+static void __gen8_ppgtt_clear(struct i915_address_space *vm,
+ struct i915_page_directory * const pd,
+ u64 *start, u64 *length, int lvl)
{
- const unsigned int num_entries = gen8_pte_count(start, length);
- gen8_pte_t *vaddr;
+ struct i915_page_dma * const scratch = &vm->scratch[lvl];
+ unsigned int idx, len;
- vaddr = kmap_atomic_px(pt);
- memset64(vaddr + gen8_pte_index(start), vm->scratch_pte, num_entries);
- kunmap_atomic(vaddr);
+ len = gen8_pd_range(*start, *length, lvl, &idx);
+ GEM_BUG_ON(len > atomic_read(px_used(pd)));
- GEM_BUG_ON(num_entries > atomic_read(&pt->used));
+ if (!lvl) {
+ u64 *vaddr;
- atomic_sub(num_entries, &pt->used);
-}
+ vaddr = kmap_atomic_px(pd);
+ memset64(vaddr + idx, vm->scratch_pte, len);
+ kunmap_atomic(vaddr);
-static void gen8_ppgtt_clear_pd(struct i915_address_space *vm,
- struct i915_page_directory *pd,
- u64 start, u64 length)
-{
- struct i915_page_table *pt;
- u32 pde;
+ atomic_sub(len, px_used(pd));
+ *start += len << gen8_pd_shift(lvl);
+ *length -= len << gen8_pd_shift(lvl);
+ return;
+ }
- gen8_for_each_pde(pt, pd, start, length, pde) {
- GEM_BUG_ON(px_base(pt) == &vm->scratch[1]);
+ do {
+ struct i915_page_table *pt = pd->entry[idx];
+
+ GEM_BUG_ON(pd->entry[idx] == scratch);
+
+ if (*length >= gen8_pd_size(lvl) && /* i.e. uncontended */
+ atomic_read(&pt->used) == I915_PDES) {
+ clear_pd_entry(pd, idx, scratch);
+ __gen8_ppgtt_cleanup(vm, as_pd(pt), I915_PDES, lvl - 1);
+ *start += gen8_pd_size(lvl);
+ *length -= gen8_pd_size(lvl);
+ continue;
+ }
atomic_inc(&pt->used);
- gen8_ppgtt_clear_pt(vm, pt, start, length);
- if (release_pd_entry(pd, pde, pt, &vm->scratch[1]))
- free_px(vm, pt);
- }
+ __gen8_ppgtt_clear(vm, as_pd(pt), start, length, lvl - 1);
+ if (release_pd_entry(pd, idx, pt, scratch))
+ free_pd(vm, px_base(pt));
+ } while (idx++, --len);
}
-/* Removes entries from a single page dir pointer, releasing it if it's empty.
- * Caller can use the return value to update higher-level entries
- */
-static void gen8_ppgtt_clear_pdp(struct i915_address_space *vm,
- struct i915_page_directory * const pdp,
- u64 start, u64 length)
+static void gen8_ppgtt_clear(struct i915_address_space *vm,
+ u64 start, u64 length)
{
- struct i915_page_directory *pd;
- unsigned int pdpe;
-
- gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
- GEM_BUG_ON(px_base(pd) == &vm->scratch[2]);
-
- atomic_inc(px_used(pd));
- gen8_ppgtt_clear_pd(vm, pd, start, length);
- if (release_pd_entry(pdp, pdpe, &pd->pt, &vm->scratch[2]))
- free_px(vm, pd);
- }
+ __gen8_ppgtt_clear(vm, i915_vm_to_ppgtt(vm)->pd,
+ &start, &length, vm->top);
+ GEM_BUG_ON(length);
}
-static void gen8_ppgtt_clear_3lvl(struct i915_address_space *vm,
- u64 start, u64 length)
+static void gen8_ppgtt_clear_pd(struct i915_address_space *vm,
+ struct i915_page_directory *pd,
+ u64 start, u64 length)
{
- gen8_ppgtt_clear_pdp(vm, i915_vm_to_ppgtt(vm)->pd, start, length);
+ __gen8_ppgtt_clear(vm, pd, &start, &length, 1);
}
-/* Removes entries from a single pml4.
- * This is the top-level structure in 4-level page tables used on gen8+.
- * Empty entries are always scratch pml4e.
- */
-static void gen8_ppgtt_clear_4lvl(struct i915_address_space *vm,
- u64 start, u64 length)
+static void gen8_ppgtt_clear_pdp(struct i915_address_space *vm,
+ struct i915_page_directory * const pdp,
+ u64 start, u64 length)
{
- struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
- struct i915_page_directory * const pml4 = ppgtt->pd;
- struct i915_page_directory *pdp;
- unsigned int pml4e;
-
- GEM_BUG_ON(!i915_vm_is_4lvl(vm));
-
- gen8_for_each_pml4e(pdp, pml4, start, length, pml4e) {
- GEM_BUG_ON(px_base(pdp) == &vm->scratch[3]);
-
- atomic_inc(px_used(pdp));
- gen8_ppgtt_clear_pdp(vm, pdp, start, length);
- if (release_pd_entry(pml4, pml4e, &pdp->pt, &vm->scratch[3]))
- free_px(vm, pdp);
- }
+ __gen8_ppgtt_clear(vm, pdp, &start, &length, 2);
}
-
static int gen8_ppgtt_alloc_pd(struct i915_address_space *vm,
struct i915_page_directory *pd,
u64 start, u64 length)
@@ -1171,7 +1150,7 @@ static int gen8_ppgtt_alloc_4lvl(struct i915_address_space *vm,
if (release_pd_entry(pml4, pml4e, &pdp->pt, &vm->scratch[3]))
free_px(vm, pdp);
unwind:
- gen8_ppgtt_clear_4lvl(vm, from, start - from);
+ gen8_ppgtt_clear(vm, from, start - from);
out:
if (alloc)
free_px(vm, alloc);
@@ -1604,7 +1583,6 @@ static struct i915_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915)
if (i915_vm_is_4lvl(&ppgtt->vm)) {
ppgtt->vm.allocate_va_range = gen8_ppgtt_alloc_4lvl;
ppgtt->vm.insert_entries = gen8_ppgtt_insert_4lvl;
- ppgtt->vm.clear_range = gen8_ppgtt_clear_4lvl;
} else {
if (intel_vgpu_active(i915)) {
err = gen8_preallocate_top_level_pdp(ppgtt);
@@ -1614,9 +1592,10 @@ static struct i915_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915)
ppgtt->vm.allocate_va_range = gen8_ppgtt_alloc_3lvl;
ppgtt->vm.insert_entries = gen8_ppgtt_insert_3lvl;
- ppgtt->vm.clear_range = gen8_ppgtt_clear_3lvl;
}
+ ppgtt->vm.clear_range = gen8_ppgtt_clear;
+
if (intel_vgpu_active(i915))
gen8_ppgtt_notify_vgt(ppgtt, true);
--
2.20.1
More information about the Intel-gfx-trybot
mailing list