From b4494a4b866d8a280b5de4234b0aa1a0f1d32d6e Mon Sep 17 00:00:00 2001 From: prsethi Date: Fri, 2 Dec 2022 17:59:25 +0000 Subject: [PATCH] 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(¤t->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 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2820781 Tested-by: mobile promotions Reviewed-by: mobile promotions --- drivers/gpu/nvgpu/common/nvs/nvs_sched_ctrl.c | 3 ++- drivers/gpu/nvgpu/include/nvgpu/dma.h | 9 ++++++- drivers/gpu/nvgpu/os/linux/linux-dma.c | 26 +++++++++---------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/nvgpu/common/nvs/nvs_sched_ctrl.c b/drivers/gpu/nvgpu/common/nvs/nvs_sched_ctrl.c index 1824f1f10..399534a50 100644 --- a/drivers/gpu/nvgpu/common/nvs/nvs_sched_ctrl.c +++ b/drivers/gpu/nvgpu/common/nvs/nvs_sched_ctrl.c @@ -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; diff --git a/drivers/gpu/nvgpu/include/nvgpu/dma.h b/drivers/gpu/nvgpu/include/nvgpu/dma.h index 9307deac2..78751a589 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/dma.h +++ b/drivers/gpu/nvgpu/include/nvgpu/dma.h @@ -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 diff --git a/drivers/gpu/nvgpu/os/linux/linux-dma.c b/drivers/gpu/nvgpu/os/linux/linux-dma.c index f437dbeee..45f9830f8 100644 --- a/drivers/gpu/nvgpu/os/linux/linux-dma.c +++ b/drivers/gpu/nvgpu/os/linux/linux-dma.c @@ -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;