@@ -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);
@@ -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;
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(-)