aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShow Liu <show.liu@linaro.org>2013-12-26 10:58:18 +0800
committerShow Liu <show.liu@linaro.org>2014-02-20 15:59:54 +0800
commitb82db44ee85b14fd588373f24d48ce1e9ef94c4c (patch)
tree865f12e754531d5c7e7517cb8336eb129f9f09b4
parent3bf3cb238e6fec7ff976d3e641ad18750c6700f2 (diff)
Added ARM mali UMP driver support
-rw-r--r--drivers/base/Kconfig2
-rw-r--r--drivers/base/Makefile1
-rwxr-xr-xdrivers/base/ump/Kbuild17
-rwxr-xr-xdrivers/base/ump/Kconfig25
-rwxr-xr-xdrivers/base/ump/docs/Doxyfile124
-rwxr-xr-xdrivers/base/ump/docs/sconscript30
-rwxr-xr-xdrivers/base/ump/example_kernel_api.c71
-rwxr-xr-xdrivers/base/ump/example_user_api.c151
-rwxr-xr-xdrivers/base/ump/sconscript20
-rwxr-xr-xdrivers/base/ump/src/Kbuild48
-rwxr-xr-xdrivers/base/ump/src/Makefile86
-rwxr-xr-xdrivers/base/ump/src/Makefile.common18
-rw-r--r--drivers/base/ump/src/Module.symvers28
l---------drivers/base/ump/src/arch1
-rwxr-xr-xdrivers/base/ump/src/arch-arm/config.h25
-rwxr-xr-xdrivers/base/ump/src/common/ump_kernel_core.c754
-rwxr-xr-xdrivers/base/ump/src/common/ump_kernel_core.h226
-rwxr-xr-xdrivers/base/ump/src/common/ump_kernel_descriptor_mapping.c160
-rwxr-xr-xdrivers/base/ump/src/common/ump_kernel_descriptor_mapping.h92
-rwxr-xr-xdrivers/base/ump/src/common/ump_kernel_priv.h71
-rwxr-xr-xdrivers/base/ump/src/imports/ion/Makefile52
-rwxr-xr-xdrivers/base/ump/src/imports/ion/sconscript57
-rwxr-xr-xdrivers/base/ump/src/imports/ion/ump_kernel_import_ion.c208
-rwxr-xr-xdrivers/base/ump/src/imports/sconscript24
-rwxr-xr-xdrivers/base/ump/src/linux/ump_kernel_linux.c830
-rwxr-xr-xdrivers/base/ump/src/linux/ump_kernel_linux_mem.c248
-rwxr-xr-xdrivers/base/ump/src/linux/ump_kernel_linux_mem.h24
-rwxr-xr-xdrivers/base/ump/src/sconscript80
-rwxr-xr-xdrivers/base/ump/src/ump_arch.h40
-rwxr-xr-xdrivers/base/ump/ump_ref_drv.h31
-rwxr-xr-xinclude/linux/ump-common.h250
-rwxr-xr-xinclude/linux/ump-import.h97
-rwxr-xr-xinclude/linux/ump-ioctl.h150
-rwxr-xr-xinclude/linux/ump.h479
34 files changed, 4520 insertions, 0 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index c09a1ddba29..0e0a5e147a8 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -304,4 +304,6 @@ config KDS
help
This option enables the generic kernel dependency system
+source "drivers/base/ump/Kconfig"
+
endmenu
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 435077321aa..e4dd2c5ed4f 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_HAS_DMA) += dma-mapping.o
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o
obj-$(CONFIG_KDS) += kds/
+obj-y += ump/
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
diff --git a/drivers/base/ump/Kbuild b/drivers/base/ump/Kbuild
new file mode 100755
index 00000000000..738aed36ed4
--- /dev/null
+++ b/drivers/base/ump/Kbuild
@@ -0,0 +1,17 @@
+#
+# (C) COPYRIGHT 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.
+#
+#
+
+
+obj-y += src/
+
diff --git a/drivers/base/ump/Kconfig b/drivers/base/ump/Kconfig
new file mode 100755
index 00000000000..2e49a38a616
--- /dev/null
+++ b/drivers/base/ump/Kconfig
@@ -0,0 +1,25 @@
+#
+# (C) COPYRIGHT 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.
+#
+#
+
+
+config UMP
+ tristate "Enable Unified Memory Provider (UMP) support"
+ default n
+ help
+ Enable this option to build support for the ARM UMP module.
+ UMP can be used by the Mali T6xx module to improve performance
+ by reducing the copying of data by sharing memory.
+
+ To compile this driver as a module, choose M here:
+ this will generate one module, called ump.
diff --git a/drivers/base/ump/docs/Doxyfile b/drivers/base/ump/docs/Doxyfile
new file mode 100755
index 00000000000..c4a6d1d6a5d
--- /dev/null
+++ b/drivers/base/ump/docs/Doxyfile
@@ -0,0 +1,124 @@
+#
+# (C) COPYRIGHT 2011-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.
+#
+#
+
+
+##############################################################################
+
+# This file contains per-module Doxygen configuration. Please do not add
+# extra settings to this file without consulting all stakeholders, as they
+# may cause override project-wide settings.
+#
+# Additionally, when defining aliases, macros, sections etc, use the module
+# name as a prefix e.g. gles_my_alias.
+
+##############################################################################
+
+@INCLUDE = ../../bldsys/Doxyfile_common
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT += ../../kernel/include/linux/ump-common.h ../../kernel/include/linux/ump.h
+
+##############################################################################
+# Everything below here is optional, and in most cases not required
+##############################################################################
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES +=
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS +=
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS +=
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE +=
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS +=
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS +=
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH += ../../kernel/drivers/base/ump
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH +=
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH +=
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED +=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED +=
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS +=
diff --git a/drivers/base/ump/docs/sconscript b/drivers/base/ump/docs/sconscript
new file mode 100755
index 00000000000..73a25a1964d
--- /dev/null
+++ b/drivers/base/ump/docs/sconscript
@@ -0,0 +1,30 @@
+#
+# (C) COPYRIGHT 2010-2011 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.
+#
+#
+
+
+Import('env')
+
+doxygen_sources = [
+ 'Doxyfile',
+ Glob('*.png'),
+ Glob('../*.h'),
+ Glob('../src/*.h') ]
+
+if env['doc'] == '1':
+ doxygen_target = env.Command('doxygen/html/index.html', doxygen_sources,
+ ['cd ${SOURCE.dir} && doxygen'])
+ env.Clean(doxygen_target, './doxygen')
+
+ Alias('doxygen', doxygen_target)
+
diff --git a/drivers/base/ump/example_kernel_api.c b/drivers/base/ump/example_kernel_api.c
new file mode 100755
index 00000000000..41f5214e210
--- /dev/null
+++ b/drivers/base/ump/example_kernel_api.c
@@ -0,0 +1,71 @@
+/*
+ *
+ * (C) COPYRIGHT 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/ump.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ * Example routine to display information about an UMP allocation
+ * The routine takes an secure_id which can come from a different kernel module
+ * or from a client application (i.e. an ioctl).
+ * It creates a ump handle from the secure id (which validates the secure id)
+ * and if successful dumps the physical memory information.
+ * It follows the API and pins the memory while "using" the physical memory.
+ * Finally it calls the release function to indicate it's finished with the handle.
+ *
+ * If the function can't look up the handle it fails with return value -1.
+ * If the testy succeeds then it return 0.
+ * */
+
+static int display_ump_memory_information(ump_secure_id secure_id)
+{
+ const ump_dd_physical_block_64 * ump_blocks = NULL;
+ ump_dd_handle ump_mem;
+ uint64_t nr_blocks;
+ int i;
+ ump_alloc_flags flags;
+
+ /* get a handle from the secure id */
+ ump_mem = ump_dd_from_secure_id(secure_id);
+
+ if (UMP_DD_INVALID_MEMORY_HANDLE == ump_mem)
+ {
+ /* invalid ID received */
+ return -1;
+ }
+
+ /* at this point we know we've added a reference to the ump allocation, so we must release it with ump_dd_release */
+
+ ump_dd_phys_blocks_get_64(ump_mem, &nr_blocks, &ump_blocks);
+ flags = ump_dd_allocation_flags_get(ump_mem);
+
+ printf("UMP allocation with secure ID %u consists of %zd physical block(s):\n", secure_id, nr_blocks);
+
+ for(i=0; i<nr_blocks; ++i)
+ {
+ printf("\tBlock %d: 0x%08zX size 0x%08zX\n", i, ump_blocks[i].addr, ump_blocks[i].size);
+ }
+
+ printf("and was allocated using the following bitflag combo: 0x%lX\n", flags);
+
+ ump_dd_release(ump_mem);
+
+ return 0;
+}
+
diff --git a/drivers/base/ump/example_user_api.c b/drivers/base/ump/example_user_api.c
new file mode 100755
index 00000000000..e3d55f65294
--- /dev/null
+++ b/drivers/base/ump/example_user_api.c
@@ -0,0 +1,151 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2011 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 <ump/ump.h>
+#include <memory.h>
+#include <stdio.h>
+
+/*
+ * Example routine to exercise the user space UMP api.
+ * This routine initializes the UMP api and allocates some CPU+device X memory.
+ * No usage hints are given, so the driver will use the default cacheability policy.
+ * With the allocation it creates a duplicate handle and plays with the reference count.
+ * Then it simulates interacting with a device and contains pseudo code for the device.
+ *
+ * If any error is detected correct cleanup will be performed and -1 will be returned.
+ * If successful then 0 will be returned.
+ */
+
+static int test_ump_user_api(void)
+{
+ /* This is the size we try to allocate*/
+ const size_t alloc_size = 4096;
+
+ ump_handle h = UMP_INVALID_MEMORY_HANDLE;
+ ump_handle h_copy = UMP_INVALID_MEMORY_HANDLE;
+ ump_handle h_clone = UMP_INVALID_MEMORY_HANDLE;
+
+ void * mapping = NULL;
+
+ ump_result ump_api_res;
+ int result = -1;
+
+ ump_secure_id id;
+
+ size_t size_returned;
+
+ ump_api_res = ump_open();
+ if (UMP_OK != ump_api_res)
+ {
+ /* failed to open an ump session */
+ /* early out */
+ return -1;
+ }
+
+ h = ump_allocate_64(alloc_size, UMP_PROT_CPU_RD | UMP_PROT_CPU_WR | UMP_PROT_X_RD | UMP_PROT_X_WR);
+ /* the refcount is now 1 */
+ if (UMP_INVALID_MEMORY_HANDLE == h)
+ {
+ /* allocation failure */
+ goto cleanup;
+ }
+
+ /* this is how we could share this allocation with another process */
+
+ /* in process A: */
+ id = ump_secure_id_get(h);
+ /* still ref count 1 */
+ /* send the id to process B */
+
+ /* in process B: */
+ /* receive the id from A */
+ h_clone = ump_from_secure_id(id);
+ /* the ref count of the allocation is now 2 (one from each handle to it) */
+ /* do something ... */
+ /* release our clone */
+ ump_release(h_clone); /* safe to call even if ump_from_secure_id failed */
+ h_clone = UMP_INVALID_MEMORY_HANDLE;
+
+
+ /* a simple save-for-future-use logic inside the driver would just copy the handle (but add a ref manually too!) */
+ /*
+ * void assign_memory_to_job(h)
+ * {
+ */
+ h_copy = h;
+ ump_retain(h_copy); /* manual retain needed as we just assigned the handle, now 2 */
+ /*
+ * }
+ *
+ * void job_completed(void)
+ * {
+ */
+ ump_release(h_copy); /* normal handle release as if we got via an ump_allocate */
+ h_copy = UMP_INVALID_MEMORY_HANDLE;
+ /*
+ * }
+ */
+
+ /* we're now back at ref count 1, and only h is a valid handle */
+ /* enough handle duplication show-off, let's play with the contents instead */
+
+ mapping = ump_map(h, 0, alloc_size);
+ if (NULL == mapping)
+ {
+ /* mapping failure, either out of address space or some other error */
+ goto cleanup;
+ }
+
+ memset(mapping, 0, alloc_size);
+
+ /* let's pretend we're going to start some hw device on this buffer and read the result afterwards */
+ ump_cpu_msync_now(h, UMP_MSYNC_CLEAN, mapping, alloc_size);
+ /*
+ device cache invalidate
+
+ memory barrier
+
+ start device
+
+ memory barrier
+
+ wait for device
+
+ memory barrier
+
+ device cache clean
+
+ memory barrier
+ */
+ ump_cpu_msync_now(h, UMP_MSYNC_CLEAN_AND_INVALIDATE, mapping, alloc_size);
+
+ /* we could now peek at the result produced by the hw device, which is now accessible via our mapping */
+
+ /* unmap the buffer when we're done with it */
+ ump_unmap(h, mapping, alloc_size);
+
+ result = 0;
+
+cleanup:
+ ump_release(h);
+ h = UMP_INVALID_MEMORY_HANDLE;
+
+ ump_close();
+
+ return result;
+}
+
diff --git a/drivers/base/ump/sconscript b/drivers/base/ump/sconscript
new file mode 100755
index 00000000000..c27950f9d86
--- /dev/null
+++ b/drivers/base/ump/sconscript
@@ -0,0 +1,20 @@
+#
+# (C) COPYRIGHT 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.
+#
+#
+
+Import('env')
+
+if Glob('src/sconscript') and int(env['ump']) == 1:
+ SConscript( 'src/sconscript' )
+ SConscript( 'docs/sconscript' )
+
diff --git a/drivers/base/ump/src/Kbuild b/drivers/base/ump/src/Kbuild
new file mode 100755
index 00000000000..6184be86df6
--- /dev/null
+++ b/drivers/base/ump/src/Kbuild
@@ -0,0 +1,48 @@
+#
+# (C) COPYRIGHT 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.
+#
+#
+
+
+# Paths required for build
+UMP_PATH = $(src)/../..
+UMP_DEVICEDRV_PATH = $(src)/.
+
+# Set up defaults if not defined by the user
+MALI_UNIT_TEST ?= 0
+
+SRC :=\
+ common/ump_kernel_core.c \
+ common/ump_kernel_descriptor_mapping.c \
+ linux/ump_kernel_linux.c \
+ linux/ump_kernel_linux_mem.c
+
+UNIT_TEST_DEFINES=
+ifeq ($(MALI_UNIT_TEST), 1)
+ MALI_DEBUG ?= 1
+
+ UNIT_TEST_DEFINES = -DMALI_UNIT_TEST=1 \
+ -DMALI_DEBUG=$(MALI_DEBUG)
+endif
+
+# Use our defines when compiling
+ccflags-y += -I$(UMP_PATH) -I$(UMP_DEVICEDRV_PATH) $(UNIT_TEST_DEFINES)
+
+
+# Tell the Linux build system from which .o file to create the kernel module
+obj-$(CONFIG_UMP) += ump.o
+ifeq ($(CONFIG_ION),y)
+obj-$(CONFIG_UMP) += imports/ion/ump_kernel_import_ion.o
+endif
+
+# Tell the Linux build system to enable building of our .c files
+ump-y := $(SRC:.c=.o)
diff --git a/drivers/base/ump/src/Makefile b/drivers/base/ump/src/Makefile
new file mode 100755
index 00000000000..3bc0db926bc
--- /dev/null
+++ b/drivers/base/ump/src/Makefile
@@ -0,0 +1,86 @@
+#
+# (C) COPYRIGHT 2008-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.
+#
+#
+
+
+ifneq ($(KBUILD_EXTMOD),)
+include $(KBUILD_EXTMOD)/Makefile.common
+else
+include ./Makefile.common
+endif
+
+# default to building for the host
+ARCH ?= $(shell uname -m)
+
+# linux build system integration
+RELATIVE_ROOT=../../../../..
+ROOT = $(CURDIR)/$(RELATIVE_ROOT)
+
+EXTRA_CFLAGS=-I$(CURDIR)/../../../../include
+
+ifeq ($(MALI_UNIT_TEST),1)
+ EXTRA_CFLAGS += -DMALI_UNIT_TEST=$(MALI_UNIT_TEST)
+endif
+
+# Get any user defined KDIR-<names> or maybe even a hardcoded KDIR
+-include KDIR_CONFIGURATION
+
+# Define host system directory
+KDIR-$(shell uname -m):=/lib/modules/$(shell uname -r)/build
+
+ifeq ($(ARCH), arm)
+ # Compiling for ARM
+ CONFIG ?= arm
+else
+ # Compiling for the host
+ CONFIG ?= $(shell uname -m)
+endif
+
+# default cpu to select
+CPU ?= $(shell uname -m)
+
+# look up KDIR based om CPU selection
+KDIR ?= $(KDIR-$(CPU))
+
+ifeq ($(KDIR),)
+$(error No KDIR found for platform $(CPU))
+endif
+
+# Validate selected config
+ifneq ($(shell [ -d arch-$(CONFIG) ] && [ -f arch-$(CONFIG)/config.h ] && echo "OK"), OK)
+$(warning Current directory is $(shell pwd))
+$(error No configuration found for config $(CONFIG). Check that arch-$(CONFIG)/config.h exists)
+else
+# Link arch to the selected arch-config directory
+$(shell [ -L arch ] && rm arch)
+$(shell ln -sf arch-$(CONFIG) arch)
+$(shell touch arch/config.h)
+endif
+
+EXTRA_SYMBOLS=
+
+ifeq ($(MALI_UNIT_TEST),1)
+ KBASE_PATH=$(ROOT)/kernel/drivers/gpu/arm/t6xx/kbase
+ EXTRA_SYMBOLS+=$(KBASE_PATH)/tests/internal/src/kernel_assert_module/linux/Module.symvers
+endif
+KDS_PATH=$(ROOT)/kernel/drivers/base/kds
+EXTRA_SYMBOLS+=$(KDS_PATH)/Module.symvers
+
+all:
+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) EXTRA_CFLAGS="$(EXTRA_CFLAGS) $(SCONS_CFLAGS)" CONFIG_UMP=m KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" modules
+
+kernelrelease:
+ $(MAKE) -C $(KDIR) KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" kernelrelease
+
+clean:
+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean
diff --git a/drivers/base/ump/src/Makefile.common b/drivers/base/ump/src/Makefile.common
new file mode 100755
index 00000000000..8240a0f36aa
--- /dev/null
+++ b/drivers/base/ump/src/Makefile.common
@@ -0,0 +1,18 @@
+#
+# (C) COPYRIGHT 2008-2010 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.
+#
+#
+
+
+SRC = $(UMP_FILE_PREFIX)/common/ump_kernel_core.c \
+ $(UMP_FILE_PREFIX)/common/ump_kernel_descriptor_mapping.c
+
diff --git a/drivers/base/ump/src/Module.symvers b/drivers/base/ump/src/Module.symvers
new file mode 100644
index 00000000000..bb974bc0146
--- /dev/null
+++ b/drivers/base/ump/src/Module.symvers
@@ -0,0 +1,28 @@
+0x00000000 ump_dd_handle_create_from_secure_id /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 kds_waitall /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/kds/kds EXPORT_SYMBOL
+0x00000000 kds_resource_set_release_sync /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/kds/kds EXPORT_SYMBOL
+0x00000000 ump_import_module_unregister /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 kds_resource_term /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/kds/kds EXPORT_SYMBOL
+0x00000000 ump_dd_create_from_phys_blocks_64 /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_reference_release /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 kds_async_waitall /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/kds/kds EXPORT_SYMBOL
+0x00000000 ump_dd_phys_blocks_get_64 /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_handle_create_from_phys_blocks /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 kds_callback_init /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/kds/kds EXPORT_SYMBOL
+0x00000000 ump_import_module_register /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_allocate_64 /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_release /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_secure_id_get /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_phys_block_count_get /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_kds_resource_get /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 kds_callback_term /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/kds/kds EXPORT_SYMBOL
+0x00000000 ump_dd_phys_blocks_get /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_reference_add /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_size_get /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_retain /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_phys_block_get /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_size_get_64 /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_from_secure_id /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 ump_dd_allocation_flags_get /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/ump/src/ump EXPORT_SYMBOL
+0x00000000 kds_resource_init /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/kds/kds EXPORT_SYMBOL
+0x00000000 kds_resource_set_release /home/show/workspace/arndale/mali/TX011-SW-99002-r3p0-02rel0/driver/product/kernel/drivers/base/kds/kds EXPORT_SYMBOL
diff --git a/drivers/base/ump/src/arch b/drivers/base/ump/src/arch
new file mode 120000
index 00000000000..85405c2b098
--- /dev/null
+++ b/drivers/base/ump/src/arch
@@ -0,0 +1 @@
+arch-arm \ No newline at end of file
diff --git a/drivers/base/ump/src/arch-arm/config.h b/drivers/base/ump/src/arch-arm/config.h
new file mode 100755
index 00000000000..13cf5738084
--- /dev/null
+++ b/drivers/base/ump/src/arch-arm/config.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2009 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 __ARCH_CONFIG_H__
+#define __ARCH_CONFIG_H__
+
+#define ARCH_UMP_BACKEND_DEFAULT 1
+#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x00000000
+#define ARCH_UMP_MEMORY_SIZE_DEFAULT 32UL * 1024UL * 1024UL
+
+#endif /* __ARCH_CONFIG_H__ */
diff --git a/drivers/base/ump/src/common/ump_kernel_core.c b/drivers/base/ump/src/common/ump_kernel_core.c
new file mode 100755
index 00000000000..9d65a1989b4
--- /dev/null
+++ b/drivers/base/ump/src/common/ump_kernel_core.c
@@ -0,0 +1,754 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2013 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.
+ *
+ */
+
+
+
+/* module headers */
+#include <linux/ump.h>
+#include <linux/ump-ioctl.h>
+
+/* local headers */
+#include <common/ump_kernel_core.h>
+#include <common/ump_kernel_descriptor_mapping.h>
+#include <ump_arch.h>
+#include <common/ump_kernel_priv.h>
+
+#define UMP_FLAGS_RANGE ((UMP_PROT_SHAREABLE<<1) - 1u)
+
+static umpp_device device;
+
+ump_result umpp_core_constructor(void)
+{
+ mutex_init(&device.secure_id_map_lock);
+ device.secure_id_map = umpp_descriptor_mapping_create(UMP_EXPECTED_IDS, UMP_MAX_IDS);
+ if (NULL != device.secure_id_map)
+ {
+ if (UMP_OK == umpp_device_initialize())
+ {
+ return UMP_OK;
+ }
+ umpp_descriptor_mapping_destroy(device.secure_id_map);
+ }
+ mutex_destroy(&device.secure_id_map_lock);
+
+ return UMP_ERROR;
+}
+
+void umpp_core_destructor(void)
+{
+ umpp_device_terminate();
+ umpp_descriptor_mapping_destroy(device.secure_id_map);
+ mutex_destroy(&device.secure_id_map_lock);
+}
+
+umpp_session *umpp_core_session_start(void)
+{
+ umpp_session * session;
+
+ session = kzalloc(sizeof(*session), GFP_KERNEL);
+ if (NULL != session)
+ {
+ mutex_init(&session->session_lock);
+
+ INIT_LIST_HEAD(&session->memory_usage);
+
+ /* try to create import client session, not a failure if they fail to initialize */
+ umpp_import_handlers_init(session);
+ }
+
+ return session;
+}
+
+void umpp_core_session_end(umpp_session *session)
+{
+ umpp_session_memory_usage * usage, *_usage;
+ UMP_ASSERT(session);
+
+ list_for_each_entry_safe(usage, _usage, &session->memory_usage, link)
+ {
+ printk(KERN_WARNING "UMP: Memory usage cleanup, releasing secure ID %d\n", ump_dd_secure_id_get(usage->mem));
+ ump_dd_release(usage->mem);
+ kfree(usage);
+
+ }
+
+ /* we should now not hold any imported memory objects,
+ * detatch all import handlers */
+ umpp_import_handlers_term(session);
+
+ mutex_destroy(&session->session_lock);
+ kfree(session);
+}
+
+ump_dd_handle ump_dd_allocate_64(uint64_t size, ump_alloc_flags flags, ump_dd_security_filter filter_func, ump_dd_final_release_callback final_release_func, void* callback_data)
+{
+ umpp_allocation * alloc;
+ int i;
+
+ UMP_ASSERT(size);
+
+ if (flags & (~UMP_FLAGS_RANGE))
+ {
+ printk(KERN_WARNING "UMP: allocation flags out of allowed bits range\n");
+ return UMP_DD_INVALID_MEMORY_HANDLE;
+ }
+
+ if( ( flags & (UMP_PROT_CPU_RD | UMP_PROT_W_RD | UMP_PROT_X_RD | UMP_PROT_Y_RD | UMP_PROT_Z_RD ) ) == 0 ||
+ ( flags & (UMP_PROT_CPU_WR | UMP_PROT_W_WR | UMP_PROT_X_WR | UMP_PROT_Y_WR | UMP_PROT_Z_WR )) == 0 )
+ {
+ printk(KERN_WARNING "UMP: allocation flags should have at least one read and one write permission bit set\n");
+ return UMP_DD_INVALID_MEMORY_HANDLE;
+ }
+
+ /*check permission flags to be set if hit flags are set too*/
+ for (i = UMP_DEVICE_CPU_SHIFT; i<=UMP_DEVICE_Z_SHIFT; i+=4)
+ {
+ if (flags & (UMP_HINT_DEVICE_RD<<i))
+ {
+ UMP_ASSERT(flags & (UMP_PROT_DEVICE_RD<<i));
+ }
+ if (flags & (UMP_HINT_DEVICE_WR<<i))
+ {
+ UMP_ASSERT(flags & (UMP_PROT_DEVICE_WR<<i));
+ }
+ }
+
+ alloc = kzalloc(sizeof(*alloc), GFP_KERNEL | __GFP_HARDWALL);
+
+ if (NULL == alloc)
+ goto out1;
+
+ alloc->flags = flags;
+ alloc->filter_func = filter_func;
+ alloc->final_release_func = final_release_func;
+ alloc->callback_data = callback_data;
+ alloc->size = size;
+
+ mutex_init(&alloc->map_list_lock);
+ INIT_LIST_HEAD(&alloc->map_list);
+ atomic_set(&alloc->refcount, 1);
+
+#ifdef CONFIG_KDS
+ kds_resource_init(&alloc->kds_res);
+#endif
+
+ if (!(alloc->flags & UMP_PROT_SHAREABLE))
+ {
+ alloc->owner = get_current()->pid;
+ }
+
+ if (0 != umpp_phys_commit(alloc))
+ {
+ goto out2;
+ }
+
+ /* all set up, allocate an ID for it */
+
+ mutex_lock(&device.secure_id_map_lock);
+ alloc->id = umpp_descriptor_mapping_allocate(device.secure_id_map, (void*)alloc);
+ mutex_unlock(&device.secure_id_map_lock);
+
+ if ((int)alloc->id == 0)
+ {
+ /* failed to allocate a secure_id */
+ goto out3;
+ }
+
+ return alloc;
+
+out3:
+ umpp_phys_free(alloc);
+out2:
+ kfree(alloc);
+out1:
+ return UMP_DD_INVALID_MEMORY_HANDLE;
+}
+
+uint64_t ump_dd_size_get_64(const ump_dd_handle mem)
+{
+ umpp_allocation * alloc;
+
+ UMP_ASSERT(mem);
+
+ alloc = (umpp_allocation*)mem;
+
+ return alloc->size;
+}
+
+/*
+ * UMP v1 API
+ */
+unsigned long ump_dd_size_get(ump_dd_handle mem)
+{
+ umpp_allocation * alloc;
+
+ UMP_ASSERT(mem);
+
+ alloc = (umpp_allocation*)mem;
+
+ UMP_ASSERT(alloc->flags & UMP_CONSTRAINT_32BIT_ADDRESSABLE);
+ UMP_ASSERT(alloc->size <= UMP_UINT32_MAX);
+
+ return (unsigned long)alloc->size;
+}
+
+ump_secure_id ump_dd_secure_id_get(const ump_dd_handle mem)
+{
+ umpp_allocation * alloc;
+
+ UMP_ASSERT(mem);
+
+ alloc = (umpp_allocation*)mem;
+
+ return alloc->id;
+}
+
+#ifdef CONFIG_KDS
+struct kds_resource * ump_dd_kds_resource_get(const ump_dd_handle mem)
+{
+ umpp_allocation * alloc;
+
+ UMP_ASSERT(mem);
+
+ alloc = (umpp_allocation*)mem;
+
+ return &alloc->kds_res;
+}
+#endif
+
+ump_alloc_flags ump_dd_allocation_flags_get(const ump_dd_handle mem)
+{
+ const umpp_allocation * alloc;
+
+ UMP_ASSERT(mem);
+ alloc = (const umpp_allocation *)mem;
+
+ return alloc->flags;
+}
+
+ump_dd_handle ump_dd_from_secure_id(ump_secure_id secure_id)
+{
+ umpp_allocation * alloc = UMP_DD_INVALID_MEMORY_HANDLE;
+
+ mutex_lock(&device.secure_id_map_lock);
+
+ if (0 == umpp_descriptor_mapping_lookup(device.secure_id_map, secure_id, (void**)&alloc))
+ {
+ if (NULL != alloc->filter_func)
+ {
+ if (!alloc->filter_func(secure_id, alloc, alloc->callback_data))
+ {
+ alloc = UMP_DD_INVALID_MEMORY_HANDLE; /* the filter denied access */
+ }
+ }
+
+ /* check permission to access it */
+ if ((UMP_DD_INVALID_MEMORY_HANDLE != alloc) && !(alloc->flags & UMP_PROT_SHAREABLE))
+ {
+ if (alloc->owner != get_current()->pid)
+ {
+ alloc = UMP_DD_INVALID_MEMORY_HANDLE; /*no rights for the current process*/
+ }
+ }
+
+ if (UMP_DD_INVALID_MEMORY_HANDLE != alloc)
+ {
+ if( ump_dd_retain(alloc) != UMP_DD_SUCCESS)
+ {
+ alloc = UMP_DD_INVALID_MEMORY_HANDLE;
+ }
+ }
+ }
+ mutex_unlock(&device.secure_id_map_lock);
+
+ return alloc;
+}
+
+/*
+ * UMP v1 API
+ */
+ump_dd_handle ump_dd_handle_create_from_secure_id(ump_secure_id secure_id)
+{
+ return ump_dd_from_secure_id(secure_id);
+}
+
+int ump_dd_retain(ump_dd_handle mem)
+{
+ umpp_allocation * alloc;
+
+ UMP_ASSERT(mem);
+
+ alloc = (umpp_allocation*)mem;
+
+ /* check for overflow */
+ while(1)
+ {
+ int refcnt = atomic_read(&alloc->refcount);
+ if (refcnt + 1 > 0)
+ {
+ if(atomic_cmpxchg(&alloc->refcount, refcnt, refcnt + 1) == refcnt)
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ return -EBUSY;
+ }
+ }
+}
+
+/*
+ * UMP v1 API
+ */
+void ump_dd_reference_add(ump_dd_handle mem)
+{
+ ump_dd_retain(mem);
+}
+
+
+void ump_dd_release(ump_dd_handle mem)
+{
+ umpp_allocation * alloc;
+ uint32_t new_cnt;
+
+ UMP_ASSERT(mem);
+
+ alloc = (umpp_allocation*)mem;
+
+ /* secure the id for lookup while releasing */
+ mutex_lock(&device.secure_id_map_lock);
+
+ /* do the actual release */
+ new_cnt = atomic_sub_return(1, &alloc->refcount);
+ if (0 == new_cnt)
+ {
+ /* remove from the table as this was the last ref */
+ umpp_descriptor_mapping_remove(device.secure_id_map, alloc->id);
+ }
+
+ /* release the lock as early as possible */
+ mutex_unlock(&device.secure_id_map_lock);
+
+ if (0 != new_cnt)
+ {
+ /* exit if still have refs */
+ return;
+ }
+
+ UMP_ASSERT(list_empty(&alloc->map_list));
+
+#ifdef CONFIG_KDS
+ if (kds_resource_term(&alloc->kds_res))
+ {
+ printk(KERN_ERR "ump_dd_release: kds_resource_term failed,"
+ "unable to release UMP allocation\n");
+ return;
+ }
+#endif
+ /* cleanup */
+ if (NULL != alloc->final_release_func)
+ {
+ alloc->final_release_func(alloc, alloc->callback_data);
+ }
+
+ if (0 == (alloc->management_flags & UMP_MGMT_EXTERNAL))
+ {
+ umpp_phys_free(alloc);
+ }
+ else
+ {
+ kfree(alloc->block_array);
+ }
+
+ mutex_destroy(&alloc->map_list_lock);
+
+ kfree(alloc);
+}
+
+/*
+ * UMP v1 API
+ */
+void ump_dd_reference_release(ump_dd_handle mem)
+{
+ ump_dd_release(mem);
+}
+
+void ump_dd_phys_blocks_get_64(const ump_dd_handle mem, uint64_t * const pCount, const ump_dd_physical_block_64 ** const pArray)
+{
+ const umpp_allocation * alloc;
+ UMP_ASSERT(pCount);
+ UMP_ASSERT(pArray);
+ UMP_ASSERT(mem);
+ alloc = (const umpp_allocation *)mem;
+ *pCount = alloc->blocksCount;
+ *pArray = alloc->block_array;
+}
+
+/*
+ * UMP v1 API
+ */
+ump_dd_status_code ump_dd_phys_blocks_get(ump_dd_handle mem, ump_dd_physical_block * const blocks, unsigned long num_blocks)
+{
+ const umpp_allocation * alloc;
+ unsigned long i;
+ UMP_ASSERT(mem);
+ UMP_ASSERT(blocks);
+ UMP_ASSERT(num_blocks);
+
+ alloc = (const umpp_allocation *)mem;
+
+ UMP_ASSERT(alloc->flags & UMP_CONSTRAINT_32BIT_ADDRESSABLE);
+
+ if((uint64_t)num_blocks != alloc->blocksCount)
+ {
+ return UMP_DD_INVALID;
+ }
+
+ for( i = 0; i < num_blocks; i++)
+ {
+ UMP_ASSERT(alloc->block_array[i].addr <= UMP_UINT32_MAX);
+ UMP_ASSERT(alloc->block_array[i].size <= UMP_UINT32_MAX);
+
+ blocks[i].addr = (unsigned long)alloc->block_array[i].addr;
+ blocks[i].size = (unsigned long)alloc->block_array[i].size;
+ }
+
+ return UMP_DD_SUCCESS;
+}
+/*
+ * UMP v1 API
+ */
+ump_dd_status_code ump_dd_phys_block_get(ump_dd_handle mem, unsigned long index, ump_dd_physical_block * const block)
+{
+ const umpp_allocation * alloc;
+ UMP_ASSERT(mem);
+ UMP_ASSERT(block);
+ alloc = (const umpp_allocation *)mem;
+
+ UMP_ASSERT(alloc->flags & UMP_CONSTRAINT_32BIT_ADDRESSABLE);
+
+ UMP_ASSERT(alloc->block_array[index].addr <= UMP_UINT32_MAX);
+ UMP_ASSERT(alloc->block_array[index].size <= UMP_UINT32_MAX);
+
+ block->addr = (unsigned long)alloc->block_array[index].addr;
+ block->size = (unsigned long)alloc->block_array[index].size;
+
+ return UMP_DD_SUCCESS;
+}
+
+/*
+ * UMP v1 API
+ */
+unsigned long ump_dd_phys_block_count_get(ump_dd_handle mem)
+{
+ const umpp_allocation * alloc;
+ UMP_ASSERT(mem);
+ alloc = (const umpp_allocation *)mem;
+
+ UMP_ASSERT(alloc->flags & UMP_CONSTRAINT_32BIT_ADDRESSABLE);
+ UMP_ASSERT(alloc->blocksCount <= UMP_UINT32_MAX);
+
+ return (unsigned long)alloc->blocksCount;
+}
+
+umpp_cpu_mapping * umpp_dd_find_enclosing_mapping(umpp_allocation * alloc, void *uaddr, size_t size)
+{
+ umpp_cpu_mapping *map;
+
+ void *target_first = uaddr;
+ void *target_last = (void*)((uintptr_t)uaddr - 1 + size);
+
+ if (target_last < target_first) /* wrapped */
+ {
+ return NULL;
+ }
+
+ mutex_lock(&alloc->map_list_lock);
+ list_for_each_entry(map, &alloc->map_list, link)
+ {
+ if ( map->vaddr_start <= target_first &&
+ (void*)((uintptr_t)map->vaddr_start + (map->nr_pages << PAGE_SHIFT) - 1) >= target_last)
+ {
+ goto out;
+ }
+ }
+ map = NULL;
+out:
+ mutex_unlock(&alloc->map_list_lock);
+
+ return map;
+}
+
+void umpp_dd_add_cpu_mapping(umpp_allocation * alloc, umpp_cpu_mapping * map)
+{
+ UMP_ASSERT(alloc);
+ UMP_ASSERT(map);
+ mutex_lock(&alloc->map_list_lock);
+ list_add(&map->link, &alloc->map_list);
+ mutex_unlock(&alloc->map_list_lock);
+}
+
+void umpp_dd_remove_cpu_mapping(umpp_allocation * alloc, umpp_cpu_mapping * target)
+{
+ umpp_cpu_mapping * map;
+
+ UMP_ASSERT(alloc);
+ UMP_ASSERT(target);
+
+ mutex_lock(&alloc->map_list_lock);
+ list_for_each_entry(map, &alloc->map_list, link)
+ {
+ if (map == target)
+ {
+ list_del(&target->link);
+ kfree(target);
+ mutex_unlock(&alloc->map_list_lock);
+ return;
+ }
+ }
+
+ /* not found, error */
+ UMP_ASSERT(0);
+}
+
+int umpp_dd_find_start_block(const umpp_allocation * alloc, uint64_t offset, uint64_t * const block_index, uint64_t * const block_internal_offset)
+{
+ uint64_t i;
+
+ for (i = 0 ; i < alloc->blocksCount; i++)
+ {
+ if (offset < alloc->block_array[i].size)
+ {
+ /* found the block_array element containing this offset */
+ *block_index = i;
+ *block_internal_offset = offset;
+ return 0;
+ }
+ offset -= alloc->block_array[i].size;
+ }
+
+ return -ENXIO;
+}
+
+void umpp_dd_cpu_msync_now(ump_dd_handle mem, ump_cpu_msync_op op, void * address, size_t size)
+{
+ umpp_allocation * alloc;
+ void *vaddr;
+ umpp_cpu_mapping * mapping;
+ uint64_t virt_page_off; /* offset of given address from beginning of the virtual mapping */
+ uint64_t phys_page_off; /* offset of the virtual mapping from the beginning of the physical buffer */
+ uint64_t page_count; /* number of pages to sync */
+ uint64_t i;
+ uint64_t block_idx;
+ uint64_t block_offset;
+ uint64_t paddr;
+
+ UMP_ASSERT((UMP_MSYNC_CLEAN == op) || (UMP_MSYNC_CLEAN_AND_INVALIDATE == op));
+
+ alloc = (umpp_allocation*)mem;
+ vaddr = (void*)(uintptr_t)address;
+
+ if((alloc->flags & UMP_CONSTRAINT_UNCACHED) != 0)
+ {
+ /* mapping is not cached */
+ return;
+ }
+
+ mapping = umpp_dd_find_enclosing_mapping(alloc, vaddr, size);
+ if (NULL == mapping)
+ {
+ printk(KERN_WARNING "UMP: Illegal cache sync address %lx\n", (uintptr_t)vaddr);
+ return; /* invalid pointer or size causes out-of-bounds */
+ }
+
+ /* we already know that address + size don't wrap around as umpp_dd_find_enclosing_mapping didn't fail */
+ page_count = ((((((uintptr_t)address + size - 1) & PAGE_MASK) - ((uintptr_t)address & PAGE_MASK))) >> PAGE_SHIFT) + 1;
+ virt_page_off = (vaddr - mapping->vaddr_start) >> PAGE_SHIFT;
+ phys_page_off = mapping->page_off;
+
+ if (umpp_dd_find_start_block(alloc, (virt_page_off + phys_page_off) << PAGE_SHIFT, &block_idx, &block_offset))
+ {
+ /* should not fail as a valid mapping was found, so the phys mem must exists */
+ printk(KERN_WARNING "UMP: Unable to find physical start block with offset %llx\n", virt_page_off + phys_page_off);
+ UMP_ASSERT(0);
+ return;
+ }
+
+ paddr = alloc->block_array[block_idx].addr + block_offset + (((uintptr_t)vaddr) & ((1u << PAGE_SHIFT)-1));
+
+ for (i = 0; i < page_count; i++)
+ {
+ size_t offset = ((uintptr_t)vaddr) & ((1u << PAGE_SHIFT)-1);
+ size_t sz = min((size_t)PAGE_SIZE - offset, size);
+
+ /* check if we've overrrun the current block, if so move to the next block */
+ if (paddr >= (alloc->block_array[block_idx].addr + alloc->block_array[block_idx].size))
+ {
+ block_idx++;
+ UMP_ASSERT(block_idx < alloc->blocksCount);
+ paddr = alloc->block_array[block_idx].addr;
+ }
+
+ if (UMP_MSYNC_CLEAN == op)
+ {
+ ump_sync_to_memory(paddr, vaddr, sz);
+ }
+ else /* (UMP_MSYNC_CLEAN_AND_INVALIDATE == op) already validated on entry */
+ {
+ ump_sync_to_cpu(paddr, vaddr, sz);
+ }
+
+ /* advance to next page */
+ vaddr = (void*)((uintptr_t)vaddr + sz);
+ size -= sz;
+ paddr += sz;
+ }
+}
+
+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_create_from_phys_blocks_64(const ump_dd_physical_block_64 * blocks, uint64_t num_blocks, ump_alloc_flags flags, ump_dd_security_filter filter_func, ump_dd_final_release_callback final_release_func, void* callback_data)
+{
+ uint64_t size = 0;
+ uint64_t i;
+ umpp_allocation * alloc;
+
+ UMP_ASSERT(blocks);
+ UMP_ASSERT(num_blocks);
+
+ for (i = 0; i < num_blocks; i++)
+ {
+ size += blocks[i].size;
+ }
+ UMP_ASSERT(size);
+
+ if (flags & (~UMP_FLAGS_RANGE))
+ {
+ printk(KERN_WARNING "UMP: allocation flags out of allowed bits range\n");
+ return UMP_DD_INVALID_MEMORY_HANDLE;
+ }
+
+ if( ( flags & (UMP_PROT_CPU_RD | UMP_PROT_W_RD | UMP_PROT_X_RD | UMP_PROT_Y_RD | UMP_PROT_Z_RD
+ | UMP_PROT_CPU_WR | UMP_PROT_W_WR | UMP_PROT_X_WR | UMP_PROT_Y_WR | UMP_PROT_Z_WR )) == 0 )
+ {
+ printk(KERN_WARNING "UMP: allocation flags should have at least one read or write permission bit set\n");
+ return UMP_DD_INVALID_MEMORY_HANDLE;
+ }
+
+ /*check permission flags to be set if hit flags are set too*/
+ for (i = UMP_DEVICE_CPU_SHIFT; i<=UMP_DEVICE_Z_SHIFT; i+=4)
+ {
+ if (flags & (UMP_HINT_DEVICE_RD<<i))
+ {
+ UMP_ASSERT(flags & (UMP_PROT_DEVICE_RD<<i));
+ }
+ if (flags & (UMP_HINT_DEVICE_WR<<i))
+ {
+ UMP_ASSERT(flags & (UMP_PROT_DEVICE_WR<<i));
+ }
+ }
+
+ alloc = kzalloc(sizeof(*alloc),__GFP_HARDWALL | GFP_KERNEL);
+
+ if (NULL == alloc)
+ {
+ goto out1;
+ }
+
+ alloc->block_array = kzalloc(sizeof(ump_dd_physical_block_64) * num_blocks,__GFP_HARDWALL | GFP_KERNEL);
+ if (NULL == alloc->block_array)
+ {
+ goto out2;
+ }
+
+ memcpy(alloc->block_array, blocks, sizeof(ump_dd_physical_block_64) * num_blocks);
+
+#ifdef CONFIG_KDS
+ kds_resource_init(&alloc->kds_res);
+#endif
+ alloc->size = size;
+ alloc->blocksCount = num_blocks;
+ alloc->flags = flags;
+ alloc->filter_func = filter_func;
+ alloc->final_release_func = final_release_func;
+ alloc->callback_data = callback_data;
+
+ if (!(alloc->flags & UMP_PROT_SHAREABLE))
+ {
+ alloc->owner = get_current()->pid;
+ }
+
+ mutex_init(&alloc->map_list_lock);
+ INIT_LIST_HEAD(&alloc->map_list);
+ atomic_set(&alloc->refcount, 1);
+
+ /* all set up, allocate an ID */
+
+ mutex_lock(&device.secure_id_map_lock);
+ alloc->id = umpp_descriptor_mapping_allocate(device.secure_id_map, (void*)alloc);
+ mutex_unlock(&device.secure_id_map_lock);
+
+ if ((int)alloc->id == 0)
+ {
+ /* failed to allocate a secure_id */
+ goto out3;
+ }
+
+ alloc->management_flags |= UMP_MGMT_EXTERNAL;
+
+ return alloc;
+
+out3:
+ kfree(alloc->block_array);
+out2:
+ kfree(alloc);
+out1:
+ return UMP_DD_INVALID_MEMORY_HANDLE;
+}
+
+
+/*
+ * UMP v1 API
+ */
+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block * blocks, unsigned long num_blocks)
+{
+ ump_dd_handle mem;
+ ump_dd_physical_block_64 *block_64_array;
+ ump_alloc_flags flags = UMP_V1_API_DEFAULT_ALLOCATION_FLAGS;
+ unsigned long i;
+
+ UMP_ASSERT(blocks);
+ UMP_ASSERT(num_blocks);
+
+ block_64_array = kzalloc(num_blocks * sizeof(*block_64_array), __GFP_HARDWALL | GFP_KERNEL);
+
+ if(block_64_array == NULL)
+ {
+ return UMP_DD_INVALID_MEMORY_HANDLE;
+ }
+
+ /* copy physical blocks */
+ for( i = 0; i < num_blocks; i++)
+ {
+ block_64_array[i].addr = blocks[i].addr;
+ block_64_array[i].size = blocks[i].size;
+ }
+
+ mem = ump_dd_create_from_phys_blocks_64(block_64_array, num_blocks, flags, NULL, NULL, NULL);
+
+ kfree(block_64_array);
+
+ return mem;
+
+}
diff --git a/drivers/base/ump/src/common/ump_kernel_core.h b/drivers/base/ump/src/common/ump_kernel_core.h
new file mode 100755
index 00000000000..ea41d5ba7d8
--- /dev/null
+++ b/drivers/base/ump/src/common/ump_kernel_core.h
@@ -0,0 +1,226 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-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_CORE_H_
+#define _UMP_KERNEL_CORE_H_
+
+
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <asm/atomic.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/cred.h>
+#include <asm/mmu_context.h>
+
+#ifdef CONFIG_KDS
+#include <linux/kds.h>
+#endif
+#include <linux/ump-common.h>
+#include <ump/src/common/ump_kernel_descriptor_mapping.h>
+
+/* forward decl */
+struct umpp_session;
+
+/**
+ * UMP handle metadata.
+ * Tracks various data about a handle not of any use to user space
+ */
+typedef enum
+{
+ UMP_MGMT_EXTERNAL = (1ul << 0) /**< Handle created via the ump_dd_create_from_phys_blocks interface */
+ /* (1ul << 31) not to be used */
+} umpp_management_flags;
+
+/**
+ * Structure tracking the single global UMP device.
+ * Holds global data like the ID map
+ */
+typedef struct umpp_device
+{
+ struct mutex secure_id_map_lock; /**< Lock protecting access to the map */
+ umpp_descriptor_mapping * secure_id_map; /**< Map of all known secure IDs on the system */
+} umpp_device;
+
+/**
+ * Structure tracking all memory allocations of a UMP allocation.
+ * Tracks info about an mapping so we can verify cache maintenace
+ * operations and help in the unmap cleanup.
+ */
+typedef struct umpp_cpu_mapping
+{
+ struct list_head link; /**< link to list of mappings for an allocation */
+ void *vaddr_start; /**< CPU VA start of the mapping */
+ size_t nr_pages; /**< Size (in pages) of the mapping */
+ uint64_t page_off; /**< Offset (in pages) from start of the allocation where the mapping starts */
+ ump_dd_handle handle; /**< Which handle this mapping is linked to */
+ struct umpp_session * session; /**< Which session created the mapping */
+} umpp_cpu_mapping;
+
+/**
+ * Structure tracking UMP allocation.
+ * Represent a memory allocation with its ID.
+ * Tracks all needed meta-data about an allocation.
+ * */
+typedef struct umpp_allocation
+{
+ ump_secure_id id; /**< Secure ID of the allocation */
+ atomic_t refcount; /**< Usage count */
+
+ ump_alloc_flags flags; /**< Flags for all supported devices */
+ uint32_t management_flags; /**< Managment flags tracking */
+
+ pid_t owner; /**< The process ID owning the memory if not sharable */
+
+ ump_dd_security_filter filter_func; /**< Hook to verify use, called during retains from new clients */
+ ump_dd_final_release_callback final_release_func; /**< Hook called when the last reference is removed */
+ void* callback_data; /**< Additional data given to release hook */
+
+ uint64_t size; /**< Size (in bytes) of the allocation */
+ uint64_t blocksCount; /**< Number of physsical blocks the allocation is built up of */
+ ump_dd_physical_block_64 * block_array; /**< Array, one entry per block, describing block start and length */
+
+ struct mutex map_list_lock; /**< Lock protecting the map_list */
+ struct list_head map_list; /**< Tracks all CPU VA mappings of this allocation */
+
+#ifdef CONFIG_KDS
+ struct kds_resource kds_res; /**< The KDS resource controlling access to this allocation */
+#endif
+
+ void * backendData; /**< Physical memory backend meta-data */
+} umpp_allocation;
+
+/**
+ * Structure tracking use of UMP memory by a session.
+ * Tracks the use of an allocation by a session so session termination can clean up any outstanding references.
+ * Also protects agains non-matched release calls from user space.
+ */
+typedef struct umpp_session_memory_usage
+{
+ ump_secure_id id; /**< ID being used. For quick look-up */
+ ump_dd_handle mem; /**< Handle being used. */
+
+ /**
+ * Track how many times has the process retained this handle in the kernel.
+ * This should usually just be 1(allocated or resolved) or 2(mapped),
+ * but could be more if someone is playing with the low-level API
+ * */
+ atomic_t process_usage_count;
+
+ struct list_head link; /**< link to other usage trackers for a session */
+} umpp_session_memory_usage;
+
+/**
+ * Structure representing a session/client.
+ * Tracks the UMP allocations being used by this client.
+ */
+typedef struct umpp_session
+{
+ struct mutex session_lock; /**< Lock for memory usage manipulation */
+ struct list_head memory_usage; /**< list of memory currently being used by the this session */
+ void* import_handler_data[UMPP_EXTERNAL_MEM_COUNT]; /**< Import modules per-session data pointer */
+} umpp_session;
+
+/**
+ * UMP core setup.
+ * Called by any OS specific startup function to initialize the common part.
+ * @return UMP_OK if core initialized correctly, any other value for errors
+ */
+ump_result umpp_core_constructor(void);
+
+/**
+ * UMP core teardown.
+ * Called by any OS specific unload function to clean up the common part.
+ */
+void umpp_core_destructor(void);
+
+/**
+ * UMP session start.
+ * Called by any OS specific session handler when a new session is detected
+ * @return Non-NULL if a matching core session could be set up. NULL on failure
+ */
+umpp_session *umpp_core_session_start(void);
+
+/**
+ * UMP session end.
+ * Called by any OS specific session handler when a session is ended/terminated.
+ * @param session The core session object returned by ump_core_session_start
+ */
+void umpp_core_session_end(umpp_session *session);
+
+/**
+ * Find a mapping object (if any) for this allocation.
+ * Called by any function needing to identify a mapping from a user virtual address.
+ * Verifies that the whole range to be within a mapping object.
+ * @param alloc The UMP allocation to find a matching mapping object of
+ * @param uaddr User mapping address to find the mapping object for
+ * @param size Length of the mapping
+ * @return NULL on error (no match found), pointer to mapping object if match found
+ */
+umpp_cpu_mapping * umpp_dd_find_enclosing_mapping(umpp_allocation * alloc, void* uaddr, size_t size);
+
+/**
+ * Register a new mapping of an allocation.
+ * Called by functions creating a new mapping of an allocation, typically OS specific handlers.
+ * @param alloc The allocation object which has been mapped
+ * @param map Info about the mapping
+ */
+void umpp_dd_add_cpu_mapping(umpp_allocation * alloc, umpp_cpu_mapping * map);
+
+/**
+ * Remove and free mapping object from an allocation.
+ * @param alloc The allocation object to remove the mapping info from
+ * @param target The mapping object to remove
+ */
+void umpp_dd_remove_cpu_mapping(umpp_allocation * alloc, umpp_cpu_mapping * target);
+
+/**
+ * Helper to find a block in the blockArray which holds a given byte offset.
+ * @param alloc The allocation object to find the block in
+ * @param offset Offset (in bytes) from allocation start to find the block of
+ * @param[out] block_index Pointer to the index of the block matching
+ * @param[out] block_internal_offset Offset within the returned block of the searched offset
+ * @return 0 if a matching block was found, any other value for error
+ */
+int umpp_dd_find_start_block(const umpp_allocation * alloc, uint64_t offset, uint64_t * const block_index, uint64_t * const block_internal_offset);
+
+/**
+ * Cache maintenance helper.
+ * Performs the requested cache operation on the given handle.
+ * @param mem Allocation handle
+ * @param op Cache maintenance operation to perform
+ * @param address User mapping at which to do the operation
+ * @param size Length (in bytes) of the range to do the operation on
+ */
+void umpp_dd_cpu_msync_now(ump_dd_handle mem, ump_cpu_msync_op op, void * address, size_t size);
+
+/**
+ * Import module session early init.
+ * Calls session_begin on all installed import modules.
+ * @param session The core session object to initialized the import handler for
+ * */
+void umpp_import_handlers_init(umpp_session * session);
+
+/**
+ * Import module session cleanup.
+ * Calls session_end on all import modules bound to the session.
+ * @param session The core session object to initialized the import handler for
+ */
+void umpp_import_handlers_term(umpp_session * session);
+
+#endif /* _UMP_KERNEL_CORE_H_ */
+
diff --git a/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.c b/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.c
new file mode 100755
index 00000000000..148ef1246c5
--- /dev/null
+++ b/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.c
@@ -0,0 +1,160 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-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 <common/ump_kernel_descriptor_mapping.h>
+#include <common/ump_kernel_priv.h>
+
+#define MALI_PAD_INT(x) (((x) + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1))
+
+/**
+ * Allocate a descriptor table capable of holding 'count' mappings
+ * @param count Number of mappings in the table
+ * @return Pointer to a new table, NULL on error
+ */
+static umpp_descriptor_table * descriptor_table_alloc(unsigned int count);
+
+/**
+ * Free a descriptor table
+ * @param table The table to free
+ */
+static void descriptor_table_free(umpp_descriptor_table * table);
+
+umpp_descriptor_mapping * umpp_descriptor_mapping_create(unsigned int init_entries, unsigned int max_entries)
+{
+ umpp_descriptor_mapping * map = kzalloc(sizeof(umpp_descriptor_mapping), GFP_KERNEL);
+
+ init_entries = MALI_PAD_INT(init_entries);
+ max_entries = MALI_PAD_INT(max_entries);
+
+ if (NULL != map)
+ {
+ map->table = descriptor_table_alloc(init_entries);
+ if (NULL != map->table)
+ {
+ init_rwsem( &map->lock);
+ set_bit(0, map->table->usage);
+ map->max_nr_mappings_allowed = max_entries;
+ map->current_nr_mappings = init_entries;
+ return map;
+
+ descriptor_table_free(map->table);
+ }
+ kfree(map);
+ }
+ return NULL;
+}
+
+void umpp_descriptor_mapping_destroy(umpp_descriptor_mapping * map)
+{
+ UMP_ASSERT(NULL != map);
+ descriptor_table_free(map->table);
+ kfree(map);
+}
+
+unsigned int umpp_descriptor_mapping_allocate(umpp_descriptor_mapping * map, void * target)
+{
+ int descriptor = 0;
+ UMP_ASSERT(NULL != map);
+ down_write( &map->lock);
+ descriptor = find_first_zero_bit(map->table->usage, map->current_nr_mappings);
+ if (descriptor == map->current_nr_mappings)
+ {
+ /* no free descriptor, try to expand the table */
+ umpp_descriptor_table * new_table;
+ umpp_descriptor_table * old_table = map->table;
+ int nr_mappings_new = map->current_nr_mappings + BITS_PER_LONG;
+
+ if (map->current_nr_mappings >= map->max_nr_mappings_allowed)
+ {
+ descriptor = 0;
+ goto unlock_and_exit;
+ }
+
+ new_table = descriptor_table_alloc(nr_mappings_new);
+ if (NULL == new_table)
+ {
+ descriptor = 0;
+ goto unlock_and_exit;
+ }
+
+ memcpy(new_table->usage, old_table->usage, (sizeof(unsigned long)*map->current_nr_mappings) / BITS_PER_LONG);
+ memcpy(new_table->mappings, old_table->mappings, map->current_nr_mappings * sizeof(void*));
+
+ map->table = new_table;
+ map->current_nr_mappings = nr_mappings_new;
+ descriptor_table_free(old_table);
+ }
+
+ /* we have found a valid descriptor, set the value and usage bit */
+ set_bit(descriptor, map->table->usage);
+ map->table->mappings[descriptor] = target;
+
+unlock_and_exit:
+ up_write(&map->lock);
+ return descriptor;
+}
+
+int umpp_descriptor_mapping_lookup(umpp_descriptor_mapping * map, unsigned int descriptor, void** const target)
+{
+ int result = -EINVAL;
+ UMP_ASSERT(map);
+ UMP_ASSERT(target);
+ down_read(&map->lock);
+ if ( (descriptor > 0) && (descriptor < map->current_nr_mappings) && test_bit(descriptor, map->table->usage) )
+ {
+ *target = map->table->mappings[descriptor];
+ result = 0;
+ }
+ /* keep target untouched if the descriptor was not found */
+ up_read(&map->lock);
+ return result;
+}
+
+void umpp_descriptor_mapping_remove(umpp_descriptor_mapping * map, unsigned int descriptor)
+{
+ UMP_ASSERT(map);
+ down_write(&map->lock);
+ if ( (descriptor > 0) && (descriptor < map->current_nr_mappings) && test_bit(descriptor, map->table->usage) )
+ {
+ map->table->mappings[descriptor] = NULL;
+ clear_bit(descriptor, map->table->usage);
+ }
+ up_write(&map->lock);
+}
+
+static umpp_descriptor_table * descriptor_table_alloc(unsigned int count)
+{
+ umpp_descriptor_table * table;
+
+ table = kzalloc(sizeof(umpp_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG) + (sizeof(void*) * count), __GFP_HARDWALL | GFP_KERNEL );
+
+ if (NULL != table)
+ {
+ table->usage = (unsigned long*)((u8*)table + sizeof(umpp_descriptor_table));
+ table->mappings = (void**)((u8*)table + sizeof(umpp_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG));
+ }
+
+ return table;
+}
+
+static void descriptor_table_free(umpp_descriptor_table * table)
+{
+ UMP_ASSERT(table);
+ kfree(table);
+}
+
diff --git a/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.h b/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.h
new file mode 100755
index 00000000000..49a7b91f08f
--- /dev/null
+++ b/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.h
@@ -0,0 +1,92 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-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_descriptor_mapping.h
+ */
+
+#ifndef _UMP_KERNEL_DESCRIPTOR_MAPPING_H_
+#define _UMP_KERNEL_DESCRIPTOR_MAPPING_H_
+
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+/**
+ * The actual descriptor mapping table, never directly accessed by clients
+ */
+typedef struct umpp_descriptor_table
+{
+ /* keep as a unsigned long to rely on the OS's bitops support */
+ unsigned long * usage; /**< Pointer to bitpattern indicating if a descriptor is valid/used(1) or not(0) */
+ void** mappings; /**< Array of the pointers the descriptors map to */
+} umpp_descriptor_table;
+
+/**
+ * The descriptor mapping object
+ * Provides a separate namespace where we can map an integer to a pointer
+ */
+typedef struct umpp_descriptor_mapping
+{
+ struct rw_semaphore lock; /**< Lock protecting access to the mapping object */
+ unsigned int max_nr_mappings_allowed; /**< Max number of mappings to support in this namespace */
+ unsigned int current_nr_mappings; /**< Current number of possible mappings */
+ umpp_descriptor_table * table; /**< Pointer to the current mapping table */
+} umpp_descriptor_mapping;
+
+/**
+ * Create a descriptor mapping object.
+ * Create a descriptor mapping capable of holding init_entries growable to max_entries.
+ * ID 0 is reserved so the number of available entries will be max - 1.
+ * @param init_entries Number of entries to preallocate memory for
+ * @param max_entries Number of entries to max support
+ * @return Pointer to a descriptor mapping object, NULL on failure
+ */
+umpp_descriptor_mapping * umpp_descriptor_mapping_create(unsigned int init_entries, unsigned int max_entries);
+
+/**
+ * Destroy a descriptor mapping object
+ * @param[in] map The map to free
+ */
+void umpp_descriptor_mapping_destroy(umpp_descriptor_mapping * map);
+
+/**
+ * Allocate a new mapping entry (descriptor ID)
+ * Allocates a new entry in the map.
+ * @param[in] map The map to allocate a new entry in
+ * @param[in] target The value to map to
+ * @return The descriptor allocated, ID 0 on failure.
+ */
+unsigned int umpp_descriptor_mapping_allocate(umpp_descriptor_mapping * map, void * target);
+
+/**
+ * Get the value mapped to by a descriptor ID
+ * @param[in] map The map to lookup the descriptor id in
+ * @param[in] descriptor The descriptor ID to lookup
+ * @param[out] target Pointer to a pointer which will receive the stored value
+ *
+ * @return 0 on success lookup, -EINVAL on lookup failure.
+ */
+int umpp_descriptor_mapping_lookup(umpp_descriptor_mapping * map, unsigned int descriptor, void** const target);
+
+/**
+ * Free the descriptor ID
+ * For the descriptor to be reused it has to be freed
+ * @param[in] map The map to free the descriptor from
+ * @param descriptor The descriptor ID to free
+ */
+void umpp_descriptor_mapping_remove(umpp_descriptor_mapping * map, unsigned int descriptor);
+
+#endif /* _UMP_KERNEL_DESCRIPTOR_MAPPING_H_ */
diff --git a/drivers/base/ump/src/common/ump_kernel_priv.h b/drivers/base/ump/src/common/ump_kernel_priv.h
new file mode 100755
index 00000000000..d44d029fd41
--- /dev/null
+++ b/drivers/base/ump/src/common/ump_kernel_priv.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2013 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_PRIV_H_
+#define _UMP_KERNEL_PRIV_H_
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <asm/cacheflush.h>
+#endif
+
+
+#define UMP_EXPECTED_IDS 64
+#define UMP_MAX_IDS 32768
+
+#ifdef __KERNEL__
+#define UMP_ASSERT(expr) \
+ if (!(expr)) { \
+ printk(KERN_ERR "UMP: Assertion failed! %s,%s,%s,line=%d\n",\
+ #expr,__FILE__,__func__,__LINE__); \
+ BUG(); \
+ }
+
+static inline void ump_sync_to_memory(uint64_t paddr, void* vaddr, size_t sz)
+{
+#ifdef CONFIG_ARM
+ __cpuc_flush_dcache_area(vaddr, sz);
+ outer_flush_range(paddr, paddr+sz);
+#elif defined(CONFIG_X86)
+ struct scatterlist scl = {0, };
+ sg_set_page(&scl, pfn_to_page(PFN_DOWN(paddr)), sz,
+ paddr & (PAGE_SIZE -1 ));
+ dma_sync_sg_for_cpu(NULL, &scl, 1, DMA_TO_DEVICE);
+ mb(); /* for outer_sync (if needed) */
+#else
+#error Implement cache maintenance for your architecture here
+#endif
+}
+
+static inline void ump_sync_to_cpu(uint64_t paddr, void* vaddr, size_t sz)
+{
+#ifdef CONFIG_ARM
+ __cpuc_flush_dcache_area(vaddr, sz);
+ outer_flush_range(paddr, paddr+sz);
+#elif defined(CONFIG_X86)
+ struct scatterlist scl = {0, };
+ sg_set_page(&scl, pfn_to_page(PFN_DOWN(paddr)), sz,
+ paddr & (PAGE_SIZE -1 ));
+ dma_sync_sg_for_cpu(NULL, &scl, 1, DMA_FROM_DEVICE);
+#else
+#error Implement cache maintenance for your architecture here
+#endif
+}
+#endif /* __KERNEL__*/
+#endif /* _UMP_KERNEL_PRIV_H_ */
+
diff --git a/drivers/base/ump/src/imports/ion/Makefile b/drivers/base/ump/src/imports/ion/Makefile
new file mode 100755
index 00000000000..2095fcca117
--- /dev/null
+++ b/drivers/base/ump/src/imports/ion/Makefile
@@ -0,0 +1,52 @@
+#
+# (C) COPYRIGHT 2011 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.
+#
+#
+
+
+
+# default to building for the host
+ARCH ?= $(shell uname -m)
+
+# linux build system integration
+
+ifneq ($(KERNELRELEASE),)
+# Inside the kernel build system
+
+EXTRA_CFLAGS += -I$(KBUILD_EXTMOD) -I$(KBUILD_EXTMOD)/../../../../..
+KBUILD_EXTRA_SYMBOLS += "$(KBUILD_EXTMOD)/../../Module.symvers"
+
+SRC += ump_kernel_import_ion.c
+
+MODULE:=ump_ion_import.ko
+
+obj-m := $(MODULE:.ko=.o)
+$(MODULE:.ko=-y) := $(SRC:.c=.o)
+$(MODULE:.ko=-objs) := $(SRC:.c=.o)
+
+else
+# Outside the kernel build system
+#
+#
+
+ifeq ($(KDIR),)
+$(error Must specify KDIR to point to the kernel to target))
+endif
+
+all:
+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR)
+
+clean:
+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean
+
+endif
+
diff --git a/drivers/base/ump/src/imports/ion/sconscript b/drivers/base/ump/src/imports/ion/sconscript
new file mode 100755
index 00000000000..dde149076a2
--- /dev/null
+++ b/drivers/base/ump/src/imports/ion/sconscript
@@ -0,0 +1,57 @@
+#
+# (C) COPYRIGHT 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.
+#
+#
+
+
+import os
+Import('env')
+
+# Clone the environment so changes don't affect other build files
+env_ion = env.Clone()
+
+if env_ion['ump_ion'] != '1':
+ Return()
+
+if env_ion['v'] != '1':
+ env_ion['MAKECOMSTR'] = '[MAKE] ${SOURCE.dir}'
+
+# Source files required for UMP.
+ion_src = [Glob('#kernel/drivers/base/ump/src/imports/ion/*.c')]
+
+# Note: cleaning via the Linux kernel build system does not yet work
+if env_ion.GetOption('clean') :
+ makeAction=Action("cd ${SOURCE.dir} && make clean", '$MAKECOMSTR')
+else:
+ if env['arch'] == 'x86_32' :
+ env_ion['arch_linux'] = 'x86'
+ elif 'arm' in env['arch']:
+ env_ion['arch_linux'] = 'arm'
+ else:
+ env_ion['arch_linux'] = env['arch']
+ makeAction=Action("cd ${SOURCE.dir} && make ARCH=$arch_linux PLATFORM=${platform} && cp ump_ion_import.ko $STATIC_LIB_PATH/ump_ion_import.ko", '$MAKECOMSTR')
+# The target is ump_import_ion.ko, built from the source in ion_src, via the action makeAction
+# ump_import_ion.ko will be copied to $STATIC_LIB_PATH after being built by the standard Linux
+# kernel build system, after which it can be installed to the directory specified if
+# "libs_install" is set; this is done by LibTarget.
+cmd = env_ion.Command('$STATIC_LIB_PATH/ump_ion_import.ko', ion_src, [makeAction])
+
+# Until we fathom out how the invoke the Linux build system to clean, we can use Clean
+# to remove generated files.
+
+patterns = ['*.mod.c', '*.o', '*.ko', '*.a', '.*.cmd', 'modules.order', '.tmp_versions', 'Module.symvers']
+
+for p in patterns:
+ Clean(cmd, Glob('#kernel/drivers/base/ump/src/imports/ion/%s' % p))
+
+env_ion.Depends('$STATIC_LIB_PATH/ump_ion_import.ko', '$STATIC_LIB_PATH/ump.ko')
+env_ion.ProgTarget('ump', cmd)
diff --git a/drivers/base/ump/src/imports/ion/ump_kernel_import_ion.c b/drivers/base/ump/src/imports/ion/ump_kernel_import_ion.c
new file mode 100755
index 00000000000..9353e6aa987
--- /dev/null
+++ b/drivers/base/ump/src/imports/ion/ump_kernel_import_ion.c
@@ -0,0 +1,208 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-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/ump.h>
+#include <linux/dma-mapping.h>
+#include <linux/ion.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+
+struct ion_wrapping_info
+{
+ struct ion_client * ion_client;
+ struct ion_handle * ion_handle;
+ int num_phys_blocks;
+ struct scatterlist * sglist;
+};
+
+static struct ion_device * ion_device_get(void)
+{
+ /* < Customer to provide implementation >
+ * Return a pointer to the global ion_device on the system
+ */
+ return NULL;
+}
+
+static unsigned int ion_heap_mask_get(void)
+{
+ /* < Customer to provide implementation >
+ * Return the heap mask to use with UMP clients.
+ * Suspect this can be kept as 0 as we won't allocate memory, just import.
+ */
+ return 0;
+}
+
+static int import_ion_client_create(void** const custom_session_data)
+{
+ struct ion_client ** ion_client;
+
+ ion_client = (struct ion_client**)custom_session_data;
+ *ion_client = ion_client_create(ion_device_get(), ion_heap_mask_get(), "ump");
+
+ return PTR_RET(*ion_client);
+}
+
+
+static void import_ion_client_destroy(void* custom_session_data)
+{
+ struct ion_client * ion_client;
+
+ ion_client = (struct ion_client*)custom_session_data;
+ BUG_ON(!ion_client);
+
+ ion_client_destroy(ion_client);
+}
+
+
+static void import_ion_final_release_callback(const ump_dd_handle handle, void * info)
+{
+ struct ion_wrapping_info * ion_info;
+
+ BUG_ON(!info);
+
+ (void)handle;
+ ion_info = (struct ion_wrapping_info*)info;
+
+ dma_unmap_sg(NULL, ion_info->sglist, ion_info->num_phys_blocks, DMA_BIDIRECTIONAL);
+ ion_unmap_dma(ion_info->ion_client, ion_info->ion_handle);
+ ion_free(ion_info->ion_client, ion_info->ion_handle);
+ kfree(ion_info);
+ module_put(THIS_MODULE);
+}
+
+static ump_dd_handle import_ion_import(void * custom_session_data, void * pfd, ump_alloc_flags flags)
+{
+ int fd;
+ ump_dd_handle ump_handle;
+ struct scatterlist * sg;
+ int num_dma_blocks;
+ ump_dd_physical_block_64 * phys_blocks;
+ unsigned long i;
+
+ struct ion_wrapping_info * ion_info;
+
+ BUG_ON(!custom_session_data);
+ BUG_ON(!pfd);
+
+ ion_info = kzalloc(GFP_KERNEL, sizeof(*ion_info));
+ if (NULL == ion_info)
+ {
+ return UMP_DD_INVALID_MEMORY_HANDLE;
+ }
+
+ ion_info->ion_client = (struct ion_client*)custom_session_data;
+
+ if (get_user(fd, (int*)pfd))
+ {
+ goto out;
+ }
+
+ ion_info->ion_handle = ion_import_fd(ion_info->ion_client, fd);
+
+ if (IS_ERR_OR_NULL(ion_info->ion_handle))
+ {
+ goto out;
+ }
+
+ ion_info->sglist = ion_map_dma(ion_info->ion_client, ion_info->ion_handle);
+ if (IS_ERR_OR_NULL(ion_info->sglist))
+ {
+ goto ion_dma_map_failed;
+ }
+
+ sg = ion_info->sglist;
+ while (sg)
+ {
+ ion_info->num_phys_blocks++;
+ sg = sg_next(sg);
+ }
+
+ num_dma_blocks = dma_map_sg(NULL, ion_info->sglist, ion_info->num_phys_blocks, DMA_BIDIRECTIONAL);
+
+ if (0 == num_dma_blocks)
+ {
+ goto linux_dma_map_failed;
+ }
+
+ phys_blocks = vmalloc(num_dma_blocks * sizeof(*phys_blocks));
+ if (NULL == phys_blocks)
+ {
+ goto vmalloc_failed;
+ }
+
+ for_each_sg(ion_info->sglist, sg, num_dma_blocks, i)
+ {
+ phys_blocks[i].addr = sg_phys(sg);
+ phys_blocks[i].size = sg_dma_len(sg);
+ }
+
+ ump_handle = ump_dd_create_from_phys_blocks_64(phys_blocks, num_dma_blocks, flags, NULL, import_ion_final_release_callback, ion_info);
+
+ vfree(phys_blocks);
+
+ if (ump_handle != UMP_DD_INVALID_MEMORY_HANDLE)
+ {
+ /*
+ * As we have a final release callback installed
+ * we must keep the module locked until
+ * the callback has been triggered
+ * */
+ __module_get(THIS_MODULE);
+ return ump_handle;
+ }
+
+ /* failed*/
+vmalloc_failed:
+ dma_unmap_sg(NULL, ion_info->sglist, ion_info->num_phys_blocks, DMA_BIDIRECTIONAL);
+linux_dma_map_failed:
+ ion_unmap_dma(ion_info->ion_client, ion_info->ion_handle);
+ion_dma_map_failed:
+ ion_free(ion_info->ion_client, ion_info->ion_handle);
+out:
+ kfree(ion_info);
+ return UMP_DD_INVALID_MEMORY_HANDLE;
+}
+
+struct ump_import_handler import_handler_ion =
+{
+ .linux_module = THIS_MODULE,
+ .session_begin = import_ion_client_create,
+ .session_end = import_ion_client_destroy,
+ .import = import_ion_import
+};
+
+static int __init import_ion_initialize_module(void)
+{
+ /* register with UMP */
+ return ump_import_module_register(UMP_EXTERNAL_MEM_TYPE_ION, &import_handler_ion);
+}
+
+static void __exit import_ion_cleanup_module(void)
+{
+ /* unregister import handler */
+ ump_import_module_unregister(UMP_EXTERNAL_MEM_TYPE_ION);
+}
+
+/* Setup init and exit functions for this module */
+module_init(import_ion_initialize_module);
+module_exit(import_ion_cleanup_module);
+
+/* And some module information */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ARM Ltd.");
+MODULE_VERSION("1.0");
diff --git a/drivers/base/ump/src/imports/sconscript b/drivers/base/ump/src/imports/sconscript
new file mode 100755
index 00000000000..a42c2f36e3a
--- /dev/null
+++ b/drivers/base/ump/src/imports/sconscript
@@ -0,0 +1,24 @@
+#
+# (C) COPYRIGHT 2011-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.
+#
+#
+
+
+import os, sys
+Import('env')
+
+import_modules = [ os.path.join( path, 'sconscript' ) for path in sorted(os.listdir( os.getcwd() )) ]
+
+for m in import_modules:
+ if os.path.exists(m):
+ SConscript( m, variant_dir=os.path.join( env['BUILD_DIR_PATH'], os.path.dirname(m) ), duplicate=0 )
+
diff --git a/drivers/base/ump/src/linux/ump_kernel_linux.c b/drivers/base/ump/src/linux/ump_kernel_linux.c
new file mode 100755
index 00000000000..29e7812a7ac
--- /dev/null
+++ b/drivers/base/ump/src/linux/ump_kernel_linux.c
@@ -0,0 +1,830 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2013 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/ump-ioctl.h>
+#include <linux/ump.h>
+
+#include <asm/uaccess.h> /* copy_*_user */
+#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/device.h> /* class registration support */
+
+#include <common/ump_kernel_core.h>
+
+#include "ump_kernel_linux_mem.h"
+#include <ump_arch.h>
+
+
+struct ump_linux_device
+{
+ struct cdev cdev;
+ struct class * ump_class;
+};
+
+/* Name of the UMP device driver */
+static char ump_dev_name[] = "ump"; /* should be const, but the functions we call requires non-cost */
+
+/* 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 = 0;
+module_param(ump_major, int, S_IRUGO); /* r--r--r-- */
+MODULE_PARM_DESC(ump_major, "Device major number");
+
+#define UMP_REV_STRING "1.0"
+
+char * ump_revision = UMP_REV_STRING;
+module_param(ump_revision, charp, S_IRUGO); /* r--r--r-- */
+MODULE_PARM_DESC(ump_revision, "Revision info");
+
+static int umpp_linux_open(struct inode *inode, struct file *filp);
+static int umpp_linux_release(struct inode *inode, struct file *filp);
+#ifdef HAVE_UNLOCKED_IOCTL
+static long umpp_linux_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+#else
+static int umpp_linux_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+#endif
+
+/* This variable defines the file operations this UMP device driver offers */
+static struct file_operations ump_fops =
+{
+ .owner = THIS_MODULE,
+ .open = umpp_linux_open,
+ .release = umpp_linux_release,
+#ifdef HAVE_UNLOCKED_IOCTL
+ .unlocked_ioctl = umpp_linux_ioctl,
+#else
+ .ioctl = umpp_linux_ioctl,
+#endif
+ .compat_ioctl = umpp_linux_ioctl,
+ .mmap = umpp_linux_mmap
+};
+
+/* import module handling */
+DEFINE_MUTEX(import_list_lock);
+struct ump_import_handler * import_handlers[UMPP_EXTERNAL_MEM_COUNT];
+
+/* The global variable containing the global device data */
+static struct ump_linux_device ump_linux_device;
+
+#define DBG_MSG(level, ...) do { \
+if ((level) <= ump_debug_level)\
+{\
+printk(KERN_DEBUG "UMP<" #level ">:\n" __VA_ARGS__);\
+} \
+} while (0)
+
+#define MSG_ERR(...) do{ \
+printk(KERN_ERR "UMP: ERR: %s\n %s()%4d\n", __FILE__, __func__ , __LINE__) ; \
+printk(KERN_ERR __VA_ARGS__); \
+printk(KERN_ERR "\n"); \
+} while(0)
+
+#define MSG(...) do{ \
+printk(KERN_INFO "UMP: " __VA_ARGS__);\
+} while (0)
+
+/*
+ * This function is called by Linux to initialize this module.
+ * All we do is initialize the UMP device driver.
+ */
+static int __init umpp_linux_initialize_module(void)
+{
+ ump_result err;
+
+ DBG_MSG(2, "Inserting UMP device driver. Compiled: %s, time: %s\n", __DATE__, __TIME__);
+
+ err = umpp_core_constructor();
+ if (UMP_OK != err)
+ {
+ MSG_ERR("UMP device driver init failed\n");
+ return -ENOTTY;
+ }
+
+ MSG("UMP device driver %s loaded\n", UMP_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 __exit umpp_linux_cleanup_module(void)
+{
+ DBG_MSG(2, "Unloading UMP device driver\n");
+ umpp_core_destructor();
+ DBG_MSG(2, "Module unloaded\n");
+}
+
+
+
+/*
+ * Initialize the UMP device driver.
+ */
+ump_result umpp_device_initialize(void)
+{
+ int err;
+ dev_t dev = 0;
+
+ 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_linux_device, 0, sizeof(ump_linux_device));
+
+ /* initialize our char dev data */
+ cdev_init(&ump_linux_device.cdev, &ump_fops);
+ ump_linux_device.cdev.owner = THIS_MODULE;
+ ump_linux_device.cdev.ops = &ump_fops;
+
+ /* register char dev with the kernel */
+ err = cdev_add(&ump_linux_device.cdev, dev, 1/*count*/);
+ if (0 == err)
+ {
+
+ ump_linux_device.ump_class = class_create(THIS_MODULE, ump_dev_name);
+ if (IS_ERR(ump_linux_device.ump_class))
+ {
+ err = PTR_ERR(ump_linux_device.ump_class);
+ }
+ else
+ {
+ struct device * mdev;
+ mdev = device_create(ump_linux_device.ump_class, NULL, dev, NULL, ump_dev_name);
+ if (!IS_ERR(mdev))
+ {
+ return UMP_OK;
+ }
+
+ err = PTR_ERR(mdev);
+ class_destroy(ump_linux_device.ump_class);
+ }
+ cdev_del(&ump_linux_device.cdev);
+ }
+
+ unregister_chrdev_region(dev, 1);
+ }
+
+ return UMP_ERROR;
+}
+
+
+
+/*
+ * Terminate the UMP device driver
+ */
+void umpp_device_terminate(void)
+{
+ dev_t dev = MKDEV(ump_major, 0);
+
+ device_destroy(ump_linux_device.ump_class, dev);
+ class_destroy(ump_linux_device.ump_class);
+
+ /* unregister char device */
+ cdev_del(&ump_linux_device.cdev);
+
+ /* free major */
+ unregister_chrdev_region(dev, 1);
+}
+
+
+static int umpp_linux_open(struct inode *inode, struct file *filp)
+{
+ umpp_session *session;
+
+ session = umpp_core_session_start();
+ if (NULL == session)
+ {
+ return -EFAULT;
+ }
+
+ filp->private_data = session;
+
+ return 0;
+}
+
+static int umpp_linux_release(struct inode *inode, struct file *filp)
+{
+ umpp_session *session;
+
+ session = filp->private_data;
+
+ umpp_core_session_end(session);
+
+ filp->private_data = NULL;
+
+ return 0;
+}
+
+/**************************/
+/*ioctl specific functions*/
+/**************************/
+static int do_ump_dd_allocate(umpp_session * session, ump_k_allocate * params)
+{
+ ump_dd_handle new_allocation;
+ new_allocation = ump_dd_allocate_64(params->size, params->alloc_flags, NULL, NULL, NULL);
+
+ if (UMP_DD_INVALID_MEMORY_HANDLE != new_allocation)
+ {
+ umpp_session_memory_usage * tracker;
+
+ tracker = kmalloc(sizeof(*tracker), GFP_KERNEL | __GFP_HARDWALL);
+ if (NULL != tracker)
+ {
+ /* update the return struct with the new ID */
+ params->secure_id = ump_dd_secure_id_get(new_allocation);
+
+ tracker->mem = new_allocation;
+ tracker->id = params->secure_id;
+ atomic_set(&tracker->process_usage_count, 1);
+
+ /* link it into the session in-use list */
+ mutex_lock(&session->session_lock);
+ list_add(&tracker->link, &session->memory_usage);
+ mutex_unlock(&session->session_lock);
+
+ return 0;
+ }
+ ump_dd_release(new_allocation);
+ }
+
+ printk(KERN_WARNING "UMP: Allocation FAILED\n");
+ return -ENOMEM;
+}
+
+static int do_ump_dd_retain(umpp_session * session, ump_k_retain * params)
+{
+ umpp_session_memory_usage * it;
+
+ mutex_lock(&session->session_lock);
+
+ /* try to find it on the session usage list */
+ list_for_each_entry(it, &session->memory_usage, link)
+ {
+ if (it->id == params->secure_id)
+ {
+ /* found to already be in use */
+ /* check for overflow */
+ while(1)
+ {
+ int refcnt = atomic_read(&it->process_usage_count);
+ if (refcnt + 1 > 0)
+ {
+ /* add a process local ref */
+ if(atomic_cmpxchg(&it->process_usage_count, refcnt, refcnt + 1) == refcnt)
+ {
+ mutex_unlock(&session->session_lock);
+ return 0;
+ }
+ }
+ else
+ {
+ /* maximum usage cap reached */
+ mutex_unlock(&session->session_lock);
+ return -EBUSY;
+ }
+ }
+ }
+ }
+ /* try to look it up globally */
+
+ it = kmalloc(sizeof(*it), GFP_KERNEL);
+
+ if (NULL != it)
+ {
+ it->mem = ump_dd_from_secure_id(params->secure_id);
+ if (UMP_DD_INVALID_MEMORY_HANDLE != it->mem)
+ {
+ /* found, add it to the session usage list */
+ it->id = params->secure_id;
+ atomic_set(&it->process_usage_count, 1);
+ list_add(&it->link, &session->memory_usage);
+ }
+ else
+ {
+ /* not found */
+ kfree(it);
+ it = NULL;
+ }
+ }
+
+ mutex_unlock(&session->session_lock);
+
+ return (NULL != it) ? 0 : -ENODEV;
+}
+
+
+static int do_ump_dd_release(umpp_session * session, ump_k_release * params)
+{
+ umpp_session_memory_usage * it;
+ int result = -ENODEV;
+
+ mutex_lock(&session->session_lock);
+
+ /* only do a release if found on the session list */
+ list_for_each_entry(it, &session->memory_usage, link)
+ {
+ if (it->id == params->secure_id)
+ {
+ /* found, a valid call */
+ result = 0;
+
+ if (0 == atomic_sub_return(1, &it->process_usage_count))
+ {
+ /* last ref in this process remove from the usage list and remove the underlying ref */
+ list_del(&it->link);
+ ump_dd_release(it->mem);
+ kfree(it);
+ }
+
+ break;
+ }
+ }
+ mutex_unlock(&session->session_lock);
+
+ return result;
+}
+
+static int do_ump_dd_sizequery(umpp_session * session, ump_k_sizequery * params)
+{
+ umpp_session_memory_usage * it;
+ int result = -ENODEV;
+
+ mutex_lock(&session->session_lock);
+
+ /* only valid if found on the session list */
+ list_for_each_entry(it, &session->memory_usage, link)
+ {
+ if (it->id == params->secure_id)
+ {
+ /* found, a valid call */
+ params->size = ump_dd_size_get_64(it->mem);
+ result = 0;
+ break;
+ }
+
+ }
+ mutex_unlock(&session->session_lock);
+
+ return result;
+}
+
+static int do_ump_dd_allocation_flags_get(umpp_session * session, ump_k_allocation_flags * params)
+{
+ umpp_session_memory_usage * it;
+ int result = -ENODEV;
+
+ mutex_lock(&session->session_lock);
+
+ /* only valid if found on the session list */
+ list_for_each_entry(it, &session->memory_usage, link)
+ {
+ if (it->id == params->secure_id)
+ {
+ /* found, a valid call */
+ params->alloc_flags = ump_dd_allocation_flags_get(it->mem);
+ result = 0;
+ break;
+ }
+
+ }
+ mutex_unlock(&session->session_lock);
+
+ return result;
+}
+
+static int do_ump_dd_msync_now(umpp_session * session, ump_k_msync * params)
+{
+ umpp_session_memory_usage * it;
+ int result = -ENODEV;
+
+ mutex_lock(&session->session_lock);
+
+ /* only valid if found on the session list */
+ list_for_each_entry(it, &session->memory_usage, link)
+ {
+ if (it->id == params->secure_id)
+ {
+ /* found, do the cache op */
+#if defined CONFIG_64BIT && CONFIG_64BIT
+ if (is_compat_task())
+ {
+ umpp_dd_cpu_msync_now(it->mem, params->cache_operation, params->mapped_ptr.compat_value, params->size);
+ result = 0;
+ }
+ else
+ {
+#endif
+ umpp_dd_cpu_msync_now(it->mem, params->cache_operation, params->mapped_ptr.value, params->size);
+ result = 0;
+#if defined CONFIG_64BIT && CONFIG_64BIT
+ }
+#endif
+ break;
+ }
+ }
+ mutex_unlock(&session->session_lock);
+
+ return result;
+}
+
+
+void umpp_import_handlers_init(umpp_session * session)
+{
+ int i;
+ mutex_lock(&import_list_lock);
+ for ( i = 1; i < UMPP_EXTERNAL_MEM_COUNT; i++ )
+ {
+ if (import_handlers[i])
+ {
+ import_handlers[i]->session_begin(&session->import_handler_data[i]);
+ /* It is OK if session_begin returned an error.
+ * We won't do any import calls if so */
+ }
+ }
+ mutex_unlock(&import_list_lock);
+}
+
+void umpp_import_handlers_term(umpp_session * session)
+{
+ int i;
+ mutex_lock(&import_list_lock);
+ for ( i = 1; i < UMPP_EXTERNAL_MEM_COUNT; i++ )
+ {
+ /* only call if session_begin succeeded */
+ if (session->import_handler_data[i] != NULL)
+ {
+ /* if session_beging succeeded the handler
+ * should not have unregistered with us */
+ BUG_ON(!import_handlers[i]);
+ import_handlers[i]->session_end(session->import_handler_data[i]);
+ session->import_handler_data[i] = NULL;
+ }
+ }
+ mutex_unlock(&import_list_lock);
+}
+
+int ump_import_module_register(enum ump_external_memory_type type, struct ump_import_handler * handler)
+{
+ int res = -EEXIST;
+
+ /* validate input */
+ BUG_ON(type == 0 || type >= UMPP_EXTERNAL_MEM_COUNT);
+ BUG_ON(!handler);
+ BUG_ON(!handler->linux_module);
+ BUG_ON(!handler->session_begin);
+ BUG_ON(!handler->session_end);
+ BUG_ON(!handler->import);
+
+ mutex_lock(&import_list_lock);
+
+ if (!import_handlers[type])
+ {
+ import_handlers[type] = handler;
+ res = 0;
+ }
+
+ mutex_unlock(&import_list_lock);
+
+ return res;
+}
+
+void ump_import_module_unregister(enum ump_external_memory_type type)
+{
+ BUG_ON(type == 0 || type >= UMPP_EXTERNAL_MEM_COUNT);
+
+ mutex_lock(&import_list_lock);
+ /* an error to call this if ump_import_module_register didn't succeed */
+ BUG_ON(!import_handlers[type]);
+ import_handlers[type] = NULL;
+ mutex_unlock(&import_list_lock);
+}
+
+static struct ump_import_handler * import_handler_get(int type_id)
+{
+ enum ump_external_memory_type type;
+ struct ump_import_handler * handler;
+
+ /* validate and convert input */
+ /* handle bad data here, not just BUG_ON */
+ if (type_id == 0 || type_id >= UMPP_EXTERNAL_MEM_COUNT)
+ return NULL;
+
+ type = (enum ump_external_memory_type)type_id;
+
+ /* find the handler */
+ mutex_lock(&import_list_lock);
+
+ handler = import_handlers[type];
+
+ if (handler)
+ {
+ if (!try_module_get(handler->linux_module))
+ {
+ handler = NULL;
+ }
+ }
+
+ mutex_unlock(&import_list_lock);
+
+ return handler;
+}
+
+static void import_handler_put(struct ump_import_handler * handler)
+{
+ module_put(handler->linux_module);
+}
+
+static int do_ump_dd_import(umpp_session * session, ump_k_import * params)
+{
+ ump_dd_handle new_allocation = UMP_DD_INVALID_MEMORY_HANDLE;
+ struct ump_import_handler * handler;
+
+ handler = import_handler_get(params->type);
+
+ if (handler)
+ {
+ /* try late binding if not already bound */
+ if (!session->import_handler_data[params->type])
+ {
+ handler->session_begin(&session->import_handler_data[params->type]);
+ }
+
+ /* do we have a bound session? */
+ if (session->import_handler_data[params->type])
+ {
+ new_allocation = handler->import( session->import_handler_data[params->type],
+ params->phandle.value,
+ params->alloc_flags);
+ }
+
+ /* done with the handler */
+ import_handler_put(handler);
+ }
+
+ /* did the import succeed? */
+ if (UMP_DD_INVALID_MEMORY_HANDLE != new_allocation)
+ {
+ umpp_session_memory_usage * tracker;
+
+ tracker = kmalloc(sizeof(*tracker), GFP_KERNEL | __GFP_HARDWALL);
+ if (NULL != tracker)
+ {
+ /* update the return struct with the new ID */
+ params->secure_id = ump_dd_secure_id_get(new_allocation);
+
+ tracker->mem = new_allocation;
+ tracker->id = params->secure_id;
+ atomic_set(&tracker->process_usage_count, 1);
+
+ /* link it into the session in-use list */
+ mutex_lock(&session->session_lock);
+ list_add(&tracker->link, &session->memory_usage);
+ mutex_unlock(&session->session_lock);
+
+ return 0;
+ }
+ ump_dd_release(new_allocation);
+ }
+
+ return -ENOMEM;
+
+}
+
+#ifdef HAVE_UNLOCKED_IOCTL
+static long umpp_linux_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+#else
+static int umpp_linux_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+#endif
+{
+ int ret;
+ uint64_t msg[(UMP_CALL_MAX_SIZE+7)>>3]; /* alignment fixup */
+ uint32_t size = _IOC_SIZE(cmd);
+ struct umpp_session *session = filp->private_data;
+
+#ifndef HAVE_UNLOCKED_IOCTL
+ (void)inode; /* unused arg */
+#endif
+
+ /*
+ * extract the type and number bitfields, and don't decode
+ * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+ */
+ if (_IOC_TYPE(cmd) != UMP_IOC_MAGIC)
+ {
+ return -ENOTTY;
+
+ }
+ if (_IOC_NR(cmd) > UMP_IOC_MAXNR)
+ {
+ return -ENOTTY;
+ }
+
+ switch(cmd)
+ {
+ case UMP_FUNC_ALLOCATE:
+ if (size != sizeof(ump_k_allocate))
+ {
+ return -ENOTTY;
+ }
+ if (copy_from_user(&msg, (void __user *)arg, size))
+ {
+ return -EFAULT;
+ }
+ ret = do_ump_dd_allocate(session, (ump_k_allocate *)&msg);
+ if (ret)
+ {
+ return ret;
+ }
+ if (copy_to_user((void *)arg, &msg, size))
+ {
+ return -EFAULT;
+ }
+ return 0;
+ case UMP_FUNC_SIZEQUERY:
+ if (size != sizeof(ump_k_sizequery))
+ {
+ return -ENOTTY;
+ }
+ if (copy_from_user(&msg, (void __user *)arg, size))
+ {
+ return -EFAULT;
+ }
+ ret = do_ump_dd_sizequery(session,(ump_k_sizequery*) &msg);
+ if (ret)
+ {
+ return ret;
+ }
+ if (copy_to_user((void *)arg, &msg, size))
+ {
+ return -EFAULT;
+ }
+ return 0;
+ case UMP_FUNC_MSYNC:
+ if (size != sizeof(ump_k_msync))
+ {
+ return -ENOTTY;
+ }
+ if (copy_from_user(&msg, (void __user *)arg, size))
+ {
+ return -EFAULT;
+ }
+ ret = do_ump_dd_msync_now(session,(ump_k_msync*) &msg);
+ if (ret)
+ {
+ return ret;
+ }
+ if (copy_to_user((void *)arg, &msg, size))
+ {
+ return -EFAULT;
+ }
+ return 0;
+ case UMP_FUNC_IMPORT:
+ if (size != sizeof(ump_k_import))
+ {
+ return -ENOTTY;
+ }
+ if (copy_from_user(&msg, (void __user*)arg, size))
+ {
+ return -EFAULT;
+ }
+ ret = do_ump_dd_import(session, (ump_k_import*) &msg);
+ if (ret)
+ {
+ return ret;
+ }
+ if (copy_to_user((void *)arg, &msg, size))
+ {
+ return -EFAULT;
+ }
+ return 0;
+ /* used only by v1 API */
+ case UMP_FUNC_ALLOCATION_FLAGS_GET:
+ if (size != sizeof(ump_k_allocation_flags))
+ {
+ return -ENOTTY;
+ }
+ if (copy_from_user(&msg, (void __user *)arg, size))
+ {
+ return -EFAULT;
+ }
+ ret = do_ump_dd_allocation_flags_get(session,(ump_k_allocation_flags*) &msg);
+ if (ret)
+ {
+ return ret;
+ }
+ if (copy_to_user((void *)arg, &msg, size))
+ {
+ return -EFAULT;
+ }
+ return 0;
+ case UMP_FUNC_RETAIN:
+ if (size != sizeof(ump_k_retain))
+ {
+ return -ENOTTY;
+ }
+ if (copy_from_user(&msg, (void __user *)arg, size))
+ {
+ return -EFAULT;
+ }
+ ret = do_ump_dd_retain(session,(ump_k_retain*) &msg);
+ if (ret)
+ {
+ return ret;
+ }
+ return 0;
+ case UMP_FUNC_RELEASE:
+ if (size != sizeof(ump_k_release))
+ {
+ return -ENOTTY;
+ }
+ if (copy_from_user(&msg, (void __user *)arg, size))
+ {
+ return -EFAULT;
+ }
+ ret = do_ump_dd_release(session,(ump_k_release*) &msg);
+ if (ret)
+ {
+ return ret;
+ }
+ return 0;
+ default:
+ /* not ours */
+ return -ENOTTY;
+ }
+ /*redundant below*/
+ return -ENOTTY;
+}
+
+
+/* Export UMP kernel space API functions */
+EXPORT_SYMBOL(ump_dd_allocate_64);
+EXPORT_SYMBOL(ump_dd_allocation_flags_get);
+EXPORT_SYMBOL(ump_dd_secure_id_get);
+EXPORT_SYMBOL(ump_dd_from_secure_id);
+EXPORT_SYMBOL(ump_dd_phys_blocks_get_64);
+EXPORT_SYMBOL(ump_dd_size_get_64);
+EXPORT_SYMBOL(ump_dd_retain);
+EXPORT_SYMBOL(ump_dd_release);
+EXPORT_SYMBOL(ump_dd_create_from_phys_blocks_64);
+#ifdef CONFIG_KDS
+EXPORT_SYMBOL(ump_dd_kds_resource_get);
+#endif
+
+/* import API */
+EXPORT_SYMBOL(ump_import_module_register);
+EXPORT_SYMBOL(ump_import_module_unregister);
+
+
+
+/* V1 API */
+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_handle_create_from_phys_blocks);
+
+
+/* Setup init and exit functions for this module */
+module_init(umpp_linux_initialize_module);
+module_exit(umpp_linux_cleanup_module);
+
+/* And some module informatio */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ARM Ltd.");
+MODULE_VERSION(UMP_REV_STRING);
diff --git a/drivers/base/ump/src/linux/ump_kernel_linux_mem.c b/drivers/base/ump/src/linux/ump_kernel_linux_mem.c
new file mode 100755
index 00000000000..e3de61f3d45
--- /dev/null
+++ b/drivers/base/ump/src/linux/ump_kernel_linux_mem.c
@@ -0,0 +1,248 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2013 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/ump.h>
+#include <linux/ump-ioctl.h>
+
+#include <linux/version.h>
+#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 mananger definitions */
+#include <linux/pfn.h>
+#include <linux/highmem.h> /*kmap*/
+
+#include <linux/compat.h> /* is_compat_task */
+
+#include <common/ump_kernel_core.h>
+#include <ump_arch.h>
+#include <common/ump_kernel_priv.h>
+
+static void umpp_vm_close(struct vm_area_struct *vma)
+{
+ umpp_cpu_mapping * mapping;
+ umpp_session * session;
+ ump_dd_handle handle;
+
+ mapping = (umpp_cpu_mapping*)vma->vm_private_data;
+ UMP_ASSERT(mapping);
+
+ session = mapping->session;
+ handle = mapping->handle;
+
+ umpp_dd_remove_cpu_mapping(mapping->handle, mapping); /* will free the mapping object */
+ ump_dd_release(handle);
+}
+
+
+static const struct vm_operations_struct umpp_vm_ops = {
+ .close = umpp_vm_close
+};
+
+int umpp_phys_commit(umpp_allocation * alloc)
+{
+ uint64_t i;
+
+ /* round up to a page boundary */
+ alloc->size = (alloc->size + PAGE_SIZE - 1) & ~((uint64_t)PAGE_SIZE-1) ;
+ /* calculate number of pages */
+ alloc->blocksCount = alloc->size >> PAGE_SHIFT;
+
+ if( (sizeof(ump_dd_physical_block_64) * alloc->blocksCount) > ((size_t)-1))
+ {
+ printk(KERN_WARNING "UMP: umpp_phys_commit - trying to allocate more than possible\n");
+ return -ENOMEM;
+ }
+
+ alloc->block_array = kmalloc(sizeof(ump_dd_physical_block_64) * alloc->blocksCount, __GFP_HARDWALL | GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
+ if (NULL == alloc->block_array)
+ {
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < alloc->blocksCount; i++)
+ {
+ void * mp;
+ struct page * page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY | __GFP_NOWARN | __GFP_COLD);
+ if (NULL == page)
+ {
+ break;
+ }
+
+ alloc->block_array[i].addr = page_to_pfn(page) << PAGE_SHIFT;
+ alloc->block_array[i].size = PAGE_SIZE;
+
+ mp = kmap(page);
+ if (NULL == mp)
+ {
+ __free_page(page);
+ break;
+ }
+
+ memset(mp, 0x00, PAGE_SIZE); /* instead of __GFP_ZERO, so we can do cache maintenance */
+ ump_sync_to_memory(PFN_PHYS(page_to_pfn(page)), mp, PAGE_SIZE);
+ kunmap(page);
+ }
+
+ if (i == alloc->blocksCount)
+ {
+ return 0;
+ }
+ else
+ {
+ uint64_t j;
+ for (j = 0; j < i; j++)
+ {
+ struct page * page;
+ page = pfn_to_page(alloc->block_array[j].addr >> PAGE_SHIFT);
+ __free_page(page);
+ }
+
+ kfree(alloc->block_array);
+
+ return -ENOMEM;
+ }
+}
+
+void umpp_phys_free(umpp_allocation * alloc)
+{
+ uint64_t i;
+
+ for (i = 0; i < alloc->blocksCount; i++)
+ {
+ __free_page(pfn_to_page(alloc->block_array[i].addr >> PAGE_SHIFT));
+ }
+
+ kfree(alloc->block_array);
+}
+
+int umpp_linux_mmap(struct file * filp, struct vm_area_struct * vma)
+{
+ ump_secure_id id;
+ ump_dd_handle h;
+ size_t offset;
+ int err = -EINVAL;
+ size_t length = vma->vm_end - vma->vm_start;
+
+ umpp_cpu_mapping * map = NULL;
+ umpp_session *session = filp->private_data;
+
+ if ( 0 == length )
+ {
+ return -EINVAL;
+ }
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (NULL == map)
+ {
+ WARN_ON(1);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* unpack our arg */
+#if defined CONFIG_64BIT && CONFIG_64BIT
+ if (is_compat_task())
+ {
+#endif
+ id = vma->vm_pgoff >> UMP_LINUX_OFFSET_BITS_32;
+ offset = vma->vm_pgoff & UMP_LINUX_OFFSET_MASK_32;
+#if defined CONFIG_64BIT && CONFIG_64BIT
+ }
+ else
+ {
+ id = vma->vm_pgoff >> UMP_LINUX_OFFSET_BITS_64;
+ offset = vma->vm_pgoff & UMP_LINUX_OFFSET_MASK_64;
+ }
+#endif
+
+ h = ump_dd_from_secure_id(id);
+ if (UMP_DD_INVALID_MEMORY_HANDLE != h)
+ {
+ uint64_t i;
+ uint64_t block_idx;
+ uint64_t block_offset;
+ uint64_t paddr;
+ umpp_allocation * alloc;
+ uint64_t last_byte;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0))
+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_IO | VM_MIXEDMAP | VM_DONTDUMP;
+#else
+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED | VM_IO | VM_MIXEDMAP;
+#endif
+ vma->vm_ops = &umpp_vm_ops;
+ vma->vm_private_data = map;
+
+ alloc = (umpp_allocation*)h;
+
+ if( (alloc->flags & UMP_CONSTRAINT_UNCACHED) != 0)
+ {
+ /* cache disabled flag set, disable caching for cpu mappings */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ }
+
+ last_byte = length + (offset << PAGE_SHIFT) - 1;
+ if (last_byte >= alloc->size || last_byte < (offset << PAGE_SHIFT))
+ {
+ goto err_out;
+ }
+
+ if (umpp_dd_find_start_block(alloc, offset << PAGE_SHIFT, &block_idx, &block_offset))
+ {
+ goto err_out;
+ }
+
+ paddr = alloc->block_array[block_idx].addr + block_offset;
+
+ for (i = 0; i < (length >> PAGE_SHIFT); i++)
+ {
+ /* check if we've overrrun the current block, if so move to the next block */
+ if (paddr >= (alloc->block_array[block_idx].addr + alloc->block_array[block_idx].size))
+ {
+ block_idx++;
+ UMP_ASSERT(block_idx < alloc->blocksCount);
+ paddr = alloc->block_array[block_idx].addr;
+ }
+
+ err = vm_insert_mixed(vma, vma->vm_start + (i << PAGE_SHIFT), paddr >> PAGE_SHIFT);
+ paddr += PAGE_SIZE;
+ }
+
+ map->vaddr_start = (void*)vma->vm_start;
+ map->nr_pages = length >> PAGE_SHIFT;
+ map->page_off = offset;
+ map->handle = h;
+ map->session = session;
+
+ umpp_dd_add_cpu_mapping(h, map);
+
+ return 0;
+
+ err_out:
+
+ ump_dd_release(h);
+ }
+
+ kfree(map);
+
+out:
+
+ return err;
+}
+
diff --git a/drivers/base/ump/src/linux/ump_kernel_linux_mem.h b/drivers/base/ump/src/linux/ump_kernel_linux_mem.h
new file mode 100755
index 00000000000..9b28cffff1d
--- /dev/null
+++ b/drivers/base/ump/src/linux/ump_kernel_linux_mem.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2011 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_MEM_H_
+#define _UMP_KERNEL_LINUX_MEM_H_
+
+
+int umpp_linux_mmap(struct file * filp, struct vm_area_struct * vma);
+
+#endif /* _UMP_KERNEL_LINUX_MEM_H_ */
diff --git a/drivers/base/ump/src/sconscript b/drivers/base/ump/src/sconscript
new file mode 100755
index 00000000000..b493738ce63
--- /dev/null
+++ b/drivers/base/ump/src/sconscript
@@ -0,0 +1,80 @@
+#
+# (C) COPYRIGHT 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.
+#
+#
+
+
+import os
+import re
+Import('env')
+
+# Clone the environment so changes don't affect other build files
+env_ump = env.Clone()
+
+if env_ump['v'] != '1':
+ env_ump['MAKECOMSTR'] = '[MAKE] ${SOURCE.dir}'
+
+# Source files required for UMP.
+ump_src = [Glob('#kernel/drivers/base/ump/src/linux/*.c'), Glob('#kernel/drivers/base/ump/src/common/*.c'), Glob('#kernel/drivers/base/ump/src/imports/*/*.c')]
+
+env_ump.Append( CPPPATH='#kernel/drivers/base/ump/src/' )
+
+# Note: cleaning via the Linux kernel build system does not yet work
+if env_ump.GetOption('clean') :
+ makeAction=Action("cd ${SOURCE.dir}/.. && make clean", '$MAKECOMSTR')
+else:
+ if env['arch'] == 'x86_32' :
+ env_ump['arch_linux'] = 'x86'
+ elif 'arm' in env['arch']:
+ env_ump['arch_linux'] = 'arm'
+ else:
+ env_ump['arch_linux'] = env['arch']
+ if env['unit'] == '1':
+ makeAction=Action("cd ${SOURCE.dir}/.. && make ARCH=$arch_linux MALI_UNIT_TEST=${unit} PLATFORM=${platform} %s && cp ump.ko $STATIC_LIB_PATH/ump.ko" % env.kernel_get_config_defines(), '$MAKECOMSTR')
+ else:
+ makeAction=Action("cd ${SOURCE.dir}/.. && make ARCH=$arch_linux PLATFORM=${platform} %s && cp ump.ko $STATIC_LIB_PATH/ump.ko" % env.kernel_get_config_defines(), '$MAKECOMSTR')
+# The target is ump.ko, built from the source in ump_src, via the action makeAction
+# ump.ko will be copied to $STATIC_LIB_PATH after being built by the standard Linux
+# kernel build system, after which it can be installed to the directory specified if
+# "libs_install" is set; this is done by LibTarget.
+cmd = env_ump.Command('$STATIC_LIB_PATH/ump.ko', ump_src, [makeAction])
+
+if env['unit'] == '1':
+ env.Depends('$STATIC_LIB_PATH/ump.ko', '$STATIC_LIB_PATH/libosk.a')
+
+# Add a dependency on kds.ko.
+# Only necessary when KDS is not built into the kernel.
+#
+linux_config_file = os.path.normpath(os.environ['KDIR']) + '/.config'
+search_term = '^[\ ]*CONFIG_KDS[\ ]*=[\ ]*y'
+kds_in_kernel = 0
+for line in open(linux_config_file, 'r'):
+ if re.search(search_term, line):
+ # KDS in kernel.
+ kds_in_kernel = 1
+if not kds_in_kernel:
+ env.Depends('$STATIC_LIB_PATH/ump.ko', '$STATIC_LIB_PATH/kds.ko')
+
+# Until we fathom out how the invoke the Linux build system to clean, we can use Clean
+# to remove generated files.
+
+patterns = ['*.mod.c', '*.o', '*.ko', '*.a', '.*.cmd', 'modules.order', '.tmp_versions', 'Module.symvers']
+
+for p in patterns:
+ Clean(cmd, Glob('#kernel/drivers/base/ump/src/common/%s' % p))
+ Clean(cmd, Glob('#kernel/drivers/base/ump/src/linux/%s' % p))
+ Clean(cmd, Glob('#kernel/drivers/base/ump/src/%s' % p))
+
+env_ump.ProgTarget('ump', cmd)
+
+SConscript( 'imports/sconscript' )
+
diff --git a/drivers/base/ump/src/ump_arch.h b/drivers/base/ump/src/ump_arch.h
new file mode 100755
index 00000000000..5c1160b1fc3
--- /dev/null
+++ b/drivers/base/ump/src/ump_arch.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2011 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_ARCH_H_
+#define _UMP_ARCH_H_
+
+#include <common/ump_kernel_core.h>
+
+/**
+ * Device specific setup.
+ * Called by the UMP core code to to host OS/device specific setup.
+ * Typical use case is device node creation for talking to user space.
+ * @return UMP_OK on success, any other value on failure
+ */
+extern ump_result umpp_device_initialize(void);
+
+/**
+ * Device specific teardown.
+ * Undo any things done by ump_device_initialize.
+ */
+extern void umpp_device_terminate(void);
+
+extern int umpp_phys_commit(umpp_allocation * alloc);
+extern void umpp_phys_free(umpp_allocation * alloc);
+
+#endif /* _UMP_ARCH_H_ */
diff --git a/drivers/base/ump/ump_ref_drv.h b/drivers/base/ump/ump_ref_drv.h
new file mode 100755
index 00000000000..2ec85d9afee
--- /dev/null
+++ b/drivers/base/ump/ump_ref_drv.h
@@ -0,0 +1,31 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-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_ref_drv.h
+ *
+ * This file contains the link to user space part of the UMP API for usage by MALI 400 gralloc.
+ *
+ */
+
+#ifndef _UMP_REF_DRV_H_
+#define _UMP_REF_DRV_H_
+
+#include <ump/ump.h>
+
+
+#endif /* _UMP_REF_DRV_H_ */
diff --git a/include/linux/ump-common.h b/include/linux/ump-common.h
new file mode 100755
index 00000000000..85264c09a49
--- /dev/null
+++ b/include/linux/ump-common.h
@@ -0,0 +1,250 @@
+/*
+ *
+ * (C) COPYRIGHT 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-common.h
+ *
+ * This file contains some common enum values used both in both the user and kernel space side of UMP.
+ */
+
+#ifndef _UMP_COMMON_H_
+#define _UMP_COMMON_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
+#define UMP_UINT32_MAX (4294967295U)
+#define UMP_UINT64_MAX (18446744073709551615ULL)
+
+#ifdef __GNUC__
+ #define CHECK_RESULT __attribute__((__warn_unused_result__))
+ #define INLINE __inline__
+#else
+ #define CHECK_RESULT
+ #define INLINE __inline
+#endif
+
+#ifndef STATIC
+ #define STATIC static
+#endif
+
+/**
+ * Values to identify major and minor version of UMP
+ */
+#define UMP_VERSION_MAJOR 2
+#define UMP_VERSION_MINOR 0
+
+/**
+ * Typedef for a secure ID, a system wide identifier for UMP memory buffers.
+ */
+typedef int32_t ump_secure_id;
+
+/**
+ * Value to indicate an invalid secure Id.
+ */
+#define UMP_INVALID_SECURE_ID ((ump_secure_id)0)
+
+/**
+ * UMP error codes.
+ */
+typedef enum
+{
+ UMP_OK = 0, /**< indicates success */
+ UMP_ERROR = 1 /**< indicates failure */
+} ump_result;
+
+/**
+ * Allocation flag bits.
+ *
+ * ump_allocate accepts zero or more flags to specify the type of memory to allocate and how to expose it to devices.
+ *
+ * For each supported device there are 4 flags to control access permissions and give usage characteristic hints to optimize the allocation/mapping.
+ * They are;
+ * @li @a UMP_PROT_<device>_RD read permission
+ * @li @a UMP_PROT_<device>_WR write permission
+ * @li @a UMP_HINT_<device>_RD read often
+ * @li @a UMP_HINT_<device>_WR written often
+ *
+ * 5 devices are currently supported, with a device being the CPU itself.
+ * The other 4 devices will be mapped to real devices per SoC design.
+ * They are just named W,X,Y,Z by UMP as it has no knowledge of their real names/identifiers.
+ * As an example device W could be a camera device while device Z could be an ARM GPU device, leaving X and Y unused.
+ *
+ * 2 additional flags control the allocation;
+ * @li @a UMP_CONSTRAINT_PHYSICALLY_LINEAR the allocation must be physical linear. Typical for devices without an MMU and no IOMMU to help it.
+ * @li @a UMP_PROT_SHAREABLE the allocation can be shared with other processes on the system. Without this flag the returned allocation won't be resolvable in other processes.
+ *
+ * All UMP allocation are growable unless they're @a UMP_PROT_SHAREABLE.
+ * The hint bits should be used to indicate the access pattern so the driver can select the most optimal memory type and cache settings based on the what the system supports.
+ */
+typedef enum
+{
+ /* Generic helpers */
+ UMP_PROT_DEVICE_RD = (1u << 0),
+ UMP_PROT_DEVICE_WR = (1u << 1),
+ UMP_HINT_DEVICE_RD = (1u << 2),
+ UMP_HINT_DEVICE_WR = (1u << 3),
+ UMP_DEVICE_MASK = 0xF,
+ UMP_DEVICE_CPU_SHIFT = 0,
+ UMP_DEVICE_W_SHIFT = 4,
+ UMP_DEVICE_X_SHIFT = 8,
+ UMP_DEVICE_Y_SHIFT = 12,
+ UMP_DEVICE_Z_SHIFT = 16,
+
+ /* CPU protection and hints. */
+ UMP_PROT_CPU_RD = (1u << 0),
+ UMP_PROT_CPU_WR = (1u << 1),
+ UMP_HINT_CPU_RD = (1u << 2),
+ UMP_HINT_CPU_WR = (1u << 3),
+
+ /* device W */
+ UMP_PROT_W_RD = (1u << 4),
+ UMP_PROT_W_WR = (1u << 5),
+ UMP_HINT_W_RD = (1u << 6),
+ UMP_HINT_W_WR = (1u << 7),
+
+ /* device X */
+ UMP_PROT_X_RD = (1u << 8),
+ UMP_PROT_X_WR = (1u << 9),
+ UMP_HINT_X_RD = (1u << 10),
+ UMP_HINT_X_WR = (1u << 11),
+
+ /* device Y */
+ UMP_PROT_Y_RD = (1u << 12),
+ UMP_PROT_Y_WR = (1u << 13),
+ UMP_HINT_Y_RD = (1u << 14),
+ UMP_HINT_Y_WR = (1u << 15),
+
+ /* device Z */
+ UMP_PROT_Z_RD = (1u << 16),
+ UMP_PROT_Z_WR = (1u << 17),
+ UMP_HINT_Z_RD = (1u << 18),
+ UMP_HINT_Z_WR = (1u << 19),
+
+ /* 20-26 reserved for future use */
+ UMPP_ALLOCBITS_UNUSED = (0x7Fu << 20),
+ /** Allocations marked as @ UMP_CONSTRAINT_UNCACHED won't be mapped as cached by the cpu */
+ UMP_CONSTRAINT_UNCACHED = (1u << 27),
+ /** Require 32-bit physically addressable memory */
+ UMP_CONSTRAINT_32BIT_ADDRESSABLE = (1u << 28),
+ /** For devices without an MMU and with no IOMMU assistance. */
+ UMP_CONSTRAINT_PHYSICALLY_LINEAR = (1u << 29),
+ /** Shareable must be set to allow the allocation to be used by other processes, the default is non-shared */
+ UMP_PROT_SHAREABLE = (1u << 30)
+ /* (1u << 31) should not be used to ensure compiler portability */
+} ump_allocation_bits;
+
+/**
+ * ump_allocation_bits combination argument type.
+ *
+ * Type used to pass zero or more bits from the @ref ump_allocation_bits enum
+ */
+typedef uint32_t ump_alloc_flags;
+
+
+/**
+ * Default allocation flags for UMP v1 compatible allocations.
+ */
+#define UMP_V1_API_DEFAULT_ALLOCATION_FLAGS UMP_PROT_CPU_RD | UMP_PROT_CPU_WR | \
+ UMP_PROT_W_RD | UMP_PROT_W_WR | \
+ UMP_PROT_X_RD | UMP_PROT_X_WR | \
+ UMP_PROT_Y_RD | UMP_PROT_Y_WR | \
+ UMP_PROT_Z_RD | UMP_PROT_Z_WR | \
+ UMP_PROT_SHAREABLE | \
+ UMP_CONSTRAINT_32BIT_ADDRESSABLE
+
+/**
+ * CPU cache sync operations.
+ *
+ * Cache synchronization operations to pass to @ref ump_cpu_msync_now
+ */
+enum
+{
+ /**
+ * Cleans any dirty cache lines to main memory, but the data will still be available in the cache.
+ * After a clean the contents of memory is considered to be "owned" by the device.
+ * */
+ UMP_MSYNC_CLEAN = 1,
+
+ /** Cleans any dirty cache lines to main memory and Ejects all lines from the cache.
+ * After an clean&invalidate the contents of memory is considered to be "owned" by the CPU.
+ * Any subsequent access will fetch data from main memory.
+ *
+ * @note Due to CPUs doing speculative prefetching a UMP_MSYNC_CLEAN_AND_INVALIDATE must be done before and after interacting with hardware.
+ * */
+ UMP_MSYNC_CLEAN_AND_INVALIDATE
+
+};
+
+typedef uint32_t ump_cpu_msync_op;
+
+/**
+ * Memory import types supported.
+ * If new import types are added they will appear here.
+ * They must be added before UMPP_EXTERNAL_MEM_COUNT and
+ * must be assigned an explicit sequantial number.
+ *
+ * @li UMP_EXTERNAL_MEM_TYPE_ION - Import an ION allocation
+ * Takes a int* (pointer to a file descriptor)
+ * Another ION reference is taken which is released on the final ump_release
+ */
+enum ump_external_memory_type
+{
+ UMPP_EXTERNAL_MEM_TYPE_UNUSED = 0, /* reserve type 0 */
+ UMP_EXTERNAL_MEM_TYPE_ION = 1,
+ UMPP_EXTERNAL_MEM_COUNT
+};
+
+/** @name UMP v1 API
+ *
+ *@{
+ */
+
+/**
+ * Allocation constraints.
+ *
+ * Allocation flags to pass @ref ump_ref_drv_allocate
+ *
+ * UMP v1 API only.
+ */
+typedef enum
+{
+ /** the allocation is mapped as noncached. */
+ UMP_REF_DRV_CONSTRAINT_NONE = 0,
+ /** not supported. */
+ UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR = 1,
+ /** the allocation is mapped as cached by the cpu. */
+ UMP_REF_DRV_CONSTRAINT_USE_CACHE = 4
+} ump_alloc_constraints;
+
+/* @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _UMP_COMMON_H_ */
diff --git a/include/linux/ump-import.h b/include/linux/ump-import.h
new file mode 100755
index 00000000000..af162ddc7b9
--- /dev/null
+++ b/include/linux/ump-import.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-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_IMPORT_H_
+#define _UMP_IMPORT_H_
+
+#include <linux/ump.h>
+#include <linux/module.h>
+
+/**
+ * UMP import module info.
+ * Contains information about the Linux module providing the import module,
+ * used to block unloading of the Linux module while imported memory exists.
+ * Lists the functions implementing the UMP import functions.
+ */
+struct ump_import_handler
+{
+ /**
+ * Linux module of the import handler
+ */
+ struct module * linux_module;
+
+ /**
+ * UMP session usage begin.
+ *
+ * Called when a UMP session first is bound to the handler.
+ * Typically used to set up any import module specific per-session data.
+ * The function returns a pointer to this data in the output pointer custom_session_data
+ * which will be passed to \a session_end and \a import.
+ *
+ * Note: custom_session_data must be set to non-NULL if successful.
+ * If no pointer is needed set it a magic value to validate instead.
+ *
+ * @param[out] custom_session_data Pointer to a generic pointer where any data can be stored
+ * @return 0 on success, error code if the session could not be initiated.
+ */
+ int (*session_begin)(void ** custom_session_data);
+
+ /**
+ * UMP session usage end.
+ *
+ * Called when a UMP session is no longer using the handler.
+ * Only called if @a session_begin returned OK.
+ *
+ * @param[in] custom_session_data The value set by the session_begin handler
+ */
+ void (*session_end)(void * custom_session_data);
+
+ /**
+ * Import request.
+ *
+ * Called when a client has asked to import a resource of the type the import module was installed for.
+ * Only called if @a session_begin returned OK.
+ *
+ * The requested flags must be verified to be valid to apply to the imported memory.
+ * If not valid return UMP_DD_INVALID_MEMORY_HANDLE.
+ * If the flags are found to be valid call \a ump_dd_create_from_phys_blocks_64 to create a handle.
+ *
+ * @param[in] custom_session_data The value set by the session_begin handler
+ * @param[in] phandle Pointer to the handle to import
+ * @param flags The requested UMPv2 flags to assign to the imported handle
+ * @return UMP_DD_INVALID_MEMORY_HANDLE if the import failed, a valid ump handle on success
+ */
+ ump_dd_handle (*import)(void * custom_session_data, void * phandle, ump_alloc_flags flags);
+};
+
+/**
+ * Import module registration.
+ * Registers a ump_import_handler structure for a memory type.
+ * @param type Type of the memory to register a handler for
+ * @param[in] handler Handler strcture to install
+ * @return 0 on success, a Linux error code on failure
+ */
+int ump_import_module_register(enum ump_external_memory_type type, struct ump_import_handler * handler);
+
+/**
+ * Import module deregistration.
+ * Uninstalls the handler for the given memory type.
+ * @param type Type of the memory to unregister the handler for
+ */
+void ump_import_module_unregister(enum ump_external_memory_type type);
+
+#endif /* _UMP_IMPORT_H_ */
diff --git a/include/linux/ump-ioctl.h b/include/linux/ump-ioctl.h
new file mode 100755
index 00000000000..8a13896dc4b
--- /dev/null
+++ b/include/linux/ump-ioctl.h
@@ -0,0 +1,150 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-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
+
+#include <linux/ump-common.h>
+
+/*
+ * The order and size of the members of these have been chosen so the structures look the same in 32-bit and 64-bit builds.
+ * If any changes are done build the ump_struct_size_checker test for 32-bit and 64-bit targets. Both must compile successfully to commit.
+ */
+
+/** 32/64-bit neutral way to represent pointers */
+typedef union ump_pointer
+{
+ void * value; /**< client should store their pointers here */
+ uint32_t compat_value; /**< 64-bit kernels should fetch value here when handling 32-bit clients */
+ uint64_t sizer; /**< Force 64-bit storage for all clients regardless */
+} ump_pointer;
+
+/**
+ * UMP allocation request.
+ * Used when performing ump_allocate
+ */
+typedef struct ump_k_allocate
+{
+ uint64_t size; /**< [in] Size in bytes to allocate */
+ ump_secure_id secure_id; /**< [out] Secure ID of allocation on success */
+ ump_alloc_flags alloc_flags; /**< [in] Flags to use when allocating */
+} ump_k_allocate;
+
+/**
+ * UMP size query request.
+ * Used when performing ump_size_get
+ */
+typedef struct ump_k_sizequery
+{
+ uint64_t size; /**< [out] Size of allocation */
+ ump_secure_id secure_id; /**< [in] ID of allocation to query the size of */
+ uint32_t padding; /* don't remove */
+} ump_k_sizequery;
+
+/**
+ * UMP cache synchronization request.
+ * Used when performing ump_cpu_msync_now
+ */
+typedef struct ump_k_msync
+{
+ ump_pointer mapped_ptr; /**< [in] CPU VA to perform cache operation on */
+ ump_secure_id secure_id; /**< [in] ID of allocation to perform cache operation on */
+ ump_cpu_msync_op cache_operation; /**< [in] Cache operation to perform */
+ uint64_t size; /**< [in] Size in bytes of the range to synchronize */
+} ump_k_msync;
+
+/**
+ * UMP memory retain request.
+ * Used when performing ump_retain
+ */
+typedef struct ump_k_retain
+{
+ ump_secure_id secure_id; /**< [in] ID of allocation to retain a reference to */
+ uint32_t padding; /* don't remove */
+} ump_k_retain;
+
+/**
+ * UMP memory release request.
+ * Used when performing ump_release
+ */
+typedef struct ump_k_release
+{
+ ump_secure_id secure_id; /**< [in] ID of allocation to release a reference to */
+ uint32_t padding; /* don't remove */
+} ump_k_release;
+
+typedef struct ump_k_import
+{
+ ump_pointer phandle; /**< [in] Pointer to handle to import */
+ uint32_t type; /**< [in] Type of handle to import */
+ ump_alloc_flags alloc_flags; /**< [in] Flags to assign to the imported memory */
+ ump_secure_id secure_id; /**< [out] UMP ID representing the imported memory */
+ uint32_t padding; /* don't remove */
+} ump_k_import;
+
+/**
+ * UMP allocation flags request.
+ * Used when performing umpp_get_allocation_flags
+ *
+ * used only by v1 API
+ */
+typedef struct ump_k_allocation_flags
+{
+ ump_secure_id secure_id; /**< [in] Secure ID of allocation on success */
+ ump_alloc_flags alloc_flags; /**< [out] Flags to use when allocating */
+} ump_k_allocation_flags;
+
+#define UMP_CALL_MAX_SIZE 512
+/*
+ * Ioctl definitions
+ */
+
+/* Use '~' as magic number */
+
+#define UMP_IOC_MAGIC '~'
+
+#define UMP_FUNC_ALLOCATE _IOWR(UMP_IOC_MAGIC, 1, ump_k_allocate)
+#define UMP_FUNC_SIZEQUERY _IOWR(UMP_IOC_MAGIC, 2, ump_k_sizequery)
+#define UMP_FUNC_MSYNC _IOWR(UMP_IOC_MAGIC, 3, ump_k_msync)
+#define UMP_FUNC_RETAIN _IOW(UMP_IOC_MAGIC, 4, ump_k_retain)
+#define UMP_FUNC_RELEASE _IOW(UMP_IOC_MAGIC, 5, ump_k_release)
+#define UMP_FUNC_ALLOCATION_FLAGS_GET _IOWR(UMP_IOC_MAGIC, 6, ump_k_allocation_flags)
+#define UMP_FUNC_IMPORT _IOWR(UMP_IOC_MAGIC, 7, ump_k_import)
+
+/*max ioctl sequential number*/
+#define UMP_IOC_MAXNR 7
+
+/* 15 bits for the UMP ID (allowing 32768 IDs) */
+#define UMP_LINUX_ID_BITS 15
+#define UMP_LINUX_ID_MASK ((1ULL << UMP_LINUX_ID_BITS) - 1ULL)
+
+/* 64-bit (really 52 bits) encoding: 15 bits for the ID, 37 bits for the offset */
+#define UMP_LINUX_OFFSET_BITS_64 37
+#define UMP_LINUX_OFFSET_MASK_64 ((1ULL << UMP_LINUX_OFFSET_BITS_64)-1)
+/* 32-bit encoding: 15 bits for the ID, 17 bits for the offset */
+#define UMP_LINUX_OFFSET_BITS_32 17
+#define UMP_LINUX_OFFSET_MASK_32 ((1ULL << UMP_LINUX_OFFSET_BITS_32)-1)
+
+#if __SIZEOF_LONG__ == 8
+#define UMP_LINUX_OFFSET_BITS UMP_LINUX_OFFSET_BITS_64
+#define UMP_LINUX_OFFSET_MASK UMP_LINUX_OFFSET_MASK_64
+#else
+#define UMP_LINUX_OFFSET_BITS UMP_LINUX_OFFSET_BITS_32
+#define UMP_LINUX_OFFSET_MASK UMP_LINUX_OFFSET_MASK_32
+#endif
+
+#endif /* _UMP_IOCTL_H_ */
diff --git a/include/linux/ump.h b/include/linux/ump.h
new file mode 100755
index 00000000000..8758de986d1
--- /dev/null
+++ b/include/linux/ump.h
@@ -0,0 +1,479 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-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
+ *
+ * This file contains the kernel space part of the UMP API.
+ *
+ */
+
+#ifndef _UMP_KERNEL_INTERFACE_H_
+#define _UMP_KERNEL_INTERFACE_H_
+
+/**
+ * @addtogroup ump_api
+ * @{
+ */
+
+/** @defgroup ump_kernel_space_api UMP Kernel Space API
+ * @{ */
+
+/**
+ * External representation of a UMP handle in kernel space.
+ */
+typedef void * ump_dd_handle;
+
+#ifdef CONFIG_KDS
+#include <linux/kds.h>
+#endif
+
+#include <linux/ump-common.h>
+
+#define UMP_KERNEL_API_EXPORT
+
+#if defined(__KERNEL__)
+#include <linux/ump-import.h>
+#else
+#include <ump/src/library/common/ump_user.h>
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Value to indicate an invalid UMP memory handle.
+ */
+#define UMP_DD_INVALID_MEMORY_HANDLE ((ump_dd_handle)0)
+
+/**
+ * Struct used to describe a physical block used by UMP memory
+ */
+typedef struct ump_dd_physical_block_64
+{
+ uint64_t addr; /**< The physical address of the block */
+ uint64_t size; /**< The length of the block, in bytes, typically page aligned */
+} ump_dd_physical_block_64;
+
+/**
+ * Security filter hook.
+ *
+ * Each allocation can have a security filter attached to it.@n
+ * The hook receives
+ * @li the secure ID
+ * @li a handle to the allocation
+ * @li the callback_data argument provided to @ref ump_dd_allocate_64 or @ref ump_dd_create_from_phys_blocks_64
+ *
+ * The hook must return @a MALI_TRUE to indicate that access to the handle is allowed or @n
+ * @a MALI_FALSE to state that no access is permitted.@n
+ * This hook is guaranteed to be called in the context of the requesting process/address space.
+ *
+ * The arguments provided to the hook are;
+ * @li the secure ID
+ * @li handle to the allocation
+ * @li the callback_data set when registering the hook
+ *
+ * Return value;
+ * @li @a TRUE to permit access
+ * @li @a FALSE to deny access
+ */
+typedef bool (*ump_dd_security_filter)(ump_secure_id, ump_dd_handle, void *);
+
+/**
+ * Final release notify hook.
+ *
+ * Allocations can have a hook attached to them which is called when the last reference to the allocation is released.
+ * No reference count manipulation is allowed on the provided handle, just property querying (ID get, size get, phys block get).
+ * This is similar to finalizers in OO languages.
+ *
+ * The arguments provided to the hook are;
+ * * handle to the allocation
+ * * the callback_data set when registering the hook
+ */
+typedef void (*ump_dd_final_release_callback)(const ump_dd_handle, void *);
+
+/**
+ * Allocate a buffer.
+ * The lifetime of the allocation is controlled by a reference count.
+ * The reference count of the returned buffer is set to 1.
+ * The memory will be freed once the reference count reaches 0.
+ * Use @ref ump_dd_retain and @ref ump_dd_release to control the reference count.
+ * @param size Number of bytes to allocate. Will be padded up to a multiple of the page size.
+ * @param flags Bit-wise OR of zero or more of the allocation flag bits.
+ * @param[in] filter_func Pointer to a function which will be called when an allocation is required from a
+ * secure id before the allocation itself is returned to user-space.
+ * NULL permitted if no need for a callback.
+ * @param[in] final_release_func Pointer to a function which will be called when the last reference is removed,
+ * just before the allocation is freed. NULL permitted if no need for a callback.
+ * @param[in] callback_data An opaque pointer which will be provided to @a filter_func and @a final_release_func
+ * @return Handle to the new allocation, or @a UMP_DD_INVALID_MEMORY_HANDLE on allocation failure.
+ */
+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_allocate_64(uint64_t size, ump_alloc_flags flags, ump_dd_security_filter filter_func, ump_dd_final_release_callback final_release_func, void* callback_data);
+
+
+/**
+ * Allocation bits getter.
+ * Retrieves the allocation flags used when instantiating the given handle.
+ * Just a copy of the flag given to @ref ump_dd_allocate_64 and @ref ump_dd_create_from_phys_blocks_64
+ * @param mem The handle retrieve the bits for
+ * @return The allocation bits used to instantiate the allocation
+ */
+UMP_KERNEL_API_EXPORT ump_alloc_flags ump_dd_allocation_flags_get(const ump_dd_handle mem);
+
+
+/**
+ * Retrieves the secure ID for the specified UMP memory.
+ *
+ * This identifier is unique across the entire system, and uniquely identifies
+ * the specified UMP memory allocation. This identifier can later be used through the
+ * @ref ump_dd_from_secure_id or
+ * @ref ump_from_secure_id
+ * functions in order to access this UMP memory, for instance from another process (if shared of course).
+ * Unless the allocation was marked as shared the returned ID will only be resolvable in the same process as did the allocation.
+ *
+ * Calling on an @a UMP_DD_INVALID_MEMORY_HANDLE will result in undefined behavior.
+ * Debug builds will assert on this.
+ *
+ * @note There is a user space equivalent function called @ref ump_secure_id_get
+ *
+ * @see ump_dd_from_secure_id
+ * @see ump_from_secure_id
+ * @see ump_secure_id_get
+ *
+ * @param mem Handle to UMP memory.
+ *
+ * @return Returns the secure ID for the specified UMP memory.
+ */
+UMP_KERNEL_API_EXPORT ump_secure_id ump_dd_secure_id_get(const ump_dd_handle mem);
+
+#ifdef CONFIG_KDS
+/**
+ * Retrieve the KDS resource for the specified UMP memory.
+ *
+ * The KDS resource should be used to synchronize access to the UMP allocation.
+ * See the KDS API for how to do that.
+ *
+ * @param mem Handle to the UMP memory to query.
+ * @return Pointer to the KDS resource controlling access to the UMP memory.
+ */
+UMP_KERNEL_API_EXPORT struct kds_resource * ump_dd_kds_resource_get(const ump_dd_handle mem);
+#endif
+
+/**
+ * Retrieves a handle to allocated UMP memory.
+ *
+ * The usage of UMP memory is reference counted, so this will increment the reference
+ * count by one for the specified UMP memory.
+ * Use @ref ump_dd_release when there is no longer any
+ * use for the retrieved handle.
+ *
+ * If called on an non-shared allocation and this is a different process @a UMP_DD_INVALID_MEMORY_HANDLE will be returned.
+ *
+ * Calling on an @a UMP_INVALID_SECURE_ID will return @a UMP_DD_INVALID_MEMORY_HANDLE
+ *
+ * @note There is a user space equivalent function called @ref ump_from_secure_id
+ *
+ * @see ump_dd_release
+ * @see ump_from_secure_id
+ *
+ * @param secure_id The secure ID of the UMP memory to open, that can be retrieved using the @ref ump_secure_id_get function.
+ *
+ * @return @a UMP_DD_INVALID_MEMORY_HANDLE indicates failure, otherwise a valid handle is returned.
+ */
+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_from_secure_id(ump_secure_id secure_id);
+
+
+/**
+ * Retrieves all physical memory block information for specified UMP memory.
+ *
+ * This function can be used by other device drivers in order to create MMU tables.
+ * This function will return a pointer to an array of @ref ump_dd_physical_block_64 in @a pArray and the number of array elements in @a pCount
+ *
+ * Calling on an @a UMP_DD_INVALID_MEMORY_HANDLE results in undefined behavior.
+ * Debug builds will assert on this.
+ *
+ * @param mem Handle to UMP memory.
+ * @param[out] pCount Pointer to where to store the number of items in the returned array
+ * @param[out] pArray Pointer to where to store a pointer to the physical blocks array
+ */
+UMP_KERNEL_API_EXPORT void ump_dd_phys_blocks_get_64(const ump_dd_handle mem, uint64_t * const pCount, const ump_dd_physical_block_64 ** const pArray);
+
+/**
+ * Retrieves the actual size of the specified UMP memory.
+ *
+ * The size is reported in bytes, and is typically page aligned.
+ *
+ * Calling on an @a UMP_DD_INVALID_MEMORY_HANDLE results in undefined behavior.
+ * Debug builds will assert on this.
+ *
+ * @note There is a user space equivalent function called @ref ump_size_get
+ *
+ * @see ump_size_get
+ *
+ * @param mem Handle to UMP memory.
+ *
+ * @return Returns the allocated size of the specified UMP memory, in bytes.
+ */
+UMP_KERNEL_API_EXPORT uint64_t ump_dd_size_get_64(const ump_dd_handle mem);
+
+
+/**
+ * Adds an extra reference to the specified UMP memory allocation.
+ *
+ * The function @ref ump_dd_release must then be used
+ * to release each copy of the UMP memory handle.
+ *
+ * Calling on an @a UMP_DD_INVALID_MEMORY_HANDLE results in undefined behavior.
+ * Debug builds will assert on this.
+ *
+ * @note You are not required to call @ref ump_dd_retain
+ * for UMP handles returned from
+ * @ref ump_dd_from_secure_id,
+ * because these handles are already reference counted by this function.
+ *
+ * @note There is a user space equivalent function called @ref ump_retain
+ *
+ * @see ump_retain
+ *
+ * @param mem Handle to UMP memory.
+ * @return 0 indicates success, any other value indicates failure.
+ */
+UMP_KERNEL_API_EXPORT int ump_dd_retain(ump_dd_handle mem);
+
+
+/**
+ * Releases a reference from the specified UMP memory.
+ *
+ * This function must be called once for every reference to the UMP memory handle.
+ * When the last reference is released, all resources associated with this UMP memory
+ * handle are freed.
+ *
+ * One can only call ump_release when matched with a successful ump_dd_retain, ump_dd_allocate_64 or ump_dd_from_secure_id
+ * If called on an @a UMP_DD_INVALID_MEMORY_HANDLE the function will early out.
+ *
+ * @note There is a user space equivalent function called @ref ump_release
+ *
+ * @see ump_release
+ *
+ * @param mem Handle to UMP memory.
+ */
+UMP_KERNEL_API_EXPORT void ump_dd_release(ump_dd_handle mem);
+
+/**
+ * Create an ump allocation handle based on externally managed memory.
+ * Used to wrap an existing allocation as an UMP memory handle.
+ * Once wrapped the memory acts just like a normal allocation coming from @ref ump_dd_allocate_64.
+ * The only exception is that the freed physical memory is not put into the pool of free memory, but instead considered returned to the caller once @a final_release_func returns.
+ * The blocks array will be copied, so no need to hold on to it after this function returns.
+ * @param[in] blocks Array of @ref ump_dd_physical_block_64
+ * @param num_blocks Number of elements in the array pointed to by @a blocks
+ * @param flags Allocation flags to mark the handle with
+ * @param[in] filter_func Pointer to a function which will be called when an allocation is required from a secure id before the allocation itself is returned to user-space.
+ * NULL permitted if no need for a callback.
+ * @param[in] final_release_func Pointer to a function which will be called when the last reference is removed, just before the allocation is freed. NULL permitted if no need for a callback.
+ * @param[in] callback_data An opaque pointer which will be provided to @a filter_func and @a final_release_func
+ * @return Handle to the UMP allocation handle created, or @a UMP_DD_INVALID_MEMORY_HANDLE if no such handle could be created.
+ */
+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_create_from_phys_blocks_64(const ump_dd_physical_block_64 * blocks, uint64_t num_blocks, ump_alloc_flags flags, ump_dd_security_filter filter_func, ump_dd_final_release_callback final_release_func, void* callback_data);
+
+
+/** @name UMP v1 API
+ * Functions provided to support compatibility with UMP v1 API
+ *
+ *@{
+ */
+
+/**
+ * Value to indicate an invalid UMP memory handle.
+ */
+#define UMP_DD_HANDLE_INVALID UMP_DD_INVALID_MEMORY_HANDLE
+
+/**
+ * UMP error codes for kernel space.
+ */
+typedef enum
+{
+ UMP_DD_SUCCESS, /**< indicates success */
+ UMP_DD_INVALID /**< indicates failure */
+} ump_dd_status_code;
+
+
+/**
+ * Struct used to describe a physical block used by UMP memory
+ */
+typedef struct ump_dd_physical_block
+{
+ unsigned long addr; /**< The physical address of the block */
+ unsigned long size; /**< The length of the block, typically page aligned */
+} ump_dd_physical_block;
+
+
+/**
+ * Retrieves a handle to allocated UMP memory.
+ *
+ * The usage of UMP memory is reference counted, so this will increment the reference
+ * count by one for the specified UMP memory.
+ * Use @ref ump_dd_reference_release "ump_dd_reference_release" when there is no longer any
+ * use for the retrieved handle.
+ *
+ * @note There is a user space equivalent function called @ref ump_handle_create_from_secure_id "ump_handle_create_from_secure_id"
+ *
+ * @see ump_dd_reference_release
+ * @see ump_handle_create_from_secure_id
+ *
+ * @param secure_id The secure ID of the UMP memory to open, that can be retrieved using the @ref ump_secure_id_get "ump_secure_id_get " function.
+ *
+ * @return UMP_INVALID_MEMORY_HANDLE indicates failure, otherwise a valid handle is returned.
+ */
+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_secure_id(ump_secure_id secure_id);
+
+
+
+/**
+ * Create an ump allocation handle based on externally managed memory.
+ * Used to wrap an existing allocation as an UMP memory handle.
+ *
+ * @param[in] blocks Array of @ref ump_dd_physical_block
+ * @param num_blocks Number of elements in the array pointed to by @a blocks
+ *
+ * @return Handle to the UMP allocation handle created, or @a UMP_DD_INVALID_MEMORY_HANDLE if no such handle could be created.
+ */
+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block * blocks, unsigned long num_blocks);
+
+
+/**
+ * Retrieves the number of physical blocks used by the specified UMP memory.
+ *
+ * This function retrieves the number of @ref ump_dd_physical_block "ump_dd_physical_block" structs needed
+ * to describe the physical memory layout of the given UMP memory. This can later be used when calling
+ * the functions @ref ump_dd_phys_blocks_get "ump_dd_phys_blocks_get" and
+ * @ref ump_dd_phys_block_get "ump_dd_phys_block_get".
+ *
+ * @see ump_dd_phys_blocks_get
+ * @see ump_dd_phys_block_get
+ *
+ * @param mem Handle to UMP memory.
+ *
+ * @return The number of ump_dd_physical_block structs required to describe the physical memory layout of the specified UMP memory.
+ */
+UMP_KERNEL_API_EXPORT unsigned long ump_dd_phys_block_count_get(ump_dd_handle mem);
+
+
+/**
+ * Retrieves all physical memory block information for specified UMP memory.
+ *
+ * This function can be used by other device drivers in order to create MMU tables.
+ *
+ * @note This function will fail if the num_blocks parameter is either to large or to small.
+ *
+ * @see ump_dd_phys_block_get
+ *
+ * @param mem Handle to UMP memory.
+ * @param blocks An array of @ref ump_dd_physical_block "ump_dd_physical_block" structs that will receive the physical description.
+ * @param num_blocks The number of blocks to return in the blocks array. Use the function
+ * @ref ump_dd_phys_block_count_get "ump_dd_phys_block_count_get" first to determine the number of blocks required.
+ *
+ * @return UMP_DD_SUCCESS indicates success, UMP_DD_INVALID indicates failure.
+ */
+UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_phys_blocks_get(ump_dd_handle mem, ump_dd_physical_block * const blocks, unsigned long num_blocks);
+
+
+/**
+ * Retrieves the physical memory block information for specified block for the specified UMP memory.
+ *
+ * This function can be used by other device drivers in order to create MMU tables.
+ *
+ * @note This function will return UMP_DD_INVALID if the specified index is out of range.
+ *
+ * @see ump_dd_phys_blocks_get
+ *
+ * @param mem Handle to UMP memory.
+ * @param index Which physical info block to retrieve.
+ * @param block Pointer to a @ref ump_dd_physical_block "ump_dd_physical_block" struct which will receive the requested information.
+ *
+ * @return UMP_DD_SUCCESS indicates success, UMP_DD_INVALID indicates failure.
+ */
+UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_phys_block_get(ump_dd_handle mem, unsigned long index, ump_dd_physical_block * const block);
+
+
+/**
+ * Retrieves the actual size of the specified UMP memory.
+ *
+ * The size is reported in bytes, and is typically page aligned.
+ *
+ * @note There is a user space equivalent function called @ref ump_size_get "ump_size_get"
+ *
+ * @see ump_size_get
+ *
+ * @param mem Handle to UMP memory.
+ *
+ * @return Returns the allocated size of the specified UMP memory, in bytes.
+ */
+UMP_KERNEL_API_EXPORT unsigned long ump_dd_size_get(ump_dd_handle mem);
+
+
+/**
+ * Adds an extra reference to the specified UMP memory.
+ *
+ * This function adds an extra reference to the specified UMP memory. This function should
+ * be used every time a UMP memory handle is duplicated, that is, assigned to another ump_dd_handle
+ * variable. The function @ref ump_dd_reference_release "ump_dd_reference_release" must then be used
+ * to release each copy of the UMP memory handle.
+ *
+ * @note You are not required to call @ref ump_dd_reference_add "ump_dd_reference_add"
+ * for UMP handles returned from
+ * @ref ump_dd_handle_create_from_secure_id "ump_dd_handle_create_from_secure_id",
+ * because these handles are already reference counted by this function.
+ *
+ * @note There is a user space equivalent function called @ref ump_reference_add "ump_reference_add"
+ *
+ * @see ump_reference_add
+ *
+ * @param mem Handle to UMP memory.
+ */
+UMP_KERNEL_API_EXPORT void ump_dd_reference_add(ump_dd_handle mem);
+
+
+/**
+ * Releases a reference from the specified UMP memory.
+ *
+ * This function should be called once for every reference to the UMP memory handle.
+ * When the last reference is released, all resources associated with this UMP memory
+ * handle are freed.
+ *
+ * @note There is a user space equivalent function called @ref ump_reference_release "ump_reference_release"
+ *
+ * @see ump_reference_release
+ *
+ * @param mem Handle to UMP memory.
+ */
+UMP_KERNEL_API_EXPORT void ump_dd_reference_release(ump_dd_handle mem);
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/** @} */ /* end group ump_kernel_space_api */
+
+/** @} */ /* end group ump_api */
+
+#endif /* _UMP_KERNEL_INTERFACE_H_ */