Skip to content

Commit e3d8b08

Browse files
Ralph CampbellBen Skeggs
authored andcommitted
drm/nouveau/svm: map pages after migration
When memory is migrated to the GPU, it is likely to be accessed by GPU code soon afterwards. Instead of waiting for a GPU fault, map the migrated memory into the GPU page tables with the same access permissions as the source CPU page table entries. This preserves copy on write semantics. Signed-off-by: Ralph Campbell <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: Jason Gunthorpe <[email protected]> Cc: "Jérôme Glisse" <[email protected]> Cc: Ben Skeggs <[email protected]> Signed-off-by: Ben Skeggs <[email protected]>
1 parent 9c1c08a commit e3d8b08

File tree

4 files changed

+95
-17
lines changed

4 files changed

+95
-17
lines changed

drivers/gpu/drm/nouveau/nouveau_dmem.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@
2525
#include "nouveau_dma.h"
2626
#include "nouveau_mem.h"
2727
#include "nouveau_bo.h"
28+
#include "nouveau_svm.h"
2829

2930
#include <nvif/class.h>
3031
#include <nvif/object.h>
3132
#include <nvif/if000c.h>
3233
#include <nvif/if500b.h>
3334
#include <nvif/if900b.h>
35+
#include <nvif/if000c.h>
3436

3537
#include <linux/sched/mm.h>
3638
#include <linux/hmm.h>
@@ -561,47 +563,54 @@ nouveau_dmem_init(struct nouveau_drm *drm)
561563
}
562564

563565
static unsigned long nouveau_dmem_migrate_copy_one(struct nouveau_drm *drm,
564-
unsigned long src, dma_addr_t *dma_addr)
566+
unsigned long src, dma_addr_t *dma_addr, u64 *pfn)
565567
{
566568
struct device *dev = drm->dev->dev;
567569
struct page *dpage, *spage;
570+
unsigned long paddr;
568571

569572
spage = migrate_pfn_to_page(src);
570573
if (!spage || !(src & MIGRATE_PFN_MIGRATE))
571574
goto out;
572575

573576
dpage = nouveau_dmem_page_alloc_locked(drm);
574577
if (!dpage)
575-
return 0;
578+
goto out;
576579

577580
*dma_addr = dma_map_page(dev, spage, 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
578581
if (dma_mapping_error(dev, *dma_addr))
579582
goto out_free_page;
580583

584+
paddr = nouveau_dmem_page_addr(dpage);
581585
if (drm->dmem->migrate.copy_func(drm, 1, NOUVEAU_APER_VRAM,
582-
nouveau_dmem_page_addr(dpage), NOUVEAU_APER_HOST,
583-
*dma_addr))
586+
paddr, NOUVEAU_APER_HOST, *dma_addr))
584587
goto out_dma_unmap;
585588

589+
*pfn = NVIF_VMM_PFNMAP_V0_V | NVIF_VMM_PFNMAP_V0_VRAM |
590+
((paddr >> PAGE_SHIFT) << NVIF_VMM_PFNMAP_V0_ADDR_SHIFT);
591+
if (src & MIGRATE_PFN_WRITE)
592+
*pfn |= NVIF_VMM_PFNMAP_V0_W;
586593
return migrate_pfn(page_to_pfn(dpage)) | MIGRATE_PFN_LOCKED;
587594

588595
out_dma_unmap:
589596
dma_unmap_page(dev, *dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
590597
out_free_page:
591598
nouveau_dmem_page_free_locked(drm, dpage);
592599
out:
600+
*pfn = NVIF_VMM_PFNMAP_V0_NONE;
593601
return 0;
594602
}
595603

596604
static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
597-
struct migrate_vma *args, dma_addr_t *dma_addrs)
605+
struct nouveau_svmm *svmm, struct migrate_vma *args,
606+
dma_addr_t *dma_addrs, u64 *pfns)
598607
{
599608
struct nouveau_fence *fence;
600609
unsigned long addr = args->start, nr_dma = 0, i;
601610

602611
for (i = 0; addr < args->end; i++) {
603612
args->dst[i] = nouveau_dmem_migrate_copy_one(drm, args->src[i],
604-
dma_addrs + nr_dma);
613+
dma_addrs + nr_dma, pfns + i);
605614
if (args->dst[i])
606615
nr_dma++;
607616
addr += PAGE_SIZE;
@@ -610,20 +619,18 @@ static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
610619
nouveau_fence_new(drm->dmem->migrate.chan, false, &fence);
611620
migrate_vma_pages(args);
612621
nouveau_dmem_fence_done(&fence);
622+
nouveau_pfns_map(svmm, args->vma->vm_mm, args->start, pfns, i);
613623

614624
while (nr_dma--) {
615625
dma_unmap_page(drm->dev->dev, dma_addrs[nr_dma], PAGE_SIZE,
616626
DMA_BIDIRECTIONAL);
617627
}
618-
/*
619-
* FIXME optimization: update GPU page table to point to newly migrated
620-
* memory.
621-
*/
622628
migrate_vma_finalize(args);
623629
}
624630

625631
int
626632
nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
633+
struct nouveau_svmm *svmm,
627634
struct vm_area_struct *vma,
628635
unsigned long start,
629636
unsigned long end)
@@ -635,7 +642,8 @@ nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
635642
.vma = vma,
636643
.start = start,
637644
};
638-
unsigned long c, i;
645+
unsigned long i;
646+
u64 *pfns;
639647
int ret = -ENOMEM;
640648

641649
args.src = kcalloc(max, sizeof(*args.src), GFP_KERNEL);
@@ -649,19 +657,25 @@ nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
649657
if (!dma_addrs)
650658
goto out_free_dst;
651659

652-
for (i = 0; i < npages; i += c) {
653-
c = min(SG_MAX_SINGLE_ALLOC, npages);
654-
args.end = start + (c << PAGE_SHIFT);
660+
pfns = nouveau_pfns_alloc(max);
661+
if (!pfns)
662+
goto out_free_dma;
663+
664+
for (i = 0; i < npages; i += max) {
665+
args.end = start + (max << PAGE_SHIFT);
655666
ret = migrate_vma_setup(&args);
656667
if (ret)
657-
goto out_free_dma;
668+
goto out_free_pfns;
658669

659670
if (args.cpages)
660-
nouveau_dmem_migrate_chunk(drm, &args, dma_addrs);
671+
nouveau_dmem_migrate_chunk(drm, svmm, &args, dma_addrs,
672+
pfns);
661673
args.start = args.end;
662674
}
663675

664676
ret = 0;
677+
out_free_pfns:
678+
nouveau_pfns_free(pfns);
665679
out_free_dma:
666680
kfree(dma_addrs);
667681
out_free_dst:

drivers/gpu/drm/nouveau/nouveau_dmem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
struct drm_device;
2626
struct drm_file;
2727
struct nouveau_drm;
28+
struct nouveau_svmm;
2829
struct hmm_range;
2930

3031
#if IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM)
@@ -34,6 +35,7 @@ void nouveau_dmem_suspend(struct nouveau_drm *);
3435
void nouveau_dmem_resume(struct nouveau_drm *);
3536

3637
int nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
38+
struct nouveau_svmm *svmm,
3739
struct vm_area_struct *vma,
3840
unsigned long start,
3941
unsigned long end);

drivers/gpu/drm/nouveau/nouveau_svm.c

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ struct nouveau_svm {
7070
#define SVM_DBG(s,f,a...) NV_DEBUG((s)->drm, "svm: "f"\n", ##a)
7171
#define SVM_ERR(s,f,a...) NV_WARN((s)->drm, "svm: "f"\n", ##a)
7272

73+
struct nouveau_pfnmap_args {
74+
struct nvif_ioctl_v0 i;
75+
struct nvif_ioctl_mthd_v0 m;
76+
struct nvif_vmm_pfnmap_v0 p;
77+
};
78+
7379
struct nouveau_ivmm {
7480
struct nouveau_svmm *svmm;
7581
u64 inst;
@@ -187,7 +193,8 @@ nouveau_svmm_bind(struct drm_device *dev, void *data,
187193
addr = max(addr, vma->vm_start);
188194
next = min(vma->vm_end, end);
189195
/* This is a best effort so we ignore errors */
190-
nouveau_dmem_migrate_vma(cli->drm, vma, addr, next);
196+
nouveau_dmem_migrate_vma(cli->drm, cli->svm.svmm, vma, addr,
197+
next);
191198
addr = next;
192199
}
193200

@@ -784,6 +791,56 @@ nouveau_svm_fault(struct nvif_notify *notify)
784791
return NVIF_NOTIFY_KEEP;
785792
}
786793

794+
static struct nouveau_pfnmap_args *
795+
nouveau_pfns_to_args(void *pfns)
796+
{
797+
return container_of(pfns, struct nouveau_pfnmap_args, p.phys);
798+
}
799+
800+
u64 *
801+
nouveau_pfns_alloc(unsigned long npages)
802+
{
803+
struct nouveau_pfnmap_args *args;
804+
805+
args = kzalloc(struct_size(args, p.phys, npages), GFP_KERNEL);
806+
if (!args)
807+
return NULL;
808+
809+
args->i.type = NVIF_IOCTL_V0_MTHD;
810+
args->m.method = NVIF_VMM_V0_PFNMAP;
811+
args->p.page = PAGE_SHIFT;
812+
813+
return args->p.phys;
814+
}
815+
816+
void
817+
nouveau_pfns_free(u64 *pfns)
818+
{
819+
struct nouveau_pfnmap_args *args = nouveau_pfns_to_args(pfns);
820+
821+
kfree(args);
822+
}
823+
824+
void
825+
nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm,
826+
unsigned long addr, u64 *pfns, unsigned long npages)
827+
{
828+
struct nouveau_pfnmap_args *args = nouveau_pfns_to_args(pfns);
829+
int ret;
830+
831+
args->p.addr = addr;
832+
args->p.size = npages << PAGE_SHIFT;
833+
834+
mutex_lock(&svmm->mutex);
835+
836+
svmm->vmm->vmm.object.client->super = true;
837+
ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, sizeof(*args) +
838+
npages * sizeof(args->p.phys[0]), NULL);
839+
svmm->vmm->vmm.object.client->super = false;
840+
841+
mutex_unlock(&svmm->mutex);
842+
}
843+
787844
static void
788845
nouveau_svm_fault_buffer_fini(struct nouveau_svm *svm, int id)
789846
{

drivers/gpu/drm/nouveau/nouveau_svm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ void nouveau_svmm_fini(struct nouveau_svmm **);
1818
int nouveau_svmm_join(struct nouveau_svmm *, u64 inst);
1919
void nouveau_svmm_part(struct nouveau_svmm *, u64 inst);
2020
int nouveau_svmm_bind(struct drm_device *, void *, struct drm_file *);
21+
22+
u64 *nouveau_pfns_alloc(unsigned long npages);
23+
void nouveau_pfns_free(u64 *pfns);
24+
void nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm,
25+
unsigned long addr, u64 *pfns, unsigned long npages);
2126
#else /* IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM) */
2227
static inline void nouveau_svm_init(struct nouveau_drm *drm) {}
2328
static inline void nouveau_svm_fini(struct nouveau_drm *drm) {}

0 commit comments

Comments
 (0)