/*
|
* Copyright (C) 2010-2014, 2016-2017 ARM Limited. All rights reserved.
|
*
|
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
|
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
|
*
|
* A copy of the licence is included with the program, and can also be obtained from Free Software
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
*/
|
|
/**
|
* @file mali_osk_low_level_mem.c
|
* Implementation of the OS abstraction layer for the kernel device driver
|
*/
|
|
#include <asm/io.h>
|
#include <linux/ioport.h>
|
#include <linux/slab.h>
|
|
#include "mali_kernel_common.h"
|
#include "mali_osk.h"
|
#include "mali_ukk.h"
|
|
void _mali_osk_mem_barrier(void)
|
{
|
mb();
|
}
|
|
void _mali_osk_write_mem_barrier(void)
|
{
|
wmb();
|
}
|
|
mali_io_address _mali_osk_mem_mapioregion(uintptr_t phys, u32 size, const char *description)
|
{
|
return (mali_io_address)ioremap(phys, size);
|
}
|
|
void _mali_osk_mem_unmapioregion(uintptr_t phys, u32 size, mali_io_address virt)
|
{
|
iounmap((void *)virt);
|
}
|
|
_mali_osk_errcode_t inline _mali_osk_mem_reqregion(uintptr_t phys, u32 size, const char *description)
|
{
|
#if MALI_LICENSE_IS_GPL
|
return _MALI_OSK_ERR_OK; /* GPL driver gets the mem region for the resources registered automatically */
|
#else
|
return ((NULL == request_mem_region(phys, size, description)) ? _MALI_OSK_ERR_NOMEM : _MALI_OSK_ERR_OK);
|
#endif
|
}
|
|
void inline _mali_osk_mem_unreqregion(uintptr_t phys, u32 size)
|
{
|
#if !MALI_LICENSE_IS_GPL
|
release_mem_region(phys, size);
|
#endif
|
}
|
|
void inline _mali_osk_mem_iowrite32_relaxed(volatile mali_io_address addr, u32 offset, u32 val)
|
{
|
__raw_writel(cpu_to_le32(val), ((u8 *)addr) + offset);
|
}
|
|
u32 inline _mali_osk_mem_ioread32(volatile mali_io_address addr, u32 offset)
|
{
|
return ioread32(((u8 *)addr) + offset);
|
}
|
|
void inline _mali_osk_mem_iowrite32(volatile mali_io_address addr, u32 offset, u32 val)
|
{
|
iowrite32(val, ((u8 *)addr) + offset);
|
}
|
|
void _mali_osk_cache_flushall(void)
|
{
|
/** @note Cached memory is not currently supported in this implementation */
|
}
|
|
void _mali_osk_cache_ensure_uncached_range_flushed(void *uncached_mapping, u32 offset, u32 size)
|
{
|
_mali_osk_write_mem_barrier();
|
}
|
|
u32 _mali_osk_mem_write_safe(void __user *dest, const void __user *src, u32 size)
|
{
|
#define MALI_MEM_SAFE_COPY_BLOCK_SIZE 4096
|
u32 retval = 0;
|
void *temp_buf;
|
|
temp_buf = kmalloc(MALI_MEM_SAFE_COPY_BLOCK_SIZE, GFP_KERNEL);
|
if (NULL != temp_buf) {
|
u32 bytes_left_to_copy = size;
|
u32 i;
|
for (i = 0; i < size; i += MALI_MEM_SAFE_COPY_BLOCK_SIZE) {
|
u32 size_to_copy;
|
u32 size_copied;
|
u32 bytes_left;
|
|
if (bytes_left_to_copy > MALI_MEM_SAFE_COPY_BLOCK_SIZE) {
|
size_to_copy = MALI_MEM_SAFE_COPY_BLOCK_SIZE;
|
} else {
|
size_to_copy = bytes_left_to_copy;
|
}
|
|
bytes_left = copy_from_user(temp_buf, ((char *)src) + i, size_to_copy);
|
size_copied = size_to_copy - bytes_left;
|
|
bytes_left = copy_to_user(((char *)dest) + i, temp_buf, size_copied);
|
size_copied -= bytes_left;
|
|
bytes_left_to_copy -= size_copied;
|
retval += size_copied;
|
|
if (size_copied != size_to_copy) {
|
break; /* Early out, we was not able to copy this entire block */
|
}
|
}
|
|
kfree(temp_buf);
|
}
|
|
return retval;
|
}
|
|
_mali_osk_errcode_t _mali_ukk_mem_write_safe(_mali_uk_mem_write_safe_s *args)
|
{
|
void __user *src;
|
void __user *dst;
|
struct mali_session_data *session;
|
|
MALI_DEBUG_ASSERT_POINTER(args);
|
|
session = (struct mali_session_data *)(uintptr_t)args->ctx;
|
|
if (NULL == session) {
|
return _MALI_OSK_ERR_INVALID_ARGS;
|
}
|
|
src = (void __user *)(uintptr_t)args->src;
|
dst = (void __user *)(uintptr_t)args->dest;
|
|
/* Return number of bytes actually copied */
|
args->size = _mali_osk_mem_write_safe(dst, src, args->size);
|
return _MALI_OSK_ERR_OK;
|
}
|