diff options
Diffstat (limited to 'drivers/gpu/drm/drm_gpusvm.c')
| -rw-r--r-- | drivers/gpu/drm/drm_gpusvm.c | 76 |
1 files changed, 67 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index 38431e8360e7..ab198645d90f 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -7,6 +7,7 @@ */ #include <linux/dma-mapping.h> +#include <linux/export.h> #include <linux/hmm.h> #include <linux/memremap.h> #include <linux/migrate.h> @@ -981,6 +982,40 @@ static void drm_gpusvm_driver_lock_held(struct drm_gpusvm *gpusvm) #endif /** + * drm_gpusvm_find_vma_start() - Find start address for first VMA in range + * @gpusvm: Pointer to the GPU SVM structure + * @start: The inclusive start user address. + * @end: The exclusive end user address. + * + * Returns: The start address of first VMA within the provided range, + * ULONG_MAX otherwise. Assumes start_addr < end_addr. + */ +unsigned long +drm_gpusvm_find_vma_start(struct drm_gpusvm *gpusvm, + unsigned long start, + unsigned long end) +{ + struct mm_struct *mm = gpusvm->mm; + struct vm_area_struct *vma; + unsigned long addr = ULONG_MAX; + + if (!mmget_not_zero(mm)) + return addr; + + mmap_read_lock(mm); + + vma = find_vma_intersection(mm, start, end); + if (vma) + addr = vma->vm_start; + + mmap_read_unlock(mm); + mmput(mm); + + return addr; +} +EXPORT_SYMBOL_GPL(drm_gpusvm_find_vma_start); + +/** * drm_gpusvm_range_find_or_insert() - Find or insert GPU SVM range * @gpusvm: Pointer to the GPU SVM structure * @fault_addr: Fault address @@ -1118,6 +1153,10 @@ static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm, lockdep_assert_held(&gpusvm->notifier_lock); if (range->flags.has_dma_mapping) { + struct drm_gpusvm_range_flags flags = { + .__flags = range->flags.__flags, + }; + for (i = 0, j = 0; i < npages; j++) { struct drm_pagemap_device_addr *addr = &range->dma_addr[j]; @@ -1131,8 +1170,12 @@ static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm, dev, *addr); i += 1 << addr->order; } - range->flags.has_devmem_pages = false; - range->flags.has_dma_mapping = false; + + /* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */ + flags.has_devmem_pages = false; + flags.has_dma_mapping = false; + WRITE_ONCE(range->flags.__flags, flags.__flags); + range->dpagemap = NULL; } } @@ -1330,10 +1373,10 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, unsigned long num_dma_mapped; unsigned int order = 0; unsigned long *pfns; - struct page **pages; int err = 0; struct dev_pagemap *pagemap; struct drm_pagemap *dpagemap; + struct drm_gpusvm_range_flags flags; retry: hmm_range.notifier_seq = mmu_interval_read_begin(notifier); @@ -1369,7 +1412,6 @@ retry: if (err) goto err_free; - pages = (struct page **)pfns; map_pages: /* * Perform all dma mappings under the notifier lock to not @@ -1378,7 +1420,8 @@ map_pages: */ drm_gpusvm_notifier_lock(gpusvm); - if (range->flags.unmapped) { + flags.__flags = range->flags.__flags; + if (flags.unmapped) { drm_gpusvm_notifier_unlock(gpusvm); err = -EFAULT; goto err_free; @@ -1444,8 +1487,6 @@ map_pages: err = -EFAULT; goto err_unmap; } - - pages[i] = page; } else { dma_addr_t addr; @@ -1454,6 +1495,11 @@ map_pages: goto err_unmap; } + if (ctx->devmem_only) { + err = -EFAULT; + goto err_unmap; + } + addr = dma_map_page(gpusvm->drm->dev, page, 0, PAGE_SIZE << order, @@ -1469,14 +1515,17 @@ map_pages: } i += 1 << order; num_dma_mapped = i; + flags.has_dma_mapping = true; } - range->flags.has_dma_mapping = true; if (zdd) { - range->flags.has_devmem_pages = true; + flags.has_devmem_pages = true; range->dpagemap = dpagemap; } + /* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */ + WRITE_ONCE(range->flags.__flags, flags.__flags); + drm_gpusvm_notifier_unlock(gpusvm); kvfree(pfns); set_seqno: @@ -1765,6 +1814,8 @@ int drm_gpusvm_migrate_to_devmem(struct drm_gpusvm *gpusvm, goto err_finalize; /* Upon success bind devmem allocation to range and zdd */ + devmem_allocation->timeslice_expiration = get_jiffies_64() + + msecs_to_jiffies(ctx->timeslice_ms); zdd->devmem_allocation = devmem_allocation; /* Owns ref */ err_finalize: @@ -1985,6 +2036,13 @@ static int __drm_gpusvm_migrate_to_ram(struct vm_area_struct *vas, void *buf; int i, err = 0; + if (page) { + zdd = page->zone_device_data; + if (time_before64(get_jiffies_64(), + zdd->devmem_allocation->timeslice_expiration)) + return 0; + } + start = ALIGN_DOWN(fault_addr, size); end = ALIGN(fault_addr + 1, size); |
