162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright © 2020 Intel Corporation
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/log2.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "gem/i915_gem_lmem.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "gen8_ppgtt.h"
1162306a36Sopenharmony_ci#include "i915_scatterlist.h"
1262306a36Sopenharmony_ci#include "i915_trace.h"
1362306a36Sopenharmony_ci#include "i915_pvinfo.h"
1462306a36Sopenharmony_ci#include "i915_vgpu.h"
1562306a36Sopenharmony_ci#include "intel_gt.h"
1662306a36Sopenharmony_ci#include "intel_gtt.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic u64 gen8_pde_encode(const dma_addr_t addr,
1962306a36Sopenharmony_ci			   const enum i915_cache_level level)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	u64 pde = addr | GEN8_PAGE_PRESENT | GEN8_PAGE_RW;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	if (level != I915_CACHE_NONE)
2462306a36Sopenharmony_ci		pde |= PPAT_CACHED_PDE;
2562306a36Sopenharmony_ci	else
2662306a36Sopenharmony_ci		pde |= PPAT_UNCACHED;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	return pde;
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic u64 gen8_pte_encode(dma_addr_t addr,
3262306a36Sopenharmony_ci			   unsigned int pat_index,
3362306a36Sopenharmony_ci			   u32 flags)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	gen8_pte_t pte = addr | GEN8_PAGE_PRESENT | GEN8_PAGE_RW;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (unlikely(flags & PTE_READ_ONLY))
3862306a36Sopenharmony_ci		pte &= ~GEN8_PAGE_RW;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	/*
4162306a36Sopenharmony_ci	 * For pre-gen12 platforms pat_index is the same as enum
4262306a36Sopenharmony_ci	 * i915_cache_level, so the switch-case here is still valid.
4362306a36Sopenharmony_ci	 * See translation table defined by LEGACY_CACHELEVEL.
4462306a36Sopenharmony_ci	 */
4562306a36Sopenharmony_ci	switch (pat_index) {
4662306a36Sopenharmony_ci	case I915_CACHE_NONE:
4762306a36Sopenharmony_ci		pte |= PPAT_UNCACHED;
4862306a36Sopenharmony_ci		break;
4962306a36Sopenharmony_ci	case I915_CACHE_WT:
5062306a36Sopenharmony_ci		pte |= PPAT_DISPLAY_ELLC;
5162306a36Sopenharmony_ci		break;
5262306a36Sopenharmony_ci	default:
5362306a36Sopenharmony_ci		pte |= PPAT_CACHED;
5462306a36Sopenharmony_ci		break;
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	return pte;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic u64 gen12_pte_encode(dma_addr_t addr,
6162306a36Sopenharmony_ci			    unsigned int pat_index,
6262306a36Sopenharmony_ci			    u32 flags)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	gen8_pte_t pte = addr | GEN8_PAGE_PRESENT | GEN8_PAGE_RW;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (unlikely(flags & PTE_READ_ONLY))
6762306a36Sopenharmony_ci		pte &= ~GEN8_PAGE_RW;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (flags & PTE_LM)
7062306a36Sopenharmony_ci		pte |= GEN12_PPGTT_PTE_LM;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (pat_index & BIT(0))
7362306a36Sopenharmony_ci		pte |= GEN12_PPGTT_PTE_PAT0;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (pat_index & BIT(1))
7662306a36Sopenharmony_ci		pte |= GEN12_PPGTT_PTE_PAT1;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (pat_index & BIT(2))
7962306a36Sopenharmony_ci		pte |= GEN12_PPGTT_PTE_PAT2;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (pat_index & BIT(3))
8262306a36Sopenharmony_ci		pte |= MTL_PPGTT_PTE_PAT3;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return pte;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic void gen8_ppgtt_notify_vgt(struct i915_ppgtt *ppgtt, bool create)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct drm_i915_private *i915 = ppgtt->vm.i915;
9062306a36Sopenharmony_ci	struct intel_uncore *uncore = ppgtt->vm.gt->uncore;
9162306a36Sopenharmony_ci	enum vgt_g2v_type msg;
9262306a36Sopenharmony_ci	int i;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (create)
9562306a36Sopenharmony_ci		atomic_inc(px_used(ppgtt->pd)); /* never remove */
9662306a36Sopenharmony_ci	else
9762306a36Sopenharmony_ci		atomic_dec(px_used(ppgtt->pd));
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	mutex_lock(&i915->vgpu.lock);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (i915_vm_is_4lvl(&ppgtt->vm)) {
10262306a36Sopenharmony_ci		const u64 daddr = px_dma(ppgtt->pd);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		intel_uncore_write(uncore,
10562306a36Sopenharmony_ci				   vgtif_reg(pdp[0].lo), lower_32_bits(daddr));
10662306a36Sopenharmony_ci		intel_uncore_write(uncore,
10762306a36Sopenharmony_ci				   vgtif_reg(pdp[0].hi), upper_32_bits(daddr));
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		msg = create ?
11062306a36Sopenharmony_ci			VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE :
11162306a36Sopenharmony_ci			VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY;
11262306a36Sopenharmony_ci	} else {
11362306a36Sopenharmony_ci		for (i = 0; i < GEN8_3LVL_PDPES; i++) {
11462306a36Sopenharmony_ci			const u64 daddr = i915_page_dir_dma_addr(ppgtt, i);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci			intel_uncore_write(uncore,
11762306a36Sopenharmony_ci					   vgtif_reg(pdp[i].lo),
11862306a36Sopenharmony_ci					   lower_32_bits(daddr));
11962306a36Sopenharmony_ci			intel_uncore_write(uncore,
12062306a36Sopenharmony_ci					   vgtif_reg(pdp[i].hi),
12162306a36Sopenharmony_ci					   upper_32_bits(daddr));
12262306a36Sopenharmony_ci		}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		msg = create ?
12562306a36Sopenharmony_ci			VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE :
12662306a36Sopenharmony_ci			VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* g2v_notify atomically (via hv trap) consumes the message packet. */
13062306a36Sopenharmony_ci	intel_uncore_write(uncore, vgtif_reg(g2v_notify), msg);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	mutex_unlock(&i915->vgpu.lock);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/* Index shifts into the pagetable are offset by GEN8_PTE_SHIFT [12] */
13662306a36Sopenharmony_ci#define GEN8_PAGE_SIZE (SZ_4K) /* page and page-directory sizes are the same */
13762306a36Sopenharmony_ci#define GEN8_PTE_SHIFT (ilog2(GEN8_PAGE_SIZE))
13862306a36Sopenharmony_ci#define GEN8_PDES (GEN8_PAGE_SIZE / sizeof(u64))
13962306a36Sopenharmony_ci#define gen8_pd_shift(lvl) ((lvl) * ilog2(GEN8_PDES))
14062306a36Sopenharmony_ci#define gen8_pd_index(i, lvl) i915_pde_index((i), gen8_pd_shift(lvl))
14162306a36Sopenharmony_ci#define __gen8_pte_shift(lvl) (GEN8_PTE_SHIFT + gen8_pd_shift(lvl))
14262306a36Sopenharmony_ci#define __gen8_pte_index(a, lvl) i915_pde_index((a), __gen8_pte_shift(lvl))
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#define as_pd(x) container_of((x), typeof(struct i915_page_directory), pt)
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic unsigned int
14762306a36Sopenharmony_cigen8_pd_range(u64 start, u64 end, int lvl, unsigned int *idx)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	const int shift = gen8_pd_shift(lvl);
15062306a36Sopenharmony_ci	const u64 mask = ~0ull << gen8_pd_shift(lvl + 1);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	GEM_BUG_ON(start >= end);
15362306a36Sopenharmony_ci	end += ~mask >> gen8_pd_shift(1);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	*idx = i915_pde_index(start, shift);
15662306a36Sopenharmony_ci	if ((start ^ end) & mask)
15762306a36Sopenharmony_ci		return GEN8_PDES - *idx;
15862306a36Sopenharmony_ci	else
15962306a36Sopenharmony_ci		return i915_pde_index(end, shift) - *idx;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic bool gen8_pd_contains(u64 start, u64 end, int lvl)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	const u64 mask = ~0ull << gen8_pd_shift(lvl + 1);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	GEM_BUG_ON(start >= end);
16762306a36Sopenharmony_ci	return (start ^ end) & mask && (start & ~mask) == 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic unsigned int gen8_pt_count(u64 start, u64 end)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	GEM_BUG_ON(start >= end);
17362306a36Sopenharmony_ci	if ((start ^ end) >> gen8_pd_shift(1))
17462306a36Sopenharmony_ci		return GEN8_PDES - (start & (GEN8_PDES - 1));
17562306a36Sopenharmony_ci	else
17662306a36Sopenharmony_ci		return end - start;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic unsigned int gen8_pd_top_count(const struct i915_address_space *vm)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	unsigned int shift = __gen8_pte_shift(vm->top);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	return (vm->total + (1ull << shift) - 1) >> shift;
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic struct i915_page_directory *
18762306a36Sopenharmony_cigen8_pdp_for_page_index(struct i915_address_space * const vm, const u64 idx)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct i915_ppgtt * const ppgtt = i915_vm_to_ppgtt(vm);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (vm->top == 2)
19262306a36Sopenharmony_ci		return ppgtt->pd;
19362306a36Sopenharmony_ci	else
19462306a36Sopenharmony_ci		return i915_pd_entry(ppgtt->pd, gen8_pd_index(idx, vm->top));
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic struct i915_page_directory *
19862306a36Sopenharmony_cigen8_pdp_for_page_address(struct i915_address_space * const vm, const u64 addr)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	return gen8_pdp_for_page_index(vm, addr >> GEN8_PTE_SHIFT);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic void __gen8_ppgtt_cleanup(struct i915_address_space *vm,
20462306a36Sopenharmony_ci				 struct i915_page_directory *pd,
20562306a36Sopenharmony_ci				 int count, int lvl)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	if (lvl) {
20862306a36Sopenharmony_ci		void **pde = pd->entry;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		do {
21162306a36Sopenharmony_ci			if (!*pde)
21262306a36Sopenharmony_ci				continue;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci			__gen8_ppgtt_cleanup(vm, *pde, GEN8_PDES, lvl - 1);
21562306a36Sopenharmony_ci		} while (pde++, --count);
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	free_px(vm, &pd->pt, lvl);
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic void gen8_ppgtt_cleanup(struct i915_address_space *vm)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (intel_vgpu_active(vm->i915))
22662306a36Sopenharmony_ci		gen8_ppgtt_notify_vgt(ppgtt, false);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (ppgtt->pd)
22962306a36Sopenharmony_ci		__gen8_ppgtt_cleanup(vm, ppgtt->pd,
23062306a36Sopenharmony_ci				     gen8_pd_top_count(vm), vm->top);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	free_scratch(vm);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic u64 __gen8_ppgtt_clear(struct i915_address_space * const vm,
23662306a36Sopenharmony_ci			      struct i915_page_directory * const pd,
23762306a36Sopenharmony_ci			      u64 start, const u64 end, int lvl)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	const struct drm_i915_gem_object * const scratch = vm->scratch[lvl];
24062306a36Sopenharmony_ci	unsigned int idx, len;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	GEM_BUG_ON(end > vm->total >> GEN8_PTE_SHIFT);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	len = gen8_pd_range(start, end, lvl--, &idx);
24562306a36Sopenharmony_ci	DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n",
24662306a36Sopenharmony_ci	    __func__, vm, lvl + 1, start, end,
24762306a36Sopenharmony_ci	    idx, len, atomic_read(px_used(pd)));
24862306a36Sopenharmony_ci	GEM_BUG_ON(!len || len >= atomic_read(px_used(pd)));
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	do {
25162306a36Sopenharmony_ci		struct i915_page_table *pt = pd->entry[idx];
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		if (atomic_fetch_inc(&pt->used) >> gen8_pd_shift(1) &&
25462306a36Sopenharmony_ci		    gen8_pd_contains(start, end, lvl)) {
25562306a36Sopenharmony_ci			DBG("%s(%p):{ lvl:%d, idx:%d, start:%llx, end:%llx } removing pd\n",
25662306a36Sopenharmony_ci			    __func__, vm, lvl + 1, idx, start, end);
25762306a36Sopenharmony_ci			clear_pd_entry(pd, idx, scratch);
25862306a36Sopenharmony_ci			__gen8_ppgtt_cleanup(vm, as_pd(pt), I915_PDES, lvl);
25962306a36Sopenharmony_ci			start += (u64)I915_PDES << gen8_pd_shift(lvl);
26062306a36Sopenharmony_ci			continue;
26162306a36Sopenharmony_ci		}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		if (lvl) {
26462306a36Sopenharmony_ci			start = __gen8_ppgtt_clear(vm, as_pd(pt),
26562306a36Sopenharmony_ci						   start, end, lvl);
26662306a36Sopenharmony_ci		} else {
26762306a36Sopenharmony_ci			unsigned int count;
26862306a36Sopenharmony_ci			unsigned int pte = gen8_pd_index(start, 0);
26962306a36Sopenharmony_ci			unsigned int num_ptes;
27062306a36Sopenharmony_ci			u64 *vaddr;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci			count = gen8_pt_count(start, end);
27362306a36Sopenharmony_ci			DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } removing pte\n",
27462306a36Sopenharmony_ci			    __func__, vm, lvl, start, end,
27562306a36Sopenharmony_ci			    gen8_pd_index(start, 0), count,
27662306a36Sopenharmony_ci			    atomic_read(&pt->used));
27762306a36Sopenharmony_ci			GEM_BUG_ON(!count || count >= atomic_read(&pt->used));
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci			num_ptes = count;
28062306a36Sopenharmony_ci			if (pt->is_compact) {
28162306a36Sopenharmony_ci				GEM_BUG_ON(num_ptes % 16);
28262306a36Sopenharmony_ci				GEM_BUG_ON(pte % 16);
28362306a36Sopenharmony_ci				num_ptes /= 16;
28462306a36Sopenharmony_ci				pte /= 16;
28562306a36Sopenharmony_ci			}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci			vaddr = px_vaddr(pt);
28862306a36Sopenharmony_ci			memset64(vaddr + pte,
28962306a36Sopenharmony_ci				 vm->scratch[0]->encode,
29062306a36Sopenharmony_ci				 num_ptes);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci			atomic_sub(count, &pt->used);
29362306a36Sopenharmony_ci			start += count;
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		if (release_pd_entry(pd, idx, pt, scratch))
29762306a36Sopenharmony_ci			free_px(vm, pt, lvl);
29862306a36Sopenharmony_ci	} while (idx++, --len);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	return start;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic void gen8_ppgtt_clear(struct i915_address_space *vm,
30462306a36Sopenharmony_ci			     u64 start, u64 length)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	GEM_BUG_ON(!IS_ALIGNED(start, BIT_ULL(GEN8_PTE_SHIFT)));
30762306a36Sopenharmony_ci	GEM_BUG_ON(!IS_ALIGNED(length, BIT_ULL(GEN8_PTE_SHIFT)));
30862306a36Sopenharmony_ci	GEM_BUG_ON(range_overflows(start, length, vm->total));
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	start >>= GEN8_PTE_SHIFT;
31162306a36Sopenharmony_ci	length >>= GEN8_PTE_SHIFT;
31262306a36Sopenharmony_ci	GEM_BUG_ON(length == 0);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	__gen8_ppgtt_clear(vm, i915_vm_to_ppgtt(vm)->pd,
31562306a36Sopenharmony_ci			   start, start + length, vm->top);
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic void __gen8_ppgtt_alloc(struct i915_address_space * const vm,
31962306a36Sopenharmony_ci			       struct i915_vm_pt_stash *stash,
32062306a36Sopenharmony_ci			       struct i915_page_directory * const pd,
32162306a36Sopenharmony_ci			       u64 * const start, const u64 end, int lvl)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	unsigned int idx, len;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	GEM_BUG_ON(end > vm->total >> GEN8_PTE_SHIFT);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	len = gen8_pd_range(*start, end, lvl--, &idx);
32862306a36Sopenharmony_ci	DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d }\n",
32962306a36Sopenharmony_ci	    __func__, vm, lvl + 1, *start, end,
33062306a36Sopenharmony_ci	    idx, len, atomic_read(px_used(pd)));
33162306a36Sopenharmony_ci	GEM_BUG_ON(!len || (idx + len - 1) >> gen8_pd_shift(1));
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	spin_lock(&pd->lock);
33462306a36Sopenharmony_ci	GEM_BUG_ON(!atomic_read(px_used(pd))); /* Must be pinned! */
33562306a36Sopenharmony_ci	do {
33662306a36Sopenharmony_ci		struct i915_page_table *pt = pd->entry[idx];
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci		if (!pt) {
33962306a36Sopenharmony_ci			spin_unlock(&pd->lock);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci			DBG("%s(%p):{ lvl:%d, idx:%d } allocating new tree\n",
34262306a36Sopenharmony_ci			    __func__, vm, lvl + 1, idx);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci			pt = stash->pt[!!lvl];
34562306a36Sopenharmony_ci			__i915_gem_object_pin_pages(pt->base);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci			fill_px(pt, vm->scratch[lvl]->encode);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci			spin_lock(&pd->lock);
35062306a36Sopenharmony_ci			if (likely(!pd->entry[idx])) {
35162306a36Sopenharmony_ci				stash->pt[!!lvl] = pt->stash;
35262306a36Sopenharmony_ci				atomic_set(&pt->used, 0);
35362306a36Sopenharmony_ci				set_pd_entry(pd, idx, pt);
35462306a36Sopenharmony_ci			} else {
35562306a36Sopenharmony_ci				pt = pd->entry[idx];
35662306a36Sopenharmony_ci			}
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		if (lvl) {
36062306a36Sopenharmony_ci			atomic_inc(&pt->used);
36162306a36Sopenharmony_ci			spin_unlock(&pd->lock);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci			__gen8_ppgtt_alloc(vm, stash,
36462306a36Sopenharmony_ci					   as_pd(pt), start, end, lvl);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci			spin_lock(&pd->lock);
36762306a36Sopenharmony_ci			atomic_dec(&pt->used);
36862306a36Sopenharmony_ci			GEM_BUG_ON(!atomic_read(&pt->used));
36962306a36Sopenharmony_ci		} else {
37062306a36Sopenharmony_ci			unsigned int count = gen8_pt_count(*start, end);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci			DBG("%s(%p):{ lvl:%d, start:%llx, end:%llx, idx:%d, len:%d, used:%d } inserting pte\n",
37362306a36Sopenharmony_ci			    __func__, vm, lvl, *start, end,
37462306a36Sopenharmony_ci			    gen8_pd_index(*start, 0), count,
37562306a36Sopenharmony_ci			    atomic_read(&pt->used));
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci			atomic_add(count, &pt->used);
37862306a36Sopenharmony_ci			/* All other pdes may be simultaneously removed */
37962306a36Sopenharmony_ci			GEM_BUG_ON(atomic_read(&pt->used) > NALLOC * I915_PDES);
38062306a36Sopenharmony_ci			*start += count;
38162306a36Sopenharmony_ci		}
38262306a36Sopenharmony_ci	} while (idx++, --len);
38362306a36Sopenharmony_ci	spin_unlock(&pd->lock);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic void gen8_ppgtt_alloc(struct i915_address_space *vm,
38762306a36Sopenharmony_ci			     struct i915_vm_pt_stash *stash,
38862306a36Sopenharmony_ci			     u64 start, u64 length)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	GEM_BUG_ON(!IS_ALIGNED(start, BIT_ULL(GEN8_PTE_SHIFT)));
39162306a36Sopenharmony_ci	GEM_BUG_ON(!IS_ALIGNED(length, BIT_ULL(GEN8_PTE_SHIFT)));
39262306a36Sopenharmony_ci	GEM_BUG_ON(range_overflows(start, length, vm->total));
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	start >>= GEN8_PTE_SHIFT;
39562306a36Sopenharmony_ci	length >>= GEN8_PTE_SHIFT;
39662306a36Sopenharmony_ci	GEM_BUG_ON(length == 0);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	__gen8_ppgtt_alloc(vm, stash, i915_vm_to_ppgtt(vm)->pd,
39962306a36Sopenharmony_ci			   &start, start + length, vm->top);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic void __gen8_ppgtt_foreach(struct i915_address_space *vm,
40362306a36Sopenharmony_ci				 struct i915_page_directory *pd,
40462306a36Sopenharmony_ci				 u64 *start, u64 end, int lvl,
40562306a36Sopenharmony_ci				 void (*fn)(struct i915_address_space *vm,
40662306a36Sopenharmony_ci					    struct i915_page_table *pt,
40762306a36Sopenharmony_ci					    void *data),
40862306a36Sopenharmony_ci				 void *data)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	unsigned int idx, len;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	len = gen8_pd_range(*start, end, lvl--, &idx);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	spin_lock(&pd->lock);
41562306a36Sopenharmony_ci	do {
41662306a36Sopenharmony_ci		struct i915_page_table *pt = pd->entry[idx];
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		atomic_inc(&pt->used);
41962306a36Sopenharmony_ci		spin_unlock(&pd->lock);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		if (lvl) {
42262306a36Sopenharmony_ci			__gen8_ppgtt_foreach(vm, as_pd(pt), start, end, lvl,
42362306a36Sopenharmony_ci					     fn, data);
42462306a36Sopenharmony_ci		} else {
42562306a36Sopenharmony_ci			fn(vm, pt, data);
42662306a36Sopenharmony_ci			*start += gen8_pt_count(*start, end);
42762306a36Sopenharmony_ci		}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci		spin_lock(&pd->lock);
43062306a36Sopenharmony_ci		atomic_dec(&pt->used);
43162306a36Sopenharmony_ci	} while (idx++, --len);
43262306a36Sopenharmony_ci	spin_unlock(&pd->lock);
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic void gen8_ppgtt_foreach(struct i915_address_space *vm,
43662306a36Sopenharmony_ci			       u64 start, u64 length,
43762306a36Sopenharmony_ci			       void (*fn)(struct i915_address_space *vm,
43862306a36Sopenharmony_ci					  struct i915_page_table *pt,
43962306a36Sopenharmony_ci					  void *data),
44062306a36Sopenharmony_ci			       void *data)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	start >>= GEN8_PTE_SHIFT;
44362306a36Sopenharmony_ci	length >>= GEN8_PTE_SHIFT;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	__gen8_ppgtt_foreach(vm, i915_vm_to_ppgtt(vm)->pd,
44662306a36Sopenharmony_ci			     &start, start + length, vm->top,
44762306a36Sopenharmony_ci			     fn, data);
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic __always_inline u64
45162306a36Sopenharmony_cigen8_ppgtt_insert_pte(struct i915_ppgtt *ppgtt,
45262306a36Sopenharmony_ci		      struct i915_page_directory *pdp,
45362306a36Sopenharmony_ci		      struct sgt_dma *iter,
45462306a36Sopenharmony_ci		      u64 idx,
45562306a36Sopenharmony_ci		      unsigned int pat_index,
45662306a36Sopenharmony_ci		      u32 flags)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	struct i915_page_directory *pd;
45962306a36Sopenharmony_ci	const gen8_pte_t pte_encode = ppgtt->vm.pte_encode(0, pat_index, flags);
46062306a36Sopenharmony_ci	gen8_pte_t *vaddr;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	pd = i915_pd_entry(pdp, gen8_pd_index(idx, 2));
46362306a36Sopenharmony_ci	vaddr = px_vaddr(i915_pt_entry(pd, gen8_pd_index(idx, 1)));
46462306a36Sopenharmony_ci	do {
46562306a36Sopenharmony_ci		GEM_BUG_ON(sg_dma_len(iter->sg) < I915_GTT_PAGE_SIZE);
46662306a36Sopenharmony_ci		vaddr[gen8_pd_index(idx, 0)] = pte_encode | iter->dma;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		iter->dma += I915_GTT_PAGE_SIZE;
46962306a36Sopenharmony_ci		if (iter->dma >= iter->max) {
47062306a36Sopenharmony_ci			iter->sg = __sg_next(iter->sg);
47162306a36Sopenharmony_ci			if (!iter->sg || sg_dma_len(iter->sg) == 0) {
47262306a36Sopenharmony_ci				idx = 0;
47362306a36Sopenharmony_ci				break;
47462306a36Sopenharmony_ci			}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci			iter->dma = sg_dma_address(iter->sg);
47762306a36Sopenharmony_ci			iter->max = iter->dma + sg_dma_len(iter->sg);
47862306a36Sopenharmony_ci		}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		if (gen8_pd_index(++idx, 0) == 0) {
48162306a36Sopenharmony_ci			if (gen8_pd_index(idx, 1) == 0) {
48262306a36Sopenharmony_ci				/* Limited by sg length for 3lvl */
48362306a36Sopenharmony_ci				if (gen8_pd_index(idx, 2) == 0)
48462306a36Sopenharmony_ci					break;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci				pd = pdp->entry[gen8_pd_index(idx, 2)];
48762306a36Sopenharmony_ci			}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci			drm_clflush_virt_range(vaddr, PAGE_SIZE);
49062306a36Sopenharmony_ci			vaddr = px_vaddr(i915_pt_entry(pd, gen8_pd_index(idx, 1)));
49162306a36Sopenharmony_ci		}
49262306a36Sopenharmony_ci	} while (1);
49362306a36Sopenharmony_ci	drm_clflush_virt_range(vaddr, PAGE_SIZE);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	return idx;
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic void
49962306a36Sopenharmony_cixehpsdv_ppgtt_insert_huge(struct i915_address_space *vm,
50062306a36Sopenharmony_ci			  struct i915_vma_resource *vma_res,
50162306a36Sopenharmony_ci			  struct sgt_dma *iter,
50262306a36Sopenharmony_ci			  unsigned int pat_index,
50362306a36Sopenharmony_ci			  u32 flags)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	const gen8_pte_t pte_encode = vm->pte_encode(0, pat_index, flags);
50662306a36Sopenharmony_ci	unsigned int rem = sg_dma_len(iter->sg);
50762306a36Sopenharmony_ci	u64 start = vma_res->start;
50862306a36Sopenharmony_ci	u64 end = start + vma_res->vma_size;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	GEM_BUG_ON(!i915_vm_is_4lvl(vm));
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	do {
51362306a36Sopenharmony_ci		struct i915_page_directory * const pdp =
51462306a36Sopenharmony_ci			gen8_pdp_for_page_address(vm, start);
51562306a36Sopenharmony_ci		struct i915_page_directory * const pd =
51662306a36Sopenharmony_ci			i915_pd_entry(pdp, __gen8_pte_index(start, 2));
51762306a36Sopenharmony_ci		struct i915_page_table *pt =
51862306a36Sopenharmony_ci			i915_pt_entry(pd, __gen8_pte_index(start, 1));
51962306a36Sopenharmony_ci		gen8_pte_t encode = pte_encode;
52062306a36Sopenharmony_ci		unsigned int page_size;
52162306a36Sopenharmony_ci		gen8_pte_t *vaddr;
52262306a36Sopenharmony_ci		u16 index, max, nent, i;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci		max = I915_PDES;
52562306a36Sopenharmony_ci		nent = 1;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_2M &&
52862306a36Sopenharmony_ci		    IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_2M) &&
52962306a36Sopenharmony_ci		    rem >= I915_GTT_PAGE_SIZE_2M &&
53062306a36Sopenharmony_ci		    !__gen8_pte_index(start, 0)) {
53162306a36Sopenharmony_ci			index = __gen8_pte_index(start, 1);
53262306a36Sopenharmony_ci			encode |= GEN8_PDE_PS_2M;
53362306a36Sopenharmony_ci			page_size = I915_GTT_PAGE_SIZE_2M;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci			vaddr = px_vaddr(pd);
53662306a36Sopenharmony_ci		} else {
53762306a36Sopenharmony_ci			index =  __gen8_pte_index(start, 0);
53862306a36Sopenharmony_ci			page_size = I915_GTT_PAGE_SIZE;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci			if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_64K) {
54162306a36Sopenharmony_ci				/*
54262306a36Sopenharmony_ci				 * Device local-memory on these platforms should
54362306a36Sopenharmony_ci				 * always use 64K pages or larger (including GTT
54462306a36Sopenharmony_ci				 * alignment), therefore if we know the whole
54562306a36Sopenharmony_ci				 * page-table needs to be filled we can always
54662306a36Sopenharmony_ci				 * safely use the compact-layout. Otherwise fall
54762306a36Sopenharmony_ci				 * back to the TLB hint with PS64. If this is
54862306a36Sopenharmony_ci				 * system memory we only bother with PS64.
54962306a36Sopenharmony_ci				 */
55062306a36Sopenharmony_ci				if ((encode & GEN12_PPGTT_PTE_LM) &&
55162306a36Sopenharmony_ci				    end - start >= SZ_2M && !index) {
55262306a36Sopenharmony_ci					index = __gen8_pte_index(start, 0) / 16;
55362306a36Sopenharmony_ci					page_size = I915_GTT_PAGE_SIZE_64K;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci					max /= 16;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci					vaddr = px_vaddr(pd);
55862306a36Sopenharmony_ci					vaddr[__gen8_pte_index(start, 1)] |= GEN12_PDE_64K;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci					pt->is_compact = true;
56162306a36Sopenharmony_ci				} else if (IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
56262306a36Sopenharmony_ci					   rem >= I915_GTT_PAGE_SIZE_64K &&
56362306a36Sopenharmony_ci					   !(index % 16)) {
56462306a36Sopenharmony_ci					encode |= GEN12_PTE_PS64;
56562306a36Sopenharmony_ci					page_size = I915_GTT_PAGE_SIZE_64K;
56662306a36Sopenharmony_ci					nent = 16;
56762306a36Sopenharmony_ci				}
56862306a36Sopenharmony_ci			}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci			vaddr = px_vaddr(pt);
57162306a36Sopenharmony_ci		}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci		do {
57462306a36Sopenharmony_ci			GEM_BUG_ON(rem < page_size);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci			for (i = 0; i < nent; i++) {
57762306a36Sopenharmony_ci				vaddr[index++] =
57862306a36Sopenharmony_ci					encode | (iter->dma + i *
57962306a36Sopenharmony_ci						  I915_GTT_PAGE_SIZE);
58062306a36Sopenharmony_ci			}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci			start += page_size;
58362306a36Sopenharmony_ci			iter->dma += page_size;
58462306a36Sopenharmony_ci			rem -= page_size;
58562306a36Sopenharmony_ci			if (iter->dma >= iter->max) {
58662306a36Sopenharmony_ci				iter->sg = __sg_next(iter->sg);
58762306a36Sopenharmony_ci				if (!iter->sg)
58862306a36Sopenharmony_ci					break;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci				rem = sg_dma_len(iter->sg);
59162306a36Sopenharmony_ci				if (!rem)
59262306a36Sopenharmony_ci					break;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci				iter->dma = sg_dma_address(iter->sg);
59562306a36Sopenharmony_ci				iter->max = iter->dma + rem;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci				if (unlikely(!IS_ALIGNED(iter->dma, page_size)))
59862306a36Sopenharmony_ci					break;
59962306a36Sopenharmony_ci			}
60062306a36Sopenharmony_ci		} while (rem >= page_size && index < max);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		drm_clflush_virt_range(vaddr, PAGE_SIZE);
60362306a36Sopenharmony_ci		vma_res->page_sizes_gtt |= page_size;
60462306a36Sopenharmony_ci	} while (iter->sg && sg_dma_len(iter->sg));
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic void gen8_ppgtt_insert_huge(struct i915_address_space *vm,
60862306a36Sopenharmony_ci				   struct i915_vma_resource *vma_res,
60962306a36Sopenharmony_ci				   struct sgt_dma *iter,
61062306a36Sopenharmony_ci				   unsigned int pat_index,
61162306a36Sopenharmony_ci				   u32 flags)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	const gen8_pte_t pte_encode = vm->pte_encode(0, pat_index, flags);
61462306a36Sopenharmony_ci	unsigned int rem = sg_dma_len(iter->sg);
61562306a36Sopenharmony_ci	u64 start = vma_res->start;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	GEM_BUG_ON(!i915_vm_is_4lvl(vm));
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	do {
62062306a36Sopenharmony_ci		struct i915_page_directory * const pdp =
62162306a36Sopenharmony_ci			gen8_pdp_for_page_address(vm, start);
62262306a36Sopenharmony_ci		struct i915_page_directory * const pd =
62362306a36Sopenharmony_ci			i915_pd_entry(pdp, __gen8_pte_index(start, 2));
62462306a36Sopenharmony_ci		gen8_pte_t encode = pte_encode;
62562306a36Sopenharmony_ci		unsigned int maybe_64K = -1;
62662306a36Sopenharmony_ci		unsigned int page_size;
62762306a36Sopenharmony_ci		gen8_pte_t *vaddr;
62862306a36Sopenharmony_ci		u16 index;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci		if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_2M &&
63162306a36Sopenharmony_ci		    IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_2M) &&
63262306a36Sopenharmony_ci		    rem >= I915_GTT_PAGE_SIZE_2M &&
63362306a36Sopenharmony_ci		    !__gen8_pte_index(start, 0)) {
63462306a36Sopenharmony_ci			index = __gen8_pte_index(start, 1);
63562306a36Sopenharmony_ci			encode |= GEN8_PDE_PS_2M;
63662306a36Sopenharmony_ci			page_size = I915_GTT_PAGE_SIZE_2M;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci			vaddr = px_vaddr(pd);
63962306a36Sopenharmony_ci		} else {
64062306a36Sopenharmony_ci			struct i915_page_table *pt =
64162306a36Sopenharmony_ci				i915_pt_entry(pd, __gen8_pte_index(start, 1));
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci			index = __gen8_pte_index(start, 0);
64462306a36Sopenharmony_ci			page_size = I915_GTT_PAGE_SIZE;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci			if (!index &&
64762306a36Sopenharmony_ci			    vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_64K &&
64862306a36Sopenharmony_ci			    IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
64962306a36Sopenharmony_ci			    (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
65062306a36Sopenharmony_ci			     rem >= (I915_PDES - index) * I915_GTT_PAGE_SIZE))
65162306a36Sopenharmony_ci				maybe_64K = __gen8_pte_index(start, 1);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci			vaddr = px_vaddr(pt);
65462306a36Sopenharmony_ci		}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci		do {
65762306a36Sopenharmony_ci			GEM_BUG_ON(sg_dma_len(iter->sg) < page_size);
65862306a36Sopenharmony_ci			vaddr[index++] = encode | iter->dma;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci			start += page_size;
66162306a36Sopenharmony_ci			iter->dma += page_size;
66262306a36Sopenharmony_ci			rem -= page_size;
66362306a36Sopenharmony_ci			if (iter->dma >= iter->max) {
66462306a36Sopenharmony_ci				iter->sg = __sg_next(iter->sg);
66562306a36Sopenharmony_ci				if (!iter->sg)
66662306a36Sopenharmony_ci					break;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci				rem = sg_dma_len(iter->sg);
66962306a36Sopenharmony_ci				if (!rem)
67062306a36Sopenharmony_ci					break;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci				iter->dma = sg_dma_address(iter->sg);
67362306a36Sopenharmony_ci				iter->max = iter->dma + rem;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci				if (maybe_64K != -1 && index < I915_PDES &&
67662306a36Sopenharmony_ci				    !(IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
67762306a36Sopenharmony_ci				      (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
67862306a36Sopenharmony_ci				       rem >= (I915_PDES - index) * I915_GTT_PAGE_SIZE)))
67962306a36Sopenharmony_ci					maybe_64K = -1;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci				if (unlikely(!IS_ALIGNED(iter->dma, page_size)))
68262306a36Sopenharmony_ci					break;
68362306a36Sopenharmony_ci			}
68462306a36Sopenharmony_ci		} while (rem >= page_size && index < I915_PDES);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		drm_clflush_virt_range(vaddr, PAGE_SIZE);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		/*
68962306a36Sopenharmony_ci		 * Is it safe to mark the 2M block as 64K? -- Either we have
69062306a36Sopenharmony_ci		 * filled whole page-table with 64K entries, or filled part of
69162306a36Sopenharmony_ci		 * it and have reached the end of the sg table and we have
69262306a36Sopenharmony_ci		 * enough padding.
69362306a36Sopenharmony_ci		 */
69462306a36Sopenharmony_ci		if (maybe_64K != -1 &&
69562306a36Sopenharmony_ci		    (index == I915_PDES ||
69662306a36Sopenharmony_ci		     (i915_vm_has_scratch_64K(vm) &&
69762306a36Sopenharmony_ci		      !iter->sg && IS_ALIGNED(vma_res->start +
69862306a36Sopenharmony_ci					      vma_res->node_size,
69962306a36Sopenharmony_ci					      I915_GTT_PAGE_SIZE_2M)))) {
70062306a36Sopenharmony_ci			vaddr = px_vaddr(pd);
70162306a36Sopenharmony_ci			vaddr[maybe_64K] |= GEN8_PDE_IPS_64K;
70262306a36Sopenharmony_ci			drm_clflush_virt_range(vaddr, PAGE_SIZE);
70362306a36Sopenharmony_ci			page_size = I915_GTT_PAGE_SIZE_64K;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci			/*
70662306a36Sopenharmony_ci			 * We write all 4K page entries, even when using 64K
70762306a36Sopenharmony_ci			 * pages. In order to verify that the HW isn't cheating
70862306a36Sopenharmony_ci			 * by using the 4K PTE instead of the 64K PTE, we want
70962306a36Sopenharmony_ci			 * to remove all the surplus entries. If the HW skipped
71062306a36Sopenharmony_ci			 * the 64K PTE, it will read/write into the scratch page
71162306a36Sopenharmony_ci			 * instead - which we detect as missing results during
71262306a36Sopenharmony_ci			 * selftests.
71362306a36Sopenharmony_ci			 */
71462306a36Sopenharmony_ci			if (I915_SELFTEST_ONLY(vm->scrub_64K)) {
71562306a36Sopenharmony_ci				u16 i;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci				encode = vm->scratch[0]->encode;
71862306a36Sopenharmony_ci				vaddr = px_vaddr(i915_pt_entry(pd, maybe_64K));
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci				for (i = 1; i < index; i += 16)
72162306a36Sopenharmony_ci					memset64(vaddr + i, encode, 15);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci				drm_clflush_virt_range(vaddr, PAGE_SIZE);
72462306a36Sopenharmony_ci			}
72562306a36Sopenharmony_ci		}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci		vma_res->page_sizes_gtt |= page_size;
72862306a36Sopenharmony_ci	} while (iter->sg && sg_dma_len(iter->sg));
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic void gen8_ppgtt_insert(struct i915_address_space *vm,
73262306a36Sopenharmony_ci			      struct i915_vma_resource *vma_res,
73362306a36Sopenharmony_ci			      unsigned int pat_index,
73462306a36Sopenharmony_ci			      u32 flags)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	struct i915_ppgtt * const ppgtt = i915_vm_to_ppgtt(vm);
73762306a36Sopenharmony_ci	struct sgt_dma iter = sgt_dma(vma_res);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	if (vma_res->bi.page_sizes.sg > I915_GTT_PAGE_SIZE) {
74062306a36Sopenharmony_ci		if (GRAPHICS_VER_FULL(vm->i915) >= IP_VER(12, 50))
74162306a36Sopenharmony_ci			xehpsdv_ppgtt_insert_huge(vm, vma_res, &iter, pat_index, flags);
74262306a36Sopenharmony_ci		else
74362306a36Sopenharmony_ci			gen8_ppgtt_insert_huge(vm, vma_res, &iter, pat_index, flags);
74462306a36Sopenharmony_ci	} else  {
74562306a36Sopenharmony_ci		u64 idx = vma_res->start >> GEN8_PTE_SHIFT;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		do {
74862306a36Sopenharmony_ci			struct i915_page_directory * const pdp =
74962306a36Sopenharmony_ci				gen8_pdp_for_page_index(vm, idx);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci			idx = gen8_ppgtt_insert_pte(ppgtt, pdp, &iter, idx,
75262306a36Sopenharmony_ci						    pat_index, flags);
75362306a36Sopenharmony_ci		} while (idx);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		vma_res->page_sizes_gtt = I915_GTT_PAGE_SIZE;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_cistatic void gen8_ppgtt_insert_entry(struct i915_address_space *vm,
76062306a36Sopenharmony_ci				    dma_addr_t addr,
76162306a36Sopenharmony_ci				    u64 offset,
76262306a36Sopenharmony_ci				    unsigned int pat_index,
76362306a36Sopenharmony_ci				    u32 flags)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	u64 idx = offset >> GEN8_PTE_SHIFT;
76662306a36Sopenharmony_ci	struct i915_page_directory * const pdp =
76762306a36Sopenharmony_ci		gen8_pdp_for_page_index(vm, idx);
76862306a36Sopenharmony_ci	struct i915_page_directory *pd =
76962306a36Sopenharmony_ci		i915_pd_entry(pdp, gen8_pd_index(idx, 2));
77062306a36Sopenharmony_ci	struct i915_page_table *pt = i915_pt_entry(pd, gen8_pd_index(idx, 1));
77162306a36Sopenharmony_ci	gen8_pte_t *vaddr;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	GEM_BUG_ON(pt->is_compact);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	vaddr = px_vaddr(pt);
77662306a36Sopenharmony_ci	vaddr[gen8_pd_index(idx, 0)] = vm->pte_encode(addr, pat_index, flags);
77762306a36Sopenharmony_ci	drm_clflush_virt_range(&vaddr[gen8_pd_index(idx, 0)], sizeof(*vaddr));
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic void __xehpsdv_ppgtt_insert_entry_lm(struct i915_address_space *vm,
78162306a36Sopenharmony_ci					    dma_addr_t addr,
78262306a36Sopenharmony_ci					    u64 offset,
78362306a36Sopenharmony_ci					    unsigned int pat_index,
78462306a36Sopenharmony_ci					    u32 flags)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	u64 idx = offset >> GEN8_PTE_SHIFT;
78762306a36Sopenharmony_ci	struct i915_page_directory * const pdp =
78862306a36Sopenharmony_ci		gen8_pdp_for_page_index(vm, idx);
78962306a36Sopenharmony_ci	struct i915_page_directory *pd =
79062306a36Sopenharmony_ci		i915_pd_entry(pdp, gen8_pd_index(idx, 2));
79162306a36Sopenharmony_ci	struct i915_page_table *pt = i915_pt_entry(pd, gen8_pd_index(idx, 1));
79262306a36Sopenharmony_ci	gen8_pte_t *vaddr;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	GEM_BUG_ON(!IS_ALIGNED(addr, SZ_64K));
79562306a36Sopenharmony_ci	GEM_BUG_ON(!IS_ALIGNED(offset, SZ_64K));
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	/* XXX: we don't strictly need to use this layout */
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (!pt->is_compact) {
80062306a36Sopenharmony_ci		vaddr = px_vaddr(pd);
80162306a36Sopenharmony_ci		vaddr[gen8_pd_index(idx, 1)] |= GEN12_PDE_64K;
80262306a36Sopenharmony_ci		pt->is_compact = true;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	vaddr = px_vaddr(pt);
80662306a36Sopenharmony_ci	vaddr[gen8_pd_index(idx, 0) / 16] = vm->pte_encode(addr, pat_index, flags);
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cistatic void xehpsdv_ppgtt_insert_entry(struct i915_address_space *vm,
81062306a36Sopenharmony_ci				       dma_addr_t addr,
81162306a36Sopenharmony_ci				       u64 offset,
81262306a36Sopenharmony_ci				       unsigned int pat_index,
81362306a36Sopenharmony_ci				       u32 flags)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	if (flags & PTE_LM)
81662306a36Sopenharmony_ci		return __xehpsdv_ppgtt_insert_entry_lm(vm, addr, offset,
81762306a36Sopenharmony_ci						       pat_index, flags);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return gen8_ppgtt_insert_entry(vm, addr, offset, pat_index, flags);
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic int gen8_init_scratch(struct i915_address_space *vm)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	u32 pte_flags;
82562306a36Sopenharmony_ci	int ret;
82662306a36Sopenharmony_ci	int i;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	/*
82962306a36Sopenharmony_ci	 * If everybody agrees to not to write into the scratch page,
83062306a36Sopenharmony_ci	 * we can reuse it for all vm, keeping contexts and processes separate.
83162306a36Sopenharmony_ci	 */
83262306a36Sopenharmony_ci	if (vm->has_read_only && vm->gt->vm && !i915_is_ggtt(vm->gt->vm)) {
83362306a36Sopenharmony_ci		struct i915_address_space *clone = vm->gt->vm;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		GEM_BUG_ON(!clone->has_read_only);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		vm->scratch_order = clone->scratch_order;
83862306a36Sopenharmony_ci		for (i = 0; i <= vm->top; i++)
83962306a36Sopenharmony_ci			vm->scratch[i] = i915_gem_object_get(clone->scratch[i]);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci		return 0;
84262306a36Sopenharmony_ci	}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	ret = setup_scratch_page(vm);
84562306a36Sopenharmony_ci	if (ret)
84662306a36Sopenharmony_ci		return ret;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	pte_flags = vm->has_read_only;
84962306a36Sopenharmony_ci	if (i915_gem_object_is_lmem(vm->scratch[0]))
85062306a36Sopenharmony_ci		pte_flags |= PTE_LM;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	vm->scratch[0]->encode =
85362306a36Sopenharmony_ci		vm->pte_encode(px_dma(vm->scratch[0]),
85462306a36Sopenharmony_ci			       i915_gem_get_pat_index(vm->i915,
85562306a36Sopenharmony_ci						      I915_CACHE_NONE),
85662306a36Sopenharmony_ci			       pte_flags);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	for (i = 1; i <= vm->top; i++) {
85962306a36Sopenharmony_ci		struct drm_i915_gem_object *obj;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		obj = vm->alloc_pt_dma(vm, I915_GTT_PAGE_SIZE_4K);
86262306a36Sopenharmony_ci		if (IS_ERR(obj)) {
86362306a36Sopenharmony_ci			ret = PTR_ERR(obj);
86462306a36Sopenharmony_ci			goto free_scratch;
86562306a36Sopenharmony_ci		}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		ret = map_pt_dma(vm, obj);
86862306a36Sopenharmony_ci		if (ret) {
86962306a36Sopenharmony_ci			i915_gem_object_put(obj);
87062306a36Sopenharmony_ci			goto free_scratch;
87162306a36Sopenharmony_ci		}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci		fill_px(obj, vm->scratch[i - 1]->encode);
87462306a36Sopenharmony_ci		obj->encode = gen8_pde_encode(px_dma(obj), I915_CACHE_NONE);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci		vm->scratch[i] = obj;
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	return 0;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_cifree_scratch:
88262306a36Sopenharmony_ci	while (i--)
88362306a36Sopenharmony_ci		i915_gem_object_put(vm->scratch[i]);
88462306a36Sopenharmony_ci	vm->scratch[0] = NULL;
88562306a36Sopenharmony_ci	return ret;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic int gen8_preallocate_top_level_pdp(struct i915_ppgtt *ppgtt)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	struct i915_address_space *vm = &ppgtt->vm;
89162306a36Sopenharmony_ci	struct i915_page_directory *pd = ppgtt->pd;
89262306a36Sopenharmony_ci	unsigned int idx;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	GEM_BUG_ON(vm->top != 2);
89562306a36Sopenharmony_ci	GEM_BUG_ON(gen8_pd_top_count(vm) != GEN8_3LVL_PDPES);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	for (idx = 0; idx < GEN8_3LVL_PDPES; idx++) {
89862306a36Sopenharmony_ci		struct i915_page_directory *pde;
89962306a36Sopenharmony_ci		int err;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		pde = alloc_pd(vm);
90262306a36Sopenharmony_ci		if (IS_ERR(pde))
90362306a36Sopenharmony_ci			return PTR_ERR(pde);
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci		err = map_pt_dma(vm, pde->pt.base);
90662306a36Sopenharmony_ci		if (err) {
90762306a36Sopenharmony_ci			free_pd(vm, pde);
90862306a36Sopenharmony_ci			return err;
90962306a36Sopenharmony_ci		}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci		fill_px(pde, vm->scratch[1]->encode);
91262306a36Sopenharmony_ci		set_pd_entry(pd, idx, pde);
91362306a36Sopenharmony_ci		atomic_inc(px_used(pde)); /* keep pinned */
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci	wmb();
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	return 0;
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_cistatic struct i915_page_directory *
92162306a36Sopenharmony_cigen8_alloc_top_pd(struct i915_address_space *vm)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	const unsigned int count = gen8_pd_top_count(vm);
92462306a36Sopenharmony_ci	struct i915_page_directory *pd;
92562306a36Sopenharmony_ci	int err;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	GEM_BUG_ON(count > I915_PDES);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	pd = __alloc_pd(count);
93062306a36Sopenharmony_ci	if (unlikely(!pd))
93162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	pd->pt.base = vm->alloc_pt_dma(vm, I915_GTT_PAGE_SIZE_4K);
93462306a36Sopenharmony_ci	if (IS_ERR(pd->pt.base)) {
93562306a36Sopenharmony_ci		err = PTR_ERR(pd->pt.base);
93662306a36Sopenharmony_ci		pd->pt.base = NULL;
93762306a36Sopenharmony_ci		goto err_pd;
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	err = map_pt_dma(vm, pd->pt.base);
94162306a36Sopenharmony_ci	if (err)
94262306a36Sopenharmony_ci		goto err_pd;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	fill_page_dma(px_base(pd), vm->scratch[vm->top]->encode, count);
94562306a36Sopenharmony_ci	atomic_inc(px_used(pd)); /* mark as pinned */
94662306a36Sopenharmony_ci	return pd;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_cierr_pd:
94962306a36Sopenharmony_ci	free_pd(vm, pd);
95062306a36Sopenharmony_ci	return ERR_PTR(err);
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci/*
95462306a36Sopenharmony_ci * GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers
95562306a36Sopenharmony_ci * with a net effect resembling a 2-level page table in normal x86 terms. Each
95662306a36Sopenharmony_ci * PDP represents 1GB of memory 4 * 512 * 512 * 4096 = 4GB legacy 32b address
95762306a36Sopenharmony_ci * space.
95862306a36Sopenharmony_ci *
95962306a36Sopenharmony_ci */
96062306a36Sopenharmony_cistruct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt,
96162306a36Sopenharmony_ci				     unsigned long lmem_pt_obj_flags)
96262306a36Sopenharmony_ci{
96362306a36Sopenharmony_ci	struct i915_page_directory *pd;
96462306a36Sopenharmony_ci	struct i915_ppgtt *ppgtt;
96562306a36Sopenharmony_ci	int err;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
96862306a36Sopenharmony_ci	if (!ppgtt)
96962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	ppgtt_init(ppgtt, gt, lmem_pt_obj_flags);
97262306a36Sopenharmony_ci	ppgtt->vm.top = i915_vm_is_4lvl(&ppgtt->vm) ? 3 : 2;
97362306a36Sopenharmony_ci	ppgtt->vm.pd_shift = ilog2(SZ_4K * SZ_4K / sizeof(gen8_pte_t));
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	/*
97662306a36Sopenharmony_ci	 * From bdw, there is hw support for read-only pages in the PPGTT.
97762306a36Sopenharmony_ci	 *
97862306a36Sopenharmony_ci	 * Gen11 has HSDES#:1807136187 unresolved. Disable ro support
97962306a36Sopenharmony_ci	 * for now.
98062306a36Sopenharmony_ci	 *
98162306a36Sopenharmony_ci	 * Gen12 has inherited the same read-only fault issue from gen11.
98262306a36Sopenharmony_ci	 */
98362306a36Sopenharmony_ci	ppgtt->vm.has_read_only = !IS_GRAPHICS_VER(gt->i915, 11, 12);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (HAS_LMEM(gt->i915))
98662306a36Sopenharmony_ci		ppgtt->vm.alloc_pt_dma = alloc_pt_lmem;
98762306a36Sopenharmony_ci	else
98862306a36Sopenharmony_ci		ppgtt->vm.alloc_pt_dma = alloc_pt_dma;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	/*
99162306a36Sopenharmony_ci	 * Using SMEM here instead of LMEM has the advantage of not reserving
99262306a36Sopenharmony_ci	 * high performance memory for a "never" used filler page. It also
99362306a36Sopenharmony_ci	 * removes the device access that would be required to initialise the
99462306a36Sopenharmony_ci	 * scratch page, reducing pressure on an even scarcer resource.
99562306a36Sopenharmony_ci	 */
99662306a36Sopenharmony_ci	ppgtt->vm.alloc_scratch_dma = alloc_pt_dma;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	if (GRAPHICS_VER(gt->i915) >= 12)
99962306a36Sopenharmony_ci		ppgtt->vm.pte_encode = gen12_pte_encode;
100062306a36Sopenharmony_ci	else
100162306a36Sopenharmony_ci		ppgtt->vm.pte_encode = gen8_pte_encode;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	ppgtt->vm.bind_async_flags = I915_VMA_LOCAL_BIND;
100462306a36Sopenharmony_ci	ppgtt->vm.insert_entries = gen8_ppgtt_insert;
100562306a36Sopenharmony_ci	if (HAS_64K_PAGES(gt->i915))
100662306a36Sopenharmony_ci		ppgtt->vm.insert_page = xehpsdv_ppgtt_insert_entry;
100762306a36Sopenharmony_ci	else
100862306a36Sopenharmony_ci		ppgtt->vm.insert_page = gen8_ppgtt_insert_entry;
100962306a36Sopenharmony_ci	ppgtt->vm.allocate_va_range = gen8_ppgtt_alloc;
101062306a36Sopenharmony_ci	ppgtt->vm.clear_range = gen8_ppgtt_clear;
101162306a36Sopenharmony_ci	ppgtt->vm.foreach = gen8_ppgtt_foreach;
101262306a36Sopenharmony_ci	ppgtt->vm.cleanup = gen8_ppgtt_cleanup;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	err = gen8_init_scratch(&ppgtt->vm);
101562306a36Sopenharmony_ci	if (err)
101662306a36Sopenharmony_ci		goto err_put;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	pd = gen8_alloc_top_pd(&ppgtt->vm);
101962306a36Sopenharmony_ci	if (IS_ERR(pd)) {
102062306a36Sopenharmony_ci		err = PTR_ERR(pd);
102162306a36Sopenharmony_ci		goto err_put;
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci	ppgtt->pd = pd;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	if (!i915_vm_is_4lvl(&ppgtt->vm)) {
102662306a36Sopenharmony_ci		err = gen8_preallocate_top_level_pdp(ppgtt);
102762306a36Sopenharmony_ci		if (err)
102862306a36Sopenharmony_ci			goto err_put;
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	if (intel_vgpu_active(gt->i915))
103262306a36Sopenharmony_ci		gen8_ppgtt_notify_vgt(ppgtt, true);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	return ppgtt;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cierr_put:
103762306a36Sopenharmony_ci	i915_vm_put(&ppgtt->vm);
103862306a36Sopenharmony_ci	return ERR_PTR(err);
103962306a36Sopenharmony_ci}
1040