summaryrefslogtreecommitdiff
path: root/mali_kbase/mali_kbase_mem_linux.c
diff options
context:
space:
mode:
authorJack Diver <diverj@google.com>2022-11-07 12:13:47 +0000
committerJack Diver <diverj@google.com>2022-11-09 17:51:01 +0000
commite19249ece66a726b13d0ed8734c4059f364ca2f5 (patch)
tree0bdfdcc3c70a6378c8265b03e3fba6b8120ffa21 /mali_kbase/mali_kbase_mem_linux.c
parent34e635317dc2a91076ac341df3867ac3bdb31ef1 (diff)
downloadgpu-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.c218
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;