diff options
author | Jack Diver <diverj@google.com> | 2022-11-07 12:13:47 +0000 |
---|---|---|
committer | Jack Diver <diverj@google.com> | 2022-11-09 17:51:01 +0000 |
commit | e19249ece66a726b13d0ed8734c4059f364ca2f5 (patch) | |
tree | 0bdfdcc3c70a6378c8265b03e3fba6b8120ffa21 /mali_kbase/mali_kbase_mem_linux.c | |
parent | 34e635317dc2a91076ac341df3867ac3bdb31ef1 (diff) | |
download | gpu-e19249ece66a726b13d0ed8734c4059f364ca2f5.tar.gz |
Revert "Revert "Merge r38p1 from upstream into partner/android13-gs-pixel-5.10-tm-qpr2""
This reverts commit 34e635317dc2a91076ac341df3867ac3bdb31ef1.
Bug: 228779790
Change-Id: Ic9d131af5568d7f55f610f255fa1c02925b18482
(cherry picked from commit 1c916e3f7c4d999f68e40c60fee6fe39418fcecd)
Diffstat (limited to 'mali_kbase/mali_kbase_mem_linux.c')
-rw-r--r-- | mali_kbase/mali_kbase_mem_linux.c | 218 |
1 files changed, 139 insertions, 79 deletions
diff --git a/mali_kbase/mali_kbase_mem_linux.c b/mali_kbase/mali_kbase_mem_linux.c index 327b7dc..c0ee10c 100644 --- a/mali_kbase/mali_kbase_mem_linux.c +++ b/mali_kbase/mali_kbase_mem_linux.c @@ -31,13 +31,11 @@ #include <linux/fs.h> #include <linux/version.h> #include <linux/dma-mapping.h> -#if (KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE) -#include <linux/dma-attrs.h> -#endif /* LINUX_VERSION_CODE < 4.8.0 */ #include <linux/dma-buf.h> #include <linux/shrinker.h> #include <linux/cache.h> #include <linux/memory_group_manager.h> +#include <linux/math64.h> #include <mali_kbase.h> #include <mali_kbase_mem_linux.h> @@ -84,10 +82,8 @@ #define IR_THRESHOLD_STEPS (256u) #if MALI_USE_CSF -static int kbase_csf_cpu_mmap_user_reg_page(struct kbase_context *kctx, - struct vm_area_struct *vma); -static int kbase_csf_cpu_mmap_user_io_pages(struct kbase_context *kctx, - struct vm_area_struct *vma); +static int kbase_csf_cpu_mmap_user_reg_page(struct kbase_context *kctx, struct vm_area_struct *vma); +static int kbase_csf_cpu_mmap_user_io_pages(struct kbase_context *kctx, struct vm_area_struct *vma); #endif static int kbase_vmap_phy_pages(struct kbase_context *kctx, @@ -115,6 +111,7 @@ static bool is_process_exiting(struct vm_area_struct *vma) */ if (atomic_read(&vma->vm_mm->mm_users)) return false; + return true; } @@ -1120,19 +1117,7 @@ int kbase_mem_do_sync_imported(struct kbase_context *kctx, ret = 0; } #else - /* Though the below version check could be superfluous depending upon the version condition - * used for enabling KBASE_MEM_ION_SYNC_WORKAROUND, we still keep this check here to allow - * ease of modification for non-ION systems or systems where ION has been patched. - */ -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE && !defined(CONFIG_CHROMEOS) - dma_buf_end_cpu_access(dma_buf, - 0, dma_buf->size, - dir); - ret = 0; -#else - ret = dma_buf_end_cpu_access(dma_buf, - dir); -#endif + ret = dma_buf_end_cpu_access(dma_buf, dir); #endif /* KBASE_MEM_ION_SYNC_WORKAROUND */ break; case KBASE_SYNC_TO_CPU: @@ -1149,11 +1134,7 @@ int kbase_mem_do_sync_imported(struct kbase_context *kctx, ret = 0; } #else - ret = dma_buf_begin_cpu_access(dma_buf, -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE && !defined(CONFIG_CHROMEOS) - 0, dma_buf->size, -#endif - dir); + ret = dma_buf_begin_cpu_access(dma_buf, dir); #endif /* KBASE_MEM_ION_SYNC_WORKAROUND */ break; } @@ -1329,11 +1310,8 @@ int kbase_mem_umm_map(struct kbase_context *kctx, return 0; bad_pad_insert: - kbase_mmu_teardown_pages(kctx->kbdev, - &kctx->mmu, - reg->start_pfn, - alloc->nents, - kctx->as_nr); + kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, + alloc->nents, kctx->as_nr); bad_insert: kbase_mem_umm_unmap_attachment(kctx, alloc); bad_map_attachment: @@ -1361,11 +1339,8 @@ void kbase_mem_umm_unmap(struct kbase_context *kctx, if (!kbase_is_region_invalid_or_free(reg) && reg->gpu_alloc == alloc) { int err; - err = kbase_mmu_teardown_pages(kctx->kbdev, - &kctx->mmu, - reg->start_pfn, - reg->nr_pages, - kctx->as_nr); + err = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, + alloc->pages, reg->nr_pages, kctx->as_nr); WARN_ON(err); } @@ -1558,13 +1533,15 @@ static struct kbase_va_region *kbase_mem_from_user_buffer( struct kbase_context *kctx, unsigned long address, unsigned long size, u64 *va_pages, u64 *flags) { - long i; + long i, dma_mapped_pages; struct kbase_va_region *reg; struct rb_root *rbtree; long faulted_pages; int zone = KBASE_REG_ZONE_CUSTOM_VA; bool shared_zone = false; u32 cache_line_alignment = kbase_get_cache_line_alignment(kctx->kbdev); + unsigned long offset_within_page; + unsigned long remaining_size; struct kbase_alloc_import_user_buf *user_buf; struct page **pages = NULL; int write; @@ -1683,18 +1660,7 @@ static struct kbase_va_region *kbase_mem_from_user_buffer( write = reg->flags & (KBASE_REG_CPU_WR | KBASE_REG_GPU_WR); -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE - faulted_pages = get_user_pages(current, current->mm, address, *va_pages, -#if KERNEL_VERSION(4, 4, 168) <= LINUX_VERSION_CODE && \ -KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE - write ? FOLL_WRITE : 0, pages, NULL); -#else - write, 0, pages, NULL); -#endif -#elif KERNEL_VERSION(4, 9, 0) > LINUX_VERSION_CODE - faulted_pages = get_user_pages(address, *va_pages, - write, 0, pages, NULL); -#elif KERNEL_VERSION(5, 9, 0) > LINUX_VERSION_CODE +#if KERNEL_VERSION(5, 9, 0) > LINUX_VERSION_CODE faulted_pages = get_user_pages(address, *va_pages, write ? FOLL_WRITE : 0, pages, NULL); #else @@ -1727,29 +1693,27 @@ KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE if (pages) { struct device *dev = kctx->kbdev->dev; - unsigned long local_size = user_buf->size; - unsigned long offset = user_buf->address & ~PAGE_MASK; struct tagged_addr *pa = kbase_get_gpu_phy_pages(reg); /* Top bit signifies that this was pinned on import */ user_buf->current_mapping_usage_count |= PINNED_ON_IMPORT; + offset_within_page = user_buf->address & ~PAGE_MASK; + remaining_size = user_buf->size; for (i = 0; i < faulted_pages; i++) { - dma_addr_t dma_addr; - unsigned long min; + unsigned long map_size = + MIN(PAGE_SIZE - offset_within_page, remaining_size); + dma_addr_t dma_addr = dma_map_page(dev, pages[i], + offset_within_page, map_size, DMA_BIDIRECTIONAL); - min = MIN(PAGE_SIZE - offset, local_size); - dma_addr = dma_map_page(dev, pages[i], - offset, min, - DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, dma_addr)) goto unwind_dma_map; user_buf->dma_addrs[i] = dma_addr; pa[i] = as_tagged(page_to_phys(pages[i])); - local_size -= min; - offset = 0; + remaining_size -= map_size; + offset_within_page = 0; } reg->gpu_alloc->nents = faulted_pages; @@ -1758,10 +1722,19 @@ KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE return reg; unwind_dma_map: - while (i--) { + offset_within_page = user_buf->address & ~PAGE_MASK; + remaining_size = user_buf->size; + dma_mapped_pages = i; + /* Run the unmap loop in the same order as map loop */ + for (i = 0; i < dma_mapped_pages; i++) { + unsigned long unmap_size = + MIN(PAGE_SIZE - offset_within_page, remaining_size); + dma_unmap_page(kctx->kbdev->dev, user_buf->dma_addrs[i], - PAGE_SIZE, DMA_BIDIRECTIONAL); + unmap_size, DMA_BIDIRECTIONAL); + remaining_size -= unmap_size; + offset_within_page = 0; } fault_mismatch: if (pages) { @@ -1793,6 +1766,7 @@ u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride, u64 gpu_va; size_t i; bool coherent; + uint64_t max_stride; /* Calls to this function are inherently asynchronous, with respect to * MMU operations. @@ -1825,7 +1799,9 @@ u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride, if (!nents) goto bad_nents; - if (stride > U64_MAX / nents) + max_stride = div64_u64(U64_MAX, nents); + + if (stride > max_stride) goto bad_size; if ((nents * stride) > (U64_MAX / PAGE_SIZE)) @@ -2217,10 +2193,11 @@ static int kbase_mem_shrink_gpu_mapping(struct kbase_context *const kctx, u64 const new_pages, u64 const old_pages) { u64 delta = old_pages - new_pages; + struct kbase_mem_phy_alloc *alloc = reg->gpu_alloc; int ret = 0; - ret = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, - reg->start_pfn + new_pages, delta, kctx->as_nr); + ret = kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn + new_pages, + alloc->pages + new_pages, delta, kctx->as_nr); return ret; } @@ -3434,13 +3411,6 @@ static vm_fault_t kbase_csf_user_io_pages_vm_fault(struct vm_fault *vmf) /* Always map the doorbell page as uncached */ doorbell_pgprot = pgprot_device(vma->vm_page_prot); -#if ((KERNEL_VERSION(4, 4, 147) >= LINUX_VERSION_CODE) || \ - ((KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE) && \ - (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE))) - vma->vm_page_prot = doorbell_pgprot; - input_page_pgprot = doorbell_pgprot; - output_page_pgprot = doorbell_pgprot; -#else if (kbdev->system_coherency == COHERENCY_NONE) { input_page_pgprot = pgprot_writecombine(vma->vm_page_prot); output_page_pgprot = pgprot_writecombine(vma->vm_page_prot); @@ -3448,7 +3418,6 @@ static vm_fault_t kbase_csf_user_io_pages_vm_fault(struct vm_fault *vmf) input_page_pgprot = vma->vm_page_prot; output_page_pgprot = vma->vm_page_prot; } -#endif doorbell_cpu_addr = vma->vm_start; @@ -3572,13 +3541,71 @@ map_failed: return err; } +/** + * kbase_csf_user_reg_vm_open - VMA open function for the USER page + * + * @vma: Pointer to the struct containing information about + * the userspace mapping of USER page. + * Note: + * This function isn't expected to be called. If called (i.e> mremap), + * set private_data as NULL to indicate to close() and fault() functions. + */ +static void kbase_csf_user_reg_vm_open(struct vm_area_struct *vma) +{ + pr_debug("Unexpected call to the open method for USER register mapping"); + vma->vm_private_data = NULL; +} + +/** + * kbase_csf_user_reg_vm_close - VMA close function for the USER page + * + * @vma: Pointer to the struct containing information about + * the userspace mapping of USER page. + */ static void kbase_csf_user_reg_vm_close(struct vm_area_struct *vma) { struct kbase_context *kctx = vma->vm_private_data; - WARN_ON(!kctx->csf.user_reg_vma); + if (!kctx) { + pr_debug("Close function called for the unexpected mapping"); + return; + } + + if (unlikely(!kctx->csf.user_reg_vma)) + dev_warn(kctx->kbdev->dev, "user_reg_vma pointer unexpectedly NULL"); kctx->csf.user_reg_vma = NULL; + + mutex_lock(&kctx->kbdev->csf.reg_lock); + if (unlikely(kctx->kbdev->csf.nr_user_page_mapped == 0)) + dev_warn(kctx->kbdev->dev, "Unexpected value for the USER page mapping counter"); + else + kctx->kbdev->csf.nr_user_page_mapped--; + mutex_unlock(&kctx->kbdev->csf.reg_lock); +} + +/** + * kbase_csf_user_reg_vm_mremap - VMA mremap function for the USER page + * + * @vma: Pointer to the struct containing information about + * the userspace mapping of USER page. + * + * Return: -EINVAL + * + * Note: + * User space must not attempt mremap on USER page mapping. + * This function will return an error to fail the attempt. + */ +static int +#if ((KERNEL_VERSION(5, 13, 0) <= LINUX_VERSION_CODE) || \ + (KERNEL_VERSION(5, 11, 0) > LINUX_VERSION_CODE)) +kbase_csf_user_reg_vm_mremap(struct vm_area_struct *vma) +#else +kbase_csf_user_reg_vm_mremap(struct vm_area_struct *vma, unsigned long flags) +#endif +{ + pr_debug("Unexpected call to mremap method for USER page mapping vma\n"); + return -EINVAL; } #if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) @@ -3591,19 +3618,24 @@ static vm_fault_t kbase_csf_user_reg_vm_fault(struct vm_fault *vmf) struct vm_area_struct *vma = vmf->vma; #endif struct kbase_context *kctx = vma->vm_private_data; - struct kbase_device *kbdev = kctx->kbdev; - struct memory_group_manager_device *mgm_dev = kbdev->mgm_dev; - unsigned long pfn = PFN_DOWN(kbdev->reg_start + USER_BASE); + struct kbase_device *kbdev; + struct memory_group_manager_device *mgm_dev; + unsigned long pfn; size_t nr_pages = PFN_DOWN(vma->vm_end - vma->vm_start); vm_fault_t ret = VM_FAULT_SIGBUS; unsigned long flags; /* Few sanity checks up front */ - if (WARN_ON(nr_pages != 1) || - WARN_ON(vma != kctx->csf.user_reg_vma) || - WARN_ON(vma->vm_pgoff != - PFN_DOWN(BASEP_MEM_CSF_USER_REG_PAGE_HANDLE))) + if (!kctx || (nr_pages != 1) || (vma != kctx->csf.user_reg_vma) || + (vma->vm_pgoff != PFN_DOWN(BASEP_MEM_CSF_USER_REG_PAGE_HANDLE))) { + pr_warn("Unexpected CPU page fault on USER page mapping for process %s tgid %d pid %d\n", + current->comm, current->tgid, current->pid); return VM_FAULT_SIGBUS; + } + + kbdev = kctx->kbdev; + mgm_dev = kbdev->mgm_dev; + pfn = PFN_DOWN(kbdev->reg_start + USER_BASE); mutex_lock(&kbdev->csf.reg_lock); spin_lock_irqsave(&kbdev->hwaccess_lock, flags); @@ -3628,14 +3660,31 @@ static vm_fault_t kbase_csf_user_reg_vm_fault(struct vm_fault *vmf) } static const struct vm_operations_struct kbase_csf_user_reg_vm_ops = { + .open = kbase_csf_user_reg_vm_open, .close = kbase_csf_user_reg_vm_close, + .mremap = kbase_csf_user_reg_vm_mremap, .fault = kbase_csf_user_reg_vm_fault }; +/** + * kbase_csf_cpu_mmap_user_reg_page - Memory map method for USER page. + * + * @kctx: Pointer of the kernel context. + * @vma: Pointer to the struct containing the information about + * the userspace mapping of USER page. + * + * Return: 0 on success, error code otherwise. + * + * Note: + * New Base will request Kbase to read the LATEST_FLUSH of USER page on its behalf. + * But this function needs to be kept for backward-compatibility as old Base (<=1.12) + * will try to mmap USER page for direct access when it creates a base context. + */ static int kbase_csf_cpu_mmap_user_reg_page(struct kbase_context *kctx, struct vm_area_struct *vma) { size_t nr_pages = PFN_DOWN(vma->vm_end - vma->vm_start); + struct kbase_device *kbdev = kctx->kbdev; /* Few sanity checks */ if (kctx->csf.user_reg_vma) @@ -3659,6 +3708,17 @@ static int kbase_csf_cpu_mmap_user_reg_page(struct kbase_context *kctx, kctx->csf.user_reg_vma = vma; + mutex_lock(&kbdev->csf.reg_lock); + kbdev->csf.nr_user_page_mapped++; + + if (!kbdev->csf.mali_file_inode) + kbdev->csf.mali_file_inode = kctx->filp->f_inode; + + if (unlikely(kbdev->csf.mali_file_inode != kctx->filp->f_inode)) + dev_warn(kbdev->dev, "Device file inode pointer not same for all contexts"); + + mutex_unlock(&kbdev->csf.reg_lock); + vma->vm_ops = &kbase_csf_user_reg_vm_ops; vma->vm_private_data = kctx; |