drm/i915/userptr: Probe existence of backing struct pages upon creation
Jason Ekstrand requested a more efficient method than userptr+set-domain to determine if the userptr object was backed by a complete set of pages upon creation. To be more efficient than simply populating the userptr using get_user_pages() (as done by the call to set-domain or execbuf), we can walk the tree of vm_area_struct and check for gaps or vma not backed by struct page (VM_PFNMAP). The question is how to handle VM_MIXEDMAP which may be either struct page or pfn backed... With discrete we are going to drop support for set_domain(), so offering a way to probe the pages, without having to resort to dummy batches has been requested. v2: - add new query param for the PROBE flag, so userspace can easily check if the kernel supports it(Jason). - use mmap_read_{lock, unlock}. - add some kernel-doc. v3: - In the docs also mention that PROBE doesn't guarantee that the pages will remain valid by the time they are actually used(Tvrtko). - Add a small comment for the hole finding logic(Jason). - Move the param next to all the other params which just return true. Testcase: igt/gem_userptr_blits/probe Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Matthew Auld <matthew.auld@intel.com> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Kenneth Graunke <kenneth@whitecape.org> Cc: Jason Ekstrand <jason@jlekstrand.net> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Ramalingam C <ramalingam.c@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Acked-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Jason Ekstrand <jason@jlekstrand.net> Acked-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210723113405.427004-1-matthew.auld@intel.com
This commit is contained in:
parent
8e02cceb1f
commit
b65a948973
|
@ -422,6 +422,34 @@ static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = {
|
|||
|
||||
#endif
|
||||
|
||||
static int
|
||||
probe_range(struct mm_struct *mm, unsigned long addr, unsigned long len)
|
||||
{
|
||||
const unsigned long end = addr + len;
|
||||
struct vm_area_struct *vma;
|
||||
int ret = -EFAULT;
|
||||
|
||||
mmap_read_lock(mm);
|
||||
for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
|
||||
/* Check for holes, note that we also update the addr below */
|
||||
if (vma->vm_start > addr)
|
||||
break;
|
||||
|
||||
if (vma->vm_flags & (VM_PFNMAP | VM_MIXEDMAP))
|
||||
break;
|
||||
|
||||
if (vma->vm_end >= end) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
addr = vma->vm_end;
|
||||
}
|
||||
mmap_read_unlock(mm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new mm object that wraps some normal memory from the process
|
||||
* context - user memory.
|
||||
|
@ -477,7 +505,8 @@ i915_gem_userptr_ioctl(struct drm_device *dev,
|
|||
}
|
||||
|
||||
if (args->flags & ~(I915_USERPTR_READ_ONLY |
|
||||
I915_USERPTR_UNSYNCHRONIZED))
|
||||
I915_USERPTR_UNSYNCHRONIZED |
|
||||
I915_USERPTR_PROBE))
|
||||
return -EINVAL;
|
||||
|
||||
if (i915_gem_object_size_2big(args->user_size))
|
||||
|
@ -504,6 +533,16 @@ i915_gem_userptr_ioctl(struct drm_device *dev,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (args->flags & I915_USERPTR_PROBE) {
|
||||
/*
|
||||
* Check that the range pointed to represents real struct
|
||||
* pages and not iomappings (at this moment in time!)
|
||||
*/
|
||||
ret = probe_range(current->mm, args->user_ptr, args->user_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MMU_NOTIFIER
|
||||
obj = i915_gem_object_alloc();
|
||||
if (obj == NULL)
|
||||
|
|
|
@ -134,6 +134,7 @@ int i915_getparam_ioctl(struct drm_device *dev, void *data,
|
|||
case I915_PARAM_HAS_EXEC_FENCE_ARRAY:
|
||||
case I915_PARAM_HAS_EXEC_SUBMIT_FENCE:
|
||||
case I915_PARAM_HAS_EXEC_TIMELINE_FENCES:
|
||||
case I915_PARAM_HAS_USERPTR_PROBE:
|
||||
/* For the time being all of these are always true;
|
||||
* if some supported hardware does not have one of these
|
||||
* features this value needs to be provided from
|
||||
|
|
|
@ -683,6 +683,9 @@ typedef struct drm_i915_irq_wait {
|
|||
*/
|
||||
#define I915_PARAM_HAS_EXEC_TIMELINE_FENCES 55
|
||||
|
||||
/* Query if the kernel supports the I915_USERPTR_PROBE flag. */
|
||||
#define I915_PARAM_HAS_USERPTR_PROBE 56
|
||||
|
||||
/* Must be kept compact -- no holes and well documented */
|
||||
|
||||
typedef struct drm_i915_getparam {
|
||||
|
@ -2231,12 +2234,29 @@ struct drm_i915_gem_userptr {
|
|||
* through the GTT. If the HW can't support readonly access, an error is
|
||||
* returned.
|
||||
*
|
||||
* I915_USERPTR_PROBE:
|
||||
*
|
||||
* Probe the provided @user_ptr range and validate that the @user_ptr is
|
||||
* indeed pointing to normal memory and that the range is also valid.
|
||||
* For example if some garbage address is given to the kernel, then this
|
||||
* should complain.
|
||||
*
|
||||
* Returns -EFAULT if the probe failed.
|
||||
*
|
||||
* Note that this doesn't populate the backing pages, and also doesn't
|
||||
* guarantee that the object will remain valid when the object is
|
||||
* eventually used.
|
||||
*
|
||||
* The kernel supports this feature if I915_PARAM_HAS_USERPTR_PROBE
|
||||
* returns a non-zero value.
|
||||
*
|
||||
* I915_USERPTR_UNSYNCHRONIZED:
|
||||
*
|
||||
* NOT USED. Setting this flag will result in an error.
|
||||
*/
|
||||
__u32 flags;
|
||||
#define I915_USERPTR_READ_ONLY 0x1
|
||||
#define I915_USERPTR_PROBE 0x2
|
||||
#define I915_USERPTR_UNSYNCHRONIZED 0x80000000
|
||||
/**
|
||||
* @handle: Returned handle for the object.
|
||||
|
|
Loading…
Reference in New Issue