gpu:nvgpu: fix the nvs mmap issues

- As part of mmap call handler mmap_sem is being acquired which is
causing an BUG: scheduling while atomic:. This is happening because
mmap callback gets called with mmap_sem held. The mmap file handler
is called via call_mmap() via mmap_region() via do_mmap(), and the
caller of do_mmap() must hold down_write(&current->mm->mmap_sem).
To fix this issue removing the mmap_sem locking from nvs mmap handler.

- If remap_vmalloc_range() is used to map the pages to userspace then
allocated pages should be mapped into virtually contiguous space by
passing VM_USERMAP flag to vmap(). Passing VM_USERMAP to vmap() call
if API nvgpu_dma_alloc_flags_sys() is called with flag
NVGPU_DMA_VM_USERMAP_ADDRESS.

Bug 3884011

Change-Id: I64264f6f6e0dd75b1f828dc58355d740e6ef5ccb
Signed-off-by: prsethi <prsethi@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2820781
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
prsethi
2022-12-02 17:59:25 +00:00
committed by mobile promotions
parent 0e6c8bb521
commit b4494a4b86
3 changed files with 23 additions and 15 deletions

View File

@@ -507,7 +507,8 @@ int nvgpu_nvs_buffer_alloc(struct nvgpu_nvs_domain_ctrl_fifo *sched_ctrl,
(void)memset(buf, 0, sizeof(*buf));
buf->g = g;
err = nvgpu_dma_alloc_map_sys(system_vm, bytes, &buf->mem);
err = nvgpu_dma_alloc_map_flags_sys(system_vm,
NVGPU_DMA_VM_USERMAP_ADDRESS, bytes, &buf->mem);
if (err != 0) {
nvgpu_err(g, "failed to allocate memory for dma");
goto fail;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2017-2022, NVIDIA CORPORATION. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -62,6 +62,13 @@ struct nvgpu_mem;
*/
#define NVGPU_DMA_PHYSICALLY_ADDRESSED BIT64(2)
/**
* If remap_vmalloc_range() is used to map the pages to userspace then allocated
* pages should be mapped into virtually contiguous space by passing VM_USERMAP
* flag to vmap().
*/
#define NVGPU_DMA_VM_USERMAP_ADDRESS BIT64(3)
/**
* nvgpu_iommuable - Check if GPU is behind IOMMU

View File

@@ -260,6 +260,7 @@ int nvgpu_dma_alloc_flags_sys(struct gk20a *g, unsigned long flags,
gfp_t gfps = GFP_KERNEL|__GFP_ZERO;
dma_addr_t iova;
unsigned long dma_attrs = 0;
unsigned long vma_flags = 0;
void *alloc_ret;
int err;
@@ -309,8 +310,18 @@ int nvgpu_dma_alloc_flags_sys(struct gk20a *g, unsigned long flags,
/* Map the page list from the non-contiguous allocation */
if (nvgpu_nvlink_non_contig(g, flags)) {
/*
* If remap_vmalloc_range() is going to be used to map cpu_va to
* userspace then VM_USERMAP flag should be passed to vmap() to
* get appropriate cpu_va.
*/
if (flags & NVGPU_DMA_VM_USERMAP_ADDRESS) {
vma_flags |= VM_USERMAP;
}
mem->cpu_va = vmap(mem->priv.pages, size >> PAGE_SHIFT,
0, PAGE_KERNEL);
vma_flags, PAGE_KERNEL);
if (!mem->cpu_va) {
err = -ENOMEM;
goto fail_free_sgt;
@@ -365,12 +376,6 @@ int nvgpu_dma_mmap_sys(struct gk20a *g, struct vm_area_struct *vma, struct nvgpu
return -EINVAL;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
mmap_write_lock(vma->vm_mm);
#else
down_write(&vma->vm_mm->mmap_sem);
#endif
vma_exists = find_vma_intersection(vma->vm_mm, vma->vm_start, vma->vm_end);
if (vma_exists != NULL) {
err = -EEXIST;
@@ -395,14 +400,9 @@ int nvgpu_dma_mmap_sys(struct gk20a *g, struct vm_area_struct *vma, struct nvgpu
}
done:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
mmap_write_unlock(vma->vm_mm);
#else
up_write(&vma->vm_mm->mmap_sem);
#endif
if (err != 0) {
nvgpu_err(g, "failed to map mem into userspace vma");
nvgpu_err(g, "failed to map mem into userspace vma %d", err);
}
return err;