@@ -579,27 +579,32 @@ 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 < GEN8_PDES_PER_PAGE; 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);
}
}
-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;
-
- for (i = 0; i < ppgtt->num_pd_pages; i++) {
- gen8_free_page_tables(ppgtt->pdp.pagedir[i], ppgtt->base.dev);
- free_pd_single(ppgtt->pdp.pagedir[i]);
- }
+ gen8_teardown_va_range(&ppgtt->base,
+ i << GEN8_PDPE_SHIFT,
+ (1 << GEN8_PDPE_SHIFT));
}
static void gen8_ppgtt_unmap_pages(struct i915_hw_ppgtt *ppgtt)
@@ -614,19 +619,28 @@ static void gen8_ppgtt_unmap_pages(struct i915_hw_ppgtt *ppgtt)
continue;
pci_unmap_page(hwdev, ppgtt->pdp.pagedir[i]->daddr, PAGE_SIZE,
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_BIDIRECTIONAL);
for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
struct i915_pagedir *pd = ppgtt->pdp.pagedir[i];
- struct i915_pagetab *pt = pd->page_tables[j];
+ struct i915_pagetab *pt = pd->page_tables[j];
dma_addr_t addr = pt->daddr;
if (addr)
pci_unmap_page(hwdev, addr, PAGE_SIZE,
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_BIDIRECTIONAL);
}
}
}
+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)
{
struct i915_hw_ppgtt *ppgtt =
@@ -651,7 +665,7 @@ static int gen8_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt)
unwind_out:
while (i--)
- gen8_free_page_tables(ppgtt->pdp.pagedir[i], ppgtt->base.dev);
+ gen8_free_full_pagedir(ppgtt, i);
return -ENOMEM;
}
@@ -387,6 +387,52 @@ static inline uint32_t gen6_pde_index(uint32_t addr)
return i915_pde_index(addr, 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 < GEN8_PDES_PER_PAGE; \
+ 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)->pagedir[iter]; \
+ length > 0 && iter < GEN8_LEGACY_PDPES; \
+ pd = (pdp)->pagedir[++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);
+}
+
+static inline uint32_t gen8_pde_index(uint64_t address)
+{
+ return i915_pde_index(address, GEN8_PDE_SHIFT);
+}
+
+static inline uint32_t gen8_pdpe_index(uint64_t address)
+{
+ return (address >> GEN8_PDPE_SHIFT) & GEN8_PDPE_MASK;
+}
+
+static inline uint32_t gen8_pml4e_index(uint64_t address)
+{
+ BUG(); /* For 64B */
+}
+
int i915_gem_gtt_init(struct drm_device *dev);
void i915_gem_init_global_gtt(struct drm_device *dev);
void i915_global_gtt_cleanup(struct drm_device *dev);