diff options
author | Dorian Snyder <dastin1015@gmail.com> | 2014-06-15 01:24:33 -0700 |
---|---|---|
committer | Dorian Snyder <dastin1015@gmail.com> | 2014-08-04 18:46:06 +0000 |
commit | d90b43b963027b4d1559cec14e97117827a6458d (patch) | |
tree | 00d1334c383628e7d6f38a4f7ca0c575a4916d91 /drivers/media/video/samsung/ump/linux | |
parent | 89e6992285b4274996b39cd953c0adb5e95a3236 (diff) | |
download | kernel_samsung_smdk4412-d90b43b963027b4d1559cec14e97117827a6458d.zip kernel_samsung_smdk4412-d90b43b963027b4d1559cec14e97117827a6458d.tar.gz kernel_samsung_smdk4412-d90b43b963027b4d1559cec14e97117827a6458d.tar.bz2 |
mali: add r3p1 for devices that need it
d710 needs to use old mali drivers due to new ones causing signal to be completely killed
Change-Id: I450c356b50e3f3521a63717a1c241e3b818b936f
Diffstat (limited to 'drivers/media/video/samsung/ump/linux')
18 files changed, 2849 insertions, 0 deletions
diff --git a/drivers/media/video/samsung/ump/linux/license/gpl/ump_kernel_license.h b/drivers/media/video/samsung/ump/linux/license/gpl/ump_kernel_license.h new file mode 100644 index 0000000..187e33b --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/license/gpl/ump_kernel_license.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010, 2012 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 ump_kernel_license.h + * Defines for the macro MODULE_LICENSE. + */ + +#ifndef __UMP_KERNEL_LICENSE_H__ +#define __UMP_KERNEL_LICENSE_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define UMP_KERNEL_LINUX_LICENSE "GPL" +#define UMP_LICENSE_IS_GPL 1 + +#ifdef __cplusplus +} +#endif + +#endif /* __UMP_KERNEL_LICENSE_H__ */ diff --git a/drivers/media/video/samsung/ump/linux/ump_ioctl.h b/drivers/media/video/samsung/ump/linux/ump_ioctl.h new file mode 100644 index 0000000..83bb2a4 --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_ioctl.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +#ifndef __UMP_IOCTL_H__ +#define __UMP_IOCTL_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <linux/types.h> +#include <linux/ioctl.h> + +#include <ump_uk_types.h> + +#ifndef __user +#define __user +#endif + + +/** + * @file UMP_ioctl.h + * This file describes the interface needed to use the Linux device driver. + * The interface is used by the userpace UMP driver. + */ + +#define UMP_IOCTL_NR 0x90 + + +#define UMP_IOC_QUERY_API_VERSION _IOR(UMP_IOCTL_NR, _UMP_IOC_QUERY_API_VERSION, _ump_uk_api_version_s) +#define UMP_IOC_ALLOCATE _IOWR(UMP_IOCTL_NR, _UMP_IOC_ALLOCATE, _ump_uk_allocate_s) +#define UMP_IOC_RELEASE _IOR(UMP_IOCTL_NR, _UMP_IOC_RELEASE, _ump_uk_release_s) +#define UMP_IOC_SIZE_GET _IOWR(UMP_IOCTL_NR, _UMP_IOC_SIZE_GET, _ump_uk_size_get_s) +#define UMP_IOC_MSYNC _IOW(UMP_IOCTL_NR, _UMP_IOC_MSYNC, _ump_uk_msync_s) +#ifdef CONFIG_ION_EXYNOS +#define UMP_IOC_ION_IMPORT _IOW(UMP_IOCTL_NR, _UMP_IOC_ION_IMPORT, _ump_uk_ion_import_s) +#endif +#ifdef CONFIG_DMA_SHARED_BUFFER +#define UMP_IOC_DMABUF_IMPORT _IOW(UMP_IOCTL_NR, _UMP_IOC_DMABUF_IMPORT,\ + struct ump_uk_dmabuf) +#endif + +#define UMP_IOC_CACHE_OPERATIONS_CONTROL _IOW(UMP_IOCTL_NR, _UMP_IOC_CACHE_OPERATIONS_CONTROL, _ump_uk_cache_operations_control_s) +#define UMP_IOC_SWITCH_HW_USAGE _IOW(UMP_IOCTL_NR, _UMP_IOC_SWITCH_HW_USAGE, _ump_uk_switch_hw_usage_s) +#define UMP_IOC_LOCK _IOW(UMP_IOCTL_NR, _UMP_IOC_LOCK, _ump_uk_lock_s) +#define UMP_IOC_UNLOCK _IOW(UMP_IOCTL_NR, _UMP_IOC_UNLOCK, _ump_uk_unlock_s) + + +#ifdef __cplusplus +} +#endif + +#endif /* __UMP_IOCTL_H__ */ diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_linux.c b/drivers/media/video/samsung/ump/linux/ump_kernel_linux.c new file mode 100644 index 0000000..a358a3c --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_linux.c @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +#include <linux/module.h> /* kernel module definitions */ +#include <linux/fs.h> /* file system operations */ +#include <linux/cdev.h> /* character device definitions */ +#include <linux/ioport.h> /* request_mem_region */ +#include <linux/mm.h> /* memory management functions and types */ +#include <asm/uaccess.h> /* user space access */ +#include <asm/atomic.h> +#include <linux/device.h> +#include <linux/debugfs.h> + +#include "arch/config.h" /* Configuration for current platform. The symlinc for arch is set by Makefile */ +#include "ump_ioctl.h" +#include "ump_kernel_common.h" +#include "ump_kernel_interface.h" +#include "ump_kernel_interface_ref_drv.h" +#include "ump_kernel_descriptor_mapping.h" +#include "ump_kernel_memory_backend.h" +#include "ump_kernel_memory_backend_os.h" +#include "ump_kernel_memory_backend_dedicated.h" +#include "ump_kernel_license.h" + +#include "ump_osk.h" +#include "ump_ukk.h" +#include "ump_uk_types.h" +#include "ump_ukk_wrappers.h" +#include "ump_ukk_ref_wrappers.h" + +#ifdef CONFIG_ION_EXYNOS +#include <linux/ion.h> +extern struct ion_device *ion_exynos; +struct ion_client *ion_client_ump = NULL; +#endif + +/* Module parameter to control log level */ +int ump_debug_level = 2; +module_param(ump_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */ +MODULE_PARM_DESC(ump_debug_level, "Higher number, more dmesg output"); + +/* By default the module uses any available major, but it's possible to set it at load time to a specific number */ +int ump_major = 243; +module_param(ump_major, int, S_IRUGO); /* r--r--r-- */ +MODULE_PARM_DESC(ump_major, "Device major number"); + +/* Name of the UMP device driver */ +static char ump_dev_name[] = "ump"; /* should be const, but the functions we call requires non-cost */ + + +#if UMP_LICENSE_IS_GPL +static struct dentry *ump_debugfs_dir = NULL; +#endif + +/* + * The data which we attached to each virtual memory mapping request we get. + * Each memory mapping has a reference to the UMP memory it maps. + * We release this reference when the last memory mapping is unmapped. + */ +typedef struct ump_vma_usage_tracker +{ + int references; + ump_dd_handle handle; +} ump_vma_usage_tracker; + +struct ump_device +{ + struct cdev cdev; +#if UMP_LICENSE_IS_GPL + struct class * ump_class; +#endif +}; + +/* The global variable containing the global device data */ +static struct ump_device ump_device; + + +/* Forward declare static functions */ +static int ump_file_open(struct inode *inode, struct file *filp); +static int ump_file_release(struct inode *inode, struct file *filp); +#ifdef HAVE_UNLOCKED_IOCTL +static long ump_file_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#else +static int ump_file_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +#endif +static int ump_file_mmap(struct file * filp, struct vm_area_struct * vma); + +#if defined(CONFIG_VIDEO_UMP) +extern int map_errcode( _mali_osk_errcode_t err ); +#endif + +/* This variable defines the file operations this UMP device driver offer */ +static struct file_operations ump_fops = +{ + .owner = THIS_MODULE, + .open = ump_file_open, + .release = ump_file_release, +#ifdef HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = ump_file_ioctl, +#else + .ioctl = ump_file_ioctl, +#endif + .mmap = ump_file_mmap +}; + + +/* This function is called by Linux to initialize this module. + * All we do is initialize the UMP device driver. + */ +static int ump_initialize_module(void) +{ + _mali_osk_errcode_t err; + + DBG_MSG(2, ("Inserting UMP device driver. Compiled: %s, time: %s\n", __DATE__, __TIME__)); + + err = ump_kernel_constructor(); + if (_MALI_OSK_ERR_OK != err) + { + MSG_ERR(("UMP device driver init failed\n")); + return map_errcode(err); + } + + MSG(("UMP device driver %s loaded\n", SVN_REV_STRING)); + return 0; +} + + + +/* + * This function is called by Linux to unload/terminate/exit/cleanup this module. + * All we do is terminate the UMP device driver. + */ +static void ump_cleanup_module(void) +{ +#ifdef CONFIG_ION_EXYNOS + if (ion_client_ump) + ion_client_destroy(ion_client_ump); +#endif + + DBG_MSG(2, ("Unloading UMP device driver\n")); + ump_kernel_destructor(); + DBG_MSG(2, ("Module unloaded\n")); +} + + + +static ssize_t ump_memory_used_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char buf[64]; + size_t r; + u32 mem = _ump_ukk_report_memory_usage(); + + r = snprintf(buf, 64, "%u\n", mem); + return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); +} + +static const struct file_operations ump_memory_usage_fops = { + .owner = THIS_MODULE, + .read = ump_memory_used_read, +}; + +/* + * Initialize the UMP device driver. + */ +int ump_kernel_device_initialize(void) +{ + int err; + dev_t dev = 0; +#if UMP_LICENSE_IS_GPL + ump_debugfs_dir = debugfs_create_dir(ump_dev_name, NULL); + if (ERR_PTR(-ENODEV) == ump_debugfs_dir) + { + ump_debugfs_dir = NULL; + } + else + { + debugfs_create_file("memory_usage", 0400, ump_debugfs_dir, NULL, &ump_memory_usage_fops); + } +#endif + + if (0 == ump_major) + { + /* auto select a major */ + err = alloc_chrdev_region(&dev, 0, 1, ump_dev_name); + ump_major = MAJOR(dev); + } + else + { + /* use load time defined major number */ + dev = MKDEV(ump_major, 0); + err = register_chrdev_region(dev, 1, ump_dev_name); + } + + if (0 == err) + { + memset(&ump_device, 0, sizeof(ump_device)); + + /* initialize our char dev data */ + cdev_init(&ump_device.cdev, &ump_fops); + ump_device.cdev.owner = THIS_MODULE; + ump_device.cdev.ops = &ump_fops; + + /* register char dev with the kernel */ + err = cdev_add(&ump_device.cdev, dev, 1/*count*/); + if (0 == err) + { + +#if UMP_LICENSE_IS_GPL + ump_device.ump_class = class_create(THIS_MODULE, ump_dev_name); + if (IS_ERR(ump_device.ump_class)) + { + err = PTR_ERR(ump_device.ump_class); + } + else + { + struct device * mdev; + mdev = device_create(ump_device.ump_class, NULL, dev, NULL, ump_dev_name); + if (!IS_ERR(mdev)) + { + return 0; + } + + err = PTR_ERR(mdev); + } + cdev_del(&ump_device.cdev); +#else + return 0; +#endif + } + + unregister_chrdev_region(dev, 1); + } + + return err; +} + + + +/* + * Terminate the UMP device driver + */ +void ump_kernel_device_terminate(void) +{ + dev_t dev = MKDEV(ump_major, 0); + +#if UMP_LICENSE_IS_GPL + device_destroy(ump_device.ump_class, dev); + class_destroy(ump_device.ump_class); +#endif + + /* unregister char device */ + cdev_del(&ump_device.cdev); + + /* free major */ + unregister_chrdev_region(dev, 1); + +#if UMP_LICENSE_IS_GPL + if(ump_debugfs_dir) + debugfs_remove_recursive(ump_debugfs_dir); +#endif +} + +/* + * Open a new session. User space has called open() on us. + */ +static int ump_file_open(struct inode *inode, struct file *filp) +{ + struct ump_session_data * session_data; + _mali_osk_errcode_t err; + + /* input validation */ + if (0 != MINOR(inode->i_rdev)) + { + MSG_ERR(("Minor not zero in ump_file_open()\n")); + return -ENODEV; + } + + /* Call the OS-Independent UMP Open function */ + err = _ump_ukk_open((void**) &session_data ); + if( _MALI_OSK_ERR_OK != err ) + { + MSG_ERR(("Ump failed to open a new session\n")); + return map_errcode( err ); + } + + filp->private_data = (void*)session_data; + filp->f_pos = 0; + + return 0; /* success */ +} + + + +/* + * Close a session. User space has called close() or crashed/terminated. + */ +static int ump_file_release(struct inode *inode, struct file *filp) +{ + _mali_osk_errcode_t err; + + err = _ump_ukk_close((void**) &filp->private_data ); + if( _MALI_OSK_ERR_OK != err ) + { + return map_errcode( err ); + } + + return 0; /* success */ +} + + + +/* + * Handle IOCTL requests. + */ +#ifdef HAVE_UNLOCKED_IOCTL +static long ump_file_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +#else +static int ump_file_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +#endif +{ + int err = -ENOTTY; + void __user * argument; + struct ump_session_data * session_data; + +#ifndef HAVE_UNLOCKED_IOCTL + (void)inode; /* inode not used */ +#endif + + session_data = (struct ump_session_data *)filp->private_data; + if (NULL == session_data) + { + MSG_ERR(("No session data attached to file object\n")); + return -ENOTTY; + } + + /* interpret the argument as a user pointer to something */ + argument = (void __user *)arg; + + switch (cmd) + { + case UMP_IOC_QUERY_API_VERSION: + err = ump_get_api_version_wrapper((u32 __user *)argument, session_data); + break; + + case UMP_IOC_ALLOCATE : + err = ump_allocate_wrapper((u32 __user *)argument, session_data); + break; +#ifdef CONFIG_ION_EXYNOS + case UMP_IOC_ION_IMPORT: + err = ump_ion_import_wrapper((u32 __user *)argument, session_data); + break; +#endif +#ifdef CONFIG_DMA_SHARED_BUFFER + case UMP_IOC_DMABUF_IMPORT: + err = ump_dmabuf_import_wrapper((u32 __user *)argument, + session_data); + break; +#endif + case UMP_IOC_RELEASE: + err = ump_release_wrapper((u32 __user *)argument, session_data); + break; + + case UMP_IOC_SIZE_GET: + err = ump_size_get_wrapper((u32 __user *)argument, session_data); + break; + + case UMP_IOC_MSYNC: + err = ump_msync_wrapper((u32 __user *)argument, session_data); + break; + + case UMP_IOC_CACHE_OPERATIONS_CONTROL: + err = ump_cache_operations_control_wrapper((u32 __user *)argument, session_data); + break; + + case UMP_IOC_SWITCH_HW_USAGE: + err = ump_switch_hw_usage_wrapper((u32 __user *)argument, session_data); + break; + + case UMP_IOC_LOCK: + err = ump_lock_wrapper((u32 __user *)argument, session_data); + break; + + case UMP_IOC_UNLOCK: + err = ump_unlock_wrapper((u32 __user *)argument, session_data); + break; + + default: + DBG_MSG(1, ("No handler for IOCTL. cmd: 0x%08x, arg: 0x%08lx\n", cmd, arg)); + err = -EFAULT; + break; + } + + return err; +} + +#ifndef CONFIG_VIDEO_UMP +int map_errcode( _mali_osk_errcode_t err ) +{ + switch(err) + { + case _MALI_OSK_ERR_OK : return 0; + case _MALI_OSK_ERR_FAULT: return -EFAULT; + case _MALI_OSK_ERR_INVALID_FUNC: return -ENOTTY; + case _MALI_OSK_ERR_INVALID_ARGS: return -EINVAL; + case _MALI_OSK_ERR_NOMEM: return -ENOMEM; + case _MALI_OSK_ERR_TIMEOUT: return -ETIMEDOUT; + case _MALI_OSK_ERR_RESTARTSYSCALL: return -ERESTARTSYS; + case _MALI_OSK_ERR_ITEM_NOT_FOUND: return -ENOENT; + default: return -EFAULT; + } +} +#endif + +/* + * Handle from OS to map specified virtual memory to specified UMP memory. + */ +static int ump_file_mmap(struct file * filp, struct vm_area_struct * vma) +{ + _ump_uk_map_mem_s args; + _mali_osk_errcode_t err; + struct ump_session_data * session_data; + + /* Validate the session data */ + session_data = (struct ump_session_data *)filp->private_data; + if (NULL == session_data || NULL == session_data->cookies_map->table->mappings) + { + MSG_ERR(("mmap() called without any session data available\n")); + return -EFAULT; + } + + /* Re-pack the arguments that mmap() packed for us */ + args.ctx = session_data; + args.phys_addr = 0; + args.size = vma->vm_end - vma->vm_start; + args._ukk_private = vma; + args.secure_id = vma->vm_pgoff; + args.is_cached = 0; + + if (!(vma->vm_flags & VM_SHARED)) + { + args.is_cached = 1; + vma->vm_flags = vma->vm_flags | VM_SHARED | VM_MAYSHARE ; + DBG_MSG(3, ("UMP Map function: Forcing the CPU to use cache\n")); + } + /* By setting this flag, during a process fork; the child process will not have the parent UMP mappings */ + vma->vm_flags |= VM_DONTCOPY; + + DBG_MSG(4, ("UMP vma->flags: %x\n", vma->vm_flags )); + + /* Call the common mmap handler */ + err = _ump_ukk_map_mem( &args ); + if ( _MALI_OSK_ERR_OK != err) + { + MSG_ERR(("_ump_ukk_map_mem() failed in function ump_file_mmap()")); + return map_errcode( err ); + } + + return 0; /* success */ +} + +/* Export UMP kernel space API functions */ +EXPORT_SYMBOL(ump_dd_secure_id_get); +EXPORT_SYMBOL(ump_dd_handle_create_from_secure_id); +EXPORT_SYMBOL(ump_dd_phys_block_count_get); +EXPORT_SYMBOL(ump_dd_phys_block_get); +EXPORT_SYMBOL(ump_dd_phys_blocks_get); +EXPORT_SYMBOL(ump_dd_size_get); +EXPORT_SYMBOL(ump_dd_reference_add); +EXPORT_SYMBOL(ump_dd_reference_release); +EXPORT_SYMBOL(ump_dd_meminfo_get); +EXPORT_SYMBOL(ump_dd_meminfo_set); +EXPORT_SYMBOL(ump_dd_handle_get_from_vaddr); + +/* Export our own extended kernel space allocator */ +EXPORT_SYMBOL(ump_dd_handle_create_from_phys_blocks); + +/* Setup init and exit functions for this module */ +//module_init(ump_initialize_module); +arch_initcall(ump_initialize_module); +module_exit(ump_cleanup_module); + +/* And some module informatio */ +MODULE_LICENSE(UMP_KERNEL_LINUX_LICENSE); +MODULE_AUTHOR("ARM Ltd."); +MODULE_VERSION(SVN_REV_STRING); diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_linux.h b/drivers/media/video/samsung/ump/linux/ump_kernel_linux.h new file mode 100644 index 0000000..4985bb7 --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_linux.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +#ifndef __UMP_KERNEL_LINUX_H__ +#define __UMP_KERNEL_LINUX_H__ + +int ump_kernel_device_initialize(void); +void ump_kernel_device_terminate(void); + + +#endif /* __UMP_KERNEL_H__ */ diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.c b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.c new file mode 100644 index 0000000..82c16cc --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +/* needed to detect kernel version specific code */ +#include <linux/version.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#include <linux/semaphore.h> +#else /* pre 2.6.26 the file was in the arch specific location */ +#include <asm/semaphore.h> +#endif + +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/atomic.h> +#include <linux/vmalloc.h> +#include "ump_kernel_common.h" +#include "ump_kernel_memory_backend.h" + + + +#define UMP_BLOCK_SIZE (256UL * 1024UL) /* 256kB, remember to keep the ()s */ + + + +typedef struct block_info +{ + struct block_info * next; +} block_info; + + + +typedef struct block_allocator +{ + struct semaphore mutex; + block_info * all_blocks; + block_info * first_free; + u32 base; + u32 num_blocks; + u32 num_free; +} block_allocator; + + +static void block_allocator_shutdown(ump_memory_backend * backend); +static int block_allocator_allocate(void* ctx, ump_dd_mem * mem); +static void block_allocator_release(void * ctx, ump_dd_mem * handle); +static inline u32 get_phys(block_allocator * allocator, block_info * block); +static u32 block_allocator_stat(struct ump_memory_backend *backend); + + + +/* + * Create dedicated memory backend + */ +ump_memory_backend * ump_block_allocator_create(u32 base_address, u32 size) +{ + ump_memory_backend * backend; + block_allocator * allocator; + u32 usable_size; + u32 num_blocks; + + usable_size = (size + UMP_BLOCK_SIZE - 1) & ~(UMP_BLOCK_SIZE - 1); + num_blocks = usable_size / UMP_BLOCK_SIZE; + + if (0 == usable_size) + { + DBG_MSG(1, ("Memory block of size %u is unusable\n", size)); + return NULL; + } + + DBG_MSG(5, ("Creating dedicated UMP memory backend. Base address: 0x%08x, size: 0x%08x\n", base_address, size)); + DBG_MSG(6, ("%u usable bytes which becomes %u blocks\n", usable_size, num_blocks)); + + backend = kzalloc(sizeof(ump_memory_backend), GFP_KERNEL); + if (NULL != backend) + { + allocator = kmalloc(sizeof(block_allocator), GFP_KERNEL); + if (NULL != allocator) + { + allocator->all_blocks = kmalloc(sizeof(block_allocator) * num_blocks, GFP_KERNEL); + if (NULL != allocator->all_blocks) + { + int i; + + allocator->first_free = NULL; + allocator->num_blocks = num_blocks; + allocator->num_free = num_blocks; + allocator->base = base_address; + sema_init(&allocator->mutex, 1); + + for (i = 0; i < num_blocks; i++) + { + allocator->all_blocks[i].next = allocator->first_free; + allocator->first_free = &allocator->all_blocks[i]; + } + + backend->ctx = allocator; + backend->allocate = block_allocator_allocate; + backend->release = block_allocator_release; + backend->shutdown = block_allocator_shutdown; + backend->stat = block_allocator_stat; + backend->pre_allocate_physical_check = NULL; + backend->adjust_to_mali_phys = NULL; + backend->get = NULL; + backend->set = NULL; + + return backend; + } + kfree(allocator); + } + kfree(backend); + } + + return NULL; +} + + + +/* + * Destroy specified dedicated memory backend + */ +static void block_allocator_shutdown(ump_memory_backend * backend) +{ + block_allocator * allocator; + + BUG_ON(!backend); + BUG_ON(!backend->ctx); + + allocator = (block_allocator*)backend->ctx; + + DBG_MSG_IF(1, allocator->num_free != allocator->num_blocks, ("%u blocks still in use during shutdown\n", allocator->num_blocks - allocator->num_free)); + + kfree(allocator->all_blocks); + kfree(allocator); + kfree(backend); +} + + + +static int block_allocator_allocate(void* ctx, ump_dd_mem * mem) +{ + block_allocator * allocator; + u32 left; + block_info * last_allocated = NULL; + int i = 0; + + BUG_ON(!ctx); + BUG_ON(!mem); + + allocator = (block_allocator*)ctx; + left = mem->size_bytes; + + BUG_ON(!left); + BUG_ON(!&allocator->mutex); + + mem->nr_blocks = ((left + UMP_BLOCK_SIZE - 1) & ~(UMP_BLOCK_SIZE - 1)) / UMP_BLOCK_SIZE; + mem->block_array = (ump_dd_physical_block*)vmalloc(sizeof(ump_dd_physical_block) * mem->nr_blocks); + if (NULL == mem->block_array) + { + MSG_ERR(("Failed to allocate block array\n")); + return 0; + } + + if (down_interruptible(&allocator->mutex)) + { + MSG_ERR(("Could not get mutex to do block_allocate\n")); + return 0; + } + + mem->size_bytes = 0; + + while ((left > 0) && (allocator->first_free)) + { + block_info * block; + + block = allocator->first_free; + allocator->first_free = allocator->first_free->next; + block->next = last_allocated; + last_allocated = block; + allocator->num_free--; + + mem->block_array[i].addr = get_phys(allocator, block); + mem->block_array[i].size = UMP_BLOCK_SIZE; + mem->size_bytes += UMP_BLOCK_SIZE; + + i++; + + if (left < UMP_BLOCK_SIZE) left = 0; + else left -= UMP_BLOCK_SIZE; + } + + if (left) + { + block_info * block; + /* release all memory back to the pool */ + while (last_allocated) + { + block = last_allocated->next; + last_allocated->next = allocator->first_free; + allocator->first_free = last_allocated; + last_allocated = block; + allocator->num_free++; + } + + vfree(mem->block_array); + mem->backend_info = NULL; + mem->block_array = NULL; + + DBG_MSG(4, ("Could not find a mem-block for the allocation.\n")); + up(&allocator->mutex); + + return 0; + } + + mem->backend_info = last_allocated; + + up(&allocator->mutex); + mem->is_cached=0; + + return 1; +} + + + +static void block_allocator_release(void * ctx, ump_dd_mem * handle) +{ + block_allocator * allocator; + block_info * block, * next; + + BUG_ON(!ctx); + BUG_ON(!handle); + + allocator = (block_allocator*)ctx; + block = (block_info*)handle->backend_info; + BUG_ON(!block); + + if (down_interruptible(&allocator->mutex)) + { + MSG_ERR(("Allocator release: Failed to get mutex - memory leak\n")); + return; + } + + while (block) + { + next = block->next; + + BUG_ON( (block < allocator->all_blocks) || (block > (allocator->all_blocks + allocator->num_blocks))); + + block->next = allocator->first_free; + allocator->first_free = block; + allocator->num_free++; + + block = next; + } + DBG_MSG(3, ("%d blocks free after release call\n", allocator->num_free)); + up(&allocator->mutex); + + vfree(handle->block_array); + handle->block_array = NULL; +} + + + +/* + * Helper function for calculating the physical base adderss of a memory block + */ +static inline u32 get_phys(block_allocator * allocator, block_info * block) +{ + return allocator->base + ((block - allocator->all_blocks) * UMP_BLOCK_SIZE); +} + +static u32 block_allocator_stat(struct ump_memory_backend *backend) +{ + block_allocator *allocator; + BUG_ON(!backend); + allocator = (block_allocator*)backend->ctx; + BUG_ON(!allocator); + + return (allocator->num_blocks - allocator->num_free)* UMP_BLOCK_SIZE; +} diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.h b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.h new file mode 100644 index 0000000..ca8faae --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2010, 2012 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 ump_kernel_memory_backend_dedicated.h + */ + +#ifndef __UMP_KERNEL_MEMORY_BACKEND_DEDICATED_H__ +#define __UMP_KERNEL_MEMORY_BACKEND_DEDICATED_H__ + +#include "ump_kernel_memory_backend.h" + +ump_memory_backend * ump_block_allocator_create(u32 base_address, u32 size); + +#endif /* __UMP_KERNEL_MEMORY_BACKEND_DEDICATED_H__ */ + diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c new file mode 100644 index 0000000..8f6a9b3 --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +/* needed to detect kernel version specific code */ +#include <linux/version.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#include <linux/semaphore.h> +#else /* pre 2.6.26 the file was in the arch specific location */ +#include <asm/semaphore.h> +#endif + +#include <linux/dma-mapping.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/atomic.h> +#include <linux/vmalloc.h> +#include <asm/cacheflush.h> +#include "ump_kernel_common.h" +#include "ump_kernel_memory_backend.h" + + + +typedef struct os_allocator +{ + struct semaphore mutex; + u32 num_pages_max; /**< Maximum number of pages to allocate from the OS */ + u32 num_pages_allocated; /**< Number of pages allocated from the OS */ +} os_allocator; + + + +static void os_free(void* ctx, ump_dd_mem * descriptor); +static int os_allocate(void* ctx, ump_dd_mem * descriptor); +static void os_memory_backend_destroy(ump_memory_backend * backend); +static u32 os_stat(struct ump_memory_backend *backend); + + + +/* + * Create OS memory backend + */ +ump_memory_backend * ump_os_memory_backend_create(const int max_allocation) +{ + ump_memory_backend * backend; + os_allocator * info; + + info = kmalloc(sizeof(os_allocator), GFP_KERNEL); + if (NULL == info) + { + return NULL; + } + + info->num_pages_max = max_allocation >> PAGE_SHIFT; + info->num_pages_allocated = 0; + + sema_init(&info->mutex, 1); + + backend = kmalloc(sizeof(ump_memory_backend), GFP_KERNEL); + if (NULL == backend) + { + kfree(info); + return NULL; + } + + backend->ctx = info; + backend->allocate = os_allocate; + backend->release = os_free; + backend->shutdown = os_memory_backend_destroy; + backend->stat = os_stat; + backend->pre_allocate_physical_check = NULL; + backend->adjust_to_mali_phys = NULL; + backend->get = NULL; + backend->set = NULL; + + return backend; +} + + + +/* + * Destroy specified OS memory backend + */ +static void os_memory_backend_destroy(ump_memory_backend * backend) +{ + os_allocator * info = (os_allocator*)backend->ctx; + + DBG_MSG_IF(1, 0 != info->num_pages_allocated, ("%d pages still in use during shutdown\n", info->num_pages_allocated)); + + kfree(info); + kfree(backend); +} + + + +/* + * Allocate UMP memory + */ +static int os_allocate(void* ctx, ump_dd_mem * descriptor) +{ + u32 left; + os_allocator * info; + int pages_allocated = 0; + int is_cached; + + BUG_ON(!descriptor); + BUG_ON(!ctx); + + info = (os_allocator*)ctx; + left = descriptor->size_bytes; + is_cached = descriptor->is_cached; + + if (down_interruptible(&info->mutex)) + { + DBG_MSG(1, ("Failed to get mutex in os_free\n")); + return 0; /* failure */ + } + + descriptor->backend_info = NULL; + descriptor->nr_blocks = ((left + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) >> PAGE_SHIFT; + + DBG_MSG(5, ("Allocating page array. Size: %lu\n", descriptor->nr_blocks * sizeof(ump_dd_physical_block))); + + descriptor->block_array = (ump_dd_physical_block *)vmalloc(sizeof(ump_dd_physical_block) * descriptor->nr_blocks); + if (NULL == descriptor->block_array) + { + up(&info->mutex); + DBG_MSG(1, ("Block array could not be allocated\n")); + return 0; /* failure */ + } + + while (left > 0) + { + struct page * new_page; + + if (is_cached) + { + new_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NORETRY | __GFP_NOWARN ); + } else + { + new_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NORETRY | __GFP_NOWARN | __GFP_COLD); + } + if (NULL == new_page) + { + MSG_ERR(("UMP memory allocated: Out of Memory !!\n")); + break; + } + + /* Ensure page caches are flushed. */ + if ( is_cached ) + { + descriptor->block_array[pages_allocated].addr = page_to_phys(new_page); + descriptor->block_array[pages_allocated].size = PAGE_SIZE; + } else + { + descriptor->block_array[pages_allocated].addr = dma_map_page(NULL, new_page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL ); + descriptor->block_array[pages_allocated].size = PAGE_SIZE; + } + + DBG_MSG(5, ("Allocated page 0x%08lx cached: %d\n", descriptor->block_array[pages_allocated].addr, is_cached)); + + if (left < PAGE_SIZE) + { + left = 0; + } + else + { + left -= PAGE_SIZE; + } + + pages_allocated++; + } + + DBG_MSG(5, ("Alloce for ID:%2d got %d pages, cached: %d\n", descriptor->secure_id, pages_allocated)); + + if (left) + { + DBG_MSG(1, ("Failed to allocate needed pages\n")); + DBG_MSG(1, ("UMP memory allocated: %d kB Configured maximum OS memory usage: %d kB\n", + (pages_allocated * _MALI_OSK_CPU_PAGE_SIZE)/1024, (info->num_pages_max* _MALI_OSK_CPU_PAGE_SIZE)/1024)); + + while(pages_allocated) + { + pages_allocated--; + if ( !is_cached ) + { + dma_unmap_page(NULL, descriptor->block_array[pages_allocated].addr, PAGE_SIZE, DMA_BIDIRECTIONAL); + } + __free_page(pfn_to_page(descriptor->block_array[pages_allocated].addr >> PAGE_SHIFT) ); + } + + up(&info->mutex); + + return 0; /* failure */ + } + + info->num_pages_allocated += pages_allocated; + + DBG_MSG(6, ("%d out of %d pages now allocated\n", info->num_pages_allocated, info->num_pages_max)); + + up(&info->mutex); + + return 1; /* success*/ +} + + +/* + * Free specified UMP memory + */ +static void os_free(void* ctx, ump_dd_mem * descriptor) +{ + os_allocator * info; + int i; + + BUG_ON(!ctx); + BUG_ON(!descriptor); + + info = (os_allocator*)ctx; + + BUG_ON(descriptor->nr_blocks > info->num_pages_allocated); + + if (down_interruptible(&info->mutex)) + { + DBG_MSG(1, ("Failed to get mutex in os_free\n")); + return; + } + + DBG_MSG(5, ("Releasing %lu OS pages\n", descriptor->nr_blocks)); + + info->num_pages_allocated -= descriptor->nr_blocks; + + up(&info->mutex); + + for ( i = 0; i < descriptor->nr_blocks; i++) + { + DBG_MSG(6, ("Freeing physical page. Address: 0x%08lx\n", descriptor->block_array[i].addr)); + if ( ! descriptor->is_cached) + { + dma_unmap_page(NULL, descriptor->block_array[i].addr, PAGE_SIZE, DMA_BIDIRECTIONAL); + } + __free_page(pfn_to_page(descriptor->block_array[i].addr>>PAGE_SHIFT) ); + } + + vfree(descriptor->block_array); +} + + +static u32 os_stat(struct ump_memory_backend *backend) +{ + os_allocator *info; + info = (os_allocator*)backend->ctx; + return info->num_pages_allocated * _MALI_OSK_MALI_PAGE_SIZE; +} diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.h b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.h new file mode 100644 index 0000000..6f7e610 --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2010, 2012 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 ump_kernel_memory_backend_os.h + */ + +#ifndef __UMP_KERNEL_MEMORY_BACKEND_OS_H__ +#define __UMP_KERNEL_MEMORY_BACKEND_OS_H__ + +#include "ump_kernel_memory_backend.h" + +ump_memory_backend * ump_os_memory_backend_create(const int max_allocation); + +#endif /* __UMP_KERNEL_MEMORY_BACKEND_OS_H__ */ + diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.c b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.c new file mode 100644 index 0000000..46797ea --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +/* create by boojin.kim@samsung.com */ +/* needed to detect kernel version specific code */ +#include <linux/version.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#include <linux/semaphore.h> +#else /* pre 2.6.26 the file was in the arch specific location */ +#include <asm/semaphore.h> +#endif + +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/atomic.h> +#include <linux/vmalloc.h> +#include <asm/cacheflush.h> +#include "ump_kernel_common.h" +#include "ump_kernel_memory_backend.h" +#include "ump_kernel_interface_ref_drv.h" +#include "ump_kernel_memory_backend_vcm.h" +#include "../common/ump_uk_types.h" +#include <linux/vcm-drv.h> +#include <plat/s5p-vcm.h> +#include <linux/dma-mapping.h> + +#define UMP_REF_DRV_UK_VCM_DEV_G2D 12 + +typedef struct ump_vcm { + struct vcm *vcm; + struct vcm_res *vcm_res; + unsigned int dev_id; +} ump_vcm; + +typedef struct vcm_allocator { + struct semaphore mutex; + u32 num_vcm_blocks; +} vcm_allocator; + +static void ump_vcm_free(void* ctx, ump_dd_mem * descriptor); +static int ump_vcm_allocate(void* ctx, ump_dd_mem * descriptor); +static void *vcm_res_get(ump_dd_mem *mem, void* args); +static void vcm_attr_set(ump_dd_mem *mem, void* args); +static int vcm_mem_allocator(vcm_allocator *info, ump_dd_mem *descriptor); +static void vcm_memory_backend_destroy(ump_memory_backend * backend); + + +/* + * Create VCM memory backend + */ +ump_memory_backend * ump_vcm_memory_backend_create(const int max_allocation) +{ + ump_memory_backend * backend; + vcm_allocator * info; + + info = kmalloc(sizeof(vcm_allocator), GFP_KERNEL); + if (NULL == info) + { + return NULL; + } + + info->num_vcm_blocks = 0; + + + sema_init(&info->mutex, 1); + + backend = kmalloc(sizeof(ump_memory_backend), GFP_KERNEL); + if (NULL == backend) + { + kfree(info); + return NULL; + } + + backend->ctx = info; + backend->allocate = ump_vcm_allocate; + backend->release = ump_vcm_free; + backend->shutdown = vcm_memory_backend_destroy; + backend->pre_allocate_physical_check = NULL; + backend->adjust_to_mali_phys = NULL; + + backend->get = vcm_res_get; + backend->set = vcm_attr_set; + + + return backend; +} + +/* + * Destroy specified VCM memory backend + */ +static void vcm_memory_backend_destroy(ump_memory_backend * backend) +{ + vcm_allocator * info = (vcm_allocator*)backend->ctx; +#if 0 + DBG_MSG_IF(1, 0 != info->num_pages_allocated, ("%d pages still in use during shutdown\n", info->num_pages_allocated)); +#endif + kfree(info); + kfree(backend); +} + +/* + * Allocate UMP memory + */ +static int ump_vcm_allocate(void *ctx, ump_dd_mem * descriptor) +{ + int ret; /* success */ + vcm_allocator *info; + struct ump_vcm *ump_vcm; + + BUG_ON(!descriptor); + BUG_ON(!ctx); + + info = (vcm_allocator*)ctx; + + ump_vcm = kmalloc(sizeof(struct ump_vcm), GFP_KERNEL); + if (NULL == ump_vcm) + { + return 0; + } + + ump_vcm->dev_id = (int)descriptor->backend_info & ~UMP_REF_DRV_UK_CONSTRAINT_USE_CACHE; + + if(ump_vcm->dev_id == UMP_REF_DRV_UK_CONSTRAINT_NONE) { /* None */ + ump_vcm->dev_id = UMP_REF_DRV_UK_VCM_DEV_G2D; /* this ID is G2D */ + } + else if(ump_vcm->dev_id == UMP_REF_DRV_UK_CONSTRAINT_PHYSICALLY_LINEAR) { /* Physical Linear */ + return 0; + } + else { /* Other VCM */ + ump_vcm->dev_id -= 2; + } + + DBG_MSG(5, ("Device ID for VCM : %d\n", ump_vcm->dev_id)); + ump_vcm->vcm = vcm_find_vcm(ump_vcm->dev_id); + + if (!ump_vcm->vcm) + { + return 0; + } + descriptor->backend_info = (void*)ump_vcm; + + if (down_interruptible(&info->mutex)) { + DBG_MSG(1, ("Failed to get mutex in ump_vcm_allocate\n")); + return 0; /* failure */ + } + + ret = vcm_mem_allocator(info, descriptor); + up(&info->mutex); + + return ret; /* success */ +} + +static int vcm_mem_allocator(vcm_allocator *info, ump_dd_mem *descriptor) +{ + unsigned long num_blocks; + int i; + struct vcm_phys *phys; + struct vcm_phys_part *part; + int size_total = 0; + struct ump_vcm *ump_vcm; + + ump_vcm = (struct ump_vcm*)descriptor->backend_info; + + ump_vcm->vcm_res = + vcm_make_binding(ump_vcm->vcm, descriptor->size_bytes, + ump_vcm->dev_id, 0); + + phys = ump_vcm->vcm_res->phys; + part = phys->parts; + num_blocks = phys->count; + + DBG_MSG(5, + ("Allocating page array. Size: %lu, VCM Reservation : 0x%x\n", + phys->count * sizeof(ump_dd_physical_block), + ump_vcm->vcm_res->start)); + + /* Now, make a copy of the block information supplied by the user */ + descriptor->block_array = + (ump_dd_physical_block *) vmalloc(sizeof(ump_dd_physical_block) * + num_blocks); + + if (NULL == descriptor->block_array) { + vfree(descriptor->block_array); + DBG_MSG(1, ("Could not allocate a mem handle for function.\n")); + return 0; /* failure */ + } + + for (i = 0; i < num_blocks; i++) { + descriptor->block_array[i].addr = part->start; + descriptor->block_array[i].size = part->size; + + dmac_unmap_area(phys_to_virt(part->start), part->size, DMA_FROM_DEVICE); + outer_inv_range(part->start, part->start + part->size); + + ++part; + size_total += descriptor->block_array[i].size; + DBG_MSG(6, + ("UMP memory created with VCM. addr 0x%x, size: 0x%x\n", + descriptor->block_array[i].addr, + descriptor->block_array[i].size)); + } + + descriptor->size_bytes = size_total; + descriptor->nr_blocks = num_blocks; + descriptor->ctx = NULL; + + info->num_vcm_blocks += num_blocks; + return 1; +} + +/* + * Free specified UMP memory + */ +static void ump_vcm_free(void *ctx, ump_dd_mem * descriptor) +{ + struct ump_vcm *ump_vcm; + vcm_allocator *info; + + BUG_ON(!descriptor); + BUG_ON(!ctx); + + ump_vcm = (struct ump_vcm*)descriptor->backend_info; + info = (vcm_allocator*)ctx; + + BUG_ON(descriptor->nr_blocks > info->num_vcm_blocks); + + if (down_interruptible(&info->mutex)) { + DBG_MSG(1, ("Failed to get mutex in ump_vcm_free\n")); + return; + } + + DBG_MSG(5, ("Releasing %lu VCM pages\n", descriptor->nr_blocks)); + + info->num_vcm_blocks -= descriptor->nr_blocks; + + up(&info->mutex); + + DBG_MSG(6, ("Freeing physical page by VCM\n")); + vcm_destroy_binding(ump_vcm->vcm_res); + ump_vcm->vcm = NULL; + ump_vcm->vcm_res = NULL; + + kfree(ump_vcm); + vfree(descriptor->block_array); +} + +static void *vcm_res_get(ump_dd_mem *mem, void *args) +{ + struct ump_vcm *ump_vcm; + enum vcm_dev_id vcm_id; + + ump_vcm = (struct ump_vcm*)mem->backend_info; + vcm_id = (enum vcm_dev_id)args; + + if (vcm_reservation_in_vcm + (vcm_find_vcm(vcm_id), ump_vcm->vcm_res) + == S5PVCM_RES_NOT_IN_VCM) + return NULL; + else + return ump_vcm->vcm_res; +} + +static void vcm_attr_set(ump_dd_mem *mem, void *args) +{ + struct ump_vcm *ump_vcm, *ump_vcmh; + + ump_vcm = (struct ump_vcm*)args; + + ump_vcmh = kmalloc(sizeof(struct ump_vcm), GFP_KERNEL); + if (NULL == ump_vcmh) + { + return; + } + + ump_vcmh->dev_id = ump_vcm->dev_id; + ump_vcmh->vcm = ump_vcm->vcm; + ump_vcmh->vcm_res = ump_vcm->vcm_res; + + mem->backend_info= (void*)ump_vcmh; + + return; +} diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.h b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.h new file mode 100644 index 0000000..c1ead0d --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2010-2012 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 ump_kernel_memory_backend_vcm.h + */ + +#ifndef __UMP_KERNEL_MEMORY_BACKEND_VCM_H__ +#define __UMP_KERNEL_MEMORY_BACKEND_VCM_H__ + +#include "ump_kernel_memory_backend.h" + +ump_memory_backend * ump_vcm_memory_backend_create(const int max_allocation); + +#endif /* __UMP_KERNEL_MEMORY_BACKEND_VCM_H__ */ diff --git a/drivers/media/video/samsung/ump/linux/ump_memory_backend.c b/drivers/media/video/samsung/ump/linux/ump_memory_backend.c new file mode 100644 index 0000000..d067cfe --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_memory_backend.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010, 2012 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. + */ + +#include <linux/module.h> /* kernel module definitions */ +#include <linux/ioport.h> /* request_mem_region */ + +#include "arch/config.h" /* Configuration for current platform. The symlink for arch is set by Makefile */ + +#include "ump_osk.h" +#include "ump_kernel_common.h" +#include "ump_kernel_memory_backend_os.h" +#include "ump_kernel_memory_backend_dedicated.h" + +/* Configure which dynamic memory allocator to use */ +int ump_backend = ARCH_UMP_BACKEND_DEFAULT; +module_param(ump_backend, int, S_IRUGO); /* r--r--r-- */ +MODULE_PARM_DESC(ump_backend, "0 = dedicated memory backend (default), 1 = OS memory backend"); + +/* The base address of the memory block for the dedicated memory backend */ +unsigned int ump_memory_address = ARCH_UMP_MEMORY_ADDRESS_DEFAULT; +module_param(ump_memory_address, uint, S_IRUGO); /* r--r--r-- */ +MODULE_PARM_DESC(ump_memory_address, "The physical address to map for the dedicated memory backend"); + +/* The size of the memory block for the dedicated memory backend */ +unsigned int ump_memory_size = ARCH_UMP_MEMORY_SIZE_DEFAULT; +module_param(ump_memory_size, uint, S_IRUGO); /* r--r--r-- */ +MODULE_PARM_DESC(ump_memory_size, "The size of fixed memory to map in the dedicated memory backend"); + +ump_memory_backend* ump_memory_backend_create ( void ) +{ + ump_memory_backend * backend = NULL; + + /* Create the dynamic memory allocator backend */ + if (0 == ump_backend) + { + DBG_MSG(2, ("Using dedicated memory backend\n")); + + DBG_MSG(2, ("Requesting dedicated memory: 0x%08x, size: %u\n", ump_memory_address, ump_memory_size)); + /* Ask the OS if we can use the specified physical memory */ + if (NULL == request_mem_region(ump_memory_address, ump_memory_size, "UMP Memory")) + { + MSG_ERR(("Failed to request memory region (0x%08X - 0x%08X). Is Mali DD already loaded?\n", ump_memory_address, ump_memory_address + ump_memory_size - 1)); + return NULL; + } + backend = ump_block_allocator_create(ump_memory_address, ump_memory_size); + } + else if (1 == ump_backend) + { + DBG_MSG(2, ("Using OS memory backend, allocation limit: %d\n", ump_memory_size)); + backend = ump_os_memory_backend_create(ump_memory_size); + } +#ifdef CONFIG_UMP_VCM_ALLOC + else if (2 == ump_backend) + { + DBG_MSG(2, ("Using VCM memory backend, allocation limit: %d\n", ump_memory_size)); + backend = ump_vcm_memory_backend_create(ump_memory_size); + } +#endif + + return backend; +} + +void ump_memory_backend_destroy( void ) +{ + if (0 == ump_backend) + { + DBG_MSG(2, ("Releasing dedicated memory: 0x%08x\n", ump_memory_address)); + release_mem_region(ump_memory_address, ump_memory_size); + } +} diff --git a/drivers/media/video/samsung/ump/linux/ump_osk_atomics.c b/drivers/media/video/samsung/ump/linux/ump_osk_atomics.c new file mode 100644 index 0000000..b117d99 --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_osk_atomics.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2010, 2012 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 ump_osk_atomics.c + * Implementation of the OS abstraction layer for the UMP kernel device driver + */ + +#include "ump_osk.h" +#include <asm/atomic.h> + +int _ump_osk_atomic_dec_and_read( _mali_osk_atomic_t *atom ) +{ + return atomic_dec_return((atomic_t *)&atom->u.val); +} + +int _ump_osk_atomic_inc_and_read( _mali_osk_atomic_t *atom ) +{ + return atomic_inc_return((atomic_t *)&atom->u.val); +} diff --git a/drivers/media/video/samsung/ump/linux/ump_osk_low_level_mem.c b/drivers/media/video/samsung/ump/linux/ump_osk_low_level_mem.c new file mode 100644 index 0000000..8ae169a --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_osk_low_level_mem.c @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2010-2012 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 ump_osk_memory.c + * Implementation of the OS abstraction layer for the kernel device driver + */ + +/* needed to detect kernel version specific code */ +#include <linux/version.h> + +#include "ump_osk.h" +#include "ump_uk_types.h" +#include "ump_ukk.h" +#include "ump_kernel_common.h" +#include <linux/module.h> /* kernel module definitions */ +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/slab.h> + +#include <asm/memory.h> +#include <asm/uaccess.h> /* to verify pointers from user space */ +#include <asm/cacheflush.h> +#include <linux/dma-mapping.h> + +typedef struct ump_vma_usage_tracker +{ + atomic_t references; + ump_memory_allocation *descriptor; +} ump_vma_usage_tracker; + +static void ump_vma_open(struct vm_area_struct * vma); +static void ump_vma_close(struct vm_area_struct * vma); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +static int ump_cpu_page_fault_handler(struct vm_area_struct *vma, struct vm_fault *vmf); +#else +static unsigned long ump_cpu_page_fault_handler(struct vm_area_struct * vma, unsigned long address); +#endif + +static struct vm_operations_struct ump_vm_ops = +{ + .open = ump_vma_open, + .close = ump_vma_close, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + .fault = ump_cpu_page_fault_handler +#else + .nopfn = ump_cpu_page_fault_handler +#endif +}; + +/* + * Page fault for VMA region + * This should never happen since we always map in the entire virtual memory range. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +static int ump_cpu_page_fault_handler(struct vm_area_struct *vma, struct vm_fault *vmf) +#else +static unsigned long ump_cpu_page_fault_handler(struct vm_area_struct * vma, unsigned long address) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + void __user * address; + address = vmf->virtual_address; +#endif + MSG_ERR(("Page-fault in UMP memory region caused by the CPU\n")); + MSG_ERR(("VMA: 0x%08lx, virtual address: 0x%08lx\n", (unsigned long)vma, address)); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + return VM_FAULT_SIGBUS; +#else + return NOPFN_SIGBUS; +#endif +} + +static void ump_vma_open(struct vm_area_struct * vma) +{ + ump_vma_usage_tracker * vma_usage_tracker; + int new_val; + + vma_usage_tracker = (ump_vma_usage_tracker*)vma->vm_private_data; + BUG_ON(NULL == vma_usage_tracker); + + new_val = atomic_inc_return(&vma_usage_tracker->references); + + DBG_MSG(4, ("VMA open, VMA reference count incremented. VMA: 0x%08lx, reference count: %d\n", (unsigned long)vma, new_val)); +} + +static void ump_vma_close(struct vm_area_struct * vma) +{ + ump_vma_usage_tracker * vma_usage_tracker; + _ump_uk_unmap_mem_s args; + int new_val; + + vma_usage_tracker = (ump_vma_usage_tracker*)vma->vm_private_data; + BUG_ON(NULL == vma_usage_tracker); + + new_val = atomic_dec_return(&vma_usage_tracker->references); + + DBG_MSG(4, ("VMA close, VMA reference count decremented. VMA: 0x%08lx, reference count: %d\n", (unsigned long)vma, new_val)); + + if (0 == new_val) + { + ump_memory_allocation * descriptor; + + descriptor = vma_usage_tracker->descriptor; + + args.ctx = descriptor->ump_session; + args.cookie = descriptor->cookie; + args.mapping = descriptor->mapping; + args.size = descriptor->size; + + args._ukk_private = NULL; /** @note unused */ + + DBG_MSG(4, ("No more VMA references left, releasing UMP memory\n")); + _ump_ukk_unmap_mem( & args ); + + /* vma_usage_tracker is free()d by _ump_osk_mem_mapregion_term() */ + } +} + +_mali_osk_errcode_t _ump_osk_mem_mapregion_init( ump_memory_allocation * descriptor ) +{ + ump_vma_usage_tracker * vma_usage_tracker; + struct vm_area_struct *vma; + + if (NULL == descriptor) return _MALI_OSK_ERR_FAULT; + + vma_usage_tracker = kmalloc(sizeof(ump_vma_usage_tracker), GFP_KERNEL); + if (NULL == vma_usage_tracker) + { + DBG_MSG(1, ("Failed to allocate memory for ump_vma_usage_tracker in _mali_osk_mem_mapregion_init\n")); + return -_MALI_OSK_ERR_FAULT; + } + + vma = (struct vm_area_struct*)descriptor->process_mapping_info; + if (NULL == vma ) + { + kfree(vma_usage_tracker); + return _MALI_OSK_ERR_FAULT; + } + + vma->vm_private_data = vma_usage_tracker; + vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_RESERVED; + + if (0==descriptor->is_cached) + { + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + } + DBG_MSG(3, ("Mapping with page_prot: 0x%x\n", vma->vm_page_prot )); + + /* Setup the functions which handle further VMA handling */ + vma->vm_ops = &ump_vm_ops; + + /* Do the va range allocation - in this case, it was done earlier, so we copy in that information */ + descriptor->mapping = (void __user*)vma->vm_start; + + atomic_set(&vma_usage_tracker->references, 1); /*this can later be increased if process is forked, see ump_vma_open() */ + vma_usage_tracker->descriptor = descriptor; + + return _MALI_OSK_ERR_OK; +} + +void _ump_osk_mem_mapregion_term( ump_memory_allocation * descriptor ) +{ + struct vm_area_struct* vma; + ump_vma_usage_tracker * vma_usage_tracker; + + if (NULL == descriptor) return; + + /* Linux does the right thing as part of munmap to remove the mapping + * All that remains is that we remove the vma_usage_tracker setup in init() */ + vma = (struct vm_area_struct*)descriptor->process_mapping_info; + + vma_usage_tracker = vma->vm_private_data; + + /* We only get called if mem_mapregion_init succeeded */ + kfree(vma_usage_tracker); + return; +} + +_mali_osk_errcode_t _ump_osk_mem_mapregion_map( ump_memory_allocation * descriptor, u32 offset, u32 * phys_addr, unsigned long size ) +{ + struct vm_area_struct *vma; + _mali_osk_errcode_t retval; + + if (NULL == descriptor) return _MALI_OSK_ERR_FAULT; + + vma = (struct vm_area_struct*)descriptor->process_mapping_info; + + if (NULL == vma ) return _MALI_OSK_ERR_FAULT; + + retval = remap_pfn_range( vma, ((u32)descriptor->mapping) + offset, (*phys_addr) >> PAGE_SHIFT, size, vma->vm_page_prot) ? _MALI_OSK_ERR_FAULT : _MALI_OSK_ERR_OK;; + + DBG_MSG(4, ("Mapping virtual to physical memory. ID: %u, vma: 0x%08lx, virtual addr:0x%08lx, physical addr: 0x%08lx, size:%lu, prot:0x%x, vm_flags:0x%x RETVAL: 0x%x\n", + ump_dd_secure_id_get(descriptor->handle), + (unsigned long)vma, + (unsigned long)(vma->vm_start + offset), + (unsigned long)*phys_addr, + size, + (unsigned int)vma->vm_page_prot, vma->vm_flags, retval)); + + return retval; +} + +static u32 _ump_osk_virt_to_phys_start(ump_dd_mem * mem, u32 start, u32 address, int *index) +{ + int i; + u32 offset = address - start; + ump_dd_physical_block *block; + u32 sum = 0; + + for (i=0; i<mem->nr_blocks; i++) { + block = &mem->block_array[i]; + sum += block->size; + if (sum > offset) { + *index = i; + DBG_MSG(3, ("_ump_osk_virt_to_phys : index : %d, virtual 0x%x, phys 0x%x\n", i, address, (u32)block->addr + offset - (sum -block->size))); + return (u32)block->addr + offset - (sum -block->size); + } + } + + return _MALI_OSK_ERR_FAULT; +} + +static u32 _ump_osk_virt_to_phys_end(ump_dd_mem * mem, u32 start, u32 address, int *index) +{ + int i; + u32 offset = address - start; + ump_dd_physical_block *block; + u32 sum = 0; + + for (i=0; i<mem->nr_blocks; i++) { + block = &mem->block_array[i]; + sum += block->size; + if (sum >= offset) { + *index = i; + DBG_MSG(3, ("_ump_osk_virt_to_phys : index : %d, virtual 0x%x, phys 0x%x\n", i, address, (u32)block->addr + offset - (sum -block->size))); + return (u32)block->addr + offset - (sum -block->size); + } + } + + return _MALI_OSK_ERR_FAULT; +} + +static void _ump_osk_msync_with_virt(ump_dd_mem * mem, ump_uk_msync_op op, u32 start, u32 address, u32 size) +{ + int start_index, end_index; + u32 start_p, end_p; + + DBG_MSG(3, ("Cache flush with user virtual address. start : 0x%x, end : 0x%x, address 0x%x, size 0x%x\n", start, start+mem->size_bytes, address, size)); + + start_p = _ump_osk_virt_to_phys_start(mem, start, address, &start_index); + end_p = _ump_osk_virt_to_phys_end(mem, start, address+size, &end_index); + + if (start_index==end_index) { + if (op == _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE) + outer_flush_range(start_p, end_p); + else + outer_clean_range(start_p, end_p); + } else { + ump_dd_physical_block *block; + int i; + + for (i=start_index; i<=end_index; i++) { + block = &mem->block_array[i]; + + if (i == start_index) { + if (op == _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE) { + outer_flush_range(start_p, block->addr+block->size); + } else { + outer_clean_range(start_p, block->addr+block->size); + } + } + else if (i == end_index) { + if (op == _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE) { + outer_flush_range(block->addr, end_p); + } else { + outer_clean_range(block->addr, end_p); + } + break; + } + else { + if (op == _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE) { + outer_flush_range(block->addr, block->addr+block->size); + } else { + outer_clean_range(block->addr, block->addr+block->size); + } + } + } + } + return; +} + +static void level1_cache_flush_all(void) +{ + DBG_MSG(4, ("UMP[xx] Flushing complete L1 cache\n")); + __cpuc_flush_kern_all(); +} + +void _ump_osk_msync( ump_dd_mem * mem, void * virt, u32 offset, u32 size, ump_uk_msync_op op, ump_session_data * session_data ) +{ + int i; + const void *start_v, *end_v; + + /* Flush L1 using virtual address, the entire range in one go. + * Only flush if user space process has a valid write mapping on given address. */ + if( (mem) && (virt!=NULL) && (access_ok(VERIFY_WRITE, virt, size)) ) + { + start_v = (void *)virt; + end_v = (void *)(start_v + size - 1); + /* There is no dmac_clean_range, so the L1 is always flushed, + * also for UMP_MSYNC_CLEAN. */ + if (size >= SZ_64K) + flush_all_cpu_caches(); + else + dmac_flush_range(start_v, end_v); + + DBG_MSG(3, ("UMP[%02u] Flushing CPU L1 Cache. Cpu address: %x-%x\n", mem->secure_id, start_v,end_v)); + } + else + { + if (session_data) + { + if (op == _UMP_UK_MSYNC_FLUSH_L1 ) + { + DBG_MSG(4, ("UMP Pending L1 cache flushes: %d\n", session_data->has_pending_level1_cache_flush)); + session_data->has_pending_level1_cache_flush = 0; + level1_cache_flush_all(); + return; + } + else + { + if (session_data->cache_operations_ongoing) + { + session_data->has_pending_level1_cache_flush++; + DBG_MSG(4, ("UMP[%02u] Defering the L1 flush. Nr pending:%d\n", mem->secure_id, session_data->has_pending_level1_cache_flush) ); + } + else + { + /* Flushing the L1 cache for each switch_user() if ump_cache_operations_control(START) is not called */ + level1_cache_flush_all(); + } + } + } + else + { + DBG_MSG(4, ("Unkown state %s %d\n", __FUNCTION__, __LINE__)); + level1_cache_flush_all(); + } + } + + if ( NULL == mem ) return; + + if ( mem->size_bytes==size) + { + DBG_MSG(3, ("UMP[%02u] Flushing CPU L2 Cache\n",mem->secure_id)); + } + else + { + DBG_MSG(3, ("UMP[%02u] Flushing CPU L2 Cache. Blocks:%u, TotalSize:%u. FlushSize:%u Offset:0x%x FirstPaddr:0x%08x\n", + mem->secure_id, mem->nr_blocks, mem->size_bytes, size, offset, mem->block_array[0].addr)); + } + + + /* Flush L2 using physical addresses, block for block. */ + if ((virt!=NULL) && (mem->size_bytes >= SZ_1M)) { + if (op == _UMP_UK_MSYNC_CLEAN) + outer_clean_all(); + else if ((op == _UMP_UK_MSYNC_INVALIDATE) || (op == _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE)) + outer_flush_all(); + return; + } + + for (i=0 ; i < mem->nr_blocks; i++) + { + u32 start_p, end_p; + ump_dd_physical_block *block; + block = &mem->block_array[i]; + + if(offset >= block->size) + { + offset -= block->size; + continue; + } + + if(offset) + { + start_p = (u32)block->addr + offset; + /* We'll zero the offset later, after using it to calculate end_p. */ + } + else + { + start_p = (u32)block->addr; + } + + if(size < block->size - offset) + { + end_p = start_p + size - 1; + size = 0; + } + else + { + if(offset) + { + end_p = start_p + (block->size - offset - 1); + size -= block->size - offset; + offset = 0; + } + else + { + end_p = start_p + block->size - 1; + size -= block->size; + } + } + + switch(op) + { + case _UMP_UK_MSYNC_CLEAN: + outer_clean_range(start_p, end_p); + break; + case _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE: + outer_flush_range(start_p, end_p); + break; + case _UMP_UK_MSYNC_INVALIDATE: + outer_inv_range(start_p, end_p); + break; + default: + break; + } + + if(0 == size) + { + /* Nothing left to flush. */ + break; + } + } + + return; +} + +void _ump_osk_mem_mapregion_get( ump_dd_mem ** mem, unsigned long vaddr) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + ump_vma_usage_tracker * vma_usage_tracker; + ump_memory_allocation *descriptor; + ump_dd_handle handle; + + DBG_MSG(3, ("_ump_osk_mem_mapregion_get: vaddr 0x%08lx\n", vaddr)); + + down_read(&mm->mmap_sem); + vma = find_vma(mm, vaddr); + up_read(&mm->mmap_sem); + if(!vma) + { + DBG_MSG(3, ("Not found VMA\n")); + *mem = NULL; + return; + } + DBG_MSG(4, ("Get vma: 0x%08lx vma->vm_start: 0x%08lx\n", (unsigned long)vma, vma->vm_start)); + + vma_usage_tracker = (struct ump_vma_usage_tracker*)vma->vm_private_data; + if(vma_usage_tracker == NULL) + { + DBG_MSG(3, ("Not found vma_usage_tracker\n")); + *mem = NULL; + return; + } + + descriptor = (struct ump_memory_allocation*)vma_usage_tracker->descriptor; + handle = (ump_dd_handle)descriptor->handle; + + DBG_MSG(3, ("Get handle: 0x%08lx\n", handle)); + *mem = (ump_dd_mem*)handle; +} + diff --git a/drivers/media/video/samsung/ump/linux/ump_osk_misc.c b/drivers/media/video/samsung/ump/linux/ump_osk_misc.c new file mode 100644 index 0000000..3be6fed --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_osk_misc.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010, 2012 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 ump_osk_misc.c + * Implementation of the OS abstraction layer for the UMP kernel device driver + */ + + +#include "ump_osk.h" + +#include <linux/kernel.h> +#include "ump_kernel_linux.h" + +/* is called from ump_kernel_constructor in common code */ +_mali_osk_errcode_t _ump_osk_init( void ) +{ + if (0 != ump_kernel_device_initialize()) + { + return _MALI_OSK_ERR_FAULT; + } + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _ump_osk_term( void ) +{ + ump_kernel_device_terminate(); + return _MALI_OSK_ERR_OK; +} diff --git a/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.c b/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.c new file mode 100644 index 0000000..a6691ed --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.c @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2010, 2012 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 ump_ukk_wrappers.c + * Defines the wrapper functions which turn Linux IOCTL calls into _ukk_ calls for the reference implementation + */ + + +#include <asm/uaccess.h> /* user space access */ + +#include "ump_osk.h" +#include "ump_uk_types.h" +#include "ump_ukk.h" +#include "ump_kernel_common.h" + +#if defined(CONFIG_ION_EXYNOS) || defined(CONFIG_DMA_SHARED_BUFFER) +#include <linux/scatterlist.h> +#include "ump_kernel_interface_ref_drv.h" +#include "mali_osk_list.h" +#ifdef CONFIG_ION_EXYNOS +#include <linux/ion.h> +#include "../../../../../gpu/ion/ion_priv.h" +extern struct ion_device *ion_exynos; +extern struct ion_client *ion_client_ump; +#endif +#ifdef CONFIG_DMA_SHARED_BUFFER +#include <linux/dma-buf.h> +#endif +#endif + +/* + * IOCTL operation; Allocate UMP memory + */ +int ump_allocate_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_allocate_s user_interaction; + _mali_osk_errcode_t err; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_allocate()\n")); + return -ENOTTY; + } + + /* Copy the user space memory to kernel space (so we safely can read it) */ + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_allocate()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + err = _ump_ukk_allocate( &user_interaction ); + if( _MALI_OSK_ERR_OK != err ) + { + DBG_MSG(1, ("_ump_ukk_allocate() failed in ump_ioctl_allocate()\n")); + return map_errcode(err); + } + user_interaction.ctx = NULL; + + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + /* If the copy fails then we should release the memory. We can use the IOCTL release to accomplish this */ + _ump_uk_release_s release_args; + + MSG_ERR(("copy_to_user() failed in ump_ioctl_allocate()\n")); + + release_args.ctx = (void *) session_data; + release_args.secure_id = user_interaction.secure_id; + + err = _ump_ukk_release( &release_args ); + if(_MALI_OSK_ERR_OK != err) + { + MSG_ERR(("_ump_ukk_release() also failed when trying to release newly allocated memory in ump_ioctl_allocate()\n")); + } + + return -EFAULT; + } + + return 0; /* success */ +} +#ifdef CONFIG_ION_EXYNOS +/* + * IOCTL operation; Import fd to UMP memory + */ +int ump_ion_import_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_ion_import_s user_interaction; + ump_dd_handle *ump_handle; + ump_dd_physical_block * blocks; + unsigned long num_blocks; + struct ion_handle *ion_hnd; + struct scatterlist *sg; + struct scatterlist *sg_ion; + unsigned long i = 0; + + ump_session_memory_list_element * session_memory_element = NULL; + if (ion_client_ump==NULL) + ion_client_ump = ion_client_create(ion_exynos, -1, "ump"); + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_allocate()\n")); + return -ENOTTY; + } + + /* Copy the user space memory to kernel space (so we safely can read it) */ + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_allocate()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + /* translate fd to secure ID*/ + ion_hnd = ion_import_fd(ion_client_ump, user_interaction.ion_fd); + sg_ion = ion_map_dma(ion_client_ump,ion_hnd); + + blocks = (ump_dd_physical_block*)_mali_osk_malloc(sizeof(ump_dd_physical_block)*1024); + + if (NULL == blocks) { + MSG_ERR(("Failed to allocate blocks in ump_ioctl_allocate()\n")); + return -ENOMEM; + } + + sg = sg_ion; + do { + blocks[i].addr = sg_phys(sg); + blocks[i].size = sg_dma_len(sg); + i++; + if (i>=1024) { + _mali_osk_free(blocks); + MSG_ERR(("ion_import fail() in ump_ioctl_allocate()\n")); + return -EFAULT; + } + sg = sg_next(sg); + } while(sg); + + num_blocks = i; + + /* Initialize the session_memory_element, and add it to the session object */ + session_memory_element = _mali_osk_calloc( 1, sizeof(ump_session_memory_list_element)); + + if (NULL == session_memory_element) + { + _mali_osk_free(blocks); + DBG_MSG(1, ("Failed to allocate ump_session_memory_list_element in ump_ioctl_allocate()\n")); + return -EFAULT; + } + + ump_handle = ump_dd_handle_create_from_phys_blocks(blocks, num_blocks); + if (UMP_DD_HANDLE_INVALID == ump_handle) + { + _mali_osk_free(session_memory_element); + _mali_osk_free(blocks); + DBG_MSG(1, ("Failed to allocate ump_session_memory_list_element in ump_ioctl_allocate()\n")); + return -EFAULT; + } + + session_memory_element->mem = (ump_dd_mem*)ump_handle; + _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); + _mali_osk_list_add(&(session_memory_element->list), &(session_data->list_head_session_memory_list)); + _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); + ion_unmap_dma(ion_client_ump,ion_hnd); + ion_free(ion_client_ump, ion_hnd); + + _mali_osk_free(blocks); + + user_interaction.secure_id = ump_dd_secure_id_get(ump_handle); + user_interaction.size = ump_dd_size_get(ump_handle); + user_interaction.ctx = NULL; + + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + /* If the copy fails then we should release the memory. We can use the IOCTL release to accomplish this */ + + MSG_ERR(("copy_to_user() failed in ump_ioctl_allocate()\n")); + + return -EFAULT; + } + return 0; /* success */ +} +#endif + +#ifdef CONFIG_DMA_SHARED_BUFFER +int ump_dmabuf_import_wrapper(u32 __user *argument, + struct ump_session_data *session_data) +{ + ump_session_memory_list_element *session = NULL; + struct ump_uk_dmabuf ump_dmabuf; + ump_dd_handle *ump_handle; + ump_dd_physical_block *blocks; + struct dma_buf_attachment *attach; + struct dma_buf *dma_buf; + struct sg_table *sgt; + struct scatterlist *sgl; + unsigned long block_size; + /* FIXME */ + struct device dev; + unsigned int i = 0, npages; + int ret; + + /* Sanity check input parameters */ + if (!argument || !session_data) { + MSG_ERR(("NULL parameter.\n")); + return -EINVAL; + } + + if (copy_from_user(&ump_dmabuf, argument, + sizeof(struct ump_uk_dmabuf))) { + MSG_ERR(("copy_from_user() failed.\n")); + return -EFAULT; + } + + dma_buf = dma_buf_get(ump_dmabuf.fd); + if (IS_ERR(dma_buf)) + return PTR_ERR(dma_buf); + + /* + * check whether dma_buf imported already exists or not. + * + * TODO + * if already imported then dma_buf_put() should be called + * and then just return dma_buf imported. + */ + + attach = dma_buf_attach(dma_buf, &dev); + if (IS_ERR(attach)) { + ret = PTR_ERR(attach); + goto err_dma_buf_put; + } + + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + goto err_dma_buf_detach; + } + + npages = sgt->nents; + + /* really need? */ + ump_dmabuf.ctx = (void *)session_data; + + block_size = sizeof(ump_dd_physical_block) * npages; + + blocks = (ump_dd_physical_block *)_mali_osk_malloc(block_size); + sgl = sgt->sgl; + + while (i < npages) { + blocks[i].addr = sg_phys(sgl); + blocks[i].size = sg_dma_len(sgl); + sgl = sg_next(sgl); + i++; + } + + /* + * Initialize the session memory list element, and add it + * to the session object + */ + session = _mali_osk_calloc(1, sizeof(*session)); + if (!session) { + DBG_MSG(1, ("Failed to allocate session.\n")); + ret = -EFAULT; + goto err_free_block; + } + + ump_handle = ump_dd_handle_create_from_phys_blocks(blocks, i); + if (UMP_DD_HANDLE_INVALID == ump_handle) { + DBG_MSG(1, ("Failed to create ump handle.\n")); + ret = -EFAULT; + goto err_free_session; + } + + session->mem = (ump_dd_mem *)ump_handle; + + _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); + _mali_osk_list_add(&(session->list), + &(session_data->list_head_session_memory_list)); + _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); + + _mali_osk_free(blocks); + + ump_dmabuf.ump_handle = (uint32_t)ump_handle; + ump_dmabuf.size = ump_dd_size_get(ump_handle); + + if (copy_to_user(argument, &ump_dmabuf, + sizeof(struct ump_uk_dmabuf))) { + MSG_ERR(("copy_to_user() failed.\n")); + ret = -EFAULT; + goto err_release_ump_handle; + } + + return 0; + +err_release_ump_handle: + ump_dd_reference_release(ump_handle); +err_free_session: + _mali_osk_free(session); +err_free_block: + _mali_osk_free(blocks); + dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); +err_dma_buf_detach: + dma_buf_detach(dma_buf, attach); +err_dma_buf_put: + dma_buf_put(dma_buf); + return ret; +} +#endif diff --git a/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.h b/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.h new file mode 100644 index 0000000..416a584 --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010, 2012 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 ump_ukk_wrappers.h + * Defines the wrapper functions which turn Linux IOCTL calls into _ukk_ calls for the reference implementation + */ + +#ifndef __UMP_UKK_REF_WRAPPERS_H__ +#define __UMP_UKK_REF_WRAPPERS_H__ + +#include <linux/kernel.h> +#include "ump_kernel_common.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +int ump_allocate_wrapper(u32 __user * argument, struct ump_session_data * session_data); + +#ifdef CONFIG_ION_EXYNOS +int ump_ion_import_wrapper(u32 __user * argument, struct ump_session_data * session_data); +#endif + +#ifdef CONFIG_DMA_SHARED_BUFFER +int ump_dmabuf_import_wrapper(u32 __user *argument, + struct ump_session_data *session_data); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __UMP_UKK_REF_WRAPPERS_H__ */ diff --git a/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.c b/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.c new file mode 100644 index 0000000..780f311 --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.c @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2010-2012 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 ump_ukk_wrappers.c + * Defines the wrapper functions which turn Linux IOCTL calls into _ukk_ calls + */ + +#include <asm/uaccess.h> /* user space access */ + +#include "ump_osk.h" +#include "ump_uk_types.h" +#include "ump_ukk.h" +#include "ump_kernel_common.h" + +/* + * IOCTL operation; Negotiate version of IOCTL API + */ +int ump_get_api_version_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_api_version_s version_info; + _mali_osk_errcode_t err; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_get_api_version()\n")); + return -ENOTTY; + } + + /* Copy the user space memory to kernel space (so we safely can read it) */ + if (0 != copy_from_user(&version_info, argument, sizeof(version_info))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_get_api_version()\n")); + return -EFAULT; + } + + version_info.ctx = (void*) session_data; + err = _ump_uku_get_api_version( &version_info ); + if( _MALI_OSK_ERR_OK != err ) + { + MSG_ERR(("_ump_uku_get_api_version() failed in ump_ioctl_get_api_version()\n")); + return map_errcode(err); + } + + version_info.ctx = NULL; + + /* Copy ouput data back to user space */ + if (0 != copy_to_user(argument, &version_info, sizeof(version_info))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_get_api_version()\n")); + return -EFAULT; + } + + return 0; /* success */ +} + + +/* + * IOCTL operation; Release reference to specified UMP memory. + */ +int ump_release_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_release_s release_args; + _mali_osk_errcode_t err; + + /* Sanity check input parameters */ + if (NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_release()\n")); + return -ENOTTY; + } + + /* Copy the user space memory to kernel space (so we safely can read it) */ + if (0 != copy_from_user(&release_args, argument, sizeof(release_args))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_get_api_version()\n")); + return -EFAULT; + } + + release_args.ctx = (void*) session_data; + err = _ump_ukk_release( &release_args ); + if( _MALI_OSK_ERR_OK != err ) + { + MSG_ERR(("_ump_ukk_release() failed in ump_ioctl_release()\n")); + return map_errcode(err); + } + + + return 0; /* success */ +} + +/* + * IOCTL operation; Return size for specified UMP memory. + */ +int ump_size_get_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_size_get_s user_interaction; + _mali_osk_errcode_t err; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); + return -ENOTTY; + } + + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_size_get()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + err = _ump_ukk_size_get( &user_interaction ); + if( _MALI_OSK_ERR_OK != err ) + { + MSG_ERR(("_ump_ukk_size_get() failed in ump_ioctl_size_get()\n")); + return map_errcode(err); + } + + user_interaction.ctx = NULL; + + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_size_get()\n")); + return -EFAULT; + } + + return 0; /* success */ +} + +/* + * IOCTL operation; Do cache maintenance on specified UMP memory. + */ +int ump_msync_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_msync_s user_interaction; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); + return -ENOTTY; + } + + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_msync()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + _ump_ukk_msync( &user_interaction ); + + user_interaction.ctx = NULL; + + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_msync()\n")); + return -EFAULT; + } + + return 0; /* success */ +} +int ump_cache_operations_control_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_cache_operations_control_s user_interaction; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); + return -ENOTTY; + } + + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_cache_operations_control()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + _ump_ukk_cache_operations_control((_ump_uk_cache_operations_control_s*) &user_interaction ); + + user_interaction.ctx = NULL; + +#if 0 /* No data to copy back */ + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_cache_operations_control()\n")); + return -EFAULT; + } +#endif + return 0; /* success */ +} + +int ump_switch_hw_usage_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_switch_hw_usage_s user_interaction; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); + return -ENOTTY; + } + + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + _ump_ukk_switch_hw_usage( &user_interaction ); + + user_interaction.ctx = NULL; + +#if 0 /* No data to copy back */ + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } +#endif + return 0; /* success */ +} + +int ump_lock_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_lock_s user_interaction; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); + return -ENOTTY; + } + + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + _ump_ukk_lock( &user_interaction ); + + user_interaction.ctx = NULL; + +#if 0 /* No data to copy back */ + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } +#endif + + return 0; /* success */ +} + +int ump_unlock_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_unlock_s user_interaction; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); + return -ENOTTY; + } + + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + _ump_ukk_unlock( &user_interaction ); + + user_interaction.ctx = NULL; + +#if 0 /* No data to copy back */ + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } +#endif + + return 0; /* success */ +} diff --git a/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.h b/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.h new file mode 100644 index 0000000..e87a903 --- /dev/null +++ b/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010, 2012 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 ump_ukk_wrappers.h + * Defines the wrapper functions which turn Linux IOCTL calls into _ukk_ calls + */ + +#ifndef __UMP_UKK_WRAPPERS_H__ +#define __UMP_UKK_WRAPPERS_H__ + +#include <linux/kernel.h> +#include "ump_kernel_common.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +int ump_get_api_version_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_release_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_size_get_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_msync_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_cache_operations_control_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_switch_hw_usage_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_lock_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_unlock_wrapper(u32 __user * argument, struct ump_session_data * session_data); + + + + +#ifdef __cplusplus +} +#endif + + + +#endif /* __UMP_UKK_WRAPPERS_H__ */ |