[RFC 06/13] drm/i915/svm: Page table mirroring support

Jason Gunthorpe jgg at mellanox.com
Fri Nov 22 23:33:12 UTC 2019


On Fri, Nov 22, 2019 at 12:57:27PM -0800, Niranjana Vishwanathapura wrote:

> +static inline bool
> +i915_range_done(struct hmm_range *range)
> +{
> +	bool ret = hmm_range_valid(range);
> +
> +	hmm_range_unregister(range);
> +	return ret;
> +}

This needs to be updated to follow the new API, but this pattern is
generally wrong, failure if hmm_range_valid should retry the
range_fault and so forth. See the hmm.rst.

> +static int
> +i915_range_fault(struct i915_svm *svm, struct hmm_range *range)
> +{
> +	long ret;
> +
> +	range->default_flags = 0;
> +	range->pfn_flags_mask = -1UL;
> +
> +	ret = hmm_range_register(range, &svm->mirror);
> +	if (ret) {
> +		up_read(&svm->mm->mmap_sem);
> +		return (int)ret;
> +	}


Using a temporary range is the pattern from nouveau, is it really
necessary in this driver?

> +static u32 i915_svm_build_sg(struct i915_address_space *vm,
> +			     struct hmm_range *range,
> +			     struct sg_table *st)
> +{
> +	struct scatterlist *sg;
> +	u32 sg_page_sizes = 0;
> +	u64 i, npages;
> +
> +	sg = NULL;
> +	st->nents = 0;
> +	npages = (range->end - range->start) / PAGE_SIZE;
> +
> +	/*
> +	 * No needd to dma map the host pages and later unmap it, as
> +	 * GPU is not allowed to access it with SVM. Hence, no need
> +	 * of any intermediate data strucutre to hold the mappings.
> +	 */
> +	for (i = 0; i < npages; i++) {
> +		u64 addr = range->pfns[i] & ~((1UL << range->pfn_shift) - 1);
> +
> +		if (sg && (addr == (sg_dma_address(sg) + sg->length))) {
> +			sg->length += PAGE_SIZE;
> +			sg_dma_len(sg) += PAGE_SIZE;
> +			continue;
> +		}
> +
> +		if (sg)
> +			sg_page_sizes |= sg->length;
> +
> +		sg =  sg ? __sg_next(sg) : st->sgl;
> +		sg_dma_address(sg) = addr;
> +		sg_dma_len(sg) = PAGE_SIZE;
> +		sg->length = PAGE_SIZE;
> +		st->nents++;

It is odd to build the range into a sgl.

IMHO it is not a good idea to use the sg_dma_address like this, that
should only be filled in by a dma map. Where does it end up being
used?

> +	range.pfn_shift = PAGE_SHIFT;
> +	range.start = args->start;
> +	range.flags = i915_range_flags;
> +	range.values = i915_range_values;
> +	range.end = range.start + args->length;
> +	for (i = 0; i < npages; ++i) {
> +		range.pfns[i] = range.flags[HMM_PFN_VALID];
> +		if (!(args->flags & I915_BIND_READONLY))
> +			range.pfns[i] |= range.flags[HMM_PFN_WRITE];
> +	}
> +
> +	down_read(&svm->mm->mmap_sem);
> +	vma = find_vma(svm->mm, range.start);

Why is find_vma needed?

> +	if (unlikely(!vma || vma->vm_end < range.end)) {
> +		ret = -EFAULT;
> +		goto vma_done;
> +	}
> +again:
> +	ret = i915_range_fault(svm, &range);
> +	if (unlikely(ret))
> +		goto vma_done;
> +
> +	sg_page_sizes = i915_svm_build_sg(vm, &range, &st);
>

Keep in mind what can be done with the range values is limited until
the lock is obtained. Reading the pfns and flags is OK though.

> +int i915_svm_bind_mm(struct i915_address_space *vm)
> +{
> +	struct i915_svm *svm;
> +	struct mm_struct *mm;
> +	int ret = 0;
> +
> +	mm = get_task_mm(current);

I don't think the get_task_mm(current) is needed, the mmget is already
done for current->mm ?

Jason


More information about the dri-devel mailing list