Idea is to use this for userptr, where we mostly just need get/unmap/free pages, plus some kind of common notifier lock at the svm level (provided by gpusvm). The range itself also maps to a single notifier, covering the entire range (provided by the user).
TODO: needs proper kernel-doc, assuming this change makes sense. Signed-off-by: Matthew Auld <matthew.a...@intel.com> Cc: Thomas Hellström <thomas.hellst...@linux.intel.com> Cc: Matthew Brost <matthew.br...@intel.com> --- drivers/gpu/drm/drm_gpusvm.c | 138 +++++++++++++++++++++++++++++------ include/drm/drm_gpusvm.h | 23 ++++++ 2 files changed, 137 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index 2beca5a6dc0a..ca571610214c 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -521,6 +521,41 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = { .invalidate = drm_gpusvm_notifier_invalidate, }; +static void __drm_gpusvm_init(struct drm_gpusvm *gpusvm, const char *name, + struct drm_device *drm, struct mm_struct *mm, + void *device_private_page_owner, + unsigned long mm_start, unsigned long mm_range, + unsigned long notifier_size, + const struct drm_gpusvm_ops *ops, + const unsigned long *chunk_sizes, int num_chunks) +{ + gpusvm->name = name; + gpusvm->drm = drm; + gpusvm->mm = mm; + gpusvm->device_private_page_owner = device_private_page_owner; + gpusvm->mm_start = mm_start; + gpusvm->mm_range = mm_range; + gpusvm->notifier_size = notifier_size; + gpusvm->ops = ops; + gpusvm->chunk_sizes = chunk_sizes; + gpusvm->num_chunks = num_chunks; + + if (mm) + mmgrab(mm); + gpusvm->root = RB_ROOT_CACHED; + INIT_LIST_HEAD(&gpusvm->notifier_list); + + init_rwsem(&gpusvm->notifier_lock); + + fs_reclaim_acquire(GFP_KERNEL); + might_lock(&gpusvm->notifier_lock); + fs_reclaim_release(GFP_KERNEL); + +#ifdef CONFIG_LOCKDEP + gpusvm->lock_dep_map = NULL; +#endif +} + /** * drm_gpusvm_init() - Initialize the GPU SVM. * @gpusvm: Pointer to the GPU SVM structure. @@ -552,35 +587,32 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm, if (!ops->invalidate || !num_chunks) return -EINVAL; - gpusvm->name = name; - gpusvm->drm = drm; - gpusvm->mm = mm; - gpusvm->device_private_page_owner = device_private_page_owner; - gpusvm->mm_start = mm_start; - gpusvm->mm_range = mm_range; - gpusvm->notifier_size = notifier_size; - gpusvm->ops = ops; - gpusvm->chunk_sizes = chunk_sizes; - gpusvm->num_chunks = num_chunks; - - mmgrab(mm); - gpusvm->root = RB_ROOT_CACHED; - INIT_LIST_HEAD(&gpusvm->notifier_list); - - init_rwsem(&gpusvm->notifier_lock); - - fs_reclaim_acquire(GFP_KERNEL); - might_lock(&gpusvm->notifier_lock); - fs_reclaim_release(GFP_KERNEL); - -#ifdef CONFIG_LOCKDEP - gpusvm->lock_dep_map = NULL; -#endif + __drm_gpusvm_init(gpusvm, name, drm, mm, device_private_page_owner, + mm_start, mm_range, notifier_size, ops, chunk_sizes, + num_chunks); return 0; } EXPORT_SYMBOL_GPL(drm_gpusvm_init); +static bool drm_gpusvm_is_basic(struct drm_gpusvm *svm) +{ + return !svm->mm; +} + +void drm_gpusvm_basic_init(struct drm_gpusvm *gpusvm, const char *name, + struct drm_device *drm) +{ + __drm_gpusvm_init(gpusvm, name, drm, NULL, NULL, 0, 0, 0, NULL, NULL, + 0); +} +EXPORT_SYMBOL_GPL(drm_gpusvm_basic_init); + +void drm_gpusvm_basic_fini(struct drm_gpusvm *gpusvm) +{ +} +EXPORT_SYMBOL_GPL(drm_gpusvm_basic_fini); + /** * drm_gpusvm_notifier_find() - Find GPU SVM notifier * @gpusvm: Pointer to the GPU SVM structure @@ -1001,6 +1033,27 @@ static void drm_gpusvm_driver_lock_held(struct drm_gpusvm *gpusvm) } #endif +void drm_gpusvm_basic_range_init(struct drm_gpusvm *svm, + struct drm_gpusvm_basic_range *range, + struct mmu_interval_notifier *notifier, + unsigned long *notifier_seq) +{ + WARN_ON(!drm_gpusvm_is_basic(svm)); + + range->gpusvm = svm; + range->notifier = notifier; + range->notifier_seq = notifier_seq; + *notifier_seq = LONG_MAX; + memset(&range->pages, 0, sizeof(range->pages)); +} +EXPORT_SYMBOL_GPL(drm_gpusvm_basic_range_init); + +void drm_gpusvm_basic_range_fini(struct drm_gpusvm_basic_range *range) +{ + WARN_ON(range->pages.flags.has_dma_mapping); +} +EXPORT_SYMBOL_GPL(drm_gpusvm_basic_range_fini); + /** * drm_gpusvm_range_find_or_insert() - Find or insert GPU SVM range * @gpusvm: Pointer to the GPU SVM structure @@ -1176,6 +1229,19 @@ static void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm, } } +void drm_gpusvm_basic_range_free_pages(struct drm_gpusvm_basic_range *range) +{ + unsigned long npages = + npages_in_range(range->notifier->interval_tree.start, + range->notifier->interval_tree.last + 1); + + drm_gpusvm_notifier_lock(range->gpusvm); + __drm_gpusvm_unmap_pages(range->gpusvm, &range->pages, npages); + drm_gpusvm_free_pages(range->gpusvm, &range->pages); + drm_gpusvm_notifier_unlock(range->gpusvm); +} +EXPORT_SYMBOL_GPL(drm_gpusvm_basic_range_free_pages); + /** * drm_gpusvm_range_remove() - Remove GPU SVM range * @gpusvm: Pointer to the GPU SVM structure @@ -1545,6 +1611,20 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, } EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages); +int drm_gpusvm_basic_range_get_pages(struct drm_gpusvm_basic_range *range, + const struct drm_gpusvm_ctx *ctx) +{ + drm_gpusvm_driver_lock_held(range->gpusvm); + + return drm_gpusvm_get_pages(range->gpusvm, &range->pages, + range->notifier->mm, range->notifier, + range->notifier_seq, + range->notifier->interval_tree.start, + range->notifier->interval_tree.last + 1, + ctx); +} +EXPORT_SYMBOL_GPL(drm_gpusvm_basic_range_get_pages); + static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm, unsigned long mm_start, unsigned long mm_end, struct drm_gpusvm_pages *svm_pages, @@ -1585,6 +1665,16 @@ void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm, } EXPORT_SYMBOL_GPL(drm_gpusvm_range_unmap_pages); +void drm_gpusvm_basic_range_unmap_pages(struct drm_gpusvm_basic_range *range, + const struct drm_gpusvm_ctx *ctx) +{ + drm_gpusvm_unmap_pages(range->gpusvm, + range->notifier->interval_tree.start, + range->notifier->interval_tree.last + 1, + &range->pages, ctx); +} +EXPORT_SYMBOL_GPL(drm_gpusvm_basic_range_unmap_pages); + /** * drm_gpusvm_migration_unlock_put_page() - Put a migration page * @page: Pointer to the page to put diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h index c15c733ef0ad..82c4e58fa84c 100644 --- a/include/drm/drm_gpusvm.h +++ b/include/drm/drm_gpusvm.h @@ -305,6 +305,29 @@ struct drm_gpusvm_ctx { unsigned int devmem_possible :1; }; +struct drm_gpusvm_basic_range { + struct drm_gpusvm *gpusvm; + struct drm_gpusvm_pages pages; + struct mmu_interval_notifier *notifier; + unsigned long *notifier_seq; +}; + +void drm_gpusvm_basic_init(struct drm_gpusvm *gpusvm, const char *name, + struct drm_device *drm); +void drm_gpusvm_basic_fini(struct drm_gpusvm *gpusvm); + +void drm_gpusvm_basic_range_init(struct drm_gpusvm *svm, + struct drm_gpusvm_basic_range *range, + struct mmu_interval_notifier *notifier, + unsigned long *notifier_seq); +void drm_gpusvm_basic_range_fini(struct drm_gpusvm_basic_range *range); + +int drm_gpusvm_basic_range_get_pages(struct drm_gpusvm_basic_range *range, + const struct drm_gpusvm_ctx *ctx); +void drm_gpusvm_basic_range_unmap_pages(struct drm_gpusvm_basic_range *range, + const struct drm_gpusvm_ctx *ctx); +void drm_gpusvm_basic_range_free_pages(struct drm_gpusvm_basic_range *range); + int drm_gpusvm_init(struct drm_gpusvm *gpusvm, const char *name, struct drm_device *drm, struct mm_struct *mm, void *device_private_page_owner, -- 2.48.1