drm/gpusvm: embed struct drm_device into drm_gpusvm_pages

drm_gpusvm_pages is the layer that actually represents physical
pages/mappings it owns the dma_addr array, the dma_iova_state...
With the previous patch, so drm_gpusvm_pages is now strictly about
physical pages and their DMA view.

Since now the drm_gpusvm_pages instance is inherently bound to one
specific drm_device, make that ownership explicit by giving
drm_gpusvm_pages its own drm_device handle, and drive all DMA through
it instead of through the gpusvm:

  - Add drm to struct drm_gpusvm_pages and route all DMA in
    drm_gpusvm_get_pages() / __drm_gpusvm_unmap_pages() through
    svm_pages->drm instead of gpusvm->drm.
  - Bind svm_pages->drm where the pages object is initialised
    (drm_gpusvm_range_alloc() and the xe userptr setup) and require
    it to be set on entry to drm_gpusvm_get_pages(); the dma device
    is immutable for the lifetime of the pages instance. A later
    patch introduces drm_gpusvm_init_pages() to centralise this.

Suggested-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Honglei Huang <honghuan@amd.com>
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Link: https://patch.msgid.link/20260630102127.392396-3-honghuan@amd.com
This commit is contained in:
Honglei Huang 2026-06-30 18:21:24 +08:00 committed by Matthew Brost
parent ba40db3697
commit 1d0c4c15c2
3 changed files with 24 additions and 10 deletions

View File

@ -641,6 +641,7 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm,
range->itree.last = ALIGN(fault_addr + 1, chunk_size) - 1;
INIT_LIST_HEAD(&range->entry);
range->pages.notifier_seq = LONG_MAX;
range->pages.drm = gpusvm->drm;
range->flags.migrate_devmem = migrate_devmem ? 1 : 0;
return range;
@ -1135,11 +1136,16 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
unsigned long npages)
{
struct drm_pagemap *dpagemap = svm_pages->dpagemap;
struct device *dev = gpusvm->drm->dev;
struct device *dev;
unsigned long i, j;
lockdep_assert_held(&gpusvm->notifier_lock);
if (!svm_pages->drm)
return;
dev = svm_pages->drm->dev;
if (svm_pages->flags.has_dma_mapping) {
struct drm_gpusvm_pages_flags flags = {
.__flags = svm_pages->flags.__flags,
@ -1421,6 +1427,9 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
DMA_BIDIRECTIONAL;
struct dma_iova_state *state = &svm_pages->state;
if (!svm_pages->drm)
return -EINVAL;
retry:
if (time_after(jiffies, timeout))
return -EBUSY;
@ -1520,7 +1529,7 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
pagemap = page_pgmap(page);
dpagemap = drm_pagemap_page_to_dpagemap(page);
if (drm_WARN_ON(gpusvm->drm, !dpagemap)) {
if (drm_WARN_ON(svm_pages->drm, !dpagemap)) {
/*
* Raced. This is not supposed to happen
* since hmm_range_fault() should've migrated
@ -1532,10 +1541,10 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
}
svm_pages->dma_addr[j] =
dpagemap->ops->device_map(dpagemap,
gpusvm->drm->dev,
svm_pages->drm->dev,
page, order,
dma_dir);
if (dma_mapping_error(gpusvm->drm->dev,
if (dma_mapping_error(svm_pages->drm->dev,
svm_pages->dma_addr[j].addr)) {
err = -EFAULT;
goto err_unmap;
@ -1555,11 +1564,11 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
}
if (!i)
dma_iova_try_alloc(gpusvm->drm->dev, state,
dma_iova_try_alloc(svm_pages->drm->dev, state,
0, npages * PAGE_SIZE);
if (dma_use_iova(state)) {
err = dma_iova_link(gpusvm->drm->dev, state,
err = dma_iova_link(svm_pages->drm->dev, state,
hmm_pfn_to_phys(pfns[i]),
svm_pages->state_offset,
PAGE_SIZE << order,
@ -1570,11 +1579,11 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
addr = state->addr + svm_pages->state_offset;
svm_pages->state_offset += PAGE_SIZE << order;
} else {
addr = dma_map_page(gpusvm->drm->dev,
addr = dma_map_page(svm_pages->drm->dev,
page, 0,
PAGE_SIZE << order,
dma_dir);
if (dma_mapping_error(gpusvm->drm->dev, addr)) {
if (dma_mapping_error(svm_pages->drm->dev, addr)) {
err = -EFAULT;
goto err_unmap;
}
@ -1590,7 +1599,7 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
}
if (dma_use_iova(state)) {
err = dma_iova_sync(gpusvm->drm->dev, state, 0,
err = dma_iova_sync(svm_pages->drm->dev, state, 0,
svm_pages->state_offset);
if (err)
goto err_unmap;
@ -1640,7 +1649,8 @@ 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,
return drm_gpusvm_get_pages(gpusvm, &range->pages,
gpusvm->mm,
&range->notifier->notifier,
drm_gpusvm_range_start(range),
drm_gpusvm_range_end(range), ctx);

View File

@ -390,6 +390,7 @@ int xe_userptr_setup(struct xe_userptr_vma *uvma, unsigned long start,
unsigned long range)
{
struct xe_userptr *userptr = &uvma->userptr;
struct xe_vm *vm = xe_vma_vm(&uvma->vma);
int err;
INIT_LIST_HEAD(&userptr->invalidate_link);
@ -402,6 +403,7 @@ int xe_userptr_setup(struct xe_userptr_vma *uvma, unsigned long start,
return err;
userptr->pages.notifier_seq = LONG_MAX;
userptr->pages.drm = &vm->xe->drm;
return 0;
}

View File

@ -129,6 +129,7 @@ struct drm_gpusvm_pages_flags {
/**
* struct drm_gpusvm_pages - Structure representing a GPU SVM mapped pages
*
* @drm: The DRM device that owns the dma mappings
* @dma_addr: Device address array
* @dpagemap: The struct drm_pagemap of the device pages we're dma-mapping.
* Note this is assuming only one drm_pagemap per range is allowed.
@ -138,6 +139,7 @@ struct drm_gpusvm_pages_flags {
* @flags: Flags for the range; see &struct drm_gpusvm_pages_flags
*/
struct drm_gpusvm_pages {
struct drm_device *drm;
struct drm_pagemap_addr *dma_addr;
struct drm_pagemap *dpagemap;
struct dma_iova_state state;