summaryrefslogtreecommitdiff
path: root/mali_kbase/mali_kbase_mem_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'mali_kbase/mali_kbase_mem_linux.c')
-rw-r--r--mali_kbase/mali_kbase_mem_linux.c168
1 files changed, 79 insertions, 89 deletions
diff --git a/mali_kbase/mali_kbase_mem_linux.c b/mali_kbase/mali_kbase_mem_linux.c
index f91d3c9..b6dac55 100644
--- a/mali_kbase/mali_kbase_mem_linux.c
+++ b/mali_kbase/mali_kbase_mem_linux.c
@@ -30,13 +30,15 @@
#include <linux/fs.h>
#include <linux/version.h>
#include <linux/dma-mapping.h>
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
- #include <linux/dma-attrs.h>
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) && \
+ (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0))
+#include <linux/dma-attrs.h>
+#endif /* LINUX_VERSION_CODE >= 3.5.0 && < 4.8.0 */
#ifdef CONFIG_DMA_SHARED_BUFFER
#include <linux/dma-buf.h>
#endif /* defined(CONFIG_DMA_SHARED_BUFFER) */
#include <linux/shrinker.h>
+#include <linux/cache.h>
#include <mali_kbase.h>
#include <mali_kbase_mem_linux.h>
@@ -112,7 +114,7 @@ struct kbase_va_region *kbase_mem_alloc(struct kbase_context *kctx, u64 va_pages
goto bad_size;
#if defined(CONFIG_64BIT)
- if (kctx->is_compat)
+ if (kbase_ctx_flag(kctx, KCTX_COMPAT))
cpu_va_bits = 32;
#endif
@@ -208,18 +210,19 @@ struct kbase_va_region *kbase_mem_alloc(struct kbase_context *kctx, u64 va_pages
}
/*
- * Pre-10.1 UKU userland calls mmap for us so return the
- * unaligned address and skip the map.
+ * 10.1-10.4 UKU userland relies on the kernel to call mmap.
+ * For all other versions we can just return the cookie
*/
- if (kctx->api_version < KBASE_API_VERSION(10, 1)) {
+ if (kctx->api_version < KBASE_API_VERSION(10, 1) ||
+ kctx->api_version > KBASE_API_VERSION(10, 4)) {
*gpu_va = (u64) cookie;
return reg;
}
/*
- * GPUCORE-2190:
- *
- * We still need to return alignment for old userspace.
+ * To achieve alignment and avoid allocating on large alignment
+ * (to work around a GPU hardware issue) we must allocate 3
+ * times the required size.
*/
if (*va_alignment)
va_map += 3 * (1UL << *va_alignment);
@@ -233,8 +236,10 @@ struct kbase_va_region *kbase_mem_alloc(struct kbase_context *kctx, u64 va_pages
MAP_SHARED, cookie);
if (IS_ERR_VALUE(cpu_addr)) {
+ kbase_gpu_vm_lock(kctx);
kctx->pending_regions[cookie_nr] = NULL;
kctx->cookies |= (1UL << cookie_nr);
+ kbase_gpu_vm_unlock(kctx);
goto no_mmap;
}
@@ -1036,7 +1041,7 @@ static struct kbase_va_region *kbase_mem_from_umm(struct kbase_context *kctx, in
shared_zone = true;
#ifdef CONFIG_64BIT
- if (!kctx->is_compat) {
+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) {
/*
* 64-bit tasks require us to reserve VA on the CPU that we use
* on the GPU.
@@ -1133,7 +1138,7 @@ static struct kbase_va_region *kbase_mem_from_user_buffer(
shared_zone = true;
#ifdef CONFIG_64BIT
- if (!kctx->is_compat) {
+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) {
/*
* 64-bit tasks require us to reserve VA on the CPU that we use
* on the GPU.
@@ -1266,7 +1271,7 @@ u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride,
*num_pages = nents * stride;
#ifdef CONFIG_64BIT
- if (!kctx->is_compat) {
+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) {
/* 64-bit tasks must MMAP anyway, but not expose this address to
* clients */
*flags |= BASE_MEM_NEED_MMAP;
@@ -1358,7 +1363,7 @@ u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride,
}
#ifdef CONFIG_64BIT
- if (!kctx->is_compat) {
+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) {
/* Bind to a cookie */
if (!kctx->cookies) {
dev_err(kctx->kbdev->dev, "No cookies available for allocation!");
@@ -1411,6 +1416,32 @@ bad_flags:
return 0;
}
+static u32 kbase_get_cache_line_alignment(struct kbase_context *kctx)
+{
+ u32 cpu_cache_line_size = cache_line_size();
+ u32 gpu_cache_line_size =
+ (1UL << kctx->kbdev->gpu_props.props.l2_props.log2_line_size);
+
+ return ((cpu_cache_line_size > gpu_cache_line_size) ?
+ cpu_cache_line_size :
+ gpu_cache_line_size);
+}
+
+static int kbase_check_buffer_size(struct kbase_context *kctx, u64 size)
+{
+ u32 cache_line_align = kbase_get_cache_line_alignment(kctx);
+
+ return (size & (cache_line_align - 1)) == 0 ? 0 : -EINVAL;
+}
+
+static int kbase_check_buffer_cache_alignment(struct kbase_context *kctx,
+ void __user *ptr)
+{
+ u32 cache_line_align = kbase_get_cache_line_alignment(kctx);
+
+ return ((uintptr_t)ptr & (cache_line_align - 1)) == 0 ? 0 : -EINVAL;
+}
+
int kbase_mem_import(struct kbase_context *kctx, enum base_mem_import_type type,
void __user *phandle, u64 *gpu_va, u64 *va_pages,
u64 *flags)
@@ -1423,7 +1454,7 @@ int kbase_mem_import(struct kbase_context *kctx, enum base_mem_import_type type,
KBASE_DEBUG_ASSERT(flags);
#ifdef CONFIG_64BIT
- if (!kctx->is_compat)
+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT))
*flags |= BASE_MEM_SAME_VA;
#endif
@@ -1466,12 +1497,26 @@ int kbase_mem_import(struct kbase_context *kctx, enum base_mem_import_type type,
reg = NULL;
} else {
#ifdef CONFIG_COMPAT
- if (kctx->is_compat)
+ if (kbase_ctx_flag(kctx, KCTX_COMPAT))
uptr = compat_ptr(user_buffer.ptr.compat_value);
else
#endif
uptr = user_buffer.ptr.value;
+ if (0 != kbase_check_buffer_cache_alignment(kctx,
+ uptr)) {
+ dev_warn(kctx->kbdev->dev,
+ "User buffer is not cache line aligned!\n");
+ goto no_reg;
+ }
+
+ if (0 != kbase_check_buffer_size(kctx,
+ user_buffer.length)) {
+ dev_warn(kctx->kbdev->dev,
+ "User buffer size is not multiple of cache line size!\n");
+ goto no_reg;
+ }
+
reg = kbase_mem_from_user_buffer(kctx,
(unsigned long)uptr, user_buffer.length,
va_pages, flags);
@@ -2146,44 +2191,6 @@ void kbase_os_mem_map_unlock(struct kbase_context *kctx)
up_read(&mm->mmap_sem);
}
-#if defined(CONFIG_DMA_SHARED_BUFFER) && defined(CONFIG_MALI_TRACE_TIMELINE)
-/* This section is required only for instrumentation. */
-
-static void kbase_dma_buf_vm_open(struct vm_area_struct *vma)
-{
- struct kbase_cpu_mapping *map = vma->vm_private_data;
-
- KBASE_DEBUG_ASSERT(map);
- KBASE_DEBUG_ASSERT(map->count > 0);
- /* Non-atomic as we're under Linux's mm lock. */
- map->count++;
-}
-
-static void kbase_dma_buf_vm_close(struct vm_area_struct *vma)
-{
- struct kbase_cpu_mapping *map = vma->vm_private_data;
-
- KBASE_DEBUG_ASSERT(map);
- KBASE_DEBUG_ASSERT(map->count > 0);
-
- /* Non-atomic as we're under Linux's mm lock. */
- if (--map->count)
- return;
-
- KBASE_DEBUG_ASSERT(map->kctx);
-
- kbase_gpu_vm_lock(map->kctx);
- list_del(&map->mappings_list);
- kbase_gpu_vm_unlock(map->kctx);
- kfree(map);
-}
-
-static const struct vm_operations_struct kbase_dma_mmap_ops = {
- .open = kbase_dma_buf_vm_open,
- .close = kbase_dma_buf_vm_close,
-};
-#endif /* CONFIG_DMA_SHARED_BUFFER && CONFIG_MALI_TRACE_TIMELINE */
-
int kbase_mmap(struct file *file, struct vm_area_struct *vma)
{
struct kbase_context *kctx = file->private_data;
@@ -2402,35 +2409,6 @@ map:
#ifdef CONFIG_DMA_SHARED_BUFFER
dma_map:
err = dma_buf_mmap(reg->cpu_alloc->imported.umm.dma_buf, vma, vma->vm_pgoff - reg->start_pfn);
-#if defined(CONFIG_MALI_TRACE_TIMELINE)
- /* This section is required only for instrumentation. */
- /* Add created mapping to imported region mapping list.
- * It is important to make it visible to dumping infrastructure.
- * Add mapping only if vm_ops structure is not used by memory owner. */
- WARN_ON(vma->vm_ops);
- WARN_ON(vma->vm_private_data);
- if (!err && !vma->vm_ops && !vma->vm_private_data) {
- struct kbase_cpu_mapping *map = kzalloc(
- sizeof(*map),
- GFP_KERNEL);
-
- if (map) {
- map->kctx = reg->kctx;
- map->region = NULL;
- map->page_off = vma->vm_pgoff;
- map->vm_start = vma->vm_start;
- map->vm_end = vma->vm_end;
- map->count = 1; /* start with one ref */
-
- vma->vm_ops = &kbase_dma_mmap_ops;
- vma->vm_private_data = map;
-
- list_add(
- &map->mappings_list,
- &reg->cpu_alloc->mappings);
- }
- }
-#endif /* CONFIG_MALI_TRACE_TIMELINE */
#endif /* CONFIG_DMA_SHARED_BUFFER */
out_unlock:
kbase_gpu_vm_unlock(kctx);
@@ -2719,7 +2697,9 @@ void *kbase_va_alloc(struct kbase_context *kctx, u32 size, struct kbase_hwc_dma_
dma_addr_t dma_pa;
struct kbase_va_region *reg;
phys_addr_t *page_array;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
+ unsigned long attrs = DMA_ATTR_WRITE_COMBINE;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
DEFINE_DMA_ATTRS(attrs);
#endif
@@ -2735,9 +2715,13 @@ void *kbase_va_alloc(struct kbase_context *kctx, u32 size, struct kbase_hwc_dma_
goto err;
/* All the alloc calls return zeroed memory */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
+ va = dma_alloc_attrs(kctx->kbdev->dev, size, &dma_pa, GFP_KERNEL,
+ attrs);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
- va = dma_alloc_attrs(kctx->kbdev->dev, size, &dma_pa, GFP_KERNEL, &attrs);
+ va = dma_alloc_attrs(kctx->kbdev->dev, size, &dma_pa, GFP_KERNEL,
+ &attrs);
#else
va = dma_alloc_writecombine(kctx->kbdev->dev, size, &dma_pa, GFP_KERNEL);
#endif
@@ -2784,7 +2768,9 @@ no_mmap:
no_alloc:
kfree(reg);
no_reg:
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
+ dma_free_attrs(kctx->kbdev->dev, size, va, dma_pa, attrs);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
dma_free_attrs(kctx->kbdev->dev, size, va, dma_pa, &attrs);
#else
dma_free_writecombine(kctx->kbdev->dev, size, va, dma_pa);
@@ -2798,7 +2784,8 @@ void kbase_va_free(struct kbase_context *kctx, struct kbase_hwc_dma_mapping *han
{
struct kbase_va_region *reg;
int err;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) && \
+ (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0))
DEFINE_DMA_ATTRS(attrs);
#endif
@@ -2816,7 +2803,10 @@ void kbase_va_free(struct kbase_context *kctx, struct kbase_hwc_dma_mapping *han
kbase_mem_phy_alloc_put(reg->gpu_alloc);
kfree(reg);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
+ dma_free_attrs(kctx->kbdev->dev, handle->size,
+ handle->cpu_va, handle->dma_pa, DMA_ATTR_WRITE_COMBINE);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
dma_free_attrs(kctx->kbdev->dev, handle->size,
handle->cpu_va, handle->dma_pa, &attrs);