Skip to content

Commit b223555

Browse files
Ralph Campbelljgunthorpe
authored andcommitted
nouveau/hmm: support mapping large sysmem pages
Nouveau currently only supports mapping PAGE_SIZE sized pages of system memory when shared virtual memory (SVM) is enabled. Use the new hmm_pfn_to_map_order() function to support mapping system memory pages that are PMD_SIZE. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ralph Campbell <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 4725c6b commit b223555

File tree

1 file changed

+40
-13
lines changed

1 file changed

+40
-13
lines changed

drivers/gpu/drm/nouveau/nouveau_svm.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -514,38 +514,57 @@ static const struct mmu_interval_notifier_ops nouveau_svm_mni_ops = {
514514
};
515515

516516
static void nouveau_hmm_convert_pfn(struct nouveau_drm *drm,
517-
struct hmm_range *range, u64 *ioctl_addr)
517+
struct hmm_range *range,
518+
struct nouveau_pfnmap_args *args)
518519
{
519520
struct page *page;
520521

521522
/*
522-
* The ioctl_addr prepared here is passed through nvif_object_ioctl()
523+
* The address prepared here is passed through nvif_object_ioctl()
523524
* to an eventual DMA map in something like gp100_vmm_pgt_pfn()
524525
*
525526
* This is all just encoding the internal hmm representation into a
526527
* different nouveau internal representation.
527528
*/
528529
if (!(range->hmm_pfns[0] & HMM_PFN_VALID)) {
529-
ioctl_addr[0] = 0;
530+
args->p.phys[0] = 0;
530531
return;
531532
}
532533

533534
page = hmm_pfn_to_page(range->hmm_pfns[0]);
535+
/*
536+
* Only map compound pages to the GPU if the CPU is also mapping the
537+
* page as a compound page. Otherwise, the PTE protections might not be
538+
* consistent (e.g., CPU only maps part of a compound page).
539+
* Note that the underlying page might still be larger than the
540+
* CPU mapping (e.g., a PUD sized compound page partially mapped with
541+
* a PMD sized page table entry).
542+
*/
543+
if (hmm_pfn_to_map_order(range->hmm_pfns[0])) {
544+
unsigned long addr = args->p.addr;
545+
546+
args->p.page = hmm_pfn_to_map_order(range->hmm_pfns[0]) +
547+
PAGE_SHIFT;
548+
args->p.size = 1UL << args->p.page;
549+
args->p.addr &= ~(args->p.size - 1);
550+
page -= (addr - args->p.addr) >> PAGE_SHIFT;
551+
}
534552
if (is_device_private_page(page))
535-
ioctl_addr[0] = nouveau_dmem_page_addr(page) |
553+
args->p.phys[0] = nouveau_dmem_page_addr(page) |
536554
NVIF_VMM_PFNMAP_V0_V |
537555
NVIF_VMM_PFNMAP_V0_VRAM;
538556
else
539-
ioctl_addr[0] = page_to_phys(page) |
557+
args->p.phys[0] = page_to_phys(page) |
540558
NVIF_VMM_PFNMAP_V0_V |
541559
NVIF_VMM_PFNMAP_V0_HOST;
542560
if (range->hmm_pfns[0] & HMM_PFN_WRITE)
543-
ioctl_addr[0] |= NVIF_VMM_PFNMAP_V0_W;
561+
args->p.phys[0] |= NVIF_VMM_PFNMAP_V0_W;
544562
}
545563

546564
static int nouveau_range_fault(struct nouveau_svmm *svmm,
547-
struct nouveau_drm *drm, void *data, u32 size,
548-
u64 *ioctl_addr, unsigned long hmm_flags,
565+
struct nouveau_drm *drm,
566+
struct nouveau_pfnmap_args *args, u32 size,
567+
unsigned long hmm_flags,
549568
struct svm_notifier *notifier)
550569
{
551570
unsigned long timeout =
@@ -585,10 +604,10 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm,
585604
break;
586605
}
587606

588-
nouveau_hmm_convert_pfn(drm, &range, ioctl_addr);
607+
nouveau_hmm_convert_pfn(drm, &range, args);
589608

590609
svmm->vmm->vmm.object.client->super = true;
591-
ret = nvif_object_ioctl(&svmm->vmm->vmm.object, data, size, NULL);
610+
ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, size, NULL);
592611
svmm->vmm->vmm.object.client->super = false;
593612
mutex_unlock(&svmm->mutex);
594613

@@ -717,22 +736,30 @@ nouveau_svm_fault(struct nvif_notify *notify)
717736
args.i.p.addr, args.i.p.size,
718737
&nouveau_svm_mni_ops);
719738
if (!ret) {
720-
ret = nouveau_range_fault(svmm, svm->drm, &args,
721-
sizeof(args), args.phys, hmm_flags, &notifier);
739+
ret = nouveau_range_fault(svmm, svm->drm, &args.i,
740+
sizeof(args), hmm_flags, &notifier);
722741
mmu_interval_notifier_remove(&notifier.notifier);
723742
}
724743
mmput(mm);
725744

745+
limit = args.i.p.addr + args.i.p.size;
726746
for (fn = fi; ++fn < buffer->fault_nr; ) {
727747
/* It's okay to skip over duplicate addresses from the
728748
* same SVMM as faults are ordered by access type such
729749
* that only the first one needs to be handled.
730750
*
731751
* ie. WRITE faults appear first, thus any handling of
732752
* pending READ faults will already be satisfied.
753+
* But if a large page is mapped, make sure subsequent
754+
* fault addresses have sufficient access permission.
733755
*/
734756
if (buffer->fault[fn]->svmm != svmm ||
735-
buffer->fault[fn]->addr >= limit)
757+
buffer->fault[fn]->addr >= limit ||
758+
(buffer->fault[fi]->access == 0 /* READ. */ &&
759+
!(args.phys[0] & NVIF_VMM_PFNMAP_V0_V)) ||
760+
(buffer->fault[fi]->access != 0 /* READ. */ &&
761+
buffer->fault[fi]->access != 3 /* PREFETCH. */ &&
762+
!(args.phys[0] & NVIF_VMM_PFNMAP_V0_W)))
736763
break;
737764
}
738765

0 commit comments

Comments
 (0)