Skip to content

Commit b901b25

Browse files
Changbin Duzhenyw
authored andcommitted
drm/i915/gvt: Add 2M huge gtt support
This add 2M huge gtt support for GVTg. Unlike 64K gtt entry, we can shadow 2M guest entry with real huge gtt. But before that, we have to check memory physical continuous, alignment and if it is supported on the host. We can get all supported page sizes from intel_device_info.page_sizes. Finally we must split the 2M page into smaller pages if we cannot satisfy guest Huge Page. Signed-off-by: Changbin Du <[email protected]> Signed-off-by: Zhenyu Wang <[email protected]>
1 parent 79e542f commit b901b25

File tree

1 file changed

+95
-5
lines changed
  • drivers/gpu/drm/i915/gvt

1 file changed

+95
-5
lines changed

drivers/gpu/drm/i915/gvt/gtt.c

Lines changed: 95 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
905910
static 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+
10881163
static 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

Comments
 (0)