162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * GTT virtualization
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
762306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
862306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
962306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1062306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
1162306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the next
1462306a36Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
1562306a36Sopenharmony_ci * Software.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1862306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1962306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2062306a36Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2162306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2262306a36Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2362306a36Sopenharmony_ci * SOFTWARE.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * Authors:
2662306a36Sopenharmony_ci *    Zhi Wang <zhi.a.wang@intel.com>
2762306a36Sopenharmony_ci *    Zhenyu Wang <zhenyuw@linux.intel.com>
2862306a36Sopenharmony_ci *    Xiao Zheng <xiao.zheng@intel.com>
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * Contributors:
3162306a36Sopenharmony_ci *    Min He <min.he@intel.com>
3262306a36Sopenharmony_ci *    Bing Niu <bing.niu@intel.com>
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "i915_drv.h"
3762306a36Sopenharmony_ci#include "gvt.h"
3862306a36Sopenharmony_ci#include "i915_pvinfo.h"
3962306a36Sopenharmony_ci#include "trace.h"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "gt/intel_gt_regs.h"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#if defined(VERBOSE_DEBUG)
4462306a36Sopenharmony_ci#define gvt_vdbg_mm(fmt, args...) gvt_dbg_mm(fmt, ##args)
4562306a36Sopenharmony_ci#else
4662306a36Sopenharmony_ci#define gvt_vdbg_mm(fmt, args...)
4762306a36Sopenharmony_ci#endif
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic bool enable_out_of_sync = false;
5062306a36Sopenharmony_cistatic int preallocated_oos_pages = 8192;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/*
5362306a36Sopenharmony_ci * validate a gm address and related range size,
5462306a36Sopenharmony_ci * translate it to host gm address
5562306a36Sopenharmony_ci */
5662306a36Sopenharmony_cibool intel_gvt_ggtt_validate_range(struct intel_vgpu *vgpu, u64 addr, u32 size)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	if (size == 0)
5962306a36Sopenharmony_ci		return vgpu_gmadr_is_valid(vgpu, addr);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (vgpu_gmadr_is_aperture(vgpu, addr) &&
6262306a36Sopenharmony_ci	    vgpu_gmadr_is_aperture(vgpu, addr + size - 1))
6362306a36Sopenharmony_ci		return true;
6462306a36Sopenharmony_ci	else if (vgpu_gmadr_is_hidden(vgpu, addr) &&
6562306a36Sopenharmony_ci		 vgpu_gmadr_is_hidden(vgpu, addr + size - 1))
6662306a36Sopenharmony_ci		return true;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	gvt_dbg_mm("Invalid ggtt range at 0x%llx, size: 0x%x\n",
6962306a36Sopenharmony_ci		     addr, size);
7062306a36Sopenharmony_ci	return false;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* translate a guest gmadr to host gmadr */
7462306a36Sopenharmony_ciint intel_gvt_ggtt_gmadr_g2h(struct intel_vgpu *vgpu, u64 g_addr, u64 *h_addr)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (drm_WARN(&i915->drm, !vgpu_gmadr_is_valid(vgpu, g_addr),
7962306a36Sopenharmony_ci		     "invalid guest gmadr %llx\n", g_addr))
8062306a36Sopenharmony_ci		return -EACCES;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (vgpu_gmadr_is_aperture(vgpu, g_addr))
8362306a36Sopenharmony_ci		*h_addr = vgpu_aperture_gmadr_base(vgpu)
8462306a36Sopenharmony_ci			  + (g_addr - vgpu_aperture_offset(vgpu));
8562306a36Sopenharmony_ci	else
8662306a36Sopenharmony_ci		*h_addr = vgpu_hidden_gmadr_base(vgpu)
8762306a36Sopenharmony_ci			  + (g_addr - vgpu_hidden_offset(vgpu));
8862306a36Sopenharmony_ci	return 0;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/* translate a host gmadr to guest gmadr */
9262306a36Sopenharmony_ciint intel_gvt_ggtt_gmadr_h2g(struct intel_vgpu *vgpu, u64 h_addr, u64 *g_addr)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (drm_WARN(&i915->drm, !gvt_gmadr_is_valid(vgpu->gvt, h_addr),
9762306a36Sopenharmony_ci		     "invalid host gmadr %llx\n", h_addr))
9862306a36Sopenharmony_ci		return -EACCES;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (gvt_gmadr_is_aperture(vgpu->gvt, h_addr))
10162306a36Sopenharmony_ci		*g_addr = vgpu_aperture_gmadr_base(vgpu)
10262306a36Sopenharmony_ci			+ (h_addr - gvt_aperture_gmadr_base(vgpu->gvt));
10362306a36Sopenharmony_ci	else
10462306a36Sopenharmony_ci		*g_addr = vgpu_hidden_gmadr_base(vgpu)
10562306a36Sopenharmony_ci			+ (h_addr - gvt_hidden_gmadr_base(vgpu->gvt));
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciint intel_gvt_ggtt_index_g2h(struct intel_vgpu *vgpu, unsigned long g_index,
11062306a36Sopenharmony_ci			     unsigned long *h_index)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	u64 h_addr;
11362306a36Sopenharmony_ci	int ret;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	ret = intel_gvt_ggtt_gmadr_g2h(vgpu, g_index << I915_GTT_PAGE_SHIFT,
11662306a36Sopenharmony_ci				       &h_addr);
11762306a36Sopenharmony_ci	if (ret)
11862306a36Sopenharmony_ci		return ret;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	*h_index = h_addr >> I915_GTT_PAGE_SHIFT;
12162306a36Sopenharmony_ci	return 0;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ciint intel_gvt_ggtt_h2g_index(struct intel_vgpu *vgpu, unsigned long h_index,
12562306a36Sopenharmony_ci			     unsigned long *g_index)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	u64 g_addr;
12862306a36Sopenharmony_ci	int ret;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	ret = intel_gvt_ggtt_gmadr_h2g(vgpu, h_index << I915_GTT_PAGE_SHIFT,
13162306a36Sopenharmony_ci				       &g_addr);
13262306a36Sopenharmony_ci	if (ret)
13362306a36Sopenharmony_ci		return ret;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	*g_index = g_addr >> I915_GTT_PAGE_SHIFT;
13662306a36Sopenharmony_ci	return 0;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#define gtt_type_is_entry(type) \
14062306a36Sopenharmony_ci	(type > GTT_TYPE_INVALID && type < GTT_TYPE_PPGTT_ENTRY \
14162306a36Sopenharmony_ci	 && type != GTT_TYPE_PPGTT_PTE_ENTRY \
14262306a36Sopenharmony_ci	 && type != GTT_TYPE_PPGTT_ROOT_ENTRY)
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#define gtt_type_is_pt(type) \
14562306a36Sopenharmony_ci	(type >= GTT_TYPE_PPGTT_PTE_PT && type < GTT_TYPE_MAX)
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#define gtt_type_is_pte_pt(type) \
14862306a36Sopenharmony_ci	(type == GTT_TYPE_PPGTT_PTE_PT)
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#define gtt_type_is_root_pointer(type) \
15162306a36Sopenharmony_ci	(gtt_type_is_entry(type) && type > GTT_TYPE_PPGTT_ROOT_ENTRY)
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define gtt_init_entry(e, t, p, v) do { \
15462306a36Sopenharmony_ci	(e)->type = t; \
15562306a36Sopenharmony_ci	(e)->pdev = p; \
15662306a36Sopenharmony_ci	memcpy(&(e)->val64, &v, sizeof(v)); \
15762306a36Sopenharmony_ci} while (0)
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * Mappings between GTT_TYPE* enumerations.
16162306a36Sopenharmony_ci * Following information can be found according to the given type:
16262306a36Sopenharmony_ci * - type of next level page table
16362306a36Sopenharmony_ci * - type of entry inside this level page table
16462306a36Sopenharmony_ci * - type of entry with PSE set
16562306a36Sopenharmony_ci *
16662306a36Sopenharmony_ci * If the given type doesn't have such a kind of information,
16762306a36Sopenharmony_ci * e.g. give a l4 root entry type, then request to get its PSE type,
16862306a36Sopenharmony_ci * give a PTE page table type, then request to get its next level page
16962306a36Sopenharmony_ci * table type, as we know l4 root entry doesn't have a PSE bit,
17062306a36Sopenharmony_ci * and a PTE page table doesn't have a next level page table type,
17162306a36Sopenharmony_ci * GTT_TYPE_INVALID will be returned. This is useful when traversing a
17262306a36Sopenharmony_ci * page table.
17362306a36Sopenharmony_ci */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistruct gtt_type_table_entry {
17662306a36Sopenharmony_ci	int entry_type;
17762306a36Sopenharmony_ci	int pt_type;
17862306a36Sopenharmony_ci	int next_pt_type;
17962306a36Sopenharmony_ci	int pse_entry_type;
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci#define GTT_TYPE_TABLE_ENTRY(type, e_type, cpt_type, npt_type, pse_type) \
18362306a36Sopenharmony_ci	[type] = { \
18462306a36Sopenharmony_ci		.entry_type = e_type, \
18562306a36Sopenharmony_ci		.pt_type = cpt_type, \
18662306a36Sopenharmony_ci		.next_pt_type = npt_type, \
18762306a36Sopenharmony_ci		.pse_entry_type = pse_type, \
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic const struct gtt_type_table_entry gtt_type_table[] = {
19162306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_ROOT_L4_ENTRY,
19262306a36Sopenharmony_ci			GTT_TYPE_PPGTT_ROOT_L4_ENTRY,
19362306a36Sopenharmony_ci			GTT_TYPE_INVALID,
19462306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PML4_PT,
19562306a36Sopenharmony_ci			GTT_TYPE_INVALID),
19662306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PML4_PT,
19762306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PML4_ENTRY,
19862306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PML4_PT,
19962306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_PT,
20062306a36Sopenharmony_ci			GTT_TYPE_INVALID),
20162306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PML4_ENTRY,
20262306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PML4_ENTRY,
20362306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PML4_PT,
20462306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_PT,
20562306a36Sopenharmony_ci			GTT_TYPE_INVALID),
20662306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDP_PT,
20762306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_ENTRY,
20862306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_PT,
20962306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
21062306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
21162306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_ROOT_L3_ENTRY,
21262306a36Sopenharmony_ci			GTT_TYPE_PPGTT_ROOT_L3_ENTRY,
21362306a36Sopenharmony_ci			GTT_TYPE_INVALID,
21462306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
21562306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
21662306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDP_ENTRY,
21762306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_ENTRY,
21862306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_PT,
21962306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
22062306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
22162306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDE_PT,
22262306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_ENTRY,
22362306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
22462306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_PT,
22562306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_2M_ENTRY),
22662306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDE_ENTRY,
22762306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_ENTRY,
22862306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
22962306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_PT,
23062306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_2M_ENTRY),
23162306a36Sopenharmony_ci	/* We take IPS bit as 'PSE' for PTE level. */
23262306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_PT,
23362306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_4K_ENTRY,
23462306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_PT,
23562306a36Sopenharmony_ci			GTT_TYPE_INVALID,
23662306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_64K_ENTRY),
23762306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_4K_ENTRY,
23862306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_4K_ENTRY,
23962306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_PT,
24062306a36Sopenharmony_ci			GTT_TYPE_INVALID,
24162306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_64K_ENTRY),
24262306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_64K_ENTRY,
24362306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_4K_ENTRY,
24462306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_PT,
24562306a36Sopenharmony_ci			GTT_TYPE_INVALID,
24662306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_64K_ENTRY),
24762306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_2M_ENTRY,
24862306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_ENTRY,
24962306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
25062306a36Sopenharmony_ci			GTT_TYPE_INVALID,
25162306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_2M_ENTRY),
25262306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_1G_ENTRY,
25362306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_ENTRY,
25462306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_PT,
25562306a36Sopenharmony_ci			GTT_TYPE_INVALID,
25662306a36Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
25762306a36Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_GGTT_PTE,
25862306a36Sopenharmony_ci			GTT_TYPE_GGTT_PTE,
25962306a36Sopenharmony_ci			GTT_TYPE_INVALID,
26062306a36Sopenharmony_ci			GTT_TYPE_INVALID,
26162306a36Sopenharmony_ci			GTT_TYPE_INVALID),
26262306a36Sopenharmony_ci};
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic inline int get_next_pt_type(int type)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	return gtt_type_table[type].next_pt_type;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic inline int get_entry_type(int type)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	return gtt_type_table[type].entry_type;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic inline int get_pse_type(int type)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	return gtt_type_table[type].pse_entry_type;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic u64 read_pte64(struct i915_ggtt *ggtt, unsigned long index)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	void __iomem *addr = (gen8_pte_t __iomem *)ggtt->gsm + index;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return readq(addr);
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic void ggtt_invalidate(struct intel_gt *gt)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	mmio_hw_access_pre(gt);
28962306a36Sopenharmony_ci	intel_uncore_write(gt->uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
29062306a36Sopenharmony_ci	mmio_hw_access_post(gt);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic void write_pte64(struct i915_ggtt *ggtt, unsigned long index, u64 pte)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	void __iomem *addr = (gen8_pte_t __iomem *)ggtt->gsm + index;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	writeq(pte, addr);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic inline int gtt_get_entry64(void *pt,
30162306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *e,
30262306a36Sopenharmony_ci		unsigned long index, bool hypervisor_access, unsigned long gpa,
30362306a36Sopenharmony_ci		struct intel_vgpu *vgpu)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
30662306a36Sopenharmony_ci	int ret;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (WARN_ON(info->gtt_entry_size != 8))
30962306a36Sopenharmony_ci		return -EINVAL;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (hypervisor_access) {
31262306a36Sopenharmony_ci		ret = intel_gvt_read_gpa(vgpu, gpa +
31362306a36Sopenharmony_ci				(index << info->gtt_entry_size_shift),
31462306a36Sopenharmony_ci				&e->val64, 8);
31562306a36Sopenharmony_ci		if (WARN_ON(ret))
31662306a36Sopenharmony_ci			return ret;
31762306a36Sopenharmony_ci	} else if (!pt) {
31862306a36Sopenharmony_ci		e->val64 = read_pte64(vgpu->gvt->gt->ggtt, index);
31962306a36Sopenharmony_ci	} else {
32062306a36Sopenharmony_ci		e->val64 = *((u64 *)pt + index);
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci	return 0;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic inline int gtt_set_entry64(void *pt,
32662306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *e,
32762306a36Sopenharmony_ci		unsigned long index, bool hypervisor_access, unsigned long gpa,
32862306a36Sopenharmony_ci		struct intel_vgpu *vgpu)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
33162306a36Sopenharmony_ci	int ret;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (WARN_ON(info->gtt_entry_size != 8))
33462306a36Sopenharmony_ci		return -EINVAL;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (hypervisor_access) {
33762306a36Sopenharmony_ci		ret = intel_gvt_write_gpa(vgpu, gpa +
33862306a36Sopenharmony_ci				(index << info->gtt_entry_size_shift),
33962306a36Sopenharmony_ci				&e->val64, 8);
34062306a36Sopenharmony_ci		if (WARN_ON(ret))
34162306a36Sopenharmony_ci			return ret;
34262306a36Sopenharmony_ci	} else if (!pt) {
34362306a36Sopenharmony_ci		write_pte64(vgpu->gvt->gt->ggtt, index, e->val64);
34462306a36Sopenharmony_ci	} else {
34562306a36Sopenharmony_ci		*((u64 *)pt + index) = e->val64;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci	return 0;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci#define GTT_HAW 46
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci#define ADDR_1G_MASK	GENMASK_ULL(GTT_HAW - 1, 30)
35362306a36Sopenharmony_ci#define ADDR_2M_MASK	GENMASK_ULL(GTT_HAW - 1, 21)
35462306a36Sopenharmony_ci#define ADDR_64K_MASK	GENMASK_ULL(GTT_HAW - 1, 16)
35562306a36Sopenharmony_ci#define ADDR_4K_MASK	GENMASK_ULL(GTT_HAW - 1, 12)
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci#define GTT_SPTE_FLAG_MASK GENMASK_ULL(62, 52)
35862306a36Sopenharmony_ci#define GTT_SPTE_FLAG_64K_SPLITED BIT(52) /* splited 64K gtt entry */
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci#define GTT_64K_PTE_STRIDE 16
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic unsigned long gen8_gtt_get_pfn(struct intel_gvt_gtt_entry *e)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	unsigned long pfn;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (e->type == GTT_TYPE_PPGTT_PTE_1G_ENTRY)
36762306a36Sopenharmony_ci		pfn = (e->val64 & ADDR_1G_MASK) >> PAGE_SHIFT;
36862306a36Sopenharmony_ci	else if (e->type == GTT_TYPE_PPGTT_PTE_2M_ENTRY)
36962306a36Sopenharmony_ci		pfn = (e->val64 & ADDR_2M_MASK) >> PAGE_SHIFT;
37062306a36Sopenharmony_ci	else if (e->type == GTT_TYPE_PPGTT_PTE_64K_ENTRY)
37162306a36Sopenharmony_ci		pfn = (e->val64 & ADDR_64K_MASK) >> PAGE_SHIFT;
37262306a36Sopenharmony_ci	else
37362306a36Sopenharmony_ci		pfn = (e->val64 & ADDR_4K_MASK) >> PAGE_SHIFT;
37462306a36Sopenharmony_ci	return pfn;
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic void gen8_gtt_set_pfn(struct intel_gvt_gtt_entry *e, unsigned long pfn)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	if (e->type == GTT_TYPE_PPGTT_PTE_1G_ENTRY) {
38062306a36Sopenharmony_ci		e->val64 &= ~ADDR_1G_MASK;
38162306a36Sopenharmony_ci		pfn &= (ADDR_1G_MASK >> PAGE_SHIFT);
38262306a36Sopenharmony_ci	} else if (e->type == GTT_TYPE_PPGTT_PTE_2M_ENTRY) {
38362306a36Sopenharmony_ci		e->val64 &= ~ADDR_2M_MASK;
38462306a36Sopenharmony_ci		pfn &= (ADDR_2M_MASK >> PAGE_SHIFT);
38562306a36Sopenharmony_ci	} else if (e->type == GTT_TYPE_PPGTT_PTE_64K_ENTRY) {
38662306a36Sopenharmony_ci		e->val64 &= ~ADDR_64K_MASK;
38762306a36Sopenharmony_ci		pfn &= (ADDR_64K_MASK >> PAGE_SHIFT);
38862306a36Sopenharmony_ci	} else {
38962306a36Sopenharmony_ci		e->val64 &= ~ADDR_4K_MASK;
39062306a36Sopenharmony_ci		pfn &= (ADDR_4K_MASK >> PAGE_SHIFT);
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	e->val64 |= (pfn << PAGE_SHIFT);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic bool gen8_gtt_test_pse(struct intel_gvt_gtt_entry *e)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	return !!(e->val64 & _PAGE_PSE);
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic void gen8_gtt_clear_pse(struct intel_gvt_gtt_entry *e)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	if (gen8_gtt_test_pse(e)) {
40462306a36Sopenharmony_ci		switch (e->type) {
40562306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_2M_ENTRY:
40662306a36Sopenharmony_ci			e->val64 &= ~_PAGE_PSE;
40762306a36Sopenharmony_ci			e->type = GTT_TYPE_PPGTT_PDE_ENTRY;
40862306a36Sopenharmony_ci			break;
40962306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_1G_ENTRY:
41062306a36Sopenharmony_ci			e->type = GTT_TYPE_PPGTT_PDP_ENTRY;
41162306a36Sopenharmony_ci			e->val64 &= ~_PAGE_PSE;
41262306a36Sopenharmony_ci			break;
41362306a36Sopenharmony_ci		default:
41462306a36Sopenharmony_ci			WARN_ON(1);
41562306a36Sopenharmony_ci		}
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic bool gen8_gtt_test_ips(struct intel_gvt_gtt_entry *e)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	if (GEM_WARN_ON(e->type != GTT_TYPE_PPGTT_PDE_ENTRY))
42262306a36Sopenharmony_ci		return false;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return !!(e->val64 & GEN8_PDE_IPS_64K);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic void gen8_gtt_clear_ips(struct intel_gvt_gtt_entry *e)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	if (GEM_WARN_ON(e->type != GTT_TYPE_PPGTT_PDE_ENTRY))
43062306a36Sopenharmony_ci		return;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	e->val64 &= ~GEN8_PDE_IPS_64K;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic bool gen8_gtt_test_present(struct intel_gvt_gtt_entry *e)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	/*
43862306a36Sopenharmony_ci	 * i915 writes PDP root pointer registers without present bit,
43962306a36Sopenharmony_ci	 * it also works, so we need to treat root pointer entry
44062306a36Sopenharmony_ci	 * specifically.
44162306a36Sopenharmony_ci	 */
44262306a36Sopenharmony_ci	if (e->type == GTT_TYPE_PPGTT_ROOT_L3_ENTRY
44362306a36Sopenharmony_ci			|| e->type == GTT_TYPE_PPGTT_ROOT_L4_ENTRY)
44462306a36Sopenharmony_ci		return (e->val64 != 0);
44562306a36Sopenharmony_ci	else
44662306a36Sopenharmony_ci		return (e->val64 & GEN8_PAGE_PRESENT);
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic void gtt_entry_clear_present(struct intel_gvt_gtt_entry *e)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	e->val64 &= ~GEN8_PAGE_PRESENT;
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic void gtt_entry_set_present(struct intel_gvt_gtt_entry *e)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	e->val64 |= GEN8_PAGE_PRESENT;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic bool gen8_gtt_test_64k_splited(struct intel_gvt_gtt_entry *e)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	return !!(e->val64 & GTT_SPTE_FLAG_64K_SPLITED);
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic void gen8_gtt_set_64k_splited(struct intel_gvt_gtt_entry *e)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	e->val64 |= GTT_SPTE_FLAG_64K_SPLITED;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic void gen8_gtt_clear_64k_splited(struct intel_gvt_gtt_entry *e)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	e->val64 &= ~GTT_SPTE_FLAG_64K_SPLITED;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci/*
47562306a36Sopenharmony_ci * Per-platform GMA routines.
47662306a36Sopenharmony_ci */
47762306a36Sopenharmony_cistatic unsigned long gma_to_ggtt_pte_index(unsigned long gma)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	unsigned long x = (gma >> I915_GTT_PAGE_SHIFT);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	trace_gma_index(__func__, gma, x);
48262306a36Sopenharmony_ci	return x;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci#define DEFINE_PPGTT_GMA_TO_INDEX(prefix, ename, exp) \
48662306a36Sopenharmony_cistatic unsigned long prefix##_gma_to_##ename##_index(unsigned long gma) \
48762306a36Sopenharmony_ci{ \
48862306a36Sopenharmony_ci	unsigned long x = (exp); \
48962306a36Sopenharmony_ci	trace_gma_index(__func__, gma, x); \
49062306a36Sopenharmony_ci	return x; \
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ciDEFINE_PPGTT_GMA_TO_INDEX(gen8, pte, (gma >> 12 & 0x1ff));
49462306a36Sopenharmony_ciDEFINE_PPGTT_GMA_TO_INDEX(gen8, pde, (gma >> 21 & 0x1ff));
49562306a36Sopenharmony_ciDEFINE_PPGTT_GMA_TO_INDEX(gen8, l3_pdp, (gma >> 30 & 0x3));
49662306a36Sopenharmony_ciDEFINE_PPGTT_GMA_TO_INDEX(gen8, l4_pdp, (gma >> 30 & 0x1ff));
49762306a36Sopenharmony_ciDEFINE_PPGTT_GMA_TO_INDEX(gen8, pml4, (gma >> 39 & 0x1ff));
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic const struct intel_gvt_gtt_pte_ops gen8_gtt_pte_ops = {
50062306a36Sopenharmony_ci	.get_entry = gtt_get_entry64,
50162306a36Sopenharmony_ci	.set_entry = gtt_set_entry64,
50262306a36Sopenharmony_ci	.clear_present = gtt_entry_clear_present,
50362306a36Sopenharmony_ci	.set_present = gtt_entry_set_present,
50462306a36Sopenharmony_ci	.test_present = gen8_gtt_test_present,
50562306a36Sopenharmony_ci	.test_pse = gen8_gtt_test_pse,
50662306a36Sopenharmony_ci	.clear_pse = gen8_gtt_clear_pse,
50762306a36Sopenharmony_ci	.clear_ips = gen8_gtt_clear_ips,
50862306a36Sopenharmony_ci	.test_ips = gen8_gtt_test_ips,
50962306a36Sopenharmony_ci	.clear_64k_splited = gen8_gtt_clear_64k_splited,
51062306a36Sopenharmony_ci	.set_64k_splited = gen8_gtt_set_64k_splited,
51162306a36Sopenharmony_ci	.test_64k_splited = gen8_gtt_test_64k_splited,
51262306a36Sopenharmony_ci	.get_pfn = gen8_gtt_get_pfn,
51362306a36Sopenharmony_ci	.set_pfn = gen8_gtt_set_pfn,
51462306a36Sopenharmony_ci};
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic const struct intel_gvt_gtt_gma_ops gen8_gtt_gma_ops = {
51762306a36Sopenharmony_ci	.gma_to_ggtt_pte_index = gma_to_ggtt_pte_index,
51862306a36Sopenharmony_ci	.gma_to_pte_index = gen8_gma_to_pte_index,
51962306a36Sopenharmony_ci	.gma_to_pde_index = gen8_gma_to_pde_index,
52062306a36Sopenharmony_ci	.gma_to_l3_pdp_index = gen8_gma_to_l3_pdp_index,
52162306a36Sopenharmony_ci	.gma_to_l4_pdp_index = gen8_gma_to_l4_pdp_index,
52262306a36Sopenharmony_ci	.gma_to_pml4_index = gen8_gma_to_pml4_index,
52362306a36Sopenharmony_ci};
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci/* Update entry type per pse and ips bit. */
52662306a36Sopenharmony_cistatic void update_entry_type_for_real(const struct intel_gvt_gtt_pte_ops *pte_ops,
52762306a36Sopenharmony_ci	struct intel_gvt_gtt_entry *entry, bool ips)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	switch (entry->type) {
53062306a36Sopenharmony_ci	case GTT_TYPE_PPGTT_PDE_ENTRY:
53162306a36Sopenharmony_ci	case GTT_TYPE_PPGTT_PDP_ENTRY:
53262306a36Sopenharmony_ci		if (pte_ops->test_pse(entry))
53362306a36Sopenharmony_ci			entry->type = get_pse_type(entry->type);
53462306a36Sopenharmony_ci		break;
53562306a36Sopenharmony_ci	case GTT_TYPE_PPGTT_PTE_4K_ENTRY:
53662306a36Sopenharmony_ci		if (ips)
53762306a36Sopenharmony_ci			entry->type = get_pse_type(entry->type);
53862306a36Sopenharmony_ci		break;
53962306a36Sopenharmony_ci	default:
54062306a36Sopenharmony_ci		GEM_BUG_ON(!gtt_type_is_entry(entry->type));
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	GEM_BUG_ON(entry->type == GTT_TYPE_INVALID);
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci/*
54762306a36Sopenharmony_ci * MM helpers.
54862306a36Sopenharmony_ci */
54962306a36Sopenharmony_cistatic void _ppgtt_get_root_entry(struct intel_vgpu_mm *mm,
55062306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index,
55162306a36Sopenharmony_ci		bool guest)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_PPGTT);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	entry->type = mm->ppgtt_mm.root_entry_type;
55862306a36Sopenharmony_ci	pte_ops->get_entry(guest ? mm->ppgtt_mm.guest_pdps :
55962306a36Sopenharmony_ci			   mm->ppgtt_mm.shadow_pdps,
56062306a36Sopenharmony_ci			   entry, index, false, 0, mm->vgpu);
56162306a36Sopenharmony_ci	update_entry_type_for_real(pte_ops, entry, false);
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic inline void ppgtt_get_guest_root_entry(struct intel_vgpu_mm *mm,
56562306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	_ppgtt_get_root_entry(mm, entry, index, true);
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic inline void ppgtt_get_shadow_root_entry(struct intel_vgpu_mm *mm,
57162306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	_ppgtt_get_root_entry(mm, entry, index, false);
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic void _ppgtt_set_root_entry(struct intel_vgpu_mm *mm,
57762306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index,
57862306a36Sopenharmony_ci		bool guest)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	pte_ops->set_entry(guest ? mm->ppgtt_mm.guest_pdps :
58362306a36Sopenharmony_ci			   mm->ppgtt_mm.shadow_pdps,
58462306a36Sopenharmony_ci			   entry, index, false, 0, mm->vgpu);
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic inline void ppgtt_set_shadow_root_entry(struct intel_vgpu_mm *mm,
58862306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	_ppgtt_set_root_entry(mm, entry, index, false);
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic void ggtt_get_guest_entry(struct intel_vgpu_mm *mm,
59462306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	entry->type = GTT_TYPE_GGTT_PTE;
60162306a36Sopenharmony_ci	pte_ops->get_entry(mm->ggtt_mm.virtual_ggtt, entry, index,
60262306a36Sopenharmony_ci			   false, 0, mm->vgpu);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic void ggtt_set_guest_entry(struct intel_vgpu_mm *mm,
60662306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	pte_ops->set_entry(mm->ggtt_mm.virtual_ggtt, entry, index,
61362306a36Sopenharmony_ci			   false, 0, mm->vgpu);
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic void ggtt_get_host_entry(struct intel_vgpu_mm *mm,
61762306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	pte_ops->get_entry(NULL, entry, index, false, 0, mm->vgpu);
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic void ggtt_set_host_entry(struct intel_vgpu_mm *mm,
62762306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
63062306a36Sopenharmony_ci	unsigned long offset = index;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (vgpu_gmadr_is_aperture(mm->vgpu, index << I915_GTT_PAGE_SHIFT)) {
63562306a36Sopenharmony_ci		offset -= (vgpu_aperture_gmadr_base(mm->vgpu) >> PAGE_SHIFT);
63662306a36Sopenharmony_ci		mm->ggtt_mm.host_ggtt_aperture[offset] = entry->val64;
63762306a36Sopenharmony_ci	} else if (vgpu_gmadr_is_hidden(mm->vgpu, index << I915_GTT_PAGE_SHIFT)) {
63862306a36Sopenharmony_ci		offset -= (vgpu_hidden_gmadr_base(mm->vgpu) >> PAGE_SHIFT);
63962306a36Sopenharmony_ci		mm->ggtt_mm.host_ggtt_hidden[offset] = entry->val64;
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	pte_ops->set_entry(NULL, entry, index, false, 0, mm->vgpu);
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci/*
64662306a36Sopenharmony_ci * PPGTT shadow page table helpers.
64762306a36Sopenharmony_ci */
64862306a36Sopenharmony_cistatic inline int ppgtt_spt_get_entry(
64962306a36Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt,
65062306a36Sopenharmony_ci		void *page_table, int type,
65162306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *e, unsigned long index,
65262306a36Sopenharmony_ci		bool guest)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	struct intel_gvt *gvt = spt->vgpu->gvt;
65562306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops;
65662306a36Sopenharmony_ci	int ret;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	e->type = get_entry_type(type);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (WARN(!gtt_type_is_entry(e->type), "invalid entry type\n"))
66162306a36Sopenharmony_ci		return -EINVAL;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	ret = ops->get_entry(page_table, e, index, guest,
66462306a36Sopenharmony_ci			spt->guest_page.gfn << I915_GTT_PAGE_SHIFT,
66562306a36Sopenharmony_ci			spt->vgpu);
66662306a36Sopenharmony_ci	if (ret)
66762306a36Sopenharmony_ci		return ret;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	update_entry_type_for_real(ops, e, guest ?
67062306a36Sopenharmony_ci				   spt->guest_page.pde_ips : false);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	gvt_vdbg_mm("read ppgtt entry, spt type %d, entry type %d, index %lu, value %llx\n",
67362306a36Sopenharmony_ci		    type, e->type, index, e->val64);
67462306a36Sopenharmony_ci	return 0;
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic inline int ppgtt_spt_set_entry(
67862306a36Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt,
67962306a36Sopenharmony_ci		void *page_table, int type,
68062306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *e, unsigned long index,
68162306a36Sopenharmony_ci		bool guest)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	struct intel_gvt *gvt = spt->vgpu->gvt;
68462306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	if (WARN(!gtt_type_is_entry(e->type), "invalid entry type\n"))
68762306a36Sopenharmony_ci		return -EINVAL;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	gvt_vdbg_mm("set ppgtt entry, spt type %d, entry type %d, index %lu, value %llx\n",
69062306a36Sopenharmony_ci		    type, e->type, index, e->val64);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	return ops->set_entry(page_table, e, index, guest,
69362306a36Sopenharmony_ci			spt->guest_page.gfn << I915_GTT_PAGE_SHIFT,
69462306a36Sopenharmony_ci			spt->vgpu);
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci#define ppgtt_get_guest_entry(spt, e, index) \
69862306a36Sopenharmony_ci	ppgtt_spt_get_entry(spt, NULL, \
69962306a36Sopenharmony_ci		spt->guest_page.type, e, index, true)
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci#define ppgtt_set_guest_entry(spt, e, index) \
70262306a36Sopenharmony_ci	ppgtt_spt_set_entry(spt, NULL, \
70362306a36Sopenharmony_ci		spt->guest_page.type, e, index, true)
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci#define ppgtt_get_shadow_entry(spt, e, index) \
70662306a36Sopenharmony_ci	ppgtt_spt_get_entry(spt, spt->shadow_page.vaddr, \
70762306a36Sopenharmony_ci		spt->shadow_page.type, e, index, false)
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci#define ppgtt_set_shadow_entry(spt, e, index) \
71062306a36Sopenharmony_ci	ppgtt_spt_set_entry(spt, spt->shadow_page.vaddr, \
71162306a36Sopenharmony_ci		spt->shadow_page.type, e, index, false)
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistatic void *alloc_spt(gfp_t gfp_mask)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	spt = kzalloc(sizeof(*spt), gfp_mask);
71862306a36Sopenharmony_ci	if (!spt)
71962306a36Sopenharmony_ci		return NULL;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	spt->shadow_page.page = alloc_page(gfp_mask);
72262306a36Sopenharmony_ci	if (!spt->shadow_page.page) {
72362306a36Sopenharmony_ci		kfree(spt);
72462306a36Sopenharmony_ci		return NULL;
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci	return spt;
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_cistatic void free_spt(struct intel_vgpu_ppgtt_spt *spt)
73062306a36Sopenharmony_ci{
73162306a36Sopenharmony_ci	__free_page(spt->shadow_page.page);
73262306a36Sopenharmony_ci	kfree(spt);
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_cistatic int detach_oos_page(struct intel_vgpu *vgpu,
73662306a36Sopenharmony_ci		struct intel_vgpu_oos_page *oos_page);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic void ppgtt_free_spt(struct intel_vgpu_ppgtt_spt *spt)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	struct device *kdev = spt->vgpu->gvt->gt->i915->drm.dev;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	trace_spt_free(spt->vgpu->id, spt, spt->guest_page.type);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	dma_unmap_page(kdev, spt->shadow_page.mfn << I915_GTT_PAGE_SHIFT, 4096,
74562306a36Sopenharmony_ci		       DMA_BIDIRECTIONAL);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	radix_tree_delete(&spt->vgpu->gtt.spt_tree, spt->shadow_page.mfn);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	if (spt->guest_page.gfn) {
75062306a36Sopenharmony_ci		if (spt->guest_page.oos_page)
75162306a36Sopenharmony_ci			detach_oos_page(spt->vgpu, spt->guest_page.oos_page);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		intel_vgpu_unregister_page_track(spt->vgpu, spt->guest_page.gfn);
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	list_del_init(&spt->post_shadow_list);
75762306a36Sopenharmony_ci	free_spt(spt);
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic void ppgtt_free_all_spt(struct intel_vgpu *vgpu)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt, *spn;
76362306a36Sopenharmony_ci	struct radix_tree_iter iter;
76462306a36Sopenharmony_ci	LIST_HEAD(all_spt);
76562306a36Sopenharmony_ci	void __rcu **slot;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	rcu_read_lock();
76862306a36Sopenharmony_ci	radix_tree_for_each_slot(slot, &vgpu->gtt.spt_tree, &iter, 0) {
76962306a36Sopenharmony_ci		spt = radix_tree_deref_slot(slot);
77062306a36Sopenharmony_ci		list_move(&spt->post_shadow_list, &all_spt);
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci	rcu_read_unlock();
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	list_for_each_entry_safe(spt, spn, &all_spt, post_shadow_list)
77562306a36Sopenharmony_ci		ppgtt_free_spt(spt);
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic int ppgtt_handle_guest_write_page_table_bytes(
77962306a36Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt,
78062306a36Sopenharmony_ci		u64 pa, void *p_data, int bytes);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cistatic int ppgtt_write_protection_handler(
78362306a36Sopenharmony_ci		struct intel_vgpu_page_track *page_track,
78462306a36Sopenharmony_ci		u64 gpa, void *data, int bytes)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt = page_track->priv_data;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	int ret;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	if (bytes != 4 && bytes != 8)
79162306a36Sopenharmony_ci		return -EINVAL;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	ret = ppgtt_handle_guest_write_page_table_bytes(spt, gpa, data, bytes);
79462306a36Sopenharmony_ci	if (ret)
79562306a36Sopenharmony_ci		return ret;
79662306a36Sopenharmony_ci	return ret;
79762306a36Sopenharmony_ci}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci/* Find a spt by guest gfn. */
80062306a36Sopenharmony_cistatic struct intel_vgpu_ppgtt_spt *intel_vgpu_find_spt_by_gfn(
80162306a36Sopenharmony_ci		struct intel_vgpu *vgpu, unsigned long gfn)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct intel_vgpu_page_track *track;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	track = intel_vgpu_find_page_track(vgpu, gfn);
80662306a36Sopenharmony_ci	if (track && track->handler == ppgtt_write_protection_handler)
80762306a36Sopenharmony_ci		return track->priv_data;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	return NULL;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci/* Find the spt by shadow page mfn. */
81362306a36Sopenharmony_cistatic inline struct intel_vgpu_ppgtt_spt *intel_vgpu_find_spt_by_mfn(
81462306a36Sopenharmony_ci		struct intel_vgpu *vgpu, unsigned long mfn)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	return radix_tree_lookup(&vgpu->gtt.spt_tree, mfn);
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic int reclaim_one_ppgtt_mm(struct intel_gvt *gvt);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci/* Allocate shadow page table without guest page. */
82262306a36Sopenharmony_cistatic struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt(
82362306a36Sopenharmony_ci		struct intel_vgpu *vgpu, enum intel_gvt_gtt_type type)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	struct device *kdev = vgpu->gvt->gt->i915->drm.dev;
82662306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt = NULL;
82762306a36Sopenharmony_ci	dma_addr_t daddr;
82862306a36Sopenharmony_ci	int ret;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ciretry:
83162306a36Sopenharmony_ci	spt = alloc_spt(GFP_KERNEL | __GFP_ZERO);
83262306a36Sopenharmony_ci	if (!spt) {
83362306a36Sopenharmony_ci		if (reclaim_one_ppgtt_mm(vgpu->gvt))
83462306a36Sopenharmony_ci			goto retry;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci		gvt_vgpu_err("fail to allocate ppgtt shadow page\n");
83762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	spt->vgpu = vgpu;
84162306a36Sopenharmony_ci	atomic_set(&spt->refcount, 1);
84262306a36Sopenharmony_ci	INIT_LIST_HEAD(&spt->post_shadow_list);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	/*
84562306a36Sopenharmony_ci	 * Init shadow_page.
84662306a36Sopenharmony_ci	 */
84762306a36Sopenharmony_ci	spt->shadow_page.type = type;
84862306a36Sopenharmony_ci	daddr = dma_map_page(kdev, spt->shadow_page.page,
84962306a36Sopenharmony_ci			     0, 4096, DMA_BIDIRECTIONAL);
85062306a36Sopenharmony_ci	if (dma_mapping_error(kdev, daddr)) {
85162306a36Sopenharmony_ci		gvt_vgpu_err("fail to map dma addr\n");
85262306a36Sopenharmony_ci		ret = -EINVAL;
85362306a36Sopenharmony_ci		goto err_free_spt;
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci	spt->shadow_page.vaddr = page_address(spt->shadow_page.page);
85662306a36Sopenharmony_ci	spt->shadow_page.mfn = daddr >> I915_GTT_PAGE_SHIFT;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	ret = radix_tree_insert(&vgpu->gtt.spt_tree, spt->shadow_page.mfn, spt);
85962306a36Sopenharmony_ci	if (ret)
86062306a36Sopenharmony_ci		goto err_unmap_dma;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	return spt;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cierr_unmap_dma:
86562306a36Sopenharmony_ci	dma_unmap_page(kdev, daddr, PAGE_SIZE, DMA_BIDIRECTIONAL);
86662306a36Sopenharmony_cierr_free_spt:
86762306a36Sopenharmony_ci	free_spt(spt);
86862306a36Sopenharmony_ci	return ERR_PTR(ret);
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci/* Allocate shadow page table associated with specific gfn. */
87262306a36Sopenharmony_cistatic struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt_gfn(
87362306a36Sopenharmony_ci		struct intel_vgpu *vgpu, enum intel_gvt_gtt_type type,
87462306a36Sopenharmony_ci		unsigned long gfn, bool guest_pde_ips)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt;
87762306a36Sopenharmony_ci	int ret;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	spt = ppgtt_alloc_spt(vgpu, type);
88062306a36Sopenharmony_ci	if (IS_ERR(spt))
88162306a36Sopenharmony_ci		return spt;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/*
88462306a36Sopenharmony_ci	 * Init guest_page.
88562306a36Sopenharmony_ci	 */
88662306a36Sopenharmony_ci	ret = intel_vgpu_register_page_track(vgpu, gfn,
88762306a36Sopenharmony_ci			ppgtt_write_protection_handler, spt);
88862306a36Sopenharmony_ci	if (ret) {
88962306a36Sopenharmony_ci		ppgtt_free_spt(spt);
89062306a36Sopenharmony_ci		return ERR_PTR(ret);
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	spt->guest_page.type = type;
89462306a36Sopenharmony_ci	spt->guest_page.gfn = gfn;
89562306a36Sopenharmony_ci	spt->guest_page.pde_ips = guest_pde_ips;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	trace_spt_alloc(vgpu->id, spt, type, spt->shadow_page.mfn, gfn);
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	return spt;
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci#define pt_entry_size_shift(spt) \
90362306a36Sopenharmony_ci	((spt)->vgpu->gvt->device_info.gtt_entry_size_shift)
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci#define pt_entries(spt) \
90662306a36Sopenharmony_ci	(I915_GTT_PAGE_SIZE >> pt_entry_size_shift(spt))
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci#define for_each_present_guest_entry(spt, e, i) \
90962306a36Sopenharmony_ci	for (i = 0; i < pt_entries(spt); \
91062306a36Sopenharmony_ci	     i += spt->guest_page.pde_ips ? GTT_64K_PTE_STRIDE : 1) \
91162306a36Sopenharmony_ci		if (!ppgtt_get_guest_entry(spt, e, i) && \
91262306a36Sopenharmony_ci		    spt->vgpu->gvt->gtt.pte_ops->test_present(e))
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci#define for_each_present_shadow_entry(spt, e, i) \
91562306a36Sopenharmony_ci	for (i = 0; i < pt_entries(spt); \
91662306a36Sopenharmony_ci	     i += spt->shadow_page.pde_ips ? GTT_64K_PTE_STRIDE : 1) \
91762306a36Sopenharmony_ci		if (!ppgtt_get_shadow_entry(spt, e, i) && \
91862306a36Sopenharmony_ci		    spt->vgpu->gvt->gtt.pte_ops->test_present(e))
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci#define for_each_shadow_entry(spt, e, i) \
92162306a36Sopenharmony_ci	for (i = 0; i < pt_entries(spt); \
92262306a36Sopenharmony_ci	     i += (spt->shadow_page.pde_ips ? GTT_64K_PTE_STRIDE : 1)) \
92362306a36Sopenharmony_ci		if (!ppgtt_get_shadow_entry(spt, e, i))
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic inline void ppgtt_get_spt(struct intel_vgpu_ppgtt_spt *spt)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	int v = atomic_read(&spt->refcount);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	trace_spt_refcount(spt->vgpu->id, "inc", spt, v, (v + 1));
93062306a36Sopenharmony_ci	atomic_inc(&spt->refcount);
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_cistatic inline int ppgtt_put_spt(struct intel_vgpu_ppgtt_spt *spt)
93462306a36Sopenharmony_ci{
93562306a36Sopenharmony_ci	int v = atomic_read(&spt->refcount);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	trace_spt_refcount(spt->vgpu->id, "dec", spt, v, (v - 1));
93862306a36Sopenharmony_ci	return atomic_dec_return(&spt->refcount);
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_cistatic int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic int ppgtt_invalidate_spt_by_shadow_entry(struct intel_vgpu *vgpu,
94462306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *e)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
94762306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
94862306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *s;
94962306a36Sopenharmony_ci	enum intel_gvt_gtt_type cur_pt_type;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	GEM_BUG_ON(!gtt_type_is_pt(get_next_pt_type(e->type)));
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (e->type != GTT_TYPE_PPGTT_ROOT_L3_ENTRY
95462306a36Sopenharmony_ci		&& e->type != GTT_TYPE_PPGTT_ROOT_L4_ENTRY) {
95562306a36Sopenharmony_ci		cur_pt_type = get_next_pt_type(e->type);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci		if (!gtt_type_is_pt(cur_pt_type) ||
95862306a36Sopenharmony_ci				!gtt_type_is_pt(cur_pt_type + 1)) {
95962306a36Sopenharmony_ci			drm_WARN(&i915->drm, 1,
96062306a36Sopenharmony_ci				 "Invalid page table type, cur_pt_type is: %d\n",
96162306a36Sopenharmony_ci				 cur_pt_type);
96262306a36Sopenharmony_ci			return -EINVAL;
96362306a36Sopenharmony_ci		}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci		cur_pt_type += 1;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci		if (ops->get_pfn(e) ==
96862306a36Sopenharmony_ci			vgpu->gtt.scratch_pt[cur_pt_type].page_mfn)
96962306a36Sopenharmony_ci			return 0;
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci	s = intel_vgpu_find_spt_by_mfn(vgpu, ops->get_pfn(e));
97262306a36Sopenharmony_ci	if (!s) {
97362306a36Sopenharmony_ci		gvt_vgpu_err("fail to find shadow page: mfn: 0x%lx\n",
97462306a36Sopenharmony_ci				ops->get_pfn(e));
97562306a36Sopenharmony_ci		return -ENXIO;
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci	return ppgtt_invalidate_spt(s);
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_cistatic inline void ppgtt_invalidate_pte(struct intel_vgpu_ppgtt_spt *spt,
98162306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
98462306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
98562306a36Sopenharmony_ci	unsigned long pfn;
98662306a36Sopenharmony_ci	int type;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	pfn = ops->get_pfn(entry);
98962306a36Sopenharmony_ci	type = spt->shadow_page.type;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	/* Uninitialized spte or unshadowed spte. */
99262306a36Sopenharmony_ci	if (!pfn || pfn == vgpu->gtt.scratch_pt[type].page_mfn)
99362306a36Sopenharmony_ci		return;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	intel_gvt_dma_unmap_guest_page(vgpu, pfn << PAGE_SHIFT);
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
100162306a36Sopenharmony_ci	struct intel_gvt_gtt_entry e;
100262306a36Sopenharmony_ci	unsigned long index;
100362306a36Sopenharmony_ci	int ret;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	trace_spt_change(spt->vgpu->id, "die", spt,
100662306a36Sopenharmony_ci			spt->guest_page.gfn, spt->shadow_page.type);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (ppgtt_put_spt(spt) > 0)
100962306a36Sopenharmony_ci		return 0;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	for_each_present_shadow_entry(spt, &e, index) {
101262306a36Sopenharmony_ci		switch (e.type) {
101362306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_4K_ENTRY:
101462306a36Sopenharmony_ci			gvt_vdbg_mm("invalidate 4K entry\n");
101562306a36Sopenharmony_ci			ppgtt_invalidate_pte(spt, &e);
101662306a36Sopenharmony_ci			break;
101762306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_64K_ENTRY:
101862306a36Sopenharmony_ci			/* We don't setup 64K shadow entry so far. */
101962306a36Sopenharmony_ci			WARN(1, "suspicious 64K gtt entry\n");
102062306a36Sopenharmony_ci			continue;
102162306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_2M_ENTRY:
102262306a36Sopenharmony_ci			gvt_vdbg_mm("invalidate 2M entry\n");
102362306a36Sopenharmony_ci			continue;
102462306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_1G_ENTRY:
102562306a36Sopenharmony_ci			WARN(1, "GVT doesn't support 1GB page\n");
102662306a36Sopenharmony_ci			continue;
102762306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_PML4_ENTRY:
102862306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_PDP_ENTRY:
102962306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_PDE_ENTRY:
103062306a36Sopenharmony_ci			gvt_vdbg_mm("invalidate PMUL4/PDP/PDE entry\n");
103162306a36Sopenharmony_ci			ret = ppgtt_invalidate_spt_by_shadow_entry(
103262306a36Sopenharmony_ci					spt->vgpu, &e);
103362306a36Sopenharmony_ci			if (ret)
103462306a36Sopenharmony_ci				goto fail;
103562306a36Sopenharmony_ci			break;
103662306a36Sopenharmony_ci		default:
103762306a36Sopenharmony_ci			GEM_BUG_ON(1);
103862306a36Sopenharmony_ci		}
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	trace_spt_change(spt->vgpu->id, "release", spt,
104262306a36Sopenharmony_ci			 spt->guest_page.gfn, spt->shadow_page.type);
104362306a36Sopenharmony_ci	ppgtt_free_spt(spt);
104462306a36Sopenharmony_ci	return 0;
104562306a36Sopenharmony_cifail:
104662306a36Sopenharmony_ci	gvt_vgpu_err("fail: shadow page %p shadow entry 0x%llx type %d\n",
104762306a36Sopenharmony_ci			spt, e.val64, e.type);
104862306a36Sopenharmony_ci	return ret;
104962306a36Sopenharmony_ci}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_cistatic bool vgpu_ips_enabled(struct intel_vgpu *vgpu)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	struct drm_i915_private *dev_priv = vgpu->gvt->gt->i915;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	if (GRAPHICS_VER(dev_priv) == 9) {
105662306a36Sopenharmony_ci		u32 ips = vgpu_vreg_t(vgpu, GEN8_GAMW_ECO_DEV_RW_IA) &
105762306a36Sopenharmony_ci			GAMW_ECO_ENABLE_64K_IPS_FIELD;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci		return ips == GAMW_ECO_ENABLE_64K_IPS_FIELD;
106062306a36Sopenharmony_ci	} else if (GRAPHICS_VER(dev_priv) >= 11) {
106162306a36Sopenharmony_ci		/* 64K paging only controlled by IPS bit in PTE now. */
106262306a36Sopenharmony_ci		return true;
106362306a36Sopenharmony_ci	} else
106462306a36Sopenharmony_ci		return false;
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_cistatic int ppgtt_populate_spt(struct intel_vgpu_ppgtt_spt *spt);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_cistatic struct intel_vgpu_ppgtt_spt *ppgtt_populate_spt_by_guest_entry(
107062306a36Sopenharmony_ci		struct intel_vgpu *vgpu, struct intel_gvt_gtt_entry *we)
107162306a36Sopenharmony_ci{
107262306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
107362306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt = NULL;
107462306a36Sopenharmony_ci	bool ips = false;
107562306a36Sopenharmony_ci	int ret;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	GEM_BUG_ON(!gtt_type_is_pt(get_next_pt_type(we->type)));
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	if (we->type == GTT_TYPE_PPGTT_PDE_ENTRY)
108062306a36Sopenharmony_ci		ips = vgpu_ips_enabled(vgpu) && ops->test_ips(we);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	spt = intel_vgpu_find_spt_by_gfn(vgpu, ops->get_pfn(we));
108362306a36Sopenharmony_ci	if (spt) {
108462306a36Sopenharmony_ci		ppgtt_get_spt(spt);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci		if (ips != spt->guest_page.pde_ips) {
108762306a36Sopenharmony_ci			spt->guest_page.pde_ips = ips;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci			gvt_dbg_mm("reshadow PDE since ips changed\n");
109062306a36Sopenharmony_ci			clear_page(spt->shadow_page.vaddr);
109162306a36Sopenharmony_ci			ret = ppgtt_populate_spt(spt);
109262306a36Sopenharmony_ci			if (ret) {
109362306a36Sopenharmony_ci				ppgtt_put_spt(spt);
109462306a36Sopenharmony_ci				goto err;
109562306a36Sopenharmony_ci			}
109662306a36Sopenharmony_ci		}
109762306a36Sopenharmony_ci	} else {
109862306a36Sopenharmony_ci		int type = get_next_pt_type(we->type);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci		if (!gtt_type_is_pt(type)) {
110162306a36Sopenharmony_ci			ret = -EINVAL;
110262306a36Sopenharmony_ci			goto err;
110362306a36Sopenharmony_ci		}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci		spt = ppgtt_alloc_spt_gfn(vgpu, type, ops->get_pfn(we), ips);
110662306a36Sopenharmony_ci		if (IS_ERR(spt)) {
110762306a36Sopenharmony_ci			ret = PTR_ERR(spt);
110862306a36Sopenharmony_ci			goto err;
110962306a36Sopenharmony_ci		}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci		ret = intel_vgpu_enable_page_track(vgpu, spt->guest_page.gfn);
111262306a36Sopenharmony_ci		if (ret)
111362306a36Sopenharmony_ci			goto err_free_spt;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci		ret = ppgtt_populate_spt(spt);
111662306a36Sopenharmony_ci		if (ret)
111762306a36Sopenharmony_ci			goto err_free_spt;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci		trace_spt_change(vgpu->id, "new", spt, spt->guest_page.gfn,
112062306a36Sopenharmony_ci				 spt->shadow_page.type);
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci	return spt;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_cierr_free_spt:
112562306a36Sopenharmony_ci	ppgtt_free_spt(spt);
112662306a36Sopenharmony_ci	spt = NULL;
112762306a36Sopenharmony_cierr:
112862306a36Sopenharmony_ci	gvt_vgpu_err("fail: shadow page %p guest entry 0x%llx type %d\n",
112962306a36Sopenharmony_ci		     spt, we->val64, we->type);
113062306a36Sopenharmony_ci	return ERR_PTR(ret);
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se,
113462306a36Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *s, struct intel_gvt_gtt_entry *ge)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = s->vgpu->gvt->gtt.pte_ops;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	se->type = ge->type;
113962306a36Sopenharmony_ci	se->val64 = ge->val64;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/* Because we always split 64KB pages, so clear IPS in shadow PDE. */
114262306a36Sopenharmony_ci	if (se->type == GTT_TYPE_PPGTT_PDE_ENTRY)
114362306a36Sopenharmony_ci		ops->clear_ips(se);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	ops->set_pfn(se, s->shadow_page.mfn);
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_cistatic int split_2MB_gtt_entry(struct intel_vgpu *vgpu,
114962306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt, unsigned long index,
115062306a36Sopenharmony_ci	struct intel_gvt_gtt_entry *se)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
115362306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *sub_spt;
115462306a36Sopenharmony_ci	struct intel_gvt_gtt_entry sub_se;
115562306a36Sopenharmony_ci	unsigned long start_gfn;
115662306a36Sopenharmony_ci	dma_addr_t dma_addr;
115762306a36Sopenharmony_ci	unsigned long sub_index;
115862306a36Sopenharmony_ci	int ret;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	gvt_dbg_mm("Split 2M gtt entry, index %lu\n", index);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	start_gfn = ops->get_pfn(se);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	sub_spt = ppgtt_alloc_spt(vgpu, GTT_TYPE_PPGTT_PTE_PT);
116562306a36Sopenharmony_ci	if (IS_ERR(sub_spt))
116662306a36Sopenharmony_ci		return PTR_ERR(sub_spt);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	for_each_shadow_entry(sub_spt, &sub_se, sub_index) {
116962306a36Sopenharmony_ci		ret = intel_gvt_dma_map_guest_page(vgpu, start_gfn + sub_index,
117062306a36Sopenharmony_ci						   PAGE_SIZE, &dma_addr);
117162306a36Sopenharmony_ci		if (ret)
117262306a36Sopenharmony_ci			goto err;
117362306a36Sopenharmony_ci		sub_se.val64 = se->val64;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci		/* Copy the PAT field from PDE. */
117662306a36Sopenharmony_ci		sub_se.val64 &= ~_PAGE_PAT;
117762306a36Sopenharmony_ci		sub_se.val64 |= (se->val64 & _PAGE_PAT_LARGE) >> 5;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci		ops->set_pfn(&sub_se, dma_addr >> PAGE_SHIFT);
118062306a36Sopenharmony_ci		ppgtt_set_shadow_entry(sub_spt, &sub_se, sub_index);
118162306a36Sopenharmony_ci	}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/* Clear dirty field. */
118462306a36Sopenharmony_ci	se->val64 &= ~_PAGE_DIRTY;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	ops->clear_pse(se);
118762306a36Sopenharmony_ci	ops->clear_ips(se);
118862306a36Sopenharmony_ci	ops->set_pfn(se, sub_spt->shadow_page.mfn);
118962306a36Sopenharmony_ci	ppgtt_set_shadow_entry(spt, se, index);
119062306a36Sopenharmony_ci	return 0;
119162306a36Sopenharmony_cierr:
119262306a36Sopenharmony_ci	/* Cancel the existing addess mappings of DMA addr. */
119362306a36Sopenharmony_ci	for_each_present_shadow_entry(sub_spt, &sub_se, sub_index) {
119462306a36Sopenharmony_ci		gvt_vdbg_mm("invalidate 4K entry\n");
119562306a36Sopenharmony_ci		ppgtt_invalidate_pte(sub_spt, &sub_se);
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci	/* Release the new allocated spt. */
119862306a36Sopenharmony_ci	trace_spt_change(sub_spt->vgpu->id, "release", sub_spt,
119962306a36Sopenharmony_ci		sub_spt->guest_page.gfn, sub_spt->shadow_page.type);
120062306a36Sopenharmony_ci	ppgtt_free_spt(sub_spt);
120162306a36Sopenharmony_ci	return ret;
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_cistatic int split_64KB_gtt_entry(struct intel_vgpu *vgpu,
120562306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt, unsigned long index,
120662306a36Sopenharmony_ci	struct intel_gvt_gtt_entry *se)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
120962306a36Sopenharmony_ci	struct intel_gvt_gtt_entry entry = *se;
121062306a36Sopenharmony_ci	unsigned long start_gfn;
121162306a36Sopenharmony_ci	dma_addr_t dma_addr;
121262306a36Sopenharmony_ci	int i, ret;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	gvt_vdbg_mm("Split 64K gtt entry, index %lu\n", index);
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	GEM_BUG_ON(index % GTT_64K_PTE_STRIDE);
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	start_gfn = ops->get_pfn(se);
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	entry.type = GTT_TYPE_PPGTT_PTE_4K_ENTRY;
122162306a36Sopenharmony_ci	ops->set_64k_splited(&entry);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	for (i = 0; i < GTT_64K_PTE_STRIDE; i++) {
122462306a36Sopenharmony_ci		ret = intel_gvt_dma_map_guest_page(vgpu, start_gfn + i,
122562306a36Sopenharmony_ci						   PAGE_SIZE, &dma_addr);
122662306a36Sopenharmony_ci		if (ret)
122762306a36Sopenharmony_ci			return ret;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci		ops->set_pfn(&entry, dma_addr >> PAGE_SHIFT);
123062306a36Sopenharmony_ci		ppgtt_set_shadow_entry(spt, &entry, index + i);
123162306a36Sopenharmony_ci	}
123262306a36Sopenharmony_ci	return 0;
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu,
123662306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt, unsigned long index,
123762306a36Sopenharmony_ci	struct intel_gvt_gtt_entry *ge)
123862306a36Sopenharmony_ci{
123962306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops;
124062306a36Sopenharmony_ci	struct intel_gvt_gtt_entry se = *ge;
124162306a36Sopenharmony_ci	unsigned long gfn;
124262306a36Sopenharmony_ci	dma_addr_t dma_addr;
124362306a36Sopenharmony_ci	int ret;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (!pte_ops->test_present(ge))
124662306a36Sopenharmony_ci		return 0;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	gfn = pte_ops->get_pfn(ge);
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	switch (ge->type) {
125162306a36Sopenharmony_ci	case GTT_TYPE_PPGTT_PTE_4K_ENTRY:
125262306a36Sopenharmony_ci		gvt_vdbg_mm("shadow 4K gtt entry\n");
125362306a36Sopenharmony_ci		ret = intel_gvt_dma_map_guest_page(vgpu, gfn, PAGE_SIZE, &dma_addr);
125462306a36Sopenharmony_ci		if (ret)
125562306a36Sopenharmony_ci			return -ENXIO;
125662306a36Sopenharmony_ci		break;
125762306a36Sopenharmony_ci	case GTT_TYPE_PPGTT_PTE_64K_ENTRY:
125862306a36Sopenharmony_ci		gvt_vdbg_mm("shadow 64K gtt entry\n");
125962306a36Sopenharmony_ci		/*
126062306a36Sopenharmony_ci		 * The layout of 64K page is special, the page size is
126162306a36Sopenharmony_ci		 * controlled by uper PDE. To be simple, we always split
126262306a36Sopenharmony_ci		 * 64K page to smaller 4K pages in shadow PT.
126362306a36Sopenharmony_ci		 */
126462306a36Sopenharmony_ci		return split_64KB_gtt_entry(vgpu, spt, index, &se);
126562306a36Sopenharmony_ci	case GTT_TYPE_PPGTT_PTE_2M_ENTRY:
126662306a36Sopenharmony_ci		gvt_vdbg_mm("shadow 2M gtt entry\n");
126762306a36Sopenharmony_ci		if (!HAS_PAGE_SIZES(vgpu->gvt->gt->i915, I915_GTT_PAGE_SIZE_2M) ||
126862306a36Sopenharmony_ci		    intel_gvt_dma_map_guest_page(vgpu, gfn,
126962306a36Sopenharmony_ci						 I915_GTT_PAGE_SIZE_2M, &dma_addr))
127062306a36Sopenharmony_ci			return split_2MB_gtt_entry(vgpu, spt, index, &se);
127162306a36Sopenharmony_ci		break;
127262306a36Sopenharmony_ci	case GTT_TYPE_PPGTT_PTE_1G_ENTRY:
127362306a36Sopenharmony_ci		gvt_vgpu_err("GVT doesn't support 1GB entry\n");
127462306a36Sopenharmony_ci		return -EINVAL;
127562306a36Sopenharmony_ci	default:
127662306a36Sopenharmony_ci		GEM_BUG_ON(1);
127762306a36Sopenharmony_ci		return -EINVAL;
127862306a36Sopenharmony_ci	}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	/* Successfully shadowed a 4K or 2M page (without splitting). */
128162306a36Sopenharmony_ci	pte_ops->set_pfn(&se, dma_addr >> PAGE_SHIFT);
128262306a36Sopenharmony_ci	ppgtt_set_shadow_entry(spt, &se, index);
128362306a36Sopenharmony_ci	return 0;
128462306a36Sopenharmony_ci}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_cistatic int ppgtt_populate_spt(struct intel_vgpu_ppgtt_spt *spt)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
128962306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *s;
129062306a36Sopenharmony_ci	struct intel_gvt_gtt_entry se, ge;
129162306a36Sopenharmony_ci	unsigned long i;
129262306a36Sopenharmony_ci	int ret;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	trace_spt_change(spt->vgpu->id, "born", spt,
129562306a36Sopenharmony_ci			 spt->guest_page.gfn, spt->shadow_page.type);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	for_each_present_guest_entry(spt, &ge, i) {
129862306a36Sopenharmony_ci		if (gtt_type_is_pt(get_next_pt_type(ge.type))) {
129962306a36Sopenharmony_ci			s = ppgtt_populate_spt_by_guest_entry(vgpu, &ge);
130062306a36Sopenharmony_ci			if (IS_ERR(s)) {
130162306a36Sopenharmony_ci				ret = PTR_ERR(s);
130262306a36Sopenharmony_ci				goto fail;
130362306a36Sopenharmony_ci			}
130462306a36Sopenharmony_ci			ppgtt_get_shadow_entry(spt, &se, i);
130562306a36Sopenharmony_ci			ppgtt_generate_shadow_entry(&se, s, &ge);
130662306a36Sopenharmony_ci			ppgtt_set_shadow_entry(spt, &se, i);
130762306a36Sopenharmony_ci		} else {
130862306a36Sopenharmony_ci			ret = ppgtt_populate_shadow_entry(vgpu, spt, i, &ge);
130962306a36Sopenharmony_ci			if (ret)
131062306a36Sopenharmony_ci				goto fail;
131162306a36Sopenharmony_ci		}
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci	return 0;
131462306a36Sopenharmony_cifail:
131562306a36Sopenharmony_ci	gvt_vgpu_err("fail: shadow page %p guest entry 0x%llx type %d\n",
131662306a36Sopenharmony_ci			spt, ge.val64, ge.type);
131762306a36Sopenharmony_ci	return ret;
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_cistatic int ppgtt_handle_guest_entry_removal(struct intel_vgpu_ppgtt_spt *spt,
132162306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *se, unsigned long index)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
132462306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
132562306a36Sopenharmony_ci	int ret;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	trace_spt_guest_change(spt->vgpu->id, "remove", spt,
132862306a36Sopenharmony_ci			       spt->shadow_page.type, se->val64, index);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	gvt_vdbg_mm("destroy old shadow entry, type %d, index %lu, value %llx\n",
133162306a36Sopenharmony_ci		    se->type, index, se->val64);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (!ops->test_present(se))
133462306a36Sopenharmony_ci		return 0;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	if (ops->get_pfn(se) ==
133762306a36Sopenharmony_ci	    vgpu->gtt.scratch_pt[spt->shadow_page.type].page_mfn)
133862306a36Sopenharmony_ci		return 0;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	if (gtt_type_is_pt(get_next_pt_type(se->type))) {
134162306a36Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *s =
134262306a36Sopenharmony_ci			intel_vgpu_find_spt_by_mfn(vgpu, ops->get_pfn(se));
134362306a36Sopenharmony_ci		if (!s) {
134462306a36Sopenharmony_ci			gvt_vgpu_err("fail to find guest page\n");
134562306a36Sopenharmony_ci			ret = -ENXIO;
134662306a36Sopenharmony_ci			goto fail;
134762306a36Sopenharmony_ci		}
134862306a36Sopenharmony_ci		ret = ppgtt_invalidate_spt(s);
134962306a36Sopenharmony_ci		if (ret)
135062306a36Sopenharmony_ci			goto fail;
135162306a36Sopenharmony_ci	} else {
135262306a36Sopenharmony_ci		/* We don't setup 64K shadow entry so far. */
135362306a36Sopenharmony_ci		WARN(se->type == GTT_TYPE_PPGTT_PTE_64K_ENTRY,
135462306a36Sopenharmony_ci		     "suspicious 64K entry\n");
135562306a36Sopenharmony_ci		ppgtt_invalidate_pte(spt, se);
135662306a36Sopenharmony_ci	}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	return 0;
135962306a36Sopenharmony_cifail:
136062306a36Sopenharmony_ci	gvt_vgpu_err("fail: shadow page %p guest entry 0x%llx type %d\n",
136162306a36Sopenharmony_ci			spt, se->val64, se->type);
136262306a36Sopenharmony_ci	return ret;
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic int ppgtt_handle_guest_entry_add(struct intel_vgpu_ppgtt_spt *spt,
136662306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *we, unsigned long index)
136762306a36Sopenharmony_ci{
136862306a36Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
136962306a36Sopenharmony_ci	struct intel_gvt_gtt_entry m;
137062306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *s;
137162306a36Sopenharmony_ci	int ret;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	trace_spt_guest_change(spt->vgpu->id, "add", spt, spt->shadow_page.type,
137462306a36Sopenharmony_ci			       we->val64, index);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	gvt_vdbg_mm("add shadow entry: type %d, index %lu, value %llx\n",
137762306a36Sopenharmony_ci		    we->type, index, we->val64);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	if (gtt_type_is_pt(get_next_pt_type(we->type))) {
138062306a36Sopenharmony_ci		s = ppgtt_populate_spt_by_guest_entry(vgpu, we);
138162306a36Sopenharmony_ci		if (IS_ERR(s)) {
138262306a36Sopenharmony_ci			ret = PTR_ERR(s);
138362306a36Sopenharmony_ci			goto fail;
138462306a36Sopenharmony_ci		}
138562306a36Sopenharmony_ci		ppgtt_get_shadow_entry(spt, &m, index);
138662306a36Sopenharmony_ci		ppgtt_generate_shadow_entry(&m, s, we);
138762306a36Sopenharmony_ci		ppgtt_set_shadow_entry(spt, &m, index);
138862306a36Sopenharmony_ci	} else {
138962306a36Sopenharmony_ci		ret = ppgtt_populate_shadow_entry(vgpu, spt, index, we);
139062306a36Sopenharmony_ci		if (ret)
139162306a36Sopenharmony_ci			goto fail;
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci	return 0;
139462306a36Sopenharmony_cifail:
139562306a36Sopenharmony_ci	gvt_vgpu_err("fail: spt %p guest entry 0x%llx type %d\n",
139662306a36Sopenharmony_ci		spt, we->val64, we->type);
139762306a36Sopenharmony_ci	return ret;
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cistatic int sync_oos_page(struct intel_vgpu *vgpu,
140162306a36Sopenharmony_ci		struct intel_vgpu_oos_page *oos_page)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
140462306a36Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
140562306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops;
140662306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt = oos_page->spt;
140762306a36Sopenharmony_ci	struct intel_gvt_gtt_entry old, new;
140862306a36Sopenharmony_ci	int index;
140962306a36Sopenharmony_ci	int ret;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	trace_oos_change(vgpu->id, "sync", oos_page->id,
141262306a36Sopenharmony_ci			 spt, spt->guest_page.type);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	old.type = new.type = get_entry_type(spt->guest_page.type);
141562306a36Sopenharmony_ci	old.val64 = new.val64 = 0;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	for (index = 0; index < (I915_GTT_PAGE_SIZE >>
141862306a36Sopenharmony_ci				info->gtt_entry_size_shift); index++) {
141962306a36Sopenharmony_ci		ops->get_entry(oos_page->mem, &old, index, false, 0, vgpu);
142062306a36Sopenharmony_ci		ops->get_entry(NULL, &new, index, true,
142162306a36Sopenharmony_ci			       spt->guest_page.gfn << PAGE_SHIFT, vgpu);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci		if (old.val64 == new.val64
142462306a36Sopenharmony_ci			&& !test_and_clear_bit(index, spt->post_shadow_bitmap))
142562306a36Sopenharmony_ci			continue;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci		trace_oos_sync(vgpu->id, oos_page->id,
142862306a36Sopenharmony_ci				spt, spt->guest_page.type,
142962306a36Sopenharmony_ci				new.val64, index);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci		ret = ppgtt_populate_shadow_entry(vgpu, spt, index, &new);
143262306a36Sopenharmony_ci		if (ret)
143362306a36Sopenharmony_ci			return ret;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci		ops->set_entry(oos_page->mem, &new, index, false, 0, vgpu);
143662306a36Sopenharmony_ci	}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	spt->guest_page.write_cnt = 0;
143962306a36Sopenharmony_ci	list_del_init(&spt->post_shadow_list);
144062306a36Sopenharmony_ci	return 0;
144162306a36Sopenharmony_ci}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_cistatic int detach_oos_page(struct intel_vgpu *vgpu,
144462306a36Sopenharmony_ci		struct intel_vgpu_oos_page *oos_page)
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
144762306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt = oos_page->spt;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	trace_oos_change(vgpu->id, "detach", oos_page->id,
145062306a36Sopenharmony_ci			 spt, spt->guest_page.type);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	spt->guest_page.write_cnt = 0;
145362306a36Sopenharmony_ci	spt->guest_page.oos_page = NULL;
145462306a36Sopenharmony_ci	oos_page->spt = NULL;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	list_del_init(&oos_page->vm_list);
145762306a36Sopenharmony_ci	list_move_tail(&oos_page->list, &gvt->gtt.oos_page_free_list_head);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	return 0;
146062306a36Sopenharmony_ci}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_cistatic int attach_oos_page(struct intel_vgpu_oos_page *oos_page,
146362306a36Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt)
146462306a36Sopenharmony_ci{
146562306a36Sopenharmony_ci	struct intel_gvt *gvt = spt->vgpu->gvt;
146662306a36Sopenharmony_ci	int ret;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	ret = intel_gvt_read_gpa(spt->vgpu,
146962306a36Sopenharmony_ci			spt->guest_page.gfn << I915_GTT_PAGE_SHIFT,
147062306a36Sopenharmony_ci			oos_page->mem, I915_GTT_PAGE_SIZE);
147162306a36Sopenharmony_ci	if (ret)
147262306a36Sopenharmony_ci		return ret;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	oos_page->spt = spt;
147562306a36Sopenharmony_ci	spt->guest_page.oos_page = oos_page;
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	list_move_tail(&oos_page->list, &gvt->gtt.oos_page_use_list_head);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	trace_oos_change(spt->vgpu->id, "attach", oos_page->id,
148062306a36Sopenharmony_ci			 spt, spt->guest_page.type);
148162306a36Sopenharmony_ci	return 0;
148262306a36Sopenharmony_ci}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_cistatic int ppgtt_set_guest_page_sync(struct intel_vgpu_ppgtt_spt *spt)
148562306a36Sopenharmony_ci{
148662306a36Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page = spt->guest_page.oos_page;
148762306a36Sopenharmony_ci	int ret;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	ret = intel_vgpu_enable_page_track(spt->vgpu, spt->guest_page.gfn);
149062306a36Sopenharmony_ci	if (ret)
149162306a36Sopenharmony_ci		return ret;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	trace_oos_change(spt->vgpu->id, "set page sync", oos_page->id,
149462306a36Sopenharmony_ci			 spt, spt->guest_page.type);
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	list_del_init(&oos_page->vm_list);
149762306a36Sopenharmony_ci	return sync_oos_page(spt->vgpu, oos_page);
149862306a36Sopenharmony_ci}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_cistatic int ppgtt_allocate_oos_page(struct intel_vgpu_ppgtt_spt *spt)
150162306a36Sopenharmony_ci{
150262306a36Sopenharmony_ci	struct intel_gvt *gvt = spt->vgpu->gvt;
150362306a36Sopenharmony_ci	struct intel_gvt_gtt *gtt = &gvt->gtt;
150462306a36Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page = spt->guest_page.oos_page;
150562306a36Sopenharmony_ci	int ret;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	WARN(oos_page, "shadow PPGTT page has already has a oos page\n");
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	if (list_empty(&gtt->oos_page_free_list_head)) {
151062306a36Sopenharmony_ci		oos_page = container_of(gtt->oos_page_use_list_head.next,
151162306a36Sopenharmony_ci			struct intel_vgpu_oos_page, list);
151262306a36Sopenharmony_ci		ret = ppgtt_set_guest_page_sync(oos_page->spt);
151362306a36Sopenharmony_ci		if (ret)
151462306a36Sopenharmony_ci			return ret;
151562306a36Sopenharmony_ci		ret = detach_oos_page(spt->vgpu, oos_page);
151662306a36Sopenharmony_ci		if (ret)
151762306a36Sopenharmony_ci			return ret;
151862306a36Sopenharmony_ci	} else
151962306a36Sopenharmony_ci		oos_page = container_of(gtt->oos_page_free_list_head.next,
152062306a36Sopenharmony_ci			struct intel_vgpu_oos_page, list);
152162306a36Sopenharmony_ci	return attach_oos_page(oos_page, spt);
152262306a36Sopenharmony_ci}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_cistatic int ppgtt_set_guest_page_oos(struct intel_vgpu_ppgtt_spt *spt)
152562306a36Sopenharmony_ci{
152662306a36Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page = spt->guest_page.oos_page;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if (WARN(!oos_page, "shadow PPGTT page should have a oos page\n"))
152962306a36Sopenharmony_ci		return -EINVAL;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	trace_oos_change(spt->vgpu->id, "set page out of sync", oos_page->id,
153262306a36Sopenharmony_ci			 spt, spt->guest_page.type);
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	list_add_tail(&oos_page->vm_list, &spt->vgpu->gtt.oos_page_list_head);
153562306a36Sopenharmony_ci	return intel_vgpu_disable_page_track(spt->vgpu, spt->guest_page.gfn);
153662306a36Sopenharmony_ci}
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci/**
153962306a36Sopenharmony_ci * intel_vgpu_sync_oos_pages - sync all the out-of-synced shadow for vGPU
154062306a36Sopenharmony_ci * @vgpu: a vGPU
154162306a36Sopenharmony_ci *
154262306a36Sopenharmony_ci * This function is called before submitting a guest workload to host,
154362306a36Sopenharmony_ci * to sync all the out-of-synced shadow for vGPU
154462306a36Sopenharmony_ci *
154562306a36Sopenharmony_ci * Returns:
154662306a36Sopenharmony_ci * Zero on success, negative error code if failed.
154762306a36Sopenharmony_ci */
154862306a36Sopenharmony_ciint intel_vgpu_sync_oos_pages(struct intel_vgpu *vgpu)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	struct list_head *pos, *n;
155162306a36Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page;
155262306a36Sopenharmony_ci	int ret;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	if (!enable_out_of_sync)
155562306a36Sopenharmony_ci		return 0;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	list_for_each_safe(pos, n, &vgpu->gtt.oos_page_list_head) {
155862306a36Sopenharmony_ci		oos_page = container_of(pos,
155962306a36Sopenharmony_ci				struct intel_vgpu_oos_page, vm_list);
156062306a36Sopenharmony_ci		ret = ppgtt_set_guest_page_sync(oos_page->spt);
156162306a36Sopenharmony_ci		if (ret)
156262306a36Sopenharmony_ci			return ret;
156362306a36Sopenharmony_ci	}
156462306a36Sopenharmony_ci	return 0;
156562306a36Sopenharmony_ci}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci/*
156862306a36Sopenharmony_ci * The heart of PPGTT shadow page table.
156962306a36Sopenharmony_ci */
157062306a36Sopenharmony_cistatic int ppgtt_handle_guest_write_page_table(
157162306a36Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt,
157262306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *we, unsigned long index)
157362306a36Sopenharmony_ci{
157462306a36Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
157562306a36Sopenharmony_ci	int type = spt->shadow_page.type;
157662306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
157762306a36Sopenharmony_ci	struct intel_gvt_gtt_entry old_se;
157862306a36Sopenharmony_ci	int new_present;
157962306a36Sopenharmony_ci	int i, ret;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	new_present = ops->test_present(we);
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	/*
158462306a36Sopenharmony_ci	 * Adding the new entry first and then removing the old one, that can
158562306a36Sopenharmony_ci	 * guarantee the ppgtt table is validated during the window between
158662306a36Sopenharmony_ci	 * adding and removal.
158762306a36Sopenharmony_ci	 */
158862306a36Sopenharmony_ci	ppgtt_get_shadow_entry(spt, &old_se, index);
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	if (new_present) {
159162306a36Sopenharmony_ci		ret = ppgtt_handle_guest_entry_add(spt, we, index);
159262306a36Sopenharmony_ci		if (ret)
159362306a36Sopenharmony_ci			goto fail;
159462306a36Sopenharmony_ci	}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	ret = ppgtt_handle_guest_entry_removal(spt, &old_se, index);
159762306a36Sopenharmony_ci	if (ret)
159862306a36Sopenharmony_ci		goto fail;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	if (!new_present) {
160162306a36Sopenharmony_ci		/* For 64KB splited entries, we need clear them all. */
160262306a36Sopenharmony_ci		if (ops->test_64k_splited(&old_se) &&
160362306a36Sopenharmony_ci		    !(index % GTT_64K_PTE_STRIDE)) {
160462306a36Sopenharmony_ci			gvt_vdbg_mm("remove splited 64K shadow entries\n");
160562306a36Sopenharmony_ci			for (i = 0; i < GTT_64K_PTE_STRIDE; i++) {
160662306a36Sopenharmony_ci				ops->clear_64k_splited(&old_se);
160762306a36Sopenharmony_ci				ops->set_pfn(&old_se,
160862306a36Sopenharmony_ci					vgpu->gtt.scratch_pt[type].page_mfn);
160962306a36Sopenharmony_ci				ppgtt_set_shadow_entry(spt, &old_se, index + i);
161062306a36Sopenharmony_ci			}
161162306a36Sopenharmony_ci		} else if (old_se.type == GTT_TYPE_PPGTT_PTE_2M_ENTRY ||
161262306a36Sopenharmony_ci			   old_se.type == GTT_TYPE_PPGTT_PTE_1G_ENTRY) {
161362306a36Sopenharmony_ci			ops->clear_pse(&old_se);
161462306a36Sopenharmony_ci			ops->set_pfn(&old_se,
161562306a36Sopenharmony_ci				     vgpu->gtt.scratch_pt[type].page_mfn);
161662306a36Sopenharmony_ci			ppgtt_set_shadow_entry(spt, &old_se, index);
161762306a36Sopenharmony_ci		} else {
161862306a36Sopenharmony_ci			ops->set_pfn(&old_se,
161962306a36Sopenharmony_ci				     vgpu->gtt.scratch_pt[type].page_mfn);
162062306a36Sopenharmony_ci			ppgtt_set_shadow_entry(spt, &old_se, index);
162162306a36Sopenharmony_ci		}
162262306a36Sopenharmony_ci	}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	return 0;
162562306a36Sopenharmony_cifail:
162662306a36Sopenharmony_ci	gvt_vgpu_err("fail: shadow page %p guest entry 0x%llx type %d.\n",
162762306a36Sopenharmony_ci			spt, we->val64, we->type);
162862306a36Sopenharmony_ci	return ret;
162962306a36Sopenharmony_ci}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_cistatic inline bool can_do_out_of_sync(struct intel_vgpu_ppgtt_spt *spt)
163462306a36Sopenharmony_ci{
163562306a36Sopenharmony_ci	return enable_out_of_sync
163662306a36Sopenharmony_ci		&& gtt_type_is_pte_pt(spt->guest_page.type)
163762306a36Sopenharmony_ci		&& spt->guest_page.write_cnt >= 2;
163862306a36Sopenharmony_ci}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_cistatic void ppgtt_set_post_shadow(struct intel_vgpu_ppgtt_spt *spt,
164162306a36Sopenharmony_ci		unsigned long index)
164262306a36Sopenharmony_ci{
164362306a36Sopenharmony_ci	set_bit(index, spt->post_shadow_bitmap);
164462306a36Sopenharmony_ci	if (!list_empty(&spt->post_shadow_list))
164562306a36Sopenharmony_ci		return;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	list_add_tail(&spt->post_shadow_list,
164862306a36Sopenharmony_ci			&spt->vgpu->gtt.post_shadow_list_head);
164962306a36Sopenharmony_ci}
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci/**
165262306a36Sopenharmony_ci * intel_vgpu_flush_post_shadow - flush the post shadow transactions
165362306a36Sopenharmony_ci * @vgpu: a vGPU
165462306a36Sopenharmony_ci *
165562306a36Sopenharmony_ci * This function is called before submitting a guest workload to host,
165662306a36Sopenharmony_ci * to flush all the post shadows for a vGPU.
165762306a36Sopenharmony_ci *
165862306a36Sopenharmony_ci * Returns:
165962306a36Sopenharmony_ci * Zero on success, negative error code if failed.
166062306a36Sopenharmony_ci */
166162306a36Sopenharmony_ciint intel_vgpu_flush_post_shadow(struct intel_vgpu *vgpu)
166262306a36Sopenharmony_ci{
166362306a36Sopenharmony_ci	struct list_head *pos, *n;
166462306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt;
166562306a36Sopenharmony_ci	struct intel_gvt_gtt_entry ge;
166662306a36Sopenharmony_ci	unsigned long index;
166762306a36Sopenharmony_ci	int ret;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	list_for_each_safe(pos, n, &vgpu->gtt.post_shadow_list_head) {
167062306a36Sopenharmony_ci		spt = container_of(pos, struct intel_vgpu_ppgtt_spt,
167162306a36Sopenharmony_ci				post_shadow_list);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci		for_each_set_bit(index, spt->post_shadow_bitmap,
167462306a36Sopenharmony_ci				GTT_ENTRY_NUM_IN_ONE_PAGE) {
167562306a36Sopenharmony_ci			ppgtt_get_guest_entry(spt, &ge, index);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci			ret = ppgtt_handle_guest_write_page_table(spt,
167862306a36Sopenharmony_ci							&ge, index);
167962306a36Sopenharmony_ci			if (ret)
168062306a36Sopenharmony_ci				return ret;
168162306a36Sopenharmony_ci			clear_bit(index, spt->post_shadow_bitmap);
168262306a36Sopenharmony_ci		}
168362306a36Sopenharmony_ci		list_del_init(&spt->post_shadow_list);
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci	return 0;
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_cistatic int ppgtt_handle_guest_write_page_table_bytes(
168962306a36Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt,
169062306a36Sopenharmony_ci		u64 pa, void *p_data, int bytes)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
169362306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
169462306a36Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
169562306a36Sopenharmony_ci	struct intel_gvt_gtt_entry we, se;
169662306a36Sopenharmony_ci	unsigned long index;
169762306a36Sopenharmony_ci	int ret;
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	index = (pa & (PAGE_SIZE - 1)) >> info->gtt_entry_size_shift;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	ppgtt_get_guest_entry(spt, &we, index);
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	/*
170462306a36Sopenharmony_ci	 * For page table which has 64K gtt entry, only PTE#0, PTE#16,
170562306a36Sopenharmony_ci	 * PTE#32, ... PTE#496 are used. Unused PTEs update should be
170662306a36Sopenharmony_ci	 * ignored.
170762306a36Sopenharmony_ci	 */
170862306a36Sopenharmony_ci	if (we.type == GTT_TYPE_PPGTT_PTE_64K_ENTRY &&
170962306a36Sopenharmony_ci	    (index % GTT_64K_PTE_STRIDE)) {
171062306a36Sopenharmony_ci		gvt_vdbg_mm("Ignore write to unused PTE entry, index %lu\n",
171162306a36Sopenharmony_ci			    index);
171262306a36Sopenharmony_ci		return 0;
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	if (bytes == info->gtt_entry_size) {
171662306a36Sopenharmony_ci		ret = ppgtt_handle_guest_write_page_table(spt, &we, index);
171762306a36Sopenharmony_ci		if (ret)
171862306a36Sopenharmony_ci			return ret;
171962306a36Sopenharmony_ci	} else {
172062306a36Sopenharmony_ci		if (!test_bit(index, spt->post_shadow_bitmap)) {
172162306a36Sopenharmony_ci			int type = spt->shadow_page.type;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci			ppgtt_get_shadow_entry(spt, &se, index);
172462306a36Sopenharmony_ci			ret = ppgtt_handle_guest_entry_removal(spt, &se, index);
172562306a36Sopenharmony_ci			if (ret)
172662306a36Sopenharmony_ci				return ret;
172762306a36Sopenharmony_ci			ops->set_pfn(&se, vgpu->gtt.scratch_pt[type].page_mfn);
172862306a36Sopenharmony_ci			ppgtt_set_shadow_entry(spt, &se, index);
172962306a36Sopenharmony_ci		}
173062306a36Sopenharmony_ci		ppgtt_set_post_shadow(spt, index);
173162306a36Sopenharmony_ci	}
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	if (!enable_out_of_sync)
173462306a36Sopenharmony_ci		return 0;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	spt->guest_page.write_cnt++;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	if (spt->guest_page.oos_page)
173962306a36Sopenharmony_ci		ops->set_entry(spt->guest_page.oos_page->mem, &we, index,
174062306a36Sopenharmony_ci				false, 0, vgpu);
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	if (can_do_out_of_sync(spt)) {
174362306a36Sopenharmony_ci		if (!spt->guest_page.oos_page)
174462306a36Sopenharmony_ci			ppgtt_allocate_oos_page(spt);
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci		ret = ppgtt_set_guest_page_oos(spt);
174762306a36Sopenharmony_ci		if (ret < 0)
174862306a36Sopenharmony_ci			return ret;
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci	return 0;
175162306a36Sopenharmony_ci}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cistatic void invalidate_ppgtt_mm(struct intel_vgpu_mm *mm)
175462306a36Sopenharmony_ci{
175562306a36Sopenharmony_ci	struct intel_vgpu *vgpu = mm->vgpu;
175662306a36Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
175762306a36Sopenharmony_ci	struct intel_gvt_gtt *gtt = &gvt->gtt;
175862306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = gtt->pte_ops;
175962306a36Sopenharmony_ci	struct intel_gvt_gtt_entry se;
176062306a36Sopenharmony_ci	int index;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	if (!mm->ppgtt_mm.shadowed)
176362306a36Sopenharmony_ci		return;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	for (index = 0; index < ARRAY_SIZE(mm->ppgtt_mm.shadow_pdps); index++) {
176662306a36Sopenharmony_ci		ppgtt_get_shadow_root_entry(mm, &se, index);
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci		if (!ops->test_present(&se))
176962306a36Sopenharmony_ci			continue;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci		ppgtt_invalidate_spt_by_shadow_entry(vgpu, &se);
177262306a36Sopenharmony_ci		se.val64 = 0;
177362306a36Sopenharmony_ci		ppgtt_set_shadow_root_entry(mm, &se, index);
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci		trace_spt_guest_change(vgpu->id, "destroy root pointer",
177662306a36Sopenharmony_ci				       NULL, se.type, se.val64, index);
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	mm->ppgtt_mm.shadowed = false;
178062306a36Sopenharmony_ci}
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_cistatic int shadow_ppgtt_mm(struct intel_vgpu_mm *mm)
178462306a36Sopenharmony_ci{
178562306a36Sopenharmony_ci	struct intel_vgpu *vgpu = mm->vgpu;
178662306a36Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
178762306a36Sopenharmony_ci	struct intel_gvt_gtt *gtt = &gvt->gtt;
178862306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = gtt->pte_ops;
178962306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt;
179062306a36Sopenharmony_ci	struct intel_gvt_gtt_entry ge, se;
179162306a36Sopenharmony_ci	int index, ret;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	if (mm->ppgtt_mm.shadowed)
179462306a36Sopenharmony_ci		return 0;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status))
179762306a36Sopenharmony_ci		return -EINVAL;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	mm->ppgtt_mm.shadowed = true;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	for (index = 0; index < ARRAY_SIZE(mm->ppgtt_mm.guest_pdps); index++) {
180262306a36Sopenharmony_ci		ppgtt_get_guest_root_entry(mm, &ge, index);
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci		if (!ops->test_present(&ge))
180562306a36Sopenharmony_ci			continue;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci		trace_spt_guest_change(vgpu->id, __func__, NULL,
180862306a36Sopenharmony_ci				       ge.type, ge.val64, index);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci		spt = ppgtt_populate_spt_by_guest_entry(vgpu, &ge);
181162306a36Sopenharmony_ci		if (IS_ERR(spt)) {
181262306a36Sopenharmony_ci			gvt_vgpu_err("fail to populate guest root pointer\n");
181362306a36Sopenharmony_ci			ret = PTR_ERR(spt);
181462306a36Sopenharmony_ci			goto fail;
181562306a36Sopenharmony_ci		}
181662306a36Sopenharmony_ci		ppgtt_generate_shadow_entry(&se, spt, &ge);
181762306a36Sopenharmony_ci		ppgtt_set_shadow_root_entry(mm, &se, index);
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci		trace_spt_guest_change(vgpu->id, "populate root pointer",
182062306a36Sopenharmony_ci				       NULL, se.type, se.val64, index);
182162306a36Sopenharmony_ci	}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	return 0;
182462306a36Sopenharmony_cifail:
182562306a36Sopenharmony_ci	invalidate_ppgtt_mm(mm);
182662306a36Sopenharmony_ci	return ret;
182762306a36Sopenharmony_ci}
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_cistatic struct intel_vgpu_mm *vgpu_alloc_mm(struct intel_vgpu *vgpu)
183062306a36Sopenharmony_ci{
183162306a36Sopenharmony_ci	struct intel_vgpu_mm *mm;
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	mm = kzalloc(sizeof(*mm), GFP_KERNEL);
183462306a36Sopenharmony_ci	if (!mm)
183562306a36Sopenharmony_ci		return NULL;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	mm->vgpu = vgpu;
183862306a36Sopenharmony_ci	kref_init(&mm->ref);
183962306a36Sopenharmony_ci	atomic_set(&mm->pincount, 0);
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	return mm;
184262306a36Sopenharmony_ci}
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_cistatic void vgpu_free_mm(struct intel_vgpu_mm *mm)
184562306a36Sopenharmony_ci{
184662306a36Sopenharmony_ci	kfree(mm);
184762306a36Sopenharmony_ci}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci/**
185062306a36Sopenharmony_ci * intel_vgpu_create_ppgtt_mm - create a ppgtt mm object for a vGPU
185162306a36Sopenharmony_ci * @vgpu: a vGPU
185262306a36Sopenharmony_ci * @root_entry_type: ppgtt root entry type
185362306a36Sopenharmony_ci * @pdps: guest pdps.
185462306a36Sopenharmony_ci *
185562306a36Sopenharmony_ci * This function is used to create a ppgtt mm object for a vGPU.
185662306a36Sopenharmony_ci *
185762306a36Sopenharmony_ci * Returns:
185862306a36Sopenharmony_ci * Zero on success, negative error code in pointer if failed.
185962306a36Sopenharmony_ci */
186062306a36Sopenharmony_cistruct intel_vgpu_mm *intel_vgpu_create_ppgtt_mm(struct intel_vgpu *vgpu,
186162306a36Sopenharmony_ci		enum intel_gvt_gtt_type root_entry_type, u64 pdps[])
186262306a36Sopenharmony_ci{
186362306a36Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
186462306a36Sopenharmony_ci	struct intel_vgpu_mm *mm;
186562306a36Sopenharmony_ci	int ret;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	mm = vgpu_alloc_mm(vgpu);
186862306a36Sopenharmony_ci	if (!mm)
186962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	mm->type = INTEL_GVT_MM_PPGTT;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	GEM_BUG_ON(root_entry_type != GTT_TYPE_PPGTT_ROOT_L3_ENTRY &&
187462306a36Sopenharmony_ci		   root_entry_type != GTT_TYPE_PPGTT_ROOT_L4_ENTRY);
187562306a36Sopenharmony_ci	mm->ppgtt_mm.root_entry_type = root_entry_type;
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	INIT_LIST_HEAD(&mm->ppgtt_mm.list);
187862306a36Sopenharmony_ci	INIT_LIST_HEAD(&mm->ppgtt_mm.lru_list);
187962306a36Sopenharmony_ci	INIT_LIST_HEAD(&mm->ppgtt_mm.link);
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	if (root_entry_type == GTT_TYPE_PPGTT_ROOT_L4_ENTRY)
188262306a36Sopenharmony_ci		mm->ppgtt_mm.guest_pdps[0] = pdps[0];
188362306a36Sopenharmony_ci	else
188462306a36Sopenharmony_ci		memcpy(mm->ppgtt_mm.guest_pdps, pdps,
188562306a36Sopenharmony_ci		       sizeof(mm->ppgtt_mm.guest_pdps));
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	ret = shadow_ppgtt_mm(mm);
188862306a36Sopenharmony_ci	if (ret) {
188962306a36Sopenharmony_ci		gvt_vgpu_err("failed to shadow ppgtt mm\n");
189062306a36Sopenharmony_ci		vgpu_free_mm(mm);
189162306a36Sopenharmony_ci		return ERR_PTR(ret);
189262306a36Sopenharmony_ci	}
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	list_add_tail(&mm->ppgtt_mm.list, &vgpu->gtt.ppgtt_mm_list_head);
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	mutex_lock(&gvt->gtt.ppgtt_mm_lock);
189762306a36Sopenharmony_ci	list_add_tail(&mm->ppgtt_mm.lru_list, &gvt->gtt.ppgtt_mm_lru_list_head);
189862306a36Sopenharmony_ci	mutex_unlock(&gvt->gtt.ppgtt_mm_lock);
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	return mm;
190162306a36Sopenharmony_ci}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_cistatic struct intel_vgpu_mm *intel_vgpu_create_ggtt_mm(struct intel_vgpu *vgpu)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	struct intel_vgpu_mm *mm;
190662306a36Sopenharmony_ci	unsigned long nr_entries;
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	mm = vgpu_alloc_mm(vgpu);
190962306a36Sopenharmony_ci	if (!mm)
191062306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	mm->type = INTEL_GVT_MM_GGTT;
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	nr_entries = gvt_ggtt_gm_sz(vgpu->gvt) >> I915_GTT_PAGE_SHIFT;
191562306a36Sopenharmony_ci	mm->ggtt_mm.virtual_ggtt =
191662306a36Sopenharmony_ci		vzalloc(array_size(nr_entries,
191762306a36Sopenharmony_ci				   vgpu->gvt->device_info.gtt_entry_size));
191862306a36Sopenharmony_ci	if (!mm->ggtt_mm.virtual_ggtt) {
191962306a36Sopenharmony_ci		vgpu_free_mm(mm);
192062306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
192162306a36Sopenharmony_ci	}
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	mm->ggtt_mm.host_ggtt_aperture = vzalloc((vgpu_aperture_sz(vgpu) >> PAGE_SHIFT) * sizeof(u64));
192462306a36Sopenharmony_ci	if (!mm->ggtt_mm.host_ggtt_aperture) {
192562306a36Sopenharmony_ci		vfree(mm->ggtt_mm.virtual_ggtt);
192662306a36Sopenharmony_ci		vgpu_free_mm(mm);
192762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
192862306a36Sopenharmony_ci	}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	mm->ggtt_mm.host_ggtt_hidden = vzalloc((vgpu_hidden_sz(vgpu) >> PAGE_SHIFT) * sizeof(u64));
193162306a36Sopenharmony_ci	if (!mm->ggtt_mm.host_ggtt_hidden) {
193262306a36Sopenharmony_ci		vfree(mm->ggtt_mm.host_ggtt_aperture);
193362306a36Sopenharmony_ci		vfree(mm->ggtt_mm.virtual_ggtt);
193462306a36Sopenharmony_ci		vgpu_free_mm(mm);
193562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
193662306a36Sopenharmony_ci	}
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	return mm;
193962306a36Sopenharmony_ci}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci/**
194262306a36Sopenharmony_ci * _intel_vgpu_mm_release - destroy a mm object
194362306a36Sopenharmony_ci * @mm_ref: a kref object
194462306a36Sopenharmony_ci *
194562306a36Sopenharmony_ci * This function is used to destroy a mm object for vGPU
194662306a36Sopenharmony_ci *
194762306a36Sopenharmony_ci */
194862306a36Sopenharmony_civoid _intel_vgpu_mm_release(struct kref *mm_ref)
194962306a36Sopenharmony_ci{
195062306a36Sopenharmony_ci	struct intel_vgpu_mm *mm = container_of(mm_ref, typeof(*mm), ref);
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	if (GEM_WARN_ON(atomic_read(&mm->pincount)))
195362306a36Sopenharmony_ci		gvt_err("vgpu mm pin count bug detected\n");
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	if (mm->type == INTEL_GVT_MM_PPGTT) {
195662306a36Sopenharmony_ci		list_del(&mm->ppgtt_mm.list);
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci		mutex_lock(&mm->vgpu->gvt->gtt.ppgtt_mm_lock);
195962306a36Sopenharmony_ci		list_del(&mm->ppgtt_mm.lru_list);
196062306a36Sopenharmony_ci		mutex_unlock(&mm->vgpu->gvt->gtt.ppgtt_mm_lock);
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci		invalidate_ppgtt_mm(mm);
196362306a36Sopenharmony_ci	} else {
196462306a36Sopenharmony_ci		vfree(mm->ggtt_mm.virtual_ggtt);
196562306a36Sopenharmony_ci		vfree(mm->ggtt_mm.host_ggtt_aperture);
196662306a36Sopenharmony_ci		vfree(mm->ggtt_mm.host_ggtt_hidden);
196762306a36Sopenharmony_ci	}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	vgpu_free_mm(mm);
197062306a36Sopenharmony_ci}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci/**
197362306a36Sopenharmony_ci * intel_vgpu_unpin_mm - decrease the pin count of a vGPU mm object
197462306a36Sopenharmony_ci * @mm: a vGPU mm object
197562306a36Sopenharmony_ci *
197662306a36Sopenharmony_ci * This function is called when user doesn't want to use a vGPU mm object
197762306a36Sopenharmony_ci */
197862306a36Sopenharmony_civoid intel_vgpu_unpin_mm(struct intel_vgpu_mm *mm)
197962306a36Sopenharmony_ci{
198062306a36Sopenharmony_ci	atomic_dec_if_positive(&mm->pincount);
198162306a36Sopenharmony_ci}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci/**
198462306a36Sopenharmony_ci * intel_vgpu_pin_mm - increase the pin count of a vGPU mm object
198562306a36Sopenharmony_ci * @mm: target vgpu mm
198662306a36Sopenharmony_ci *
198762306a36Sopenharmony_ci * This function is called when user wants to use a vGPU mm object. If this
198862306a36Sopenharmony_ci * mm object hasn't been shadowed yet, the shadow will be populated at this
198962306a36Sopenharmony_ci * time.
199062306a36Sopenharmony_ci *
199162306a36Sopenharmony_ci * Returns:
199262306a36Sopenharmony_ci * Zero on success, negative error code if failed.
199362306a36Sopenharmony_ci */
199462306a36Sopenharmony_ciint intel_vgpu_pin_mm(struct intel_vgpu_mm *mm)
199562306a36Sopenharmony_ci{
199662306a36Sopenharmony_ci	int ret;
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	atomic_inc(&mm->pincount);
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	if (mm->type == INTEL_GVT_MM_PPGTT) {
200162306a36Sopenharmony_ci		ret = shadow_ppgtt_mm(mm);
200262306a36Sopenharmony_ci		if (ret)
200362306a36Sopenharmony_ci			return ret;
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci		mutex_lock(&mm->vgpu->gvt->gtt.ppgtt_mm_lock);
200662306a36Sopenharmony_ci		list_move_tail(&mm->ppgtt_mm.lru_list,
200762306a36Sopenharmony_ci			       &mm->vgpu->gvt->gtt.ppgtt_mm_lru_list_head);
200862306a36Sopenharmony_ci		mutex_unlock(&mm->vgpu->gvt->gtt.ppgtt_mm_lock);
200962306a36Sopenharmony_ci	}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	return 0;
201262306a36Sopenharmony_ci}
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_cistatic int reclaim_one_ppgtt_mm(struct intel_gvt *gvt)
201562306a36Sopenharmony_ci{
201662306a36Sopenharmony_ci	struct intel_vgpu_mm *mm;
201762306a36Sopenharmony_ci	struct list_head *pos, *n;
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	mutex_lock(&gvt->gtt.ppgtt_mm_lock);
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	list_for_each_safe(pos, n, &gvt->gtt.ppgtt_mm_lru_list_head) {
202262306a36Sopenharmony_ci		mm = container_of(pos, struct intel_vgpu_mm, ppgtt_mm.lru_list);
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci		if (atomic_read(&mm->pincount))
202562306a36Sopenharmony_ci			continue;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci		list_del_init(&mm->ppgtt_mm.lru_list);
202862306a36Sopenharmony_ci		mutex_unlock(&gvt->gtt.ppgtt_mm_lock);
202962306a36Sopenharmony_ci		invalidate_ppgtt_mm(mm);
203062306a36Sopenharmony_ci		return 1;
203162306a36Sopenharmony_ci	}
203262306a36Sopenharmony_ci	mutex_unlock(&gvt->gtt.ppgtt_mm_lock);
203362306a36Sopenharmony_ci	return 0;
203462306a36Sopenharmony_ci}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci/*
203762306a36Sopenharmony_ci * GMA translation APIs.
203862306a36Sopenharmony_ci */
203962306a36Sopenharmony_cistatic inline int ppgtt_get_next_level_entry(struct intel_vgpu_mm *mm,
204062306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *e, unsigned long index, bool guest)
204162306a36Sopenharmony_ci{
204262306a36Sopenharmony_ci	struct intel_vgpu *vgpu = mm->vgpu;
204362306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
204462306a36Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *s;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	s = intel_vgpu_find_spt_by_mfn(vgpu, ops->get_pfn(e));
204762306a36Sopenharmony_ci	if (!s)
204862306a36Sopenharmony_ci		return -ENXIO;
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	if (!guest)
205162306a36Sopenharmony_ci		ppgtt_get_shadow_entry(s, e, index);
205262306a36Sopenharmony_ci	else
205362306a36Sopenharmony_ci		ppgtt_get_guest_entry(s, e, index);
205462306a36Sopenharmony_ci	return 0;
205562306a36Sopenharmony_ci}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci/**
205862306a36Sopenharmony_ci * intel_vgpu_gma_to_gpa - translate a gma to GPA
205962306a36Sopenharmony_ci * @mm: mm object. could be a PPGTT or GGTT mm object
206062306a36Sopenharmony_ci * @gma: graphics memory address in this mm object
206162306a36Sopenharmony_ci *
206262306a36Sopenharmony_ci * This function is used to translate a graphics memory address in specific
206362306a36Sopenharmony_ci * graphics memory space to guest physical address.
206462306a36Sopenharmony_ci *
206562306a36Sopenharmony_ci * Returns:
206662306a36Sopenharmony_ci * Guest physical address on success, INTEL_GVT_INVALID_ADDR if failed.
206762306a36Sopenharmony_ci */
206862306a36Sopenharmony_ciunsigned long intel_vgpu_gma_to_gpa(struct intel_vgpu_mm *mm, unsigned long gma)
206962306a36Sopenharmony_ci{
207062306a36Sopenharmony_ci	struct intel_vgpu *vgpu = mm->vgpu;
207162306a36Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
207262306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *pte_ops = gvt->gtt.pte_ops;
207362306a36Sopenharmony_ci	const struct intel_gvt_gtt_gma_ops *gma_ops = gvt->gtt.gma_ops;
207462306a36Sopenharmony_ci	unsigned long gpa = INTEL_GVT_INVALID_ADDR;
207562306a36Sopenharmony_ci	unsigned long gma_index[4];
207662306a36Sopenharmony_ci	struct intel_gvt_gtt_entry e;
207762306a36Sopenharmony_ci	int i, levels = 0;
207862306a36Sopenharmony_ci	int ret;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT &&
208162306a36Sopenharmony_ci		   mm->type != INTEL_GVT_MM_PPGTT);
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	if (mm->type == INTEL_GVT_MM_GGTT) {
208462306a36Sopenharmony_ci		if (!vgpu_gmadr_is_valid(vgpu, gma))
208562306a36Sopenharmony_ci			goto err;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci		ggtt_get_guest_entry(mm, &e,
208862306a36Sopenharmony_ci			gma_ops->gma_to_ggtt_pte_index(gma));
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci		gpa = (pte_ops->get_pfn(&e) << I915_GTT_PAGE_SHIFT)
209162306a36Sopenharmony_ci			+ (gma & ~I915_GTT_PAGE_MASK);
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci		trace_gma_translate(vgpu->id, "ggtt", 0, 0, gma, gpa);
209462306a36Sopenharmony_ci	} else {
209562306a36Sopenharmony_ci		switch (mm->ppgtt_mm.root_entry_type) {
209662306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_ROOT_L4_ENTRY:
209762306a36Sopenharmony_ci			ppgtt_get_shadow_root_entry(mm, &e, 0);
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci			gma_index[0] = gma_ops->gma_to_pml4_index(gma);
210062306a36Sopenharmony_ci			gma_index[1] = gma_ops->gma_to_l4_pdp_index(gma);
210162306a36Sopenharmony_ci			gma_index[2] = gma_ops->gma_to_pde_index(gma);
210262306a36Sopenharmony_ci			gma_index[3] = gma_ops->gma_to_pte_index(gma);
210362306a36Sopenharmony_ci			levels = 4;
210462306a36Sopenharmony_ci			break;
210562306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_ROOT_L3_ENTRY:
210662306a36Sopenharmony_ci			ppgtt_get_shadow_root_entry(mm, &e,
210762306a36Sopenharmony_ci					gma_ops->gma_to_l3_pdp_index(gma));
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci			gma_index[0] = gma_ops->gma_to_pde_index(gma);
211062306a36Sopenharmony_ci			gma_index[1] = gma_ops->gma_to_pte_index(gma);
211162306a36Sopenharmony_ci			levels = 2;
211262306a36Sopenharmony_ci			break;
211362306a36Sopenharmony_ci		default:
211462306a36Sopenharmony_ci			GEM_BUG_ON(1);
211562306a36Sopenharmony_ci		}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci		/* walk the shadow page table and get gpa from guest entry */
211862306a36Sopenharmony_ci		for (i = 0; i < levels; i++) {
211962306a36Sopenharmony_ci			ret = ppgtt_get_next_level_entry(mm, &e, gma_index[i],
212062306a36Sopenharmony_ci				(i == levels - 1));
212162306a36Sopenharmony_ci			if (ret)
212262306a36Sopenharmony_ci				goto err;
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci			if (!pte_ops->test_present(&e)) {
212562306a36Sopenharmony_ci				gvt_dbg_core("GMA 0x%lx is not present\n", gma);
212662306a36Sopenharmony_ci				goto err;
212762306a36Sopenharmony_ci			}
212862306a36Sopenharmony_ci		}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci		gpa = (pte_ops->get_pfn(&e) << I915_GTT_PAGE_SHIFT) +
213162306a36Sopenharmony_ci					(gma & ~I915_GTT_PAGE_MASK);
213262306a36Sopenharmony_ci		trace_gma_translate(vgpu->id, "ppgtt", 0,
213362306a36Sopenharmony_ci				    mm->ppgtt_mm.root_entry_type, gma, gpa);
213462306a36Sopenharmony_ci	}
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	return gpa;
213762306a36Sopenharmony_cierr:
213862306a36Sopenharmony_ci	gvt_vgpu_err("invalid mm type: %d gma %lx\n", mm->type, gma);
213962306a36Sopenharmony_ci	return INTEL_GVT_INVALID_ADDR;
214062306a36Sopenharmony_ci}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_cistatic int emulate_ggtt_mmio_read(struct intel_vgpu *vgpu,
214362306a36Sopenharmony_ci	unsigned int off, void *p_data, unsigned int bytes)
214462306a36Sopenharmony_ci{
214562306a36Sopenharmony_ci	struct intel_vgpu_mm *ggtt_mm = vgpu->gtt.ggtt_mm;
214662306a36Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
214762306a36Sopenharmony_ci	unsigned long index = off >> info->gtt_entry_size_shift;
214862306a36Sopenharmony_ci	unsigned long gma;
214962306a36Sopenharmony_ci	struct intel_gvt_gtt_entry e;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	if (bytes != 4 && bytes != 8)
215262306a36Sopenharmony_ci		return -EINVAL;
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	gma = index << I915_GTT_PAGE_SHIFT;
215562306a36Sopenharmony_ci	if (!intel_gvt_ggtt_validate_range(vgpu,
215662306a36Sopenharmony_ci					   gma, 1 << I915_GTT_PAGE_SHIFT)) {
215762306a36Sopenharmony_ci		gvt_dbg_mm("read invalid ggtt at 0x%lx\n", gma);
215862306a36Sopenharmony_ci		memset(p_data, 0, bytes);
215962306a36Sopenharmony_ci		return 0;
216062306a36Sopenharmony_ci	}
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci	ggtt_get_guest_entry(ggtt_mm, &e, index);
216362306a36Sopenharmony_ci	memcpy(p_data, (void *)&e.val64 + (off & (info->gtt_entry_size - 1)),
216462306a36Sopenharmony_ci			bytes);
216562306a36Sopenharmony_ci	return 0;
216662306a36Sopenharmony_ci}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci/**
216962306a36Sopenharmony_ci * intel_vgpu_emulate_ggtt_mmio_read - emulate GTT MMIO register read
217062306a36Sopenharmony_ci * @vgpu: a vGPU
217162306a36Sopenharmony_ci * @off: register offset
217262306a36Sopenharmony_ci * @p_data: data will be returned to guest
217362306a36Sopenharmony_ci * @bytes: data length
217462306a36Sopenharmony_ci *
217562306a36Sopenharmony_ci * This function is used to emulate the GTT MMIO register read
217662306a36Sopenharmony_ci *
217762306a36Sopenharmony_ci * Returns:
217862306a36Sopenharmony_ci * Zero on success, error code if failed.
217962306a36Sopenharmony_ci */
218062306a36Sopenharmony_ciint intel_vgpu_emulate_ggtt_mmio_read(struct intel_vgpu *vgpu, unsigned int off,
218162306a36Sopenharmony_ci	void *p_data, unsigned int bytes)
218262306a36Sopenharmony_ci{
218362306a36Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
218462306a36Sopenharmony_ci	int ret;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	if (bytes != 4 && bytes != 8)
218762306a36Sopenharmony_ci		return -EINVAL;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	off -= info->gtt_start_offset;
219062306a36Sopenharmony_ci	ret = emulate_ggtt_mmio_read(vgpu, off, p_data, bytes);
219162306a36Sopenharmony_ci	return ret;
219262306a36Sopenharmony_ci}
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_cistatic void ggtt_invalidate_pte(struct intel_vgpu *vgpu,
219562306a36Sopenharmony_ci		struct intel_gvt_gtt_entry *entry)
219662306a36Sopenharmony_ci{
219762306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops;
219862306a36Sopenharmony_ci	unsigned long pfn;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	pfn = pte_ops->get_pfn(entry);
220162306a36Sopenharmony_ci	if (pfn != vgpu->gvt->gtt.scratch_mfn)
220262306a36Sopenharmony_ci		intel_gvt_dma_unmap_guest_page(vgpu, pfn << PAGE_SHIFT);
220362306a36Sopenharmony_ci}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_cistatic int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
220662306a36Sopenharmony_ci	void *p_data, unsigned int bytes)
220762306a36Sopenharmony_ci{
220862306a36Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
220962306a36Sopenharmony_ci	const struct intel_gvt_device_info *info = &gvt->device_info;
221062306a36Sopenharmony_ci	struct intel_vgpu_mm *ggtt_mm = vgpu->gtt.ggtt_mm;
221162306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops;
221262306a36Sopenharmony_ci	unsigned long g_gtt_index = off >> info->gtt_entry_size_shift;
221362306a36Sopenharmony_ci	unsigned long gma, gfn;
221462306a36Sopenharmony_ci	struct intel_gvt_gtt_entry e = {.val64 = 0, .type = GTT_TYPE_GGTT_PTE};
221562306a36Sopenharmony_ci	struct intel_gvt_gtt_entry m = {.val64 = 0, .type = GTT_TYPE_GGTT_PTE};
221662306a36Sopenharmony_ci	dma_addr_t dma_addr;
221762306a36Sopenharmony_ci	int ret;
221862306a36Sopenharmony_ci	struct intel_gvt_partial_pte *partial_pte, *pos, *n;
221962306a36Sopenharmony_ci	bool partial_update = false;
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	if (bytes != 4 && bytes != 8)
222262306a36Sopenharmony_ci		return -EINVAL;
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	gma = g_gtt_index << I915_GTT_PAGE_SHIFT;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	/* the VM may configure the whole GM space when ballooning is used */
222762306a36Sopenharmony_ci	if (!vgpu_gmadr_is_valid(vgpu, gma))
222862306a36Sopenharmony_ci		return 0;
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	e.type = GTT_TYPE_GGTT_PTE;
223162306a36Sopenharmony_ci	memcpy((void *)&e.val64 + (off & (info->gtt_entry_size - 1)), p_data,
223262306a36Sopenharmony_ci			bytes);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	/* If ggtt entry size is 8 bytes, and it's split into two 4 bytes
223562306a36Sopenharmony_ci	 * write, save the first 4 bytes in a list and update virtual
223662306a36Sopenharmony_ci	 * PTE. Only update shadow PTE when the second 4 bytes comes.
223762306a36Sopenharmony_ci	 */
223862306a36Sopenharmony_ci	if (bytes < info->gtt_entry_size) {
223962306a36Sopenharmony_ci		bool found = false;
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci		list_for_each_entry_safe(pos, n,
224262306a36Sopenharmony_ci				&ggtt_mm->ggtt_mm.partial_pte_list, list) {
224362306a36Sopenharmony_ci			if (g_gtt_index == pos->offset >>
224462306a36Sopenharmony_ci					info->gtt_entry_size_shift) {
224562306a36Sopenharmony_ci				if (off != pos->offset) {
224662306a36Sopenharmony_ci					/* the second partial part*/
224762306a36Sopenharmony_ci					int last_off = pos->offset &
224862306a36Sopenharmony_ci						(info->gtt_entry_size - 1);
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci					memcpy((void *)&e.val64 + last_off,
225162306a36Sopenharmony_ci						(void *)&pos->data + last_off,
225262306a36Sopenharmony_ci						bytes);
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci					list_del(&pos->list);
225562306a36Sopenharmony_ci					kfree(pos);
225662306a36Sopenharmony_ci					found = true;
225762306a36Sopenharmony_ci					break;
225862306a36Sopenharmony_ci				}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci				/* update of the first partial part */
226162306a36Sopenharmony_ci				pos->data = e.val64;
226262306a36Sopenharmony_ci				ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
226362306a36Sopenharmony_ci				return 0;
226462306a36Sopenharmony_ci			}
226562306a36Sopenharmony_ci		}
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci		if (!found) {
226862306a36Sopenharmony_ci			/* the first partial part */
226962306a36Sopenharmony_ci			partial_pte = kzalloc(sizeof(*partial_pte), GFP_KERNEL);
227062306a36Sopenharmony_ci			if (!partial_pte)
227162306a36Sopenharmony_ci				return -ENOMEM;
227262306a36Sopenharmony_ci			partial_pte->offset = off;
227362306a36Sopenharmony_ci			partial_pte->data = e.val64;
227462306a36Sopenharmony_ci			list_add_tail(&partial_pte->list,
227562306a36Sopenharmony_ci				&ggtt_mm->ggtt_mm.partial_pte_list);
227662306a36Sopenharmony_ci			partial_update = true;
227762306a36Sopenharmony_ci		}
227862306a36Sopenharmony_ci	}
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	if (!partial_update && (ops->test_present(&e))) {
228162306a36Sopenharmony_ci		gfn = ops->get_pfn(&e);
228262306a36Sopenharmony_ci		m.val64 = e.val64;
228362306a36Sopenharmony_ci		m.type = e.type;
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci		ret = intel_gvt_dma_map_guest_page(vgpu, gfn, PAGE_SIZE,
228662306a36Sopenharmony_ci						   &dma_addr);
228762306a36Sopenharmony_ci		if (ret) {
228862306a36Sopenharmony_ci			gvt_vgpu_err("fail to populate guest ggtt entry\n");
228962306a36Sopenharmony_ci			/* guest driver may read/write the entry when partial
229062306a36Sopenharmony_ci			 * update the entry in this situation p2m will fail
229162306a36Sopenharmony_ci			 * setting the shadow entry to point to a scratch page
229262306a36Sopenharmony_ci			 */
229362306a36Sopenharmony_ci			ops->set_pfn(&m, gvt->gtt.scratch_mfn);
229462306a36Sopenharmony_ci		} else
229562306a36Sopenharmony_ci			ops->set_pfn(&m, dma_addr >> PAGE_SHIFT);
229662306a36Sopenharmony_ci	} else {
229762306a36Sopenharmony_ci		ops->set_pfn(&m, gvt->gtt.scratch_mfn);
229862306a36Sopenharmony_ci		ops->clear_present(&m);
229962306a36Sopenharmony_ci	}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	ggtt_get_host_entry(ggtt_mm, &e, g_gtt_index);
230462306a36Sopenharmony_ci	ggtt_invalidate_pte(vgpu, &e);
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	ggtt_set_host_entry(ggtt_mm, &m, g_gtt_index);
230762306a36Sopenharmony_ci	ggtt_invalidate(gvt->gt);
230862306a36Sopenharmony_ci	return 0;
230962306a36Sopenharmony_ci}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci/*
231262306a36Sopenharmony_ci * intel_vgpu_emulate_ggtt_mmio_write - emulate GTT MMIO register write
231362306a36Sopenharmony_ci * @vgpu: a vGPU
231462306a36Sopenharmony_ci * @off: register offset
231562306a36Sopenharmony_ci * @p_data: data from guest write
231662306a36Sopenharmony_ci * @bytes: data length
231762306a36Sopenharmony_ci *
231862306a36Sopenharmony_ci * This function is used to emulate the GTT MMIO register write
231962306a36Sopenharmony_ci *
232062306a36Sopenharmony_ci * Returns:
232162306a36Sopenharmony_ci * Zero on success, error code if failed.
232262306a36Sopenharmony_ci */
232362306a36Sopenharmony_ciint intel_vgpu_emulate_ggtt_mmio_write(struct intel_vgpu *vgpu,
232462306a36Sopenharmony_ci		unsigned int off, void *p_data, unsigned int bytes)
232562306a36Sopenharmony_ci{
232662306a36Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
232762306a36Sopenharmony_ci	int ret;
232862306a36Sopenharmony_ci	struct intel_vgpu_submission *s = &vgpu->submission;
232962306a36Sopenharmony_ci	struct intel_engine_cs *engine;
233062306a36Sopenharmony_ci	int i;
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	if (bytes != 4 && bytes != 8)
233362306a36Sopenharmony_ci		return -EINVAL;
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	off -= info->gtt_start_offset;
233662306a36Sopenharmony_ci	ret = emulate_ggtt_mmio_write(vgpu, off, p_data, bytes);
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	/* if ggtt of last submitted context is written,
233962306a36Sopenharmony_ci	 * that context is probably got unpinned.
234062306a36Sopenharmony_ci	 * Set last shadowed ctx to invalid.
234162306a36Sopenharmony_ci	 */
234262306a36Sopenharmony_ci	for_each_engine(engine, vgpu->gvt->gt, i) {
234362306a36Sopenharmony_ci		if (!s->last_ctx[i].valid)
234462306a36Sopenharmony_ci			continue;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci		if (s->last_ctx[i].lrca == (off >> info->gtt_entry_size_shift))
234762306a36Sopenharmony_ci			s->last_ctx[i].valid = false;
234862306a36Sopenharmony_ci	}
234962306a36Sopenharmony_ci	return ret;
235062306a36Sopenharmony_ci}
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_cistatic int alloc_scratch_pages(struct intel_vgpu *vgpu,
235362306a36Sopenharmony_ci		enum intel_gvt_gtt_type type)
235462306a36Sopenharmony_ci{
235562306a36Sopenharmony_ci	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
235662306a36Sopenharmony_ci	struct intel_vgpu_gtt *gtt = &vgpu->gtt;
235762306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
235862306a36Sopenharmony_ci	int page_entry_num = I915_GTT_PAGE_SIZE >>
235962306a36Sopenharmony_ci				vgpu->gvt->device_info.gtt_entry_size_shift;
236062306a36Sopenharmony_ci	void *scratch_pt;
236162306a36Sopenharmony_ci	int i;
236262306a36Sopenharmony_ci	struct device *dev = vgpu->gvt->gt->i915->drm.dev;
236362306a36Sopenharmony_ci	dma_addr_t daddr;
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	if (drm_WARN_ON(&i915->drm,
236662306a36Sopenharmony_ci			type < GTT_TYPE_PPGTT_PTE_PT || type >= GTT_TYPE_MAX))
236762306a36Sopenharmony_ci		return -EINVAL;
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	scratch_pt = (void *)get_zeroed_page(GFP_KERNEL);
237062306a36Sopenharmony_ci	if (!scratch_pt) {
237162306a36Sopenharmony_ci		gvt_vgpu_err("fail to allocate scratch page\n");
237262306a36Sopenharmony_ci		return -ENOMEM;
237362306a36Sopenharmony_ci	}
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci	daddr = dma_map_page(dev, virt_to_page(scratch_pt), 0, 4096, DMA_BIDIRECTIONAL);
237662306a36Sopenharmony_ci	if (dma_mapping_error(dev, daddr)) {
237762306a36Sopenharmony_ci		gvt_vgpu_err("fail to dmamap scratch_pt\n");
237862306a36Sopenharmony_ci		__free_page(virt_to_page(scratch_pt));
237962306a36Sopenharmony_ci		return -ENOMEM;
238062306a36Sopenharmony_ci	}
238162306a36Sopenharmony_ci	gtt->scratch_pt[type].page_mfn =
238262306a36Sopenharmony_ci		(unsigned long)(daddr >> I915_GTT_PAGE_SHIFT);
238362306a36Sopenharmony_ci	gtt->scratch_pt[type].page = virt_to_page(scratch_pt);
238462306a36Sopenharmony_ci	gvt_dbg_mm("vgpu%d create scratch_pt: type %d mfn=0x%lx\n",
238562306a36Sopenharmony_ci			vgpu->id, type, gtt->scratch_pt[type].page_mfn);
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	/* Build the tree by full filled the scratch pt with the entries which
238862306a36Sopenharmony_ci	 * point to the next level scratch pt or scratch page. The
238962306a36Sopenharmony_ci	 * scratch_pt[type] indicate the scratch pt/scratch page used by the
239062306a36Sopenharmony_ci	 * 'type' pt.
239162306a36Sopenharmony_ci	 * e.g. scratch_pt[GTT_TYPE_PPGTT_PDE_PT] is used by
239262306a36Sopenharmony_ci	 * GTT_TYPE_PPGTT_PDE_PT level pt, that means this scratch_pt it self
239362306a36Sopenharmony_ci	 * is GTT_TYPE_PPGTT_PTE_PT, and full filled by scratch page mfn.
239462306a36Sopenharmony_ci	 */
239562306a36Sopenharmony_ci	if (type > GTT_TYPE_PPGTT_PTE_PT) {
239662306a36Sopenharmony_ci		struct intel_gvt_gtt_entry se;
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci		memset(&se, 0, sizeof(struct intel_gvt_gtt_entry));
239962306a36Sopenharmony_ci		se.type = get_entry_type(type - 1);
240062306a36Sopenharmony_ci		ops->set_pfn(&se, gtt->scratch_pt[type - 1].page_mfn);
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci		/* The entry parameters like present/writeable/cache type
240362306a36Sopenharmony_ci		 * set to the same as i915's scratch page tree.
240462306a36Sopenharmony_ci		 */
240562306a36Sopenharmony_ci		se.val64 |= GEN8_PAGE_PRESENT | GEN8_PAGE_RW;
240662306a36Sopenharmony_ci		if (type == GTT_TYPE_PPGTT_PDE_PT)
240762306a36Sopenharmony_ci			se.val64 |= PPAT_CACHED;
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci		for (i = 0; i < page_entry_num; i++)
241062306a36Sopenharmony_ci			ops->set_entry(scratch_pt, &se, i, false, 0, vgpu);
241162306a36Sopenharmony_ci	}
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	return 0;
241462306a36Sopenharmony_ci}
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_cistatic int release_scratch_page_tree(struct intel_vgpu *vgpu)
241762306a36Sopenharmony_ci{
241862306a36Sopenharmony_ci	int i;
241962306a36Sopenharmony_ci	struct device *dev = vgpu->gvt->gt->i915->drm.dev;
242062306a36Sopenharmony_ci	dma_addr_t daddr;
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	for (i = GTT_TYPE_PPGTT_PTE_PT; i < GTT_TYPE_MAX; i++) {
242362306a36Sopenharmony_ci		if (vgpu->gtt.scratch_pt[i].page != NULL) {
242462306a36Sopenharmony_ci			daddr = (dma_addr_t)(vgpu->gtt.scratch_pt[i].page_mfn <<
242562306a36Sopenharmony_ci					I915_GTT_PAGE_SHIFT);
242662306a36Sopenharmony_ci			dma_unmap_page(dev, daddr, 4096, DMA_BIDIRECTIONAL);
242762306a36Sopenharmony_ci			__free_page(vgpu->gtt.scratch_pt[i].page);
242862306a36Sopenharmony_ci			vgpu->gtt.scratch_pt[i].page = NULL;
242962306a36Sopenharmony_ci			vgpu->gtt.scratch_pt[i].page_mfn = 0;
243062306a36Sopenharmony_ci		}
243162306a36Sopenharmony_ci	}
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci	return 0;
243462306a36Sopenharmony_ci}
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_cistatic int create_scratch_page_tree(struct intel_vgpu *vgpu)
243762306a36Sopenharmony_ci{
243862306a36Sopenharmony_ci	int i, ret;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	for (i = GTT_TYPE_PPGTT_PTE_PT; i < GTT_TYPE_MAX; i++) {
244162306a36Sopenharmony_ci		ret = alloc_scratch_pages(vgpu, i);
244262306a36Sopenharmony_ci		if (ret)
244362306a36Sopenharmony_ci			goto err;
244462306a36Sopenharmony_ci	}
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	return 0;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_cierr:
244962306a36Sopenharmony_ci	release_scratch_page_tree(vgpu);
245062306a36Sopenharmony_ci	return ret;
245162306a36Sopenharmony_ci}
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci/**
245462306a36Sopenharmony_ci * intel_vgpu_init_gtt - initialize per-vGPU graphics memory virulization
245562306a36Sopenharmony_ci * @vgpu: a vGPU
245662306a36Sopenharmony_ci *
245762306a36Sopenharmony_ci * This function is used to initialize per-vGPU graphics memory virtualization
245862306a36Sopenharmony_ci * components.
245962306a36Sopenharmony_ci *
246062306a36Sopenharmony_ci * Returns:
246162306a36Sopenharmony_ci * Zero on success, error code if failed.
246262306a36Sopenharmony_ci */
246362306a36Sopenharmony_ciint intel_vgpu_init_gtt(struct intel_vgpu *vgpu)
246462306a36Sopenharmony_ci{
246562306a36Sopenharmony_ci	struct intel_vgpu_gtt *gtt = &vgpu->gtt;
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	INIT_RADIX_TREE(&gtt->spt_tree, GFP_KERNEL);
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	INIT_LIST_HEAD(&gtt->ppgtt_mm_list_head);
247062306a36Sopenharmony_ci	INIT_LIST_HEAD(&gtt->oos_page_list_head);
247162306a36Sopenharmony_ci	INIT_LIST_HEAD(&gtt->post_shadow_list_head);
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	gtt->ggtt_mm = intel_vgpu_create_ggtt_mm(vgpu);
247462306a36Sopenharmony_ci	if (IS_ERR(gtt->ggtt_mm)) {
247562306a36Sopenharmony_ci		gvt_vgpu_err("fail to create mm for ggtt.\n");
247662306a36Sopenharmony_ci		return PTR_ERR(gtt->ggtt_mm);
247762306a36Sopenharmony_ci	}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	intel_vgpu_reset_ggtt(vgpu, false);
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci	INIT_LIST_HEAD(&gtt->ggtt_mm->ggtt_mm.partial_pte_list);
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	return create_scratch_page_tree(vgpu);
248462306a36Sopenharmony_ci}
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_civoid intel_vgpu_destroy_all_ppgtt_mm(struct intel_vgpu *vgpu)
248762306a36Sopenharmony_ci{
248862306a36Sopenharmony_ci	struct list_head *pos, *n;
248962306a36Sopenharmony_ci	struct intel_vgpu_mm *mm;
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	list_for_each_safe(pos, n, &vgpu->gtt.ppgtt_mm_list_head) {
249262306a36Sopenharmony_ci		mm = container_of(pos, struct intel_vgpu_mm, ppgtt_mm.list);
249362306a36Sopenharmony_ci		intel_vgpu_destroy_mm(mm);
249462306a36Sopenharmony_ci	}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	if (GEM_WARN_ON(!list_empty(&vgpu->gtt.ppgtt_mm_list_head)))
249762306a36Sopenharmony_ci		gvt_err("vgpu ppgtt mm is not fully destroyed\n");
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	if (GEM_WARN_ON(!radix_tree_empty(&vgpu->gtt.spt_tree))) {
250062306a36Sopenharmony_ci		gvt_err("Why we still has spt not freed?\n");
250162306a36Sopenharmony_ci		ppgtt_free_all_spt(vgpu);
250262306a36Sopenharmony_ci	}
250362306a36Sopenharmony_ci}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_cistatic void intel_vgpu_destroy_ggtt_mm(struct intel_vgpu *vgpu)
250662306a36Sopenharmony_ci{
250762306a36Sopenharmony_ci	struct intel_gvt_partial_pte *pos, *next;
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	list_for_each_entry_safe(pos, next,
251062306a36Sopenharmony_ci				 &vgpu->gtt.ggtt_mm->ggtt_mm.partial_pte_list,
251162306a36Sopenharmony_ci				 list) {
251262306a36Sopenharmony_ci		gvt_dbg_mm("partial PTE update on hold 0x%lx : 0x%llx\n",
251362306a36Sopenharmony_ci			pos->offset, pos->data);
251462306a36Sopenharmony_ci		kfree(pos);
251562306a36Sopenharmony_ci	}
251662306a36Sopenharmony_ci	intel_vgpu_destroy_mm(vgpu->gtt.ggtt_mm);
251762306a36Sopenharmony_ci	vgpu->gtt.ggtt_mm = NULL;
251862306a36Sopenharmony_ci}
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci/**
252162306a36Sopenharmony_ci * intel_vgpu_clean_gtt - clean up per-vGPU graphics memory virulization
252262306a36Sopenharmony_ci * @vgpu: a vGPU
252362306a36Sopenharmony_ci *
252462306a36Sopenharmony_ci * This function is used to clean up per-vGPU graphics memory virtualization
252562306a36Sopenharmony_ci * components.
252662306a36Sopenharmony_ci *
252762306a36Sopenharmony_ci * Returns:
252862306a36Sopenharmony_ci * Zero on success, error code if failed.
252962306a36Sopenharmony_ci */
253062306a36Sopenharmony_civoid intel_vgpu_clean_gtt(struct intel_vgpu *vgpu)
253162306a36Sopenharmony_ci{
253262306a36Sopenharmony_ci	intel_vgpu_destroy_all_ppgtt_mm(vgpu);
253362306a36Sopenharmony_ci	intel_vgpu_destroy_ggtt_mm(vgpu);
253462306a36Sopenharmony_ci	release_scratch_page_tree(vgpu);
253562306a36Sopenharmony_ci}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_cistatic void clean_spt_oos(struct intel_gvt *gvt)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	struct intel_gvt_gtt *gtt = &gvt->gtt;
254062306a36Sopenharmony_ci	struct list_head *pos, *n;
254162306a36Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	WARN(!list_empty(&gtt->oos_page_use_list_head),
254462306a36Sopenharmony_ci		"someone is still using oos page\n");
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci	list_for_each_safe(pos, n, &gtt->oos_page_free_list_head) {
254762306a36Sopenharmony_ci		oos_page = container_of(pos, struct intel_vgpu_oos_page, list);
254862306a36Sopenharmony_ci		list_del(&oos_page->list);
254962306a36Sopenharmony_ci		free_page((unsigned long)oos_page->mem);
255062306a36Sopenharmony_ci		kfree(oos_page);
255162306a36Sopenharmony_ci	}
255262306a36Sopenharmony_ci}
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_cistatic int setup_spt_oos(struct intel_gvt *gvt)
255562306a36Sopenharmony_ci{
255662306a36Sopenharmony_ci	struct intel_gvt_gtt *gtt = &gvt->gtt;
255762306a36Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page;
255862306a36Sopenharmony_ci	int i;
255962306a36Sopenharmony_ci	int ret;
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	INIT_LIST_HEAD(&gtt->oos_page_free_list_head);
256262306a36Sopenharmony_ci	INIT_LIST_HEAD(&gtt->oos_page_use_list_head);
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci	for (i = 0; i < preallocated_oos_pages; i++) {
256562306a36Sopenharmony_ci		oos_page = kzalloc(sizeof(*oos_page), GFP_KERNEL);
256662306a36Sopenharmony_ci		if (!oos_page) {
256762306a36Sopenharmony_ci			ret = -ENOMEM;
256862306a36Sopenharmony_ci			goto fail;
256962306a36Sopenharmony_ci		}
257062306a36Sopenharmony_ci		oos_page->mem = (void *)__get_free_pages(GFP_KERNEL, 0);
257162306a36Sopenharmony_ci		if (!oos_page->mem) {
257262306a36Sopenharmony_ci			ret = -ENOMEM;
257362306a36Sopenharmony_ci			kfree(oos_page);
257462306a36Sopenharmony_ci			goto fail;
257562306a36Sopenharmony_ci		}
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci		INIT_LIST_HEAD(&oos_page->list);
257862306a36Sopenharmony_ci		INIT_LIST_HEAD(&oos_page->vm_list);
257962306a36Sopenharmony_ci		oos_page->id = i;
258062306a36Sopenharmony_ci		list_add_tail(&oos_page->list, &gtt->oos_page_free_list_head);
258162306a36Sopenharmony_ci	}
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	gvt_dbg_mm("%d oos pages preallocated\n", i);
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	return 0;
258662306a36Sopenharmony_cifail:
258762306a36Sopenharmony_ci	clean_spt_oos(gvt);
258862306a36Sopenharmony_ci	return ret;
258962306a36Sopenharmony_ci}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci/**
259262306a36Sopenharmony_ci * intel_vgpu_find_ppgtt_mm - find a PPGTT mm object
259362306a36Sopenharmony_ci * @vgpu: a vGPU
259462306a36Sopenharmony_ci * @pdps: pdp root array
259562306a36Sopenharmony_ci *
259662306a36Sopenharmony_ci * This function is used to find a PPGTT mm object from mm object pool
259762306a36Sopenharmony_ci *
259862306a36Sopenharmony_ci * Returns:
259962306a36Sopenharmony_ci * pointer to mm object on success, NULL if failed.
260062306a36Sopenharmony_ci */
260162306a36Sopenharmony_cistruct intel_vgpu_mm *intel_vgpu_find_ppgtt_mm(struct intel_vgpu *vgpu,
260262306a36Sopenharmony_ci		u64 pdps[])
260362306a36Sopenharmony_ci{
260462306a36Sopenharmony_ci	struct intel_vgpu_mm *mm;
260562306a36Sopenharmony_ci	struct list_head *pos;
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	list_for_each(pos, &vgpu->gtt.ppgtt_mm_list_head) {
260862306a36Sopenharmony_ci		mm = container_of(pos, struct intel_vgpu_mm, ppgtt_mm.list);
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci		switch (mm->ppgtt_mm.root_entry_type) {
261162306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_ROOT_L4_ENTRY:
261262306a36Sopenharmony_ci			if (pdps[0] == mm->ppgtt_mm.guest_pdps[0])
261362306a36Sopenharmony_ci				return mm;
261462306a36Sopenharmony_ci			break;
261562306a36Sopenharmony_ci		case GTT_TYPE_PPGTT_ROOT_L3_ENTRY:
261662306a36Sopenharmony_ci			if (!memcmp(pdps, mm->ppgtt_mm.guest_pdps,
261762306a36Sopenharmony_ci				    sizeof(mm->ppgtt_mm.guest_pdps)))
261862306a36Sopenharmony_ci				return mm;
261962306a36Sopenharmony_ci			break;
262062306a36Sopenharmony_ci		default:
262162306a36Sopenharmony_ci			GEM_BUG_ON(1);
262262306a36Sopenharmony_ci		}
262362306a36Sopenharmony_ci	}
262462306a36Sopenharmony_ci	return NULL;
262562306a36Sopenharmony_ci}
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci/**
262862306a36Sopenharmony_ci * intel_vgpu_get_ppgtt_mm - get or create a PPGTT mm object.
262962306a36Sopenharmony_ci * @vgpu: a vGPU
263062306a36Sopenharmony_ci * @root_entry_type: ppgtt root entry type
263162306a36Sopenharmony_ci * @pdps: guest pdps
263262306a36Sopenharmony_ci *
263362306a36Sopenharmony_ci * This function is used to find or create a PPGTT mm object from a guest.
263462306a36Sopenharmony_ci *
263562306a36Sopenharmony_ci * Returns:
263662306a36Sopenharmony_ci * Zero on success, negative error code if failed.
263762306a36Sopenharmony_ci */
263862306a36Sopenharmony_cistruct intel_vgpu_mm *intel_vgpu_get_ppgtt_mm(struct intel_vgpu *vgpu,
263962306a36Sopenharmony_ci		enum intel_gvt_gtt_type root_entry_type, u64 pdps[])
264062306a36Sopenharmony_ci{
264162306a36Sopenharmony_ci	struct intel_vgpu_mm *mm;
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	mm = intel_vgpu_find_ppgtt_mm(vgpu, pdps);
264462306a36Sopenharmony_ci	if (mm) {
264562306a36Sopenharmony_ci		intel_vgpu_mm_get(mm);
264662306a36Sopenharmony_ci	} else {
264762306a36Sopenharmony_ci		mm = intel_vgpu_create_ppgtt_mm(vgpu, root_entry_type, pdps);
264862306a36Sopenharmony_ci		if (IS_ERR(mm))
264962306a36Sopenharmony_ci			gvt_vgpu_err("fail to create mm\n");
265062306a36Sopenharmony_ci	}
265162306a36Sopenharmony_ci	return mm;
265262306a36Sopenharmony_ci}
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci/**
265562306a36Sopenharmony_ci * intel_vgpu_put_ppgtt_mm - find and put a PPGTT mm object.
265662306a36Sopenharmony_ci * @vgpu: a vGPU
265762306a36Sopenharmony_ci * @pdps: guest pdps
265862306a36Sopenharmony_ci *
265962306a36Sopenharmony_ci * This function is used to find a PPGTT mm object from a guest and destroy it.
266062306a36Sopenharmony_ci *
266162306a36Sopenharmony_ci * Returns:
266262306a36Sopenharmony_ci * Zero on success, negative error code if failed.
266362306a36Sopenharmony_ci */
266462306a36Sopenharmony_ciint intel_vgpu_put_ppgtt_mm(struct intel_vgpu *vgpu, u64 pdps[])
266562306a36Sopenharmony_ci{
266662306a36Sopenharmony_ci	struct intel_vgpu_mm *mm;
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	mm = intel_vgpu_find_ppgtt_mm(vgpu, pdps);
266962306a36Sopenharmony_ci	if (!mm) {
267062306a36Sopenharmony_ci		gvt_vgpu_err("fail to find ppgtt instance.\n");
267162306a36Sopenharmony_ci		return -EINVAL;
267262306a36Sopenharmony_ci	}
267362306a36Sopenharmony_ci	intel_vgpu_mm_put(mm);
267462306a36Sopenharmony_ci	return 0;
267562306a36Sopenharmony_ci}
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci/**
267862306a36Sopenharmony_ci * intel_gvt_init_gtt - initialize mm components of a GVT device
267962306a36Sopenharmony_ci * @gvt: GVT device
268062306a36Sopenharmony_ci *
268162306a36Sopenharmony_ci * This function is called at the initialization stage, to initialize
268262306a36Sopenharmony_ci * the mm components of a GVT device.
268362306a36Sopenharmony_ci *
268462306a36Sopenharmony_ci * Returns:
268562306a36Sopenharmony_ci * zero on success, negative error code if failed.
268662306a36Sopenharmony_ci */
268762306a36Sopenharmony_ciint intel_gvt_init_gtt(struct intel_gvt *gvt)
268862306a36Sopenharmony_ci{
268962306a36Sopenharmony_ci	int ret;
269062306a36Sopenharmony_ci	void *page;
269162306a36Sopenharmony_ci	struct device *dev = gvt->gt->i915->drm.dev;
269262306a36Sopenharmony_ci	dma_addr_t daddr;
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	gvt_dbg_core("init gtt\n");
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ci	gvt->gtt.pte_ops = &gen8_gtt_pte_ops;
269762306a36Sopenharmony_ci	gvt->gtt.gma_ops = &gen8_gtt_gma_ops;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	page = (void *)get_zeroed_page(GFP_KERNEL);
270062306a36Sopenharmony_ci	if (!page) {
270162306a36Sopenharmony_ci		gvt_err("fail to allocate scratch ggtt page\n");
270262306a36Sopenharmony_ci		return -ENOMEM;
270362306a36Sopenharmony_ci	}
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci	daddr = dma_map_page(dev, virt_to_page(page), 0,
270662306a36Sopenharmony_ci			4096, DMA_BIDIRECTIONAL);
270762306a36Sopenharmony_ci	if (dma_mapping_error(dev, daddr)) {
270862306a36Sopenharmony_ci		gvt_err("fail to dmamap scratch ggtt page\n");
270962306a36Sopenharmony_ci		__free_page(virt_to_page(page));
271062306a36Sopenharmony_ci		return -ENOMEM;
271162306a36Sopenharmony_ci	}
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	gvt->gtt.scratch_page = virt_to_page(page);
271462306a36Sopenharmony_ci	gvt->gtt.scratch_mfn = (unsigned long)(daddr >> I915_GTT_PAGE_SHIFT);
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	if (enable_out_of_sync) {
271762306a36Sopenharmony_ci		ret = setup_spt_oos(gvt);
271862306a36Sopenharmony_ci		if (ret) {
271962306a36Sopenharmony_ci			gvt_err("fail to initialize SPT oos\n");
272062306a36Sopenharmony_ci			dma_unmap_page(dev, daddr, 4096, DMA_BIDIRECTIONAL);
272162306a36Sopenharmony_ci			__free_page(gvt->gtt.scratch_page);
272262306a36Sopenharmony_ci			return ret;
272362306a36Sopenharmony_ci		}
272462306a36Sopenharmony_ci	}
272562306a36Sopenharmony_ci	INIT_LIST_HEAD(&gvt->gtt.ppgtt_mm_lru_list_head);
272662306a36Sopenharmony_ci	mutex_init(&gvt->gtt.ppgtt_mm_lock);
272762306a36Sopenharmony_ci	return 0;
272862306a36Sopenharmony_ci}
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci/**
273162306a36Sopenharmony_ci * intel_gvt_clean_gtt - clean up mm components of a GVT device
273262306a36Sopenharmony_ci * @gvt: GVT device
273362306a36Sopenharmony_ci *
273462306a36Sopenharmony_ci * This function is called at the driver unloading stage, to clean up
273562306a36Sopenharmony_ci * the mm components of a GVT device.
273662306a36Sopenharmony_ci *
273762306a36Sopenharmony_ci */
273862306a36Sopenharmony_civoid intel_gvt_clean_gtt(struct intel_gvt *gvt)
273962306a36Sopenharmony_ci{
274062306a36Sopenharmony_ci	struct device *dev = gvt->gt->i915->drm.dev;
274162306a36Sopenharmony_ci	dma_addr_t daddr = (dma_addr_t)(gvt->gtt.scratch_mfn <<
274262306a36Sopenharmony_ci					I915_GTT_PAGE_SHIFT);
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	dma_unmap_page(dev, daddr, 4096, DMA_BIDIRECTIONAL);
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci	__free_page(gvt->gtt.scratch_page);
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	if (enable_out_of_sync)
274962306a36Sopenharmony_ci		clean_spt_oos(gvt);
275062306a36Sopenharmony_ci}
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_ci/**
275362306a36Sopenharmony_ci * intel_vgpu_invalidate_ppgtt - invalidate PPGTT instances
275462306a36Sopenharmony_ci * @vgpu: a vGPU
275562306a36Sopenharmony_ci *
275662306a36Sopenharmony_ci * This function is called when invalidate all PPGTT instances of a vGPU.
275762306a36Sopenharmony_ci *
275862306a36Sopenharmony_ci */
275962306a36Sopenharmony_civoid intel_vgpu_invalidate_ppgtt(struct intel_vgpu *vgpu)
276062306a36Sopenharmony_ci{
276162306a36Sopenharmony_ci	struct list_head *pos, *n;
276262306a36Sopenharmony_ci	struct intel_vgpu_mm *mm;
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	list_for_each_safe(pos, n, &vgpu->gtt.ppgtt_mm_list_head) {
276562306a36Sopenharmony_ci		mm = container_of(pos, struct intel_vgpu_mm, ppgtt_mm.list);
276662306a36Sopenharmony_ci		if (mm->type == INTEL_GVT_MM_PPGTT) {
276762306a36Sopenharmony_ci			mutex_lock(&vgpu->gvt->gtt.ppgtt_mm_lock);
276862306a36Sopenharmony_ci			list_del_init(&mm->ppgtt_mm.lru_list);
276962306a36Sopenharmony_ci			mutex_unlock(&vgpu->gvt->gtt.ppgtt_mm_lock);
277062306a36Sopenharmony_ci			if (mm->ppgtt_mm.shadowed)
277162306a36Sopenharmony_ci				invalidate_ppgtt_mm(mm);
277262306a36Sopenharmony_ci		}
277362306a36Sopenharmony_ci	}
277462306a36Sopenharmony_ci}
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci/**
277762306a36Sopenharmony_ci * intel_vgpu_reset_ggtt - reset the GGTT entry
277862306a36Sopenharmony_ci * @vgpu: a vGPU
277962306a36Sopenharmony_ci * @invalidate_old: invalidate old entries
278062306a36Sopenharmony_ci *
278162306a36Sopenharmony_ci * This function is called at the vGPU create stage
278262306a36Sopenharmony_ci * to reset all the GGTT entries.
278362306a36Sopenharmony_ci *
278462306a36Sopenharmony_ci */
278562306a36Sopenharmony_civoid intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu, bool invalidate_old)
278662306a36Sopenharmony_ci{
278762306a36Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
278862306a36Sopenharmony_ci	const struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops;
278962306a36Sopenharmony_ci	struct intel_gvt_gtt_entry entry = {.type = GTT_TYPE_GGTT_PTE};
279062306a36Sopenharmony_ci	struct intel_gvt_gtt_entry old_entry;
279162306a36Sopenharmony_ci	u32 index;
279262306a36Sopenharmony_ci	u32 num_entries;
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	pte_ops->set_pfn(&entry, gvt->gtt.scratch_mfn);
279562306a36Sopenharmony_ci	pte_ops->set_present(&entry);
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	index = vgpu_aperture_gmadr_base(vgpu) >> PAGE_SHIFT;
279862306a36Sopenharmony_ci	num_entries = vgpu_aperture_sz(vgpu) >> PAGE_SHIFT;
279962306a36Sopenharmony_ci	while (num_entries--) {
280062306a36Sopenharmony_ci		if (invalidate_old) {
280162306a36Sopenharmony_ci			ggtt_get_host_entry(vgpu->gtt.ggtt_mm, &old_entry, index);
280262306a36Sopenharmony_ci			ggtt_invalidate_pte(vgpu, &old_entry);
280362306a36Sopenharmony_ci		}
280462306a36Sopenharmony_ci		ggtt_set_host_entry(vgpu->gtt.ggtt_mm, &entry, index++);
280562306a36Sopenharmony_ci	}
280662306a36Sopenharmony_ci
280762306a36Sopenharmony_ci	index = vgpu_hidden_gmadr_base(vgpu) >> PAGE_SHIFT;
280862306a36Sopenharmony_ci	num_entries = vgpu_hidden_sz(vgpu) >> PAGE_SHIFT;
280962306a36Sopenharmony_ci	while (num_entries--) {
281062306a36Sopenharmony_ci		if (invalidate_old) {
281162306a36Sopenharmony_ci			ggtt_get_host_entry(vgpu->gtt.ggtt_mm, &old_entry, index);
281262306a36Sopenharmony_ci			ggtt_invalidate_pte(vgpu, &old_entry);
281362306a36Sopenharmony_ci		}
281462306a36Sopenharmony_ci		ggtt_set_host_entry(vgpu->gtt.ggtt_mm, &entry, index++);
281562306a36Sopenharmony_ci	}
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	ggtt_invalidate(gvt->gt);
281862306a36Sopenharmony_ci}
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci/**
282162306a36Sopenharmony_ci * intel_gvt_restore_ggtt - restore all vGPU's ggtt entries
282262306a36Sopenharmony_ci * @gvt: intel gvt device
282362306a36Sopenharmony_ci *
282462306a36Sopenharmony_ci * This function is called at driver resume stage to restore
282562306a36Sopenharmony_ci * GGTT entries of every vGPU.
282662306a36Sopenharmony_ci *
282762306a36Sopenharmony_ci */
282862306a36Sopenharmony_civoid intel_gvt_restore_ggtt(struct intel_gvt *gvt)
282962306a36Sopenharmony_ci{
283062306a36Sopenharmony_ci	struct intel_vgpu *vgpu;
283162306a36Sopenharmony_ci	struct intel_vgpu_mm *mm;
283262306a36Sopenharmony_ci	int id;
283362306a36Sopenharmony_ci	gen8_pte_t pte;
283462306a36Sopenharmony_ci	u32 idx, num_low, num_hi, offset;
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci	/* Restore dirty host ggtt for all vGPUs */
283762306a36Sopenharmony_ci	idr_for_each_entry(&(gvt)->vgpu_idr, vgpu, id) {
283862306a36Sopenharmony_ci		mm = vgpu->gtt.ggtt_mm;
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci		num_low = vgpu_aperture_sz(vgpu) >> PAGE_SHIFT;
284162306a36Sopenharmony_ci		offset = vgpu_aperture_gmadr_base(vgpu) >> PAGE_SHIFT;
284262306a36Sopenharmony_ci		for (idx = 0; idx < num_low; idx++) {
284362306a36Sopenharmony_ci			pte = mm->ggtt_mm.host_ggtt_aperture[idx];
284462306a36Sopenharmony_ci			if (pte & GEN8_PAGE_PRESENT)
284562306a36Sopenharmony_ci				write_pte64(vgpu->gvt->gt->ggtt, offset + idx, pte);
284662306a36Sopenharmony_ci		}
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci		num_hi = vgpu_hidden_sz(vgpu) >> PAGE_SHIFT;
284962306a36Sopenharmony_ci		offset = vgpu_hidden_gmadr_base(vgpu) >> PAGE_SHIFT;
285062306a36Sopenharmony_ci		for (idx = 0; idx < num_hi; idx++) {
285162306a36Sopenharmony_ci			pte = mm->ggtt_mm.host_ggtt_hidden[idx];
285262306a36Sopenharmony_ci			if (pte & GEN8_PAGE_PRESENT)
285362306a36Sopenharmony_ci				write_pte64(vgpu->gvt->gt->ggtt, offset + idx, pte);
285462306a36Sopenharmony_ci		}
285562306a36Sopenharmony_ci	}
285662306a36Sopenharmony_ci}
2857