drm/gpusvm: refactor core API to use pages struct
Refactor the core API of get/unmap/free pages to all operate on drm_gpusvm_pages. In the next patch we want to export a simplified core API without needing fully blown svm range etc. Suggested-by: Matthew Brost <matthew.brost@intel.com> Signed-off-by: Matthew Auld <matthew.auld@intel.com> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com> Reviewed-by: Matthew Brost <matthew.brost@intel.com> Link: https://lore.kernel.org/r/20250828142430.615826-14-matthew.auld@intel.com
This commit is contained in:
@@ -980,19 +980,18 @@ err_mmunlock:
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_range_find_or_insert);
|
||||
|
||||
/**
|
||||
* __drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range (internal)
|
||||
* __drm_gpusvm_unmap_pages() - Unmap pages associated with GPU SVM pages (internal)
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
* @range: Pointer to the GPU SVM range structure
|
||||
* @svm_pages: Pointer to the GPU SVM pages structure
|
||||
* @npages: Number of pages to unmap
|
||||
*
|
||||
* This function unmap pages associated with a GPU SVM range. Assumes and
|
||||
* This function unmap pages associated with a GPU SVM pages struct. Assumes and
|
||||
* asserts correct locking is in place when called.
|
||||
*/
|
||||
static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range,
|
||||
unsigned long npages)
|
||||
static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_pages *svm_pages,
|
||||
unsigned long npages)
|
||||
{
|
||||
struct drm_gpusvm_pages *svm_pages = &range->pages;
|
||||
struct drm_pagemap *dpagemap = svm_pages->dpagemap;
|
||||
struct device *dev = gpusvm->drm->dev;
|
||||
unsigned long i, j;
|
||||
@@ -1028,17 +1027,15 @@ static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_gpusvm_range_free_pages() - Free pages associated with a GPU SVM range
|
||||
* __drm_gpusvm_free_pages() - Free dma array associated with GPU SVM pages
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
* @range: Pointer to the GPU SVM range structure
|
||||
* @svm_pages: Pointer to the GPU SVM pages structure
|
||||
*
|
||||
* This function frees the dma address array associated with a GPU SVM range.
|
||||
*/
|
||||
static void drm_gpusvm_range_free_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range)
|
||||
static void __drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_pages *svm_pages)
|
||||
{
|
||||
struct drm_gpusvm_pages *svm_pages = &range->pages;
|
||||
|
||||
lockdep_assert_held(&gpusvm->notifier_lock);
|
||||
|
||||
if (svm_pages->dma_addr) {
|
||||
@@ -1072,8 +1069,8 @@ void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm,
|
||||
return;
|
||||
|
||||
drm_gpusvm_notifier_lock(gpusvm);
|
||||
__drm_gpusvm_range_unmap_pages(gpusvm, range, npages);
|
||||
drm_gpusvm_range_free_pages(gpusvm, range);
|
||||
__drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages);
|
||||
__drm_gpusvm_free_pages(gpusvm, &range->pages);
|
||||
__drm_gpusvm_range_remove(notifier, range);
|
||||
drm_gpusvm_notifier_unlock(gpusvm);
|
||||
|
||||
@@ -1138,6 +1135,28 @@ void drm_gpusvm_range_put(struct drm_gpusvm_range *range)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_range_put);
|
||||
|
||||
/**
|
||||
* drm_gpusvm_pages_valid() - GPU SVM range pages valid
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
* @svm_pages: Pointer to the GPU SVM pages structure
|
||||
*
|
||||
* This function determines if a GPU SVM range pages are valid. Expected be
|
||||
* called holding gpusvm->notifier_lock and as the last step before committing a
|
||||
* GPU binding. This is akin to a notifier seqno check in the HMM documentation
|
||||
* but due to wider notifiers (i.e., notifiers which span multiple ranges) this
|
||||
* function is required for finer grained checking (i.e., per range) if pages
|
||||
* are valid.
|
||||
*
|
||||
* Return: True if GPU SVM range has valid pages, False otherwise
|
||||
*/
|
||||
static bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_pages *svm_pages)
|
||||
{
|
||||
lockdep_assert_held(&gpusvm->notifier_lock);
|
||||
|
||||
return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_gpusvm_range_pages_valid() - GPU SVM range pages valid
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
@@ -1155,11 +1174,7 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_put);
|
||||
bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range)
|
||||
{
|
||||
struct drm_gpusvm_pages *svm_pages = &range->pages;
|
||||
|
||||
lockdep_assert_held(&gpusvm->notifier_lock);
|
||||
|
||||
return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping;
|
||||
return drm_gpusvm_pages_valid(gpusvm, &range->pages);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid);
|
||||
|
||||
@@ -1173,57 +1188,59 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid);
|
||||
*
|
||||
* Return: True if GPU SVM range has valid pages, False otherwise
|
||||
*/
|
||||
static bool
|
||||
drm_gpusvm_range_pages_valid_unlocked(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range)
|
||||
static bool drm_gpusvm_pages_valid_unlocked(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_pages *svm_pages)
|
||||
{
|
||||
struct drm_gpusvm_pages *svm_pages = &range->pages;
|
||||
bool pages_valid;
|
||||
|
||||
if (!svm_pages->dma_addr)
|
||||
return false;
|
||||
|
||||
drm_gpusvm_notifier_lock(gpusvm);
|
||||
pages_valid = drm_gpusvm_range_pages_valid(gpusvm, range);
|
||||
pages_valid = drm_gpusvm_pages_valid(gpusvm, svm_pages);
|
||||
if (!pages_valid)
|
||||
drm_gpusvm_range_free_pages(gpusvm, range);
|
||||
__drm_gpusvm_free_pages(gpusvm, svm_pages);
|
||||
drm_gpusvm_notifier_unlock(gpusvm);
|
||||
|
||||
return pages_valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
|
||||
* drm_gpusvm_get_pages() - Get pages and populate GPU SVM pages struct
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
* @range: Pointer to the GPU SVM range structure
|
||||
* @svm_pages: The SVM pages to populate. This will contain the dma-addresses
|
||||
* @mm: The mm corresponding to the CPU range
|
||||
* @notifier: The corresponding notifier for the given CPU range
|
||||
* @pages_start: Start CPU address for the pages
|
||||
* @pages_end: End CPU address for the pages (exclusive)
|
||||
* @ctx: GPU SVM context
|
||||
*
|
||||
* This function gets pages for a GPU SVM range and ensures they are mapped for
|
||||
* DMA access.
|
||||
* This function gets and maps pages for CPU range and ensures they are
|
||||
* mapped for DMA access.
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range,
|
||||
const struct drm_gpusvm_ctx *ctx)
|
||||
static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_pages *svm_pages,
|
||||
struct mm_struct *mm,
|
||||
struct mmu_interval_notifier *notifier,
|
||||
unsigned long pages_start,
|
||||
unsigned long pages_end,
|
||||
const struct drm_gpusvm_ctx *ctx)
|
||||
{
|
||||
struct drm_gpusvm_pages *svm_pages = &range->pages;
|
||||
struct mmu_interval_notifier *notifier = &range->notifier->notifier;
|
||||
struct hmm_range hmm_range = {
|
||||
.default_flags = HMM_PFN_REQ_FAULT | (ctx->read_only ? 0 :
|
||||
HMM_PFN_REQ_WRITE),
|
||||
.notifier = notifier,
|
||||
.start = drm_gpusvm_range_start(range),
|
||||
.end = drm_gpusvm_range_end(range),
|
||||
.start = pages_start,
|
||||
.end = pages_end,
|
||||
.dev_private_owner = gpusvm->device_private_page_owner,
|
||||
};
|
||||
struct mm_struct *mm = gpusvm->mm;
|
||||
void *zdd;
|
||||
unsigned long timeout =
|
||||
jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
|
||||
unsigned long i, j;
|
||||
unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
|
||||
drm_gpusvm_range_end(range));
|
||||
unsigned long npages = npages_in_range(pages_start, pages_end);
|
||||
unsigned long num_dma_mapped;
|
||||
unsigned int order = 0;
|
||||
unsigned long *pfns;
|
||||
@@ -1236,7 +1253,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
|
||||
|
||||
retry:
|
||||
hmm_range.notifier_seq = mmu_interval_read_begin(notifier);
|
||||
if (drm_gpusvm_range_pages_valid_unlocked(gpusvm, range))
|
||||
if (drm_gpusvm_pages_valid_unlocked(gpusvm, svm_pages))
|
||||
goto set_seqno;
|
||||
|
||||
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
|
||||
@@ -1390,7 +1407,7 @@ set_seqno:
|
||||
return 0;
|
||||
|
||||
err_unmap:
|
||||
__drm_gpusvm_range_unmap_pages(gpusvm, range, num_dma_mapped);
|
||||
__drm_gpusvm_unmap_pages(gpusvm, svm_pages, num_dma_mapped);
|
||||
drm_gpusvm_notifier_unlock(gpusvm);
|
||||
err_free:
|
||||
kvfree(pfns);
|
||||
@@ -1398,8 +1415,58 @@ err_free:
|
||||
goto retry;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
* @range: Pointer to the GPU SVM range structure
|
||||
* @ctx: GPU SVM context
|
||||
*
|
||||
* This function gets pages for a GPU SVM range and ensures they are mapped for
|
||||
* DMA access.
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range,
|
||||
const struct drm_gpusvm_ctx *ctx)
|
||||
{
|
||||
return drm_gpusvm_get_pages(gpusvm, &range->pages, gpusvm->mm,
|
||||
&range->notifier->notifier,
|
||||
drm_gpusvm_range_start(range),
|
||||
drm_gpusvm_range_end(range), ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages);
|
||||
|
||||
/**
|
||||
* drm_gpusvm_unmap_pages() - Unmap GPU svm pages
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
* @svm_pages: Pointer to the GPU SVM pages structure
|
||||
* @npages: Number of pages in @svm_pages.
|
||||
* @ctx: GPU SVM context
|
||||
*
|
||||
* This function unmaps pages associated with a GPU SVM pages struct. If
|
||||
* @in_notifier is set, it is assumed that gpusvm->notifier_lock is held in
|
||||
* write mode; if it is clear, it acquires gpusvm->notifier_lock in read mode.
|
||||
* Must be called in the invalidate() callback of the corresponding notifier for
|
||||
* IOMMU security model.
|
||||
*/
|
||||
static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_pages *svm_pages,
|
||||
unsigned long npages,
|
||||
const struct drm_gpusvm_ctx *ctx)
|
||||
{
|
||||
if (ctx->in_notifier)
|
||||
lockdep_assert_held_write(&gpusvm->notifier_lock);
|
||||
else
|
||||
drm_gpusvm_notifier_lock(gpusvm);
|
||||
|
||||
__drm_gpusvm_unmap_pages(gpusvm, svm_pages, npages);
|
||||
|
||||
if (!ctx->in_notifier)
|
||||
drm_gpusvm_notifier_unlock(gpusvm);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
@@ -1419,15 +1486,7 @@ void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
|
||||
unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
|
||||
drm_gpusvm_range_end(range));
|
||||
|
||||
if (ctx->in_notifier)
|
||||
lockdep_assert_held_write(&gpusvm->notifier_lock);
|
||||
else
|
||||
drm_gpusvm_notifier_lock(gpusvm);
|
||||
|
||||
__drm_gpusvm_range_unmap_pages(gpusvm, range, npages);
|
||||
|
||||
if (!ctx->in_notifier)
|
||||
drm_gpusvm_notifier_unlock(gpusvm);
|
||||
return drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages, ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_range_unmap_pages);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user