@@ -514,38 +514,57 @@ static const struct mmu_interval_notifier_ops nouveau_svm_mni_ops = {
514514};
515515
516516static 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
546564static 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