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(>t->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(>t->spt_tree, GFP_KERNEL); 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci INIT_LIST_HEAD(>t->ppgtt_mm_list_head); 25238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(>t->oos_page_list_head); 25248c2ecf20Sopenharmony_ci INIT_LIST_HEAD(>t->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(>t->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(>t->oos_page_use_list_head), 25978c2ecf20Sopenharmony_ci "someone is still using oos page\n"); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci list_for_each_safe(pos, n, >t->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(>t->oos_page_free_list_head); 26158c2ecf20Sopenharmony_ci INIT_LIST_HEAD(>t->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, >t->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