Skip to content

Commit 7539028

Browse files
committed
drm/vmwgfx: Support huge page faults
With vmwgfx dirty-tracking we need a specialized huge_fault callback. Implement and hook it up. Cc: Andrew Morton <[email protected]> Cc: Michal Hocko <[email protected]> Cc: "Matthew Wilcox (Oracle)" <[email protected]> Cc: "Kirill A. Shutemov" <[email protected]> Cc: Ralph Campbell <[email protected]> Cc: "Jérôme Glisse" <[email protected]> Cc: "Christian König" <[email protected]> Cc: Dan Williams <[email protected]> Signed-off-by: Thomas Hellstrom (VMware) <[email protected]> Reviewed-by: Roland Scheidegger <[email protected]> Acked-by: Christian König <[email protected]>
1 parent 314b658 commit 7539028

File tree

3 files changed

+81
-2
lines changed

3 files changed

+81
-2
lines changed

drivers/gpu/drm/vmwgfx/vmwgfx_drv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,10 @@ void vmw_bo_dirty_unmap(struct vmw_buffer_object *vbo,
14021402
pgoff_t start, pgoff_t end);
14031403
vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf);
14041404
vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf);
1405+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
1406+
vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf,
1407+
enum page_entry_size pe_size);
1408+
#endif
14051409

14061410
/**
14071411
* VMW_DEBUG_KMS - Debug output for kernel mode-setting

drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf)
473473
* a lot of unnecessary write faults.
474474
*/
475475
if (vbo->dirty && vbo->dirty->method == VMW_BO_DIRTY_MKWRITE)
476-
prot = vma->vm_page_prot;
476+
prot = vm_get_page_prot(vma->vm_flags & ~VM_SHARED);
477477
else
478478
prot = vm_get_page_prot(vma->vm_flags);
479479

@@ -486,3 +486,75 @@ vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf)
486486

487487
return ret;
488488
}
489+
490+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
491+
vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf,
492+
enum page_entry_size pe_size)
493+
{
494+
struct vm_area_struct *vma = vmf->vma;
495+
struct ttm_buffer_object *bo = (struct ttm_buffer_object *)
496+
vma->vm_private_data;
497+
struct vmw_buffer_object *vbo =
498+
container_of(bo, struct vmw_buffer_object, base);
499+
pgprot_t prot;
500+
vm_fault_t ret;
501+
pgoff_t fault_page_size;
502+
bool write = vmf->flags & FAULT_FLAG_WRITE;
503+
bool is_cow_mapping =
504+
(vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
505+
506+
switch (pe_size) {
507+
case PE_SIZE_PMD:
508+
fault_page_size = HPAGE_PMD_SIZE >> PAGE_SHIFT;
509+
break;
510+
#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
511+
case PE_SIZE_PUD:
512+
fault_page_size = HPAGE_PUD_SIZE >> PAGE_SHIFT;
513+
break;
514+
#endif
515+
default:
516+
WARN_ON_ONCE(1);
517+
return VM_FAULT_FALLBACK;
518+
}
519+
520+
/* Always do write dirty-tracking and COW on PTE level. */
521+
if (write && (READ_ONCE(vbo->dirty) || is_cow_mapping))
522+
return VM_FAULT_FALLBACK;
523+
524+
ret = ttm_bo_vm_reserve(bo, vmf);
525+
if (ret)
526+
return ret;
527+
528+
if (vbo->dirty) {
529+
pgoff_t allowed_prefault;
530+
unsigned long page_offset;
531+
532+
page_offset = vmf->pgoff -
533+
drm_vma_node_start(&bo->base.vma_node);
534+
if (page_offset >= bo->num_pages ||
535+
vmw_resources_clean(vbo, page_offset,
536+
page_offset + PAGE_SIZE,
537+
&allowed_prefault)) {
538+
ret = VM_FAULT_SIGBUS;
539+
goto out_unlock;
540+
}
541+
542+
/*
543+
* Write protect, so we get a new fault on write, and can
544+
* split.
545+
*/
546+
prot = vm_get_page_prot(vma->vm_flags & ~VM_SHARED);
547+
} else {
548+
prot = vm_get_page_prot(vma->vm_flags);
549+
}
550+
551+
ret = ttm_bo_vm_fault_reserved(vmf, prot, 1, fault_page_size);
552+
if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
553+
return ret;
554+
555+
out_unlock:
556+
dma_resv_unlock(bo->base.resv);
557+
558+
return ret;
559+
}
560+
#endif

drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma)
3434
.page_mkwrite = vmw_bo_vm_mkwrite,
3535
.fault = vmw_bo_vm_fault,
3636
.open = ttm_bo_vm_open,
37-
.close = ttm_bo_vm_close
37+
.close = ttm_bo_vm_close,
38+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
39+
.huge_fault = vmw_bo_vm_huge_fault,
40+
#endif
3841
};
3942
struct drm_file *file_priv = filp->private_data;
4043
struct vmw_private *dev_priv = vmw_priv(file_priv->minor->dev);

0 commit comments

Comments
 (0)