[10/16] drm/i915/gen8: Initialize PDPs

Submitted by Michel Thierry on May 26, 2015, 2:21 p.m.

Details

Message ID 1432650084-24491-11-git-send-email-michel.thierry@intel.com
State New
Headers show

Not browsing as part of any series.

Commit Message

Michel Thierry May 26, 2015, 2:21 p.m.
Similar to PDs, while setting up a page directory pointer, make all entries
of the pdp point to the scratch pdp before mapping (and make all its entries
point to the scratch page); this is to be safe in case of out of bound
access or  proactive prefetch.

Systems without LLC require an explicit flush.

This commit also moves gen8_initialize_pt next to the other initialize
page functions.

v2: Handle scratch_pdp allocation failure correctly, and keep
initialize_px functions together (Akash)

Suggested-by: Akash Goel <akash.goel@intel.com>
Signed-off-by: Michel Thierry <michel.thierry@intel.com>
---
 drivers/gpu/drm/i915/i915_gem_gtt.c | 108 ++++++++++++++++++++++++++++--------
 drivers/gpu/drm/i915/i915_gem_gtt.h |   1 +
 2 files changed, 86 insertions(+), 23 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index dbbf367..df37c84 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -365,24 +365,6 @@  static void unmap_and_free_pt(struct i915_page_table *pt,
 	kfree(pt);
 }
 
-static void gen8_initialize_pt(struct i915_address_space *vm,
-			       struct i915_page_table *pt)
-{
-	gen8_pte_t *pt_vaddr, scratch_pte;
-	int i;
-
-	pt_vaddr = kmap_atomic(pt->page);
-	scratch_pte = gen8_pte_encode(vm->scratch.addr,
-				      I915_CACHE_LLC, true);
-
-	for (i = 0; i < GEN8_PTES; i++)
-		pt_vaddr[i] = scratch_pte;
-
-	if (!HAS_LLC(vm->dev))
-		drm_clflush_virt_range(pt_vaddr, PAGE_SIZE);
-	kunmap_atomic(pt_vaddr);
-}
-
 static struct i915_page_table *alloc_pt_single(struct drm_device *dev)
 {
 	struct i915_page_table *pt;
@@ -521,7 +503,7 @@  i915_page_directory_pointer *alloc_pdp_single(struct i915_hw_ppgtt *ppgtt)
 	if (!pdp)
 		return ERR_PTR(-ENOMEM);
 
-	pdp->page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+	pdp->page = alloc_page(GFP_KERNEL | GFP_DMA32);
 	if (!pdp->page) {
 		kfree(pdp);
 		return ERR_PTR(-ENOMEM);
@@ -761,6 +743,24 @@  static void __gen8_do_map_pt(gen8_pde_t * const pde,
 	*pde = entry;
 }
 
+static void gen8_initialize_pt(struct i915_address_space *vm,
+			       struct i915_page_table *pt)
+{
+	gen8_pte_t *pt_vaddr, scratch_pte;
+	int i;
+
+	pt_vaddr = kmap_atomic(pt->page);
+	scratch_pte = gen8_pte_encode(vm->scratch.addr,
+				      I915_CACHE_LLC, true);
+
+	for (i = 0; i < GEN8_PTES; i++)
+		pt_vaddr[i] = scratch_pte;
+
+	if (!HAS_LLC(vm->dev))
+		drm_clflush_virt_range(pt_vaddr, PAGE_SIZE);
+	kunmap_atomic(pt_vaddr);
+}
+
 static void gen8_initialize_pd(struct i915_address_space *vm,
 			       struct i915_page_directory *pd)
 {
@@ -782,6 +782,55 @@  static void gen8_initialize_pd(struct i915_address_space *vm,
 	kunmap_atomic(page_directory);
 }
 
+static void gen8_initialize_pdp(struct i915_address_space *vm,
+				struct i915_page_directory_pointer *pdp)
+{
+	struct i915_hw_ppgtt *ppgtt =
+			container_of(vm, struct i915_hw_ppgtt, base);
+	gen8_ppgtt_pdpe_t *page_directorypo;
+	struct i915_page_directory *pd;
+	int i;
+
+	page_directorypo = kmap_atomic(pdp->page);
+	pd = (struct i915_page_directory *)ppgtt->scratch_pd;
+	for (i = 0; i < I915_PDPES_PER_PDP(vm->dev); i++) {
+		/* Map the PDPE to the page directory */
+		gen8_ppgtt_pdpe_t entry =
+				gen8_pdpe_encode(vm->dev, pd->daddr, I915_CACHE_LLC);
+		page_directorypo[i] = entry;
+	}
+
+	if (!HAS_LLC(vm->dev))
+		drm_clflush_virt_range(page_directorypo, PAGE_SIZE);
+
+	kunmap_atomic(page_directorypo);
+}
+
+static void gen8_initialize_pml4(struct i915_address_space *vm,
+				 struct i915_pml4 *pml4)
+{
+	struct i915_hw_ppgtt *ppgtt =
+			container_of(vm, struct i915_hw_ppgtt, base);
+	gen8_ppgtt_pml4e_t *page_maplevel4;
+	struct i915_page_directory_pointer *pdp;
+	int i;
+
+	page_maplevel4 = kmap_atomic(pml4->page);
+	pdp = (struct i915_page_directory_pointer *)ppgtt->scratch_pdp;
+	for (i = 0; i < GEN8_PML4ES_PER_PML4; i++) {
+		/* Map the PML4E to the page directory pointer */
+		gen8_ppgtt_pml4e_t entry =
+				gen8_pml4e_encode(vm->dev, pdp->daddr,
+						  I915_CACHE_LLC);
+		page_maplevel4[i] = entry;
+	}
+
+	if (!HAS_LLC(vm->dev))
+		drm_clflush_virt_range(page_maplevel4, PAGE_SIZE);
+
+	kunmap_atomic(page_maplevel4);
+}
+
 static void pml4_fini(struct i915_pml4 *pml4)
 {
 	struct i915_hw_ppgtt *ppgtt =
@@ -795,10 +844,12 @@  static int pml4_init(struct i915_hw_ppgtt *ppgtt)
 {
 	struct i915_pml4 *pml4 = &ppgtt->pml4;
 
-	pml4->page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	pml4->page = alloc_page(GFP_KERNEL | GFP_DMA32);
 	if (!pml4->page)
 		return -ENOMEM;
 
+	gen8_initialize_pml4(&ppgtt->base, pml4);
+
 	i915_dma_map_single(pml4, ppgtt->base.dev);
 
 	return 0;
@@ -913,6 +964,7 @@  static void gen8_ppgtt_cleanup_4lvl(struct i915_hw_ppgtt *ppgtt)
 	}
 
 	pml4_fini(&ppgtt->pml4);
+	unmap_and_free_pdp(ppgtt->scratch_pdp, ppgtt->base.dev);
 }
 
 static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
@@ -1220,12 +1272,12 @@  static int __gen8_alloc_vma_range_4lvl(struct i915_address_space *vm,
 	 * and 4 level code. Just allocate the pdps.
 	 */
 	gen8_for_each_pml4e(pdp, pml4, start, length, temp, pml4e) {
-		if (!pdp) {
-			WARN_ON(test_bit(pml4e, pml4->used_pml4es));
+		if (!test_bit(pml4e, pml4->used_pml4es)) {
 			pdp = alloc_pdp_single(ppgtt);
 			if (IS_ERR(pdp))
 				goto err_out;
 
+			gen8_initialize_pdp(vm, pdp);
 			pml4->pdps[pml4e] = pdp;
 			set_bit(pml4e, new_pdps);
 			trace_i915_page_directory_pointer_entry_alloc(&ppgtt->base, pml4e,
@@ -1301,9 +1353,17 @@  static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 	gen8_initialize_pd(&ppgtt->base, ppgtt->scratch_pd);
 
 	if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
+		ppgtt->scratch_pdp = alloc_pdp_single(ppgtt);
+		if (IS_ERR(ppgtt->scratch_pdp)) {
+			ret = PTR_ERR(ppgtt->scratch_pdp);
+			goto err_out;
+		}
+
+		gen8_initialize_pdp(&ppgtt->base, ppgtt->scratch_pdp);
+
 		ret = pml4_init(ppgtt);
 		if (ret)
-			goto err_out;
+			goto err_pdp_out;
 
 		ppgtt->base.total = 1ULL << 48;
 		ppgtt->switch_mm = gen8_48b_mm_switch;
@@ -1327,6 +1387,8 @@  static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 
 	return 0;
 
+err_pdp_out:
+	unmap_and_free_pdp(ppgtt->scratch_pdp, ppgtt->base.dev);
 err_out:
 	unmap_and_free_pd(ppgtt->scratch_pd, ppgtt->base.dev);
 	unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev);
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index 9af33b2..6e2f39c 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -358,6 +358,7 @@  struct i915_hw_ppgtt {
 
 	struct i915_page_table *scratch_pt;
 	struct i915_page_directory *scratch_pd;
+	struct i915_page_directory_pointer *scratch_pdp;
 
 	struct drm_i915_file_private *file_priv;