/** * i915_gem_userptr_invalidate - callback to notify about mm change * * @mni: the range (mm) is about to update * @range: details on the invalidation * @cur_seq: Value to pass to mmu_interval_set_seq() * * Block for operations on BOs to finish and mark pages as accessed and * potentially dirty.
*/ staticbool i915_gem_userptr_invalidate(struct mmu_interval_notifier *mni, conststruct mmu_notifier_range *range, unsignedlong cur_seq)
{
mmu_interval_set_seq(mni, cur_seq); returntrue;
}
/* * We always mark objects as dirty when they are used by the GPU, * just in case. However, if we set the vma as being read-only we know * that the object will never have been written to.
*/ if (i915_gem_object_is_readonly(obj))
obj->mm.dirty = false;
for_each_sgt_page(page, sgt_iter, pages) { if (obj->mm.dirty && trylock_page(page)) { /* * As this may not be anonymous memory (e.g. shmem) * but exist on a real mapping, we have to lock * the page in order to dirty it -- holding * the page reference is not sufficient to * prevent the inode from being truncated. * Play safe and take the lock. * * However...! * * The mmu-notifier can be invalidated for a * migrate_folio, that is alreadying holding the lock * on the folio. Such a try_to_unmap() will result * in us calling put_pages() and so recursively try * to lock the page. We avoid that deadlock with * a trylock_page() and in exchange we risk missing * some page dirtying.
*/
set_page_dirty(page);
unlock_page(page);
}
if (!i915_gem_object_is_readonly(obj))
gup_flags |= FOLL_WRITE;
pinned = 0; while (pinned < num_pages) {
ret = pin_user_pages_fast(obj->userptr.ptr + pinned * PAGE_SIZE,
num_pages - pinned, gup_flags,
&pvec[pinned]); if (ret < 0) goto out;
pinned += ret;
}
ret = i915_gem_object_lock_interruptible(obj, NULL); if (ret) goto out;
if (mmu_interval_read_retry(&obj->userptr.notifier,
!obj->userptr.page_ref ? notifier_seq :
obj->userptr.notifier_seq)) {
ret = -EAGAIN; goto out_unlock;
}
if (!obj->userptr.page_ref++) {
obj->userptr.pvec = pvec;
obj->userptr.notifier_seq = notifier_seq;
pvec = NULL;
ret = ____i915_gem_object_get_pages(obj);
}
obj->userptr.page_ref--;
out_unlock:
i915_gem_object_unlock(obj);
out: if (pvec) {
unpin_user_pages(pvec, pinned);
kvfree(pvec);
}
return ret;
}
int i915_gem_object_userptr_submit_done(struct drm_i915_gem_object *obj)
{ if (mmu_interval_read_retry(&obj->userptr.notifier,
obj->userptr.notifier_seq)) { /* We collided with the mmu notifier, need to retry */
return -EAGAIN;
}
return 0;
}
int i915_gem_object_userptr_validate(struct drm_i915_gem_object *obj)
{ int err;
err = i915_gem_object_userptr_submit_init(obj); if (err) return err;
err = i915_gem_object_lock_interruptible(obj, NULL); if (!err) { /* * Since we only check validity, not use the pages, * it doesn't matter if we collide with the mmu notifier, * and -EAGAIN handling is not required.
*/
err = i915_gem_object_pin_pages(obj); if (!err)
i915_gem_object_unpin_pages(obj);
mmap_read_lock(mm);
for_each_vma_range(vmi, vma, end) { /* 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;
/* * Creates a new mm object that wraps some normal memory from the process * context - user memory. * * We impose several restrictions upon the memory being mapped * into the GPU. * 1. It must be page aligned (both start/end addresses, i.e ptr and size). * 2. It must be normal system memory, not a pointer into another map of IO * space (e.g. it must not be a GTT mmapping of another object). * 3. We only allow a bo as large as we could in theory map into the GTT, * that is we limit the size to the total size of the GTT. * 4. The bo is marked as being snoopable. The backing pages are left * accessible directly by the CPU, but reads and writes by the GPU may * incur the cost of a snoop (unless you have an LLC architecture). * * Synchronisation between multiple users and the GPU is left to userspace * through the normal set-domain-ioctl. The kernel will enforce that the * GPU relinquishes the VMA before it is returned back to the system * i.e. upon free(), munmap() or process termination. However, the userspace * malloc() library may not immediately relinquish the VMA after free() and * instead reuse it whilst the GPU is still reading and writing to the VMA. * Caveat emptor. * * Also note, that the object created here is not currently a "first class" * object, in that several ioctls are banned. These are the CPU access * ioctls: mmap(), pwrite and pread. In practice, you are expected to use * direct access via your pointer rather than use those ioctls. Another * restriction is that we do not allow userptr surfaces to be pinned to the * hardware and so we reject any attempt to create a framebuffer out of a * userptr. * * If you think this is a good interface to use to pass GPU memory between * drivers, please use dma-buf instead. In fact, wherever possible use * dma-buf instead.
*/ int
i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
{ staticstruct lock_class_key __maybe_unused lock_class; struct drm_i915_private *i915 = to_i915(dev); struct drm_i915_gem_userptr *args = data; struct drm_i915_gem_object __maybe_unused *obj; int __maybe_unused ret;
u32 __maybe_unused handle;
if (!HAS_LLC(i915) && !HAS_SNOOP(i915)) { /* We cannot support coherent userptr objects on hw without * LLC and broken snooping.
*/ return -ENODEV;
}
if (args->flags & ~(I915_USERPTR_READ_ONLY |
I915_USERPTR_UNSYNCHRONIZED |
I915_USERPTR_PROBE)) return -EINVAL;
if (i915_gem_object_size_2big(args->user_size)) return -E2BIG;
if (!args->user_size) return -EINVAL;
if (offset_in_page(args->user_ptr | args->user_size)) return -EINVAL;
if (!access_ok((char __user *)(unsignedlong)args->user_ptr, args->user_size)) return -EFAULT;
if (args->flags & I915_USERPTR_UNSYNCHRONIZED) return -ENODEV;
if (args->flags & I915_USERPTR_READ_ONLY) { /* * On almost all of the older hw, we cannot tell the GPU that * a page is readonly.
*/ if (!to_gt(i915)->vm->has_read_only) 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;
}
/* And keep a pointer to the current->mm for resolving the user pages * at binding. This means that we need to hook into the mmu_notifier * in order to detect if the mmu is destroyed.
*/
ret = i915_gem_userptr_init__mmu_notifier(obj); if (ret == 0)
ret = drm_gem_handle_create(file, &obj->base, &handle);
/* drop reference from allocate - handle holds it now */
i915_gem_object_put(obj); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.