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_internal.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "gen6_ppgtt.h"
1162306a36Sopenharmony_ci#include "i915_scatterlist.h"
1262306a36Sopenharmony_ci#include "i915_trace.h"
1362306a36Sopenharmony_ci#include "i915_vgpu.h"
1462306a36Sopenharmony_ci#include "intel_gt_regs.h"
1562306a36Sopenharmony_ci#include "intel_engine_regs.h"
1662306a36Sopenharmony_ci#include "intel_gt.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* Write pde (index) from the page directory @pd to the page table @pt */
1962306a36Sopenharmony_cistatic void gen6_write_pde(const struct gen6_ppgtt *ppgtt,
2062306a36Sopenharmony_ci			   const unsigned int pde,
2162306a36Sopenharmony_ci			   const struct i915_page_table *pt)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	dma_addr_t addr = pt ? px_dma(pt) : px_dma(ppgtt->base.vm.scratch[1]);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	/* Caller needs to make sure the write completes if necessary */
2662306a36Sopenharmony_ci	iowrite32(GEN6_PDE_ADDR_ENCODE(addr) | GEN6_PDE_VALID,
2762306a36Sopenharmony_ci		  ppgtt->pd_addr + pde);
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_civoid gen7_ppgtt_enable(struct intel_gt *gt)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	struct drm_i915_private *i915 = gt->i915;
3362306a36Sopenharmony_ci	struct intel_uncore *uncore = gt->uncore;
3462306a36Sopenharmony_ci	u32 ecochk;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	intel_uncore_rmw(uncore, GAC_ECO_BITS, 0, ECOBITS_PPGTT_CACHE64B);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	ecochk = intel_uncore_read(uncore, GAM_ECOCHK);
3962306a36Sopenharmony_ci	if (IS_HASWELL(i915)) {
4062306a36Sopenharmony_ci		ecochk |= ECOCHK_PPGTT_WB_HSW;
4162306a36Sopenharmony_ci	} else {
4262306a36Sopenharmony_ci		ecochk |= ECOCHK_PPGTT_LLC_IVB;
4362306a36Sopenharmony_ci		ecochk &= ~ECOCHK_PPGTT_GFDT_IVB;
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci	intel_uncore_write(uncore, GAM_ECOCHK, ecochk);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_civoid gen6_ppgtt_enable(struct intel_gt *gt)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct intel_uncore *uncore = gt->uncore;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	intel_uncore_rmw(uncore,
5362306a36Sopenharmony_ci			 GAC_ECO_BITS,
5462306a36Sopenharmony_ci			 0,
5562306a36Sopenharmony_ci			 ECOBITS_SNB_BIT | ECOBITS_PPGTT_CACHE64B);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	intel_uncore_rmw(uncore,
5862306a36Sopenharmony_ci			 GAB_CTL,
5962306a36Sopenharmony_ci			 0,
6062306a36Sopenharmony_ci			 GAB_CTL_CONT_AFTER_PAGEFAULT);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	intel_uncore_rmw(uncore,
6362306a36Sopenharmony_ci			 GAM_ECOCHK,
6462306a36Sopenharmony_ci			 0,
6562306a36Sopenharmony_ci			 ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (HAS_PPGTT(uncore->i915)) /* may be disabled for VT-d */
6862306a36Sopenharmony_ci		intel_uncore_write(uncore,
6962306a36Sopenharmony_ci				   GFX_MODE,
7062306a36Sopenharmony_ci				   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* PPGTT support for Sandybdrige/Gen6 and later */
7462306a36Sopenharmony_cistatic void gen6_ppgtt_clear_range(struct i915_address_space *vm,
7562306a36Sopenharmony_ci				   u64 start, u64 length)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct gen6_ppgtt * const ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm));
7862306a36Sopenharmony_ci	const unsigned int first_entry = start / I915_GTT_PAGE_SIZE;
7962306a36Sopenharmony_ci	const gen6_pte_t scratch_pte = vm->scratch[0]->encode;
8062306a36Sopenharmony_ci	unsigned int pde = first_entry / GEN6_PTES;
8162306a36Sopenharmony_ci	unsigned int pte = first_entry % GEN6_PTES;
8262306a36Sopenharmony_ci	unsigned int num_entries = length / I915_GTT_PAGE_SIZE;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	while (num_entries) {
8562306a36Sopenharmony_ci		struct i915_page_table * const pt =
8662306a36Sopenharmony_ci			i915_pt_entry(ppgtt->base.pd, pde++);
8762306a36Sopenharmony_ci		const unsigned int count = min(num_entries, GEN6_PTES - pte);
8862306a36Sopenharmony_ci		gen6_pte_t *vaddr;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci		num_entries -= count;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		GEM_BUG_ON(count > atomic_read(&pt->used));
9362306a36Sopenharmony_ci		if (!atomic_sub_return(count, &pt->used))
9462306a36Sopenharmony_ci			ppgtt->scan_for_unused_pt = true;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci		/*
9762306a36Sopenharmony_ci		 * Note that the hw doesn't support removing PDE on the fly
9862306a36Sopenharmony_ci		 * (they are cached inside the context with no means to
9962306a36Sopenharmony_ci		 * invalidate the cache), so we can only reset the PTE
10062306a36Sopenharmony_ci		 * entries back to scratch.
10162306a36Sopenharmony_ci		 */
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		vaddr = px_vaddr(pt);
10462306a36Sopenharmony_ci		memset32(vaddr + pte, scratch_pte, count);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		pte = 0;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
11162306a36Sopenharmony_ci				      struct i915_vma_resource *vma_res,
11262306a36Sopenharmony_ci				      unsigned int pat_index,
11362306a36Sopenharmony_ci				      u32 flags)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
11662306a36Sopenharmony_ci	struct i915_page_directory * const pd = ppgtt->pd;
11762306a36Sopenharmony_ci	unsigned int first_entry = vma_res->start / I915_GTT_PAGE_SIZE;
11862306a36Sopenharmony_ci	unsigned int act_pt = first_entry / GEN6_PTES;
11962306a36Sopenharmony_ci	unsigned int act_pte = first_entry % GEN6_PTES;
12062306a36Sopenharmony_ci	const u32 pte_encode = vm->pte_encode(0, pat_index, flags);
12162306a36Sopenharmony_ci	struct sgt_dma iter = sgt_dma(vma_res);
12262306a36Sopenharmony_ci	gen6_pte_t *vaddr;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	GEM_BUG_ON(!pd->entry[act_pt]);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	vaddr = px_vaddr(i915_pt_entry(pd, act_pt));
12762306a36Sopenharmony_ci	do {
12862306a36Sopenharmony_ci		GEM_BUG_ON(sg_dma_len(iter.sg) < I915_GTT_PAGE_SIZE);
12962306a36Sopenharmony_ci		vaddr[act_pte] = pte_encode | GEN6_PTE_ADDR_ENCODE(iter.dma);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		iter.dma += I915_GTT_PAGE_SIZE;
13262306a36Sopenharmony_ci		if (iter.dma == iter.max) {
13362306a36Sopenharmony_ci			iter.sg = __sg_next(iter.sg);
13462306a36Sopenharmony_ci			if (!iter.sg || sg_dma_len(iter.sg) == 0)
13562306a36Sopenharmony_ci				break;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci			iter.dma = sg_dma_address(iter.sg);
13862306a36Sopenharmony_ci			iter.max = iter.dma + sg_dma_len(iter.sg);
13962306a36Sopenharmony_ci		}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		if (++act_pte == GEN6_PTES) {
14262306a36Sopenharmony_ci			vaddr = px_vaddr(i915_pt_entry(pd, ++act_pt));
14362306a36Sopenharmony_ci			act_pte = 0;
14462306a36Sopenharmony_ci		}
14562306a36Sopenharmony_ci	} while (1);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	vma_res->page_sizes_gtt = I915_GTT_PAGE_SIZE;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void gen6_flush_pd(struct gen6_ppgtt *ppgtt, u64 start, u64 end)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct i915_page_directory * const pd = ppgtt->base.pd;
15362306a36Sopenharmony_ci	struct i915_page_table *pt;
15462306a36Sopenharmony_ci	unsigned int pde;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	start = round_down(start, SZ_64K);
15762306a36Sopenharmony_ci	end = round_up(end, SZ_64K) - start;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	mutex_lock(&ppgtt->flush);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	gen6_for_each_pde(pt, pd, start, end, pde)
16262306a36Sopenharmony_ci		gen6_write_pde(ppgtt, pde, pt);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	mb();
16562306a36Sopenharmony_ci	ioread32(ppgtt->pd_addr + pde - 1);
16662306a36Sopenharmony_ci	gen6_ggtt_invalidate(ppgtt->base.vm.gt->ggtt);
16762306a36Sopenharmony_ci	mb();
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	mutex_unlock(&ppgtt->flush);
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic void gen6_alloc_va_range(struct i915_address_space *vm,
17362306a36Sopenharmony_ci				struct i915_vm_pt_stash *stash,
17462306a36Sopenharmony_ci				u64 start, u64 length)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm));
17762306a36Sopenharmony_ci	struct i915_page_directory * const pd = ppgtt->base.pd;
17862306a36Sopenharmony_ci	struct i915_page_table *pt;
17962306a36Sopenharmony_ci	bool flush = false;
18062306a36Sopenharmony_ci	u64 from = start;
18162306a36Sopenharmony_ci	unsigned int pde;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	spin_lock(&pd->lock);
18462306a36Sopenharmony_ci	gen6_for_each_pde(pt, pd, start, length, pde) {
18562306a36Sopenharmony_ci		const unsigned int count = gen6_pte_count(start, length);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		if (!pt) {
18862306a36Sopenharmony_ci			spin_unlock(&pd->lock);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci			pt = stash->pt[0];
19162306a36Sopenharmony_ci			__i915_gem_object_pin_pages(pt->base);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci			fill32_px(pt, vm->scratch[0]->encode);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci			spin_lock(&pd->lock);
19662306a36Sopenharmony_ci			if (!pd->entry[pde]) {
19762306a36Sopenharmony_ci				stash->pt[0] = pt->stash;
19862306a36Sopenharmony_ci				atomic_set(&pt->used, 0);
19962306a36Sopenharmony_ci				pd->entry[pde] = pt;
20062306a36Sopenharmony_ci			} else {
20162306a36Sopenharmony_ci				pt = pd->entry[pde];
20262306a36Sopenharmony_ci			}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci			flush = true;
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		atomic_add(count, &pt->used);
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci	spin_unlock(&pd->lock);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (flush && i915_vma_is_bound(ppgtt->vma, I915_VMA_GLOBAL_BIND)) {
21262306a36Sopenharmony_ci		intel_wakeref_t wakeref;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		with_intel_runtime_pm(&vm->i915->runtime_pm, wakeref)
21562306a36Sopenharmony_ci			gen6_flush_pd(ppgtt, from, start);
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic int gen6_ppgtt_init_scratch(struct gen6_ppgtt *ppgtt)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	struct i915_address_space * const vm = &ppgtt->base.vm;
22262306a36Sopenharmony_ci	int ret;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	ret = setup_scratch_page(vm);
22562306a36Sopenharmony_ci	if (ret)
22662306a36Sopenharmony_ci		return ret;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	vm->scratch[0]->encode =
22962306a36Sopenharmony_ci		vm->pte_encode(px_dma(vm->scratch[0]),
23062306a36Sopenharmony_ci			       i915_gem_get_pat_index(vm->i915,
23162306a36Sopenharmony_ci						      I915_CACHE_NONE),
23262306a36Sopenharmony_ci			       PTE_READ_ONLY);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	vm->scratch[1] = vm->alloc_pt_dma(vm, I915_GTT_PAGE_SIZE_4K);
23562306a36Sopenharmony_ci	if (IS_ERR(vm->scratch[1])) {
23662306a36Sopenharmony_ci		ret = PTR_ERR(vm->scratch[1]);
23762306a36Sopenharmony_ci		goto err_scratch0;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	ret = map_pt_dma(vm, vm->scratch[1]);
24162306a36Sopenharmony_ci	if (ret)
24262306a36Sopenharmony_ci		goto err_scratch1;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	fill32_px(vm->scratch[1], vm->scratch[0]->encode);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return 0;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cierr_scratch1:
24962306a36Sopenharmony_ci	i915_gem_object_put(vm->scratch[1]);
25062306a36Sopenharmony_cierr_scratch0:
25162306a36Sopenharmony_ci	i915_gem_object_put(vm->scratch[0]);
25262306a36Sopenharmony_ci	vm->scratch[0] = NULL;
25362306a36Sopenharmony_ci	return ret;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic void gen6_ppgtt_free_pd(struct gen6_ppgtt *ppgtt)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct i915_page_directory * const pd = ppgtt->base.pd;
25962306a36Sopenharmony_ci	struct i915_page_table *pt;
26062306a36Sopenharmony_ci	u32 pde;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	gen6_for_all_pdes(pt, pd, pde)
26362306a36Sopenharmony_ci		if (pt)
26462306a36Sopenharmony_ci			free_pt(&ppgtt->base.vm, pt);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic void gen6_ppgtt_cleanup(struct i915_address_space *vm)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm));
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	gen6_ppgtt_free_pd(ppgtt);
27262306a36Sopenharmony_ci	free_scratch(vm);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (ppgtt->base.pd)
27562306a36Sopenharmony_ci		free_pd(&ppgtt->base.vm, ppgtt->base.pd);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	mutex_destroy(&ppgtt->flush);
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic void pd_vma_bind(struct i915_address_space *vm,
28162306a36Sopenharmony_ci			struct i915_vm_pt_stash *stash,
28262306a36Sopenharmony_ci			struct i915_vma_resource *vma_res,
28362306a36Sopenharmony_ci			unsigned int pat_index,
28462306a36Sopenharmony_ci			u32 unused)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
28762306a36Sopenharmony_ci	struct gen6_ppgtt *ppgtt = vma_res->private;
28862306a36Sopenharmony_ci	u32 ggtt_offset = vma_res->start / I915_GTT_PAGE_SIZE;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	ppgtt->pp_dir = ggtt_offset * sizeof(gen6_pte_t) << 10;
29162306a36Sopenharmony_ci	ppgtt->pd_addr = (gen6_pte_t __iomem *)ggtt->gsm + ggtt_offset;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	gen6_flush_pd(ppgtt, 0, ppgtt->base.vm.total);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void pd_vma_unbind(struct i915_address_space *vm,
29762306a36Sopenharmony_ci			  struct i915_vma_resource *vma_res)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct gen6_ppgtt *ppgtt = vma_res->private;
30062306a36Sopenharmony_ci	struct i915_page_directory * const pd = ppgtt->base.pd;
30162306a36Sopenharmony_ci	struct i915_page_table *pt;
30262306a36Sopenharmony_ci	unsigned int pde;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (!ppgtt->scan_for_unused_pt)
30562306a36Sopenharmony_ci		return;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* Free all no longer used page tables */
30862306a36Sopenharmony_ci	gen6_for_all_pdes(pt, ppgtt->base.pd, pde) {
30962306a36Sopenharmony_ci		if (!pt || atomic_read(&pt->used))
31062306a36Sopenharmony_ci			continue;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		free_pt(&ppgtt->base.vm, pt);
31362306a36Sopenharmony_ci		pd->entry[pde] = NULL;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	ppgtt->scan_for_unused_pt = false;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic const struct i915_vma_ops pd_vma_ops = {
32062306a36Sopenharmony_ci	.bind_vma = pd_vma_bind,
32162306a36Sopenharmony_ci	.unbind_vma = pd_vma_unbind,
32262306a36Sopenharmony_ci};
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ciint gen6_ppgtt_pin(struct i915_ppgtt *base, struct i915_gem_ww_ctx *ww)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
32762306a36Sopenharmony_ci	int err;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	GEM_BUG_ON(!kref_read(&ppgtt->base.vm.ref));
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/*
33262306a36Sopenharmony_ci	 * Workaround the limited maximum vma->pin_count and the aliasing_ppgtt
33362306a36Sopenharmony_ci	 * which will be pinned into every active context.
33462306a36Sopenharmony_ci	 * (When vma->pin_count becomes atomic, I expect we will naturally
33562306a36Sopenharmony_ci	 * need a larger, unpacked, type and kill this redundancy.)
33662306a36Sopenharmony_ci	 */
33762306a36Sopenharmony_ci	if (atomic_add_unless(&ppgtt->pin_count, 1, 0))
33862306a36Sopenharmony_ci		return 0;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* grab the ppgtt resv to pin the object */
34162306a36Sopenharmony_ci	err = i915_vm_lock_objects(&ppgtt->base.vm, ww);
34262306a36Sopenharmony_ci	if (err)
34362306a36Sopenharmony_ci		return err;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/*
34662306a36Sopenharmony_ci	 * PPGTT PDEs reside in the GGTT and consists of 512 entries. The
34762306a36Sopenharmony_ci	 * allocator works in address space sizes, so it's multiplied by page
34862306a36Sopenharmony_ci	 * size. We allocate at the top of the GTT to avoid fragmentation.
34962306a36Sopenharmony_ci	 */
35062306a36Sopenharmony_ci	if (!atomic_read(&ppgtt->pin_count)) {
35162306a36Sopenharmony_ci		err = i915_ggtt_pin(ppgtt->vma, ww, GEN6_PD_ALIGN, PIN_HIGH);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		GEM_BUG_ON(ppgtt->vma->fence);
35462306a36Sopenharmony_ci		clear_bit(I915_VMA_CAN_FENCE_BIT, __i915_vma_flags(ppgtt->vma));
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci	if (!err)
35762306a36Sopenharmony_ci		atomic_inc(&ppgtt->pin_count);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return err;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic int pd_dummy_obj_get_pages(struct drm_i915_gem_object *obj)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	obj->mm.pages = ZERO_SIZE_PTR;
36562306a36Sopenharmony_ci	return 0;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic void pd_dummy_obj_put_pages(struct drm_i915_gem_object *obj,
36962306a36Sopenharmony_ci				   struct sg_table *pages)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic const struct drm_i915_gem_object_ops pd_dummy_obj_ops = {
37462306a36Sopenharmony_ci	.name = "pd_dummy_obj",
37562306a36Sopenharmony_ci	.get_pages = pd_dummy_obj_get_pages,
37662306a36Sopenharmony_ci	.put_pages = pd_dummy_obj_put_pages,
37762306a36Sopenharmony_ci};
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic struct i915_page_directory *
38062306a36Sopenharmony_cigen6_alloc_top_pd(struct gen6_ppgtt *ppgtt)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct i915_ggtt * const ggtt = ppgtt->base.vm.gt->ggtt;
38362306a36Sopenharmony_ci	struct i915_page_directory *pd;
38462306a36Sopenharmony_ci	int err;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	pd = __alloc_pd(I915_PDES);
38762306a36Sopenharmony_ci	if (unlikely(!pd))
38862306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	pd->pt.base = __i915_gem_object_create_internal(ppgtt->base.vm.gt->i915,
39162306a36Sopenharmony_ci							&pd_dummy_obj_ops,
39262306a36Sopenharmony_ci							I915_PDES * SZ_4K);
39362306a36Sopenharmony_ci	if (IS_ERR(pd->pt.base)) {
39462306a36Sopenharmony_ci		err = PTR_ERR(pd->pt.base);
39562306a36Sopenharmony_ci		pd->pt.base = NULL;
39662306a36Sopenharmony_ci		goto err_pd;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	pd->pt.base->base.resv = i915_vm_resv_get(&ppgtt->base.vm);
40062306a36Sopenharmony_ci	pd->pt.base->shares_resv_from = &ppgtt->base.vm;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	ppgtt->vma = i915_vma_instance(pd->pt.base, &ggtt->vm, NULL);
40362306a36Sopenharmony_ci	if (IS_ERR(ppgtt->vma)) {
40462306a36Sopenharmony_ci		err = PTR_ERR(ppgtt->vma);
40562306a36Sopenharmony_ci		ppgtt->vma = NULL;
40662306a36Sopenharmony_ci		goto err_pd;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/* The dummy object we create is special, override ops.. */
41062306a36Sopenharmony_ci	ppgtt->vma->ops = &pd_vma_ops;
41162306a36Sopenharmony_ci	ppgtt->vma->private = ppgtt;
41262306a36Sopenharmony_ci	return pd;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cierr_pd:
41562306a36Sopenharmony_ci	free_pd(&ppgtt->base.vm, pd);
41662306a36Sopenharmony_ci	return ERR_PTR(err);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_civoid gen6_ppgtt_unpin(struct i915_ppgtt *base)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	GEM_BUG_ON(!atomic_read(&ppgtt->pin_count));
42462306a36Sopenharmony_ci	if (atomic_dec_and_test(&ppgtt->pin_count))
42562306a36Sopenharmony_ci		i915_vma_unpin(ppgtt->vma);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistruct i915_ppgtt *gen6_ppgtt_create(struct intel_gt *gt)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	struct i915_ggtt * const ggtt = gt->ggtt;
43162306a36Sopenharmony_ci	struct gen6_ppgtt *ppgtt;
43262306a36Sopenharmony_ci	int err;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
43562306a36Sopenharmony_ci	if (!ppgtt)
43662306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	mutex_init(&ppgtt->flush);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	ppgtt_init(&ppgtt->base, gt, 0);
44162306a36Sopenharmony_ci	ppgtt->base.vm.pd_shift = ilog2(SZ_4K * SZ_4K / sizeof(gen6_pte_t));
44262306a36Sopenharmony_ci	ppgtt->base.vm.top = 1;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	ppgtt->base.vm.bind_async_flags = I915_VMA_LOCAL_BIND;
44562306a36Sopenharmony_ci	ppgtt->base.vm.allocate_va_range = gen6_alloc_va_range;
44662306a36Sopenharmony_ci	ppgtt->base.vm.clear_range = gen6_ppgtt_clear_range;
44762306a36Sopenharmony_ci	ppgtt->base.vm.insert_entries = gen6_ppgtt_insert_entries;
44862306a36Sopenharmony_ci	ppgtt->base.vm.cleanup = gen6_ppgtt_cleanup;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	ppgtt->base.vm.alloc_pt_dma = alloc_pt_dma;
45162306a36Sopenharmony_ci	ppgtt->base.vm.alloc_scratch_dma = alloc_pt_dma;
45262306a36Sopenharmony_ci	ppgtt->base.vm.pte_encode = ggtt->vm.pte_encode;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	err = gen6_ppgtt_init_scratch(ppgtt);
45562306a36Sopenharmony_ci	if (err)
45662306a36Sopenharmony_ci		goto err_put;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	ppgtt->base.pd = gen6_alloc_top_pd(ppgtt);
45962306a36Sopenharmony_ci	if (IS_ERR(ppgtt->base.pd)) {
46062306a36Sopenharmony_ci		err = PTR_ERR(ppgtt->base.pd);
46162306a36Sopenharmony_ci		goto err_put;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	return &ppgtt->base;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cierr_put:
46762306a36Sopenharmony_ci	i915_vm_put(&ppgtt->base.vm);
46862306a36Sopenharmony_ci	return ERR_PTR(err);
46962306a36Sopenharmony_ci}
470