@@ -522,27 +522,41 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
}
}
-static void gen8_free_page_tables(struct i915_pagedir *pd, struct drm_device *dev)
+static void gen8_teardown_va_range(struct i915_address_space *vm,
+ uint64_t start, uint64_t length)
{
- int i;
-
- if (!pd->page)
- return;
-
- for (i = 0; i < I915_PDES_PER_PD; i++) {
- free_pt_single(pd->page_tables[i], dev);
- pd->page_tables[i] = NULL;
+ struct i915_hw_ppgtt *ppgtt =
+ container_of(vm, struct i915_hw_ppgtt, base);
+ struct i915_pagedir *pd;
+ struct i915_pagetab *pt;
+ uint64_t temp;
+ uint32_t pdpe, pde;
+
+ gen8_for_each_pdpe(pd, &ppgtt->pdp, start, length, temp, pdpe) {
+ uint64_t pd_len = gen8_clamp_pd(start, length);
+ uint64_t pd_start = start;
+ gen8_for_each_pde(pt, pd, pd_start, pd_len, temp, pde) {
+ free_pt_single(pt, vm->dev);
+ }
+ free_pd_single(pd, vm->dev);
}
}
-static void gen8_ppgtt_free(struct i915_hw_ppgtt *ppgtt)
+/* This function will die soon */
+static void gen8_free_full_pagedir(struct i915_hw_ppgtt *ppgtt, int i)
{
- int i;
+ gen8_teardown_va_range(&ppgtt->base,
+ i << GEN8_PDPE_SHIFT,
+ (1 << GEN8_PDPE_SHIFT));
+}
- for (i = 0; i < ppgtt->num_pd_pages; i++) {
- gen8_free_page_tables(ppgtt->pdp.pagedirs[i], ppgtt->base.dev);
- free_pd_single(ppgtt->pdp.pagedirs[i], ppgtt->base.dev);
- }
+static void gen8_ppgtt_free(struct i915_hw_ppgtt *ppgtt)
+{
+ trace_i915_va_teardown(&ppgtt->base,
+ ppgtt->base.start, ppgtt->base.total,
+ VM_TO_TRACE_NAME(&ppgtt->base));
+ gen8_teardown_va_range(&ppgtt->base,
+ ppgtt->base.start, ppgtt->base.total);
}
static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
@@ -568,7 +582,7 @@ static int gen8_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt)
unwind_out:
while (i--)
- gen8_free_page_tables(ppgtt->pdp.pagedirs[i], ppgtt->base.dev);
+ gen8_free_full_pagedir(ppgtt, i);
return -ENOMEM;
}
@@ -397,6 +397,32 @@ static inline size_t gen6_pde_count(uint32_t addr, uint32_t length)
return i915_pde_count(addr, length, GEN6_PDE_SHIFT);
}
+#define gen8_for_each_pde(pt, pd, start, length, temp, iter) \
+ for (iter = gen8_pde_index(start), pt = (pd)->page_tables[iter]; \
+ length > 0 && iter < I915_PDES_PER_PD; \
+ pt = (pd)->page_tables[++iter], \
+ temp = ALIGN(start+1, 1 << GEN8_PDE_SHIFT) - start, \
+ temp = min(temp, length), \
+ start += temp, length -= temp)
+
+#define gen8_for_each_pdpe(pd, pdp, start, length, temp, iter) \
+ for (iter = gen8_pdpe_index(start), pd = (pdp)->pagedirs[iter]; \
+ length > 0 && iter < GEN8_LEGACY_PDPES; \
+ pd = (pdp)->pagedirs[++iter], \
+ temp = ALIGN(start+1, 1 << GEN8_PDPE_SHIFT) - start, \
+ temp = min(temp, length), \
+ start += temp, length -= temp)
+
+/* Clamp length to the next pagedir boundary */
+static inline uint64_t gen8_clamp_pd(uint64_t start, uint64_t length)
+{
+ uint64_t next_pd = ALIGN(start + 1, 1 << GEN8_PDPE_SHIFT);
+ if (next_pd > (start + length))
+ return length;
+
+ return next_pd - start;
+}
+
static inline uint32_t gen8_pte_index(uint64_t address)
{
return i915_pte_index(address, GEN8_PDE_SHIFT);