Skip to content

Commit bc0686f

Browse files
Hang Yuanzhenyw
authored andcommitted
drm/i915/gvt: support inconsecutive partial gtt entry write
Previously we assumed two 4-byte writes to the same PTE coming in sequence. But recently we observed inconsecutive partial write happening as well. So this patch enhances the previous solution. It now uses a list to save more partial writes. If one partial write can be combined with another one in the list to construct a full PTE, update its shadow entry. Otherwise, save the partial write in the list. v2: invalidate old entry and flush ggtt (Zhenyu) v3: split old ggtt page unmap to another patch (Zhenyu) v4: refine codes (Zhenyu) Signed-off-by: Hang Yuan <hang.yuan@linux.intel.com> Cc: Yan Zhao <yan.y.zhao@intel.com> Cc: Xiaolin Zhang <xiaolin.zhang@intel.com> Cc: Zhenyu Wang <zhenyu.z.wang@intel.com> Reviewed-by: Xiaolin Zhang <xiaolin.zhang@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
1 parent f42259e commit bc0686f

File tree

2 files changed

+60
-56
lines changed

2 files changed

+60
-56
lines changed

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

Lines changed: 53 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,7 +1901,6 @@ static struct intel_vgpu_mm *intel_vgpu_create_ggtt_mm(struct intel_vgpu *vgpu)
19011901
vgpu_free_mm(mm);
19021902
return ERR_PTR(-ENOMEM);
19031903
}
1904-
mm->ggtt_mm.last_partial_off = -1UL;
19051904

19061905
return mm;
19071906
}
@@ -1926,7 +1925,6 @@ void _intel_vgpu_mm_release(struct kref *mm_ref)
19261925
invalidate_ppgtt_mm(mm);
19271926
} else {
19281927
vfree(mm->ggtt_mm.virtual_ggtt);
1929-
mm->ggtt_mm.last_partial_off = -1UL;
19301928
}
19311929

19321930
vgpu_free_mm(mm);
@@ -2164,6 +2162,8 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
21642162
struct intel_gvt_gtt_entry e, m;
21652163
dma_addr_t dma_addr;
21662164
int ret;
2165+
struct intel_gvt_partial_pte *partial_pte, *pos, *n;
2166+
bool partial_update = false;
21672167

21682168
if (bytes != 4 && bytes != 8)
21692169
return -EINVAL;
@@ -2174,68 +2174,57 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
21742174
if (!vgpu_gmadr_is_valid(vgpu, gma))
21752175
return 0;
21762176

2177-
ggtt_get_guest_entry(ggtt_mm, &e, g_gtt_index);
2178-
2177+
e.type = GTT_TYPE_GGTT_PTE;
21792178
memcpy((void *)&e.val64 + (off & (info->gtt_entry_size - 1)), p_data,
21802179
bytes);
21812180

21822181
/* If ggtt entry size is 8 bytes, and it's split into two 4 bytes
2183-
* write, we assume the two 4 bytes writes are consecutive.
2184-
* Otherwise, we abort and report error
2182+
* write, save the first 4 bytes in a list and update virtual
2183+
* PTE. Only update shadow PTE when the second 4 bytes comes.
21852184
*/
21862185
if (bytes < info->gtt_entry_size) {
2187-
if (ggtt_mm->ggtt_mm.last_partial_off == -1UL) {
2188-
/* the first partial part*/
2189-
ggtt_mm->ggtt_mm.last_partial_off = off;
2190-
ggtt_mm->ggtt_mm.last_partial_data = e.val64;
2191-
return 0;
2192-
} else if ((g_gtt_index ==
2193-
(ggtt_mm->ggtt_mm.last_partial_off >>
2194-
info->gtt_entry_size_shift)) &&
2195-
(off != ggtt_mm->ggtt_mm.last_partial_off)) {
2196-
/* the second partial part */
2197-
2198-
int last_off = ggtt_mm->ggtt_mm.last_partial_off &
2199-
(info->gtt_entry_size - 1);
2200-
2201-
memcpy((void *)&e.val64 + last_off,
2202-
(void *)&ggtt_mm->ggtt_mm.last_partial_data +
2203-
last_off, bytes);
2204-
2205-
ggtt_mm->ggtt_mm.last_partial_off = -1UL;
2206-
} else {
2207-
int last_offset;
2208-
2209-
gvt_vgpu_err("failed to populate guest ggtt entry: abnormal ggtt entry write sequence, last_partial_off=%lx, offset=%x, bytes=%d, ggtt entry size=%d\n",
2210-
ggtt_mm->ggtt_mm.last_partial_off, off,
2211-
bytes, info->gtt_entry_size);
2212-
2213-
/* set host ggtt entry to scratch page and clear
2214-
* virtual ggtt entry as not present for last
2215-
* partially write offset
2216-
*/
2217-
last_offset = ggtt_mm->ggtt_mm.last_partial_off &
2218-
(~(info->gtt_entry_size - 1));
2219-
2220-
ggtt_get_host_entry(ggtt_mm, &m, last_offset);
2221-
ggtt_invalidate_pte(vgpu, &m);
2222-
ops->set_pfn(&m, gvt->gtt.scratch_mfn);
2223-
ops->clear_present(&m);
2224-
ggtt_set_host_entry(ggtt_mm, &m, last_offset);
2225-
ggtt_invalidate(gvt->dev_priv);
2226-
2227-
ggtt_get_guest_entry(ggtt_mm, &e, last_offset);
2228-
ops->clear_present(&e);
2229-
ggtt_set_guest_entry(ggtt_mm, &e, last_offset);
2230-
2231-
ggtt_mm->ggtt_mm.last_partial_off = off;
2232-
ggtt_mm->ggtt_mm.last_partial_data = e.val64;
2186+
bool found = false;
2187+
2188+
list_for_each_entry_safe(pos, n,
2189+
&ggtt_mm->ggtt_mm.partial_pte_list, list) {
2190+
if (g_gtt_index == pos->offset >>
2191+
info->gtt_entry_size_shift) {
2192+
if (off != pos->offset) {
2193+
/* the second partial part*/
2194+
int last_off = pos->offset &
2195+
(info->gtt_entry_size - 1);
2196+
2197+
memcpy((void *)&e.val64 + last_off,
2198+
(void *)&pos->data + last_off,
2199+
bytes);
2200+
2201+
list_del(&pos->list);
2202+
kfree(pos);
2203+
found = true;
2204+
break;
2205+
}
2206+
2207+
/* update of the first partial part */
2208+
pos->data = e.val64;
2209+
ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
2210+
return 0;
2211+
}
2212+
}
22332213

2234-
return 0;
2214+
if (!found) {
2215+
/* the first partial part */
2216+
partial_pte = kzalloc(sizeof(*partial_pte), GFP_KERNEL);
2217+
if (!partial_pte)
2218+
return -ENOMEM;
2219+
partial_pte->offset = off;
2220+
partial_pte->data = e.val64;
2221+
list_add_tail(&partial_pte->list,
2222+
&ggtt_mm->ggtt_mm.partial_pte_list);
2223+
partial_update = true;
22352224
}
22362225
}
22372226

2238-
if (ops->test_present(&e)) {
2227+
if (!partial_update && (ops->test_present(&e))) {
22392228
gfn = ops->get_pfn(&e);
22402229
m = e;
22412230

@@ -2428,6 +2417,8 @@ int intel_vgpu_init_gtt(struct intel_vgpu *vgpu)
24282417

24292418
intel_vgpu_reset_ggtt(vgpu, false);
24302419

2420+
INIT_LIST_HEAD(&gtt->ggtt_mm->ggtt_mm.partial_pte_list);
2421+
24312422
return create_scratch_page_tree(vgpu);
24322423
}
24332424

@@ -2452,6 +2443,14 @@ static void intel_vgpu_destroy_all_ppgtt_mm(struct intel_vgpu *vgpu)
24522443

24532444
static void intel_vgpu_destroy_ggtt_mm(struct intel_vgpu *vgpu)
24542445
{
2446+
struct intel_gvt_partial_pte *pos;
2447+
2448+
list_for_each_entry(pos,
2449+
&vgpu->gtt.ggtt_mm->ggtt_mm.partial_pte_list, list) {
2450+
gvt_dbg_mm("partial PTE update on hold 0x%lx : 0x%llx\n",
2451+
pos->offset, pos->data);
2452+
kfree(pos);
2453+
}
24552454
intel_vgpu_destroy_mm(vgpu->gtt.ggtt_mm);
24562455
vgpu->gtt.ggtt_mm = NULL;
24572456
}

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ enum intel_gvt_mm_type {
133133

134134
#define GVT_RING_CTX_NR_PDPS GEN8_3LVL_PDPES
135135

136+
struct intel_gvt_partial_pte {
137+
unsigned long offset;
138+
u64 data;
139+
struct list_head list;
140+
};
141+
136142
struct intel_vgpu_mm {
137143
enum intel_gvt_mm_type type;
138144
struct intel_vgpu *vgpu;
@@ -157,8 +163,7 @@ struct intel_vgpu_mm {
157163
} ppgtt_mm;
158164
struct {
159165
void *virtual_ggtt;
160-
unsigned long last_partial_off;
161-
u64 last_partial_data;
166+
struct list_head partial_pte_list;
162167
} ggtt_mm;
163168
};
164169
};

0 commit comments

Comments
 (0)