18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * GTT virtualization
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
88c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
98c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
108c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
118c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next
148c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
158c2ecf20Sopenharmony_ci * Software.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
188c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
198c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
208c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
218c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
228c2ecf20Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
238c2ecf20Sopenharmony_ci * SOFTWARE.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * Authors:
268c2ecf20Sopenharmony_ci *    Zhi Wang <zhi.a.wang@intel.com>
278c2ecf20Sopenharmony_ci *    Zhenyu Wang <zhenyuw@linux.intel.com>
288c2ecf20Sopenharmony_ci *    Xiao Zheng <xiao.zheng@intel.com>
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * Contributors:
318c2ecf20Sopenharmony_ci *    Min He <min.he@intel.com>
328c2ecf20Sopenharmony_ci *    Bing Niu <bing.niu@intel.com>
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include "i915_drv.h"
378c2ecf20Sopenharmony_ci#include "gvt.h"
388c2ecf20Sopenharmony_ci#include "i915_pvinfo.h"
398c2ecf20Sopenharmony_ci#include "trace.h"
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#if defined(VERBOSE_DEBUG)
428c2ecf20Sopenharmony_ci#define gvt_vdbg_mm(fmt, args...) gvt_dbg_mm(fmt, ##args)
438c2ecf20Sopenharmony_ci#else
448c2ecf20Sopenharmony_ci#define gvt_vdbg_mm(fmt, args...)
458c2ecf20Sopenharmony_ci#endif
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic bool enable_out_of_sync = false;
488c2ecf20Sopenharmony_cistatic int preallocated_oos_pages = 8192;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/*
518c2ecf20Sopenharmony_ci * validate a gm address and related range size,
528c2ecf20Sopenharmony_ci * translate it to host gm address
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_cibool intel_gvt_ggtt_validate_range(struct intel_vgpu *vgpu, u64 addr, u32 size)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	if (size == 0)
578c2ecf20Sopenharmony_ci		return vgpu_gmadr_is_valid(vgpu, addr);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (vgpu_gmadr_is_aperture(vgpu, addr) &&
608c2ecf20Sopenharmony_ci	    vgpu_gmadr_is_aperture(vgpu, addr + size - 1))
618c2ecf20Sopenharmony_ci		return true;
628c2ecf20Sopenharmony_ci	else if (vgpu_gmadr_is_hidden(vgpu, addr) &&
638c2ecf20Sopenharmony_ci		 vgpu_gmadr_is_hidden(vgpu, addr + size - 1))
648c2ecf20Sopenharmony_ci		return true;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	gvt_dbg_mm("Invalid ggtt range at 0x%llx, size: 0x%x\n",
678c2ecf20Sopenharmony_ci		     addr, size);
688c2ecf20Sopenharmony_ci	return false;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/* translate a guest gmadr to host gmadr */
728c2ecf20Sopenharmony_ciint intel_gvt_ggtt_gmadr_g2h(struct intel_vgpu *vgpu, u64 g_addr, u64 *h_addr)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (drm_WARN(&i915->drm, !vgpu_gmadr_is_valid(vgpu, g_addr),
778c2ecf20Sopenharmony_ci		     "invalid guest gmadr %llx\n", g_addr))
788c2ecf20Sopenharmony_ci		return -EACCES;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (vgpu_gmadr_is_aperture(vgpu, g_addr))
818c2ecf20Sopenharmony_ci		*h_addr = vgpu_aperture_gmadr_base(vgpu)
828c2ecf20Sopenharmony_ci			  + (g_addr - vgpu_aperture_offset(vgpu));
838c2ecf20Sopenharmony_ci	else
848c2ecf20Sopenharmony_ci		*h_addr = vgpu_hidden_gmadr_base(vgpu)
858c2ecf20Sopenharmony_ci			  + (g_addr - vgpu_hidden_offset(vgpu));
868c2ecf20Sopenharmony_ci	return 0;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/* translate a host gmadr to guest gmadr */
908c2ecf20Sopenharmony_ciint intel_gvt_ggtt_gmadr_h2g(struct intel_vgpu *vgpu, u64 h_addr, u64 *g_addr)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (drm_WARN(&i915->drm, !gvt_gmadr_is_valid(vgpu->gvt, h_addr),
958c2ecf20Sopenharmony_ci		     "invalid host gmadr %llx\n", h_addr))
968c2ecf20Sopenharmony_ci		return -EACCES;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (gvt_gmadr_is_aperture(vgpu->gvt, h_addr))
998c2ecf20Sopenharmony_ci		*g_addr = vgpu_aperture_gmadr_base(vgpu)
1008c2ecf20Sopenharmony_ci			+ (h_addr - gvt_aperture_gmadr_base(vgpu->gvt));
1018c2ecf20Sopenharmony_ci	else
1028c2ecf20Sopenharmony_ci		*g_addr = vgpu_hidden_gmadr_base(vgpu)
1038c2ecf20Sopenharmony_ci			+ (h_addr - gvt_hidden_gmadr_base(vgpu->gvt));
1048c2ecf20Sopenharmony_ci	return 0;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ciint intel_gvt_ggtt_index_g2h(struct intel_vgpu *vgpu, unsigned long g_index,
1088c2ecf20Sopenharmony_ci			     unsigned long *h_index)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	u64 h_addr;
1118c2ecf20Sopenharmony_ci	int ret;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	ret = intel_gvt_ggtt_gmadr_g2h(vgpu, g_index << I915_GTT_PAGE_SHIFT,
1148c2ecf20Sopenharmony_ci				       &h_addr);
1158c2ecf20Sopenharmony_ci	if (ret)
1168c2ecf20Sopenharmony_ci		return ret;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	*h_index = h_addr >> I915_GTT_PAGE_SHIFT;
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ciint intel_gvt_ggtt_h2g_index(struct intel_vgpu *vgpu, unsigned long h_index,
1238c2ecf20Sopenharmony_ci			     unsigned long *g_index)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	u64 g_addr;
1268c2ecf20Sopenharmony_ci	int ret;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	ret = intel_gvt_ggtt_gmadr_h2g(vgpu, h_index << I915_GTT_PAGE_SHIFT,
1298c2ecf20Sopenharmony_ci				       &g_addr);
1308c2ecf20Sopenharmony_ci	if (ret)
1318c2ecf20Sopenharmony_ci		return ret;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	*g_index = g_addr >> I915_GTT_PAGE_SHIFT;
1348c2ecf20Sopenharmony_ci	return 0;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#define gtt_type_is_entry(type) \
1388c2ecf20Sopenharmony_ci	(type > GTT_TYPE_INVALID && type < GTT_TYPE_PPGTT_ENTRY \
1398c2ecf20Sopenharmony_ci	 && type != GTT_TYPE_PPGTT_PTE_ENTRY \
1408c2ecf20Sopenharmony_ci	 && type != GTT_TYPE_PPGTT_ROOT_ENTRY)
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci#define gtt_type_is_pt(type) \
1438c2ecf20Sopenharmony_ci	(type >= GTT_TYPE_PPGTT_PTE_PT && type < GTT_TYPE_MAX)
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#define gtt_type_is_pte_pt(type) \
1468c2ecf20Sopenharmony_ci	(type == GTT_TYPE_PPGTT_PTE_PT)
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#define gtt_type_is_root_pointer(type) \
1498c2ecf20Sopenharmony_ci	(gtt_type_is_entry(type) && type > GTT_TYPE_PPGTT_ROOT_ENTRY)
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#define gtt_init_entry(e, t, p, v) do { \
1528c2ecf20Sopenharmony_ci	(e)->type = t; \
1538c2ecf20Sopenharmony_ci	(e)->pdev = p; \
1548c2ecf20Sopenharmony_ci	memcpy(&(e)->val64, &v, sizeof(v)); \
1558c2ecf20Sopenharmony_ci} while (0)
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/*
1588c2ecf20Sopenharmony_ci * Mappings between GTT_TYPE* enumerations.
1598c2ecf20Sopenharmony_ci * Following information can be found according to the given type:
1608c2ecf20Sopenharmony_ci * - type of next level page table
1618c2ecf20Sopenharmony_ci * - type of entry inside this level page table
1628c2ecf20Sopenharmony_ci * - type of entry with PSE set
1638c2ecf20Sopenharmony_ci *
1648c2ecf20Sopenharmony_ci * If the given type doesn't have such a kind of information,
1658c2ecf20Sopenharmony_ci * e.g. give a l4 root entry type, then request to get its PSE type,
1668c2ecf20Sopenharmony_ci * give a PTE page table type, then request to get its next level page
1678c2ecf20Sopenharmony_ci * table type, as we know l4 root entry doesn't have a PSE bit,
1688c2ecf20Sopenharmony_ci * and a PTE page table doesn't have a next level page table type,
1698c2ecf20Sopenharmony_ci * GTT_TYPE_INVALID will be returned. This is useful when traversing a
1708c2ecf20Sopenharmony_ci * page table.
1718c2ecf20Sopenharmony_ci */
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistruct gtt_type_table_entry {
1748c2ecf20Sopenharmony_ci	int entry_type;
1758c2ecf20Sopenharmony_ci	int pt_type;
1768c2ecf20Sopenharmony_ci	int next_pt_type;
1778c2ecf20Sopenharmony_ci	int pse_entry_type;
1788c2ecf20Sopenharmony_ci};
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci#define GTT_TYPE_TABLE_ENTRY(type, e_type, cpt_type, npt_type, pse_type) \
1818c2ecf20Sopenharmony_ci	[type] = { \
1828c2ecf20Sopenharmony_ci		.entry_type = e_type, \
1838c2ecf20Sopenharmony_ci		.pt_type = cpt_type, \
1848c2ecf20Sopenharmony_ci		.next_pt_type = npt_type, \
1858c2ecf20Sopenharmony_ci		.pse_entry_type = pse_type, \
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic struct gtt_type_table_entry gtt_type_table[] = {
1898c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_ROOT_L4_ENTRY,
1908c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_ROOT_L4_ENTRY,
1918c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID,
1928c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PML4_PT,
1938c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID),
1948c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PML4_PT,
1958c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PML4_ENTRY,
1968c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PML4_PT,
1978c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_PT,
1988c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID),
1998c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PML4_ENTRY,
2008c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PML4_ENTRY,
2018c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PML4_PT,
2028c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_PT,
2038c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID),
2048c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDP_PT,
2058c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_ENTRY,
2068c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_PT,
2078c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
2088c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
2098c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_ROOT_L3_ENTRY,
2108c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_ROOT_L3_ENTRY,
2118c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID,
2128c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
2138c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
2148c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDP_ENTRY,
2158c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_ENTRY,
2168c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_PT,
2178c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
2188c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
2198c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDE_PT,
2208c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_ENTRY,
2218c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
2228c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_PT,
2238c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_2M_ENTRY),
2248c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDE_ENTRY,
2258c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_ENTRY,
2268c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
2278c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_PT,
2288c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_2M_ENTRY),
2298c2ecf20Sopenharmony_ci	/* We take IPS bit as 'PSE' for PTE level. */
2308c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_PT,
2318c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_4K_ENTRY,
2328c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_PT,
2338c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID,
2348c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_64K_ENTRY),
2358c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_4K_ENTRY,
2368c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_4K_ENTRY,
2378c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_PT,
2388c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID,
2398c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_64K_ENTRY),
2408c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_64K_ENTRY,
2418c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_4K_ENTRY,
2428c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_PT,
2438c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID,
2448c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_64K_ENTRY),
2458c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_2M_ENTRY,
2468c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_ENTRY,
2478c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDE_PT,
2488c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID,
2498c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_2M_ENTRY),
2508c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_1G_ENTRY,
2518c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_ENTRY,
2528c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PDP_PT,
2538c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID,
2548c2ecf20Sopenharmony_ci			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
2558c2ecf20Sopenharmony_ci	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_GGTT_PTE,
2568c2ecf20Sopenharmony_ci			GTT_TYPE_GGTT_PTE,
2578c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID,
2588c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID,
2598c2ecf20Sopenharmony_ci			GTT_TYPE_INVALID),
2608c2ecf20Sopenharmony_ci};
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic inline int get_next_pt_type(int type)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	return gtt_type_table[type].next_pt_type;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic inline int get_pt_type(int type)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	return gtt_type_table[type].pt_type;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic inline int get_entry_type(int type)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	return gtt_type_table[type].entry_type;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic inline int get_pse_type(int type)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	return gtt_type_table[type].pse_entry_type;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic u64 read_pte64(struct i915_ggtt *ggtt, unsigned long index)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	void __iomem *addr = (gen8_pte_t __iomem *)ggtt->gsm + index;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return readq(addr);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic void ggtt_invalidate(struct intel_gt *gt)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	mmio_hw_access_pre(gt);
2928c2ecf20Sopenharmony_ci	intel_uncore_write(gt->uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
2938c2ecf20Sopenharmony_ci	mmio_hw_access_post(gt);
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic void write_pte64(struct i915_ggtt *ggtt, unsigned long index, u64 pte)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	void __iomem *addr = (gen8_pte_t __iomem *)ggtt->gsm + index;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	writeq(pte, addr);
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic inline int gtt_get_entry64(void *pt,
3048c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *e,
3058c2ecf20Sopenharmony_ci		unsigned long index, bool hypervisor_access, unsigned long gpa,
3068c2ecf20Sopenharmony_ci		struct intel_vgpu *vgpu)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
3098c2ecf20Sopenharmony_ci	int ret;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (WARN_ON(info->gtt_entry_size != 8))
3128c2ecf20Sopenharmony_ci		return -EINVAL;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (hypervisor_access) {
3158c2ecf20Sopenharmony_ci		ret = intel_gvt_hypervisor_read_gpa(vgpu, gpa +
3168c2ecf20Sopenharmony_ci				(index << info->gtt_entry_size_shift),
3178c2ecf20Sopenharmony_ci				&e->val64, 8);
3188c2ecf20Sopenharmony_ci		if (WARN_ON(ret))
3198c2ecf20Sopenharmony_ci			return ret;
3208c2ecf20Sopenharmony_ci	} else if (!pt) {
3218c2ecf20Sopenharmony_ci		e->val64 = read_pte64(vgpu->gvt->gt->ggtt, index);
3228c2ecf20Sopenharmony_ci	} else {
3238c2ecf20Sopenharmony_ci		e->val64 = *((u64 *)pt + index);
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci	return 0;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic inline int gtt_set_entry64(void *pt,
3298c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *e,
3308c2ecf20Sopenharmony_ci		unsigned long index, bool hypervisor_access, unsigned long gpa,
3318c2ecf20Sopenharmony_ci		struct intel_vgpu *vgpu)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
3348c2ecf20Sopenharmony_ci	int ret;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (WARN_ON(info->gtt_entry_size != 8))
3378c2ecf20Sopenharmony_ci		return -EINVAL;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (hypervisor_access) {
3408c2ecf20Sopenharmony_ci		ret = intel_gvt_hypervisor_write_gpa(vgpu, gpa +
3418c2ecf20Sopenharmony_ci				(index << info->gtt_entry_size_shift),
3428c2ecf20Sopenharmony_ci				&e->val64, 8);
3438c2ecf20Sopenharmony_ci		if (WARN_ON(ret))
3448c2ecf20Sopenharmony_ci			return ret;
3458c2ecf20Sopenharmony_ci	} else if (!pt) {
3468c2ecf20Sopenharmony_ci		write_pte64(vgpu->gvt->gt->ggtt, index, e->val64);
3478c2ecf20Sopenharmony_ci	} else {
3488c2ecf20Sopenharmony_ci		*((u64 *)pt + index) = e->val64;
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci	return 0;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci#define GTT_HAW 46
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci#define ADDR_1G_MASK	GENMASK_ULL(GTT_HAW - 1, 30)
3568c2ecf20Sopenharmony_ci#define ADDR_2M_MASK	GENMASK_ULL(GTT_HAW - 1, 21)
3578c2ecf20Sopenharmony_ci#define ADDR_64K_MASK	GENMASK_ULL(GTT_HAW - 1, 16)
3588c2ecf20Sopenharmony_ci#define ADDR_4K_MASK	GENMASK_ULL(GTT_HAW - 1, 12)
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci#define GTT_SPTE_FLAG_MASK GENMASK_ULL(62, 52)
3618c2ecf20Sopenharmony_ci#define GTT_SPTE_FLAG_64K_SPLITED BIT(52) /* splited 64K gtt entry */
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci#define GTT_64K_PTE_STRIDE 16
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic unsigned long gen8_gtt_get_pfn(struct intel_gvt_gtt_entry *e)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	unsigned long pfn;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (e->type == GTT_TYPE_PPGTT_PTE_1G_ENTRY)
3708c2ecf20Sopenharmony_ci		pfn = (e->val64 & ADDR_1G_MASK) >> PAGE_SHIFT;
3718c2ecf20Sopenharmony_ci	else if (e->type == GTT_TYPE_PPGTT_PTE_2M_ENTRY)
3728c2ecf20Sopenharmony_ci		pfn = (e->val64 & ADDR_2M_MASK) >> PAGE_SHIFT;
3738c2ecf20Sopenharmony_ci	else if (e->type == GTT_TYPE_PPGTT_PTE_64K_ENTRY)
3748c2ecf20Sopenharmony_ci		pfn = (e->val64 & ADDR_64K_MASK) >> PAGE_SHIFT;
3758c2ecf20Sopenharmony_ci	else
3768c2ecf20Sopenharmony_ci		pfn = (e->val64 & ADDR_4K_MASK) >> PAGE_SHIFT;
3778c2ecf20Sopenharmony_ci	return pfn;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic void gen8_gtt_set_pfn(struct intel_gvt_gtt_entry *e, unsigned long pfn)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	if (e->type == GTT_TYPE_PPGTT_PTE_1G_ENTRY) {
3838c2ecf20Sopenharmony_ci		e->val64 &= ~ADDR_1G_MASK;
3848c2ecf20Sopenharmony_ci		pfn &= (ADDR_1G_MASK >> PAGE_SHIFT);
3858c2ecf20Sopenharmony_ci	} else if (e->type == GTT_TYPE_PPGTT_PTE_2M_ENTRY) {
3868c2ecf20Sopenharmony_ci		e->val64 &= ~ADDR_2M_MASK;
3878c2ecf20Sopenharmony_ci		pfn &= (ADDR_2M_MASK >> PAGE_SHIFT);
3888c2ecf20Sopenharmony_ci	} else if (e->type == GTT_TYPE_PPGTT_PTE_64K_ENTRY) {
3898c2ecf20Sopenharmony_ci		e->val64 &= ~ADDR_64K_MASK;
3908c2ecf20Sopenharmony_ci		pfn &= (ADDR_64K_MASK >> PAGE_SHIFT);
3918c2ecf20Sopenharmony_ci	} else {
3928c2ecf20Sopenharmony_ci		e->val64 &= ~ADDR_4K_MASK;
3938c2ecf20Sopenharmony_ci		pfn &= (ADDR_4K_MASK >> PAGE_SHIFT);
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	e->val64 |= (pfn << PAGE_SHIFT);
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic bool gen8_gtt_test_pse(struct intel_gvt_gtt_entry *e)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	return !!(e->val64 & _PAGE_PSE);
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic void gen8_gtt_clear_pse(struct intel_gvt_gtt_entry *e)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	if (gen8_gtt_test_pse(e)) {
4078c2ecf20Sopenharmony_ci		switch (e->type) {
4088c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_2M_ENTRY:
4098c2ecf20Sopenharmony_ci			e->val64 &= ~_PAGE_PSE;
4108c2ecf20Sopenharmony_ci			e->type = GTT_TYPE_PPGTT_PDE_ENTRY;
4118c2ecf20Sopenharmony_ci			break;
4128c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_1G_ENTRY:
4138c2ecf20Sopenharmony_ci			e->type = GTT_TYPE_PPGTT_PDP_ENTRY;
4148c2ecf20Sopenharmony_ci			e->val64 &= ~_PAGE_PSE;
4158c2ecf20Sopenharmony_ci			break;
4168c2ecf20Sopenharmony_ci		default:
4178c2ecf20Sopenharmony_ci			WARN_ON(1);
4188c2ecf20Sopenharmony_ci		}
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic bool gen8_gtt_test_ips(struct intel_gvt_gtt_entry *e)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	if (GEM_WARN_ON(e->type != GTT_TYPE_PPGTT_PDE_ENTRY))
4258c2ecf20Sopenharmony_ci		return false;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return !!(e->val64 & GEN8_PDE_IPS_64K);
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic void gen8_gtt_clear_ips(struct intel_gvt_gtt_entry *e)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	if (GEM_WARN_ON(e->type != GTT_TYPE_PPGTT_PDE_ENTRY))
4338c2ecf20Sopenharmony_ci		return;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	e->val64 &= ~GEN8_PDE_IPS_64K;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic bool gen8_gtt_test_present(struct intel_gvt_gtt_entry *e)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	/*
4418c2ecf20Sopenharmony_ci	 * i915 writes PDP root pointer registers without present bit,
4428c2ecf20Sopenharmony_ci	 * it also works, so we need to treat root pointer entry
4438c2ecf20Sopenharmony_ci	 * specifically.
4448c2ecf20Sopenharmony_ci	 */
4458c2ecf20Sopenharmony_ci	if (e->type == GTT_TYPE_PPGTT_ROOT_L3_ENTRY
4468c2ecf20Sopenharmony_ci			|| e->type == GTT_TYPE_PPGTT_ROOT_L4_ENTRY)
4478c2ecf20Sopenharmony_ci		return (e->val64 != 0);
4488c2ecf20Sopenharmony_ci	else
4498c2ecf20Sopenharmony_ci		return (e->val64 & _PAGE_PRESENT);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic void gtt_entry_clear_present(struct intel_gvt_gtt_entry *e)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	e->val64 &= ~_PAGE_PRESENT;
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic void gtt_entry_set_present(struct intel_gvt_gtt_entry *e)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	e->val64 |= _PAGE_PRESENT;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic bool gen8_gtt_test_64k_splited(struct intel_gvt_gtt_entry *e)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	return !!(e->val64 & GTT_SPTE_FLAG_64K_SPLITED);
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic void gen8_gtt_set_64k_splited(struct intel_gvt_gtt_entry *e)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	e->val64 |= GTT_SPTE_FLAG_64K_SPLITED;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic void gen8_gtt_clear_64k_splited(struct intel_gvt_gtt_entry *e)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	e->val64 &= ~GTT_SPTE_FLAG_64K_SPLITED;
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci/*
4788c2ecf20Sopenharmony_ci * Per-platform GMA routines.
4798c2ecf20Sopenharmony_ci */
4808c2ecf20Sopenharmony_cistatic unsigned long gma_to_ggtt_pte_index(unsigned long gma)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	unsigned long x = (gma >> I915_GTT_PAGE_SHIFT);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	trace_gma_index(__func__, gma, x);
4858c2ecf20Sopenharmony_ci	return x;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci#define DEFINE_PPGTT_GMA_TO_INDEX(prefix, ename, exp) \
4898c2ecf20Sopenharmony_cistatic unsigned long prefix##_gma_to_##ename##_index(unsigned long gma) \
4908c2ecf20Sopenharmony_ci{ \
4918c2ecf20Sopenharmony_ci	unsigned long x = (exp); \
4928c2ecf20Sopenharmony_ci	trace_gma_index(__func__, gma, x); \
4938c2ecf20Sopenharmony_ci	return x; \
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ciDEFINE_PPGTT_GMA_TO_INDEX(gen8, pte, (gma >> 12 & 0x1ff));
4978c2ecf20Sopenharmony_ciDEFINE_PPGTT_GMA_TO_INDEX(gen8, pde, (gma >> 21 & 0x1ff));
4988c2ecf20Sopenharmony_ciDEFINE_PPGTT_GMA_TO_INDEX(gen8, l3_pdp, (gma >> 30 & 0x3));
4998c2ecf20Sopenharmony_ciDEFINE_PPGTT_GMA_TO_INDEX(gen8, l4_pdp, (gma >> 30 & 0x1ff));
5008c2ecf20Sopenharmony_ciDEFINE_PPGTT_GMA_TO_INDEX(gen8, pml4, (gma >> 39 & 0x1ff));
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic struct intel_gvt_gtt_pte_ops gen8_gtt_pte_ops = {
5038c2ecf20Sopenharmony_ci	.get_entry = gtt_get_entry64,
5048c2ecf20Sopenharmony_ci	.set_entry = gtt_set_entry64,
5058c2ecf20Sopenharmony_ci	.clear_present = gtt_entry_clear_present,
5068c2ecf20Sopenharmony_ci	.set_present = gtt_entry_set_present,
5078c2ecf20Sopenharmony_ci	.test_present = gen8_gtt_test_present,
5088c2ecf20Sopenharmony_ci	.test_pse = gen8_gtt_test_pse,
5098c2ecf20Sopenharmony_ci	.clear_pse = gen8_gtt_clear_pse,
5108c2ecf20Sopenharmony_ci	.clear_ips = gen8_gtt_clear_ips,
5118c2ecf20Sopenharmony_ci	.test_ips = gen8_gtt_test_ips,
5128c2ecf20Sopenharmony_ci	.clear_64k_splited = gen8_gtt_clear_64k_splited,
5138c2ecf20Sopenharmony_ci	.set_64k_splited = gen8_gtt_set_64k_splited,
5148c2ecf20Sopenharmony_ci	.test_64k_splited = gen8_gtt_test_64k_splited,
5158c2ecf20Sopenharmony_ci	.get_pfn = gen8_gtt_get_pfn,
5168c2ecf20Sopenharmony_ci	.set_pfn = gen8_gtt_set_pfn,
5178c2ecf20Sopenharmony_ci};
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic struct intel_gvt_gtt_gma_ops gen8_gtt_gma_ops = {
5208c2ecf20Sopenharmony_ci	.gma_to_ggtt_pte_index = gma_to_ggtt_pte_index,
5218c2ecf20Sopenharmony_ci	.gma_to_pte_index = gen8_gma_to_pte_index,
5228c2ecf20Sopenharmony_ci	.gma_to_pde_index = gen8_gma_to_pde_index,
5238c2ecf20Sopenharmony_ci	.gma_to_l3_pdp_index = gen8_gma_to_l3_pdp_index,
5248c2ecf20Sopenharmony_ci	.gma_to_l4_pdp_index = gen8_gma_to_l4_pdp_index,
5258c2ecf20Sopenharmony_ci	.gma_to_pml4_index = gen8_gma_to_pml4_index,
5268c2ecf20Sopenharmony_ci};
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci/* Update entry type per pse and ips bit. */
5298c2ecf20Sopenharmony_cistatic void update_entry_type_for_real(struct intel_gvt_gtt_pte_ops *pte_ops,
5308c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry *entry, bool ips)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	switch (entry->type) {
5338c2ecf20Sopenharmony_ci	case GTT_TYPE_PPGTT_PDE_ENTRY:
5348c2ecf20Sopenharmony_ci	case GTT_TYPE_PPGTT_PDP_ENTRY:
5358c2ecf20Sopenharmony_ci		if (pte_ops->test_pse(entry))
5368c2ecf20Sopenharmony_ci			entry->type = get_pse_type(entry->type);
5378c2ecf20Sopenharmony_ci		break;
5388c2ecf20Sopenharmony_ci	case GTT_TYPE_PPGTT_PTE_4K_ENTRY:
5398c2ecf20Sopenharmony_ci		if (ips)
5408c2ecf20Sopenharmony_ci			entry->type = get_pse_type(entry->type);
5418c2ecf20Sopenharmony_ci		break;
5428c2ecf20Sopenharmony_ci	default:
5438c2ecf20Sopenharmony_ci		GEM_BUG_ON(!gtt_type_is_entry(entry->type));
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	GEM_BUG_ON(entry->type == GTT_TYPE_INVALID);
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci/*
5508c2ecf20Sopenharmony_ci * MM helpers.
5518c2ecf20Sopenharmony_ci */
5528c2ecf20Sopenharmony_cistatic void _ppgtt_get_root_entry(struct intel_vgpu_mm *mm,
5538c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index,
5548c2ecf20Sopenharmony_ci		bool guest)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_PPGTT);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	entry->type = mm->ppgtt_mm.root_entry_type;
5618c2ecf20Sopenharmony_ci	pte_ops->get_entry(guest ? mm->ppgtt_mm.guest_pdps :
5628c2ecf20Sopenharmony_ci			   mm->ppgtt_mm.shadow_pdps,
5638c2ecf20Sopenharmony_ci			   entry, index, false, 0, mm->vgpu);
5648c2ecf20Sopenharmony_ci	update_entry_type_for_real(pte_ops, entry, false);
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic inline void ppgtt_get_guest_root_entry(struct intel_vgpu_mm *mm,
5688c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	_ppgtt_get_root_entry(mm, entry, index, true);
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic inline void ppgtt_get_shadow_root_entry(struct intel_vgpu_mm *mm,
5748c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	_ppgtt_get_root_entry(mm, entry, index, false);
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic void _ppgtt_set_root_entry(struct intel_vgpu_mm *mm,
5808c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index,
5818c2ecf20Sopenharmony_ci		bool guest)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	pte_ops->set_entry(guest ? mm->ppgtt_mm.guest_pdps :
5868c2ecf20Sopenharmony_ci			   mm->ppgtt_mm.shadow_pdps,
5878c2ecf20Sopenharmony_ci			   entry, index, false, 0, mm->vgpu);
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic inline void ppgtt_set_guest_root_entry(struct intel_vgpu_mm *mm,
5918c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	_ppgtt_set_root_entry(mm, entry, index, true);
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_cistatic inline void ppgtt_set_shadow_root_entry(struct intel_vgpu_mm *mm,
5978c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	_ppgtt_set_root_entry(mm, entry, index, false);
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic void ggtt_get_guest_entry(struct intel_vgpu_mm *mm,
6038c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	entry->type = GTT_TYPE_GGTT_PTE;
6108c2ecf20Sopenharmony_ci	pte_ops->get_entry(mm->ggtt_mm.virtual_ggtt, entry, index,
6118c2ecf20Sopenharmony_ci			   false, 0, mm->vgpu);
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cistatic void ggtt_set_guest_entry(struct intel_vgpu_mm *mm,
6158c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	pte_ops->set_entry(mm->ggtt_mm.virtual_ggtt, entry, index,
6228c2ecf20Sopenharmony_ci			   false, 0, mm->vgpu);
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_cistatic void ggtt_get_host_entry(struct intel_vgpu_mm *mm,
6268c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	pte_ops->get_entry(NULL, entry, index, false, 0, mm->vgpu);
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic void ggtt_set_host_entry(struct intel_vgpu_mm *mm,
6368c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry, unsigned long index)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *pte_ops = mm->vgpu->gvt->gtt.pte_ops;
6398c2ecf20Sopenharmony_ci	unsigned long offset = index;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	if (vgpu_gmadr_is_aperture(mm->vgpu, index << I915_GTT_PAGE_SHIFT)) {
6448c2ecf20Sopenharmony_ci		offset -= (vgpu_aperture_gmadr_base(mm->vgpu) >> PAGE_SHIFT);
6458c2ecf20Sopenharmony_ci		mm->ggtt_mm.host_ggtt_aperture[offset] = entry->val64;
6468c2ecf20Sopenharmony_ci	} else if (vgpu_gmadr_is_hidden(mm->vgpu, index << I915_GTT_PAGE_SHIFT)) {
6478c2ecf20Sopenharmony_ci		offset -= (vgpu_hidden_gmadr_base(mm->vgpu) >> PAGE_SHIFT);
6488c2ecf20Sopenharmony_ci		mm->ggtt_mm.host_ggtt_hidden[offset] = entry->val64;
6498c2ecf20Sopenharmony_ci	}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	pte_ops->set_entry(NULL, entry, index, false, 0, mm->vgpu);
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci/*
6558c2ecf20Sopenharmony_ci * PPGTT shadow page table helpers.
6568c2ecf20Sopenharmony_ci */
6578c2ecf20Sopenharmony_cistatic inline int ppgtt_spt_get_entry(
6588c2ecf20Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt,
6598c2ecf20Sopenharmony_ci		void *page_table, int type,
6608c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *e, unsigned long index,
6618c2ecf20Sopenharmony_ci		bool guest)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = spt->vgpu->gvt;
6648c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops;
6658c2ecf20Sopenharmony_ci	int ret;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	e->type = get_entry_type(type);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	if (WARN(!gtt_type_is_entry(e->type), "invalid entry type\n"))
6708c2ecf20Sopenharmony_ci		return -EINVAL;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	ret = ops->get_entry(page_table, e, index, guest,
6738c2ecf20Sopenharmony_ci			spt->guest_page.gfn << I915_GTT_PAGE_SHIFT,
6748c2ecf20Sopenharmony_ci			spt->vgpu);
6758c2ecf20Sopenharmony_ci	if (ret)
6768c2ecf20Sopenharmony_ci		return ret;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	update_entry_type_for_real(ops, e, guest ?
6798c2ecf20Sopenharmony_ci				   spt->guest_page.pde_ips : false);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	gvt_vdbg_mm("read ppgtt entry, spt type %d, entry type %d, index %lu, value %llx\n",
6828c2ecf20Sopenharmony_ci		    type, e->type, index, e->val64);
6838c2ecf20Sopenharmony_ci	return 0;
6848c2ecf20Sopenharmony_ci}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_cistatic inline int ppgtt_spt_set_entry(
6878c2ecf20Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt,
6888c2ecf20Sopenharmony_ci		void *page_table, int type,
6898c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *e, unsigned long index,
6908c2ecf20Sopenharmony_ci		bool guest)
6918c2ecf20Sopenharmony_ci{
6928c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = spt->vgpu->gvt;
6938c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (WARN(!gtt_type_is_entry(e->type), "invalid entry type\n"))
6968c2ecf20Sopenharmony_ci		return -EINVAL;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	gvt_vdbg_mm("set ppgtt entry, spt type %d, entry type %d, index %lu, value %llx\n",
6998c2ecf20Sopenharmony_ci		    type, e->type, index, e->val64);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	return ops->set_entry(page_table, e, index, guest,
7028c2ecf20Sopenharmony_ci			spt->guest_page.gfn << I915_GTT_PAGE_SHIFT,
7038c2ecf20Sopenharmony_ci			spt->vgpu);
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci#define ppgtt_get_guest_entry(spt, e, index) \
7078c2ecf20Sopenharmony_ci	ppgtt_spt_get_entry(spt, NULL, \
7088c2ecf20Sopenharmony_ci		spt->guest_page.type, e, index, true)
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci#define ppgtt_set_guest_entry(spt, e, index) \
7118c2ecf20Sopenharmony_ci	ppgtt_spt_set_entry(spt, NULL, \
7128c2ecf20Sopenharmony_ci		spt->guest_page.type, e, index, true)
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci#define ppgtt_get_shadow_entry(spt, e, index) \
7158c2ecf20Sopenharmony_ci	ppgtt_spt_get_entry(spt, spt->shadow_page.vaddr, \
7168c2ecf20Sopenharmony_ci		spt->shadow_page.type, e, index, false)
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci#define ppgtt_set_shadow_entry(spt, e, index) \
7198c2ecf20Sopenharmony_ci	ppgtt_spt_set_entry(spt, spt->shadow_page.vaddr, \
7208c2ecf20Sopenharmony_ci		spt->shadow_page.type, e, index, false)
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic void *alloc_spt(gfp_t gfp_mask)
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	spt = kzalloc(sizeof(*spt), gfp_mask);
7278c2ecf20Sopenharmony_ci	if (!spt)
7288c2ecf20Sopenharmony_ci		return NULL;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	spt->shadow_page.page = alloc_page(gfp_mask);
7318c2ecf20Sopenharmony_ci	if (!spt->shadow_page.page) {
7328c2ecf20Sopenharmony_ci		kfree(spt);
7338c2ecf20Sopenharmony_ci		return NULL;
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci	return spt;
7368c2ecf20Sopenharmony_ci}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_cistatic void free_spt(struct intel_vgpu_ppgtt_spt *spt)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	__free_page(spt->shadow_page.page);
7418c2ecf20Sopenharmony_ci	kfree(spt);
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cistatic int detach_oos_page(struct intel_vgpu *vgpu,
7458c2ecf20Sopenharmony_ci		struct intel_vgpu_oos_page *oos_page);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_cistatic void ppgtt_free_spt(struct intel_vgpu_ppgtt_spt *spt)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	struct device *kdev = &spt->vgpu->gvt->gt->i915->drm.pdev->dev;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	trace_spt_free(spt->vgpu->id, spt, spt->guest_page.type);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	dma_unmap_page(kdev, spt->shadow_page.mfn << I915_GTT_PAGE_SHIFT, 4096,
7548c2ecf20Sopenharmony_ci		       PCI_DMA_BIDIRECTIONAL);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	radix_tree_delete(&spt->vgpu->gtt.spt_tree, spt->shadow_page.mfn);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (spt->guest_page.gfn) {
7598c2ecf20Sopenharmony_ci		if (spt->guest_page.oos_page)
7608c2ecf20Sopenharmony_ci			detach_oos_page(spt->vgpu, spt->guest_page.oos_page);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci		intel_vgpu_unregister_page_track(spt->vgpu, spt->guest_page.gfn);
7638c2ecf20Sopenharmony_ci	}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	list_del_init(&spt->post_shadow_list);
7668c2ecf20Sopenharmony_ci	free_spt(spt);
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_cistatic void ppgtt_free_all_spt(struct intel_vgpu *vgpu)
7708c2ecf20Sopenharmony_ci{
7718c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt, *spn;
7728c2ecf20Sopenharmony_ci	struct radix_tree_iter iter;
7738c2ecf20Sopenharmony_ci	LIST_HEAD(all_spt);
7748c2ecf20Sopenharmony_ci	void __rcu **slot;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	rcu_read_lock();
7778c2ecf20Sopenharmony_ci	radix_tree_for_each_slot(slot, &vgpu->gtt.spt_tree, &iter, 0) {
7788c2ecf20Sopenharmony_ci		spt = radix_tree_deref_slot(slot);
7798c2ecf20Sopenharmony_ci		list_move(&spt->post_shadow_list, &all_spt);
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci	rcu_read_unlock();
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	list_for_each_entry_safe(spt, spn, &all_spt, post_shadow_list)
7848c2ecf20Sopenharmony_ci		ppgtt_free_spt(spt);
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic int ppgtt_handle_guest_write_page_table_bytes(
7888c2ecf20Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt,
7898c2ecf20Sopenharmony_ci		u64 pa, void *p_data, int bytes);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_cistatic int ppgtt_write_protection_handler(
7928c2ecf20Sopenharmony_ci		struct intel_vgpu_page_track *page_track,
7938c2ecf20Sopenharmony_ci		u64 gpa, void *data, int bytes)
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt = page_track->priv_data;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	int ret;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	if (bytes != 4 && bytes != 8)
8008c2ecf20Sopenharmony_ci		return -EINVAL;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	ret = ppgtt_handle_guest_write_page_table_bytes(spt, gpa, data, bytes);
8038c2ecf20Sopenharmony_ci	if (ret)
8048c2ecf20Sopenharmony_ci		return ret;
8058c2ecf20Sopenharmony_ci	return ret;
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci/* Find a spt by guest gfn. */
8098c2ecf20Sopenharmony_cistatic struct intel_vgpu_ppgtt_spt *intel_vgpu_find_spt_by_gfn(
8108c2ecf20Sopenharmony_ci		struct intel_vgpu *vgpu, unsigned long gfn)
8118c2ecf20Sopenharmony_ci{
8128c2ecf20Sopenharmony_ci	struct intel_vgpu_page_track *track;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	track = intel_vgpu_find_page_track(vgpu, gfn);
8158c2ecf20Sopenharmony_ci	if (track && track->handler == ppgtt_write_protection_handler)
8168c2ecf20Sopenharmony_ci		return track->priv_data;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	return NULL;
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci/* Find the spt by shadow page mfn. */
8228c2ecf20Sopenharmony_cistatic inline struct intel_vgpu_ppgtt_spt *intel_vgpu_find_spt_by_mfn(
8238c2ecf20Sopenharmony_ci		struct intel_vgpu *vgpu, unsigned long mfn)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	return radix_tree_lookup(&vgpu->gtt.spt_tree, mfn);
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic int reclaim_one_ppgtt_mm(struct intel_gvt *gvt);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci/* Allocate shadow page table without guest page. */
8318c2ecf20Sopenharmony_cistatic struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt(
8328c2ecf20Sopenharmony_ci		struct intel_vgpu *vgpu, enum intel_gvt_gtt_type type)
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	struct device *kdev = &vgpu->gvt->gt->i915->drm.pdev->dev;
8358c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt = NULL;
8368c2ecf20Sopenharmony_ci	dma_addr_t daddr;
8378c2ecf20Sopenharmony_ci	int ret;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ciretry:
8408c2ecf20Sopenharmony_ci	spt = alloc_spt(GFP_KERNEL | __GFP_ZERO);
8418c2ecf20Sopenharmony_ci	if (!spt) {
8428c2ecf20Sopenharmony_ci		if (reclaim_one_ppgtt_mm(vgpu->gvt))
8438c2ecf20Sopenharmony_ci			goto retry;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci		gvt_vgpu_err("fail to allocate ppgtt shadow page\n");
8468c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
8478c2ecf20Sopenharmony_ci	}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	spt->vgpu = vgpu;
8508c2ecf20Sopenharmony_ci	atomic_set(&spt->refcount, 1);
8518c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&spt->post_shadow_list);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	/*
8548c2ecf20Sopenharmony_ci	 * Init shadow_page.
8558c2ecf20Sopenharmony_ci	 */
8568c2ecf20Sopenharmony_ci	spt->shadow_page.type = type;
8578c2ecf20Sopenharmony_ci	daddr = dma_map_page(kdev, spt->shadow_page.page,
8588c2ecf20Sopenharmony_ci			     0, 4096, PCI_DMA_BIDIRECTIONAL);
8598c2ecf20Sopenharmony_ci	if (dma_mapping_error(kdev, daddr)) {
8608c2ecf20Sopenharmony_ci		gvt_vgpu_err("fail to map dma addr\n");
8618c2ecf20Sopenharmony_ci		ret = -EINVAL;
8628c2ecf20Sopenharmony_ci		goto err_free_spt;
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci	spt->shadow_page.vaddr = page_address(spt->shadow_page.page);
8658c2ecf20Sopenharmony_ci	spt->shadow_page.mfn = daddr >> I915_GTT_PAGE_SHIFT;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	ret = radix_tree_insert(&vgpu->gtt.spt_tree, spt->shadow_page.mfn, spt);
8688c2ecf20Sopenharmony_ci	if (ret)
8698c2ecf20Sopenharmony_ci		goto err_unmap_dma;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	return spt;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_cierr_unmap_dma:
8748c2ecf20Sopenharmony_ci	dma_unmap_page(kdev, daddr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
8758c2ecf20Sopenharmony_cierr_free_spt:
8768c2ecf20Sopenharmony_ci	free_spt(spt);
8778c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
8788c2ecf20Sopenharmony_ci}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci/* Allocate shadow page table associated with specific gfn. */
8818c2ecf20Sopenharmony_cistatic struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt_gfn(
8828c2ecf20Sopenharmony_ci		struct intel_vgpu *vgpu, enum intel_gvt_gtt_type type,
8838c2ecf20Sopenharmony_ci		unsigned long gfn, bool guest_pde_ips)
8848c2ecf20Sopenharmony_ci{
8858c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt;
8868c2ecf20Sopenharmony_ci	int ret;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	spt = ppgtt_alloc_spt(vgpu, type);
8898c2ecf20Sopenharmony_ci	if (IS_ERR(spt))
8908c2ecf20Sopenharmony_ci		return spt;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	/*
8938c2ecf20Sopenharmony_ci	 * Init guest_page.
8948c2ecf20Sopenharmony_ci	 */
8958c2ecf20Sopenharmony_ci	ret = intel_vgpu_register_page_track(vgpu, gfn,
8968c2ecf20Sopenharmony_ci			ppgtt_write_protection_handler, spt);
8978c2ecf20Sopenharmony_ci	if (ret) {
8988c2ecf20Sopenharmony_ci		ppgtt_free_spt(spt);
8998c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
9008c2ecf20Sopenharmony_ci	}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	spt->guest_page.type = type;
9038c2ecf20Sopenharmony_ci	spt->guest_page.gfn = gfn;
9048c2ecf20Sopenharmony_ci	spt->guest_page.pde_ips = guest_pde_ips;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	trace_spt_alloc(vgpu->id, spt, type, spt->shadow_page.mfn, gfn);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	return spt;
9098c2ecf20Sopenharmony_ci}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci#define pt_entry_size_shift(spt) \
9128c2ecf20Sopenharmony_ci	((spt)->vgpu->gvt->device_info.gtt_entry_size_shift)
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci#define pt_entries(spt) \
9158c2ecf20Sopenharmony_ci	(I915_GTT_PAGE_SIZE >> pt_entry_size_shift(spt))
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci#define for_each_present_guest_entry(spt, e, i) \
9188c2ecf20Sopenharmony_ci	for (i = 0; i < pt_entries(spt); \
9198c2ecf20Sopenharmony_ci	     i += spt->guest_page.pde_ips ? GTT_64K_PTE_STRIDE : 1) \
9208c2ecf20Sopenharmony_ci		if (!ppgtt_get_guest_entry(spt, e, i) && \
9218c2ecf20Sopenharmony_ci		    spt->vgpu->gvt->gtt.pte_ops->test_present(e))
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci#define for_each_present_shadow_entry(spt, e, i) \
9248c2ecf20Sopenharmony_ci	for (i = 0; i < pt_entries(spt); \
9258c2ecf20Sopenharmony_ci	     i += spt->shadow_page.pde_ips ? GTT_64K_PTE_STRIDE : 1) \
9268c2ecf20Sopenharmony_ci		if (!ppgtt_get_shadow_entry(spt, e, i) && \
9278c2ecf20Sopenharmony_ci		    spt->vgpu->gvt->gtt.pte_ops->test_present(e))
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci#define for_each_shadow_entry(spt, e, i) \
9308c2ecf20Sopenharmony_ci	for (i = 0; i < pt_entries(spt); \
9318c2ecf20Sopenharmony_ci	     i += (spt->shadow_page.pde_ips ? GTT_64K_PTE_STRIDE : 1)) \
9328c2ecf20Sopenharmony_ci		if (!ppgtt_get_shadow_entry(spt, e, i))
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_cistatic inline void ppgtt_get_spt(struct intel_vgpu_ppgtt_spt *spt)
9358c2ecf20Sopenharmony_ci{
9368c2ecf20Sopenharmony_ci	int v = atomic_read(&spt->refcount);
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	trace_spt_refcount(spt->vgpu->id, "inc", spt, v, (v + 1));
9398c2ecf20Sopenharmony_ci	atomic_inc(&spt->refcount);
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cistatic inline int ppgtt_put_spt(struct intel_vgpu_ppgtt_spt *spt)
9438c2ecf20Sopenharmony_ci{
9448c2ecf20Sopenharmony_ci	int v = atomic_read(&spt->refcount);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	trace_spt_refcount(spt->vgpu->id, "dec", spt, v, (v - 1));
9478c2ecf20Sopenharmony_ci	return atomic_dec_return(&spt->refcount);
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_cistatic int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_cistatic int ppgtt_invalidate_spt_by_shadow_entry(struct intel_vgpu *vgpu,
9538c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *e)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
9568c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
9578c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *s;
9588c2ecf20Sopenharmony_ci	enum intel_gvt_gtt_type cur_pt_type;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	GEM_BUG_ON(!gtt_type_is_pt(get_next_pt_type(e->type)));
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	if (e->type != GTT_TYPE_PPGTT_ROOT_L3_ENTRY
9638c2ecf20Sopenharmony_ci		&& e->type != GTT_TYPE_PPGTT_ROOT_L4_ENTRY) {
9648c2ecf20Sopenharmony_ci		cur_pt_type = get_next_pt_type(e->type);
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci		if (!gtt_type_is_pt(cur_pt_type) ||
9678c2ecf20Sopenharmony_ci				!gtt_type_is_pt(cur_pt_type + 1)) {
9688c2ecf20Sopenharmony_ci			drm_WARN(&i915->drm, 1,
9698c2ecf20Sopenharmony_ci				 "Invalid page table type, cur_pt_type is: %d\n",
9708c2ecf20Sopenharmony_ci				 cur_pt_type);
9718c2ecf20Sopenharmony_ci			return -EINVAL;
9728c2ecf20Sopenharmony_ci		}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci		cur_pt_type += 1;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci		if (ops->get_pfn(e) ==
9778c2ecf20Sopenharmony_ci			vgpu->gtt.scratch_pt[cur_pt_type].page_mfn)
9788c2ecf20Sopenharmony_ci			return 0;
9798c2ecf20Sopenharmony_ci	}
9808c2ecf20Sopenharmony_ci	s = intel_vgpu_find_spt_by_mfn(vgpu, ops->get_pfn(e));
9818c2ecf20Sopenharmony_ci	if (!s) {
9828c2ecf20Sopenharmony_ci		gvt_vgpu_err("fail to find shadow page: mfn: 0x%lx\n",
9838c2ecf20Sopenharmony_ci				ops->get_pfn(e));
9848c2ecf20Sopenharmony_ci		return -ENXIO;
9858c2ecf20Sopenharmony_ci	}
9868c2ecf20Sopenharmony_ci	return ppgtt_invalidate_spt(s);
9878c2ecf20Sopenharmony_ci}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_cistatic inline void ppgtt_invalidate_pte(struct intel_vgpu_ppgtt_spt *spt,
9908c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry)
9918c2ecf20Sopenharmony_ci{
9928c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
9938c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
9948c2ecf20Sopenharmony_ci	unsigned long pfn;
9958c2ecf20Sopenharmony_ci	int type;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	pfn = ops->get_pfn(entry);
9988c2ecf20Sopenharmony_ci	type = spt->shadow_page.type;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	/* Uninitialized spte or unshadowed spte. */
10018c2ecf20Sopenharmony_ci	if (!pfn || pfn == vgpu->gtt.scratch_pt[type].page_mfn)
10028c2ecf20Sopenharmony_ci		return;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	intel_gvt_hypervisor_dma_unmap_guest_page(vgpu, pfn << PAGE_SHIFT);
10058c2ecf20Sopenharmony_ci}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_cistatic int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt)
10088c2ecf20Sopenharmony_ci{
10098c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
10108c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry e;
10118c2ecf20Sopenharmony_ci	unsigned long index;
10128c2ecf20Sopenharmony_ci	int ret;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	trace_spt_change(spt->vgpu->id, "die", spt,
10158c2ecf20Sopenharmony_ci			spt->guest_page.gfn, spt->shadow_page.type);
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	if (ppgtt_put_spt(spt) > 0)
10188c2ecf20Sopenharmony_ci		return 0;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	for_each_present_shadow_entry(spt, &e, index) {
10218c2ecf20Sopenharmony_ci		switch (e.type) {
10228c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_4K_ENTRY:
10238c2ecf20Sopenharmony_ci			gvt_vdbg_mm("invalidate 4K entry\n");
10248c2ecf20Sopenharmony_ci			ppgtt_invalidate_pte(spt, &e);
10258c2ecf20Sopenharmony_ci			break;
10268c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_64K_ENTRY:
10278c2ecf20Sopenharmony_ci			/* We don't setup 64K shadow entry so far. */
10288c2ecf20Sopenharmony_ci			WARN(1, "suspicious 64K gtt entry\n");
10298c2ecf20Sopenharmony_ci			continue;
10308c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_2M_ENTRY:
10318c2ecf20Sopenharmony_ci			gvt_vdbg_mm("invalidate 2M entry\n");
10328c2ecf20Sopenharmony_ci			continue;
10338c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_PTE_1G_ENTRY:
10348c2ecf20Sopenharmony_ci			WARN(1, "GVT doesn't support 1GB page\n");
10358c2ecf20Sopenharmony_ci			continue;
10368c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_PML4_ENTRY:
10378c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_PDP_ENTRY:
10388c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_PDE_ENTRY:
10398c2ecf20Sopenharmony_ci			gvt_vdbg_mm("invalidate PMUL4/PDP/PDE entry\n");
10408c2ecf20Sopenharmony_ci			ret = ppgtt_invalidate_spt_by_shadow_entry(
10418c2ecf20Sopenharmony_ci					spt->vgpu, &e);
10428c2ecf20Sopenharmony_ci			if (ret)
10438c2ecf20Sopenharmony_ci				goto fail;
10448c2ecf20Sopenharmony_ci			break;
10458c2ecf20Sopenharmony_ci		default:
10468c2ecf20Sopenharmony_ci			GEM_BUG_ON(1);
10478c2ecf20Sopenharmony_ci		}
10488c2ecf20Sopenharmony_ci	}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	trace_spt_change(spt->vgpu->id, "release", spt,
10518c2ecf20Sopenharmony_ci			 spt->guest_page.gfn, spt->shadow_page.type);
10528c2ecf20Sopenharmony_ci	ppgtt_free_spt(spt);
10538c2ecf20Sopenharmony_ci	return 0;
10548c2ecf20Sopenharmony_cifail:
10558c2ecf20Sopenharmony_ci	gvt_vgpu_err("fail: shadow page %p shadow entry 0x%llx type %d\n",
10568c2ecf20Sopenharmony_ci			spt, e.val64, e.type);
10578c2ecf20Sopenharmony_ci	return ret;
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cistatic bool vgpu_ips_enabled(struct intel_vgpu *vgpu)
10618c2ecf20Sopenharmony_ci{
10628c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = vgpu->gvt->gt->i915;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) == 9 || INTEL_GEN(dev_priv) == 10) {
10658c2ecf20Sopenharmony_ci		u32 ips = vgpu_vreg_t(vgpu, GEN8_GAMW_ECO_DEV_RW_IA) &
10668c2ecf20Sopenharmony_ci			GAMW_ECO_ENABLE_64K_IPS_FIELD;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci		return ips == GAMW_ECO_ENABLE_64K_IPS_FIELD;
10698c2ecf20Sopenharmony_ci	} else if (INTEL_GEN(dev_priv) >= 11) {
10708c2ecf20Sopenharmony_ci		/* 64K paging only controlled by IPS bit in PTE now. */
10718c2ecf20Sopenharmony_ci		return true;
10728c2ecf20Sopenharmony_ci	} else
10738c2ecf20Sopenharmony_ci		return false;
10748c2ecf20Sopenharmony_ci}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_cistatic int ppgtt_populate_spt(struct intel_vgpu_ppgtt_spt *spt);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_cistatic struct intel_vgpu_ppgtt_spt *ppgtt_populate_spt_by_guest_entry(
10798c2ecf20Sopenharmony_ci		struct intel_vgpu *vgpu, struct intel_gvt_gtt_entry *we)
10808c2ecf20Sopenharmony_ci{
10818c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
10828c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt = NULL;
10838c2ecf20Sopenharmony_ci	bool ips = false;
10848c2ecf20Sopenharmony_ci	int ret;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	GEM_BUG_ON(!gtt_type_is_pt(get_next_pt_type(we->type)));
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	if (we->type == GTT_TYPE_PPGTT_PDE_ENTRY)
10898c2ecf20Sopenharmony_ci		ips = vgpu_ips_enabled(vgpu) && ops->test_ips(we);
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	spt = intel_vgpu_find_spt_by_gfn(vgpu, ops->get_pfn(we));
10928c2ecf20Sopenharmony_ci	if (spt) {
10938c2ecf20Sopenharmony_ci		ppgtt_get_spt(spt);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci		if (ips != spt->guest_page.pde_ips) {
10968c2ecf20Sopenharmony_ci			spt->guest_page.pde_ips = ips;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci			gvt_dbg_mm("reshadow PDE since ips changed\n");
10998c2ecf20Sopenharmony_ci			clear_page(spt->shadow_page.vaddr);
11008c2ecf20Sopenharmony_ci			ret = ppgtt_populate_spt(spt);
11018c2ecf20Sopenharmony_ci			if (ret) {
11028c2ecf20Sopenharmony_ci				ppgtt_put_spt(spt);
11038c2ecf20Sopenharmony_ci				goto err;
11048c2ecf20Sopenharmony_ci			}
11058c2ecf20Sopenharmony_ci		}
11068c2ecf20Sopenharmony_ci	} else {
11078c2ecf20Sopenharmony_ci		int type = get_next_pt_type(we->type);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci		if (!gtt_type_is_pt(type)) {
11108c2ecf20Sopenharmony_ci			ret = -EINVAL;
11118c2ecf20Sopenharmony_ci			goto err;
11128c2ecf20Sopenharmony_ci		}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci		spt = ppgtt_alloc_spt_gfn(vgpu, type, ops->get_pfn(we), ips);
11158c2ecf20Sopenharmony_ci		if (IS_ERR(spt)) {
11168c2ecf20Sopenharmony_ci			ret = PTR_ERR(spt);
11178c2ecf20Sopenharmony_ci			goto err;
11188c2ecf20Sopenharmony_ci		}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci		ret = intel_vgpu_enable_page_track(vgpu, spt->guest_page.gfn);
11218c2ecf20Sopenharmony_ci		if (ret)
11228c2ecf20Sopenharmony_ci			goto err_free_spt;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci		ret = ppgtt_populate_spt(spt);
11258c2ecf20Sopenharmony_ci		if (ret)
11268c2ecf20Sopenharmony_ci			goto err_free_spt;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci		trace_spt_change(vgpu->id, "new", spt, spt->guest_page.gfn,
11298c2ecf20Sopenharmony_ci				 spt->shadow_page.type);
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci	return spt;
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_cierr_free_spt:
11348c2ecf20Sopenharmony_ci	ppgtt_free_spt(spt);
11358c2ecf20Sopenharmony_ci	spt = NULL;
11368c2ecf20Sopenharmony_cierr:
11378c2ecf20Sopenharmony_ci	gvt_vgpu_err("fail: shadow page %p guest entry 0x%llx type %d\n",
11388c2ecf20Sopenharmony_ci		     spt, we->val64, we->type);
11398c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
11408c2ecf20Sopenharmony_ci}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_cistatic inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se,
11438c2ecf20Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *s, struct intel_gvt_gtt_entry *ge)
11448c2ecf20Sopenharmony_ci{
11458c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = s->vgpu->gvt->gtt.pte_ops;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	se->type = ge->type;
11488c2ecf20Sopenharmony_ci	se->val64 = ge->val64;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	/* Because we always split 64KB pages, so clear IPS in shadow PDE. */
11518c2ecf20Sopenharmony_ci	if (se->type == GTT_TYPE_PPGTT_PDE_ENTRY)
11528c2ecf20Sopenharmony_ci		ops->clear_ips(se);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	ops->set_pfn(se, s->shadow_page.mfn);
11558c2ecf20Sopenharmony_ci}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci/**
11588c2ecf20Sopenharmony_ci * Check if can do 2M page
11598c2ecf20Sopenharmony_ci * @vgpu: target vgpu
11608c2ecf20Sopenharmony_ci * @entry: target pfn's gtt entry
11618c2ecf20Sopenharmony_ci *
11628c2ecf20Sopenharmony_ci * Return 1 if 2MB huge gtt shadowing is possilbe, 0 if miscondition,
11638c2ecf20Sopenharmony_ci * negtive if found err.
11648c2ecf20Sopenharmony_ci */
11658c2ecf20Sopenharmony_cistatic int is_2MB_gtt_possible(struct intel_vgpu *vgpu,
11668c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry *entry)
11678c2ecf20Sopenharmony_ci{
11688c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
11698c2ecf20Sopenharmony_ci	unsigned long pfn;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	if (!HAS_PAGE_SIZES(vgpu->gvt->gt->i915, I915_GTT_PAGE_SIZE_2M))
11728c2ecf20Sopenharmony_ci		return 0;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	pfn = intel_gvt_hypervisor_gfn_to_mfn(vgpu, ops->get_pfn(entry));
11758c2ecf20Sopenharmony_ci	if (pfn == INTEL_GVT_INVALID_ADDR)
11768c2ecf20Sopenharmony_ci		return -EINVAL;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	return PageTransHuge(pfn_to_page(pfn));
11798c2ecf20Sopenharmony_ci}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_cistatic int split_2MB_gtt_entry(struct intel_vgpu *vgpu,
11828c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt, unsigned long index,
11838c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry *se)
11848c2ecf20Sopenharmony_ci{
11858c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
11868c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *sub_spt;
11878c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry sub_se;
11888c2ecf20Sopenharmony_ci	unsigned long start_gfn;
11898c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
11908c2ecf20Sopenharmony_ci	unsigned long sub_index;
11918c2ecf20Sopenharmony_ci	int ret;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	gvt_dbg_mm("Split 2M gtt entry, index %lu\n", index);
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	start_gfn = ops->get_pfn(se);
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	sub_spt = ppgtt_alloc_spt(vgpu, GTT_TYPE_PPGTT_PTE_PT);
11988c2ecf20Sopenharmony_ci	if (IS_ERR(sub_spt))
11998c2ecf20Sopenharmony_ci		return PTR_ERR(sub_spt);
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	for_each_shadow_entry(sub_spt, &sub_se, sub_index) {
12028c2ecf20Sopenharmony_ci		ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu,
12038c2ecf20Sopenharmony_ci				start_gfn + sub_index, PAGE_SIZE, &dma_addr);
12048c2ecf20Sopenharmony_ci		if (ret)
12058c2ecf20Sopenharmony_ci			goto err;
12068c2ecf20Sopenharmony_ci		sub_se.val64 = se->val64;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci		/* Copy the PAT field from PDE. */
12098c2ecf20Sopenharmony_ci		sub_se.val64 &= ~_PAGE_PAT;
12108c2ecf20Sopenharmony_ci		sub_se.val64 |= (se->val64 & _PAGE_PAT_LARGE) >> 5;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci		ops->set_pfn(&sub_se, dma_addr >> PAGE_SHIFT);
12138c2ecf20Sopenharmony_ci		ppgtt_set_shadow_entry(sub_spt, &sub_se, sub_index);
12148c2ecf20Sopenharmony_ci	}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	/* Clear dirty field. */
12178c2ecf20Sopenharmony_ci	se->val64 &= ~_PAGE_DIRTY;
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	ops->clear_pse(se);
12208c2ecf20Sopenharmony_ci	ops->clear_ips(se);
12218c2ecf20Sopenharmony_ci	ops->set_pfn(se, sub_spt->shadow_page.mfn);
12228c2ecf20Sopenharmony_ci	ppgtt_set_shadow_entry(spt, se, index);
12238c2ecf20Sopenharmony_ci	return 0;
12248c2ecf20Sopenharmony_cierr:
12258c2ecf20Sopenharmony_ci	/* Cancel the existing addess mappings of DMA addr. */
12268c2ecf20Sopenharmony_ci	for_each_present_shadow_entry(sub_spt, &sub_se, sub_index) {
12278c2ecf20Sopenharmony_ci		gvt_vdbg_mm("invalidate 4K entry\n");
12288c2ecf20Sopenharmony_ci		ppgtt_invalidate_pte(sub_spt, &sub_se);
12298c2ecf20Sopenharmony_ci	}
12308c2ecf20Sopenharmony_ci	/* Release the new allocated spt. */
12318c2ecf20Sopenharmony_ci	trace_spt_change(sub_spt->vgpu->id, "release", sub_spt,
12328c2ecf20Sopenharmony_ci		sub_spt->guest_page.gfn, sub_spt->shadow_page.type);
12338c2ecf20Sopenharmony_ci	ppgtt_free_spt(sub_spt);
12348c2ecf20Sopenharmony_ci	return ret;
12358c2ecf20Sopenharmony_ci}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_cistatic int split_64KB_gtt_entry(struct intel_vgpu *vgpu,
12388c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt, unsigned long index,
12398c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry *se)
12408c2ecf20Sopenharmony_ci{
12418c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
12428c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry entry = *se;
12438c2ecf20Sopenharmony_ci	unsigned long start_gfn;
12448c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
12458c2ecf20Sopenharmony_ci	int i, ret;
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	gvt_vdbg_mm("Split 64K gtt entry, index %lu\n", index);
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	GEM_BUG_ON(index % GTT_64K_PTE_STRIDE);
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	start_gfn = ops->get_pfn(se);
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	entry.type = GTT_TYPE_PPGTT_PTE_4K_ENTRY;
12548c2ecf20Sopenharmony_ci	ops->set_64k_splited(&entry);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	for (i = 0; i < GTT_64K_PTE_STRIDE; i++) {
12578c2ecf20Sopenharmony_ci		ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu,
12588c2ecf20Sopenharmony_ci					start_gfn + i, PAGE_SIZE, &dma_addr);
12598c2ecf20Sopenharmony_ci		if (ret)
12608c2ecf20Sopenharmony_ci			return ret;
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci		ops->set_pfn(&entry, dma_addr >> PAGE_SHIFT);
12638c2ecf20Sopenharmony_ci		ppgtt_set_shadow_entry(spt, &entry, index + i);
12648c2ecf20Sopenharmony_ci	}
12658c2ecf20Sopenharmony_ci	return 0;
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_cistatic int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu,
12698c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt, unsigned long index,
12708c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry *ge)
12718c2ecf20Sopenharmony_ci{
12728c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops;
12738c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry se = *ge;
12748c2ecf20Sopenharmony_ci	unsigned long gfn, page_size = PAGE_SIZE;
12758c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
12768c2ecf20Sopenharmony_ci	int ret;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	if (!pte_ops->test_present(ge))
12798c2ecf20Sopenharmony_ci		return 0;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	gfn = pte_ops->get_pfn(ge);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	switch (ge->type) {
12848c2ecf20Sopenharmony_ci	case GTT_TYPE_PPGTT_PTE_4K_ENTRY:
12858c2ecf20Sopenharmony_ci		gvt_vdbg_mm("shadow 4K gtt entry\n");
12868c2ecf20Sopenharmony_ci		break;
12878c2ecf20Sopenharmony_ci	case GTT_TYPE_PPGTT_PTE_64K_ENTRY:
12888c2ecf20Sopenharmony_ci		gvt_vdbg_mm("shadow 64K gtt entry\n");
12898c2ecf20Sopenharmony_ci		/*
12908c2ecf20Sopenharmony_ci		 * The layout of 64K page is special, the page size is
12918c2ecf20Sopenharmony_ci		 * controlled by uper PDE. To be simple, we always split
12928c2ecf20Sopenharmony_ci		 * 64K page to smaller 4K pages in shadow PT.
12938c2ecf20Sopenharmony_ci		 */
12948c2ecf20Sopenharmony_ci		return split_64KB_gtt_entry(vgpu, spt, index, &se);
12958c2ecf20Sopenharmony_ci	case GTT_TYPE_PPGTT_PTE_2M_ENTRY:
12968c2ecf20Sopenharmony_ci		gvt_vdbg_mm("shadow 2M gtt entry\n");
12978c2ecf20Sopenharmony_ci		ret = is_2MB_gtt_possible(vgpu, ge);
12988c2ecf20Sopenharmony_ci		if (ret == 0)
12998c2ecf20Sopenharmony_ci			return split_2MB_gtt_entry(vgpu, spt, index, &se);
13008c2ecf20Sopenharmony_ci		else if (ret < 0)
13018c2ecf20Sopenharmony_ci			return ret;
13028c2ecf20Sopenharmony_ci		page_size = I915_GTT_PAGE_SIZE_2M;
13038c2ecf20Sopenharmony_ci		break;
13048c2ecf20Sopenharmony_ci	case GTT_TYPE_PPGTT_PTE_1G_ENTRY:
13058c2ecf20Sopenharmony_ci		gvt_vgpu_err("GVT doesn't support 1GB entry\n");
13068c2ecf20Sopenharmony_ci		return -EINVAL;
13078c2ecf20Sopenharmony_ci	default:
13088c2ecf20Sopenharmony_ci		GEM_BUG_ON(1);
13098c2ecf20Sopenharmony_ci	}
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	/* direct shadow */
13128c2ecf20Sopenharmony_ci	ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, gfn, page_size,
13138c2ecf20Sopenharmony_ci						      &dma_addr);
13148c2ecf20Sopenharmony_ci	if (ret)
13158c2ecf20Sopenharmony_ci		return -ENXIO;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	pte_ops->set_pfn(&se, dma_addr >> PAGE_SHIFT);
13188c2ecf20Sopenharmony_ci	ppgtt_set_shadow_entry(spt, &se, index);
13198c2ecf20Sopenharmony_ci	return 0;
13208c2ecf20Sopenharmony_ci}
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_cistatic int ppgtt_populate_spt(struct intel_vgpu_ppgtt_spt *spt)
13238c2ecf20Sopenharmony_ci{
13248c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
13258c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
13268c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops;
13278c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *s;
13288c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry se, ge;
13298c2ecf20Sopenharmony_ci	unsigned long gfn, i;
13308c2ecf20Sopenharmony_ci	int ret;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	trace_spt_change(spt->vgpu->id, "born", spt,
13338c2ecf20Sopenharmony_ci			 spt->guest_page.gfn, spt->shadow_page.type);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	for_each_present_guest_entry(spt, &ge, i) {
13368c2ecf20Sopenharmony_ci		if (gtt_type_is_pt(get_next_pt_type(ge.type))) {
13378c2ecf20Sopenharmony_ci			s = ppgtt_populate_spt_by_guest_entry(vgpu, &ge);
13388c2ecf20Sopenharmony_ci			if (IS_ERR(s)) {
13398c2ecf20Sopenharmony_ci				ret = PTR_ERR(s);
13408c2ecf20Sopenharmony_ci				goto fail;
13418c2ecf20Sopenharmony_ci			}
13428c2ecf20Sopenharmony_ci			ppgtt_get_shadow_entry(spt, &se, i);
13438c2ecf20Sopenharmony_ci			ppgtt_generate_shadow_entry(&se, s, &ge);
13448c2ecf20Sopenharmony_ci			ppgtt_set_shadow_entry(spt, &se, i);
13458c2ecf20Sopenharmony_ci		} else {
13468c2ecf20Sopenharmony_ci			gfn = ops->get_pfn(&ge);
13478c2ecf20Sopenharmony_ci			if (!intel_gvt_hypervisor_is_valid_gfn(vgpu, gfn)) {
13488c2ecf20Sopenharmony_ci				ops->set_pfn(&se, gvt->gtt.scratch_mfn);
13498c2ecf20Sopenharmony_ci				ppgtt_set_shadow_entry(spt, &se, i);
13508c2ecf20Sopenharmony_ci				continue;
13518c2ecf20Sopenharmony_ci			}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci			ret = ppgtt_populate_shadow_entry(vgpu, spt, i, &ge);
13548c2ecf20Sopenharmony_ci			if (ret)
13558c2ecf20Sopenharmony_ci				goto fail;
13568c2ecf20Sopenharmony_ci		}
13578c2ecf20Sopenharmony_ci	}
13588c2ecf20Sopenharmony_ci	return 0;
13598c2ecf20Sopenharmony_cifail:
13608c2ecf20Sopenharmony_ci	gvt_vgpu_err("fail: shadow page %p guest entry 0x%llx type %d\n",
13618c2ecf20Sopenharmony_ci			spt, ge.val64, ge.type);
13628c2ecf20Sopenharmony_ci	return ret;
13638c2ecf20Sopenharmony_ci}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_cistatic int ppgtt_handle_guest_entry_removal(struct intel_vgpu_ppgtt_spt *spt,
13668c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *se, unsigned long index)
13678c2ecf20Sopenharmony_ci{
13688c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
13698c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
13708c2ecf20Sopenharmony_ci	int ret;
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	trace_spt_guest_change(spt->vgpu->id, "remove", spt,
13738c2ecf20Sopenharmony_ci			       spt->shadow_page.type, se->val64, index);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	gvt_vdbg_mm("destroy old shadow entry, type %d, index %lu, value %llx\n",
13768c2ecf20Sopenharmony_ci		    se->type, index, se->val64);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	if (!ops->test_present(se))
13798c2ecf20Sopenharmony_ci		return 0;
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	if (ops->get_pfn(se) ==
13828c2ecf20Sopenharmony_ci	    vgpu->gtt.scratch_pt[spt->shadow_page.type].page_mfn)
13838c2ecf20Sopenharmony_ci		return 0;
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	if (gtt_type_is_pt(get_next_pt_type(se->type))) {
13868c2ecf20Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *s =
13878c2ecf20Sopenharmony_ci			intel_vgpu_find_spt_by_mfn(vgpu, ops->get_pfn(se));
13888c2ecf20Sopenharmony_ci		if (!s) {
13898c2ecf20Sopenharmony_ci			gvt_vgpu_err("fail to find guest page\n");
13908c2ecf20Sopenharmony_ci			ret = -ENXIO;
13918c2ecf20Sopenharmony_ci			goto fail;
13928c2ecf20Sopenharmony_ci		}
13938c2ecf20Sopenharmony_ci		ret = ppgtt_invalidate_spt(s);
13948c2ecf20Sopenharmony_ci		if (ret)
13958c2ecf20Sopenharmony_ci			goto fail;
13968c2ecf20Sopenharmony_ci	} else {
13978c2ecf20Sopenharmony_ci		/* We don't setup 64K shadow entry so far. */
13988c2ecf20Sopenharmony_ci		WARN(se->type == GTT_TYPE_PPGTT_PTE_64K_ENTRY,
13998c2ecf20Sopenharmony_ci		     "suspicious 64K entry\n");
14008c2ecf20Sopenharmony_ci		ppgtt_invalidate_pte(spt, se);
14018c2ecf20Sopenharmony_ci	}
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	return 0;
14048c2ecf20Sopenharmony_cifail:
14058c2ecf20Sopenharmony_ci	gvt_vgpu_err("fail: shadow page %p guest entry 0x%llx type %d\n",
14068c2ecf20Sopenharmony_ci			spt, se->val64, se->type);
14078c2ecf20Sopenharmony_ci	return ret;
14088c2ecf20Sopenharmony_ci}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_cistatic int ppgtt_handle_guest_entry_add(struct intel_vgpu_ppgtt_spt *spt,
14118c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *we, unsigned long index)
14128c2ecf20Sopenharmony_ci{
14138c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
14148c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry m;
14158c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *s;
14168c2ecf20Sopenharmony_ci	int ret;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	trace_spt_guest_change(spt->vgpu->id, "add", spt, spt->shadow_page.type,
14198c2ecf20Sopenharmony_ci			       we->val64, index);
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	gvt_vdbg_mm("add shadow entry: type %d, index %lu, value %llx\n",
14228c2ecf20Sopenharmony_ci		    we->type, index, we->val64);
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	if (gtt_type_is_pt(get_next_pt_type(we->type))) {
14258c2ecf20Sopenharmony_ci		s = ppgtt_populate_spt_by_guest_entry(vgpu, we);
14268c2ecf20Sopenharmony_ci		if (IS_ERR(s)) {
14278c2ecf20Sopenharmony_ci			ret = PTR_ERR(s);
14288c2ecf20Sopenharmony_ci			goto fail;
14298c2ecf20Sopenharmony_ci		}
14308c2ecf20Sopenharmony_ci		ppgtt_get_shadow_entry(spt, &m, index);
14318c2ecf20Sopenharmony_ci		ppgtt_generate_shadow_entry(&m, s, we);
14328c2ecf20Sopenharmony_ci		ppgtt_set_shadow_entry(spt, &m, index);
14338c2ecf20Sopenharmony_ci	} else {
14348c2ecf20Sopenharmony_ci		ret = ppgtt_populate_shadow_entry(vgpu, spt, index, we);
14358c2ecf20Sopenharmony_ci		if (ret)
14368c2ecf20Sopenharmony_ci			goto fail;
14378c2ecf20Sopenharmony_ci	}
14388c2ecf20Sopenharmony_ci	return 0;
14398c2ecf20Sopenharmony_cifail:
14408c2ecf20Sopenharmony_ci	gvt_vgpu_err("fail: spt %p guest entry 0x%llx type %d\n",
14418c2ecf20Sopenharmony_ci		spt, we->val64, we->type);
14428c2ecf20Sopenharmony_ci	return ret;
14438c2ecf20Sopenharmony_ci}
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_cistatic int sync_oos_page(struct intel_vgpu *vgpu,
14468c2ecf20Sopenharmony_ci		struct intel_vgpu_oos_page *oos_page)
14478c2ecf20Sopenharmony_ci{
14488c2ecf20Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
14498c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
14508c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops;
14518c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt = oos_page->spt;
14528c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry old, new;
14538c2ecf20Sopenharmony_ci	int index;
14548c2ecf20Sopenharmony_ci	int ret;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	trace_oos_change(vgpu->id, "sync", oos_page->id,
14578c2ecf20Sopenharmony_ci			 spt, spt->guest_page.type);
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	old.type = new.type = get_entry_type(spt->guest_page.type);
14608c2ecf20Sopenharmony_ci	old.val64 = new.val64 = 0;
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	for (index = 0; index < (I915_GTT_PAGE_SIZE >>
14638c2ecf20Sopenharmony_ci				info->gtt_entry_size_shift); index++) {
14648c2ecf20Sopenharmony_ci		ops->get_entry(oos_page->mem, &old, index, false, 0, vgpu);
14658c2ecf20Sopenharmony_ci		ops->get_entry(NULL, &new, index, true,
14668c2ecf20Sopenharmony_ci			       spt->guest_page.gfn << PAGE_SHIFT, vgpu);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci		if (old.val64 == new.val64
14698c2ecf20Sopenharmony_ci			&& !test_and_clear_bit(index, spt->post_shadow_bitmap))
14708c2ecf20Sopenharmony_ci			continue;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci		trace_oos_sync(vgpu->id, oos_page->id,
14738c2ecf20Sopenharmony_ci				spt, spt->guest_page.type,
14748c2ecf20Sopenharmony_ci				new.val64, index);
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci		ret = ppgtt_populate_shadow_entry(vgpu, spt, index, &new);
14778c2ecf20Sopenharmony_ci		if (ret)
14788c2ecf20Sopenharmony_ci			return ret;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci		ops->set_entry(oos_page->mem, &new, index, false, 0, vgpu);
14818c2ecf20Sopenharmony_ci	}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	spt->guest_page.write_cnt = 0;
14848c2ecf20Sopenharmony_ci	list_del_init(&spt->post_shadow_list);
14858c2ecf20Sopenharmony_ci	return 0;
14868c2ecf20Sopenharmony_ci}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_cistatic int detach_oos_page(struct intel_vgpu *vgpu,
14898c2ecf20Sopenharmony_ci		struct intel_vgpu_oos_page *oos_page)
14908c2ecf20Sopenharmony_ci{
14918c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
14928c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt = oos_page->spt;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	trace_oos_change(vgpu->id, "detach", oos_page->id,
14958c2ecf20Sopenharmony_ci			 spt, spt->guest_page.type);
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	spt->guest_page.write_cnt = 0;
14988c2ecf20Sopenharmony_ci	spt->guest_page.oos_page = NULL;
14998c2ecf20Sopenharmony_ci	oos_page->spt = NULL;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	list_del_init(&oos_page->vm_list);
15028c2ecf20Sopenharmony_ci	list_move_tail(&oos_page->list, &gvt->gtt.oos_page_free_list_head);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	return 0;
15058c2ecf20Sopenharmony_ci}
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_cistatic int attach_oos_page(struct intel_vgpu_oos_page *oos_page,
15088c2ecf20Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt)
15098c2ecf20Sopenharmony_ci{
15108c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = spt->vgpu->gvt;
15118c2ecf20Sopenharmony_ci	int ret;
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	ret = intel_gvt_hypervisor_read_gpa(spt->vgpu,
15148c2ecf20Sopenharmony_ci			spt->guest_page.gfn << I915_GTT_PAGE_SHIFT,
15158c2ecf20Sopenharmony_ci			oos_page->mem, I915_GTT_PAGE_SIZE);
15168c2ecf20Sopenharmony_ci	if (ret)
15178c2ecf20Sopenharmony_ci		return ret;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	oos_page->spt = spt;
15208c2ecf20Sopenharmony_ci	spt->guest_page.oos_page = oos_page;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	list_move_tail(&oos_page->list, &gvt->gtt.oos_page_use_list_head);
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	trace_oos_change(spt->vgpu->id, "attach", oos_page->id,
15258c2ecf20Sopenharmony_ci			 spt, spt->guest_page.type);
15268c2ecf20Sopenharmony_ci	return 0;
15278c2ecf20Sopenharmony_ci}
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_cistatic int ppgtt_set_guest_page_sync(struct intel_vgpu_ppgtt_spt *spt)
15308c2ecf20Sopenharmony_ci{
15318c2ecf20Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page = spt->guest_page.oos_page;
15328c2ecf20Sopenharmony_ci	int ret;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	ret = intel_vgpu_enable_page_track(spt->vgpu, spt->guest_page.gfn);
15358c2ecf20Sopenharmony_ci	if (ret)
15368c2ecf20Sopenharmony_ci		return ret;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	trace_oos_change(spt->vgpu->id, "set page sync", oos_page->id,
15398c2ecf20Sopenharmony_ci			 spt, spt->guest_page.type);
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	list_del_init(&oos_page->vm_list);
15428c2ecf20Sopenharmony_ci	return sync_oos_page(spt->vgpu, oos_page);
15438c2ecf20Sopenharmony_ci}
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_cistatic int ppgtt_allocate_oos_page(struct intel_vgpu_ppgtt_spt *spt)
15468c2ecf20Sopenharmony_ci{
15478c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = spt->vgpu->gvt;
15488c2ecf20Sopenharmony_ci	struct intel_gvt_gtt *gtt = &gvt->gtt;
15498c2ecf20Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page = spt->guest_page.oos_page;
15508c2ecf20Sopenharmony_ci	int ret;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	WARN(oos_page, "shadow PPGTT page has already has a oos page\n");
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	if (list_empty(&gtt->oos_page_free_list_head)) {
15558c2ecf20Sopenharmony_ci		oos_page = container_of(gtt->oos_page_use_list_head.next,
15568c2ecf20Sopenharmony_ci			struct intel_vgpu_oos_page, list);
15578c2ecf20Sopenharmony_ci		ret = ppgtt_set_guest_page_sync(oos_page->spt);
15588c2ecf20Sopenharmony_ci		if (ret)
15598c2ecf20Sopenharmony_ci			return ret;
15608c2ecf20Sopenharmony_ci		ret = detach_oos_page(spt->vgpu, oos_page);
15618c2ecf20Sopenharmony_ci		if (ret)
15628c2ecf20Sopenharmony_ci			return ret;
15638c2ecf20Sopenharmony_ci	} else
15648c2ecf20Sopenharmony_ci		oos_page = container_of(gtt->oos_page_free_list_head.next,
15658c2ecf20Sopenharmony_ci			struct intel_vgpu_oos_page, list);
15668c2ecf20Sopenharmony_ci	return attach_oos_page(oos_page, spt);
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_cistatic int ppgtt_set_guest_page_oos(struct intel_vgpu_ppgtt_spt *spt)
15708c2ecf20Sopenharmony_ci{
15718c2ecf20Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page = spt->guest_page.oos_page;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	if (WARN(!oos_page, "shadow PPGTT page should have a oos page\n"))
15748c2ecf20Sopenharmony_ci		return -EINVAL;
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	trace_oos_change(spt->vgpu->id, "set page out of sync", oos_page->id,
15778c2ecf20Sopenharmony_ci			 spt, spt->guest_page.type);
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	list_add_tail(&oos_page->vm_list, &spt->vgpu->gtt.oos_page_list_head);
15808c2ecf20Sopenharmony_ci	return intel_vgpu_disable_page_track(spt->vgpu, spt->guest_page.gfn);
15818c2ecf20Sopenharmony_ci}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci/**
15848c2ecf20Sopenharmony_ci * intel_vgpu_sync_oos_pages - sync all the out-of-synced shadow for vGPU
15858c2ecf20Sopenharmony_ci * @vgpu: a vGPU
15868c2ecf20Sopenharmony_ci *
15878c2ecf20Sopenharmony_ci * This function is called before submitting a guest workload to host,
15888c2ecf20Sopenharmony_ci * to sync all the out-of-synced shadow for vGPU
15898c2ecf20Sopenharmony_ci *
15908c2ecf20Sopenharmony_ci * Returns:
15918c2ecf20Sopenharmony_ci * Zero on success, negative error code if failed.
15928c2ecf20Sopenharmony_ci */
15938c2ecf20Sopenharmony_ciint intel_vgpu_sync_oos_pages(struct intel_vgpu *vgpu)
15948c2ecf20Sopenharmony_ci{
15958c2ecf20Sopenharmony_ci	struct list_head *pos, *n;
15968c2ecf20Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page;
15978c2ecf20Sopenharmony_ci	int ret;
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	if (!enable_out_of_sync)
16008c2ecf20Sopenharmony_ci		return 0;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	list_for_each_safe(pos, n, &vgpu->gtt.oos_page_list_head) {
16038c2ecf20Sopenharmony_ci		oos_page = container_of(pos,
16048c2ecf20Sopenharmony_ci				struct intel_vgpu_oos_page, vm_list);
16058c2ecf20Sopenharmony_ci		ret = ppgtt_set_guest_page_sync(oos_page->spt);
16068c2ecf20Sopenharmony_ci		if (ret)
16078c2ecf20Sopenharmony_ci			return ret;
16088c2ecf20Sopenharmony_ci	}
16098c2ecf20Sopenharmony_ci	return 0;
16108c2ecf20Sopenharmony_ci}
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci/*
16138c2ecf20Sopenharmony_ci * The heart of PPGTT shadow page table.
16148c2ecf20Sopenharmony_ci */
16158c2ecf20Sopenharmony_cistatic int ppgtt_handle_guest_write_page_table(
16168c2ecf20Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt,
16178c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *we, unsigned long index)
16188c2ecf20Sopenharmony_ci{
16198c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
16208c2ecf20Sopenharmony_ci	int type = spt->shadow_page.type;
16218c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
16228c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry old_se;
16238c2ecf20Sopenharmony_ci	int new_present;
16248c2ecf20Sopenharmony_ci	int i, ret;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	new_present = ops->test_present(we);
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	/*
16298c2ecf20Sopenharmony_ci	 * Adding the new entry first and then removing the old one, that can
16308c2ecf20Sopenharmony_ci	 * guarantee the ppgtt table is validated during the window between
16318c2ecf20Sopenharmony_ci	 * adding and removal.
16328c2ecf20Sopenharmony_ci	 */
16338c2ecf20Sopenharmony_ci	ppgtt_get_shadow_entry(spt, &old_se, index);
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	if (new_present) {
16368c2ecf20Sopenharmony_ci		ret = ppgtt_handle_guest_entry_add(spt, we, index);
16378c2ecf20Sopenharmony_ci		if (ret)
16388c2ecf20Sopenharmony_ci			goto fail;
16398c2ecf20Sopenharmony_ci	}
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	ret = ppgtt_handle_guest_entry_removal(spt, &old_se, index);
16428c2ecf20Sopenharmony_ci	if (ret)
16438c2ecf20Sopenharmony_ci		goto fail;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	if (!new_present) {
16468c2ecf20Sopenharmony_ci		/* For 64KB splited entries, we need clear them all. */
16478c2ecf20Sopenharmony_ci		if (ops->test_64k_splited(&old_se) &&
16488c2ecf20Sopenharmony_ci		    !(index % GTT_64K_PTE_STRIDE)) {
16498c2ecf20Sopenharmony_ci			gvt_vdbg_mm("remove splited 64K shadow entries\n");
16508c2ecf20Sopenharmony_ci			for (i = 0; i < GTT_64K_PTE_STRIDE; i++) {
16518c2ecf20Sopenharmony_ci				ops->clear_64k_splited(&old_se);
16528c2ecf20Sopenharmony_ci				ops->set_pfn(&old_se,
16538c2ecf20Sopenharmony_ci					vgpu->gtt.scratch_pt[type].page_mfn);
16548c2ecf20Sopenharmony_ci				ppgtt_set_shadow_entry(spt, &old_se, index + i);
16558c2ecf20Sopenharmony_ci			}
16568c2ecf20Sopenharmony_ci		} else if (old_se.type == GTT_TYPE_PPGTT_PTE_2M_ENTRY ||
16578c2ecf20Sopenharmony_ci			   old_se.type == GTT_TYPE_PPGTT_PTE_1G_ENTRY) {
16588c2ecf20Sopenharmony_ci			ops->clear_pse(&old_se);
16598c2ecf20Sopenharmony_ci			ops->set_pfn(&old_se,
16608c2ecf20Sopenharmony_ci				     vgpu->gtt.scratch_pt[type].page_mfn);
16618c2ecf20Sopenharmony_ci			ppgtt_set_shadow_entry(spt, &old_se, index);
16628c2ecf20Sopenharmony_ci		} else {
16638c2ecf20Sopenharmony_ci			ops->set_pfn(&old_se,
16648c2ecf20Sopenharmony_ci				     vgpu->gtt.scratch_pt[type].page_mfn);
16658c2ecf20Sopenharmony_ci			ppgtt_set_shadow_entry(spt, &old_se, index);
16668c2ecf20Sopenharmony_ci		}
16678c2ecf20Sopenharmony_ci	}
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	return 0;
16708c2ecf20Sopenharmony_cifail:
16718c2ecf20Sopenharmony_ci	gvt_vgpu_err("fail: shadow page %p guest entry 0x%llx type %d.\n",
16728c2ecf20Sopenharmony_ci			spt, we->val64, we->type);
16738c2ecf20Sopenharmony_ci	return ret;
16748c2ecf20Sopenharmony_ci}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_cistatic inline bool can_do_out_of_sync(struct intel_vgpu_ppgtt_spt *spt)
16798c2ecf20Sopenharmony_ci{
16808c2ecf20Sopenharmony_ci	return enable_out_of_sync
16818c2ecf20Sopenharmony_ci		&& gtt_type_is_pte_pt(spt->guest_page.type)
16828c2ecf20Sopenharmony_ci		&& spt->guest_page.write_cnt >= 2;
16838c2ecf20Sopenharmony_ci}
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_cistatic void ppgtt_set_post_shadow(struct intel_vgpu_ppgtt_spt *spt,
16868c2ecf20Sopenharmony_ci		unsigned long index)
16878c2ecf20Sopenharmony_ci{
16888c2ecf20Sopenharmony_ci	set_bit(index, spt->post_shadow_bitmap);
16898c2ecf20Sopenharmony_ci	if (!list_empty(&spt->post_shadow_list))
16908c2ecf20Sopenharmony_ci		return;
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	list_add_tail(&spt->post_shadow_list,
16938c2ecf20Sopenharmony_ci			&spt->vgpu->gtt.post_shadow_list_head);
16948c2ecf20Sopenharmony_ci}
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci/**
16978c2ecf20Sopenharmony_ci * intel_vgpu_flush_post_shadow - flush the post shadow transactions
16988c2ecf20Sopenharmony_ci * @vgpu: a vGPU
16998c2ecf20Sopenharmony_ci *
17008c2ecf20Sopenharmony_ci * This function is called before submitting a guest workload to host,
17018c2ecf20Sopenharmony_ci * to flush all the post shadows for a vGPU.
17028c2ecf20Sopenharmony_ci *
17038c2ecf20Sopenharmony_ci * Returns:
17048c2ecf20Sopenharmony_ci * Zero on success, negative error code if failed.
17058c2ecf20Sopenharmony_ci */
17068c2ecf20Sopenharmony_ciint intel_vgpu_flush_post_shadow(struct intel_vgpu *vgpu)
17078c2ecf20Sopenharmony_ci{
17088c2ecf20Sopenharmony_ci	struct list_head *pos, *n;
17098c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt;
17108c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry ge;
17118c2ecf20Sopenharmony_ci	unsigned long index;
17128c2ecf20Sopenharmony_ci	int ret;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	list_for_each_safe(pos, n, &vgpu->gtt.post_shadow_list_head) {
17158c2ecf20Sopenharmony_ci		spt = container_of(pos, struct intel_vgpu_ppgtt_spt,
17168c2ecf20Sopenharmony_ci				post_shadow_list);
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci		for_each_set_bit(index, spt->post_shadow_bitmap,
17198c2ecf20Sopenharmony_ci				GTT_ENTRY_NUM_IN_ONE_PAGE) {
17208c2ecf20Sopenharmony_ci			ppgtt_get_guest_entry(spt, &ge, index);
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci			ret = ppgtt_handle_guest_write_page_table(spt,
17238c2ecf20Sopenharmony_ci							&ge, index);
17248c2ecf20Sopenharmony_ci			if (ret)
17258c2ecf20Sopenharmony_ci				return ret;
17268c2ecf20Sopenharmony_ci			clear_bit(index, spt->post_shadow_bitmap);
17278c2ecf20Sopenharmony_ci		}
17288c2ecf20Sopenharmony_ci		list_del_init(&spt->post_shadow_list);
17298c2ecf20Sopenharmony_ci	}
17308c2ecf20Sopenharmony_ci	return 0;
17318c2ecf20Sopenharmony_ci}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_cistatic int ppgtt_handle_guest_write_page_table_bytes(
17348c2ecf20Sopenharmony_ci		struct intel_vgpu_ppgtt_spt *spt,
17358c2ecf20Sopenharmony_ci		u64 pa, void *p_data, int bytes)
17368c2ecf20Sopenharmony_ci{
17378c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = spt->vgpu;
17388c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
17398c2ecf20Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
17408c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry we, se;
17418c2ecf20Sopenharmony_ci	unsigned long index;
17428c2ecf20Sopenharmony_ci	int ret;
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	index = (pa & (PAGE_SIZE - 1)) >> info->gtt_entry_size_shift;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	ppgtt_get_guest_entry(spt, &we, index);
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	/*
17498c2ecf20Sopenharmony_ci	 * For page table which has 64K gtt entry, only PTE#0, PTE#16,
17508c2ecf20Sopenharmony_ci	 * PTE#32, ... PTE#496 are used. Unused PTEs update should be
17518c2ecf20Sopenharmony_ci	 * ignored.
17528c2ecf20Sopenharmony_ci	 */
17538c2ecf20Sopenharmony_ci	if (we.type == GTT_TYPE_PPGTT_PTE_64K_ENTRY &&
17548c2ecf20Sopenharmony_ci	    (index % GTT_64K_PTE_STRIDE)) {
17558c2ecf20Sopenharmony_ci		gvt_vdbg_mm("Ignore write to unused PTE entry, index %lu\n",
17568c2ecf20Sopenharmony_ci			    index);
17578c2ecf20Sopenharmony_ci		return 0;
17588c2ecf20Sopenharmony_ci	}
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	if (bytes == info->gtt_entry_size) {
17618c2ecf20Sopenharmony_ci		ret = ppgtt_handle_guest_write_page_table(spt, &we, index);
17628c2ecf20Sopenharmony_ci		if (ret)
17638c2ecf20Sopenharmony_ci			return ret;
17648c2ecf20Sopenharmony_ci	} else {
17658c2ecf20Sopenharmony_ci		if (!test_bit(index, spt->post_shadow_bitmap)) {
17668c2ecf20Sopenharmony_ci			int type = spt->shadow_page.type;
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci			ppgtt_get_shadow_entry(spt, &se, index);
17698c2ecf20Sopenharmony_ci			ret = ppgtt_handle_guest_entry_removal(spt, &se, index);
17708c2ecf20Sopenharmony_ci			if (ret)
17718c2ecf20Sopenharmony_ci				return ret;
17728c2ecf20Sopenharmony_ci			ops->set_pfn(&se, vgpu->gtt.scratch_pt[type].page_mfn);
17738c2ecf20Sopenharmony_ci			ppgtt_set_shadow_entry(spt, &se, index);
17748c2ecf20Sopenharmony_ci		}
17758c2ecf20Sopenharmony_ci		ppgtt_set_post_shadow(spt, index);
17768c2ecf20Sopenharmony_ci	}
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	if (!enable_out_of_sync)
17798c2ecf20Sopenharmony_ci		return 0;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	spt->guest_page.write_cnt++;
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	if (spt->guest_page.oos_page)
17848c2ecf20Sopenharmony_ci		ops->set_entry(spt->guest_page.oos_page->mem, &we, index,
17858c2ecf20Sopenharmony_ci				false, 0, vgpu);
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	if (can_do_out_of_sync(spt)) {
17888c2ecf20Sopenharmony_ci		if (!spt->guest_page.oos_page)
17898c2ecf20Sopenharmony_ci			ppgtt_allocate_oos_page(spt);
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci		ret = ppgtt_set_guest_page_oos(spt);
17928c2ecf20Sopenharmony_ci		if (ret < 0)
17938c2ecf20Sopenharmony_ci			return ret;
17948c2ecf20Sopenharmony_ci	}
17958c2ecf20Sopenharmony_ci	return 0;
17968c2ecf20Sopenharmony_ci}
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_cistatic void invalidate_ppgtt_mm(struct intel_vgpu_mm *mm)
17998c2ecf20Sopenharmony_ci{
18008c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = mm->vgpu;
18018c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
18028c2ecf20Sopenharmony_ci	struct intel_gvt_gtt *gtt = &gvt->gtt;
18038c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = gtt->pte_ops;
18048c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry se;
18058c2ecf20Sopenharmony_ci	int index;
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	if (!mm->ppgtt_mm.shadowed)
18088c2ecf20Sopenharmony_ci		return;
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	for (index = 0; index < ARRAY_SIZE(mm->ppgtt_mm.shadow_pdps); index++) {
18118c2ecf20Sopenharmony_ci		ppgtt_get_shadow_root_entry(mm, &se, index);
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci		if (!ops->test_present(&se))
18148c2ecf20Sopenharmony_ci			continue;
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci		ppgtt_invalidate_spt_by_shadow_entry(vgpu, &se);
18178c2ecf20Sopenharmony_ci		se.val64 = 0;
18188c2ecf20Sopenharmony_ci		ppgtt_set_shadow_root_entry(mm, &se, index);
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci		trace_spt_guest_change(vgpu->id, "destroy root pointer",
18218c2ecf20Sopenharmony_ci				       NULL, se.type, se.val64, index);
18228c2ecf20Sopenharmony_ci	}
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	mm->ppgtt_mm.shadowed = false;
18258c2ecf20Sopenharmony_ci}
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_cistatic int shadow_ppgtt_mm(struct intel_vgpu_mm *mm)
18298c2ecf20Sopenharmony_ci{
18308c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = mm->vgpu;
18318c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
18328c2ecf20Sopenharmony_ci	struct intel_gvt_gtt *gtt = &gvt->gtt;
18338c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = gtt->pte_ops;
18348c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *spt;
18358c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry ge, se;
18368c2ecf20Sopenharmony_ci	int index, ret;
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	if (mm->ppgtt_mm.shadowed)
18398c2ecf20Sopenharmony_ci		return 0;
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	mm->ppgtt_mm.shadowed = true;
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	for (index = 0; index < ARRAY_SIZE(mm->ppgtt_mm.guest_pdps); index++) {
18448c2ecf20Sopenharmony_ci		ppgtt_get_guest_root_entry(mm, &ge, index);
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci		if (!ops->test_present(&ge))
18478c2ecf20Sopenharmony_ci			continue;
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci		trace_spt_guest_change(vgpu->id, __func__, NULL,
18508c2ecf20Sopenharmony_ci				       ge.type, ge.val64, index);
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci		spt = ppgtt_populate_spt_by_guest_entry(vgpu, &ge);
18538c2ecf20Sopenharmony_ci		if (IS_ERR(spt)) {
18548c2ecf20Sopenharmony_ci			gvt_vgpu_err("fail to populate guest root pointer\n");
18558c2ecf20Sopenharmony_ci			ret = PTR_ERR(spt);
18568c2ecf20Sopenharmony_ci			goto fail;
18578c2ecf20Sopenharmony_ci		}
18588c2ecf20Sopenharmony_ci		ppgtt_generate_shadow_entry(&se, spt, &ge);
18598c2ecf20Sopenharmony_ci		ppgtt_set_shadow_root_entry(mm, &se, index);
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci		trace_spt_guest_change(vgpu->id, "populate root pointer",
18628c2ecf20Sopenharmony_ci				       NULL, se.type, se.val64, index);
18638c2ecf20Sopenharmony_ci	}
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	return 0;
18668c2ecf20Sopenharmony_cifail:
18678c2ecf20Sopenharmony_ci	invalidate_ppgtt_mm(mm);
18688c2ecf20Sopenharmony_ci	return ret;
18698c2ecf20Sopenharmony_ci}
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_cistatic struct intel_vgpu_mm *vgpu_alloc_mm(struct intel_vgpu *vgpu)
18728c2ecf20Sopenharmony_ci{
18738c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm;
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	mm = kzalloc(sizeof(*mm), GFP_KERNEL);
18768c2ecf20Sopenharmony_ci	if (!mm)
18778c2ecf20Sopenharmony_ci		return NULL;
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	mm->vgpu = vgpu;
18808c2ecf20Sopenharmony_ci	kref_init(&mm->ref);
18818c2ecf20Sopenharmony_ci	atomic_set(&mm->pincount, 0);
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	return mm;
18848c2ecf20Sopenharmony_ci}
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_cistatic void vgpu_free_mm(struct intel_vgpu_mm *mm)
18878c2ecf20Sopenharmony_ci{
18888c2ecf20Sopenharmony_ci	kfree(mm);
18898c2ecf20Sopenharmony_ci}
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci/**
18928c2ecf20Sopenharmony_ci * intel_vgpu_create_ppgtt_mm - create a ppgtt mm object for a vGPU
18938c2ecf20Sopenharmony_ci * @vgpu: a vGPU
18948c2ecf20Sopenharmony_ci * @root_entry_type: ppgtt root entry type
18958c2ecf20Sopenharmony_ci * @pdps: guest pdps.
18968c2ecf20Sopenharmony_ci *
18978c2ecf20Sopenharmony_ci * This function is used to create a ppgtt mm object for a vGPU.
18988c2ecf20Sopenharmony_ci *
18998c2ecf20Sopenharmony_ci * Returns:
19008c2ecf20Sopenharmony_ci * Zero on success, negative error code in pointer if failed.
19018c2ecf20Sopenharmony_ci */
19028c2ecf20Sopenharmony_cistruct intel_vgpu_mm *intel_vgpu_create_ppgtt_mm(struct intel_vgpu *vgpu,
19038c2ecf20Sopenharmony_ci		enum intel_gvt_gtt_type root_entry_type, u64 pdps[])
19048c2ecf20Sopenharmony_ci{
19058c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
19068c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm;
19078c2ecf20Sopenharmony_ci	int ret;
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	mm = vgpu_alloc_mm(vgpu);
19108c2ecf20Sopenharmony_ci	if (!mm)
19118c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci	mm->type = INTEL_GVT_MM_PPGTT;
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	GEM_BUG_ON(root_entry_type != GTT_TYPE_PPGTT_ROOT_L3_ENTRY &&
19168c2ecf20Sopenharmony_ci		   root_entry_type != GTT_TYPE_PPGTT_ROOT_L4_ENTRY);
19178c2ecf20Sopenharmony_ci	mm->ppgtt_mm.root_entry_type = root_entry_type;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mm->ppgtt_mm.list);
19208c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mm->ppgtt_mm.lru_list);
19218c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mm->ppgtt_mm.link);
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	if (root_entry_type == GTT_TYPE_PPGTT_ROOT_L4_ENTRY)
19248c2ecf20Sopenharmony_ci		mm->ppgtt_mm.guest_pdps[0] = pdps[0];
19258c2ecf20Sopenharmony_ci	else
19268c2ecf20Sopenharmony_ci		memcpy(mm->ppgtt_mm.guest_pdps, pdps,
19278c2ecf20Sopenharmony_ci		       sizeof(mm->ppgtt_mm.guest_pdps));
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	ret = shadow_ppgtt_mm(mm);
19308c2ecf20Sopenharmony_ci	if (ret) {
19318c2ecf20Sopenharmony_ci		gvt_vgpu_err("failed to shadow ppgtt mm\n");
19328c2ecf20Sopenharmony_ci		vgpu_free_mm(mm);
19338c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
19348c2ecf20Sopenharmony_ci	}
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	list_add_tail(&mm->ppgtt_mm.list, &vgpu->gtt.ppgtt_mm_list_head);
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	mutex_lock(&gvt->gtt.ppgtt_mm_lock);
19398c2ecf20Sopenharmony_ci	list_add_tail(&mm->ppgtt_mm.lru_list, &gvt->gtt.ppgtt_mm_lru_list_head);
19408c2ecf20Sopenharmony_ci	mutex_unlock(&gvt->gtt.ppgtt_mm_lock);
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci	return mm;
19438c2ecf20Sopenharmony_ci}
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_cistatic struct intel_vgpu_mm *intel_vgpu_create_ggtt_mm(struct intel_vgpu *vgpu)
19468c2ecf20Sopenharmony_ci{
19478c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm;
19488c2ecf20Sopenharmony_ci	unsigned long nr_entries;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	mm = vgpu_alloc_mm(vgpu);
19518c2ecf20Sopenharmony_ci	if (!mm)
19528c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	mm->type = INTEL_GVT_MM_GGTT;
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	nr_entries = gvt_ggtt_gm_sz(vgpu->gvt) >> I915_GTT_PAGE_SHIFT;
19578c2ecf20Sopenharmony_ci	mm->ggtt_mm.virtual_ggtt =
19588c2ecf20Sopenharmony_ci		vzalloc(array_size(nr_entries,
19598c2ecf20Sopenharmony_ci				   vgpu->gvt->device_info.gtt_entry_size));
19608c2ecf20Sopenharmony_ci	if (!mm->ggtt_mm.virtual_ggtt) {
19618c2ecf20Sopenharmony_ci		vgpu_free_mm(mm);
19628c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
19638c2ecf20Sopenharmony_ci	}
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	mm->ggtt_mm.host_ggtt_aperture = vzalloc((vgpu_aperture_sz(vgpu) >> PAGE_SHIFT) * sizeof(u64));
19668c2ecf20Sopenharmony_ci	if (!mm->ggtt_mm.host_ggtt_aperture) {
19678c2ecf20Sopenharmony_ci		vfree(mm->ggtt_mm.virtual_ggtt);
19688c2ecf20Sopenharmony_ci		vgpu_free_mm(mm);
19698c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
19708c2ecf20Sopenharmony_ci	}
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	mm->ggtt_mm.host_ggtt_hidden = vzalloc((vgpu_hidden_sz(vgpu) >> PAGE_SHIFT) * sizeof(u64));
19738c2ecf20Sopenharmony_ci	if (!mm->ggtt_mm.host_ggtt_hidden) {
19748c2ecf20Sopenharmony_ci		vfree(mm->ggtt_mm.host_ggtt_aperture);
19758c2ecf20Sopenharmony_ci		vfree(mm->ggtt_mm.virtual_ggtt);
19768c2ecf20Sopenharmony_ci		vgpu_free_mm(mm);
19778c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
19788c2ecf20Sopenharmony_ci	}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	return mm;
19818c2ecf20Sopenharmony_ci}
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci/**
19848c2ecf20Sopenharmony_ci * _intel_vgpu_mm_release - destroy a mm object
19858c2ecf20Sopenharmony_ci * @mm_ref: a kref object
19868c2ecf20Sopenharmony_ci *
19878c2ecf20Sopenharmony_ci * This function is used to destroy a mm object for vGPU
19888c2ecf20Sopenharmony_ci *
19898c2ecf20Sopenharmony_ci */
19908c2ecf20Sopenharmony_civoid _intel_vgpu_mm_release(struct kref *mm_ref)
19918c2ecf20Sopenharmony_ci{
19928c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm = container_of(mm_ref, typeof(*mm), ref);
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	if (GEM_WARN_ON(atomic_read(&mm->pincount)))
19958c2ecf20Sopenharmony_ci		gvt_err("vgpu mm pin count bug detected\n");
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci	if (mm->type == INTEL_GVT_MM_PPGTT) {
19988c2ecf20Sopenharmony_ci		list_del(&mm->ppgtt_mm.list);
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci		mutex_lock(&mm->vgpu->gvt->gtt.ppgtt_mm_lock);
20018c2ecf20Sopenharmony_ci		list_del(&mm->ppgtt_mm.lru_list);
20028c2ecf20Sopenharmony_ci		mutex_unlock(&mm->vgpu->gvt->gtt.ppgtt_mm_lock);
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci		invalidate_ppgtt_mm(mm);
20058c2ecf20Sopenharmony_ci	} else {
20068c2ecf20Sopenharmony_ci		vfree(mm->ggtt_mm.virtual_ggtt);
20078c2ecf20Sopenharmony_ci		vfree(mm->ggtt_mm.host_ggtt_aperture);
20088c2ecf20Sopenharmony_ci		vfree(mm->ggtt_mm.host_ggtt_hidden);
20098c2ecf20Sopenharmony_ci	}
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	vgpu_free_mm(mm);
20128c2ecf20Sopenharmony_ci}
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci/**
20158c2ecf20Sopenharmony_ci * intel_vgpu_unpin_mm - decrease the pin count of a vGPU mm object
20168c2ecf20Sopenharmony_ci * @mm: a vGPU mm object
20178c2ecf20Sopenharmony_ci *
20188c2ecf20Sopenharmony_ci * This function is called when user doesn't want to use a vGPU mm object
20198c2ecf20Sopenharmony_ci */
20208c2ecf20Sopenharmony_civoid intel_vgpu_unpin_mm(struct intel_vgpu_mm *mm)
20218c2ecf20Sopenharmony_ci{
20228c2ecf20Sopenharmony_ci	atomic_dec_if_positive(&mm->pincount);
20238c2ecf20Sopenharmony_ci}
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci/**
20268c2ecf20Sopenharmony_ci * intel_vgpu_pin_mm - increase the pin count of a vGPU mm object
20278c2ecf20Sopenharmony_ci * @mm: target vgpu mm
20288c2ecf20Sopenharmony_ci *
20298c2ecf20Sopenharmony_ci * This function is called when user wants to use a vGPU mm object. If this
20308c2ecf20Sopenharmony_ci * mm object hasn't been shadowed yet, the shadow will be populated at this
20318c2ecf20Sopenharmony_ci * time.
20328c2ecf20Sopenharmony_ci *
20338c2ecf20Sopenharmony_ci * Returns:
20348c2ecf20Sopenharmony_ci * Zero on success, negative error code if failed.
20358c2ecf20Sopenharmony_ci */
20368c2ecf20Sopenharmony_ciint intel_vgpu_pin_mm(struct intel_vgpu_mm *mm)
20378c2ecf20Sopenharmony_ci{
20388c2ecf20Sopenharmony_ci	int ret;
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	atomic_inc(&mm->pincount);
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	if (mm->type == INTEL_GVT_MM_PPGTT) {
20438c2ecf20Sopenharmony_ci		ret = shadow_ppgtt_mm(mm);
20448c2ecf20Sopenharmony_ci		if (ret)
20458c2ecf20Sopenharmony_ci			return ret;
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci		mutex_lock(&mm->vgpu->gvt->gtt.ppgtt_mm_lock);
20488c2ecf20Sopenharmony_ci		list_move_tail(&mm->ppgtt_mm.lru_list,
20498c2ecf20Sopenharmony_ci			       &mm->vgpu->gvt->gtt.ppgtt_mm_lru_list_head);
20508c2ecf20Sopenharmony_ci		mutex_unlock(&mm->vgpu->gvt->gtt.ppgtt_mm_lock);
20518c2ecf20Sopenharmony_ci	}
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	return 0;
20548c2ecf20Sopenharmony_ci}
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_cistatic int reclaim_one_ppgtt_mm(struct intel_gvt *gvt)
20578c2ecf20Sopenharmony_ci{
20588c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm;
20598c2ecf20Sopenharmony_ci	struct list_head *pos, *n;
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	mutex_lock(&gvt->gtt.ppgtt_mm_lock);
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	list_for_each_safe(pos, n, &gvt->gtt.ppgtt_mm_lru_list_head) {
20648c2ecf20Sopenharmony_ci		mm = container_of(pos, struct intel_vgpu_mm, ppgtt_mm.lru_list);
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci		if (atomic_read(&mm->pincount))
20678c2ecf20Sopenharmony_ci			continue;
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ci		list_del_init(&mm->ppgtt_mm.lru_list);
20708c2ecf20Sopenharmony_ci		mutex_unlock(&gvt->gtt.ppgtt_mm_lock);
20718c2ecf20Sopenharmony_ci		invalidate_ppgtt_mm(mm);
20728c2ecf20Sopenharmony_ci		return 1;
20738c2ecf20Sopenharmony_ci	}
20748c2ecf20Sopenharmony_ci	mutex_unlock(&gvt->gtt.ppgtt_mm_lock);
20758c2ecf20Sopenharmony_ci	return 0;
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci/*
20798c2ecf20Sopenharmony_ci * GMA translation APIs.
20808c2ecf20Sopenharmony_ci */
20818c2ecf20Sopenharmony_cistatic inline int ppgtt_get_next_level_entry(struct intel_vgpu_mm *mm,
20828c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *e, unsigned long index, bool guest)
20838c2ecf20Sopenharmony_ci{
20848c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = mm->vgpu;
20858c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
20868c2ecf20Sopenharmony_ci	struct intel_vgpu_ppgtt_spt *s;
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	s = intel_vgpu_find_spt_by_mfn(vgpu, ops->get_pfn(e));
20898c2ecf20Sopenharmony_ci	if (!s)
20908c2ecf20Sopenharmony_ci		return -ENXIO;
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci	if (!guest)
20938c2ecf20Sopenharmony_ci		ppgtt_get_shadow_entry(s, e, index);
20948c2ecf20Sopenharmony_ci	else
20958c2ecf20Sopenharmony_ci		ppgtt_get_guest_entry(s, e, index);
20968c2ecf20Sopenharmony_ci	return 0;
20978c2ecf20Sopenharmony_ci}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci/**
21008c2ecf20Sopenharmony_ci * intel_vgpu_gma_to_gpa - translate a gma to GPA
21018c2ecf20Sopenharmony_ci * @mm: mm object. could be a PPGTT or GGTT mm object
21028c2ecf20Sopenharmony_ci * @gma: graphics memory address in this mm object
21038c2ecf20Sopenharmony_ci *
21048c2ecf20Sopenharmony_ci * This function is used to translate a graphics memory address in specific
21058c2ecf20Sopenharmony_ci * graphics memory space to guest physical address.
21068c2ecf20Sopenharmony_ci *
21078c2ecf20Sopenharmony_ci * Returns:
21088c2ecf20Sopenharmony_ci * Guest physical address on success, INTEL_GVT_INVALID_ADDR if failed.
21098c2ecf20Sopenharmony_ci */
21108c2ecf20Sopenharmony_ciunsigned long intel_vgpu_gma_to_gpa(struct intel_vgpu_mm *mm, unsigned long gma)
21118c2ecf20Sopenharmony_ci{
21128c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu = mm->vgpu;
21138c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
21148c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *pte_ops = gvt->gtt.pte_ops;
21158c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_gma_ops *gma_ops = gvt->gtt.gma_ops;
21168c2ecf20Sopenharmony_ci	unsigned long gpa = INTEL_GVT_INVALID_ADDR;
21178c2ecf20Sopenharmony_ci	unsigned long gma_index[4];
21188c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry e;
21198c2ecf20Sopenharmony_ci	int i, levels = 0;
21208c2ecf20Sopenharmony_ci	int ret;
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	GEM_BUG_ON(mm->type != INTEL_GVT_MM_GGTT &&
21238c2ecf20Sopenharmony_ci		   mm->type != INTEL_GVT_MM_PPGTT);
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	if (mm->type == INTEL_GVT_MM_GGTT) {
21268c2ecf20Sopenharmony_ci		if (!vgpu_gmadr_is_valid(vgpu, gma))
21278c2ecf20Sopenharmony_ci			goto err;
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci		ggtt_get_guest_entry(mm, &e,
21308c2ecf20Sopenharmony_ci			gma_ops->gma_to_ggtt_pte_index(gma));
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci		gpa = (pte_ops->get_pfn(&e) << I915_GTT_PAGE_SHIFT)
21338c2ecf20Sopenharmony_ci			+ (gma & ~I915_GTT_PAGE_MASK);
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci		trace_gma_translate(vgpu->id, "ggtt", 0, 0, gma, gpa);
21368c2ecf20Sopenharmony_ci	} else {
21378c2ecf20Sopenharmony_ci		switch (mm->ppgtt_mm.root_entry_type) {
21388c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_ROOT_L4_ENTRY:
21398c2ecf20Sopenharmony_ci			ppgtt_get_shadow_root_entry(mm, &e, 0);
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci			gma_index[0] = gma_ops->gma_to_pml4_index(gma);
21428c2ecf20Sopenharmony_ci			gma_index[1] = gma_ops->gma_to_l4_pdp_index(gma);
21438c2ecf20Sopenharmony_ci			gma_index[2] = gma_ops->gma_to_pde_index(gma);
21448c2ecf20Sopenharmony_ci			gma_index[3] = gma_ops->gma_to_pte_index(gma);
21458c2ecf20Sopenharmony_ci			levels = 4;
21468c2ecf20Sopenharmony_ci			break;
21478c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_ROOT_L3_ENTRY:
21488c2ecf20Sopenharmony_ci			ppgtt_get_shadow_root_entry(mm, &e,
21498c2ecf20Sopenharmony_ci					gma_ops->gma_to_l3_pdp_index(gma));
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci			gma_index[0] = gma_ops->gma_to_pde_index(gma);
21528c2ecf20Sopenharmony_ci			gma_index[1] = gma_ops->gma_to_pte_index(gma);
21538c2ecf20Sopenharmony_ci			levels = 2;
21548c2ecf20Sopenharmony_ci			break;
21558c2ecf20Sopenharmony_ci		default:
21568c2ecf20Sopenharmony_ci			GEM_BUG_ON(1);
21578c2ecf20Sopenharmony_ci		}
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci		/* walk the shadow page table and get gpa from guest entry */
21608c2ecf20Sopenharmony_ci		for (i = 0; i < levels; i++) {
21618c2ecf20Sopenharmony_ci			ret = ppgtt_get_next_level_entry(mm, &e, gma_index[i],
21628c2ecf20Sopenharmony_ci				(i == levels - 1));
21638c2ecf20Sopenharmony_ci			if (ret)
21648c2ecf20Sopenharmony_ci				goto err;
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci			if (!pte_ops->test_present(&e)) {
21678c2ecf20Sopenharmony_ci				gvt_dbg_core("GMA 0x%lx is not present\n", gma);
21688c2ecf20Sopenharmony_ci				goto err;
21698c2ecf20Sopenharmony_ci			}
21708c2ecf20Sopenharmony_ci		}
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci		gpa = (pte_ops->get_pfn(&e) << I915_GTT_PAGE_SHIFT) +
21738c2ecf20Sopenharmony_ci					(gma & ~I915_GTT_PAGE_MASK);
21748c2ecf20Sopenharmony_ci		trace_gma_translate(vgpu->id, "ppgtt", 0,
21758c2ecf20Sopenharmony_ci				    mm->ppgtt_mm.root_entry_type, gma, gpa);
21768c2ecf20Sopenharmony_ci	}
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	return gpa;
21798c2ecf20Sopenharmony_cierr:
21808c2ecf20Sopenharmony_ci	gvt_vgpu_err("invalid mm type: %d gma %lx\n", mm->type, gma);
21818c2ecf20Sopenharmony_ci	return INTEL_GVT_INVALID_ADDR;
21828c2ecf20Sopenharmony_ci}
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_cistatic int emulate_ggtt_mmio_read(struct intel_vgpu *vgpu,
21858c2ecf20Sopenharmony_ci	unsigned int off, void *p_data, unsigned int bytes)
21868c2ecf20Sopenharmony_ci{
21878c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *ggtt_mm = vgpu->gtt.ggtt_mm;
21888c2ecf20Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
21898c2ecf20Sopenharmony_ci	unsigned long index = off >> info->gtt_entry_size_shift;
21908c2ecf20Sopenharmony_ci	unsigned long gma;
21918c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry e;
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	if (bytes != 4 && bytes != 8)
21948c2ecf20Sopenharmony_ci		return -EINVAL;
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	gma = index << I915_GTT_PAGE_SHIFT;
21978c2ecf20Sopenharmony_ci	if (!intel_gvt_ggtt_validate_range(vgpu,
21988c2ecf20Sopenharmony_ci					   gma, 1 << I915_GTT_PAGE_SHIFT)) {
21998c2ecf20Sopenharmony_ci		gvt_dbg_mm("read invalid ggtt at 0x%lx\n", gma);
22008c2ecf20Sopenharmony_ci		memset(p_data, 0, bytes);
22018c2ecf20Sopenharmony_ci		return 0;
22028c2ecf20Sopenharmony_ci	}
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	ggtt_get_guest_entry(ggtt_mm, &e, index);
22058c2ecf20Sopenharmony_ci	memcpy(p_data, (void *)&e.val64 + (off & (info->gtt_entry_size - 1)),
22068c2ecf20Sopenharmony_ci			bytes);
22078c2ecf20Sopenharmony_ci	return 0;
22088c2ecf20Sopenharmony_ci}
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci/**
22118c2ecf20Sopenharmony_ci * intel_vgpu_emulate_gtt_mmio_read - emulate GTT MMIO register read
22128c2ecf20Sopenharmony_ci * @vgpu: a vGPU
22138c2ecf20Sopenharmony_ci * @off: register offset
22148c2ecf20Sopenharmony_ci * @p_data: data will be returned to guest
22158c2ecf20Sopenharmony_ci * @bytes: data length
22168c2ecf20Sopenharmony_ci *
22178c2ecf20Sopenharmony_ci * This function is used to emulate the GTT MMIO register read
22188c2ecf20Sopenharmony_ci *
22198c2ecf20Sopenharmony_ci * Returns:
22208c2ecf20Sopenharmony_ci * Zero on success, error code if failed.
22218c2ecf20Sopenharmony_ci */
22228c2ecf20Sopenharmony_ciint intel_vgpu_emulate_ggtt_mmio_read(struct intel_vgpu *vgpu, unsigned int off,
22238c2ecf20Sopenharmony_ci	void *p_data, unsigned int bytes)
22248c2ecf20Sopenharmony_ci{
22258c2ecf20Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
22268c2ecf20Sopenharmony_ci	int ret;
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci	if (bytes != 4 && bytes != 8)
22298c2ecf20Sopenharmony_ci		return -EINVAL;
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	off -= info->gtt_start_offset;
22328c2ecf20Sopenharmony_ci	ret = emulate_ggtt_mmio_read(vgpu, off, p_data, bytes);
22338c2ecf20Sopenharmony_ci	return ret;
22348c2ecf20Sopenharmony_ci}
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_cistatic void ggtt_invalidate_pte(struct intel_vgpu *vgpu,
22378c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry *entry)
22388c2ecf20Sopenharmony_ci{
22398c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops;
22408c2ecf20Sopenharmony_ci	unsigned long pfn;
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	pfn = pte_ops->get_pfn(entry);
22438c2ecf20Sopenharmony_ci	if (pfn != vgpu->gvt->gtt.scratch_mfn)
22448c2ecf20Sopenharmony_ci		intel_gvt_hypervisor_dma_unmap_guest_page(vgpu,
22458c2ecf20Sopenharmony_ci						pfn << PAGE_SHIFT);
22468c2ecf20Sopenharmony_ci}
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_cistatic int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
22498c2ecf20Sopenharmony_ci	void *p_data, unsigned int bytes)
22508c2ecf20Sopenharmony_ci{
22518c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
22528c2ecf20Sopenharmony_ci	const struct intel_gvt_device_info *info = &gvt->device_info;
22538c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *ggtt_mm = vgpu->gtt.ggtt_mm;
22548c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops;
22558c2ecf20Sopenharmony_ci	unsigned long g_gtt_index = off >> info->gtt_entry_size_shift;
22568c2ecf20Sopenharmony_ci	unsigned long gma, gfn;
22578c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry e = {.val64 = 0, .type = GTT_TYPE_GGTT_PTE};
22588c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry m = {.val64 = 0, .type = GTT_TYPE_GGTT_PTE};
22598c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
22608c2ecf20Sopenharmony_ci	int ret;
22618c2ecf20Sopenharmony_ci	struct intel_gvt_partial_pte *partial_pte, *pos, *n;
22628c2ecf20Sopenharmony_ci	bool partial_update = false;
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci	if (bytes != 4 && bytes != 8)
22658c2ecf20Sopenharmony_ci		return -EINVAL;
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	gma = g_gtt_index << I915_GTT_PAGE_SHIFT;
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci	/* the VM may configure the whole GM space when ballooning is used */
22708c2ecf20Sopenharmony_ci	if (!vgpu_gmadr_is_valid(vgpu, gma))
22718c2ecf20Sopenharmony_ci		return 0;
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	e.type = GTT_TYPE_GGTT_PTE;
22748c2ecf20Sopenharmony_ci	memcpy((void *)&e.val64 + (off & (info->gtt_entry_size - 1)), p_data,
22758c2ecf20Sopenharmony_ci			bytes);
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci	/* If ggtt entry size is 8 bytes, and it's split into two 4 bytes
22788c2ecf20Sopenharmony_ci	 * write, save the first 4 bytes in a list and update virtual
22798c2ecf20Sopenharmony_ci	 * PTE. Only update shadow PTE when the second 4 bytes comes.
22808c2ecf20Sopenharmony_ci	 */
22818c2ecf20Sopenharmony_ci	if (bytes < info->gtt_entry_size) {
22828c2ecf20Sopenharmony_ci		bool found = false;
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci		list_for_each_entry_safe(pos, n,
22858c2ecf20Sopenharmony_ci				&ggtt_mm->ggtt_mm.partial_pte_list, list) {
22868c2ecf20Sopenharmony_ci			if (g_gtt_index == pos->offset >>
22878c2ecf20Sopenharmony_ci					info->gtt_entry_size_shift) {
22888c2ecf20Sopenharmony_ci				if (off != pos->offset) {
22898c2ecf20Sopenharmony_ci					/* the second partial part*/
22908c2ecf20Sopenharmony_ci					int last_off = pos->offset &
22918c2ecf20Sopenharmony_ci						(info->gtt_entry_size - 1);
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci					memcpy((void *)&e.val64 + last_off,
22948c2ecf20Sopenharmony_ci						(void *)&pos->data + last_off,
22958c2ecf20Sopenharmony_ci						bytes);
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci					list_del(&pos->list);
22988c2ecf20Sopenharmony_ci					kfree(pos);
22998c2ecf20Sopenharmony_ci					found = true;
23008c2ecf20Sopenharmony_ci					break;
23018c2ecf20Sopenharmony_ci				}
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_ci				/* update of the first partial part */
23048c2ecf20Sopenharmony_ci				pos->data = e.val64;
23058c2ecf20Sopenharmony_ci				ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
23068c2ecf20Sopenharmony_ci				return 0;
23078c2ecf20Sopenharmony_ci			}
23088c2ecf20Sopenharmony_ci		}
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci		if (!found) {
23118c2ecf20Sopenharmony_ci			/* the first partial part */
23128c2ecf20Sopenharmony_ci			partial_pte = kzalloc(sizeof(*partial_pte), GFP_KERNEL);
23138c2ecf20Sopenharmony_ci			if (!partial_pte)
23148c2ecf20Sopenharmony_ci				return -ENOMEM;
23158c2ecf20Sopenharmony_ci			partial_pte->offset = off;
23168c2ecf20Sopenharmony_ci			partial_pte->data = e.val64;
23178c2ecf20Sopenharmony_ci			list_add_tail(&partial_pte->list,
23188c2ecf20Sopenharmony_ci				&ggtt_mm->ggtt_mm.partial_pte_list);
23198c2ecf20Sopenharmony_ci			partial_update = true;
23208c2ecf20Sopenharmony_ci		}
23218c2ecf20Sopenharmony_ci	}
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci	if (!partial_update && (ops->test_present(&e))) {
23248c2ecf20Sopenharmony_ci		gfn = ops->get_pfn(&e);
23258c2ecf20Sopenharmony_ci		m.val64 = e.val64;
23268c2ecf20Sopenharmony_ci		m.type = e.type;
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci		/* one PTE update may be issued in multiple writes and the
23298c2ecf20Sopenharmony_ci		 * first write may not construct a valid gfn
23308c2ecf20Sopenharmony_ci		 */
23318c2ecf20Sopenharmony_ci		if (!intel_gvt_hypervisor_is_valid_gfn(vgpu, gfn)) {
23328c2ecf20Sopenharmony_ci			ops->set_pfn(&m, gvt->gtt.scratch_mfn);
23338c2ecf20Sopenharmony_ci			goto out;
23348c2ecf20Sopenharmony_ci		}
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci		ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, gfn,
23378c2ecf20Sopenharmony_ci							PAGE_SIZE, &dma_addr);
23388c2ecf20Sopenharmony_ci		if (ret) {
23398c2ecf20Sopenharmony_ci			gvt_vgpu_err("fail to populate guest ggtt entry\n");
23408c2ecf20Sopenharmony_ci			/* guest driver may read/write the entry when partial
23418c2ecf20Sopenharmony_ci			 * update the entry in this situation p2m will fail
23428c2ecf20Sopenharmony_ci			 * settting the shadow entry to point to a scratch page
23438c2ecf20Sopenharmony_ci			 */
23448c2ecf20Sopenharmony_ci			ops->set_pfn(&m, gvt->gtt.scratch_mfn);
23458c2ecf20Sopenharmony_ci		} else
23468c2ecf20Sopenharmony_ci			ops->set_pfn(&m, dma_addr >> PAGE_SHIFT);
23478c2ecf20Sopenharmony_ci	} else {
23488c2ecf20Sopenharmony_ci		ops->set_pfn(&m, gvt->gtt.scratch_mfn);
23498c2ecf20Sopenharmony_ci		ops->clear_present(&m);
23508c2ecf20Sopenharmony_ci	}
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ciout:
23538c2ecf20Sopenharmony_ci	ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci	ggtt_get_host_entry(ggtt_mm, &e, g_gtt_index);
23568c2ecf20Sopenharmony_ci	ggtt_invalidate_pte(vgpu, &e);
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	ggtt_set_host_entry(ggtt_mm, &m, g_gtt_index);
23598c2ecf20Sopenharmony_ci	ggtt_invalidate(gvt->gt);
23608c2ecf20Sopenharmony_ci	return 0;
23618c2ecf20Sopenharmony_ci}
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci/*
23648c2ecf20Sopenharmony_ci * intel_vgpu_emulate_ggtt_mmio_write - emulate GTT MMIO register write
23658c2ecf20Sopenharmony_ci * @vgpu: a vGPU
23668c2ecf20Sopenharmony_ci * @off: register offset
23678c2ecf20Sopenharmony_ci * @p_data: data from guest write
23688c2ecf20Sopenharmony_ci * @bytes: data length
23698c2ecf20Sopenharmony_ci *
23708c2ecf20Sopenharmony_ci * This function is used to emulate the GTT MMIO register write
23718c2ecf20Sopenharmony_ci *
23728c2ecf20Sopenharmony_ci * Returns:
23738c2ecf20Sopenharmony_ci * Zero on success, error code if failed.
23748c2ecf20Sopenharmony_ci */
23758c2ecf20Sopenharmony_ciint intel_vgpu_emulate_ggtt_mmio_write(struct intel_vgpu *vgpu,
23768c2ecf20Sopenharmony_ci		unsigned int off, void *p_data, unsigned int bytes)
23778c2ecf20Sopenharmony_ci{
23788c2ecf20Sopenharmony_ci	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
23798c2ecf20Sopenharmony_ci	int ret;
23808c2ecf20Sopenharmony_ci	struct intel_vgpu_submission *s = &vgpu->submission;
23818c2ecf20Sopenharmony_ci	struct intel_engine_cs *engine;
23828c2ecf20Sopenharmony_ci	int i;
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci	if (bytes != 4 && bytes != 8)
23858c2ecf20Sopenharmony_ci		return -EINVAL;
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci	off -= info->gtt_start_offset;
23888c2ecf20Sopenharmony_ci	ret = emulate_ggtt_mmio_write(vgpu, off, p_data, bytes);
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci	/* if ggtt of last submitted context is written,
23918c2ecf20Sopenharmony_ci	 * that context is probably got unpinned.
23928c2ecf20Sopenharmony_ci	 * Set last shadowed ctx to invalid.
23938c2ecf20Sopenharmony_ci	 */
23948c2ecf20Sopenharmony_ci	for_each_engine(engine, vgpu->gvt->gt, i) {
23958c2ecf20Sopenharmony_ci		if (!s->last_ctx[i].valid)
23968c2ecf20Sopenharmony_ci			continue;
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci		if (s->last_ctx[i].lrca == (off >> info->gtt_entry_size_shift))
23998c2ecf20Sopenharmony_ci			s->last_ctx[i].valid = false;
24008c2ecf20Sopenharmony_ci	}
24018c2ecf20Sopenharmony_ci	return ret;
24028c2ecf20Sopenharmony_ci}
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_cistatic int alloc_scratch_pages(struct intel_vgpu *vgpu,
24058c2ecf20Sopenharmony_ci		enum intel_gvt_gtt_type type)
24068c2ecf20Sopenharmony_ci{
24078c2ecf20Sopenharmony_ci	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
24088c2ecf20Sopenharmony_ci	struct intel_vgpu_gtt *gtt = &vgpu->gtt;
24098c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
24108c2ecf20Sopenharmony_ci	int page_entry_num = I915_GTT_PAGE_SIZE >>
24118c2ecf20Sopenharmony_ci				vgpu->gvt->device_info.gtt_entry_size_shift;
24128c2ecf20Sopenharmony_ci	void *scratch_pt;
24138c2ecf20Sopenharmony_ci	int i;
24148c2ecf20Sopenharmony_ci	struct device *dev = &vgpu->gvt->gt->i915->drm.pdev->dev;
24158c2ecf20Sopenharmony_ci	dma_addr_t daddr;
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&i915->drm,
24188c2ecf20Sopenharmony_ci			type < GTT_TYPE_PPGTT_PTE_PT || type >= GTT_TYPE_MAX))
24198c2ecf20Sopenharmony_ci		return -EINVAL;
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci	scratch_pt = (void *)get_zeroed_page(GFP_KERNEL);
24228c2ecf20Sopenharmony_ci	if (!scratch_pt) {
24238c2ecf20Sopenharmony_ci		gvt_vgpu_err("fail to allocate scratch page\n");
24248c2ecf20Sopenharmony_ci		return -ENOMEM;
24258c2ecf20Sopenharmony_ci	}
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	daddr = dma_map_page(dev, virt_to_page(scratch_pt), 0,
24288c2ecf20Sopenharmony_ci			4096, PCI_DMA_BIDIRECTIONAL);
24298c2ecf20Sopenharmony_ci	if (dma_mapping_error(dev, daddr)) {
24308c2ecf20Sopenharmony_ci		gvt_vgpu_err("fail to dmamap scratch_pt\n");
24318c2ecf20Sopenharmony_ci		__free_page(virt_to_page(scratch_pt));
24328c2ecf20Sopenharmony_ci		return -ENOMEM;
24338c2ecf20Sopenharmony_ci	}
24348c2ecf20Sopenharmony_ci	gtt->scratch_pt[type].page_mfn =
24358c2ecf20Sopenharmony_ci		(unsigned long)(daddr >> I915_GTT_PAGE_SHIFT);
24368c2ecf20Sopenharmony_ci	gtt->scratch_pt[type].page = virt_to_page(scratch_pt);
24378c2ecf20Sopenharmony_ci	gvt_dbg_mm("vgpu%d create scratch_pt: type %d mfn=0x%lx\n",
24388c2ecf20Sopenharmony_ci			vgpu->id, type, gtt->scratch_pt[type].page_mfn);
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci	/* Build the tree by full filled the scratch pt with the entries which
24418c2ecf20Sopenharmony_ci	 * point to the next level scratch pt or scratch page. The
24428c2ecf20Sopenharmony_ci	 * scratch_pt[type] indicate the scratch pt/scratch page used by the
24438c2ecf20Sopenharmony_ci	 * 'type' pt.
24448c2ecf20Sopenharmony_ci	 * e.g. scratch_pt[GTT_TYPE_PPGTT_PDE_PT] is used by
24458c2ecf20Sopenharmony_ci	 * GTT_TYPE_PPGTT_PDE_PT level pt, that means this scratch_pt it self
24468c2ecf20Sopenharmony_ci	 * is GTT_TYPE_PPGTT_PTE_PT, and full filled by scratch page mfn.
24478c2ecf20Sopenharmony_ci	 */
24488c2ecf20Sopenharmony_ci	if (type > GTT_TYPE_PPGTT_PTE_PT) {
24498c2ecf20Sopenharmony_ci		struct intel_gvt_gtt_entry se;
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ci		memset(&se, 0, sizeof(struct intel_gvt_gtt_entry));
24528c2ecf20Sopenharmony_ci		se.type = get_entry_type(type - 1);
24538c2ecf20Sopenharmony_ci		ops->set_pfn(&se, gtt->scratch_pt[type - 1].page_mfn);
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ci		/* The entry parameters like present/writeable/cache type
24568c2ecf20Sopenharmony_ci		 * set to the same as i915's scratch page tree.
24578c2ecf20Sopenharmony_ci		 */
24588c2ecf20Sopenharmony_ci		se.val64 |= _PAGE_PRESENT | _PAGE_RW;
24598c2ecf20Sopenharmony_ci		if (type == GTT_TYPE_PPGTT_PDE_PT)
24608c2ecf20Sopenharmony_ci			se.val64 |= PPAT_CACHED;
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci		for (i = 0; i < page_entry_num; i++)
24638c2ecf20Sopenharmony_ci			ops->set_entry(scratch_pt, &se, i, false, 0, vgpu);
24648c2ecf20Sopenharmony_ci	}
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	return 0;
24678c2ecf20Sopenharmony_ci}
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_cistatic int release_scratch_page_tree(struct intel_vgpu *vgpu)
24708c2ecf20Sopenharmony_ci{
24718c2ecf20Sopenharmony_ci	int i;
24728c2ecf20Sopenharmony_ci	struct device *dev = &vgpu->gvt->gt->i915->drm.pdev->dev;
24738c2ecf20Sopenharmony_ci	dma_addr_t daddr;
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci	for (i = GTT_TYPE_PPGTT_PTE_PT; i < GTT_TYPE_MAX; i++) {
24768c2ecf20Sopenharmony_ci		if (vgpu->gtt.scratch_pt[i].page != NULL) {
24778c2ecf20Sopenharmony_ci			daddr = (dma_addr_t)(vgpu->gtt.scratch_pt[i].page_mfn <<
24788c2ecf20Sopenharmony_ci					I915_GTT_PAGE_SHIFT);
24798c2ecf20Sopenharmony_ci			dma_unmap_page(dev, daddr, 4096, PCI_DMA_BIDIRECTIONAL);
24808c2ecf20Sopenharmony_ci			__free_page(vgpu->gtt.scratch_pt[i].page);
24818c2ecf20Sopenharmony_ci			vgpu->gtt.scratch_pt[i].page = NULL;
24828c2ecf20Sopenharmony_ci			vgpu->gtt.scratch_pt[i].page_mfn = 0;
24838c2ecf20Sopenharmony_ci		}
24848c2ecf20Sopenharmony_ci	}
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	return 0;
24878c2ecf20Sopenharmony_ci}
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_cistatic int create_scratch_page_tree(struct intel_vgpu *vgpu)
24908c2ecf20Sopenharmony_ci{
24918c2ecf20Sopenharmony_ci	int i, ret;
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_ci	for (i = GTT_TYPE_PPGTT_PTE_PT; i < GTT_TYPE_MAX; i++) {
24948c2ecf20Sopenharmony_ci		ret = alloc_scratch_pages(vgpu, i);
24958c2ecf20Sopenharmony_ci		if (ret)
24968c2ecf20Sopenharmony_ci			goto err;
24978c2ecf20Sopenharmony_ci	}
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci	return 0;
25008c2ecf20Sopenharmony_ci
25018c2ecf20Sopenharmony_cierr:
25028c2ecf20Sopenharmony_ci	release_scratch_page_tree(vgpu);
25038c2ecf20Sopenharmony_ci	return ret;
25048c2ecf20Sopenharmony_ci}
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ci/**
25078c2ecf20Sopenharmony_ci * intel_vgpu_init_gtt - initialize per-vGPU graphics memory virulization
25088c2ecf20Sopenharmony_ci * @vgpu: a vGPU
25098c2ecf20Sopenharmony_ci *
25108c2ecf20Sopenharmony_ci * This function is used to initialize per-vGPU graphics memory virtualization
25118c2ecf20Sopenharmony_ci * components.
25128c2ecf20Sopenharmony_ci *
25138c2ecf20Sopenharmony_ci * Returns:
25148c2ecf20Sopenharmony_ci * Zero on success, error code if failed.
25158c2ecf20Sopenharmony_ci */
25168c2ecf20Sopenharmony_ciint intel_vgpu_init_gtt(struct intel_vgpu *vgpu)
25178c2ecf20Sopenharmony_ci{
25188c2ecf20Sopenharmony_ci	struct intel_vgpu_gtt *gtt = &vgpu->gtt;
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci	INIT_RADIX_TREE(&gtt->spt_tree, GFP_KERNEL);
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gtt->ppgtt_mm_list_head);
25238c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gtt->oos_page_list_head);
25248c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gtt->post_shadow_list_head);
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci	gtt->ggtt_mm = intel_vgpu_create_ggtt_mm(vgpu);
25278c2ecf20Sopenharmony_ci	if (IS_ERR(gtt->ggtt_mm)) {
25288c2ecf20Sopenharmony_ci		gvt_vgpu_err("fail to create mm for ggtt.\n");
25298c2ecf20Sopenharmony_ci		return PTR_ERR(gtt->ggtt_mm);
25308c2ecf20Sopenharmony_ci	}
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci	intel_vgpu_reset_ggtt(vgpu, false);
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gtt->ggtt_mm->ggtt_mm.partial_pte_list);
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci	return create_scratch_page_tree(vgpu);
25378c2ecf20Sopenharmony_ci}
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_civoid intel_vgpu_destroy_all_ppgtt_mm(struct intel_vgpu *vgpu)
25408c2ecf20Sopenharmony_ci{
25418c2ecf20Sopenharmony_ci	struct list_head *pos, *n;
25428c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm;
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci	list_for_each_safe(pos, n, &vgpu->gtt.ppgtt_mm_list_head) {
25458c2ecf20Sopenharmony_ci		mm = container_of(pos, struct intel_vgpu_mm, ppgtt_mm.list);
25468c2ecf20Sopenharmony_ci		intel_vgpu_destroy_mm(mm);
25478c2ecf20Sopenharmony_ci	}
25488c2ecf20Sopenharmony_ci
25498c2ecf20Sopenharmony_ci	if (GEM_WARN_ON(!list_empty(&vgpu->gtt.ppgtt_mm_list_head)))
25508c2ecf20Sopenharmony_ci		gvt_err("vgpu ppgtt mm is not fully destroyed\n");
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci	if (GEM_WARN_ON(!radix_tree_empty(&vgpu->gtt.spt_tree))) {
25538c2ecf20Sopenharmony_ci		gvt_err("Why we still has spt not freed?\n");
25548c2ecf20Sopenharmony_ci		ppgtt_free_all_spt(vgpu);
25558c2ecf20Sopenharmony_ci	}
25568c2ecf20Sopenharmony_ci}
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_cistatic void intel_vgpu_destroy_ggtt_mm(struct intel_vgpu *vgpu)
25598c2ecf20Sopenharmony_ci{
25608c2ecf20Sopenharmony_ci	struct intel_gvt_partial_pte *pos, *next;
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	list_for_each_entry_safe(pos, next,
25638c2ecf20Sopenharmony_ci				 &vgpu->gtt.ggtt_mm->ggtt_mm.partial_pte_list,
25648c2ecf20Sopenharmony_ci				 list) {
25658c2ecf20Sopenharmony_ci		gvt_dbg_mm("partial PTE update on hold 0x%lx : 0x%llx\n",
25668c2ecf20Sopenharmony_ci			pos->offset, pos->data);
25678c2ecf20Sopenharmony_ci		kfree(pos);
25688c2ecf20Sopenharmony_ci	}
25698c2ecf20Sopenharmony_ci	intel_vgpu_destroy_mm(vgpu->gtt.ggtt_mm);
25708c2ecf20Sopenharmony_ci	vgpu->gtt.ggtt_mm = NULL;
25718c2ecf20Sopenharmony_ci}
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci/**
25748c2ecf20Sopenharmony_ci * intel_vgpu_clean_gtt - clean up per-vGPU graphics memory virulization
25758c2ecf20Sopenharmony_ci * @vgpu: a vGPU
25768c2ecf20Sopenharmony_ci *
25778c2ecf20Sopenharmony_ci * This function is used to clean up per-vGPU graphics memory virtualization
25788c2ecf20Sopenharmony_ci * components.
25798c2ecf20Sopenharmony_ci *
25808c2ecf20Sopenharmony_ci * Returns:
25818c2ecf20Sopenharmony_ci * Zero on success, error code if failed.
25828c2ecf20Sopenharmony_ci */
25838c2ecf20Sopenharmony_civoid intel_vgpu_clean_gtt(struct intel_vgpu *vgpu)
25848c2ecf20Sopenharmony_ci{
25858c2ecf20Sopenharmony_ci	intel_vgpu_destroy_all_ppgtt_mm(vgpu);
25868c2ecf20Sopenharmony_ci	intel_vgpu_destroy_ggtt_mm(vgpu);
25878c2ecf20Sopenharmony_ci	release_scratch_page_tree(vgpu);
25888c2ecf20Sopenharmony_ci}
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_cistatic void clean_spt_oos(struct intel_gvt *gvt)
25918c2ecf20Sopenharmony_ci{
25928c2ecf20Sopenharmony_ci	struct intel_gvt_gtt *gtt = &gvt->gtt;
25938c2ecf20Sopenharmony_ci	struct list_head *pos, *n;
25948c2ecf20Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page;
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci	WARN(!list_empty(&gtt->oos_page_use_list_head),
25978c2ecf20Sopenharmony_ci		"someone is still using oos page\n");
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci	list_for_each_safe(pos, n, &gtt->oos_page_free_list_head) {
26008c2ecf20Sopenharmony_ci		oos_page = container_of(pos, struct intel_vgpu_oos_page, list);
26018c2ecf20Sopenharmony_ci		list_del(&oos_page->list);
26028c2ecf20Sopenharmony_ci		free_page((unsigned long)oos_page->mem);
26038c2ecf20Sopenharmony_ci		kfree(oos_page);
26048c2ecf20Sopenharmony_ci	}
26058c2ecf20Sopenharmony_ci}
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_cistatic int setup_spt_oos(struct intel_gvt *gvt)
26088c2ecf20Sopenharmony_ci{
26098c2ecf20Sopenharmony_ci	struct intel_gvt_gtt *gtt = &gvt->gtt;
26108c2ecf20Sopenharmony_ci	struct intel_vgpu_oos_page *oos_page;
26118c2ecf20Sopenharmony_ci	int i;
26128c2ecf20Sopenharmony_ci	int ret;
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gtt->oos_page_free_list_head);
26158c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gtt->oos_page_use_list_head);
26168c2ecf20Sopenharmony_ci
26178c2ecf20Sopenharmony_ci	for (i = 0; i < preallocated_oos_pages; i++) {
26188c2ecf20Sopenharmony_ci		oos_page = kzalloc(sizeof(*oos_page), GFP_KERNEL);
26198c2ecf20Sopenharmony_ci		if (!oos_page) {
26208c2ecf20Sopenharmony_ci			ret = -ENOMEM;
26218c2ecf20Sopenharmony_ci			goto fail;
26228c2ecf20Sopenharmony_ci		}
26238c2ecf20Sopenharmony_ci		oos_page->mem = (void *)__get_free_pages(GFP_KERNEL, 0);
26248c2ecf20Sopenharmony_ci		if (!oos_page->mem) {
26258c2ecf20Sopenharmony_ci			ret = -ENOMEM;
26268c2ecf20Sopenharmony_ci			kfree(oos_page);
26278c2ecf20Sopenharmony_ci			goto fail;
26288c2ecf20Sopenharmony_ci		}
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&oos_page->list);
26318c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&oos_page->vm_list);
26328c2ecf20Sopenharmony_ci		oos_page->id = i;
26338c2ecf20Sopenharmony_ci		list_add_tail(&oos_page->list, &gtt->oos_page_free_list_head);
26348c2ecf20Sopenharmony_ci	}
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci	gvt_dbg_mm("%d oos pages preallocated\n", i);
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci	return 0;
26398c2ecf20Sopenharmony_cifail:
26408c2ecf20Sopenharmony_ci	clean_spt_oos(gvt);
26418c2ecf20Sopenharmony_ci	return ret;
26428c2ecf20Sopenharmony_ci}
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci/**
26458c2ecf20Sopenharmony_ci * intel_vgpu_find_ppgtt_mm - find a PPGTT mm object
26468c2ecf20Sopenharmony_ci * @vgpu: a vGPU
26478c2ecf20Sopenharmony_ci * @pdps: pdp root array
26488c2ecf20Sopenharmony_ci *
26498c2ecf20Sopenharmony_ci * This function is used to find a PPGTT mm object from mm object pool
26508c2ecf20Sopenharmony_ci *
26518c2ecf20Sopenharmony_ci * Returns:
26528c2ecf20Sopenharmony_ci * pointer to mm object on success, NULL if failed.
26538c2ecf20Sopenharmony_ci */
26548c2ecf20Sopenharmony_cistruct intel_vgpu_mm *intel_vgpu_find_ppgtt_mm(struct intel_vgpu *vgpu,
26558c2ecf20Sopenharmony_ci		u64 pdps[])
26568c2ecf20Sopenharmony_ci{
26578c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm;
26588c2ecf20Sopenharmony_ci	struct list_head *pos;
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci	list_for_each(pos, &vgpu->gtt.ppgtt_mm_list_head) {
26618c2ecf20Sopenharmony_ci		mm = container_of(pos, struct intel_vgpu_mm, ppgtt_mm.list);
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci		switch (mm->ppgtt_mm.root_entry_type) {
26648c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_ROOT_L4_ENTRY:
26658c2ecf20Sopenharmony_ci			if (pdps[0] == mm->ppgtt_mm.guest_pdps[0])
26668c2ecf20Sopenharmony_ci				return mm;
26678c2ecf20Sopenharmony_ci			break;
26688c2ecf20Sopenharmony_ci		case GTT_TYPE_PPGTT_ROOT_L3_ENTRY:
26698c2ecf20Sopenharmony_ci			if (!memcmp(pdps, mm->ppgtt_mm.guest_pdps,
26708c2ecf20Sopenharmony_ci				    sizeof(mm->ppgtt_mm.guest_pdps)))
26718c2ecf20Sopenharmony_ci				return mm;
26728c2ecf20Sopenharmony_ci			break;
26738c2ecf20Sopenharmony_ci		default:
26748c2ecf20Sopenharmony_ci			GEM_BUG_ON(1);
26758c2ecf20Sopenharmony_ci		}
26768c2ecf20Sopenharmony_ci	}
26778c2ecf20Sopenharmony_ci	return NULL;
26788c2ecf20Sopenharmony_ci}
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_ci/**
26818c2ecf20Sopenharmony_ci * intel_vgpu_get_ppgtt_mm - get or create a PPGTT mm object.
26828c2ecf20Sopenharmony_ci * @vgpu: a vGPU
26838c2ecf20Sopenharmony_ci * @root_entry_type: ppgtt root entry type
26848c2ecf20Sopenharmony_ci * @pdps: guest pdps
26858c2ecf20Sopenharmony_ci *
26868c2ecf20Sopenharmony_ci * This function is used to find or create a PPGTT mm object from a guest.
26878c2ecf20Sopenharmony_ci *
26888c2ecf20Sopenharmony_ci * Returns:
26898c2ecf20Sopenharmony_ci * Zero on success, negative error code if failed.
26908c2ecf20Sopenharmony_ci */
26918c2ecf20Sopenharmony_cistruct intel_vgpu_mm *intel_vgpu_get_ppgtt_mm(struct intel_vgpu *vgpu,
26928c2ecf20Sopenharmony_ci		enum intel_gvt_gtt_type root_entry_type, u64 pdps[])
26938c2ecf20Sopenharmony_ci{
26948c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm;
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	mm = intel_vgpu_find_ppgtt_mm(vgpu, pdps);
26978c2ecf20Sopenharmony_ci	if (mm) {
26988c2ecf20Sopenharmony_ci		intel_vgpu_mm_get(mm);
26998c2ecf20Sopenharmony_ci	} else {
27008c2ecf20Sopenharmony_ci		mm = intel_vgpu_create_ppgtt_mm(vgpu, root_entry_type, pdps);
27018c2ecf20Sopenharmony_ci		if (IS_ERR(mm))
27028c2ecf20Sopenharmony_ci			gvt_vgpu_err("fail to create mm\n");
27038c2ecf20Sopenharmony_ci	}
27048c2ecf20Sopenharmony_ci	return mm;
27058c2ecf20Sopenharmony_ci}
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci/**
27088c2ecf20Sopenharmony_ci * intel_vgpu_put_ppgtt_mm - find and put a PPGTT mm object.
27098c2ecf20Sopenharmony_ci * @vgpu: a vGPU
27108c2ecf20Sopenharmony_ci * @pdps: guest pdps
27118c2ecf20Sopenharmony_ci *
27128c2ecf20Sopenharmony_ci * This function is used to find a PPGTT mm object from a guest and destroy it.
27138c2ecf20Sopenharmony_ci *
27148c2ecf20Sopenharmony_ci * Returns:
27158c2ecf20Sopenharmony_ci * Zero on success, negative error code if failed.
27168c2ecf20Sopenharmony_ci */
27178c2ecf20Sopenharmony_ciint intel_vgpu_put_ppgtt_mm(struct intel_vgpu *vgpu, u64 pdps[])
27188c2ecf20Sopenharmony_ci{
27198c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm;
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	mm = intel_vgpu_find_ppgtt_mm(vgpu, pdps);
27228c2ecf20Sopenharmony_ci	if (!mm) {
27238c2ecf20Sopenharmony_ci		gvt_vgpu_err("fail to find ppgtt instance.\n");
27248c2ecf20Sopenharmony_ci		return -EINVAL;
27258c2ecf20Sopenharmony_ci	}
27268c2ecf20Sopenharmony_ci	intel_vgpu_mm_put(mm);
27278c2ecf20Sopenharmony_ci	return 0;
27288c2ecf20Sopenharmony_ci}
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci/**
27318c2ecf20Sopenharmony_ci * intel_gvt_init_gtt - initialize mm components of a GVT device
27328c2ecf20Sopenharmony_ci * @gvt: GVT device
27338c2ecf20Sopenharmony_ci *
27348c2ecf20Sopenharmony_ci * This function is called at the initialization stage, to initialize
27358c2ecf20Sopenharmony_ci * the mm components of a GVT device.
27368c2ecf20Sopenharmony_ci *
27378c2ecf20Sopenharmony_ci * Returns:
27388c2ecf20Sopenharmony_ci * zero on success, negative error code if failed.
27398c2ecf20Sopenharmony_ci */
27408c2ecf20Sopenharmony_ciint intel_gvt_init_gtt(struct intel_gvt *gvt)
27418c2ecf20Sopenharmony_ci{
27428c2ecf20Sopenharmony_ci	int ret;
27438c2ecf20Sopenharmony_ci	void *page;
27448c2ecf20Sopenharmony_ci	struct device *dev = &gvt->gt->i915->drm.pdev->dev;
27458c2ecf20Sopenharmony_ci	dma_addr_t daddr;
27468c2ecf20Sopenharmony_ci
27478c2ecf20Sopenharmony_ci	gvt_dbg_core("init gtt\n");
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci	gvt->gtt.pte_ops = &gen8_gtt_pte_ops;
27508c2ecf20Sopenharmony_ci	gvt->gtt.gma_ops = &gen8_gtt_gma_ops;
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_ci	page = (void *)get_zeroed_page(GFP_KERNEL);
27538c2ecf20Sopenharmony_ci	if (!page) {
27548c2ecf20Sopenharmony_ci		gvt_err("fail to allocate scratch ggtt page\n");
27558c2ecf20Sopenharmony_ci		return -ENOMEM;
27568c2ecf20Sopenharmony_ci	}
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	daddr = dma_map_page(dev, virt_to_page(page), 0,
27598c2ecf20Sopenharmony_ci			4096, PCI_DMA_BIDIRECTIONAL);
27608c2ecf20Sopenharmony_ci	if (dma_mapping_error(dev, daddr)) {
27618c2ecf20Sopenharmony_ci		gvt_err("fail to dmamap scratch ggtt page\n");
27628c2ecf20Sopenharmony_ci		__free_page(virt_to_page(page));
27638c2ecf20Sopenharmony_ci		return -ENOMEM;
27648c2ecf20Sopenharmony_ci	}
27658c2ecf20Sopenharmony_ci
27668c2ecf20Sopenharmony_ci	gvt->gtt.scratch_page = virt_to_page(page);
27678c2ecf20Sopenharmony_ci	gvt->gtt.scratch_mfn = (unsigned long)(daddr >> I915_GTT_PAGE_SHIFT);
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_ci	if (enable_out_of_sync) {
27708c2ecf20Sopenharmony_ci		ret = setup_spt_oos(gvt);
27718c2ecf20Sopenharmony_ci		if (ret) {
27728c2ecf20Sopenharmony_ci			gvt_err("fail to initialize SPT oos\n");
27738c2ecf20Sopenharmony_ci			dma_unmap_page(dev, daddr, 4096, PCI_DMA_BIDIRECTIONAL);
27748c2ecf20Sopenharmony_ci			__free_page(gvt->gtt.scratch_page);
27758c2ecf20Sopenharmony_ci			return ret;
27768c2ecf20Sopenharmony_ci		}
27778c2ecf20Sopenharmony_ci	}
27788c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gvt->gtt.ppgtt_mm_lru_list_head);
27798c2ecf20Sopenharmony_ci	mutex_init(&gvt->gtt.ppgtt_mm_lock);
27808c2ecf20Sopenharmony_ci	return 0;
27818c2ecf20Sopenharmony_ci}
27828c2ecf20Sopenharmony_ci
27838c2ecf20Sopenharmony_ci/**
27848c2ecf20Sopenharmony_ci * intel_gvt_clean_gtt - clean up mm components of a GVT device
27858c2ecf20Sopenharmony_ci * @gvt: GVT device
27868c2ecf20Sopenharmony_ci *
27878c2ecf20Sopenharmony_ci * This function is called at the driver unloading stage, to clean up the
27888c2ecf20Sopenharmony_ci * the mm components of a GVT device.
27898c2ecf20Sopenharmony_ci *
27908c2ecf20Sopenharmony_ci */
27918c2ecf20Sopenharmony_civoid intel_gvt_clean_gtt(struct intel_gvt *gvt)
27928c2ecf20Sopenharmony_ci{
27938c2ecf20Sopenharmony_ci	struct device *dev = &gvt->gt->i915->drm.pdev->dev;
27948c2ecf20Sopenharmony_ci	dma_addr_t daddr = (dma_addr_t)(gvt->gtt.scratch_mfn <<
27958c2ecf20Sopenharmony_ci					I915_GTT_PAGE_SHIFT);
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	dma_unmap_page(dev, daddr, 4096, PCI_DMA_BIDIRECTIONAL);
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	__free_page(gvt->gtt.scratch_page);
28008c2ecf20Sopenharmony_ci
28018c2ecf20Sopenharmony_ci	if (enable_out_of_sync)
28028c2ecf20Sopenharmony_ci		clean_spt_oos(gvt);
28038c2ecf20Sopenharmony_ci}
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci/**
28068c2ecf20Sopenharmony_ci * intel_vgpu_invalidate_ppgtt - invalidate PPGTT instances
28078c2ecf20Sopenharmony_ci * @vgpu: a vGPU
28088c2ecf20Sopenharmony_ci *
28098c2ecf20Sopenharmony_ci * This function is called when invalidate all PPGTT instances of a vGPU.
28108c2ecf20Sopenharmony_ci *
28118c2ecf20Sopenharmony_ci */
28128c2ecf20Sopenharmony_civoid intel_vgpu_invalidate_ppgtt(struct intel_vgpu *vgpu)
28138c2ecf20Sopenharmony_ci{
28148c2ecf20Sopenharmony_ci	struct list_head *pos, *n;
28158c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm;
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_ci	list_for_each_safe(pos, n, &vgpu->gtt.ppgtt_mm_list_head) {
28188c2ecf20Sopenharmony_ci		mm = container_of(pos, struct intel_vgpu_mm, ppgtt_mm.list);
28198c2ecf20Sopenharmony_ci		if (mm->type == INTEL_GVT_MM_PPGTT) {
28208c2ecf20Sopenharmony_ci			mutex_lock(&vgpu->gvt->gtt.ppgtt_mm_lock);
28218c2ecf20Sopenharmony_ci			list_del_init(&mm->ppgtt_mm.lru_list);
28228c2ecf20Sopenharmony_ci			mutex_unlock(&vgpu->gvt->gtt.ppgtt_mm_lock);
28238c2ecf20Sopenharmony_ci			if (mm->ppgtt_mm.shadowed)
28248c2ecf20Sopenharmony_ci				invalidate_ppgtt_mm(mm);
28258c2ecf20Sopenharmony_ci		}
28268c2ecf20Sopenharmony_ci	}
28278c2ecf20Sopenharmony_ci}
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci/**
28308c2ecf20Sopenharmony_ci * intel_vgpu_reset_ggtt - reset the GGTT entry
28318c2ecf20Sopenharmony_ci * @vgpu: a vGPU
28328c2ecf20Sopenharmony_ci * @invalidate_old: invalidate old entries
28338c2ecf20Sopenharmony_ci *
28348c2ecf20Sopenharmony_ci * This function is called at the vGPU create stage
28358c2ecf20Sopenharmony_ci * to reset all the GGTT entries.
28368c2ecf20Sopenharmony_ci *
28378c2ecf20Sopenharmony_ci */
28388c2ecf20Sopenharmony_civoid intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu, bool invalidate_old)
28398c2ecf20Sopenharmony_ci{
28408c2ecf20Sopenharmony_ci	struct intel_gvt *gvt = vgpu->gvt;
28418c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops;
28428c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry entry = {.type = GTT_TYPE_GGTT_PTE};
28438c2ecf20Sopenharmony_ci	struct intel_gvt_gtt_entry old_entry;
28448c2ecf20Sopenharmony_ci	u32 index;
28458c2ecf20Sopenharmony_ci	u32 num_entries;
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci	pte_ops->set_pfn(&entry, gvt->gtt.scratch_mfn);
28488c2ecf20Sopenharmony_ci	pte_ops->set_present(&entry);
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ci	index = vgpu_aperture_gmadr_base(vgpu) >> PAGE_SHIFT;
28518c2ecf20Sopenharmony_ci	num_entries = vgpu_aperture_sz(vgpu) >> PAGE_SHIFT;
28528c2ecf20Sopenharmony_ci	while (num_entries--) {
28538c2ecf20Sopenharmony_ci		if (invalidate_old) {
28548c2ecf20Sopenharmony_ci			ggtt_get_host_entry(vgpu->gtt.ggtt_mm, &old_entry, index);
28558c2ecf20Sopenharmony_ci			ggtt_invalidate_pte(vgpu, &old_entry);
28568c2ecf20Sopenharmony_ci		}
28578c2ecf20Sopenharmony_ci		ggtt_set_host_entry(vgpu->gtt.ggtt_mm, &entry, index++);
28588c2ecf20Sopenharmony_ci	}
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci	index = vgpu_hidden_gmadr_base(vgpu) >> PAGE_SHIFT;
28618c2ecf20Sopenharmony_ci	num_entries = vgpu_hidden_sz(vgpu) >> PAGE_SHIFT;
28628c2ecf20Sopenharmony_ci	while (num_entries--) {
28638c2ecf20Sopenharmony_ci		if (invalidate_old) {
28648c2ecf20Sopenharmony_ci			ggtt_get_host_entry(vgpu->gtt.ggtt_mm, &old_entry, index);
28658c2ecf20Sopenharmony_ci			ggtt_invalidate_pte(vgpu, &old_entry);
28668c2ecf20Sopenharmony_ci		}
28678c2ecf20Sopenharmony_ci		ggtt_set_host_entry(vgpu->gtt.ggtt_mm, &entry, index++);
28688c2ecf20Sopenharmony_ci	}
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_ci	ggtt_invalidate(gvt->gt);
28718c2ecf20Sopenharmony_ci}
28728c2ecf20Sopenharmony_ci
28738c2ecf20Sopenharmony_ci/**
28748c2ecf20Sopenharmony_ci * intel_gvt_restore_ggtt - restore all vGPU's ggtt entries
28758c2ecf20Sopenharmony_ci * @gvt: intel gvt device
28768c2ecf20Sopenharmony_ci *
28778c2ecf20Sopenharmony_ci * This function is called at driver resume stage to restore
28788c2ecf20Sopenharmony_ci * GGTT entries of every vGPU.
28798c2ecf20Sopenharmony_ci *
28808c2ecf20Sopenharmony_ci */
28818c2ecf20Sopenharmony_civoid intel_gvt_restore_ggtt(struct intel_gvt *gvt)
28828c2ecf20Sopenharmony_ci{
28838c2ecf20Sopenharmony_ci	struct intel_vgpu *vgpu;
28848c2ecf20Sopenharmony_ci	struct intel_vgpu_mm *mm;
28858c2ecf20Sopenharmony_ci	int id;
28868c2ecf20Sopenharmony_ci	gen8_pte_t pte;
28878c2ecf20Sopenharmony_ci	u32 idx, num_low, num_hi, offset;
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci	/* Restore dirty host ggtt for all vGPUs */
28908c2ecf20Sopenharmony_ci	idr_for_each_entry(&(gvt)->vgpu_idr, vgpu, id) {
28918c2ecf20Sopenharmony_ci		mm = vgpu->gtt.ggtt_mm;
28928c2ecf20Sopenharmony_ci
28938c2ecf20Sopenharmony_ci		num_low = vgpu_aperture_sz(vgpu) >> PAGE_SHIFT;
28948c2ecf20Sopenharmony_ci		offset = vgpu_aperture_gmadr_base(vgpu) >> PAGE_SHIFT;
28958c2ecf20Sopenharmony_ci		for (idx = 0; idx < num_low; idx++) {
28968c2ecf20Sopenharmony_ci			pte = mm->ggtt_mm.host_ggtt_aperture[idx];
28978c2ecf20Sopenharmony_ci			if (pte & _PAGE_PRESENT)
28988c2ecf20Sopenharmony_ci				write_pte64(vgpu->gvt->gt->ggtt, offset + idx, pte);
28998c2ecf20Sopenharmony_ci		}
29008c2ecf20Sopenharmony_ci
29018c2ecf20Sopenharmony_ci		num_hi = vgpu_hidden_sz(vgpu) >> PAGE_SHIFT;
29028c2ecf20Sopenharmony_ci		offset = vgpu_hidden_gmadr_base(vgpu) >> PAGE_SHIFT;
29038c2ecf20Sopenharmony_ci		for (idx = 0; idx < num_hi; idx++) {
29048c2ecf20Sopenharmony_ci			pte = mm->ggtt_mm.host_ggtt_hidden[idx];
29058c2ecf20Sopenharmony_ci			if (pte & _PAGE_PRESENT)
29068c2ecf20Sopenharmony_ci				write_pte64(vgpu->gvt->gt->ggtt, offset + idx, pte);
29078c2ecf20Sopenharmony_ci		}
29088c2ecf20Sopenharmony_ci	}
29098c2ecf20Sopenharmony_ci}
2910