@@ -902,6 +902,11 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt_gfn(
902902 if (!ppgtt_get_shadow_entry(spt, e, i) && \
903903 spt->vgpu->gvt->gtt.pte_ops->test_present(e))
904904
905+ #define for_each_shadow_entry (spt , e , i ) \
906+ for (i = 0; i < pt_entries(spt); \
907+ i += (spt->shadow_page.pde_ips ? GTT_64K_PTE_STRIDE : 1)) \
908+ if (!ppgtt_get_shadow_entry(spt, e, i))
909+
905910static void ppgtt_get_spt (struct intel_vgpu_ppgtt_spt * spt )
906911{
907912 int v = atomic_read (& spt -> refcount );
@@ -949,7 +954,8 @@ static inline void ppgtt_invalidate_pte(struct intel_vgpu_ppgtt_spt *spt,
949954 pfn = ops -> get_pfn (entry );
950955 type = spt -> shadow_page .type ;
951956
952- if (pfn == vgpu -> gtt .scratch_pt [type ].page_mfn )
957+ /* Uninitialized spte or unshadowed spte. */
958+ if (!pfn || pfn == vgpu -> gtt .scratch_pt [type ].page_mfn )
953959 return ;
954960
955961 intel_gvt_hypervisor_dma_unmap_guest_page (vgpu , pfn << PAGE_SHIFT );
@@ -982,8 +988,10 @@ static int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt)
982988 WARN (1 , "suspicious 64K gtt entry\n" );
983989 continue ;
984990 case GTT_TYPE_PPGTT_PTE_2M_ENTRY :
991+ gvt_vdbg_mm ("invalidate 2M entry\n" );
992+ continue ;
985993 case GTT_TYPE_PPGTT_PTE_1G_ENTRY :
986- WARN (1 , "GVT doesn't support 2M/ 1GB page\n" );
994+ WARN (1 , "GVT doesn't support 1GB page\n" );
987995 continue ;
988996 case GTT_TYPE_PPGTT_PML4_ENTRY :
989997 case GTT_TYPE_PPGTT_PDP_ENTRY :
@@ -1085,6 +1093,73 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se,
10851093 ops -> set_pfn (se , s -> shadow_page .mfn );
10861094}
10871095
1096+ /**
1097+ * Return 1 if 2MB huge gtt shadowing is possilbe, 0 if miscondition,
1098+ * negtive if found err.
1099+ */
1100+ static int is_2MB_gtt_possible (struct intel_vgpu * vgpu ,
1101+ struct intel_gvt_gtt_entry * entry )
1102+ {
1103+ struct intel_gvt_gtt_pte_ops * ops = vgpu -> gvt -> gtt .pte_ops ;
1104+ unsigned long pfn ;
1105+
1106+ if (!HAS_PAGE_SIZES (vgpu -> gvt -> dev_priv , I915_GTT_PAGE_SIZE_2M ))
1107+ return 0 ;
1108+
1109+ pfn = intel_gvt_hypervisor_gfn_to_mfn (vgpu , ops -> get_pfn (entry ));
1110+ if (pfn == INTEL_GVT_INVALID_ADDR )
1111+ return - EINVAL ;
1112+
1113+ return PageTransHuge (pfn_to_page (pfn ));
1114+ }
1115+
1116+ static int split_2MB_gtt_entry (struct intel_vgpu * vgpu ,
1117+ struct intel_vgpu_ppgtt_spt * spt , unsigned long index ,
1118+ struct intel_gvt_gtt_entry * se )
1119+ {
1120+ struct intel_gvt_gtt_pte_ops * ops = vgpu -> gvt -> gtt .pte_ops ;
1121+ struct intel_vgpu_ppgtt_spt * sub_spt ;
1122+ struct intel_gvt_gtt_entry sub_se ;
1123+ unsigned long start_gfn ;
1124+ dma_addr_t dma_addr ;
1125+ unsigned long sub_index ;
1126+ int ret ;
1127+
1128+ gvt_dbg_mm ("Split 2M gtt entry, index %lu\n" , index );
1129+
1130+ start_gfn = ops -> get_pfn (se );
1131+
1132+ sub_spt = ppgtt_alloc_spt (vgpu , GTT_TYPE_PPGTT_PTE_PT );
1133+ if (IS_ERR (sub_spt ))
1134+ return PTR_ERR (sub_spt );
1135+
1136+ for_each_shadow_entry (sub_spt , & sub_se , sub_index ) {
1137+ ret = intel_gvt_hypervisor_dma_map_guest_page (vgpu ,
1138+ start_gfn + sub_index , PAGE_SIZE , & dma_addr );
1139+ if (ret ) {
1140+ ppgtt_invalidate_spt (spt );
1141+ return ret ;
1142+ }
1143+ sub_se .val64 = se -> val64 ;
1144+
1145+ /* Copy the PAT field from PDE. */
1146+ sub_se .val64 &= ~_PAGE_PAT ;
1147+ sub_se .val64 |= (se -> val64 & _PAGE_PAT_LARGE ) >> 5 ;
1148+
1149+ ops -> set_pfn (& sub_se , dma_addr >> PAGE_SHIFT );
1150+ ppgtt_set_shadow_entry (sub_spt , & sub_se , sub_index );
1151+ }
1152+
1153+ /* Clear dirty field. */
1154+ se -> val64 &= ~_PAGE_DIRTY ;
1155+
1156+ ops -> clear_pse (se );
1157+ ops -> clear_ips (se );
1158+ ops -> set_pfn (se , sub_spt -> shadow_page .mfn );
1159+ ppgtt_set_shadow_entry (spt , se , index );
1160+ return 0 ;
1161+ }
1162+
10881163static int split_64KB_gtt_entry (struct intel_vgpu * vgpu ,
10891164 struct intel_vgpu_ppgtt_spt * spt , unsigned long index ,
10901165 struct intel_gvt_gtt_entry * se )
@@ -1122,7 +1197,7 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu,
11221197{
11231198 struct intel_gvt_gtt_pte_ops * pte_ops = vgpu -> gvt -> gtt .pte_ops ;
11241199 struct intel_gvt_gtt_entry se = * ge ;
1125- unsigned long gfn ;
1200+ unsigned long gfn , page_size = PAGE_SIZE ;
11261201 dma_addr_t dma_addr ;
11271202 int ret ;
11281203
@@ -1144,15 +1219,24 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu,
11441219 */
11451220 return split_64KB_gtt_entry (vgpu , spt , index , & se );
11461221 case GTT_TYPE_PPGTT_PTE_2M_ENTRY :
1222+ gvt_vdbg_mm ("shadow 2M gtt entry\n" );
1223+ ret = is_2MB_gtt_possible (vgpu , ge );
1224+ if (ret == 0 )
1225+ return split_2MB_gtt_entry (vgpu , spt , index , & se );
1226+ else if (ret < 0 )
1227+ return ret ;
1228+ page_size = I915_GTT_PAGE_SIZE_2M ;
1229+ break ;
11471230 case GTT_TYPE_PPGTT_PTE_1G_ENTRY :
1148- gvt_vgpu_err ("GVT doesn't support 2M/ 1GB entry\n" );
1231+ gvt_vgpu_err ("GVT doesn't support 1GB entry\n" );
11491232 return - EINVAL ;
11501233 default :
11511234 GEM_BUG_ON (1 );
11521235 };
11531236
11541237 /* direct shadow */
1155- ret = intel_gvt_hypervisor_dma_map_guest_page (vgpu , gfn , PAGE_SIZE , & dma_addr );
1238+ ret = intel_gvt_hypervisor_dma_map_guest_page (vgpu , gfn , page_size ,
1239+ & dma_addr );
11561240 if (ret )
11571241 return - ENXIO ;
11581242
@@ -1495,6 +1579,12 @@ static int ppgtt_handle_guest_write_page_table(
14951579 vgpu -> gtt .scratch_pt [type ].page_mfn );
14961580 ppgtt_set_shadow_entry (spt , & old_se , index + i );
14971581 }
1582+ } else if (old_se .type == GTT_TYPE_PPGTT_PTE_2M_ENTRY ||
1583+ old_se .type == GTT_TYPE_PPGTT_PTE_1G_ENTRY ) {
1584+ ops -> clear_pse (& old_se );
1585+ ops -> set_pfn (& old_se ,
1586+ vgpu -> gtt .scratch_pt [type ].page_mfn );
1587+ ppgtt_set_shadow_entry (spt , & old_se , index );
14981588 } else {
14991589 ops -> set_pfn (& old_se ,
15001590 vgpu -> gtt .scratch_pt [type ].page_mfn );
0 commit comments