aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChangbin Du <changbin.du@intel.com>2018-05-14 22:35:43 -0400
committerZhenyu Wang <zhenyuw@linux.intel.com>2018-07-08 22:35:00 -0400
commitb901b252b6cf5cecc612059ccf05d974a9085c58 (patch)
tree194c6d0c8a681340c3df38e9e09917318d173505
parent79e542f5af79918e5e766c441561fb9bff8af3aa (diff)
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 <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
-rw-r--r--drivers/gpu/drm/i915/gvt/gtt.c100
1 files changed, 95 insertions, 5 deletions
diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c
index e26c01da2bd6..5a66d0f3365c 100644
--- a/drivers/gpu/drm/i915/gvt/gtt.c
+++ b/drivers/gpu/drm/i915/gvt/gtt.c
@@ -902,6 +902,11 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt_gfn(
902 if (!ppgtt_get_shadow_entry(spt, e, i) && \ 902 if (!ppgtt_get_shadow_entry(spt, e, i) && \
903 spt->vgpu->gvt->gtt.pte_ops->test_present(e)) 903 spt->vgpu->gvt->gtt.pte_ops->test_present(e))
904 904
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
905static void ppgtt_get_spt(struct intel_vgpu_ppgtt_spt *spt) 910static void ppgtt_get_spt(struct intel_vgpu_ppgtt_spt *spt)
906{ 911{
907 int v = atomic_read(&spt->refcount); 912 int v = atomic_read(&spt->refcount);
@@ -949,7 +954,8 @@ static inline void ppgtt_invalidate_pte(struct intel_vgpu_ppgtt_spt *spt,
949 pfn = ops->get_pfn(entry); 954 pfn = ops->get_pfn(entry);
950 type = spt->shadow_page.type; 955 type = spt->shadow_page.type;
951 956
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)
953 return; 959 return;
954 960
955 intel_gvt_hypervisor_dma_unmap_guest_page(vgpu, pfn << PAGE_SHIFT); 961 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)
982 WARN(1, "suspicious 64K gtt entry\n"); 988 WARN(1, "suspicious 64K gtt entry\n");
983 continue; 989 continue;
984 case GTT_TYPE_PPGTT_PTE_2M_ENTRY: 990 case GTT_TYPE_PPGTT_PTE_2M_ENTRY:
991 gvt_vdbg_mm("invalidate 2M entry\n");
992 continue;
985 case GTT_TYPE_PPGTT_PTE_1G_ENTRY: 993 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");
987 continue; 995 continue;
988 case GTT_TYPE_PPGTT_PML4_ENTRY: 996 case GTT_TYPE_PPGTT_PML4_ENTRY:
989 case GTT_TYPE_PPGTT_PDP_ENTRY: 997 case GTT_TYPE_PPGTT_PDP_ENTRY:
@@ -1085,6 +1093,73 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se,
1085 ops->set_pfn(se, s->shadow_page.mfn); 1093 ops->set_pfn(se, s->shadow_page.mfn);
1086} 1094}
1087 1095
1096/**
1097 * Return 1 if 2MB huge gtt shadowing is possilbe, 0 if miscondition,
1098 * negtive if found err.
1099 */
1100static 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
1116static 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
1088static int split_64KB_gtt_entry(struct intel_vgpu *vgpu, 1163static int split_64KB_gtt_entry(struct intel_vgpu *vgpu,
1089 struct intel_vgpu_ppgtt_spt *spt, unsigned long index, 1164 struct intel_vgpu_ppgtt_spt *spt, unsigned long index,
1090 struct intel_gvt_gtt_entry *se) 1165 struct intel_gvt_gtt_entry *se)
@@ -1122,7 +1197,7 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu,
1122{ 1197{
1123 struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops; 1198 struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops;
1124 struct intel_gvt_gtt_entry se = *ge; 1199 struct intel_gvt_gtt_entry se = *ge;
1125 unsigned long gfn; 1200 unsigned long gfn, page_size = PAGE_SIZE;
1126 dma_addr_t dma_addr; 1201 dma_addr_t dma_addr;
1127 int ret; 1202 int ret;
1128 1203
@@ -1144,15 +1219,24 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu,
1144 */ 1219 */
1145 return split_64KB_gtt_entry(vgpu, spt, index, &se); 1220 return split_64KB_gtt_entry(vgpu, spt, index, &se);
1146 case GTT_TYPE_PPGTT_PTE_2M_ENTRY: 1221 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;
1147 case GTT_TYPE_PPGTT_PTE_1G_ENTRY: 1230 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");
1149 return -EINVAL; 1232 return -EINVAL;
1150 default: 1233 default:
1151 GEM_BUG_ON(1); 1234 GEM_BUG_ON(1);
1152 }; 1235 };
1153 1236
1154 /* direct shadow */ 1237 /* 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);
1156 if (ret) 1240 if (ret)
1157 return -ENXIO; 1241 return -ENXIO;
1158 1242
@@ -1495,6 +1579,12 @@ static int ppgtt_handle_guest_write_page_table(
1495 vgpu->gtt.scratch_pt[type].page_mfn); 1579 vgpu->gtt.scratch_pt[type].page_mfn);
1496 ppgtt_set_shadow_entry(spt, &old_se, index + i); 1580 ppgtt_set_shadow_entry(spt, &old_se, index + i);
1497 } 1581 }
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);
1498 } else { 1588 } else {
1499 ops->set_pfn(&old_se, 1589 ops->set_pfn(&old_se,
1500 vgpu->gtt.scratch_pt[type].page_mfn); 1590 vgpu->gtt.scratch_pt[type].page_mfn);