diff options
author | Changbin Du <changbin.du@intel.com> | 2018-01-30 06:19:48 -0500 |
---|---|---|
committer | Zhenyu Wang <zhenyuw@linux.intel.com> | 2018-03-06 00:19:17 -0500 |
commit | 72f03d7ea16794c3ac4b7ae945510cf0015d3c3c (patch) | |
tree | e0dde2f0f99db250fb07d5e45eeeb300c70028d6 | |
parent | d861ca237df8f1ef7b6380cd61f403edfcfc2be1 (diff) |
drm/i915/gvt: Refine pte shadowing process
Make the shadow PTE population code clear. Later we will add huge gtt
support based on this.
v2:
- rebase to latest code.
Signed-off-by: Changbin Du <changbin.du@intel.com>
Reviewed-by: Zhi Wang <zhi.wang@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
-rw-r--r-- | drivers/gpu/drm/i915/gvt/gtt.c | 173 |
1 files changed, 94 insertions, 79 deletions
diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index b15b9e55a997..7b4a345a0d52 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c | |||
@@ -453,29 +453,6 @@ static struct intel_gvt_gtt_gma_ops gen8_gtt_gma_ops = { | |||
453 | .gma_to_pml4_index = gen8_gma_to_pml4_index, | 453 | .gma_to_pml4_index = gen8_gma_to_pml4_index, |
454 | }; | 454 | }; |
455 | 455 | ||
456 | static int gtt_entry_p2m(struct intel_vgpu *vgpu, struct intel_gvt_gtt_entry *p, | ||
457 | struct intel_gvt_gtt_entry *m) | ||
458 | { | ||
459 | struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; | ||
460 | unsigned long gfn, mfn; | ||
461 | |||
462 | *m = *p; | ||
463 | |||
464 | if (!ops->test_present(p)) | ||
465 | return 0; | ||
466 | |||
467 | gfn = ops->get_pfn(p); | ||
468 | |||
469 | mfn = intel_gvt_hypervisor_gfn_to_mfn(vgpu, gfn); | ||
470 | if (mfn == INTEL_GVT_INVALID_ADDR) { | ||
471 | gvt_vgpu_err("fail to translate gfn: 0x%lx\n", gfn); | ||
472 | return -ENXIO; | ||
473 | } | ||
474 | |||
475 | ops->set_pfn(m, mfn); | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | /* | 456 | /* |
480 | * MM helpers. | 457 | * MM helpers. |
481 | */ | 458 | */ |
@@ -943,8 +920,7 @@ static int ppgtt_invalidate_shadow_page_by_shadow_entry(struct intel_vgpu *vgpu, | |||
943 | struct intel_vgpu_ppgtt_spt *s; | 920 | struct intel_vgpu_ppgtt_spt *s; |
944 | intel_gvt_gtt_type_t cur_pt_type; | 921 | intel_gvt_gtt_type_t cur_pt_type; |
945 | 922 | ||
946 | if (WARN_ON(!gtt_type_is_pt(get_next_pt_type(e->type)))) | 923 | GEM_BUG_ON(!gtt_type_is_pt(get_next_pt_type(e->type))); |
947 | return -EINVAL; | ||
948 | 924 | ||
949 | if (e->type != GTT_TYPE_PPGTT_ROOT_L3_ENTRY | 925 | if (e->type != GTT_TYPE_PPGTT_ROOT_L3_ENTRY |
950 | && e->type != GTT_TYPE_PPGTT_ROOT_L4_ENTRY) { | 926 | && e->type != GTT_TYPE_PPGTT_ROOT_L4_ENTRY) { |
@@ -982,14 +958,26 @@ static int ppgtt_invalidate_shadow_page(struct intel_vgpu_ppgtt_spt *spt) | |||
982 | goto release; | 958 | goto release; |
983 | 959 | ||
984 | for_each_present_shadow_entry(spt, &e, index) { | 960 | for_each_present_shadow_entry(spt, &e, index) { |
985 | if (!gtt_type_is_pt(get_next_pt_type(e.type))) { | 961 | switch (e.type) { |
986 | gvt_vgpu_err("GVT doesn't support pse bit for now\n"); | 962 | case GTT_TYPE_PPGTT_PTE_4K_ENTRY: |
987 | return -EINVAL; | 963 | gvt_vdbg_mm("invalidate 4K entry\n"); |
964 | continue; | ||
965 | case GTT_TYPE_PPGTT_PTE_2M_ENTRY: | ||
966 | case GTT_TYPE_PPGTT_PTE_1G_ENTRY: | ||
967 | WARN(1, "GVT doesn't support 2M/1GB page\n"); | ||
968 | continue; | ||
969 | case GTT_TYPE_PPGTT_PML4_ENTRY: | ||
970 | case GTT_TYPE_PPGTT_PDP_ENTRY: | ||
971 | case GTT_TYPE_PPGTT_PDE_ENTRY: | ||
972 | gvt_vdbg_mm("invalidate PMUL4/PDP/PDE entry\n"); | ||
973 | ret = ppgtt_invalidate_shadow_page_by_shadow_entry( | ||
974 | spt->vgpu, &e); | ||
975 | if (ret) | ||
976 | goto fail; | ||
977 | break; | ||
978 | default: | ||
979 | GEM_BUG_ON(1); | ||
988 | } | 980 | } |
989 | ret = ppgtt_invalidate_shadow_page_by_shadow_entry( | ||
990 | spt->vgpu, &e); | ||
991 | if (ret) | ||
992 | goto fail; | ||
993 | } | 981 | } |
994 | release: | 982 | release: |
995 | trace_spt_change(spt->vgpu->id, "release", spt, | 983 | trace_spt_change(spt->vgpu->id, "release", spt, |
@@ -1013,10 +1001,7 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_populate_shadow_page_by_guest_entry( | |||
1013 | struct intel_vgpu_page_track *t; | 1001 | struct intel_vgpu_page_track *t; |
1014 | int ret; | 1002 | int ret; |
1015 | 1003 | ||
1016 | if (WARN_ON(!gtt_type_is_pt(get_next_pt_type(we->type)))) { | 1004 | GEM_BUG_ON(!gtt_type_is_pt(get_next_pt_type(we->type))); |
1017 | ret = -EINVAL; | ||
1018 | goto fail; | ||
1019 | } | ||
1020 | 1005 | ||
1021 | t = intel_vgpu_find_tracked_page(vgpu, ops->get_pfn(we)); | 1006 | t = intel_vgpu_find_tracked_page(vgpu, ops->get_pfn(we)); |
1022 | if (t) { | 1007 | if (t) { |
@@ -1062,6 +1047,41 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se, | |||
1062 | ops->set_pfn(se, s->shadow_page.mfn); | 1047 | ops->set_pfn(se, s->shadow_page.mfn); |
1063 | } | 1048 | } |
1064 | 1049 | ||
1050 | static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, | ||
1051 | struct intel_vgpu_ppgtt_spt *spt, unsigned long index, | ||
1052 | struct intel_gvt_gtt_entry *ge) | ||
1053 | { | ||
1054 | struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops; | ||
1055 | struct intel_gvt_gtt_entry se = *ge; | ||
1056 | unsigned long gfn, mfn; | ||
1057 | |||
1058 | if (!pte_ops->test_present(ge)) | ||
1059 | return 0; | ||
1060 | |||
1061 | gfn = pte_ops->get_pfn(ge); | ||
1062 | |||
1063 | switch (ge->type) { | ||
1064 | case GTT_TYPE_PPGTT_PTE_4K_ENTRY: | ||
1065 | gvt_vdbg_mm("shadow 4K gtt entry\n"); | ||
1066 | break; | ||
1067 | case GTT_TYPE_PPGTT_PTE_2M_ENTRY: | ||
1068 | case GTT_TYPE_PPGTT_PTE_1G_ENTRY: | ||
1069 | gvt_vgpu_err("GVT doesn't support 2M/1GB entry\n"); | ||
1070 | return -EINVAL; | ||
1071 | default: | ||
1072 | GEM_BUG_ON(1); | ||
1073 | }; | ||
1074 | |||
1075 | /* direct shadow */ | ||
1076 | mfn = intel_gvt_hypervisor_gfn_to_mfn(vgpu, gfn); | ||
1077 | if (mfn == INTEL_GVT_INVALID_ADDR) | ||
1078 | return -ENXIO; | ||
1079 | |||
1080 | pte_ops->set_pfn(&se, mfn); | ||
1081 | ppgtt_set_shadow_entry(spt, &se, index); | ||
1082 | return 0; | ||
1083 | } | ||
1084 | |||
1065 | static int ppgtt_populate_shadow_page(struct intel_vgpu_ppgtt_spt *spt) | 1085 | static int ppgtt_populate_shadow_page(struct intel_vgpu_ppgtt_spt *spt) |
1066 | { | 1086 | { |
1067 | struct intel_vgpu *vgpu = spt->vgpu; | 1087 | struct intel_vgpu *vgpu = spt->vgpu; |
@@ -1075,32 +1095,29 @@ static int ppgtt_populate_shadow_page(struct intel_vgpu_ppgtt_spt *spt) | |||
1075 | trace_spt_change(spt->vgpu->id, "born", spt, | 1095 | trace_spt_change(spt->vgpu->id, "born", spt, |
1076 | spt->guest_page.track.gfn, spt->shadow_page.type); | 1096 | spt->guest_page.track.gfn, spt->shadow_page.type); |
1077 | 1097 | ||
1078 | if (gtt_type_is_pte_pt(spt->shadow_page.type)) { | 1098 | for_each_present_guest_entry(spt, &ge, i) { |
1079 | for_each_present_guest_entry(spt, &ge, i) { | 1099 | if (gtt_type_is_pt(get_next_pt_type(ge.type))) { |
1100 | s = ppgtt_populate_shadow_page_by_guest_entry(vgpu, | ||
1101 | &ge); | ||
1102 | if (IS_ERR(s)) { | ||
1103 | ret = PTR_ERR(s); | ||
1104 | goto fail; | ||
1105 | } | ||
1106 | ppgtt_get_shadow_entry(spt, &se, i); | ||
1107 | ppgtt_generate_shadow_entry(&se, s, &ge); | ||
1108 | ppgtt_set_shadow_entry(spt, &se, i); | ||
1109 | } else { | ||
1080 | gfn = ops->get_pfn(&ge); | 1110 | gfn = ops->get_pfn(&ge); |
1081 | if (!intel_gvt_hypervisor_is_valid_gfn(vgpu, gfn) || | 1111 | if (!intel_gvt_hypervisor_is_valid_gfn(vgpu, gfn)) { |
1082 | gtt_entry_p2m(vgpu, &ge, &se)) | ||
1083 | ops->set_pfn(&se, gvt->gtt.scratch_mfn); | 1112 | ops->set_pfn(&se, gvt->gtt.scratch_mfn); |
1084 | ppgtt_set_shadow_entry(spt, &se, i); | 1113 | ppgtt_set_shadow_entry(spt, &se, i); |
1085 | } | 1114 | continue; |
1086 | return 0; | 1115 | } |
1087 | } | ||
1088 | |||
1089 | for_each_present_guest_entry(spt, &ge, i) { | ||
1090 | if (!gtt_type_is_pt(get_next_pt_type(ge.type))) { | ||
1091 | gvt_vgpu_err("GVT doesn't support pse bit now\n"); | ||
1092 | ret = -EINVAL; | ||
1093 | goto fail; | ||
1094 | } | ||
1095 | 1116 | ||
1096 | s = ppgtt_populate_shadow_page_by_guest_entry(vgpu, &ge); | 1117 | ret = ppgtt_populate_shadow_entry(vgpu, spt, i, &ge); |
1097 | if (IS_ERR(s)) { | 1118 | if (ret) |
1098 | ret = PTR_ERR(s); | 1119 | goto fail; |
1099 | goto fail; | ||
1100 | } | 1120 | } |
1101 | ppgtt_get_shadow_entry(spt, &se, i); | ||
1102 | ppgtt_generate_shadow_entry(&se, s, &ge); | ||
1103 | ppgtt_set_shadow_entry(spt, &se, i); | ||
1104 | } | 1121 | } |
1105 | return 0; | 1122 | return 0; |
1106 | fail: | 1123 | fail: |
@@ -1175,10 +1192,9 @@ static int ppgtt_handle_guest_entry_add(struct intel_vgpu_guest_page *gpt, | |||
1175 | ppgtt_generate_shadow_entry(&m, s, we); | 1192 | ppgtt_generate_shadow_entry(&m, s, we); |
1176 | ppgtt_set_shadow_entry(spt, &m, index); | 1193 | ppgtt_set_shadow_entry(spt, &m, index); |
1177 | } else { | 1194 | } else { |
1178 | ret = gtt_entry_p2m(vgpu, we, &m); | 1195 | ret = ppgtt_populate_shadow_entry(vgpu, spt, index, we); |
1179 | if (ret) | 1196 | if (ret) |
1180 | goto fail; | 1197 | goto fail; |
1181 | ppgtt_set_shadow_entry(spt, &m, index); | ||
1182 | } | 1198 | } |
1183 | return 0; | 1199 | return 0; |
1184 | fail: | 1200 | fail: |
@@ -1195,7 +1211,7 @@ static int sync_oos_page(struct intel_vgpu *vgpu, | |||
1195 | struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops; | 1211 | struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops; |
1196 | struct intel_vgpu_ppgtt_spt *spt = | 1212 | struct intel_vgpu_ppgtt_spt *spt = |
1197 | guest_page_to_ppgtt_spt(oos_page->guest_page); | 1213 | guest_page_to_ppgtt_spt(oos_page->guest_page); |
1198 | struct intel_gvt_gtt_entry old, new, m; | 1214 | struct intel_gvt_gtt_entry old, new; |
1199 | int index; | 1215 | int index; |
1200 | int ret; | 1216 | int ret; |
1201 | 1217 | ||
@@ -1219,12 +1235,11 @@ static int sync_oos_page(struct intel_vgpu *vgpu, | |||
1219 | oos_page->guest_page, spt->guest_page_type, | 1235 | oos_page->guest_page, spt->guest_page_type, |
1220 | new.val64, index); | 1236 | new.val64, index); |
1221 | 1237 | ||
1222 | ret = gtt_entry_p2m(vgpu, &new, &m); | 1238 | ret = ppgtt_populate_shadow_entry(vgpu, spt, index, &new); |
1223 | if (ret) | 1239 | if (ret) |
1224 | return ret; | 1240 | return ret; |
1225 | 1241 | ||
1226 | ops->set_entry(oos_page->mem, &new, index, false, 0, vgpu); | 1242 | ops->set_entry(oos_page->mem, &new, index, false, 0, vgpu); |
1227 | ppgtt_set_shadow_entry(spt, &m, index); | ||
1228 | } | 1243 | } |
1229 | 1244 | ||
1230 | oos_page->guest_page->write_cnt = 0; | 1245 | oos_page->guest_page->write_cnt = 0; |
@@ -1371,10 +1386,9 @@ static int ppgtt_handle_guest_write_page_table( | |||
1371 | struct intel_vgpu *vgpu = spt->vgpu; | 1386 | struct intel_vgpu *vgpu = spt->vgpu; |
1372 | int type = spt->shadow_page.type; | 1387 | int type = spt->shadow_page.type; |
1373 | struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; | 1388 | struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; |
1374 | struct intel_gvt_gtt_entry se; | 1389 | struct intel_gvt_gtt_entry old_se; |
1375 | |||
1376 | int ret; | ||
1377 | int new_present; | 1390 | int new_present; |
1391 | int ret; | ||
1378 | 1392 | ||
1379 | new_present = ops->test_present(we); | 1393 | new_present = ops->test_present(we); |
1380 | 1394 | ||
@@ -1383,7 +1397,7 @@ static int ppgtt_handle_guest_write_page_table( | |||
1383 | * guarantee the ppgtt table is validated during the window between | 1397 | * guarantee the ppgtt table is validated during the window between |
1384 | * adding and removal. | 1398 | * adding and removal. |
1385 | */ | 1399 | */ |
1386 | ppgtt_get_shadow_entry(spt, &se, index); | 1400 | ppgtt_get_shadow_entry(spt, &old_se, index); |
1387 | 1401 | ||
1388 | if (new_present) { | 1402 | if (new_present) { |
1389 | ret = ppgtt_handle_guest_entry_add(gpt, we, index); | 1403 | ret = ppgtt_handle_guest_entry_add(gpt, we, index); |
@@ -1391,13 +1405,13 @@ static int ppgtt_handle_guest_write_page_table( | |||
1391 | goto fail; | 1405 | goto fail; |
1392 | } | 1406 | } |
1393 | 1407 | ||
1394 | ret = ppgtt_handle_guest_entry_removal(gpt, &se, index); | 1408 | ret = ppgtt_handle_guest_entry_removal(gpt, &old_se, index); |
1395 | if (ret) | 1409 | if (ret) |
1396 | goto fail; | 1410 | goto fail; |
1397 | 1411 | ||
1398 | if (!new_present) { | 1412 | if (!new_present) { |
1399 | ops->set_pfn(&se, vgpu->gtt.scratch_pt[type].page_mfn); | 1413 | ops->set_pfn(&old_se, vgpu->gtt.scratch_pt[type].page_mfn); |
1400 | ppgtt_set_shadow_entry(spt, &se, index); | 1414 | ppgtt_set_shadow_entry(spt, &old_se, index); |
1401 | } | 1415 | } |
1402 | 1416 | ||
1403 | return 0; | 1417 | return 0; |
@@ -1407,6 +1421,8 @@ fail: | |||
1407 | return ret; | 1421 | return ret; |
1408 | } | 1422 | } |
1409 | 1423 | ||
1424 | |||
1425 | |||
1410 | static inline bool can_do_out_of_sync(struct intel_vgpu_guest_page *gpt) | 1426 | static inline bool can_do_out_of_sync(struct intel_vgpu_guest_page *gpt) |
1411 | { | 1427 | { |
1412 | return enable_out_of_sync | 1428 | return enable_out_of_sync |
@@ -1924,9 +1940,8 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off, | |||
1924 | struct intel_vgpu_mm *ggtt_mm = vgpu->gtt.ggtt_mm; | 1940 | struct intel_vgpu_mm *ggtt_mm = vgpu->gtt.ggtt_mm; |
1925 | struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops; | 1941 | struct intel_gvt_gtt_pte_ops *ops = gvt->gtt.pte_ops; |
1926 | unsigned long g_gtt_index = off >> info->gtt_entry_size_shift; | 1942 | unsigned long g_gtt_index = off >> info->gtt_entry_size_shift; |
1927 | unsigned long gma, gfn; | 1943 | unsigned long gma, gfn, mfn; |
1928 | struct intel_gvt_gtt_entry e, m; | 1944 | struct intel_gvt_gtt_entry e, m; |
1929 | int ret; | ||
1930 | 1945 | ||
1931 | if (bytes != 4 && bytes != 8) | 1946 | if (bytes != 4 && bytes != 8) |
1932 | return -EINVAL; | 1947 | return -EINVAL; |
@@ -1941,6 +1956,7 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off, | |||
1941 | 1956 | ||
1942 | memcpy((void *)&e.val64 + (off & (info->gtt_entry_size - 1)), p_data, | 1957 | memcpy((void *)&e.val64 + (off & (info->gtt_entry_size - 1)), p_data, |
1943 | bytes); | 1958 | bytes); |
1959 | m = e; | ||
1944 | 1960 | ||
1945 | if (ops->test_present(&e)) { | 1961 | if (ops->test_present(&e)) { |
1946 | gfn = ops->get_pfn(&e); | 1962 | gfn = ops->get_pfn(&e); |
@@ -1953,19 +1969,18 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off, | |||
1953 | goto out; | 1969 | goto out; |
1954 | } | 1970 | } |
1955 | 1971 | ||
1956 | ret = gtt_entry_p2m(vgpu, &e, &m); | 1972 | mfn = intel_gvt_hypervisor_gfn_to_mfn(vgpu, gfn); |
1957 | if (ret) { | 1973 | if (mfn == INTEL_GVT_INVALID_ADDR) { |
1958 | gvt_vgpu_err("fail to translate guest gtt entry\n"); | 1974 | gvt_vgpu_err("fail to populate guest ggtt entry\n"); |
1959 | /* guest driver may read/write the entry when partial | 1975 | /* guest driver may read/write the entry when partial |
1960 | * update the entry in this situation p2m will fail | 1976 | * update the entry in this situation p2m will fail |
1961 | * settting the shadow entry to point to a scratch page | 1977 | * settting the shadow entry to point to a scratch page |
1962 | */ | 1978 | */ |
1963 | ops->set_pfn(&m, gvt->gtt.scratch_mfn); | 1979 | ops->set_pfn(&m, gvt->gtt.scratch_mfn); |
1964 | } | 1980 | } else |
1965 | } else { | 1981 | ops->set_pfn(&m, mfn); |
1966 | m = e; | 1982 | } else |
1967 | ops->set_pfn(&m, gvt->gtt.scratch_mfn); | 1983 | ops->set_pfn(&m, gvt->gtt.scratch_mfn); |
1968 | } | ||
1969 | 1984 | ||
1970 | out: | 1985 | out: |
1971 | ggtt_set_host_entry(ggtt_mm, &m, g_gtt_index); | 1986 | ggtt_set_host_entry(ggtt_mm, &m, g_gtt_index); |