[PATCH] drm/i915/gvt: support inconsecutive partial PTE update

Hang Yuan hang.yuan at linux.intel.com
Fri Sep 14 05:16:52 UTC 2018


On 09/13/2018 04:28 PM, Zhenyu Wang wrote:
> On 2018.09.13 15:51:19 +0800, intel-gvt-dev-bounces at lists.freedesktop.org wrote:
>> From: Hang Yuan <hang.yuan at linux.intel.com>
>>
>> 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 will enhance the previous solution. Use a list to save first
>> part of PTE. Find and combine a full PTE when the second part comes. Then
>> update the shadow PTE.
>>
>> Signed-off-by: Hang Yuan <hang.yuan at linux.intel.com>
>> Cc: Yan Zhao <yan.y.zhao at intel.com>
>> Cc: Xiaolin Zhang <xiaolin.zhang at intel.com>
>> Cc: Zhenyu Wang <zhenyu.z.wang at intel.com>
>> ---
>>   drivers/gpu/drm/i915/gvt/gtt.c | 106 ++++++++++++++++++++++-------------------
>>   drivers/gpu/drm/i915/gvt/gtt.h |   9 +++-
>>   2 files changed, 63 insertions(+), 52 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c
>> index 2402395..e02b568 100644
>> --- a/drivers/gpu/drm/i915/gvt/gtt.c
>> +++ b/drivers/gpu/drm/i915/gvt/gtt.c
>> @@ -1905,7 +1905,6 @@ static struct intel_vgpu_mm *intel_vgpu_create_ggtt_mm(struct intel_vgpu *vgpu)
>>   		vgpu_free_mm(mm);
>>   		return ERR_PTR(-ENOMEM);
>>   	}
>> -	mm->ggtt_mm.last_partial_off = -1UL;
>>   
>>   	return mm;
>>   }
>> @@ -1930,7 +1929,6 @@ void _intel_vgpu_mm_release(struct kref *mm_ref)
>>   		invalidate_ppgtt_mm(mm);
>>   	} else {
>>   		vfree(mm->ggtt_mm.virtual_ggtt);
>> -		mm->ggtt_mm.last_partial_off = -1UL;
>>   	}
>>   
>>   	vgpu_free_mm(mm);
>> @@ -2168,6 +2166,7 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
>>   	struct intel_gvt_gtt_entry e, m;
>>   	dma_addr_t dma_addr;
>>   	int ret;
>> +	struct intel_gvt_partial_pte *partial_pte, *pos, *n;
>>   
>>   	if (bytes != 4 && bytes != 8)
>>   		return -EINVAL;
>> @@ -2178,63 +2177,60 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
>>   	if (!vgpu_gmadr_is_valid(vgpu, gma))
>>   		return 0;
>>   
>> -	ggtt_get_guest_entry(ggtt_mm, &e, g_gtt_index);
>> -
>> +	e.type = GTT_TYPE_GGTT_PTE;
>>   	memcpy((void *)&e.val64 + (off & (info->gtt_entry_size - 1)), p_data,
>>   			bytes);
>>   
>>   	/* If ggtt entry size is 8 bytes, and it's split into two 4 bytes
>> -	 * write, we assume the two 4 bytes writes are consecutive.
>> -	 * Otherwise, we abort and report error
>> +	 * write, save the first 4 bytes in a list and update virtual
>> +	 * PTE. Only update shadow PTE when the second 4 bytes comes.
>>   	 */
>>   	if (bytes < info->gtt_entry_size) {
>> -		if (ggtt_mm->ggtt_mm.last_partial_off == -1UL) {
>> -			/* the first partial part*/
>> -			ggtt_mm->ggtt_mm.last_partial_off = off;
>> -			ggtt_mm->ggtt_mm.last_partial_data = e.val64;
>> -			return 0;
>> -		} else if ((g_gtt_index ==
>> -				(ggtt_mm->ggtt_mm.last_partial_off >>
>> -				info->gtt_entry_size_shift)) &&
>> -			(off !=	ggtt_mm->ggtt_mm.last_partial_off)) {
>> -			/* the second partial part */
>> -
>> -			int last_off = ggtt_mm->ggtt_mm.last_partial_off &
>> -				(info->gtt_entry_size - 1);
>> -
>> -			memcpy((void *)&e.val64 + last_off,
>> -				(void *)&ggtt_mm->ggtt_mm.last_partial_data +
>> -				last_off, bytes);
>> -
>> -			ggtt_mm->ggtt_mm.last_partial_off = -1UL;
>> -		} else {
>> -			int last_offset;
>> -
>> -			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",
>> -					ggtt_mm->ggtt_mm.last_partial_off, off,
>> -					bytes, info->gtt_entry_size);
>> -
>> -			/* set host ggtt entry to scratch page and clear
>> -			 * virtual ggtt entry as not present for last
>> -			 * partially write offset
>> -			 */
>> -			last_offset = ggtt_mm->ggtt_mm.last_partial_off &
>> -					(~(info->gtt_entry_size - 1));
>> -
>> -			ggtt_get_host_entry(ggtt_mm, &m, last_offset);
>> -			ggtt_invalidate_pte(vgpu, &m);
>> -			ops->set_pfn(&m, gvt->gtt.scratch_mfn);
>> -			ops->clear_present(&m);
>> -			ggtt_set_host_entry(ggtt_mm, &m, last_offset);
>> -			ggtt_invalidate(gvt->dev_priv);
>> +		bool found = false;
>> +
>> +		list_for_each_entry_safe(pos, n,
>> +				&ggtt_mm->ggtt_mm.partial_pte_list, list) {
>> +			if (g_gtt_index == pos->offset >>
>> +					info->gtt_entry_size_shift) {
>> +				if (off != pos->offset) {
>> +					/* the second partial part*/
>> +
>> +					int last_off = pos->offset &
>> +						(info->gtt_entry_size - 1);
>> +
>> +					memcpy((void *)&e.val64 + last_off,
>> +						(void *)&pos->data + last_off,
>> +						bytes);
>> +
>> +					list_del(&pos->list);
>> +					kfree(pos);
>> +				} else {
>> +					/* update of the first partial part */
>> +
>> +					pos->data = e.val64;
>> +					ggtt_set_guest_entry(ggtt_mm, &e,
>> +						g_gtt_index);
>> +					return 0;
>> +				}
>> +				found = true;
>> +				break;
>> +			}
>> +		}
>>   
>> -			ggtt_get_guest_entry(ggtt_mm, &e, last_offset);
>> -			ops->clear_present(&e);
>> -			ggtt_set_guest_entry(ggtt_mm, &e, last_offset);
>> +		if (!found) {
>> +			/* the first partial part */
>>   
>> -			ggtt_mm->ggtt_mm.last_partial_off = off;
>> -			ggtt_mm->ggtt_mm.last_partial_data = e.val64;
>> +			partial_pte = kzalloc(sizeof(*partial_pte), GFP_KERNEL);
>> +			if (!partial_pte)
>> +				return -ENOMEM;
>> +			partial_pte->offset = off;
>> +			partial_pte->data = e.val64;
>> +			list_add_tail(&partial_pte->list,
>> +				&ggtt_mm->ggtt_mm.partial_pte_list);
>>   
>> +			ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
>> +			ops->set_pfn(&e, gvt->gtt.scratch_mfn);
>> +			ggtt_set_host_entry(ggtt_mm, &e, g_gtt_index);
> 
> Looks this doesn't properly invalidate old entry and flush ggtt like old code did.

Yes, will fix it. Thanks for the comments.


More information about the intel-gvt-dev mailing list