summaryrefslogtreecommitdiff
path: root/sgx/services4/srvkm/env/linux
diff options
context:
space:
mode:
authorRicardo Salveti de Araujo <ricardo.salveti@linaro.org>2012-07-18 00:30:31 -0300
committerRicardo Salveti de Araujo <ricardo.salveti@linaro.org>2012-07-18 00:30:31 -0300
commit0f9b9d9e1f16d454b12921d3429eced6dc1095d4 (patch)
tree21eaffbd85393a9e53889bbd868a255c7f6c24fc /sgx/services4/srvkm/env/linux
parent50fa520ba5f68fa76173493c44715d4542007120 (diff)
Imported Upstream version 1.9.0.4.1.1 (ARMHF)upstream/1.9.0.4.1.1
Signed-off-by: Ricardo Salveti de Araujo <ricardo.salveti@linaro.org>
Diffstat (limited to 'sgx/services4/srvkm/env/linux')
-rw-r--r--[-rwxr-xr-x]sgx/services4/srvkm/env/linux/Kbuild.mk84
-rw-r--r--[-rwxr-xr-x]sgx/services4/srvkm/env/linux/Linux.mk54
-rw-r--r--sgx/services4/srvkm/env/linux/env_data.h80
-rw-r--r--sgx/services4/srvkm/env/linux/env_perproc.h76
-rw-r--r--sgx/services4/srvkm/env/linux/event.c180
-rw-r--r--sgx/services4/srvkm/env/linux/event.h67
-rw-r--r--sgx/services4/srvkm/env/linux/linkage.h77
-rw-r--r--sgx/services4/srvkm/env/linux/lock.h77
-rw-r--r--sgx/services4/srvkm/env/linux/mm.c1706
-rw-r--r--sgx/services4/srvkm/env/linux/mm.h485
-rw-r--r--sgx/services4/srvkm/env/linux/mmap.c1082
-rw-r--r--sgx/services4/srvkm/env/linux/mmap.h197
-rw-r--r--sgx/services4/srvkm/env/linux/module.c577
-rw-r--r--sgx/services4/srvkm/env/linux/mutex.c74
-rw-r--r--sgx/services4/srvkm/env/linux/mutex.h77
-rw-r--r--sgx/services4/srvkm/env/linux/mutils.c99
-rw-r--r--sgx/services4/srvkm/env/linux/mutils.h69
-rw-r--r--sgx/services4/srvkm/env/linux/osfunc.c1988
-rw-r--r--sgx/services4/srvkm/env/linux/osperproc.c96
-rw-r--r--sgx/services4/srvkm/env/linux/pdump.c279
-rw-r--r--sgx/services4/srvkm/env/linux/private_data.h93
-rw-r--r--sgx/services4/srvkm/env/linux/proc.c644
-rw-r--r--sgx/services4/srvkm/env/linux/proc.h76
-rw-r--r--sgx/services4/srvkm/env/linux/pvr_bridge_k.c155
-rw-r--r--sgx/services4/srvkm/env/linux/pvr_debug.c193
-rw-r--r--sgx/services4/srvkm/env/linux/pvr_drm.c116
-rw-r--r--sgx/services4/srvkm/env/linux/pvr_drm.h70
-rw-r--r--sgx/services4/srvkm/env/linux/pvr_uaccess.h72
28 files changed, 6801 insertions, 2042 deletions
diff --git a/sgx/services4/srvkm/env/linux/Kbuild.mk b/sgx/services4/srvkm/env/linux/Kbuild.mk
index 95df225..b101a5f 100755..100644
--- a/sgx/services4/srvkm/env/linux/Kbuild.mk
+++ b/sgx/services4/srvkm/env/linux/Kbuild.mk
@@ -1,26 +1,43 @@
-#
-# Copyright (C) Imagination Technologies Ltd. All rights reserved.
+########################################################################### ###
+#@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+#@License Dual MIT/GPLv2
#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms and conditions of the GNU General Public License,
-# version 2, as published by the Free Software Foundation.
+# The contents of this file are subject to the MIT license as set out below.
#
-# This program is distributed in the hope it will be useful but, except
-# as otherwise stated in writing, without any warranty; without even the
-# implied warranty of merchantability or fitness for a particular purpose.
-# See the GNU General Public License for more details.
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
#
-# The full GNU General Public License is included in this distribution in
-# the file called "COPYING".
-#
-# Contact Information:
-# Imagination Technologies Ltd. <gpl-support@imgtec.com>
-# Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
+# Alternatively, the contents of this file may be used under the terms of
+# the GNU General Public License Version 2 ("GPL") in which case the provisions
+# of GPL are applicable instead of those above.
#
+# If you wish to allow use of your version of this file only under the terms of
+# GPL, and not to allow others to use your version of this file under the terms
+# of the MIT license, indicate your decision by deleting the provisions above
+# and replace them with the notice and other provisions required by GPL as set
+# out in the file called "GPL-COPYING" included in this distribution. If you do
+# not delete the provisions above, a recipient may use your version of this file
+# under the terms of either the MIT license or GPL.
+#
+# This License is also included in this distribution in the file called
+# "MIT-COPYING".
+#
+# EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+# PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+### ###########################################################################
$(PVRSRV_MODNAME)-y += \
services4/srvkm/env/linux/osfunc.o \
@@ -40,22 +57,36 @@ $(PVRSRV_MODNAME)-y += \
services4/srvkm/common/deviceclass.o \
services4/srvkm/common/handle.o \
services4/srvkm/common/hash.o \
+ services4/srvkm/common/lists.o \
+ services4/srvkm/common/mem.o \
+ services4/srvkm/common/mem_debug.o \
services4/srvkm/common/metrics.o \
+ services4/srvkm/common/osfunc_common.o \
+ services4/srvkm/common/pdump_common.o \
+ services4/srvkm/common/perproc.o \
+ services4/srvkm/common/power.o \
services4/srvkm/common/pvrsrv.o \
services4/srvkm/common/queue.o \
services4/srvkm/common/ra.o \
+ services4/srvkm/common/refcount.o \
services4/srvkm/common/resman.o \
- services4/srvkm/common/power.o \
- services4/srvkm/common/mem.o \
- services4/srvkm/common/pdump_common.o \
services4/srvkm/bridged/bridged_support.o \
services4/srvkm/bridged/bridged_pvr_bridge.o \
- services4/srvkm/common/perproc.o \
services4/system/$(PVR_SYSTEM)/sysconfig.o \
- services4/system/$(PVR_SYSTEM)/sysutils.o \
- services4/srvkm/common/lists.o \
- services4/srvkm/common/mem_debug.o \
- services4/srvkm/common/osfunc_common.o
+ services4/system/$(PVR_SYSTEM)/sysutils.o
+
+$(PVRSRV_MODNAME)-$(CONFIG_ION_OMAP) += \
+ services4/srvkm/env/linux/ion.o
+
+ifeq ($(SUPPORT_ION),1)
+$(PVRSRV_MODNAME)-y += \
+ services4/srvkm/env/linux/ion.o
+endif
+
+ifeq ($(TTRACE),1)
+$(PVRSRV_MODNAME)-y += \
+ services4/srvkm/common/ttrace.o
+endif
ifneq ($(W),1)
CFLAGS_osfunc.o := -Werror
@@ -89,6 +120,7 @@ CFLAGS_perproc.o := -Werror
CFLAGS_lists.o := -Werror
CFLAGS_mem_debug.o := -Werror
CFLAGS_osfunc_common.o := -Werror
+CFLAGS_refcount.o := -Werror
endif
# SUPPORT_SGX==1 only
diff --git a/sgx/services4/srvkm/env/linux/Linux.mk b/sgx/services4/srvkm/env/linux/Linux.mk
index 0ea43aa..b5e9de4 100755..100644
--- a/sgx/services4/srvkm/env/linux/Linux.mk
+++ b/sgx/services4/srvkm/env/linux/Linux.mk
@@ -1,27 +1,43 @@
-#
-# Copyright (C) Imagination Technologies Ltd. All rights reserved.
+########################################################################### ###
+#@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+#@License Dual MIT/GPLv2
#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms and conditions of the GNU General Public License,
-# version 2, as published by the Free Software Foundation.
+# The contents of this file are subject to the MIT license as set out below.
#
-# This program is distributed in the hope it will be useful but, except
-# as otherwise stated in writing, without any warranty; without even the
-# implied warranty of merchantability or fitness for a particular purpose.
-# See the GNU General Public License for more details.
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
#
-# The full GNU General Public License is included in this distribution in
-# the file called "COPYING".
-#
-# Contact Information:
-# Imagination Technologies Ltd. <gpl-support@imgtec.com>
-# Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
+# Alternatively, the contents of this file may be used under the terms of
+# the GNU General Public License Version 2 ("GPL") in which case the provisions
+# of GPL are applicable instead of those above.
#
-#
+# If you wish to allow use of your version of this file only under the terms of
+# GPL, and not to allow others to use your version of this file under the terms
+# of the MIT license, indicate your decision by deleting the provisions above
+# and replace them with the notice and other provisions required by GPL as set
+# out in the file called "GPL-COPYING" included in this distribution. If you do
+# not delete the provisions above, a recipient may use your version of this file
+# under the terms of either the MIT license or GPL.
+#
+# This License is also included in this distribution in the file called
+# "MIT-COPYING".
+#
+# EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+# PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+### ###########################################################################
modules := srvkm
diff --git a/sgx/services4/srvkm/env/linux/env_data.h b/sgx/services4/srvkm/env/linux/env_data.h
index 7716529..4a2b9b1 100644
--- a/sgx/services4/srvkm/env/linux/env_data.h
+++ b/sgx/services4/srvkm/env/linux/env_data.h
@@ -1,29 +1,45 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Environmental Data header file
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description Linux-specific part of system data.
+@License Dual MIT/GPLv2
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#ifndef _ENV_DATA_
#define _ENV_DATA_
@@ -34,6 +50,11 @@
#include <linux/workqueue.h>
#endif
+/*
+ * Env data specific to linux - convenient place to put this
+ */
+
+/* Fairly arbitrary sizes - hopefully enough for all bridge calls */
#define PVRSRV_MAX_BRIDGE_IN_SIZE 0x1000
#define PVRSRV_MAX_BRIDGE_OUT_SIZE 0x1000
@@ -61,6 +82,13 @@ typedef struct _ENV_DATA_TAG
#else
struct tasklet_struct sMISRTasklet;
#endif
+#if defined (SUPPORT_ION)
+ IMG_HANDLE hIonHeaps;
+ IMG_HANDLE hIonDev;
+#endif
} ENV_DATA;
-#endif
+#endif /* _ENV_DATA_ */
+/*****************************************************************************
+ End of file (env_data.h)
+*****************************************************************************/
diff --git a/sgx/services4/srvkm/env/linux/env_perproc.h b/sgx/services4/srvkm/env/linux/env_perproc.h
index 58e2c38..f434226 100644
--- a/sgx/services4/srvkm/env/linux/env_perproc.h
+++ b/sgx/services4/srvkm/env/linux/env_perproc.h
@@ -1,29 +1,45 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title OS specific per process data interface
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description Linux per process data
+@License Dual MIT/GPLv2
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#ifndef __ENV_PERPROC_H__
#define __ENV_PERPROC_H__
@@ -33,6 +49,7 @@
#include "services.h"
#include "handle.h"
+#define ION_CLIENT_NAME_SIZE 50
typedef struct _PVRSRV_ENV_PER_PROCESS_DATA_
{
IMG_HANDLE hBlockAlloc;
@@ -47,6 +64,10 @@ typedef struct _PVRSRV_ENV_PER_PROCESS_DATA_
struct drm_device *dev;
#endif /* SUPPORT_DRI_DRM_EXTERNAL */
#endif
+#if defined (SUPPORT_ION)
+ struct ion_client *psIONClient;
+ IMG_CHAR azIonClientName[ION_CLIENT_NAME_SIZE];
+#endif
} PVRSRV_ENV_PER_PROCESS_DATA;
IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc);
@@ -59,5 +80,8 @@ PVRSRV_ERROR LinuxMMapPerProcessHandleOptions(PVRSRV_HANDLE_BASE *psHandleBase);
IMG_HANDLE LinuxTerminatingProcessPrivateData(IMG_VOID);
-#endif
+#endif /* __ENV_PERPROC_H__ */
+/******************************************************************************
+ End of file (env_perproc.h)
+******************************************************************************/
diff --git a/sgx/services4/srvkm/env/linux/event.c b/sgx/services4/srvkm/env/linux/event.c
index 7e160c3..1946e61 100644
--- a/sgx/services4/srvkm/env/linux/event.c
+++ b/sgx/services4/srvkm/env/linux/event.c
@@ -1,28 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Event Object
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include <linux/version.h>
@@ -85,6 +101,20 @@ typedef struct PVRSRV_LINUX_EVENT_OBJECT_TAG
PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList;
} PVRSRV_LINUX_EVENT_OBJECT;
+/*!
+******************************************************************************
+
+ @Function LinuxEventObjectListCreate
+
+ @Description
+
+ Linux wait object list creation
+
+ @Output hOSEventKM : Pointer to the event object list handle
+
+ @Return PVRSRV_ERROR : Error code
+
+******************************************************************************/
PVRSRV_ERROR LinuxEventObjectListCreate(IMG_HANDLE *phEventObjectList)
{
PVRSRV_LINUX_EVENT_OBJECT_LIST *psEventObjectList;
@@ -106,6 +136,20 @@ PVRSRV_ERROR LinuxEventObjectListCreate(IMG_HANDLE *phEventObjectList)
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function LinuxEventObjectListDestroy
+
+ @Description
+
+ Linux wait object list destruction
+
+ @Input hOSEventKM : Event object list handle
+
+ @Return PVRSRV_ERROR : Error code
+
+******************************************************************************/
PVRSRV_ERROR LinuxEventObjectListDestroy(IMG_HANDLE hEventObjectList)
{
@@ -126,13 +170,29 @@ PVRSRV_ERROR LinuxEventObjectListDestroy(IMG_HANDLE hEventObjectList)
}
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT_LIST), psEventObjectList, IMG_NULL);
-
+ /*not nulling pointer, copy on stack*/
}
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function LinuxEventObjectDelete
+
+ @Description
+
+ Linux wait object removal
+
+ @Input hOSEventObjectList : Event object list handle
+ @Input hOSEventObject : Event object handle
+ @Input bResManCallback : Called from the resman
+
+ @Return PVRSRV_ERROR : Error code
+
+******************************************************************************/
PVRSRV_ERROR LinuxEventObjectDelete(IMG_HANDLE hOSEventObjectList, IMG_HANDLE hOSEventObject)
{
if(hOSEventObjectList)
@@ -155,6 +215,20 @@ PVRSRV_ERROR LinuxEventObjectDelete(IMG_HANDLE hOSEventObjectList, IMG_HANDLE hO
}
+/*!
+******************************************************************************
+
+ @Function LinuxEventObjectDeleteCallback
+
+ @Description
+
+ Linux wait object removal
+
+ @Input hOSEventObject : Event object handle
+
+ @Return PVRSRV_ERROR : Error code
+
+******************************************************************************/
static PVRSRV_ERROR LinuxEventObjectDeleteCallback(IMG_PVOID pvParam, IMG_UINT32 ui32Param, IMG_BOOL bForceCleanup)
{
PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = pvParam;
@@ -173,10 +247,25 @@ static PVRSRV_ERROR LinuxEventObjectDeleteCallback(IMG_PVOID pvParam, IMG_UINT32
#endif
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT), psLinuxEventObject, IMG_NULL);
-
+ /*not nulling pointer, copy on stack*/
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function LinuxEventObjectAdd
+
+ @Description
+
+ Linux wait object addition
+
+ @Input hOSEventObjectList : Event object list handle
+ @Output phOSEventObject : Pointer to the event object handle
+
+ @Return PVRSRV_ERROR : Error code
+
+******************************************************************************/
PVRSRV_ERROR LinuxEventObjectAdd(IMG_HANDLE hOSEventObjectList, IMG_HANDLE *phOSEventObject)
{
PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
@@ -192,7 +281,7 @@ PVRSRV_ERROR LinuxEventObjectAdd(IMG_HANDLE hOSEventObjectList, IMG_HANDLE *phOS
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
-
+ /* allocate completion variable */
if(OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT),
(IMG_VOID **)&psLinuxEventObject, IMG_NULL,
"Linux Event Object") != PVRSRV_OK)
@@ -228,6 +317,20 @@ PVRSRV_ERROR LinuxEventObjectAdd(IMG_HANDLE hOSEventObjectList, IMG_HANDLE *phOS
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function LinuxEventObjectSignal
+
+ @Description
+
+ Linux wait object signaling function
+
+ @Input hOSEventObjectList : Event object list handle
+
+ @Return PVRSRV_ERROR : Error code
+
+******************************************************************************/
PVRSRV_ERROR LinuxEventObjectSignal(IMG_HANDLE hOSEventObjectList)
{
PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
@@ -236,7 +339,10 @@ PVRSRV_ERROR LinuxEventObjectSignal(IMG_HANDLE hOSEventObjectList)
psList = &psLinuxEventObjectList->sList;
-
+ /*
+ * We don't take the write lock in interrupt context, so we don't
+ * need to use read_lock_irqsave.
+ */
read_lock(&psLinuxEventObjectList->sLock);
list_for_each(psListEntry, psList)
{
@@ -252,6 +358,22 @@ PVRSRV_ERROR LinuxEventObjectSignal(IMG_HANDLE hOSEventObjectList)
}
+/*!
+******************************************************************************
+
+ @Function LinuxEventObjectWait
+
+ @Description
+
+ Linux wait object routine
+
+ @Input hOSEventObject : Event object handle
+
+ @Input ui32MSTimeout : Time out value in msec
+
+ @Return PVRSRV_ERROR : Error code
+
+******************************************************************************/
PVRSRV_ERROR LinuxEventObjectWait(IMG_HANDLE hOSEventObject, IMG_UINT32 ui32MSTimeout)
{
IMG_UINT32 ui32TimeStamp;
diff --git a/sgx/services4/srvkm/env/linux/event.h b/sgx/services4/srvkm/env/linux/event.h
index 3035283..88adb27 100644
--- a/sgx/services4/srvkm/env/linux/event.h
+++ b/sgx/services4/srvkm/env/linux/event.h
@@ -1,28 +1,45 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Event Object
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
+
PVRSRV_ERROR LinuxEventObjectListCreate(IMG_HANDLE *phEventObjectList);
PVRSRV_ERROR LinuxEventObjectListDestroy(IMG_HANDLE hEventObjectList);
diff --git a/sgx/services4/srvkm/env/linux/linkage.h b/sgx/services4/srvkm/env/linux/linkage.h
index e64012c..94aae0b 100644
--- a/sgx/services4/srvkm/env/linux/linkage.h
+++ b/sgx/services4/srvkm/env/linux/linkage.h
@@ -1,29 +1,47 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Linux specific Services code internal interfaces
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description Interfaces between various parts of the Linux specific
+ Services code, that don't have any other obvious
+ header file to go into.
+@License Dual MIT/GPLv2
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#ifndef __LINKAGE_H__
#define __LINKAGE_H__
@@ -45,8 +63,11 @@ IMG_INT PVRProcSetPowerLevel(struct file *file, const IMG_CHAR *buffer, IMG_UINT
void ProcSeqShowPowerLevel(struct seq_file *sfile,void* el);
-#endif
+#endif /* PVR_MANUAL_POWER_CONTROL */
-#endif
+#endif /* DEBUG */
-#endif
+#endif /* __LINKAGE_H__ */
+/*****************************************************************************
+ End of file (linkage.h)
+*****************************************************************************/
diff --git a/sgx/services4/srvkm/env/linux/lock.h b/sgx/services4/srvkm/env/linux/lock.h
index a0854c3..d6d5b50 100644
--- a/sgx/services4/srvkm/env/linux/lock.h
+++ b/sgx/services4/srvkm/env/linux/lock.h
@@ -1,32 +1,57 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Main driver lock
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description The main driver lock, held in most places in
+ the driver.
+@License Dual MIT/GPLv2
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#ifndef __LOCK_H__
#define __LOCK_H__
+/*
+ * Main driver lock, used to ensure driver code is single threaded.
+ * There are some places where this lock must not be taken, such as
+ * in the mmap related deriver entry points.
+ */
extern PVRSRV_LINUX_MUTEX gPVRSRVLock;
-#endif
+#endif /* __LOCK_H__ */
+/*****************************************************************************
+ End of file (lock.h)
+*****************************************************************************/
diff --git a/sgx/services4/srvkm/env/linux/mm.c b/sgx/services4/srvkm/env/linux/mm.c
index 3edbc49..dc2b471 100644
--- a/sgx/services4/srvkm/env/linux/mm.c
+++ b/sgx/services4/srvkm/env/linux/mm.c
@@ -1,28 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Misc memory management utility functions for Linux
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include <linux/version.h>
@@ -32,6 +48,14 @@
#endif
#endif
+#if !defined(PVR_LINUX_MEM_AREA_POOL_MAX_PAGES)
+#define PVR_LINUX_MEM_AREA_POOL_MAX_PAGES 0
+#endif
+
+#include <linux/kernel.h>
+#include <asm/atomic.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <asm/io.h>
@@ -42,6 +66,12 @@
#include <linux/highmem.h>
#include <linux/sched.h>
+#if defined(PVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0))
+#include <linux/shrinker.h>
+#endif
+#endif
+
#include "img_defs.h"
#include "services.h"
#include "servicesint.h"
@@ -60,6 +90,13 @@
#include "lists.h"
#endif
+/*
+ * The page pool entry count is an atomic int so that the shrinker function
+ * can return it even when we can't take the lock that protects the page pool
+ * list.
+ */
+static atomic_t g_sPagePoolEntryCount = ATOMIC_INIT(0);
+
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
typedef enum {
DEBUG_MEM_ALLOC_TYPE_KMALLOC,
@@ -68,13 +105,17 @@ typedef enum {
DEBUG_MEM_ALLOC_TYPE_IOREMAP,
DEBUG_MEM_ALLOC_TYPE_IO,
DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE,
+ DEBUG_MEM_ALLOC_TYPE_ION,
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ DEBUG_MEM_ALLOC_TYPE_VMAP,
+#endif
DEBUG_MEM_ALLOC_TYPE_COUNT
-}DEBUG_MEM_ALLOC_TYPE;
+} DEBUG_MEM_ALLOC_TYPE;
typedef struct _DEBUG_MEM_ALLOC_REC
{
DEBUG_MEM_ALLOC_TYPE eAllocType;
- IMG_VOID *pvKey;
+ IMG_VOID *pvKey; /* Some unique value (private to the eAllocType) */
IMG_VOID *pvCpuVAddr;
IMG_UINT32 ulCpuPAddr;
IMG_VOID *pvPrivateData;
@@ -85,7 +126,7 @@ typedef struct _DEBUG_MEM_ALLOC_REC
struct _DEBUG_MEM_ALLOC_REC *psNext;
struct _DEBUG_MEM_ALLOC_REC **ppsThis;
-}DEBUG_MEM_ALLOC_REC;
+} DEBUG_MEM_ALLOC_REC;
static IMPLEMENT_LIST_ANY_VA_2(DEBUG_MEM_ALLOC_REC, IMG_BOOL, IMG_FALSE)
static IMPLEMENT_LIST_ANY_VA(DEBUG_MEM_ALLOC_REC)
@@ -99,9 +140,17 @@ static DEBUG_MEM_ALLOC_REC *g_MemoryRecords;
static IMG_UINT32 g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_COUNT];
static IMG_UINT32 g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_COUNT];
-static IMG_UINT32 g_SysRAMWaterMark;
-static IMG_UINT32 g_SysRAMHighWaterMark;
+/* vmalloc + kmalloc + alloc_pages + kmem_cache */
+static IMG_UINT32 g_SysRAMWaterMark; /* Doesn't include page pool */
+static IMG_UINT32 g_SysRAMHighWaterMark; /* *DOES* include page pool */
+static inline IMG_UINT32
+SysRAMTrueWaterMark(void)
+{
+ return g_SysRAMWaterMark + PAGES_TO_BYTES(atomic_read(&g_sPagePoolEntryCount));
+}
+
+/* ioremap + io */
static IMG_UINT32 g_IOMemWaterMark;
static IMG_UINT32 g_IOMemHighWaterMark;
@@ -119,7 +168,7 @@ static IMG_VOID DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE eAllocType, IMG_V
static IMG_CHAR *DebugMemAllocRecordTypeToString(DEBUG_MEM_ALLOC_TYPE eAllocType);
-static struct proc_dir_entry *g_SeqFileMemoryRecords =0;
+static struct proc_dir_entry *g_SeqFileMemoryRecords;
static void* ProcSeqNextMemoryRecords(struct seq_file *sfile,void* el,loff_t off);
static void ProcSeqShowMemoryRecords(struct seq_file *sfile,void* el);
static void* ProcSeqOff2ElementMemoryRecords(struct seq_file * sfile, loff_t off);
@@ -153,7 +202,7 @@ static IMG_UINT32 g_LinuxMemAreaWaterMark;
static IMG_UINT32 g_LinuxMemAreaHighWaterMark;
-static struct proc_dir_entry *g_SeqFileMemArea=0;
+static struct proc_dir_entry *g_SeqFileMemArea;
static void* ProcSeqNextMemArea(struct seq_file *sfile,void* el,loff_t off);
static void ProcSeqShowMemArea(struct seq_file *sfile,void* el);
@@ -169,8 +218,19 @@ static PVRSRV_LINUX_MUTEX g_sDebugMutex;
static void ProcSeqStartstopDebugMutex(struct seq_file *sfile,IMG_BOOL start);
#endif
-static LinuxKMemCache *psLinuxMemAreaCache;
+typedef struct
+{
+ /* Linkage for page pool LRU list */
+ struct list_head sPagePoolItem;
+
+ struct page *psPage;
+} LinuxPagePoolEntry;
+
+static LinuxKMemCache *g_PsLinuxMemAreaCache;
+static LinuxKMemCache *g_PsLinuxPagePoolCache;
+static LIST_HEAD(g_sPagePoolList);
+static int g_iPagePoolMaxEntries;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
static IMG_VOID ReservePages(IMG_VOID *pvAddress, IMG_UINT32 ui32Length);
@@ -185,165 +245,26 @@ static DEBUG_LINUX_MEM_AREA_REC *DebugLinuxMemAreaRecordFind(LinuxMemArea *psLin
static IMG_VOID DebugLinuxMemAreaRecordRemove(LinuxMemArea *psLinuxMemArea);
#endif
-PVRSRV_ERROR
-LinuxMMInit(IMG_VOID)
-{
-#if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
- LinuxInitMutex(&g_sDebugMutex);
-#endif
-
-#if defined(DEBUG_LINUX_MEM_AREAS)
- {
- g_SeqFileMemArea = CreateProcReadEntrySeq(
- "mem_areas",
- NULL,
- ProcSeqNextMemArea,
- ProcSeqShowMemArea,
- ProcSeqOff2ElementMemArea,
- ProcSeqStartstopDebugMutex
- );
- if(!g_SeqFileMemArea)
- {
- return PVRSRV_ERROR_OUT_OF_MEMORY;
- }
- }
-#endif
-
-
-#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
- {
- g_SeqFileMemoryRecords =CreateProcReadEntrySeq(
- "meminfo",
- NULL,
- ProcSeqNextMemoryRecords,
- ProcSeqShowMemoryRecords,
- ProcSeqOff2ElementMemoryRecords,
- ProcSeqStartstopDebugMutex
- );
- if(!g_SeqFileMemoryRecords)
- {
- return PVRSRV_ERROR_OUT_OF_MEMORY;
- }
- }
-#endif
-
- psLinuxMemAreaCache = KMemCacheCreateWrapper("img-mm", sizeof(LinuxMemArea), 0, 0);
- if(!psLinuxMemAreaCache)
- {
- PVR_DPF((PVR_DBG_ERROR,"%s: failed to allocate kmem_cache", __FUNCTION__));
- return PVRSRV_ERROR_OUT_OF_MEMORY;
- }
-
- return PVRSRV_OK;
-}
-
-#if defined(DEBUG_LINUX_MEM_AREAS)
-static IMG_VOID LinuxMMCleanup_MemAreas_ForEachCb(DEBUG_LINUX_MEM_AREA_REC *psCurrentRecord)
-{
- LinuxMemArea *psLinuxMemArea;
-
- psLinuxMemArea = psCurrentRecord->psLinuxMemArea;
- PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: Cleaning up Linux memory area (%p), type=%s, size=%d bytes",
- __FUNCTION__,
- psCurrentRecord->psLinuxMemArea,
- LinuxMemAreaTypeToString(psCurrentRecord->psLinuxMemArea->eAreaType),
- psCurrentRecord->psLinuxMemArea->ui32ByteSize));
-
- LinuxMemAreaDeepFree(psLinuxMemArea);
-}
-#endif
-
-#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
-static IMG_VOID LinuxMMCleanup_MemRecords_ForEachVa(DEBUG_MEM_ALLOC_REC *psCurrentRecord)
+static inline IMG_BOOL
+AreaIsUncached(IMG_UINT32 ui32AreaFlags)
{
-
- PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: Cleaning up memory: "
- "type=%s "
- "CpuVAddr=%p "
- "CpuPAddr=0x%08x, "
- "allocated @ file=%s,line=%d",
- __FUNCTION__,
- DebugMemAllocRecordTypeToString(psCurrentRecord->eAllocType),
- psCurrentRecord->pvCpuVAddr,
- psCurrentRecord->ulCpuPAddr,
- psCurrentRecord->pszFileName,
- psCurrentRecord->ui32Line));
- switch(psCurrentRecord->eAllocType)
- {
- case DEBUG_MEM_ALLOC_TYPE_KMALLOC:
- KFreeWrapper(psCurrentRecord->pvCpuVAddr);
- break;
- case DEBUG_MEM_ALLOC_TYPE_IOREMAP:
- IOUnmapWrapper(psCurrentRecord->pvCpuVAddr);
- break;
- case DEBUG_MEM_ALLOC_TYPE_IO:
-
- DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_IO, psCurrentRecord->pvKey, __FILE__, __LINE__);
- break;
- case DEBUG_MEM_ALLOC_TYPE_VMALLOC:
- VFreeWrapper(psCurrentRecord->pvCpuVAddr);
- break;
- case DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES:
-
- DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, psCurrentRecord->pvKey, __FILE__, __LINE__);
- break;
- case DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE:
- KMemCacheFreeWrapper(psCurrentRecord->pvPrivateData, psCurrentRecord->pvCpuVAddr);
- break;
- default:
- PVR_ASSERT(0);
- }
+ return (ui32AreaFlags & (PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_UNCACHED)) != 0;
}
-#endif
-
-IMG_VOID
-LinuxMMCleanup(IMG_VOID)
+static inline IMG_BOOL
+CanFreeToPool(LinuxMemArea *psLinuxMemArea)
{
-
-#if defined(DEBUG_LINUX_MEM_AREAS)
- {
- if(g_LinuxMemAreaCount)
- {
- PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: There are %d LinuxMemArea allocation unfreed (%d bytes)",
- __FUNCTION__, g_LinuxMemAreaCount, g_LinuxMemAreaWaterMark));
- }
-
- List_DEBUG_LINUX_MEM_AREA_REC_ForEach(g_LinuxMemAreaRecords,
- LinuxMMCleanup_MemAreas_ForEachCb);
-
- RemoveProcEntrySeq( g_SeqFileMemArea );
- }
-#endif
-
-
-#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
- {
-
-
- List_DEBUG_MEM_ALLOC_REC_ForEach(g_MemoryRecords,
- LinuxMMCleanup_MemRecords_ForEachVa);
-
- RemoveProcEntrySeq( g_SeqFileMemoryRecords );
- }
-#endif
-
- if(psLinuxMemAreaCache)
- {
- KMemCacheDestroyWrapper(psLinuxMemAreaCache);
- psLinuxMemAreaCache=NULL;
- }
+ return AreaIsUncached(psLinuxMemArea->ui32AreaFlags) && !psLinuxMemArea->bNeedsCacheInvalidate;
}
-
IMG_VOID *
_KMallocWrapper(IMG_UINT32 ui32ByteSize, gfp_t uFlags, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line)
{
IMG_VOID *pvRet;
pvRet = kmalloc(ui32ByteSize, uFlags);
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
- if(pvRet)
+ if (pvRet)
{
DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_KMALLOC,
pvRet,
@@ -353,7 +274,7 @@ _KMallocWrapper(IMG_UINT32 ui32ByteSize, gfp_t uFlags, IMG_CHAR *pszFileName, IM
ui32ByteSize,
pszFileName,
ui32Line
- );
+ );
}
#else
PVR_UNREFERENCED_PARAMETER(pszFileName);
@@ -406,27 +327,31 @@ DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE eAllocType,
List_DEBUG_MEM_ALLOC_REC_Insert(&g_MemoryRecords, psRecord);
g_WaterMarkData[eAllocType] += ui32Bytes;
- if(g_WaterMarkData[eAllocType] > g_HighWaterMarkData[eAllocType])
+ if (g_WaterMarkData[eAllocType] > g_HighWaterMarkData[eAllocType])
{
g_HighWaterMarkData[eAllocType] = g_WaterMarkData[eAllocType];
}
- if(eAllocType == DEBUG_MEM_ALLOC_TYPE_KMALLOC
+ if (eAllocType == DEBUG_MEM_ALLOC_TYPE_KMALLOC
|| eAllocType == DEBUG_MEM_ALLOC_TYPE_VMALLOC
|| eAllocType == DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES
|| eAllocType == DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE)
{
+ IMG_UINT32 ui32SysRAMTrueWaterMark;
+
g_SysRAMWaterMark += ui32Bytes;
- if(g_SysRAMWaterMark > g_SysRAMHighWaterMark)
+ ui32SysRAMTrueWaterMark = SysRAMTrueWaterMark();
+
+ if (ui32SysRAMTrueWaterMark > g_SysRAMHighWaterMark)
{
- g_SysRAMHighWaterMark = g_SysRAMWaterMark;
+ g_SysRAMHighWaterMark = ui32SysRAMTrueWaterMark;
}
}
- else if(eAllocType == DEBUG_MEM_ALLOC_TYPE_IOREMAP
+ else if (eAllocType == DEBUG_MEM_ALLOC_TYPE_IOREMAP
|| eAllocType == DEBUG_MEM_ALLOC_TYPE_IO)
{
g_IOMemWaterMark += ui32Bytes;
- if(g_IOMemWaterMark > g_IOMemHighWaterMark)
+ if (g_IOMemWaterMark > g_IOMemHighWaterMark)
{
g_IOMemHighWaterMark = g_IOMemWaterMark;
}
@@ -444,20 +369,20 @@ static IMG_BOOL DebugMemAllocRecordRemove_AnyVaCb(DEBUG_MEM_ALLOC_REC *psCurrent
eAllocType = va_arg(va, DEBUG_MEM_ALLOC_TYPE);
pvKey = va_arg(va, IMG_VOID*);
- if(psCurrentRecord->eAllocType == eAllocType
+ if (psCurrentRecord->eAllocType == eAllocType
&& psCurrentRecord->pvKey == pvKey)
{
eAllocType = psCurrentRecord->eAllocType;
g_WaterMarkData[eAllocType] -= psCurrentRecord->ui32Bytes;
- if(eAllocType == DEBUG_MEM_ALLOC_TYPE_KMALLOC
+ if (eAllocType == DEBUG_MEM_ALLOC_TYPE_KMALLOC
|| eAllocType == DEBUG_MEM_ALLOC_TYPE_VMALLOC
|| eAllocType == DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES
|| eAllocType == DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE)
{
g_SysRAMWaterMark -= psCurrentRecord->ui32Bytes;
}
- else if(eAllocType == DEBUG_MEM_ALLOC_TYPE_IOREMAP
+ else if (eAllocType == DEBUG_MEM_ALLOC_TYPE_IOREMAP
|| eAllocType == DEBUG_MEM_ALLOC_TYPE_IO)
{
g_IOMemWaterMark -= psCurrentRecord->ui32Bytes;
@@ -478,10 +403,12 @@ static IMG_BOOL DebugMemAllocRecordRemove_AnyVaCb(DEBUG_MEM_ALLOC_REC *psCurrent
static IMG_VOID
DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE eAllocType, IMG_VOID *pvKey, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line)
{
+/* DEBUG_MEM_ALLOC_REC **ppsCurrentRecord;*/
+
LinuxLockMutex(&g_sDebugMutex);
-
- if(!List_DEBUG_MEM_ALLOC_REC_IMG_BOOL_Any_va(g_MemoryRecords,
+ /* Locate the corresponding allocation entry */
+ if (!List_DEBUG_MEM_ALLOC_REC_IMG_BOOL_Any_va(g_MemoryRecords,
DebugMemAllocRecordRemove_AnyVaCb,
eAllocType,
pvKey))
@@ -504,27 +431,24 @@ DebugMemAllocRecordTypeToString(DEBUG_MEM_ALLOC_TYPE eAllocType)
"ALLOC_PAGES",
"IOREMAP",
"IO",
- "KMEM_CACHE_ALLOC"
+ "KMEM_CACHE_ALLOC",
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ "VMAP"
+#endif
};
return apszDebugMemoryRecordTypes[eAllocType];
}
#endif
-
-IMG_VOID *
-_VMallocWrapper(IMG_UINT32 ui32Bytes,
- IMG_UINT32 ui32AllocFlags,
- IMG_CHAR *pszFileName,
- IMG_UINT32 ui32Line)
+static IMG_BOOL
+AllocFlagsToPGProt(pgprot_t *pPGProtFlags, IMG_UINT32 ui32AllocFlags)
{
pgprot_t PGProtFlags;
- IMG_VOID *pvRet;
-
- switch(ui32AllocFlags & PVRSRV_HAP_CACHETYPE_MASK)
+
+ switch (ui32AllocFlags & PVRSRV_HAP_CACHETYPE_MASK)
{
case PVRSRV_HAP_CACHED:
- case PVRSRV_HAP_SMART:
PGProtFlags = PAGE_KERNEL;
break;
case PVRSRV_HAP_WRITECOMBINE:
@@ -535,17 +459,36 @@ _VMallocWrapper(IMG_UINT32 ui32Bytes,
break;
default:
PVR_DPF((PVR_DBG_ERROR,
- "VMAllocWrapper: unknown mapping flags=0x%08x",
- ui32AllocFlags));
+ "%s: Unknown mapping flags=0x%08x",
+ __FUNCTION__, ui32AllocFlags));
dump_stack();
+ return IMG_FALSE;
+ }
+
+ *pPGProtFlags = PGProtFlags;
+
+ return IMG_TRUE;
+}
+
+IMG_VOID *
+_VMallocWrapper(IMG_UINT32 ui32Bytes,
+ IMG_UINT32 ui32AllocFlags,
+ IMG_CHAR *pszFileName,
+ IMG_UINT32 ui32Line)
+{
+ pgprot_t PGProtFlags;
+ IMG_VOID *pvRet;
+
+ if (!AllocFlagsToPGProt(&PGProtFlags, ui32AllocFlags))
+ {
return NULL;
}
-
+ /* Allocate virtually contiguous pages */
pvRet = __vmalloc(ui32Bytes, GFP_KERNEL | __GFP_HIGHMEM, PGProtFlags);
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
- if(pvRet)
+ if (pvRet)
{
DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_VMALLOC,
pvRet,
@@ -555,7 +498,7 @@ _VMallocWrapper(IMG_UINT32 ui32Bytes,
PAGE_ALIGN(ui32Bytes),
pszFileName,
ui32Line
- );
+ );
}
#else
PVR_UNREFERENCED_PARAMETER(pszFileName);
@@ -579,31 +522,481 @@ _VFreeWrapper(IMG_VOID *pvCpuVAddr, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line)
}
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+static IMG_VOID *
+_VMapWrapper(struct page **ppsPageList, IMG_UINT32 ui32NumPages, IMG_UINT32 ui32AllocFlags, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line)
+{
+ pgprot_t PGProtFlags;
+ IMG_VOID *pvRet;
+
+ if (!AllocFlagsToPGProt(&PGProtFlags, ui32AllocFlags))
+ {
+ return NULL;
+ }
+
+ pvRet = vmap(ppsPageList, ui32NumPages, GFP_KERNEL | __GFP_HIGHMEM, PGProtFlags);
+
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+ if (pvRet)
+ {
+ DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_VMAP,
+ pvRet,
+ pvRet,
+ 0,
+ NULL,
+ PAGES_TO_BYTES(ui32NumPages),
+ pszFileName,
+ ui32Line
+ );
+ }
+#else
+ PVR_UNREFERENCED_PARAMETER(pszFileName);
+ PVR_UNREFERENCED_PARAMETER(ui32Line);
+#endif
+
+ return pvRet;
+}
+
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+#define VMapWrapper(ppsPageList, ui32Bytes, ui32AllocFlags) _VMapWrapper(ppsPageList, ui32Bytes, ui32AllocFlags, __FILE__, __LINE__)
+#else
+#define VMapWrapper(ppsPageList, ui32Bytes, ui32AllocFlags) _VMapWrapper(ppsPageList, ui32Bytes, ui32AllocFlags, NULL, 0)
+#endif
+
+
+static IMG_VOID
+_VUnmapWrapper(IMG_VOID *pvCpuVAddr, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line)
+{
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+ DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_VMAP, pvCpuVAddr, pszFileName, ui32Line);
+#else
+ PVR_UNREFERENCED_PARAMETER(pszFileName);
+ PVR_UNREFERENCED_PARAMETER(ui32Line);
+#endif
+ vunmap(pvCpuVAddr);
+}
+
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+#define VUnmapWrapper(pvCpuVAddr) _VUnmapWrapper(pvCpuVAddr, __FILE__, __LINE__)
+#else
+#define VUnmapWrapper(pvCpuVAddr) _VUnmapWrapper(pvCpuVAddr, NULL, 0)
+#endif
+
+#endif /* defined(PVR_LINUX_MEM_AREA_USE_VMAP) */
+
+
+IMG_VOID
+_KMemCacheFreeWrapper(LinuxKMemCache *psCache, IMG_VOID *pvObject, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line)
+{
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+ DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE, pvObject, pszFileName, ui32Line);
+#else
+ PVR_UNREFERENCED_PARAMETER(pszFileName);
+ PVR_UNREFERENCED_PARAMETER(ui32Line);
+#endif
+
+ kmem_cache_free(psCache, pvObject);
+}
+
+
+const IMG_CHAR *
+KMemCacheNameWrapper(LinuxKMemCache *psCache)
+{
+ PVR_UNREFERENCED_PARAMETER(psCache);
+
+ /* In this case kmem_cache_t is an incomplete typedef,
+ * so we can't even de-reference to get the name member. It is also a GPL export symbol */
+ return "";
+}
+
+
+static LinuxPagePoolEntry *
+LinuxPagePoolEntryAlloc(IMG_VOID)
+{
+ return KMemCacheAllocWrapper(g_PsLinuxPagePoolCache, GFP_KERNEL);
+}
+
+static IMG_VOID
+LinuxPagePoolEntryFree(LinuxPagePoolEntry *psPagePoolEntry)
+{
+ KMemCacheFreeWrapper(g_PsLinuxPagePoolCache, psPagePoolEntry);
+}
+
+
+static struct page *
+AllocPageFromLinux(void)
+{
+ struct page *psPage;
+
+ psPage = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0);
+ if (!psPage)
+ {
+ return NULL;
+
+ }
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
+ /* Reserve those pages to allow them to be re-mapped to user space */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
+ SetPageReserved(psPage);
+#else
+ mem_map_reserve(psPage);
+#endif
+#endif
+ return psPage;
+}
+
+
+static IMG_VOID
+FreePageToLinux(struct page *psPage)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
+ ClearPageReserved(psPage);
+#else
+ mem_map_reserve(psPage);
+#endif
+#endif
+ __free_pages(psPage, 0);
+}
+
+
+#if (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0)
+static DEFINE_MUTEX(g_sPagePoolMutex);
+
+static inline void
+PagePoolLock(void)
+{
+ mutex_lock(&g_sPagePoolMutex);
+}
+
+static inline void
+PagePoolUnlock(void)
+{
+ mutex_unlock(&g_sPagePoolMutex);
+}
+
+static inline int
+PagePoolTrylock(void)
+{
+ return mutex_trylock(&g_sPagePoolMutex);
+}
+
+#else /* (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0) */
+static inline void
+PagePoolLock(void)
+{
+}
+
+static inline void
+PagePoolUnlock(void)
+{
+}
+
+static inline int
+PagePoolTrylock(void)
+{
+ return 1;
+}
+#endif /* (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0) */
+
+
+static inline void
+AddEntryToPool(LinuxPagePoolEntry *psPagePoolEntry)
+{
+ list_add_tail(&psPagePoolEntry->sPagePoolItem, &g_sPagePoolList);
+ atomic_inc(&g_sPagePoolEntryCount);
+}
+
+static inline void
+RemoveEntryFromPool(LinuxPagePoolEntry *psPagePoolEntry)
+{
+ list_del(&psPagePoolEntry->sPagePoolItem);
+ atomic_dec(&g_sPagePoolEntryCount);
+}
+
+static inline LinuxPagePoolEntry *
+RemoveFirstEntryFromPool(void)
+{
+ LinuxPagePoolEntry *psPagePoolEntry;
+
+ if (list_empty(&g_sPagePoolList))
+ {
+ PVR_ASSERT(atomic_read(&g_sPagePoolEntryCount) == 0);
+
+ return NULL;
+ }
+
+ PVR_ASSERT(atomic_read(&g_sPagePoolEntryCount) > 0);
+
+ psPagePoolEntry = list_first_entry(&g_sPagePoolList, LinuxPagePoolEntry, sPagePoolItem);
+
+ RemoveEntryFromPool(psPagePoolEntry);
+
+ return psPagePoolEntry;
+}
+
+static struct page *
+AllocPage(IMG_UINT32 ui32AreaFlags, IMG_BOOL *pbFromPagePool)
+{
+ struct page *psPage = NULL;
+
+ /*
+ * Only uncached allocations can come from the page pool.
+ * The page pool is currently used to reduce the cost of
+ * invalidating the CPU cache when uncached memory is allocated.
+ */
+ if (AreaIsUncached(ui32AreaFlags) && atomic_read(&g_sPagePoolEntryCount) != 0)
+ {
+ LinuxPagePoolEntry *psPagePoolEntry;
+
+ PagePoolLock();
+ psPagePoolEntry = RemoveFirstEntryFromPool();
+ PagePoolUnlock();
+
+ /* List may have changed since we checked the counter */
+ if (psPagePoolEntry)
+ {
+ psPage = psPagePoolEntry->psPage;
+ LinuxPagePoolEntryFree(psPagePoolEntry);
+ *pbFromPagePool = IMG_TRUE;
+ }
+ }
+
+ if (!psPage)
+ {
+ psPage = AllocPageFromLinux();
+ if (psPage)
+ {
+ *pbFromPagePool = IMG_FALSE;
+ }
+ }
+
+ return psPage;
+
+}
+
+static IMG_VOID
+FreePage(IMG_BOOL bToPagePool, struct page *psPage)
+{
+ /* Only uncached allocations can be freed to the page pool */
+ if (bToPagePool && atomic_read(&g_sPagePoolEntryCount) < g_iPagePoolMaxEntries)
+ {
+ LinuxPagePoolEntry *psPagePoolEntry = LinuxPagePoolEntryAlloc();
+ if (psPagePoolEntry)
+ {
+ psPagePoolEntry->psPage = psPage;
+
+ PagePoolLock();
+ AddEntryToPool(psPagePoolEntry);
+ PagePoolUnlock();
+
+ return;
+ }
+ }
+
+ FreePageToLinux(psPage);
+}
+
+static IMG_VOID
+FreePagePool(IMG_VOID)
+{
+ LinuxPagePoolEntry *psPagePoolEntry, *psTempPoolEntry;
+
+ PagePoolLock();
+
+#if (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0)
+ PVR_TRACE(("%s: Freeing %d pages from pool", __FUNCTION__, atomic_read(&g_sPagePoolEntryCount)));
+#else
+ PVR_ASSERT(atomic_read(&g_sPagePoolEntryCount) == 0);
+ PVR_ASSERT(list_empty(&g_sPagePoolList));
+#endif
+
+ list_for_each_entry_safe(psPagePoolEntry, psTempPoolEntry, &g_sPagePoolList, sPagePoolItem)
+ {
+ RemoveEntryFromPool(psPagePoolEntry);
+
+ FreePageToLinux(psPagePoolEntry->psPage);
+ LinuxPagePoolEntryFree(psPagePoolEntry);
+ }
+
+ PVR_ASSERT(atomic_read(&g_sPagePoolEntryCount) == 0);
+
+ PagePoolUnlock();
+}
+
+#if defined(PVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK)
+#if defined(PVRSRV_NEED_PVR_ASSERT)
+static struct shrinker g_sShrinker;
+#endif
+
+static int
+ShrinkPagePool(struct shrinker *psShrinker, struct shrink_control *psShrinkControl)
+{
+ unsigned long uNumToScan = psShrinkControl->nr_to_scan;
+
+ PVR_ASSERT(psShrinker == &g_sShrinker);
+ (void)psShrinker;
+
+ if (uNumToScan != 0)
+ {
+ LinuxPagePoolEntry *psPagePoolEntry, *psTempPoolEntry;
+
+ PVR_TRACE(("%s: Number to scan: %ld", __FUNCTION__, uNumToScan));
+ PVR_TRACE(("%s: Pages in pool before scan: %d", __FUNCTION__, atomic_read(&g_sPagePoolEntryCount)));
+
+ if (!PagePoolTrylock())
+ {
+ PVR_TRACE(("%s: Couldn't get page pool lock", __FUNCTION__));
+ return -1;
+ }
+
+ list_for_each_entry_safe(psPagePoolEntry, psTempPoolEntry, &g_sPagePoolList, sPagePoolItem)
+ {
+ RemoveEntryFromPool(psPagePoolEntry);
+
+ FreePageToLinux(psPagePoolEntry->psPage);
+ LinuxPagePoolEntryFree(psPagePoolEntry);
+
+ if (--uNumToScan == 0)
+ {
+ break;
+ }
+ }
+
+ if (list_empty(&g_sPagePoolList))
+ {
+ PVR_ASSERT(atomic_read(&g_sPagePoolEntryCount) == 0);
+ }
+
+ PagePoolUnlock();
+
+ PVR_TRACE(("%s: Pages in pool after scan: %d", __FUNCTION__, atomic_read(&g_sPagePoolEntryCount)));
+ }
+
+ return atomic_read(&g_sPagePoolEntryCount);
+}
+#endif
+
+static IMG_BOOL
+AllocPages(IMG_UINT32 ui32AreaFlags, struct page ***pppsPageList, IMG_HANDLE *phBlockPageList, IMG_UINT32 ui32NumPages, IMG_BOOL *pbFromPagePool)
+{
+ struct page **ppsPageList;
+ IMG_HANDLE hBlockPageList;
+ IMG_INT32 i; /* Must be signed; see "for" loop conditions */
+ PVRSRV_ERROR eError;
+ IMG_BOOL bFromPagePool = IMG_FALSE;
+
+ eError = OSAllocMem(0, sizeof(*ppsPageList) * ui32NumPages, (IMG_VOID **)&ppsPageList, &hBlockPageList,
+ "Array of pages");
+ if (eError != PVRSRV_OK)
+ {
+ goto failed_page_list_alloc;
+ }
+
+ *pbFromPagePool = IMG_TRUE;
+ for(i = 0; i < (IMG_INT32)ui32NumPages; i++)
+ {
+ ppsPageList[i] = AllocPage(ui32AreaFlags, &bFromPagePool);
+ if (!ppsPageList[i])
+ {
+ goto failed_alloc_pages;
+ }
+ *pbFromPagePool &= bFromPagePool;
+ }
+
+ *pppsPageList = ppsPageList;
+ *phBlockPageList = hBlockPageList;
+
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+ DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES,
+ ppsPageList,
+ 0,
+ 0,
+ NULL,
+ PAGES_TO_BYTES(ui32NumPages),
+ "unknown",
+ 0
+ );
+#endif
+
+ return IMG_TRUE;
+
+failed_alloc_pages:
+ for(i--; i >= 0; i--)
+ {
+ FreePage(*pbFromPagePool, ppsPageList[i]);
+ }
+ (IMG_VOID) OSFreeMem(0, sizeof(*ppsPageList) * ui32NumPages, ppsPageList, hBlockPageList);
+
+failed_page_list_alloc:
+ return IMG_FALSE;
+}
+
+
+static IMG_VOID
+FreePages(IMG_BOOL bToPagePool, struct page **ppsPageList, IMG_HANDLE hBlockPageList, IMG_UINT32 ui32NumPages)
+{
+ IMG_INT32 i;
+
+ for(i = 0; i < (IMG_INT32)ui32NumPages; i++)
+ {
+ FreePage(bToPagePool, ppsPageList[i]);
+ }
+
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+ DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, ppsPageList, __FILE__, __LINE__);
+#endif
+
+ (IMG_VOID) OSFreeMem(0, sizeof(*ppsPageList) * ui32NumPages, ppsPageList, hBlockPageList);
+}
+
+
LinuxMemArea *
NewVMallocLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags)
{
- LinuxMemArea *psLinuxMemArea;
+ LinuxMemArea *psLinuxMemArea = NULL;
IMG_VOID *pvCpuVAddr;
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ IMG_UINT32 ui32NumPages = 0;
+ struct page **ppsPageList = NULL;
+ IMG_HANDLE hBlockPageList;
+#endif
+ IMG_BOOL bFromPagePool = IMG_FALSE;
psLinuxMemArea = LinuxMemAreaStructAlloc();
- if(!psLinuxMemArea)
+ if (!psLinuxMemArea)
{
goto failed;
}
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ ui32NumPages = RANGE_TO_PAGES(ui32Bytes);
+
+ if (!AllocPages(ui32AreaFlags, &ppsPageList, &hBlockPageList, ui32NumPages, &bFromPagePool))
+ {
+ goto failed;
+ }
+
+ pvCpuVAddr = VMapWrapper(ppsPageList, ui32NumPages, ui32AreaFlags);
+#else /* defined(PVR_LINUX_MEM_AREA_USE_VMAP) */
pvCpuVAddr = VMallocWrapper(ui32Bytes, ui32AreaFlags);
- if(!pvCpuVAddr)
+ if (!pvCpuVAddr)
{
goto failed;
}
-
+/* PG_reserved was deprecated in linux-2.6.15 */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
-
+ /* Reserve those pages to allow them to be re-mapped to user space */
ReservePages(pvCpuVAddr, ui32Bytes);
#endif
+#endif /* defined(PVR_LINUX_MEM_AREA_USE_VMAP) */
psLinuxMemArea->eAreaType = LINUX_MEM_AREA_VMALLOC;
psLinuxMemArea->uData.sVmalloc.pvVmallocAddress = pvCpuVAddr;
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ psLinuxMemArea->uData.sVmalloc.ppsPageList = ppsPageList;
+ psLinuxMemArea->uData.sVmalloc.hBlockPageList = hBlockPageList;
+#endif
psLinuxMemArea->ui32ByteSize = ui32Bytes;
psLinuxMemArea->ui32AreaFlags = ui32AreaFlags;
INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList);
@@ -612,16 +1005,41 @@ NewVMallocLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags)
DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags);
#endif
-
- if(ui32AreaFlags & (PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_UNCACHED))
- OSInvalidateCPUCacheRangeKM(psLinuxMemArea, pvCpuVAddr, ui32Bytes);
+ /* This works around a problem where Linux will not invalidate
+ * the cache for physical memory it frees that is direct mapped.
+ *
+ * As a result, cache entries remain that may be subsequently flushed
+ * to these physical pages after they have been allocated for another
+ * purpose. For a subsequent cached use of this memory, that is not a
+ * problem, but if we are allocating uncached or write-combined memory,
+ * and bypassing the cache, it can cause subsequent uncached writes to
+ * the memory to be replaced with junk from the cache.
+ *
+ * If the pages are from our page cache, no cache invalidate is needed.
+ *
+ * This just handles the __vmalloc() case (when we have a kernel virtual
+ * address range). The alloc_pages() path is handled in mmap.c.
+ */
+ if (AreaIsUncached(ui32AreaFlags) && !bFromPagePool)
+ {
+ OSInvalidateCPUCacheRangeKM(psLinuxMemArea, 0, pvCpuVAddr, ui32Bytes);
+ }
return psLinuxMemArea;
failed:
PVR_DPF((PVR_DBG_ERROR, "%s: failed!", __FUNCTION__));
- if(psLinuxMemArea)
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ if (ppsPageList)
+ {
+ FreePages(bFromPagePool, ppsPageList, hBlockPageList, ui32NumPages);
+ }
+#endif
+ if (psLinuxMemArea)
+ {
LinuxMemAreaStructFree(psLinuxMemArea);
+ }
+
return NULL;
}
@@ -629,6 +1047,12 @@ failed:
IMG_VOID
FreeVMallocLinuxMemArea(LinuxMemArea *psLinuxMemArea)
{
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ IMG_UINT32 ui32NumPages;
+ struct page **ppsPageList;
+ IMG_HANDLE hBlockPageList;
+#endif
+
PVR_ASSERT(psLinuxMemArea);
PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_VMALLOC);
PVR_ASSERT(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress);
@@ -637,20 +1061,34 @@ FreeVMallocLinuxMemArea(LinuxMemArea *psLinuxMemArea)
DebugLinuxMemAreaRecordRemove(psLinuxMemArea);
#endif
+ PVR_DPF((PVR_DBG_MESSAGE,"%s: pvCpuVAddr: %p",
+ __FUNCTION__, psLinuxMemArea->uData.sVmalloc.pvVmallocAddress));
+
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ VUnmapWrapper(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress);
+
+ ui32NumPages = RANGE_TO_PAGES(psLinuxMemArea->ui32ByteSize);
+ ppsPageList = psLinuxMemArea->uData.sVmalloc.ppsPageList;
+ hBlockPageList = psLinuxMemArea->uData.sVmalloc.hBlockPageList;
+
+ FreePages(CanFreeToPool(psLinuxMemArea), ppsPageList, hBlockPageList, ui32NumPages);
+#else
+/* PG_reserved was deprecated in linux-2.6.15 */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
- UnreservePages(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress,
+ UnreservePages(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress,
psLinuxMemArea->ui32ByteSize);
#endif
- PVR_DPF((PVR_DBG_MESSAGE,"%s: pvCpuVAddr: %p",
- __FUNCTION__, psLinuxMemArea->uData.sVmalloc.pvVmallocAddress));
VFreeWrapper(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress);
+#endif /* defined(PVR_LINUX_MEM_AREA_USE_VMAP) */
LinuxMemAreaStructFree(psLinuxMemArea);
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
+/* Reserve pages of memory in order that they're not automatically
+ deallocated after the last user reference dies. */
static IMG_VOID
ReservePages(IMG_VOID *pvAddress, IMG_UINT32 ui32Length)
{
@@ -668,6 +1106,7 @@ ReservePages(IMG_VOID *pvAddress, IMG_UINT32 ui32Length)
}
+/* Un-reserve pages of memory in order that they can be freed. */
static IMG_VOID
UnreservePages(IMG_VOID *pvAddress, IMG_UINT32 ui32Length)
{
@@ -683,7 +1122,7 @@ UnreservePages(IMG_VOID *pvAddress, IMG_UINT32 ui32Length)
#endif
}
}
-#endif
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) */
IMG_VOID *
@@ -695,10 +1134,9 @@ _IORemapWrapper(IMG_CPU_PHYADDR BasePAddr,
{
IMG_VOID *pvIORemapCookie;
- switch(ui32MappingFlags & PVRSRV_HAP_CACHETYPE_MASK)
+ switch (ui32MappingFlags & PVRSRV_HAP_CACHETYPE_MASK)
{
case PVRSRV_HAP_CACHED:
- case PVRSRV_HAP_SMART:
pvIORemapCookie = (IMG_VOID *)IOREMAP(BasePAddr.uiAddr, ui32Bytes);
break;
case PVRSRV_HAP_WRITECOMBINE:
@@ -713,7 +1151,7 @@ _IORemapWrapper(IMG_CPU_PHYADDR BasePAddr,
}
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
- if(pvIORemapCookie)
+ if (pvIORemapCookie)
{
DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_IOREMAP,
pvIORemapCookie,
@@ -723,7 +1161,7 @@ _IORemapWrapper(IMG_CPU_PHYADDR BasePAddr,
ui32Bytes,
pszFileName,
ui32Line
- );
+ );
}
#else
PVR_UNREFERENCED_PARAMETER(pszFileName);
@@ -756,13 +1194,13 @@ NewIORemapLinuxMemArea(IMG_CPU_PHYADDR BasePAddr,
IMG_VOID *pvIORemapCookie;
psLinuxMemArea = LinuxMemAreaStructAlloc();
- if(!psLinuxMemArea)
+ if (!psLinuxMemArea)
{
return NULL;
}
pvIORemapCookie = IORemapWrapper(BasePAddr, ui32Bytes, ui32AreaFlags);
- if(!pvIORemapCookie)
+ if (!pvIORemapCookie)
{
LinuxMemAreaStructFree(psLinuxMemArea);
return NULL;
@@ -799,6 +1237,16 @@ FreeIORemapLinuxMemArea(LinuxMemArea *psLinuxMemArea)
#if !defined(PVR_MAKE_ALL_PFNS_SPECIAL)
+/*
+ * Avoid using remap_pfn_range on RAM, if possible. On x86 systems, with
+ * PAT enabled, remap_pfn_range checks the page attributes requested by
+ * remap_pfn_range against those of the direct kernel mapping for those
+ * pages (if any). This is rather annoying if the pages have been obtained
+ * with alloc_pages, where we just ask for raw pages; we don't care about
+ * the direct mapping. This latter issue arises when device memory is
+ * exported from one process to another. Services implements this
+ * using memory wrapping, which ends up creating an external KV memory area.
+ */
static IMG_BOOL
TreatExternalPagesAsContiguous(IMG_SYS_PHYADDR *psSysPhysAddr, IMG_UINT32 ui32Bytes, IMG_BOOL bPhysContig)
{
@@ -806,7 +1254,10 @@ TreatExternalPagesAsContiguous(IMG_SYS_PHYADDR *psSysPhysAddr, IMG_UINT32 ui32By
IMG_UINT32 ui32AddrChk;
IMG_UINT32 ui32NumPages = RANGE_TO_PAGES(ui32Bytes);
-
+ /*
+ * If bPhysContig is IMG_TRUE, we must assume psSysPhysAddr points
+ * to the address of the first page, not an array of page addresses.
+ */
for (ui32 = 0, ui32AddrChk = psSysPhysAddr[0].uiAddr;
ui32 < ui32NumPages;
ui32++, ui32AddrChk = (bPhysContig) ? (ui32AddrChk + PAGE_SIZE) : psSysPhysAddr[ui32].uiAddr)
@@ -843,7 +1294,7 @@ LinuxMemArea *NewExternalKVLinuxMemArea(IMG_SYS_PHYADDR *pBasePAddr, IMG_VOID *p
LinuxMemArea *psLinuxMemArea;
psLinuxMemArea = LinuxMemAreaStructAlloc();
- if(!psLinuxMemArea)
+ if (!psLinuxMemArea)
{
return NULL;
}
@@ -896,12 +1347,12 @@ NewIOLinuxMemArea(IMG_CPU_PHYADDR BasePAddr,
IMG_UINT32 ui32AreaFlags)
{
LinuxMemArea *psLinuxMemArea = LinuxMemAreaStructAlloc();
- if(!psLinuxMemArea)
+ if (!psLinuxMemArea)
{
return NULL;
}
-
+ /* Nothing to activly do. We just keep a record of the physical range. */
psLinuxMemArea->eAreaType = LINUX_MEM_AREA_IO;
psLinuxMemArea->uData.sIO.CPUPhysAddr.uiAddr = BasePAddr.uiAddr;
psLinuxMemArea->ui32ByteSize = ui32Bytes;
@@ -917,7 +1368,7 @@ NewIOLinuxMemArea(IMG_CPU_PHYADDR BasePAddr,
ui32Bytes,
"unknown",
0
- );
+ );
#endif
#if defined(DEBUG_LINUX_MEM_AREAS)
@@ -942,7 +1393,7 @@ FreeIOLinuxMemArea(LinuxMemArea *psLinuxMemArea)
(IMG_VOID *)psLinuxMemArea->uData.sIO.CPUPhysAddr.uiAddr, __FILE__, __LINE__);
#endif
-
+ /* Nothing more to do than free the LinuxMemArea struct */
LinuxMemAreaStructFree(psLinuxMemArea);
}
@@ -952,68 +1403,33 @@ LinuxMemArea *
NewAllocPagesLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags)
{
LinuxMemArea *psLinuxMemArea;
- IMG_UINT32 ui32PageCount;
- struct page **pvPageList;
+ IMG_UINT32 ui32NumPages;
+ struct page **ppsPageList;
IMG_HANDLE hBlockPageList;
- IMG_INT32 i;
- PVRSRV_ERROR eError;
-
+ IMG_BOOL bFromPagePool;
+
psLinuxMemArea = LinuxMemAreaStructAlloc();
- if(!psLinuxMemArea)
+ if (!psLinuxMemArea)
{
goto failed_area_alloc;
}
- ui32PageCount = RANGE_TO_PAGES(ui32Bytes);
- eError = OSAllocMem(0, sizeof(*pvPageList) * ui32PageCount, (IMG_VOID **)&pvPageList, &hBlockPageList,
- "Array of pages");
- if(eError != PVRSRV_OK)
- {
- goto failed_page_list_alloc;
- }
-
- for(i=0; i<(IMG_INT32)ui32PageCount; i++)
- {
- pvPageList[i] = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0);
- if(!pvPageList[i])
- {
- goto failed_alloc_pages;
- }
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
- SetPageReserved(pvPageList[i]);
-#else
- mem_map_reserve(pvPageList[i]);
-#endif
-#endif
+ ui32NumPages = RANGE_TO_PAGES(ui32Bytes);
+ if (!AllocPages(ui32AreaFlags, &ppsPageList, &hBlockPageList, ui32NumPages, &bFromPagePool))
+ {
+ goto failed_alloc_pages;
}
-#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
- DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES,
- pvPageList,
- 0,
- 0,
- NULL,
- PAGE_ALIGN(ui32Bytes),
- "unknown",
- 0
- );
-#endif
-
psLinuxMemArea->eAreaType = LINUX_MEM_AREA_ALLOC_PAGES;
- psLinuxMemArea->uData.sPageList.pvPageList = pvPageList;
+ psLinuxMemArea->uData.sPageList.ppsPageList = ppsPageList;
psLinuxMemArea->uData.sPageList.hBlockPageList = hBlockPageList;
psLinuxMemArea->ui32ByteSize = ui32Bytes;
psLinuxMemArea->ui32AreaFlags = ui32AreaFlags;
INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList);
-
- if(ui32AreaFlags & (PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_UNCACHED))
- {
- psLinuxMemArea->bNeedsCacheInvalidate = IMG_TRUE;
- }
+ /* We defer the cache flush to the first user mapping of this memory */
+ psLinuxMemArea->bNeedsCacheInvalidate = AreaIsUncached(ui32AreaFlags) && !bFromPagePool;
#if defined(DEBUG_LINUX_MEM_AREAS)
DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags);
@@ -1022,13 +1438,6 @@ NewAllocPagesLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags)
return psLinuxMemArea;
failed_alloc_pages:
- for(i--; i >= 0; i--)
- {
- __free_pages(pvPageList[i], 0);
- }
- (IMG_VOID) OSFreeMem(0, sizeof(*pvPageList) * ui32PageCount, pvPageList, hBlockPageList);
- psLinuxMemArea->uData.sPageList.pvPageList = IMG_NULL;
-failed_page_list_alloc:
LinuxMemAreaStructFree(psLinuxMemArea);
failed_area_alloc:
PVR_DPF((PVR_DBG_ERROR, "%s: failed", __FUNCTION__));
@@ -1040,10 +1449,9 @@ failed_area_alloc:
IMG_VOID
FreeAllocPagesLinuxMemArea(LinuxMemArea *psLinuxMemArea)
{
- IMG_UINT32 ui32PageCount;
- struct page **pvPageList;
+ IMG_UINT32 ui32NumPages;
+ struct page **ppsPageList;
IMG_HANDLE hBlockPageList;
- IMG_INT32 i;
PVR_ASSERT(psLinuxMemArea);
PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_ALLOC_PAGES);
@@ -1052,38 +1460,162 @@ FreeAllocPagesLinuxMemArea(LinuxMemArea *psLinuxMemArea)
DebugLinuxMemAreaRecordRemove(psLinuxMemArea);
#endif
- ui32PageCount = RANGE_TO_PAGES(psLinuxMemArea->ui32ByteSize);
- pvPageList = psLinuxMemArea->uData.sPageList.pvPageList;
+ ui32NumPages = RANGE_TO_PAGES(psLinuxMemArea->ui32ByteSize);
+ ppsPageList = psLinuxMemArea->uData.sPageList.ppsPageList;
hBlockPageList = psLinuxMemArea->uData.sPageList.hBlockPageList;
-#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
- DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, pvPageList, __FILE__, __LINE__);
-#endif
+ FreePages(CanFreeToPool(psLinuxMemArea), ppsPageList, hBlockPageList, ui32NumPages);
+
+ LinuxMemAreaStructFree(psLinuxMemArea);
+}
+
+#if defined(CONFIG_ION_OMAP)
+
+#include "env_perproc.h"
- for(i=0;i<(IMG_INT32)ui32PageCount;i++)
+#include <linux/ion.h>
+#include <linux/omap_ion.h>
+
+extern struct ion_client *gpsIONClient;
+
+LinuxMemArea *
+NewIONLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags,
+ IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength)
+{
+ const IMG_UINT32 ui32AllocDataLen =
+ offsetof(struct omap_ion_tiler_alloc_data, handle);
+ struct omap_ion_tiler_alloc_data asAllocData[2] = {};
+ u32 *pu32PageAddrs[2] = { NULL, NULL };
+ IMG_UINT32 i, ui32NumHandlesPerFd;
+ IMG_BYTE *pbPrivData = pvPrivData;
+ IMG_CPU_PHYADDR *pCPUPhysAddrs;
+ int iNumPages[2] = { 0, 0 };
+ LinuxMemArea *psLinuxMemArea;
+
+ psLinuxMemArea = LinuxMemAreaStructAlloc();
+ if (!psLinuxMemArea)
{
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
- ClearPageReserved(pvPageList[i]);
-#else
- mem_map_reserve(pvPageList[i]);
-#endif
-#endif
- if (psLinuxMemArea->ui32AreaFlags & PVRSRV_HAP_SMART)
+ PVR_DPF((PVR_DBG_ERROR, "%s: Failed to allocate LinuxMemArea struct", __func__));
+ goto err_out;
+ }
+
+ /* Depending on the UM config, userspace might give us info for
+ * one or two ION allocations. Divide the total size of data we
+ * were given by this ui32AllocDataLen, and check it's 1 or 2.
+ * Otherwise abort.
+ */
+ BUG_ON(ui32PrivDataLength != ui32AllocDataLen &&
+ ui32PrivDataLength != ui32AllocDataLen * 2);
+ ui32NumHandlesPerFd = ui32PrivDataLength / ui32AllocDataLen;
+
+ /* Shuffle the alloc data into separate Y & UV bits and
+ * make two separate allocations via the tiler.
+ */
+ for(i = 0; i < ui32NumHandlesPerFd; i++)
+ {
+ memcpy(&asAllocData[i], &pbPrivData[i * ui32AllocDataLen], ui32AllocDataLen);
+
+ if (omap_ion_tiler_alloc(gpsIONClient, &asAllocData[i]) < 0)
+ {
+ PVR_DPF((PVR_DBG_ERROR, "%s: Failed to allocate via ion_tiler", __func__));
+ goto err_free;
+ }
+
+ if (omap_tiler_pages(gpsIONClient, asAllocData[i].handle, &iNumPages[i],
+ &pu32PageAddrs[i]) < 0)
{
- // XXX some race here..
- clear_bit(PG_private, &pvPageList[i]->flags);
- clear_bit(PG_private_2, &pvPageList[i]->flags);
+ PVR_DPF((PVR_DBG_ERROR, "%s: Failed to compute tiler pages", __func__));
+ goto err_free;
}
- __free_pages(pvPageList[i], 0);
}
- (IMG_VOID) OSFreeMem(0, sizeof(*pvPageList) * ui32PageCount, pvPageList, hBlockPageList);
- psLinuxMemArea->uData.sPageList.pvPageList = IMG_NULL;
+ /* Assume the user-allocator has already done the tiler math and that the
+ * number of tiler pages allocated matches any other allocation type.
+ */
+ BUG_ON(ui32Bytes != (iNumPages[0] + iNumPages[1]) * PAGE_SIZE);
+ BUG_ON(sizeof(IMG_CPU_PHYADDR) != sizeof(int));
+
+ /* Glue the page lists together */
+ pCPUPhysAddrs = vmalloc(sizeof(IMG_CPU_PHYADDR) * (iNumPages[0] + iNumPages[1]));
+ if (!pCPUPhysAddrs)
+ {
+ PVR_DPF((PVR_DBG_ERROR, "%s: Failed to allocate page list", __func__));
+ goto err_free;
+ }
+ for(i = 0; i < iNumPages[0]; i++)
+ pCPUPhysAddrs[i].uiAddr = pu32PageAddrs[0][i];
+ for(i = 0; i < iNumPages[1]; i++)
+ pCPUPhysAddrs[iNumPages[0] + i].uiAddr = pu32PageAddrs[1][i];
+
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+ DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_ION,
+ asAllocData[0].handle,
+ 0,
+ 0,
+ NULL,
+ PAGE_ALIGN(ui32Bytes),
+ "unknown",
+ 0
+ );
+#endif
+
+ for(i = 0; i < 2; i++)
+ psLinuxMemArea->uData.sIONTilerAlloc.psIONHandle[i] = asAllocData[i].handle;
+
+ psLinuxMemArea->eAreaType = LINUX_MEM_AREA_ION;
+ psLinuxMemArea->uData.sIONTilerAlloc.pCPUPhysAddrs = pCPUPhysAddrs;
+ psLinuxMemArea->ui32ByteSize = ui32Bytes;
+ psLinuxMemArea->ui32AreaFlags = ui32AreaFlags;
+ INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList);
+
+ /* We defer the cache flush to the first user mapping of this memory */
+ psLinuxMemArea->bNeedsCacheInvalidate = AreaIsUncached(ui32AreaFlags);
+
+#if defined(DEBUG_LINUX_MEM_AREAS)
+ DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags);
+#endif
+
+err_out:
+ return psLinuxMemArea;
+
+err_free:
+ LinuxMemAreaStructFree(psLinuxMemArea);
+ psLinuxMemArea = IMG_NULL;
+ goto err_out;
+}
+
+
+IMG_VOID
+FreeIONLinuxMemArea(LinuxMemArea *psLinuxMemArea)
+{
+ IMG_UINT32 i;
+
+#if defined(DEBUG_LINUX_MEM_AREAS)
+ DebugLinuxMemAreaRecordRemove(psLinuxMemArea);
+#endif
+
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+ DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ION,
+ psLinuxMemArea->uData.sIONTilerAlloc.psIONHandle[0],
+ __FILE__, __LINE__);
+#endif
+
+ for(i = 0; i < 2; i++)
+ {
+ if (!psLinuxMemArea->uData.sIONTilerAlloc.psIONHandle[i])
+ break;
+ ion_free(gpsIONClient, psLinuxMemArea->uData.sIONTilerAlloc.psIONHandle[i]);
+ psLinuxMemArea->uData.sIONTilerAlloc.psIONHandle[i] = IMG_NULL;
+ }
+
+ /* free copy of page list, originals are freed by ion_free */
+ vfree(psLinuxMemArea->uData.sIONTilerAlloc.pCPUPhysAddrs);
+ psLinuxMemArea->uData.sIONTilerAlloc.pCPUPhysAddrs = IMG_NULL;
LinuxMemAreaStructFree(psLinuxMemArea);
}
+#endif /* defined(CONFIG_ION_OMAP) */
struct page*
LinuxMemAreaOffsetToPage(LinuxMemArea *psLinuxMemArea,
@@ -1092,11 +1624,11 @@ LinuxMemAreaOffsetToPage(LinuxMemArea *psLinuxMemArea,
IMG_UINT32 ui32PageIndex;
IMG_CHAR *pui8Addr;
- switch(psLinuxMemArea->eAreaType)
+ switch (psLinuxMemArea->eAreaType)
{
case LINUX_MEM_AREA_ALLOC_PAGES:
ui32PageIndex = PHYS_TO_PFN(ui32ByteOffset);
- return psLinuxMemArea->uData.sPageList.pvPageList[ui32PageIndex];
+ return psLinuxMemArea->uData.sPageList.ppsPageList[ui32PageIndex];
case LINUX_MEM_AREA_VMALLOC:
pui8Addr = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress;
@@ -1104,7 +1636,7 @@ LinuxMemAreaOffsetToPage(LinuxMemArea *psLinuxMemArea,
return vmalloc_to_page(pui8Addr);
case LINUX_MEM_AREA_SUB_ALLOC:
-
+ /* PRQA S 3670 3 */ /* ignore recursive warning */
return LinuxMemAreaOffsetToPage(psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea,
psLinuxMemArea->uData.sSubAlloc.ui32ByteOffset
+ ui32ByteOffset);
@@ -1129,8 +1661,8 @@ KMemCacheCreateWrapper(IMG_CHAR *pszName,
return kmem_cache_create(pszName, Size, Align, ui32Flags, NULL
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22))
, NULL
-#endif
- );
+#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) */
+ );
}
@@ -1164,7 +1696,7 @@ _KMemCacheAllocWrapper(LinuxKMemCache *psCache,
kmem_cache_size(psCache),
pszFileName,
ui32Line
- );
+ );
#else
PVR_UNREFERENCED_PARAMETER(pszFileName);
PVR_UNREFERENCED_PARAMETER(ui32Line);
@@ -1174,30 +1706,6 @@ _KMemCacheAllocWrapper(LinuxKMemCache *psCache,
}
-IMG_VOID
-_KMemCacheFreeWrapper(LinuxKMemCache *psCache, IMG_VOID *pvObject, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line)
-{
-#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
- DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE, pvObject, pszFileName, ui32Line);
-#else
- PVR_UNREFERENCED_PARAMETER(pszFileName);
- PVR_UNREFERENCED_PARAMETER(ui32Line);
-#endif
-
- kmem_cache_free(psCache, pvObject);
-}
-
-
-const IMG_CHAR *
-KMemCacheNameWrapper(LinuxKMemCache *psCache)
-{
- PVR_UNREFERENCED_PARAMETER(psCache);
-
-
- return "";
-}
-
-
LinuxMemArea *
NewSubLinuxMemArea(LinuxMemArea *psParentLinuxMemArea,
IMG_UINT32 ui32ByteOffset,
@@ -1208,7 +1716,7 @@ NewSubLinuxMemArea(LinuxMemArea *psParentLinuxMemArea,
PVR_ASSERT((ui32ByteOffset+ui32Bytes) <= psParentLinuxMemArea->ui32ByteSize);
psLinuxMemArea = LinuxMemAreaStructAlloc();
- if(!psLinuxMemArea)
+ if (!psLinuxMemArea)
{
return NULL;
}
@@ -1242,7 +1750,7 @@ FreeSubLinuxMemArea(LinuxMemArea *psLinuxMemArea)
DebugLinuxMemAreaRecordRemove(psLinuxMemArea);
#endif
-
+ /* Nothing more to do than free the LinuxMemArea structure */
LinuxMemAreaStructFree(psLinuxMemArea);
}
@@ -1251,14 +1759,15 @@ FreeSubLinuxMemArea(LinuxMemArea *psLinuxMemArea)
static LinuxMemArea *
LinuxMemAreaStructAlloc(IMG_VOID)
{
+/* debug */
#if 0
LinuxMemArea *psLinuxMemArea;
- psLinuxMemArea = kmem_cache_alloc(psLinuxMemAreaCache, GFP_KERNEL);
+ psLinuxMemArea = kmem_cache_alloc(g_PsLinuxMemAreaCache, GFP_KERNEL);
printk(KERN_ERR "%s: psLinuxMemArea=%p\n", __FUNCTION__, psLinuxMemArea);
dump_stack();
return psLinuxMemArea;
#else
- return KMemCacheAllocWrapper(psLinuxMemAreaCache, GFP_KERNEL);
+ return KMemCacheAllocWrapper(g_PsLinuxMemAreaCache, GFP_KERNEL);
#endif
}
@@ -1274,16 +1783,16 @@ LinuxMemAreaStructFree(LinuxMemArea *psLinuxMemArea)
if (psLinuxMemArea->buf)
drm_gem_object_unreference_unlocked(psLinuxMemArea->buf);
#endif /* SUPPORT_DRI_DRM_EXTERNAL */
- KMemCacheFreeWrapper(psLinuxMemAreaCache, psLinuxMemArea);
-
-
+ KMemCacheFreeWrapper(g_PsLinuxMemAreaCache, psLinuxMemArea);
+ /* debug */
+ //printk(KERN_ERR "%s(%p)\n", __FUNCTION__, psLinuxMemArea);
}
IMG_VOID
LinuxMemAreaDeepFree(LinuxMemArea *psLinuxMemArea)
{
- switch(psLinuxMemArea->eAreaType)
+ switch (psLinuxMemArea->eAreaType)
{
case LINUX_MEM_AREA_VMALLOC:
FreeVMallocLinuxMemArea(psLinuxMemArea);
@@ -1294,15 +1803,18 @@ LinuxMemAreaDeepFree(LinuxMemArea *psLinuxMemArea)
case LINUX_MEM_AREA_IOREMAP:
FreeIORemapLinuxMemArea(psLinuxMemArea);
break;
- case LINUX_MEM_AREA_EXTERNAL_KV:
- FreeExternalKVLinuxMemArea(psLinuxMemArea);
- break;
+ case LINUX_MEM_AREA_EXTERNAL_KV:
+ FreeExternalKVLinuxMemArea(psLinuxMemArea);
+ break;
case LINUX_MEM_AREA_IO:
FreeIOLinuxMemArea(psLinuxMemArea);
break;
case LINUX_MEM_AREA_SUB_ALLOC:
FreeSubLinuxMemArea(psLinuxMemArea);
break;
+ case LINUX_MEM_AREA_ION:
+ FreeIONLinuxMemArea(psLinuxMemArea);
+ break;
default:
PVR_DPF((PVR_DBG_ERROR, "%s: Unknown are type (%d)\n",
__FUNCTION__, psLinuxMemArea->eAreaType));
@@ -1320,21 +1832,21 @@ DebugLinuxMemAreaRecordAdd(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32Flags)
LinuxLockMutex(&g_sDebugMutex);
- if(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC)
+ if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC)
{
g_LinuxMemAreaWaterMark += psLinuxMemArea->ui32ByteSize;
- if(g_LinuxMemAreaWaterMark > g_LinuxMemAreaHighWaterMark)
+ if (g_LinuxMemAreaWaterMark > g_LinuxMemAreaHighWaterMark)
{
g_LinuxMemAreaHighWaterMark = g_LinuxMemAreaWaterMark;
}
}
g_LinuxMemAreaCount++;
-
+ /* Create a new memory allocation record */
psNewRecord = kmalloc(sizeof(DEBUG_LINUX_MEM_AREA_REC), GFP_KERNEL);
- if(psNewRecord)
+ if (psNewRecord)
{
-
+ /* Record the allocation */
psNewRecord->psLinuxMemArea = psLinuxMemArea;
psNewRecord->ui32Flags = ui32Flags;
psNewRecord->pid = OSGetCurrentProcessIDKM();
@@ -1348,16 +1860,16 @@ DebugLinuxMemAreaRecordAdd(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32Flags)
__FUNCTION__));
}
-
+ /* Sanity check the flags */
pi8FlagsString = HAPFlagsToString(ui32Flags);
- if(strstr(pi8FlagsString, "UNKNOWN"))
+ if (strstr(pi8FlagsString, "UNKNOWN"))
{
PVR_DPF((PVR_DBG_ERROR,
"%s: Unexpected flags (0x%08x) associated with psLinuxMemArea @ %p",
__FUNCTION__,
ui32Flags,
psLinuxMemArea));
-
+ //dump_stack();
}
LinuxUnLockMutex(&g_sDebugMutex);
@@ -1371,7 +1883,7 @@ static IMG_VOID* MatchLinuxMemArea_AnyVaCb(DEBUG_LINUX_MEM_AREA_REC *psCurrentRe
LinuxMemArea *psLinuxMemArea;
psLinuxMemArea = va_arg(va, LinuxMemArea*);
- if(psCurrentRecord->psLinuxMemArea == psLinuxMemArea)
+ if (psCurrentRecord->psLinuxMemArea == psLinuxMemArea)
{
return psCurrentRecord;
}
@@ -1392,6 +1904,7 @@ DebugLinuxMemAreaRecordFind(LinuxMemArea *psLinuxMemArea)
MatchLinuxMemArea_AnyVaCb,
psLinuxMemArea);
+/*exit_unlock:*/
LinuxUnLockMutex(&g_sDebugMutex);
return psCurrentRecord;
@@ -1405,19 +1918,19 @@ DebugLinuxMemAreaRecordRemove(LinuxMemArea *psLinuxMemArea)
LinuxLockMutex(&g_sDebugMutex);
- if(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC)
+ if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC)
{
g_LinuxMemAreaWaterMark -= psLinuxMemArea->ui32ByteSize;
}
g_LinuxMemAreaCount--;
-
+ /* Locate the corresponding allocation entry */
psCurrentRecord = List_DEBUG_LINUX_MEM_AREA_REC_Any_va(g_LinuxMemAreaRecords,
MatchLinuxMemArea_AnyVaCb,
psLinuxMemArea);
- if(psCurrentRecord)
+ if (psCurrentRecord)
{
-
+ /* Unlink the allocation record */
List_DEBUG_LINUX_MEM_AREA_REC_Remove(psCurrentRecord);
kfree(psCurrentRecord);
}
@@ -1439,7 +1952,7 @@ LinuxMemAreaToCpuVAddr(LinuxMemArea *psLinuxMemArea)
{
return NULL;
}
- switch(psLinuxMemArea->eAreaType)
+ switch (psLinuxMemArea->eAreaType)
{
case LINUX_MEM_AREA_VMALLOC:
return psLinuxMemArea->uData.sVmalloc.pvVmallocAddress;
@@ -1450,8 +1963,8 @@ LinuxMemAreaToCpuVAddr(LinuxMemArea *psLinuxMemArea)
case LINUX_MEM_AREA_SUB_ALLOC:
{
IMG_CHAR *pAddr =
- LinuxMemAreaToCpuVAddr(psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea);
- if(!pAddr)
+ LinuxMemAreaToCpuVAddr(psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea); /* PRQA S 3670 */ /* ignore recursive warning */
+ if (!pAddr)
{
return NULL;
}
@@ -1473,7 +1986,7 @@ LinuxMemAreaToCpuPAddr(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32ByteOffset)
return CpuPAddr;
}
- switch(psLinuxMemArea->eAreaType)
+ switch (psLinuxMemArea->eAreaType)
{
case LINUX_MEM_AREA_IOREMAP:
{
@@ -1513,11 +2026,18 @@ LinuxMemAreaToCpuPAddr(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32ByteOffset)
CpuPAddr.uiAddr = VMallocToPhys(pCpuVAddr);
break;
}
+ case LINUX_MEM_AREA_ION:
+ {
+ IMG_UINT32 ui32PageIndex = PHYS_TO_PFN(ui32ByteOffset);
+ CpuPAddr = psLinuxMemArea->uData.sIONTilerAlloc.pCPUPhysAddrs[ui32PageIndex];
+ CpuPAddr.uiAddr += ADDR_TO_PAGE_OFFSET(ui32ByteOffset);
+ break;
+ }
case LINUX_MEM_AREA_ALLOC_PAGES:
{
struct page *page;
IMG_UINT32 ui32PageIndex = PHYS_TO_PFN(ui32ByteOffset);
- page = psLinuxMemArea->uData.sPageList.pvPageList[ui32PageIndex];
+ page = psLinuxMemArea->uData.sPageList.ppsPageList[ui32PageIndex];
CpuPAddr.uiAddr = page_to_phys(page);
CpuPAddr.uiAddr += ADDR_TO_PAGE_OFFSET(ui32ByteOffset);
break;
@@ -1546,22 +2066,23 @@ LinuxMemAreaToCpuPAddr(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32ByteOffset)
IMG_BOOL
LinuxMemAreaPhysIsContig(LinuxMemArea *psLinuxMemArea)
{
- switch(psLinuxMemArea->eAreaType)
+ switch (psLinuxMemArea->eAreaType)
{
case LINUX_MEM_AREA_IOREMAP:
case LINUX_MEM_AREA_IO:
return IMG_TRUE;
- case LINUX_MEM_AREA_EXTERNAL_KV:
- return psLinuxMemArea->uData.sExternalKV.bPhysContig;
+ case LINUX_MEM_AREA_EXTERNAL_KV:
+ return psLinuxMemArea->uData.sExternalKV.bPhysContig;
+ case LINUX_MEM_AREA_ION:
case LINUX_MEM_AREA_VMALLOC:
case LINUX_MEM_AREA_ALLOC_PAGES:
- return IMG_FALSE;
+ return IMG_FALSE;
case LINUX_MEM_AREA_SUB_ALLOC:
-
- return LinuxMemAreaPhysIsContig(psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea);
+ /* PRQA S 3670 1 */ /* ignore recursive warning */
+ return LinuxMemAreaPhysIsContig(psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea);
default:
PVR_DPF((PVR_DBG_ERROR, "%s: Unknown LinuxMemArea type (%d)\n",
@@ -1575,8 +2096,10 @@ LinuxMemAreaPhysIsContig(LinuxMemArea *psLinuxMemArea)
const IMG_CHAR *
LinuxMemAreaTypeToString(LINUX_MEM_AREA_TYPE eMemAreaType)
{
-
- switch(eMemAreaType)
+ /* Note we explicitly check the types instead of e.g.
+ * using the type to index an array of strings so
+ * we remain orthogonal to enum changes */
+ switch (eMemAreaType)
{
case LINUX_MEM_AREA_IOREMAP:
return "LINUX_MEM_AREA_IOREMAP";
@@ -1590,6 +2113,8 @@ LinuxMemAreaTypeToString(LINUX_MEM_AREA_TYPE eMemAreaType)
return "LINUX_MEM_AREA_SUB_ALLOC";
case LINUX_MEM_AREA_ALLOC_PAGES:
return "LINUX_MEM_AREA_ALLOC_PAGES";
+ case LINUX_MEM_AREA_ION:
+ return "LINUX_MEM_AREA_ION";
default:
PVR_ASSERT(0);
}
@@ -1601,7 +2126,7 @@ LinuxMemAreaTypeToString(LINUX_MEM_AREA_TYPE eMemAreaType)
#if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
static void ProcSeqStartstopDebugMutex(struct seq_file *sfile, IMG_BOOL start)
{
- if(start)
+ if (start)
{
LinuxLockMutex(&g_sDebugMutex);
}
@@ -1610,7 +2135,7 @@ static void ProcSeqStartstopDebugMutex(struct seq_file *sfile, IMG_BOOL start)
LinuxUnLockMutex(&g_sDebugMutex);
}
}
-#endif
+#endif /* defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) */
#if defined(DEBUG_LINUX_MEM_AREAS)
@@ -1627,7 +2152,7 @@ static IMG_VOID* DecOffMemAreaRec_AnyVaCb(DEBUG_LINUX_MEM_AREA_REC *psNode, va_l
}
}
-
+/* seq_file version of generating output, for reference check proc.c:CreateProcReadEntrySeq */
static void* ProcSeqNextMemArea(struct seq_file *sfile,void* el,loff_t off)
{
DEBUG_LINUX_MEM_AREA_REC *psRecord;
@@ -1641,7 +2166,7 @@ static void* ProcSeqNextMemArea(struct seq_file *sfile,void* el,loff_t off)
static void* ProcSeqOff2ElementMemArea(struct seq_file * sfile, loff_t off)
{
DEBUG_LINUX_MEM_AREA_REC *psRecord;
- if(!off)
+ if (!off)
{
return PVR_PROC_SEQ_START_TOKEN;
}
@@ -1657,11 +2182,11 @@ static void* ProcSeqOff2ElementMemArea(struct seq_file * sfile, loff_t off)
static void ProcSeqShowMemArea(struct seq_file *sfile,void* el)
{
DEBUG_LINUX_MEM_AREA_REC *psRecord = (DEBUG_LINUX_MEM_AREA_REC*)el;
- if(el == PVR_PROC_SEQ_START_TOKEN)
+ if (el == PVR_PROC_SEQ_START_TOKEN)
{
#if !defined(DEBUG_LINUX_XML_PROC_FILES)
- seq_printf( sfile,
+ seq_printf(sfile,
"Number of Linux Memory Areas: %u\n"
"At the current water mark these areas correspond to %u bytes (excluding SUB areas)\n"
"At the highest water mark these areas corresponded to %u bytes (excluding SUB areas)\n"
@@ -1677,23 +2202,23 @@ static void ProcSeqShowMemArea(struct seq_file *sfile,void* el)
"Bytes",
"Pid",
"Flags"
- );
+ );
#else
- seq_printf( sfile,
+ seq_printf(sfile,
"<mem_areas_header>\n"
"\t<count>%u</count>\n"
- "\t<watermark key=\"mar0\" description=\"current\" bytes=\"%u\"/>\n"
- "\t<watermark key=\"mar1\" description=\"high\" bytes=\"%u\"/>\n"
+ "\t<watermark key=\"mar0\" description=\"current\" bytes=\"%u\"/>\n" /* (excluding SUB areas) */
+ "\t<watermark key=\"mar1\" description=\"high\" bytes=\"%u\"/>\n" /* (excluding SUB areas) */
"</mem_areas_header>\n",
g_LinuxMemAreaCount,
g_LinuxMemAreaWaterMark,
g_LinuxMemAreaHighWaterMark
- );
+ );
#endif
return;
}
- seq_printf( sfile,
+ seq_printf(sfile,
#if !defined(DEBUG_LINUX_XML_PROC_FILES)
"%8p %-24s %8p %08x %-8d %-5u %08x=(%s)\n",
#else
@@ -1702,9 +2227,9 @@ static void ProcSeqShowMemArea(struct seq_file *sfile,void* el)
"\t<type>%s</type>\n"
"\t<cpu_virtual>%8p</cpu_virtual>\n"
"\t<cpu_physical>%08x</cpu_physical>\n"
- "\t<bytes>%ld</bytes>\n"
+ "\t<bytes>%d</bytes>\n"
"\t<pid>%u</pid>\n"
- "\t<flags>%08lx</flags>\n"
+ "\t<flags>%08x</flags>\n"
"\t<flags_string>%s</flags_string>\n"
"</linux_mem_area>\n",
#endif
@@ -1716,11 +2241,11 @@ static void ProcSeqShowMemArea(struct seq_file *sfile,void* el)
psRecord->pid,
psRecord->ui32Flags,
HAPFlagsToString(psRecord->ui32Flags)
- );
+ );
}
-#endif
+#endif /* DEBUG_LINUX_MEM_AREAS */
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
@@ -1739,7 +2264,7 @@ static IMG_VOID* DecOffMemAllocRec_AnyVaCb(DEBUG_MEM_ALLOC_REC *psNode, va_list
}
-
+/* seq_file version of generating output, for reference check proc.c:CreateProcReadEntrySeq */
static void* ProcSeqNextMemoryRecords(struct seq_file *sfile,void* el,loff_t off)
{
DEBUG_MEM_ALLOC_REC *psRecord;
@@ -1748,9 +2273,9 @@ static void* ProcSeqNextMemoryRecords(struct seq_file *sfile,void* el,loff_t off
DecOffMemAllocRec_AnyVaCb,
&off);
#if defined(DEBUG_LINUX_XML_PROC_FILES)
- if(!psRecord)
+ if (!psRecord)
{
- seq_printf( sfile, "</meminfo>\n");
+ seq_printf(sfile, "</meminfo>\n");
}
#endif
@@ -1760,7 +2285,7 @@ static void* ProcSeqNextMemoryRecords(struct seq_file *sfile,void* el,loff_t off
static void* ProcSeqOff2ElementMemoryRecords(struct seq_file *sfile, loff_t off)
{
DEBUG_MEM_ALLOC_REC *psRecord;
- if(!off)
+ if (!off)
{
return PVR_PROC_SEQ_START_TOKEN;
}
@@ -1771,9 +2296,9 @@ static void* ProcSeqOff2ElementMemoryRecords(struct seq_file *sfile, loff_t off)
&off);
#if defined(DEBUG_LINUX_XML_PROC_FILES)
- if(!psRecord)
+ if (!psRecord)
{
- seq_printf( sfile, "</meminfo>\n");
+ seq_printf(sfile, "</meminfo>\n");
}
#endif
@@ -1783,64 +2308,78 @@ static void* ProcSeqOff2ElementMemoryRecords(struct seq_file *sfile, loff_t off)
static void ProcSeqShowMemoryRecords(struct seq_file *sfile,void* el)
{
DEBUG_MEM_ALLOC_REC *psRecord = (DEBUG_MEM_ALLOC_REC*)el;
- if(el == PVR_PROC_SEQ_START_TOKEN)
+ if (el == PVR_PROC_SEQ_START_TOKEN)
{
#if !defined(DEBUG_LINUX_XML_PROC_FILES)
-
- seq_printf( sfile, "%-60s: %d bytes\n",
+ /* NOTE: If you update this code, please also update the XML varient below
+ * too! */
+
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Current Water Mark of bytes allocated via kmalloc",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMALLOC]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Highest Water Mark of bytes allocated via kmalloc",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMALLOC]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Current Water Mark of bytes allocated via vmalloc",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMALLOC]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Highest Water Mark of bytes allocated via vmalloc",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMALLOC]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Current Water Mark of bytes allocated via alloc_pages",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Highest Water Mark of bytes allocated via alloc_pages",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Current Water Mark of bytes allocated via ioremap",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_IOREMAP]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Highest Water Mark of bytes allocated via ioremap",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_IOREMAP]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Current Water Mark of bytes reserved for \"IO\" memory areas",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_IO]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Highest Water Mark of bytes allocated for \"IO\" memory areas",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_IO]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Current Water Mark of bytes allocated via kmem_cache_alloc",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE]);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"Highest Water Mark of bytes allocated via kmem_cache_alloc",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE]);
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ seq_printf(sfile, "%-60s: %d bytes\n",
+ "Current Water Mark of bytes mapped via vmap",
+ g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMAP]);
+ seq_printf(sfile, "%-60s: %d bytes\n",
+ "Highest Water Mark of bytes mapped via vmap",
+ g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMAP]);
+#endif
+#if (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0)
+ seq_printf(sfile, "%-60s: %d pages\n",
+ "Number of pages in page pool",
+ atomic_read(&g_sPagePoolEntryCount));
+#endif
seq_printf( sfile, "\n");
-
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"The Current Water Mark for memory allocated from system RAM",
- g_SysRAMWaterMark);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ SysRAMTrueWaterMark());
+ seq_printf(sfile, "%-60s: %d bytes\n",
"The Highest Water Mark for memory allocated from system RAM",
g_SysRAMHighWaterMark);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"The Current Water Mark for memory allocated from IO memory",
g_IOMemWaterMark);
- seq_printf( sfile, "%-60s: %d bytes\n",
+ seq_printf(sfile, "%-60s: %d bytes\n",
"The Highest Water Mark for memory allocated from IO memory",
g_IOMemHighWaterMark);
seq_printf( sfile, "\n");
- seq_printf( sfile, "Details for all known allocations:\n"
+ seq_printf(sfile, "Details for all known allocations:\n"
"%-16s %-8s %-8s %-10s %-5s %-10s %s\n",
"Type",
"CpuVAddr",
@@ -1850,70 +2389,84 @@ static void ProcSeqShowMemoryRecords(struct seq_file *sfile,void* el)
"PrivateData",
"Filename:Line");
-#else
-
+#else /* DEBUG_LINUX_XML_PROC_FILES */
- seq_printf( sfile, "<meminfo>\n<meminfo_header>\n");
- seq_printf( sfile,
+ /* Note: If you want to update the description property of a watermark
+ * ensure that the key property remains unchanged so that watermark data
+ * logged over time from different driver revisions may remain comparable
+ */
+ seq_printf(sfile, "<meminfo>\n<meminfo_header>\n");
+ seq_printf(sfile,
"<watermark key=\"mr0\" description=\"kmalloc_current\" bytes=\"%d\"/>\n",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMALLOC]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr1\" description=\"kmalloc_high\" bytes=\"%d\"/>\n",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMALLOC]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr2\" description=\"vmalloc_current\" bytes=\"%d\"/>\n",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMALLOC]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr3\" description=\"vmalloc_high\" bytes=\"%d\"/>\n",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMALLOC]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr4\" description=\"alloc_pages_current\" bytes=\"%d\"/>\n",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr5\" description=\"alloc_pages_high\" bytes=\"%d\"/>\n",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr6\" description=\"ioremap_current\" bytes=\"%d\"/>\n",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_IOREMAP]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr7\" description=\"ioremap_high\" bytes=\"%d\"/>\n",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_IOREMAP]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr8\" description=\"io_current\" bytes=\"%d\"/>\n",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_IO]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr9\" description=\"io_high\" bytes=\"%d\"/>\n",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_IO]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr10\" description=\"kmem_cache_current\" bytes=\"%d\"/>\n",
g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE]);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr11\" description=\"kmem_cache_high\" bytes=\"%d\"/>\n",
g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE]);
- seq_printf( sfile,"\n" );
-
- seq_printf( sfile,
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ seq_printf(sfile,
+ "<watermark key=\"mr12\" description=\"vmap_current\" bytes=\"%d\"/>\n",
+ g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMAP]);
+ seq_printf(sfile,
+ "<watermark key=\"mr13\" description=\"vmap_high\" bytes=\"%d\"/>\n",
+ g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMAP]);
+#endif
+ seq_printf(sfile,
"<watermark key=\"mr14\" description=\"system_ram_current\" bytes=\"%d\"/>\n",
- g_SysRAMWaterMark);
- seq_printf( sfile,
+ SysRAMTrueWaterMark());
+ seq_printf(sfile,
"<watermark key=\"mr15\" description=\"system_ram_high\" bytes=\"%d\"/>\n",
g_SysRAMHighWaterMark);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr16\" description=\"system_io_current\" bytes=\"%d\"/>\n",
g_IOMemWaterMark);
- seq_printf( sfile,
+ seq_printf(sfile,
"<watermark key=\"mr17\" description=\"system_io_high\" bytes=\"%d\"/>\n",
g_IOMemHighWaterMark);
- seq_printf( sfile, "</meminfo_header>\n");
+#if (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0)
+ seq_printf(sfile,
+ "<watermark key=\"mr18\" description=\"page_pool_current\" bytes=\"%d\"/>\n",
+ PAGES_TO_BYTES(atomic_read(&g_sPagePoolEntryCount)));
+#endif
+ seq_printf(sfile, "</meminfo_header>\n");
-#endif
+#endif /* DEBUG_LINUX_XML_PROC_FILES */
return;
}
- if(psRecord->eAllocType != DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE)
+ if (psRecord->eAllocType != DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE)
{
- seq_printf( sfile,
+ seq_printf(sfile,
#if !defined(DEBUG_LINUX_XML_PROC_FILES)
"%-16s %-8p %08x %-10d %-5d %-10s %s:%d\n",
#else
@@ -1939,7 +2492,7 @@ static void ProcSeqShowMemoryRecords(struct seq_file *sfile,void* el)
}
else
{
- seq_printf( sfile,
+ seq_printf(sfile,
#if !defined(DEBUG_LINUX_XML_PROC_FILES)
"%-16s %-8p %08x %-10d %-5d %-10s %s:%d\n",
#else
@@ -1965,10 +2518,11 @@ static void ProcSeqShowMemoryRecords(struct seq_file *sfile,void* el)
}
}
-#endif
+#endif /* defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) */
#if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MMAP_AREAS)
+/* This could be moved somewhere more general */
const IMG_CHAR *
HAPFlagsToString(IMG_UINT32 ui32Flags)
{
@@ -1978,7 +2532,6 @@ HAPFlagsToString(IMG_UINT32 ui32Flags)
IMG_CHAR *apszCacheTypes[] = {
"UNCACHED",
"CACHED",
- "SMART",
"WRITECOMBINE",
"UNKNOWN"
};
@@ -1991,33 +2544,35 @@ HAPFlagsToString(IMG_UINT32 ui32Flags)
"UNKNOWN"
};
-
- if(ui32Flags & PVRSRV_HAP_UNCACHED){
- ui32CacheTypeIndex=0;
- }else if(ui32Flags & PVRSRV_HAP_CACHED){
- ui32CacheTypeIndex=1;
- }else if(ui32Flags & PVRSRV_HAP_SMART){
- ui32CacheTypeIndex=2;
- }else if(ui32Flags & PVRSRV_HAP_WRITECOMBINE){
- ui32CacheTypeIndex=3;
- }else{
- ui32CacheTypeIndex=4;
+ /* FIXME create an enum for the cache type that we can
+ * cast and select so we get compiler warnings when
+ * when this code isn't complete due to new flags */
+ if (ui32Flags & PVRSRV_HAP_UNCACHED) {
+ ui32CacheTypeIndex = 0;
+ } else if (ui32Flags & PVRSRV_HAP_CACHED) {
+ ui32CacheTypeIndex = 1;
+ } else if (ui32Flags & PVRSRV_HAP_WRITECOMBINE) {
+ ui32CacheTypeIndex = 2;
+ } else {
+ ui32CacheTypeIndex = 3;
PVR_DPF((PVR_DBG_ERROR, "%s: unknown cache type (%u)",
__FUNCTION__, (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK)));
}
-
- if(ui32Flags & PVRSRV_HAP_KERNEL_ONLY){
+ /* FIXME create an enum for the map type that we can
+ * cast and select so we get compiler warnings when
+ * when this code isn't complete due to new flags */
+ if (ui32Flags & PVRSRV_HAP_KERNEL_ONLY) {
ui32MapTypeIndex = 0;
- }else if(ui32Flags & PVRSRV_HAP_SINGLE_PROCESS){
+ } else if (ui32Flags & PVRSRV_HAP_SINGLE_PROCESS) {
ui32MapTypeIndex = 1;
- }else if(ui32Flags & PVRSRV_HAP_MULTI_PROCESS){
+ } else if (ui32Flags & PVRSRV_HAP_MULTI_PROCESS) {
ui32MapTypeIndex = 2;
- }else if(ui32Flags & PVRSRV_HAP_FROM_EXISTING_PROCESS){
+ } else if (ui32Flags & PVRSRV_HAP_FROM_EXISTING_PROCESS) {
ui32MapTypeIndex = 3;
- }else if(ui32Flags & PVRSRV_HAP_NO_CPU_VIRTUAL){
+ } else if (ui32Flags & PVRSRV_HAP_NO_CPU_VIRTUAL) {
ui32MapTypeIndex = 4;
- }else{
+ } else {
ui32MapTypeIndex = 5;
PVR_DPF((PVR_DBG_ERROR, "%s: unknown map type (%u)",
__FUNCTION__, (ui32Flags & PVRSRV_HAP_MAPTYPE_MASK)));
@@ -2039,3 +2594,222 @@ HAPFlagsToString(IMG_UINT32 ui32Flags)
}
#endif
+#if defined(DEBUG_LINUX_MEM_AREAS)
+static IMG_VOID LinuxMMCleanup_MemAreas_ForEachCb(DEBUG_LINUX_MEM_AREA_REC *psCurrentRecord)
+{
+ LinuxMemArea *psLinuxMemArea;
+
+ psLinuxMemArea = psCurrentRecord->psLinuxMemArea;
+ PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: Cleaning up Linux memory area (%p), type=%s, size=%d bytes",
+ __FUNCTION__,
+ psCurrentRecord->psLinuxMemArea,
+ LinuxMemAreaTypeToString(psCurrentRecord->psLinuxMemArea->eAreaType),
+ psCurrentRecord->psLinuxMemArea->ui32ByteSize));
+ /* Note this will also remove psCurrentRecord from g_LinuxMemAreaRecords
+ * but that's ok since we have already got a pointer to the next area. */
+ LinuxMemAreaDeepFree(psLinuxMemArea);
+}
+#endif
+
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+static IMG_VOID LinuxMMCleanup_MemRecords_ForEachVa(DEBUG_MEM_ALLOC_REC *psCurrentRecord)
+
+{
+
+/* It's a bug if anything remains allocated at this point. We
+ * report an error, and simply brute force free anything we find. */
+ PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: Cleaning up memory: "
+ "type=%s "
+ "CpuVAddr=%p "
+ "CpuPAddr=0x%08x, "
+ "allocated @ file=%s,line=%d",
+ __FUNCTION__,
+ DebugMemAllocRecordTypeToString(psCurrentRecord->eAllocType),
+ psCurrentRecord->pvCpuVAddr,
+ psCurrentRecord->ulCpuPAddr,
+ psCurrentRecord->pszFileName,
+ psCurrentRecord->ui32Line));
+ switch (psCurrentRecord->eAllocType)
+ {
+ case DEBUG_MEM_ALLOC_TYPE_KMALLOC:
+ KFreeWrapper(psCurrentRecord->pvCpuVAddr);
+ break;
+ case DEBUG_MEM_ALLOC_TYPE_IOREMAP:
+ IOUnmapWrapper(psCurrentRecord->pvCpuVAddr);
+ break;
+ case DEBUG_MEM_ALLOC_TYPE_IO:
+ /* Nothing needed except to free the record */
+ DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_IO, psCurrentRecord->pvKey, __FILE__, __LINE__);
+ break;
+ case DEBUG_MEM_ALLOC_TYPE_VMALLOC:
+ VFreeWrapper(psCurrentRecord->pvCpuVAddr);
+ break;
+ case DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES:
+ DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, psCurrentRecord->pvKey, __FILE__, __LINE__);
+ break;
+ case DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE:
+ KMemCacheFreeWrapper(psCurrentRecord->pvPrivateData, psCurrentRecord->pvCpuVAddr);
+ break;
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ case DEBUG_MEM_ALLOC_TYPE_VMAP:
+ VUnmapWrapper(psCurrentRecord->pvCpuVAddr);
+ break;
+#endif
+ default:
+ PVR_ASSERT(0);
+ }
+}
+#endif
+
+
+#if defined(PVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK)
+static struct shrinker g_sShrinker =
+{
+ .shrink = ShrinkPagePool,
+ .seeks = DEFAULT_SEEKS
+};
+
+static IMG_BOOL g_bShrinkerRegistered;
+#endif
+
+IMG_VOID
+LinuxMMCleanup(IMG_VOID)
+{
+#if defined(DEBUG_LINUX_MEM_AREAS)
+ {
+ if (g_LinuxMemAreaCount)
+ {
+ PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: There are %d LinuxMemArea allocation unfreed (%d bytes)",
+ __FUNCTION__, g_LinuxMemAreaCount, g_LinuxMemAreaWaterMark));
+ }
+
+ List_DEBUG_LINUX_MEM_AREA_REC_ForEach(g_LinuxMemAreaRecords, LinuxMMCleanup_MemAreas_ForEachCb);
+
+ if (g_SeqFileMemArea)
+ {
+ RemoveProcEntrySeq(g_SeqFileMemArea);
+ }
+ }
+#endif
+
+#if defined(PVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK)
+ if (g_bShrinkerRegistered)
+ {
+ unregister_shrinker(&g_sShrinker);
+ }
+#endif
+
+ /*
+ * The page pool must be freed after any remaining mem areas, but before
+ * the remaining memory resources.
+ */
+ FreePagePool();
+
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+ {
+
+ /*
+ * It's a bug if anything remains allocated at this point. We
+ * report an error, and simply brute force free anything we find.
+ */
+ List_DEBUG_MEM_ALLOC_REC_ForEach(g_MemoryRecords, LinuxMMCleanup_MemRecords_ForEachVa);
+
+ if (g_SeqFileMemoryRecords)
+ {
+ RemoveProcEntrySeq(g_SeqFileMemoryRecords);
+ }
+ }
+#endif
+
+ if (g_PsLinuxMemAreaCache)
+ {
+ KMemCacheDestroyWrapper(g_PsLinuxMemAreaCache);
+ }
+
+ if (g_PsLinuxPagePoolCache)
+ {
+ KMemCacheDestroyWrapper(g_PsLinuxPagePoolCache);
+ }
+}
+
+PVRSRV_ERROR
+LinuxMMInit(IMG_VOID)
+{
+#if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+ LinuxInitMutex(&g_sDebugMutex);
+#endif
+
+#if defined(DEBUG_LINUX_MEM_AREAS)
+ {
+ g_SeqFileMemArea = CreateProcReadEntrySeq(
+ "mem_areas",
+ NULL,
+ ProcSeqNextMemArea,
+ ProcSeqShowMemArea,
+ ProcSeqOff2ElementMemArea,
+ ProcSeqStartstopDebugMutex
+ );
+ if (!g_SeqFileMemArea)
+ {
+ goto failed;
+ }
+ }
+#endif
+
+
+#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
+ {
+ g_SeqFileMemoryRecords = CreateProcReadEntrySeq(
+ "meminfo",
+ NULL,
+ ProcSeqNextMemoryRecords,
+ ProcSeqShowMemoryRecords,
+ ProcSeqOff2ElementMemoryRecords,
+ ProcSeqStartstopDebugMutex
+ );
+ if (!g_SeqFileMemoryRecords)
+ {
+ goto failed;
+ }
+ }
+#endif
+
+ g_PsLinuxMemAreaCache = KMemCacheCreateWrapper("img-mm", sizeof(LinuxMemArea), 0, 0);
+ if (!g_PsLinuxMemAreaCache)
+ {
+ PVR_DPF((PVR_DBG_ERROR,"%s: failed to allocate mem area kmem_cache", __FUNCTION__));
+ goto failed;
+ }
+
+#if (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0)
+ g_iPagePoolMaxEntries = PVR_LINUX_MEM_AREA_POOL_MAX_PAGES;
+ if (g_iPagePoolMaxEntries <= 0 || g_iPagePoolMaxEntries > INT_MAX/2)
+ {
+ g_iPagePoolMaxEntries = INT_MAX/2;
+ PVR_TRACE(("%s: No limit set for page pool size", __FUNCTION__));
+ }
+ else
+ {
+ PVR_TRACE(("%s: Maximum page pool size: %d", __FUNCTION__, g_iPagePoolMaxEntries));
+ }
+
+ g_PsLinuxPagePoolCache = KMemCacheCreateWrapper("img-mm-pool", sizeof(LinuxPagePoolEntry), 0, 0);
+ if (!g_PsLinuxPagePoolCache)
+ {
+ PVR_DPF((PVR_DBG_ERROR,"%s: failed to allocate page pool kmem_cache", __FUNCTION__));
+ goto failed;
+ }
+#endif
+
+#if defined(PVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK)
+ register_shrinker(&g_sShrinker);
+ g_bShrinkerRegistered = IMG_TRUE;
+#endif
+
+ return PVRSRV_OK;
+
+failed:
+ LinuxMMCleanup();
+ return PVRSRV_ERROR_OUT_OF_MEMORY;
+}
+
diff --git a/sgx/services4/srvkm/env/linux/mm.h b/sgx/services4/srvkm/env/linux/mm.h
index da49083..2bcf408 100644
--- a/sgx/services4/srvkm/env/linux/mm.h
+++ b/sgx/services4/srvkm/env/linux/mm.h
@@ -1,29 +1,46 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
-
+/*************************************************************************/ /*!
+@Title Linux Memory Management.
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description Declares various memory management utility functions
+ for Linux.
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#ifndef __IMG_LINUX_MM_H__
#define __IMG_LINUX_MM_H__
@@ -48,6 +65,8 @@
#define ADDR_TO_PAGE_OFFSET(addr) (((unsigned long)(addr)) & (PAGE_SIZE - 1))
+#define PAGES_TO_BYTES(pages) ((pages) << PAGE_SHIFT)
+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10))
#define REMAP_PFN_RANGE(vma, addr, pfn, size, prot) remap_pfn_range(vma, addr, pfn, size, prot)
#else
@@ -78,33 +97,43 @@ static inline IMG_UINT32 VMallocToPhys(IMG_VOID *pCpuVAddr)
typedef enum {
LINUX_MEM_AREA_IOREMAP,
- LINUX_MEM_AREA_EXTERNAL_KV,
+ LINUX_MEM_AREA_EXTERNAL_KV,
LINUX_MEM_AREA_IO,
LINUX_MEM_AREA_VMALLOC,
LINUX_MEM_AREA_ALLOC_PAGES,
LINUX_MEM_AREA_SUB_ALLOC,
+ LINUX_MEM_AREA_ION,
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ LINUX_MEM_AREA_VMAP,
+#endif
LINUX_MEM_AREA_TYPE_COUNT
}LINUX_MEM_AREA_TYPE;
typedef struct _LinuxMemArea LinuxMemArea;
+/* FIXME - describe this structure. */
struct _LinuxMemArea {
LINUX_MEM_AREA_TYPE eAreaType;
union _uData
{
struct _sIORemap
{
-
+ /* Note: The memory this represents is _not_ implicitly
+ * page aligned, neither is its size */
IMG_CPU_PHYADDR CPUPhysAddr;
IMG_VOID *pvIORemapCookie;
}sIORemap;
struct _sExternalKV
{
-
+ /* Note: The memory this represents is _not_ implicitly
+ * page aligned, neither is its size */
IMG_BOOL bPhysContig;
union {
-
+ /*
+ * SYSPhysAddr is valid if bPhysContig is true, else
+ * pSysPhysAddr is valid
+ */
IMG_SYS_PHYADDR SysPhysAddr;
IMG_SYS_PHYADDR *pSysPhysAddr;
} uPhysAddr;
@@ -112,44 +141,62 @@ struct _LinuxMemArea {
}sExternalKV;
struct _sIO
{
-
+ /* Note: The memory this represents is _not_ implicitly
+ * page aligned, neither is its size */
IMG_CPU_PHYADDR CPUPhysAddr;
}sIO;
struct _sVmalloc
{
-
+ /* Note the memory this represents _is_ implicitly
+ * page aligned _and_ so is its size */
IMG_VOID *pvVmallocAddress;
+#if defined(PVR_LINUX_MEM_AREA_USE_VMAP)
+ struct page **ppsPageList;
+ IMG_HANDLE hBlockPageList;
+#endif
}sVmalloc;
struct _sPageList
{
-
- struct page **pvPageList;
+ /* Note the memory this represents _is_ implicitly
+ * page aligned _and_ so is its size */
+ struct page **ppsPageList;
IMG_HANDLE hBlockPageList;
}sPageList;
+ struct _sIONTilerAlloc
+ {
+ /* Note the memory this represents _is_ implicitly
+ * page aligned _and_ so is its size */
+ IMG_CPU_PHYADDR *pCPUPhysAddrs;
+ struct ion_handle *psIONHandle[2];
+ }sIONTilerAlloc;
struct _sSubAlloc
{
-
+ /* Note: The memory this represents is _not_ implicitly
+ * page aligned, neither is its size */
LinuxMemArea *psParentLinuxMemArea;
IMG_UINT32 ui32ByteOffset;
}sSubAlloc;
}uData;
- IMG_UINT32 ui32ByteSize;
+ IMG_UINT32 ui32ByteSize; /* Size of memory area */
+
+ IMG_UINT32 ui32AreaFlags; /* Flags passed at creation time */
- IMG_UINT32 ui32AreaFlags;
+ IMG_BOOL bMMapRegistered; /* Registered with mmap code */
- IMG_BOOL bMMapRegistered;
+ IMG_BOOL bNeedsCacheInvalidate; /* Cache should be invalidated on first map? */
- IMG_BOOL bNeedsCacheInvalidate;
+ IMG_HANDLE hBMHandle; /* Handle back to BM for this allocation */
-
+ /* List entry for global list of areas registered for mmap */
struct list_head sMMapItem;
-
+ /*
+ * Head of list of all mmap offset structures associated with this
+ * memory area.
+ */
struct list_head sMMapOffsetStructList;
- IMG_HANDLE hSmartCache;
-
#if defined(SUPPORT_DRI_DRM_EXTERNAL)
IMG_HANDLE buf; /* external buffer handle, like a GEM or ION buffer */
#endif /* SUPPORT_DRI_DRM_EXTERNAL */
@@ -162,12 +209,45 @@ typedef struct kmem_cache LinuxKMemCache;
#endif
+/*!
+ *******************************************************************************
+ * @Function LinuxMMInit
+ *
+ * @Description
+ *
+ * Initialise linux memory management code.
+ * This should be called during services initialisation.
+ *
+ * @Return none
+******************************************************************************/
PVRSRV_ERROR LinuxMMInit(IMG_VOID);
+/*!
+ *******************************************************************************
+ *
+ * @Function LinuxMMCleanup
+ *
+ * @Description
+ *
+ * Cleanup state for the linux memory management code.
+ * This should be called at services cleanup.
+ *
+ * @Return none
+******************************************************************************/
IMG_VOID LinuxMMCleanup(IMG_VOID);
+/*!
+ *******************************************************************************
+ * @brief Wrappers for kmalloc/kfree with optional /proc/pvr/km tracking
+ * They can also be used as more concise replacements for OSAllocMem
+ * in Linux specific code.
+ *
+ * @param ui32ByteSize
+ *
+ * @return
+ ******************************************************************************/
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
#define KMallocWrapper(ui32ByteSize, uFlags) _KMallocWrapper(ui32ByteSize, uFlags, __FILE__, __LINE__)
#else
@@ -176,6 +256,14 @@ IMG_VOID LinuxMMCleanup(IMG_VOID);
IMG_VOID *_KMallocWrapper(IMG_UINT32 ui32ByteSize, gfp_t uFlags, IMG_CHAR *szFileName, IMG_UINT32 ui32Line);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param pvCpuVAddr
+ *
+ * @return
+ ******************************************************************************/
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
#define KFreeWrapper(pvCpuVAddr) _KFreeWrapper(pvCpuVAddr, __FILE__, __LINE__)
#else
@@ -184,6 +272,15 @@ IMG_VOID *_KMallocWrapper(IMG_UINT32 ui32ByteSize, gfp_t uFlags, IMG_CHAR *szFil
IMG_VOID _KFreeWrapper(IMG_VOID *pvCpuVAddr, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param ui32Bytes
+ * @param ui32AllocFlags
+ *
+ * @return
+ ******************************************************************************/
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
#define VMallocWrapper(ui32Bytes, ui32AllocFlags) _VMallocWrapper(ui32Bytes, ui32AllocFlags, __FILE__, __LINE__)
#else
@@ -192,6 +289,14 @@ IMG_VOID _KFreeWrapper(IMG_VOID *pvCpuVAddr, IMG_CHAR *pszFileName, IMG_UINT32 u
IMG_VOID *_VMallocWrapper(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AllocFlags, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param pvCpuVAddr
+ *
+ * @return
+ ******************************************************************************/
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
#define VFreeWrapper(pvCpuVAddr) _VFreeWrapper(pvCpuVAddr, __FILE__, __LINE__)
#else
@@ -200,12 +305,38 @@ IMG_VOID *_VMallocWrapper(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AllocFlags, IMG_C
IMG_VOID _VFreeWrapper(IMG_VOID *pvCpuVAddr, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line);
+/*!
+ *******************************************************************************
+ * @brief Allocates virtually contiguous pages
+ *
+ * @param ui32Bytes number of bytes to reserve
+ * @param ui32AreaFlags Heap caching and mapping Flags
+ *
+ * @return Page-aligned address of virtual allocation or NULL on error
+ ******************************************************************************/
LinuxMemArea *NewVMallocLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags);
+/*!
+ *******************************************************************************
+ * @brief Deallocates virtually contiguous pages
+ *
+ * @param LinuxMemArea from NewVMallocLinuxMemArea
+ *
+ ******************************************************************************/
IMG_VOID FreeVMallocLinuxMemArea(LinuxMemArea *psLinuxMemArea);
+/*!
+ *******************************************************************************
+ * @brief Reserve physical IO memory and create a CPU virtual mapping for it
+ *
+ * @param BasePAddr
+ * @param ui32Bytes
+ * @param ui32MappingFlags
+ *
+ * @return
+ ******************************************************************************/
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
#define IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags) \
_IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags, __FILE__, __LINE__)
@@ -220,17 +351,63 @@ IMG_VOID *_IORemapWrapper(IMG_CPU_PHYADDR BasePAddr,
IMG_UINT32 ui32Line);
+/*!
+ *******************************************************************************
+ * @brief Reserve physical IO memory and create a CPU virtual mapping for it
+ *
+ * @param BasePAddr
+ * @param ui32Bytes
+ * @param ui32AreaFlags Heap caching and mapping Flags
+ *
+ * @return
+ ******************************************************************************/
LinuxMemArea *NewIORemapLinuxMemArea(IMG_CPU_PHYADDR BasePAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psLinuxMemArea
+ *
+ * @return
+ ********************************************************************************/
IMG_VOID FreeIORemapLinuxMemArea(LinuxMemArea *psLinuxMemArea);
+/*!
+ *******************************************************************************
+ * @brief Register physical memory which already has a CPU virtual mapping
+ *
+ * @param pBasePAddr
+ * @param pvCPUVAddr
+ * @param bPhysContig
+ * @param ui32Bytes
+ * @param ui32AreaFlags Heap caching and mapping Flags
+ *
+ * @return
+ ******************************************************************************/
LinuxMemArea *NewExternalKVLinuxMemArea(IMG_SYS_PHYADDR *pBasePAddr, IMG_VOID *pvCPUVAddr, IMG_UINT32 ui32Bytes, IMG_BOOL bPhysContig, IMG_UINT32 ui32AreaFlags);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psLinuxMemArea
+ *
+ * @return
+ ******************************************************************************/
IMG_VOID FreeExternalKVLinuxMemArea(LinuxMemArea *psLinuxMemArea);
+/*!
+ ******************************************************************************
+ * @brief Unmaps an IO memory mapping created using IORemap
+ *
+ * @param pvIORemapCookie
+ *
+ * @return
+ ******************************************************************************/
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
#define IOUnmapWrapper(pvIORemapCookie) \
_IOUnmapWrapper(pvIORemapCookie, __FILE__, __LINE__)
@@ -241,15 +418,52 @@ IMG_VOID FreeExternalKVLinuxMemArea(LinuxMemArea *psLinuxMemArea);
IMG_VOID _IOUnmapWrapper(IMG_VOID *pvIORemapCookie, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psLinuxMemArea
+ * @param ui32ByteOffset
+ *
+ * @return
+ ******************************************************************************/
struct page *LinuxMemAreaOffsetToPage(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32ByteOffset);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param pszName
+ * @param Size
+ * @param Align
+ * @param ui32Flags
+ *
+ * @return
+ ******************************************************************************/
LinuxKMemCache *KMemCacheCreateWrapper(IMG_CHAR *pszName, size_t Size, size_t Align, IMG_UINT32 ui32Flags);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psCache
+ *
+ * @return
+ ******************************************************************************/
IMG_VOID KMemCacheDestroyWrapper(LinuxKMemCache *psCache);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psCache
+ * @param Flags
+ *
+ * @return
+ ******************************************************************************/
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
#define KMemCacheAllocWrapper(psCache, Flags) _KMemCacheAllocWrapper(psCache, Flags, __FILE__, __LINE__)
#else
@@ -262,6 +476,15 @@ IMG_VOID *_KMemCacheAllocWrapper(LinuxKMemCache *psCache, gfp_t Flags, IMG_CHAR
IMG_VOID *_KMemCacheAllocWrapper(LinuxKMemCache *psCache, int Flags, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line);
#endif
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psCache
+ * @param pvObject
+ *
+ * @return
+ ******************************************************************************/
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
#define KMemCacheFreeWrapper(psCache, pvObject) _KMemCacheFreeWrapper(psCache, pvObject, __FILE__, __LINE__)
#else
@@ -270,29 +493,146 @@ IMG_VOID *_KMemCacheAllocWrapper(LinuxKMemCache *psCache, int Flags, IMG_CHAR *p
IMG_VOID _KMemCacheFreeWrapper(LinuxKMemCache *psCache, IMG_VOID *pvObject, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psCache
+ *
+ * @return
+ ******************************************************************************/
const IMG_CHAR *KMemCacheNameWrapper(LinuxKMemCache *psCache);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param BasePAddr
+ * @param ui32Bytes
+ * @param ui32AreaFlags Heap caching and mapping Flags
+ *
+ * @return
+ ******************************************************************************/
LinuxMemArea *NewIOLinuxMemArea(IMG_CPU_PHYADDR BasePAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psLinuxMemArea
+ *
+ * @return
+ ******************************************************************************/
IMG_VOID FreeIOLinuxMemArea(LinuxMemArea *psLinuxMemArea);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param ui32Bytes
+ * @param ui32AreaFlags E.g Heap caching and mapping Flags
+ *
+ * @return
+ ******************************************************************************/
LinuxMemArea *NewAllocPagesLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psLinuxMemArea
+ *
+ * @return
+ ******************************************************************************/
IMG_VOID FreeAllocPagesLinuxMemArea(LinuxMemArea *psLinuxMemArea);
+#if defined(CONFIG_ION_OMAP)
+
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param ui32Bytes
+ * @param ui32AreaFlags E.g Heap caching and mapping Flags
+ *
+ * @return
+ ******************************************************************************/
+LinuxMemArea *
+NewIONLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags,
+ IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength);
+
+
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psLinuxMemArea
+ *
+ * @return
+ ******************************************************************************/
+IMG_VOID FreeIONLinuxMemArea(LinuxMemArea *psLinuxMemArea);
+
+#else /* defined(CONFIG_ION_OMAP) */
+
+static inline LinuxMemArea *
+NewIONLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags,
+ IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength)
+{
+ PVR_UNREFERENCED_PARAMETER(ui32Bytes);
+ PVR_UNREFERENCED_PARAMETER(ui32AreaFlags);
+ PVR_UNREFERENCED_PARAMETER(pvPrivData);
+ PVR_UNREFERENCED_PARAMETER(ui32PrivDataLength);
+ BUG();
+ return IMG_NULL;
+}
+
+static inline IMG_VOID FreeIONLinuxMemArea(LinuxMemArea *psLinuxMemArea)
+{
+ PVR_UNREFERENCED_PARAMETER(psLinuxMemArea);
+ BUG();
+}
+
+#endif /* defined(CONFIG_ION_OMAP) */
+
+
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psParentLinuxMemArea
+ * @param ui32ByteOffset
+ * @param ui32Bytes
+ *
+ * @return
+ ******************************************************************************/
LinuxMemArea *NewSubLinuxMemArea(LinuxMemArea *psParentLinuxMemArea,
IMG_UINT32 ui32ByteOffset,
IMG_UINT32 ui32Bytes);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psLinuxMemArea
+ *
+ * @return
+ ******************************************************************************/
IMG_VOID LinuxMemAreaDeepFree(LinuxMemArea *psLinuxMemArea);
+/*!
+ *******************************************************************************
+ * @brief For debug builds, LinuxMemAreas are tracked in /proc
+ *
+ * @param psLinuxMemArea
+ *
+ ******************************************************************************/
#if defined(LINUX_MEM_AREAS_DEBUG)
IMG_VOID LinuxMemAreaRegister(LinuxMemArea *psLinuxMemArea);
#else
@@ -300,16 +640,49 @@ IMG_VOID LinuxMemAreaRegister(LinuxMemArea *psLinuxMemArea);
#endif
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psLinuxMemArea
+ *
+ * @return
+ ******************************************************************************/
IMG_VOID *LinuxMemAreaToCpuVAddr(LinuxMemArea *psLinuxMemArea);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param psLinuxMemArea
+ * @param ui32ByteOffset
+ *
+ * @return
+ ******************************************************************************/
IMG_CPU_PHYADDR LinuxMemAreaToCpuPAddr(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32ByteOffset);
#define LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32ByteOffset) PHYS_TO_PFN(LinuxMemAreaToCpuPAddr(psLinuxMemArea, ui32ByteOffset).uiAddr)
+/*!
+ *******************************************************************************
+ * @brief Indicate whether a LinuxMemArea is physically contiguous
+ *
+ * @param psLinuxMemArea
+ *
+ * @return IMG_TRUE if the physical address range is contiguous, else IMG_FALSE
+ ******************************************************************************/
IMG_BOOL LinuxMemAreaPhysIsContig(LinuxMemArea *psLinuxMemArea);
+/*!
+ *******************************************************************************
+ * @brief Return the real underlying LinuxMemArea
+ *
+ * @param psLinuxMemArea
+ *
+ * @return The real underlying LinuxMemArea
+ ******************************************************************************/
static inline LinuxMemArea *
LinuxMemAreaRoot(LinuxMemArea *psLinuxMemArea)
{
@@ -324,6 +697,14 @@ LinuxMemAreaRoot(LinuxMemArea *psLinuxMemArea)
}
+/*!
+ *******************************************************************************
+ * @brief Return type of real underlying LinuxMemArea
+ *
+ * @param psLinuxMemArea
+ *
+ * @return The areas eAreaType or for SUB areas; return the parents eAreaType.
+ ******************************************************************************/
static inline LINUX_MEM_AREA_TYPE
LinuxMemAreaRootType(LinuxMemArea *psLinuxMemArea)
{
@@ -331,12 +712,28 @@ LinuxMemAreaRootType(LinuxMemArea *psLinuxMemArea)
}
+/*!
+ *******************************************************************************
+ * @brief Converts the enum type of a LinuxMemArea to a const string
+ *
+ * @param eMemAreaType
+ *
+ * @return const string representation of type
+ ******************************************************************************/
const IMG_CHAR *LinuxMemAreaTypeToString(LINUX_MEM_AREA_TYPE eMemAreaType);
+/*!
+ *******************************************************************************
+ * @brief
+ *
+ * @param ui32Flags
+ *
+ * @return
+ ******************************************************************************/
#if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MMAP_AREAS)
const IMG_CHAR *HAPFlagsToString(IMG_UINT32 ui32Flags);
#endif
-#endif
+#endif /* __IMG_LINUX_MM_H__ */
diff --git a/sgx/services4/srvkm/env/linux/mmap.c b/sgx/services4/srvkm/env/linux/mmap.c
index ca38e5d..6e032dc 100644
--- a/sgx/services4/srvkm/env/linux/mmap.c
+++ b/sgx/services4/srvkm/env/linux/mmap.c
@@ -1,28 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Linux mmap interface
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include <linux/version.h>
@@ -39,6 +55,9 @@
#include <linux/wrapper.h>
#endif
#include <linux/slab.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+#include <linux/highmem.h>
+#endif
#include <asm/io.h>
#include <asm/page.h>
#include <asm/shmparam.h>
@@ -51,15 +70,12 @@
#include <drm/drmP.h>
#endif
-#include "img_defs.h"
-#include "services.h"
-#include "servicesint.h"
+#include "services_headers.h"
+
#include "pvrmmap.h"
#include "mutils.h"
#include "mmap.h"
#include "mm.h"
-#include "pvr_debug.h"
-#include "osfunc.h"
#include "proc.h"
#include "mutex.h"
#include "handle.h"
@@ -74,7 +90,19 @@
#error "The mmap code requires PVR_SECURE_HANDLES"
#endif
-static PVRSRV_LINUX_MUTEX g_sMMapMutex;
+/* WARNING:
+ * The mmap code has its own mutex, to prevent a possible deadlock,
+ * when using gPVRSRVLock.
+ * The Linux kernel takes the mm->mmap_sem before calling the mmap
+ * entry points (PVRMMap, MMapVOpen, MMapVClose), but the ioctl
+ * entry point may take mm->mmap_sem during fault handling, or
+ * before calling get_user_pages. If gPVRSRVLock was used in the
+ * mmap entry points, a deadlock could result, due to the ioctl
+ * and mmap code taking the two locks in different orders.
+ * As a corollary to this, the mmap entry points must not call
+ * any driver code that relies on gPVRSRVLock is held.
+ */
+PVRSRV_LINUX_MUTEX g_sMMapMutex;
static LinuxKMemCache *g_psMemmapCache = NULL;
static LIST_HEAD(g_sMMapAreaList);
@@ -88,9 +116,28 @@ static inline PKV_OFFSET_STRUCT FindOffsetStructByPID(LinuxMemArea *psLinuxMemAr
#if defined(DEBUG_LINUX_MMAP_AREAS)
static struct proc_dir_entry *g_ProcMMap;
-#endif
+#endif /* defined(DEBUG_LINUX_MMAP_AREAS) */
#if !defined(PVR_MAKE_ALL_PFNS_SPECIAL)
+/*
+ * Now that we are using mmap2 in srvclient, almost (*) the full 32
+ * bit offset is available. The range of values is divided into two.
+ * The first part of the range, from FIRST_PHYSICAL_PFN to
+ * LAST_PHYSICAL_PFN, is for raw page mappings (VM_PFNMAP). The
+ * resulting 43 bit (*) physical address range should be enough for
+ * the current range of processors we support.
+ *
+ * NB: (*) -- the above figures assume 4KB page size. The offset
+ * argument to mmap2() is in units of 4,096 bytes regardless of page
+ * size. Thus, we lose (PAGE_SHIFT-12) bits of resolution on other
+ * architectures.
+ *
+ * The second part of the range, from FIRST_SPECIAL_PFN to LAST_SPECIAL_PFN,
+ * is used for all other mappings. These other mappings will always
+ * consist of pages with associated page structures, and need not
+ * represent a contiguous range of physical addresses.
+ *
+ */
#define MMAP2_PGOFF_RESOLUTION (32-PAGE_SHIFT+12)
#define RESERVED_PGOFF_BITS 1
#define MAX_MMAP_HANDLE ((1UL<<(MMAP2_PGOFF_RESOLUTION-RESERVED_PGOFF_BITS))-1)
@@ -100,12 +147,19 @@ static struct proc_dir_entry *g_ProcMMap;
#define FIRST_SPECIAL_PFN (LAST_PHYSICAL_PFN + 1)
#define LAST_SPECIAL_PFN (FIRST_SPECIAL_PFN + MAX_MMAP_HANDLE)
-#else
+#else /* !defined(PVR_MAKE_ALL_PFNS_SPECIAL) */
#if PAGE_SHIFT != 12
#error This build variant has not yet been made non-4KB page-size aware
#endif
+/*
+ * Since we no longer have to worry about clashes with the mmap
+ * offsets used for pure PFN mappings (VM_PFNMAP), there is greater
+ * freedom in choosing the mmap handles. This is useful if the
+ * mmap offset space has to be shared with another driver component.
+ */
+
#if defined(PVR_MMAP_OFFSET_BASE)
#define FIRST_SPECIAL_PFN PVR_MMAP_OFFSET_BASE
#else
@@ -118,21 +172,21 @@ static struct proc_dir_entry *g_ProcMMap;
#define MAX_MMAP_HANDLE 0x7fffffffUL
#endif
-#endif
+#endif /* !defined(PVR_MAKE_ALL_PFNS_SPECIAL) */
#if !defined(PVR_MAKE_ALL_PFNS_SPECIAL)
static inline IMG_BOOL
PFNIsPhysical(IMG_UINT32 pfn)
{
-
- return ( (pfn <= LAST_PHYSICAL_PFN)) ? IMG_TRUE : IMG_FALSE;
+ /* Unsigned, no need to compare >=0 */
+ return (/*(pfn >= FIRST_PHYSICAL_PFN) &&*/ (pfn <= LAST_PHYSICAL_PFN)) ? IMG_TRUE : IMG_FALSE;
}
static inline IMG_BOOL
PFNIsSpecial(IMG_UINT32 pfn)
{
-
- return ((pfn >= FIRST_SPECIAL_PFN) ) ? IMG_TRUE : IMG_FALSE;
+ /* Unsigned, no need to compare <=MAX_UINT */
+ return ((pfn >= FIRST_SPECIAL_PFN) /*&& (pfn <= LAST_SPECIAL_PFN)*/) ? IMG_TRUE : IMG_FALSE;
}
#endif
@@ -169,6 +223,16 @@ HandleToMMapOffset(IMG_HANDLE hHandle)
}
#if !defined(PVR_MAKE_ALL_PFNS_SPECIAL)
+/*
+ * Determine whether physical or special mappings will be used for
+ * a given memory area. At present, this decision is made on
+ * whether the mapping represents a contiguous range of physical
+ * addresses, which is a requirement for raw page mappings (VM_PFNMAP).
+ * In the VMA structure for such a mapping, vm_pgoff is the PFN
+ * (page frame number, the physical address divided by the page size)
+ * of the first page in the VMA. The second page is assumed to have
+ * PFN (vm_pgoff + 1), the third (vm_pgoff + 2) and so on.
+ */
static inline IMG_BOOL
LinuxMemAreaUsesPhysicalMap(LinuxMemArea *psLinuxMemArea)
{
@@ -180,11 +244,18 @@ LinuxMemAreaUsesPhysicalMap(LinuxMemArea *psLinuxMemArea)
static inline IMG_UINT32
GetCurrentThreadID(IMG_VOID)
{
-
+ /*
+ * The PID is the thread ID, as each thread is a
+ * seperate process.
+ */
return (IMG_UINT32)current->pid;
}
#endif
+/*
+ * Create an offset structure, which is used to hold per-process
+ * mmap data.
+ */
static PKV_OFFSET_STRUCT
CreateOffsetStruct(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32Offset, IMG_UINT32 ui32RealByteSize)
{
@@ -216,14 +287,22 @@ CreateOffsetStruct(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32Offset, IMG_UINT
psOffsetStruct->ui32RealByteSize = ui32RealByteSize;
-
+ /*
+ * We store the TID in case two threads within a process
+ * generate the same offset structure, and both end up on the
+ * list of structures waiting to be mapped, at the same time.
+ * This could happen if two sub areas within the same page are
+ * being mapped at the same time.
+ * The TID allows the mmap entry point to distinguish which
+ * mapping is being done by which thread.
+ */
#if !defined(PVR_MAKE_ALL_PFNS_SPECIAL)
psOffsetStruct->ui32TID = GetCurrentThreadID();
#endif
psOffsetStruct->ui32PID = OSGetCurrentProcessIDKM();
#if defined(DEBUG_LINUX_MMAP_AREAS)
-
+ /* Extra entries to support proc filesystem debug info */
psOffsetStruct->pszName = pszName;
#endif
@@ -259,6 +338,17 @@ DestroyOffsetStruct(PKV_OFFSET_STRUCT psOffsetStruct)
}
+/*
+ * There are no alignment constraints for mapping requests made by user
+ * mode Services. For this, and potentially other reasons, the
+ * mapping created for a users request may look different to the
+ * original request in terms of size and alignment.
+ *
+ * This function determines an offset that the user can add to the mapping
+ * that is _actually_ created which will point to the memory they are
+ * _really_ interested in.
+ *
+ */
static inline IMG_VOID
DetermineUsersSizeAndByteOffset(LinuxMemArea *psLinuxMemArea,
IMG_UINT32 *pui32RealByteSize,
@@ -337,7 +427,7 @@ create_gem_wrapper(struct drm_device *dev, LinuxMemArea *psLinuxMemArea,
case LINUX_MEM_AREA_ALLOC_PAGES:
pages = kmalloc(sizeof(pages) * npages, GFP_KERNEL);
for (i = 0; i < npages; i++) {
- pages[i] = psLinuxMemArea->uData.sPageList.pvPageList[i + PHYS_TO_PFN(ui32ByteOffset)];
+ pages[i] = psLinuxMemArea->uData.sPageList.ppsPageList[i + PHYS_TO_PFN(ui32ByteOffset)];
}
break;
case LINUX_MEM_AREA_SUB_ALLOC:
@@ -355,7 +445,6 @@ create_gem_wrapper(struct drm_device *dev, LinuxMemArea *psLinuxMemArea,
/* map PVR cache type flags to GEM.. */
switch(psLinuxMemArea->ui32AreaFlags & PVRSRV_HAP_CACHETYPE_MASK) {
case PVRSRV_HAP_CACHED:
- case PVRSRV_HAP_SMART:
flags = OMAP_BO_CACHED;
break;
case PVRSRV_HAP_WRITECOMBINE:
@@ -380,6 +469,33 @@ create_gem_wrapper(struct drm_device *dev, LinuxMemArea *psLinuxMemArea,
#endif /* SUPPORT_DRI_DRM_EXTERNAL */
+/*!
+ *******************************************************************************
+
+ @Function PVRMMapOSMemHandleToMMapData
+
+ @Description
+
+ Determine various parameters needed to mmap a memory area, and to
+ locate the memory within the mapped area.
+
+ @input psPerProc : Per-process data.
+ @input hMHandle : Memory handle.
+ @input pui32MMapOffset : pointer to location for returned mmap offset.
+ @input pui32ByteOffset : pointer to location for returned byte offset.
+ @input pui32RealByteSize : pointer to location for returned real byte size.
+ @input pui32UserVaddr : pointer to location for returned user mode address.
+
+ @output pui32MMapOffset : points to mmap offset to be used in mmap2 sys call.
+ @output pui32ByteOffset : points to byte offset of start of memory
+ within mapped area returned by mmap2.
+ @output pui32RealByteSize : points to size of area to be mapped.
+ @output pui32UserVAddr : points to user mode address of start of
+ mapping, or 0 if it hasn't been mapped yet.
+
+ @Return PVRSRV_ERROR : PVRSRV_OK, or error code.
+
+ ******************************************************************************/
PVRSRV_ERROR
PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
#if defined (SUPPORT_SID_INTERFACE)
@@ -442,24 +558,43 @@ PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
}
#endif /* SUPPORT_DRI_DRM_EXTERNAL */
- DetermineUsersSizeAndByteOffset(psLinuxMemArea,
- pui32RealByteSize,
- pui32ByteOffset);
+ /* Sparse mappings have to ask the BM for the virtual size */
+ if (psLinuxMemArea->hBMHandle)
+ {
+ *pui32RealByteSize = BM_GetVirtualSize(psLinuxMemArea->hBMHandle);
+ *pui32ByteOffset = 0;
+ }
+ else
+ {
+ DetermineUsersSizeAndByteOffset(psLinuxMemArea,
+ pui32RealByteSize,
+ pui32ByteOffset);
+ }
psOffsetStruct = FindOffsetStructByPID(psLinuxMemArea, psPerProc->ui32PID);
if (psOffsetStruct)
{
- PVR_ASSERT(*pui32RealByteSize == psOffsetStruct->ui32RealByteSize);
-
+ if (!psLinuxMemArea->hBMHandle)
+ {
+ PVR_ASSERT(*pui32RealByteSize == psOffsetStruct->ui32RealByteSize);
+ }
+ /*
+ * User mode locking is required to stop two threads racing to
+ * map the same memory area. The lock should prevent a
+ * second thread retrieving mmap data for a given handle,
+ * before the first thread has done the mmap.
+ * Without locking, both threads may attempt the mmap,
+ * and one of them will fail.
+ */
*pui32MMapOffset = psOffsetStruct->ui32MMapOffset;
*pui32UserVAddr = psOffsetStruct->ui32UserVAddr;
- psOffsetStruct->ui32RefCount++;
+ PVRSRVOffsetStructIncRef(psOffsetStruct);
eError = PVRSRV_OK;
goto exit_unlock;
}
-
+ /* Memory area won't have been mapped yet */
*pui32UserVAddr = 0;
#if !defined(PVR_MAKE_ALL_PFNS_SPECIAL)
@@ -495,18 +630,22 @@ PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
goto exit_unlock;
}
-
+ /*
+ * Offset structures representing physical mappings are added to
+ * a list, so that they can be located when the memory area is mapped.
+ */
list_add_tail(&psOffsetStruct->sMMapItem, &g_sMMapOffsetStructList);
psOffsetStruct->bOnMMapList = IMG_TRUE;
- psOffsetStruct->ui32RefCount++;
+ PVRSRVOffsetStructIncRef(psOffsetStruct);
eError = PVRSRV_OK;
-
-
-
+ /* Need to scale up the offset to counter the shifting that
+ is done in the mmap2() syscall, as it expects the pgoff
+ argument to be in units of 4,096 bytes irrespective of
+ page size */
*pui32MMapOffset = *pui32MMapOffset << (PAGE_SHIFT - 12);
exit_unlock:
@@ -517,6 +656,28 @@ exit_unlock:
}
+/*!
+ *******************************************************************************
+
+ @Function PVRMMapReleaseMMapData
+
+ @Description
+
+ Release mmap data.
+
+ @input psPerProc : Per-process data.
+ @input hMHandle : Memory handle.
+ @input pbMUnmap : pointer to location for munmap flag.
+ @input pui32UserVAddr : pointer to location for user mode address of mapping.
+ @input pui32ByteSize : pointer to location for size of mapping.
+
+ @Output pbMUnmap : points to flag that indicates whether an munmap is
+ required.
+ @output pui32UserVAddr : points to user mode address to munmap.
+
+ @Return PVRSRV_ERROR : PVRSRV_OK, or error code.
+
+ ******************************************************************************/
PVRSRV_ERROR
PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
#if defined (SUPPORT_SID_INTERFACE)
@@ -562,7 +723,7 @@ PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
goto exit_unlock;
}
- psOffsetStruct->ui32RefCount--;
+ PVRSRVOffsetStructDecRef(psOffsetStruct);
*pbMUnmap = (IMG_BOOL)((psOffsetStruct->ui32RefCount == 0) && (psOffsetStruct->ui32UserVAddr != 0));
@@ -573,7 +734,7 @@ PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
goto exit_unlock;
}
-
+ /* MMap data not found */
#if defined (SUPPORT_SID_INTERFACE)
PVR_DPF((PVR_DBG_ERROR, "%s: Mapping data not found for handle %x (memory area %p)", __FUNCTION__, hMHandle, psLinuxMemArea));
#else
@@ -602,7 +763,11 @@ FindOffsetStructByOffset(IMG_UINT32 ui32Offset, IMG_UINT32 ui32RealByteSize)
if (ui32Offset == psOffsetStruct->ui32MMapOffset && ui32RealByteSize == psOffsetStruct->ui32RealByteSize && psOffsetStruct->ui32PID == ui32PID)
{
#if !defined(PVR_MAKE_ALL_PFNS_SPECIAL)
-
+ /*
+ * If the offset is physical, make sure the thread IDs match,
+ * as different threads may be mapping different memory areas
+ * with the same offset.
+ */
if (!PFNIsPhysical(ui32Offset) || psOffsetStruct->ui32TID == ui32TID)
#endif
{
@@ -627,7 +792,11 @@ FindOffsetStructByPID(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32PID)
}
return NULL;
}
-
+/*
+ * Map a memory area into user space.
+ * Note, the ui32ByteOffset is _not_ implicitly page aligned since
+ * LINUX_MEM_AREA_SUB_ALLOC LinuxMemAreas have no alignment constraints.
+ */
static IMG_BOOL
DoMapToUser(LinuxMemArea *psLinuxMemArea,
struct vm_area_struct* ps_vma,
@@ -635,19 +804,33 @@ DoMapToUser(LinuxMemArea *psLinuxMemArea,
{
IMG_UINT32 ui32ByteSize;
+ if ((psLinuxMemArea->hBMHandle) && (ui32ByteOffset != 0))
+ {
+ /* Partial mapping of sparse allocations should never happen */
+ return IMG_FALSE;
+ }
+
if (psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC)
{
- return DoMapToUser(LinuxMemAreaRoot(psLinuxMemArea),
+ return DoMapToUser(LinuxMemAreaRoot(psLinuxMemArea), /* PRQA S 3670 */ /* allow recursion */
ps_vma,
psLinuxMemArea->uData.sSubAlloc.ui32ByteOffset + ui32ByteOffset);
}
-
+ /*
+ * Note that ui32ByteSize may be larger than the size of the memory
+ * area being mapped, as the former is a multiple of the page size.
+ */
ui32ByteSize = ps_vma->vm_end - ps_vma->vm_start;
PVR_ASSERT(ADDR_TO_PAGE_OFFSET(ui32ByteSize) == 0);
#if defined (__sparc__)
-
+ /*
+ * For LINUX_MEM_AREA_EXTERNAL_KV, we don't know where the address range
+ * we are being asked to map has come from, that is, whether it is memory
+ * or I/O. For all architectures other than SPARC, there is no distinction.
+ * Since we don't currently support SPARC, we won't worry about it.
+ */
#error "SPARC not supported"
#endif
@@ -658,7 +841,13 @@ DoMapToUser(LinuxMemArea *psLinuxMemArea,
PVR_ASSERT(LinuxMemAreaPhysIsContig(psLinuxMemArea));
PVR_ASSERT(LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32ByteOffset) == ps_vma->vm_pgoff);
-
+ /*
+ * Since the memory is contiguous, we can map the whole range in one
+ * go .
+ */
+
+ PVR_ASSERT(psLinuxMemArea->hBMHandle == IMG_NULL);
+
result = IO_REMAP_PFN_RANGE(ps_vma, ps_vma->vm_start, ps_vma->vm_pgoff, ui32ByteSize, ps_vma->vm_page_prot);
if(result == 0)
@@ -671,27 +860,51 @@ DoMapToUser(LinuxMemArea *psLinuxMemArea,
#endif
{
-
+ /*
+ * Memory may be non-contiguous, so we map the range page,
+ * by page. Since VM_PFNMAP mappings are assumed to be physically
+ * contiguous, we can't legally use REMAP_PFN_RANGE (that is, we
+ * could, but the resulting VMA may confuse other bits of the kernel
+ * that attempt to interpret it).
+ * The only alternative is to use VM_INSERT_PAGE, which requires
+ * finding the page structure corresponding to each page, or
+ * if mixed maps are supported (VM_MIXEDMAP), vm_insert_mixed.
+ */
IMG_UINT32 ulVMAPos;
IMG_UINT32 ui32ByteEnd = ui32ByteOffset + ui32ByteSize;
IMG_UINT32 ui32PA;
+ IMG_UINT32 ui32AdjustedPA = ui32ByteOffset;
#if defined(PVR_MAKE_ALL_PFNS_SPECIAL)
IMG_BOOL bMixedMap = IMG_FALSE;
#endif
-
+ /* First pass, validate the page frame numbers */
for(ui32PA = ui32ByteOffset; ui32PA < ui32ByteEnd; ui32PA += PAGE_SIZE)
{
- IMG_UINT32 pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32PA);
+ IMG_UINT32 pfn;
+ IMG_BOOL bMapPage = IMG_TRUE;
- if (!pfn_valid(pfn))
- {
+ if (psLinuxMemArea->hBMHandle)
+ {
+ if (!BM_MapPageAtOffset(psLinuxMemArea->hBMHandle, ui32PA))
+ {
+ bMapPage = IMG_FALSE;
+ }
+ }
+
+ if (bMapPage)
+ {
+ pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32AdjustedPA);
+ if (!pfn_valid(pfn))
+ {
#if !defined(PVR_MAKE_ALL_PFNS_SPECIAL)
- PVR_DPF((PVR_DBG_ERROR,"%s: Error - PFN invalid: 0x%x", __FUNCTION__, pfn));
- return IMG_FALSE;
+ PVR_DPF((PVR_DBG_ERROR,"%s: Error - PFN invalid: 0x%x", __FUNCTION__, pfn));
+ return IMG_FALSE;
#else
- bMixedMap = IMG_TRUE;
+ bMixedMap = IMG_TRUE;
#endif
- }
+ }
+ ui32AdjustedPA += PAGE_SIZE;
+ }
}
#if defined(PVR_MAKE_ALL_PFNS_SPECIAL)
@@ -700,43 +913,58 @@ DoMapToUser(LinuxMemArea *psLinuxMemArea,
ps_vma->vm_flags |= VM_MIXEDMAP;
}
#endif
-
+ /* Second pass, get the page structures and insert the pages */
ulVMAPos = ps_vma->vm_start;
+ ui32AdjustedPA = ui32ByteOffset;
for(ui32PA = ui32ByteOffset; ui32PA < ui32ByteEnd; ui32PA += PAGE_SIZE)
{
IMG_UINT32 pfn;
IMG_INT result;
+ IMG_BOOL bMapPage = IMG_TRUE;
+
+ if (psLinuxMemArea->hBMHandle)
+ {
+ /* We have a sparse allocation, check if this page should be mapped */
+ if (!BM_MapPageAtOffset(psLinuxMemArea->hBMHandle, ui32PA))
+ {
+ bMapPage = IMG_FALSE;
+ }
+ }
- pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32PA);
+ if (bMapPage)
+ {
+ pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32AdjustedPA);
#if defined(PVR_MAKE_ALL_PFNS_SPECIAL)
- if (bMixedMap)
- {
- result = vm_insert_mixed(ps_vma, ulVMAPos, pfn);
- if(result != 0)
- {
- PVR_DPF((PVR_DBG_ERROR,"%s: Error - vm_insert_mixed failed (%d)", __FUNCTION__, result));
- return IMG_FALSE;
- }
- }
- else
+ if (bMixedMap)
+ {
+ result = vm_insert_mixed(ps_vma, ulVMAPos, pfn);
+ if(result != 0)
+ {
+ PVR_DPF((PVR_DBG_ERROR,"%s: Error - vm_insert_mixed failed (%d)", __FUNCTION__, result));
+ return IMG_FALSE;
+ }
+ }
+ else
#endif
- {
- struct page *psPage;
-
- PVR_ASSERT(pfn_valid(pfn));
-
- psPage = pfn_to_page(pfn);
-
- result = VM_INSERT_PAGE(ps_vma, ulVMAPos, psPage);
- if(result != 0)
- {
- PVR_DPF((PVR_DBG_ERROR,"%s: Error - VM_INSERT_PAGE failed (%d)", __FUNCTION__, result));
- return IMG_FALSE;
- }
- }
- ulVMAPos += PAGE_SIZE;
- }
+ {
+ struct page *psPage;
+
+ PVR_ASSERT(pfn_valid(pfn));
+
+ psPage = pfn_to_page(pfn);
+
+ result = VM_INSERT_PAGE(ps_vma, ulVMAPos, psPage);
+ if(result != 0)
+ {
+ PVR_DPF((PVR_DBG_ERROR,"%s: Error - VM_INSERT_PAGE failed (%d)", __FUNCTION__, result));
+ return IMG_FALSE;
+ }
+ }
+ ui32AdjustedPA += PAGE_SIZE;
+ }
+ ulVMAPos += PAGE_SIZE;
+ }
}
return IMG_TRUE;
@@ -746,10 +974,11 @@ DoMapToUser(LinuxMemArea *psLinuxMemArea,
static IMG_VOID
MMapVOpenNoLock(struct vm_area_struct* ps_vma, PKV_OFFSET_STRUCT psOffsetStruct)
{
- PVR_ASSERT(psOffsetStruct != IMG_NULL)
- psOffsetStruct->ui32Mapped++;
+ PVR_ASSERT(psOffsetStruct != IMG_NULL);
PVR_ASSERT(!psOffsetStruct->bOnMMapList);
+ PVRSRVOffsetStructIncMapped(psOffsetStruct);
+
if (psOffsetStruct->ui32Mapped > 1)
{
PVR_DPF((PVR_DBG_WARNING, "%s: Offset structure 0x%p is being shared across processes (psOffsetStruct->ui32Mapped: %u)", __FUNCTION__, psOffsetStruct, psOffsetStruct->ui32Mapped));
@@ -769,6 +998,9 @@ MMapVOpenNoLock(struct vm_area_struct* ps_vma, PKV_OFFSET_STRUCT psOffsetStruct)
}
+/*
+ * Linux mmap open entry point.
+ */
static void
MMapVOpen(struct vm_area_struct* ps_vma)
{
@@ -799,7 +1031,7 @@ MMapVCloseNoLock(struct vm_area_struct* ps_vma, PKV_OFFSET_STRUCT psOffsetStruct
#endif
PVR_ASSERT(!psOffsetStruct->bOnMMapList);
- psOffsetStruct->ui32Mapped--;
+ PVRSRVOffsetStructDecMapped(psOffsetStruct);
if (psOffsetStruct->ui32Mapped == 0)
{
if (psOffsetStruct->ui32RefCount != 0)
@@ -813,6 +1045,9 @@ MMapVCloseNoLock(struct vm_area_struct* ps_vma, PKV_OFFSET_STRUCT psOffsetStruct
ps_vma->vm_private_data = NULL;
}
+/*
+ * Linux mmap close entry point.
+ */
static void
MMapVClose(struct vm_area_struct* ps_vma)
{
@@ -823,361 +1058,103 @@ MMapVClose(struct vm_area_struct* ps_vma)
LinuxUnLockMutex(&g_sMMapMutex);
}
-
-static struct vm_operations_struct MMapIOOps =
-{
- .open=MMapVOpen,
- .close=MMapVClose
-};
-
-/*****************************************************************************/
-/* "Smart" cached buffer support..
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+/*
+ * This vma operation is used to read data from mmap regions. It is called
+ * by access_process_vm, which is called to handle PTRACE_PEEKDATA ptrace
+ * requests and reads from /proc/<pid>/mem.
*/
-
-#include <linux/rmap.h>
-#include <linux/pagemap.h>
-
-typedef struct {
- struct mutex lock; /* mutex that protects the page list */
- struct list_head faulted; /* list of touched pages */
- int npages; /* number of pages in buffer */
- struct vm_area_struct *vma; /* vma of initial creator of buffer */
-} PVRMMapSmartCache;
-
-enum {
- PG_touched = PG_private,
- PG_written = PG_private_2
-};
-
-static IMG_VOID PVRMMapUnmapInv(IMG_HANDLE hSmartCache, bool inv);
-
-
-#ifndef DBG
-#define DBG(fmt, ...) do {} while (0)
-//#define DBG(fmt, ...) printk(KERN_INFO"[%s:%d] "fmt"\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
-#endif
-#ifndef VERB
-#define VERB(fmt, ...) do {} while (0)
-//#define VERB(fmt, ...) printk(KERN_INFO"[%s:%d] "fmt"\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
-#endif
-#define ERR(fmt, ...) printk(KERN_ERR"ERR: [%s:%d] "fmt"\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
-
-static int
-MMapVFault(struct vm_area_struct *vma, struct vm_fault *vmf)
+static int MMapVAccess(struct vm_area_struct *ps_vma, unsigned long addr,
+ void *buf, int len, int write)
{
- PKV_OFFSET_STRUCT psOffsetStruct = vma->vm_private_data;
- LinuxMemArea *psLinuxMemArea = psOffsetStruct->psLinuxMemArea;
- PVRMMapSmartCache *smart = psLinuxMemArea->hSmartCache;
- unsigned long offset, pfn;
- struct page *page;
- pgoff_t pgoff;
- int ret = VM_FAULT_NOPAGE;
-
- if (!smart)
- {
- ERR("uhh oh, I'm not smart..\n");
- return VM_FAULT_SIGBUS;
- }
-
- /* We don't use vmf->pgoff since that has the fake offset */
- pgoff = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT;
- offset = pgoff << PAGE_SHIFT;
- if (offset >= psOffsetStruct->psLinuxMemArea->ui32ByteSize)
- {
- ERR("%p: offset too big: %lu vs %u, %p", smart, offset,
- psOffsetStruct->psLinuxMemArea->ui32ByteSize,
- psOffsetStruct->psLinuxMemArea);
- return VM_FAULT_SIGBUS;
- }
-
- pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, offset);
- page = pfn_to_page(pfn);
- if (!page)
- {
- ERR("%p: can't find page: %lu, %p", smart, offset, psLinuxMemArea);
- return VM_FAULT_SIGBUS;
- }
-
+ PKV_OFFSET_STRUCT psOffsetStruct;
+ LinuxMemArea *psLinuxMemArea;
+ unsigned long ulOffset;
+ int iRetVal = -EINVAL;
+ IMG_VOID *pvKernelAddr;
- /* *** BEGIN CRITICAL SECTION ********************************************/
- mutex_lock(&smart->lock);
+ LinuxLockMutex(&g_sMMapMutex);
- /* if we already know of this page the we are done */
- if (test_and_set_bit(PG_touched, &page->flags))
- {
- VERB("%p: (already touched) get_page(%p) (idx=%08lx, flg=%08x, cnt=%d)",
- smart, page, page->index, vmf->flags, atomic_read(&page->_count));
- goto unlock;
- }
+ psOffsetStruct = (PKV_OFFSET_STRUCT)ps_vma->vm_private_data;
+ psLinuxMemArea = psOffsetStruct->psLinuxMemArea;
+ ulOffset = addr - ps_vma->vm_start;
- page->index = pgoff + vma->vm_pgoff;
+ if (ulOffset+len > psLinuxMemArea->ui32ByteSize)
+ /* Out of range. We shouldn't get here, because the kernel will do
+ the necessary checks before calling access_process_vm. */
+ goto exit_unlock;
- VERB("%p: get_page(%p) (idx=%08lx, flg=%08x, cnt=%d)",
- smart, page, page->index, vmf->flags, atomic_read(&page->_count));
+ pvKernelAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea);
- if (vma->vm_file)
+ if (pvKernelAddr)
{
- page->mapping = vma->vm_file->f_mapping;
+ memcpy(buf, pvKernelAddr+ulOffset, len);
+ iRetVal = len;
}
else
{
- ERR("%p: no mapping available\n", smart);
- }
+ IMG_UINT32 pfn, ui32OffsetInPage;
+ struct page *page;
- BUG_ON(!page->mapping);
+ pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ulOffset);
- vmf->page = page;
+ if (!pfn_valid(pfn))
+ goto exit_unlock;
- get_page(page);
- ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
- if (ret)
- {
- ERR("%p: error inserting page: %d", smart, ret);
- goto unlock;
- }
- ret = VM_FAULT_NOPAGE;
-
- /* Add the page to the list of pages that have been touched
- */
- list_add_tail(&page->lru, &smart->faulted);
-
-unlock:
- mutex_unlock(&smart->lock);
- /* *** END CRITICAL SECTION **********************************************/
-
- return ret;
-}
-
-static int
-MMapVMkWrite(struct vm_area_struct *vma, struct vm_fault *vmf)
-{
- PKV_OFFSET_STRUCT psOffsetStruct = (PKV_OFFSET_STRUCT)vma->vm_private_data;
- PVRMMapSmartCache *smart = psOffsetStruct->psLinuxMemArea->hSmartCache;
- struct page *page = vmf->page;
-
- VERB("%p: page=%p", smart, page);
-
- /* *** BEGIN CRITICAL SECTION ********************************************/
- mutex_lock(&smart->lock);
-
- /* We want the page to remain locked from ->page_mkwrite until
- * the PTE is marked dirty to avoid page_mkclean() being called
- * before the PTE is updated, which would leave the page ignored.
- *
- * Do this by locking the page here and informing the caller
- * about it with VM_FAULT_LOCKED.
- */
- lock_page(page);
+ page = pfn_to_page(pfn);
+ ui32OffsetInPage = ADDR_TO_PAGE_OFFSET(ulOffset);
- set_bit(PG_written, &page->flags);
+ if (ui32OffsetInPage+len > PAGE_SIZE)
+ /* The region crosses a page boundary */
+ goto exit_unlock;
- mutex_unlock(&smart->lock);
- /* *** END CRITICAL SECTION **********************************************/
+ pvKernelAddr = kmap(page);
+ memcpy(buf, pvKernelAddr+ui32OffsetInPage, len);
+ kunmap(page);
- return VM_FAULT_LOCKED;
-}
-
-static void
-MMapVClose2(struct vm_area_struct* vma)
-{
- PKV_OFFSET_STRUCT psOffsetStruct = (PKV_OFFSET_STRUCT)vma->vm_private_data;
- PVRMMapSmartCache *smart = psOffsetStruct->psLinuxMemArea->hSmartCache;
- DBG("%p", smart);
- PVRMMapUnmapInv(smart, false);
- MMapVClose(vma);
-}
-
-static struct vm_operations_struct MMapSmartOps = {
- .open=MMapVOpen,
- .close=MMapVClose2,
- .fault=MMapVFault,
- .page_mkwrite=MMapVMkWrite,
-};
-
-static int
-MMapSetPageDirty(struct page *page)
-{
- if (!PageDirty(page))
- SetPageDirty(page);
- return 0;
-}
-
-static const struct address_space_operations MMapSmartAOps = {
- .set_page_dirty = MMapSetPageDirty,
-};
-
-/* prepare buffer transition CPU -> GPU */
-IMG_VOID
-PVRMMapPrepareCpuToGpu(IMG_HANDLE hSmartCache)
-{
-#if 0
- PVRMMapSmartCache *smart = hSmartCache;
- struct page *page;
- int cnt = 0;
-
- /* hopefully this is the common-path.. */
- if (list_empty(&smart->faulted))
- {
- return;
+ iRetVal = len;
}
- /* *** BEGIN CRITICAL SECTION ********************************************/
- mutex_lock(&smart->lock);
-
- list_for_each_entry(page, &smart->faulted, lru) {
- if (test_and_clear_bit(PG_written, &page->flags))
- {
- void *va = (void *)(smart->vma->vm_start +
- ((page->index - smart->vma->vm_pgoff) << PAGE_SHIFT));
- unsigned long pa = page_to_phys(page);
-
- lock_page(page);
- page_mkclean(page);
- dmac_clean_range(va, va + PAGE_SIZE);
- outer_clean_range(pa, pa + PAGE_SIZE);
- unlock_page(page);
-
- cnt++;
- }
- }
-
- mutex_unlock(&smart->lock);
- /* *** END CRITICAL SECTION **********************************************/
-
- DBG("%p: cleaned %d (of %d)", smart, cnt, smart->npages);
-#else
- PVRMMapUnmapInv(hSmartCache, true);
-#endif
-}
-/* prepare buffer transition GPU -> CPU */
-IMG_VOID
-PVRMMapPrepareGpuToCpu(IMG_HANDLE hSmartCache)
-{
- PVRMMapUnmapInv(hSmartCache, true);
+exit_unlock:
+ LinuxUnLockMutex(&g_sMMapMutex);
+ return iRetVal;
}
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) */
-/* remove faulted pages from user's vm, and optionally invalidate.. */
-static IMG_VOID
-PVRMMapUnmapInv(IMG_HANDLE hSmartCache, bool inv)
+static struct vm_operations_struct MMapIOOps =
{
- PVRMMapSmartCache *smart = hSmartCache;
- struct page *page, *next;
- pgoff_t min = ULONG_MAX, max = 0;
- struct address_space *mapping = NULL;
- int cnt = 0;
-
- /* hopefully this is the common-path.. */
- if (list_empty(&smart->faulted))
- {
- return;
- }
-
- VERB("%p", smart);
-
- /* *** BEGIN CRITICAL SECTION ********************************************/
- mutex_lock(&smart->lock);
-
- list_for_each_entry(page, &smart->faulted, lru) {
-
- if (inv)
- {
- void *va = (void *)(smart->vma->vm_start +
- ((page->index - smart->vma->vm_pgoff) << PAGE_SHIFT));
-
-#if 0
- dmac_inv_range(va, va + PAGE_SIZE);
-#else
- dmac_flush_range(va, va + PAGE_SIZE);
-#endif
- }
-
- clear_bit(PG_touched, &page->flags);
- clear_bit(PG_written, &page->flags);
-
- min = min(min, page->index);
- max = max(max, page->index);
-
- mapping = page->mapping;
-
- cnt++;
- }
-
- /* clear out the mapping that we setup.. do this before
- * invalidating to avoid a window where the cache is
- * clean, but access to it is not protected by a fault
- */
- if (mapping)
- {
- VERB("unmap_mapping_range: max=%08lx, min=%08lx", max, min);
- unmap_mapping_range(mapping, min << PAGE_SHIFT,
- (max - min + 1) << PAGE_SHIFT, 1);
- }
-
- list_for_each_entry_safe(page, next, &smart->faulted, lru) {
-
- if (inv)
- {
- unsigned long pa = page_to_phys(page);
-
-#if 0
- outer_inv_range(pa, pa + PAGE_SIZE);
-#else
- outer_flush_range(pa, pa + PAGE_SIZE);
+ .open=MMapVOpen,
+ .close=MMapVClose,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+ .access=MMapVAccess,
#endif
- }
-
- VERB("%p: put_page(%p) (idx=%08lx, cnt=%d)",
- smart, page, page->index, atomic_read(&page->_count));
-
- page->index = 0;
- page->mapping = NULL;
-
- put_page(page);
-
- list_del(&page->lru);
- }
-
- mutex_unlock(&smart->lock);
- /* *** END CRITICAL SECTION **********************************************/
-
- DBG("%p: put %d (of %d)", smart, cnt, smart->npages);
-}
-
-/* setup smart cache buffer */
-IMG_HANDLE
-PVRMMapAllocateSmart(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo)
-{
- PVRMMapSmartCache *smart = kzalloc(sizeof(*smart), GFP_KERNEL);
-
- DBG("%p", smart);
+};
- mutex_init(&smart->lock);
- INIT_LIST_HEAD(&smart->faulted);
- return smart;
-}
+/*!
+ *******************************************************************************
-IMG_VOID
-PVRMMapFreeSmart(IMG_HANDLE hSmartCache)
-{
- PVRMMapSmartCache *smart = hSmartCache;
+ @Function PVRMMap
- DBG("%p", smart);
+ @Description
- PVRMMapUnmapInv(smart, false);
+ Driver mmap entry point.
- mutex_destroy(&smart->lock);
+ @input pFile : unused.
+ @input ps_vma : pointer to linux memory area descriptor.
- kfree(smart);
-}
-/*****************************************************************************/
+ @Return 0, or Linux error code.
+ ******************************************************************************/
int
PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma)
{
- IMG_UINT32 ui32ByteSize;
+ LinuxMemArea *psFlushMemArea = IMG_NULL;
PKV_OFFSET_STRUCT psOffsetStruct;
+ IMG_UINT32 ui32ByteSize;
+ IMG_VOID *pvBase = IMG_NULL;
int iRetVal = 0;
+ IMG_UINT32 ui32ByteOffset = 0; /* Keep compiler happy */
PVR_UNREFERENCED_PARAMETER(pFile);
@@ -1192,17 +1169,23 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma)
ui32ByteSize, ui32ByteSize));
psOffsetStruct = FindOffsetStructByOffset(ps_vma->vm_pgoff, ui32ByteSize);
+
if (psOffsetStruct == IMG_NULL)
{
#if defined(SUPPORT_DRI_DRM)
LinuxUnLockMutex(&g_sMMapMutex);
#if !defined(SUPPORT_DRI_DRM_EXT)
-
+ /* Pass unknown requests onto the DRM module */
return drm_mmap(pFile, ps_vma);
#else
-
- return -ENOENT;
+ /*
+ * Indicate to caller that the request is not for us.
+ * Do not return this error elsewhere in this function, as the
+ * caller may use it as a clue as to whether the mmap request
+ * should be passed on to another component (e.g. drm_mmap).
+ */
+ return -ENOENT;
#endif
#else
PVR_UNREFERENCED_PARAMETER(pFile);
@@ -1214,10 +1197,11 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma)
#endif
goto unlock_and_return;
}
+
list_del(&psOffsetStruct->sMMapItem);
psOffsetStruct->bOnMMapList = IMG_FALSE;
-
+ /* Only support shared writeable mappings */
if (((ps_vma->vm_flags & VM_WRITE) != 0) &&
((ps_vma->vm_flags & VM_SHARED) == 0))
{
@@ -1232,10 +1216,13 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma)
ps_vma->vm_flags |= VM_RESERVED;
ps_vma->vm_flags |= VM_IO;
-
+ /*
+ * Disable mremap because our nopage handler assumes all
+ * page requests have already been validated.
+ */
ps_vma->vm_flags |= VM_DONTEXPAND;
-
+ /* Don't allow mapping to be inherited across a process fork */
ps_vma->vm_flags |= VM_DONTCOPY;
ps_vma->vm_private_data = (void *)psOffsetStruct;
@@ -1243,7 +1230,7 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma)
switch(psOffsetStruct->psLinuxMemArea->ui32AreaFlags & PVRSRV_HAP_CACHETYPE_MASK)
{
case PVRSRV_HAP_CACHED:
- case PVRSRV_HAP_SMART:
+ /* This is the default, do nothing. */
break;
case PVRSRV_HAP_WRITECOMBINE:
ps_vma->vm_page_prot = PGPROT_WC(ps_vma->vm_page_prot);
@@ -1254,76 +1241,58 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma)
default:
PVR_DPF((PVR_DBG_ERROR, "%s: unknown cache type", __FUNCTION__));
iRetVal = -EINVAL;
- goto unlock_and_return;
+ goto unlock_and_return;
}
- if (psOffsetStruct->psLinuxMemArea->hSmartCache)
- {
- PVRMMapSmartCache *smart = psOffsetStruct->psLinuxMemArea->hSmartCache;
- DBG("using smart cache, smart=%p, psLinuxMemArea=%p (%d, %d)",
- psOffsetStruct->psLinuxMemArea->hSmartCache,
- psOffsetStruct->psLinuxMemArea,
- psOffsetStruct->ui32RealByteSize,
- psOffsetStruct->psLinuxMemArea->ui32ByteSize);
- smart->npages = (psOffsetStruct->ui32RealByteSize + PAGE_SIZE - 1) / PAGE_SIZE;
- /* abuse pgoff a bit less.. in unmap_mapping_range() it is assumed
- * that the offset is something sane, and I think it probably
- * shouldn't intersect with other page->index's.. otherwise I
- * suspect the prio_tree stuff won't work out..
- */
- ps_vma->vm_pgoff = ps_vma->vm_start >> PAGE_SHIFT;
- smart->vma = ps_vma;
- ps_vma->vm_ops = &MMapSmartOps;
- pFile->f_mapping->a_ops = &MMapSmartAOps;
-
- ps_vma->vm_flags |= VM_MIXEDMAP;
- }
- else
+ /* Install open and close handlers for ref-counting */
+ ps_vma->vm_ops = &MMapIOOps;
+
+ if(!DoMapToUser(psOffsetStruct->psLinuxMemArea, ps_vma, 0))
{
- ps_vma->vm_ops = &MMapIOOps;
- if(!DoMapToUser(psOffsetStruct->psLinuxMemArea, ps_vma, 0))
- {
- iRetVal = -EAGAIN;
- goto unlock_and_return;
- }
+ iRetVal = -EAGAIN;
+ goto unlock_and_return;
}
PVR_ASSERT(psOffsetStruct->ui32UserVAddr == 0);
psOffsetStruct->ui32UserVAddr = ps_vma->vm_start;
-
+ /* Compute the flush region (if necessary) inside the mmap mutex */
if(psOffsetStruct->psLinuxMemArea->bNeedsCacheInvalidate)
{
- IMG_UINT32 ui32RealByteSize, ui32ByteOffset;
- IMG_VOID *pvBase;
+ IMG_UINT32 ui32DummyByteSize;
DetermineUsersSizeAndByteOffset(psOffsetStruct->psLinuxMemArea,
- &ui32RealByteSize,
+ &ui32DummyByteSize,
&ui32ByteOffset);
- ui32RealByteSize = psOffsetStruct->psLinuxMemArea->ui32ByteSize;
pvBase = (IMG_VOID *)ps_vma->vm_start + ui32ByteOffset;
+ psFlushMemArea = psOffsetStruct->psLinuxMemArea;
- OSInvalidateCPUCacheRangeKM(psOffsetStruct->psLinuxMemArea,
- pvBase, ui32RealByteSize);
psOffsetStruct->psLinuxMemArea->bNeedsCacheInvalidate = IMG_FALSE;
}
-
+
+ /* Call the open routine to increment the usage count */
MMapVOpenNoLock(ps_vma, ps_vma->vm_private_data);
PVR_DPF((PVR_DBG_MESSAGE, "%s: Mapped area at offset 0x%08lx\n",
__FUNCTION__, ps_vma->vm_pgoff));
-
+
unlock_and_return:
if (iRetVal != 0 && psOffsetStruct != IMG_NULL)
{
- DestroyOffsetStruct(psOffsetStruct);
+ DestroyOffsetStruct(psOffsetStruct);
}
LinuxUnLockMutex(&g_sMMapMutex);
-
+
+ if(psFlushMemArea)
+ {
+ OSInvalidateCPUCacheRangeKM(psFlushMemArea, ui32ByteOffset, pvBase,
+ psFlushMemArea->ui32ByteSize);
+ }
+
return iRetVal;
}
@@ -1372,6 +1341,11 @@ PVRMMapExt(struct file* pFile, struct vm_area_struct* ps_vma)
IMG_UINT32 ui32ByteSize;
PKV_OFFSET_STRUCT psOffsetStruct;
+ /* for cache maintenance: */
+ LinuxMemArea *psFlushMemArea = IMG_NULL;
+ IMG_VOID *pvBase = IMG_NULL;
+ IMG_UINT32 ui32ByteOffset = 0; /* Keep compiler happy */
+
PVR_UNREFERENCED_PARAMETER(pFile);
LinuxLockMutex(&g_sMMapMutex);
@@ -1390,16 +1364,44 @@ PVRMMapExt(struct file* pFile, struct vm_area_struct* ps_vma)
list_del(&psOffsetStruct->sMMapItem);
psOffsetStruct->bOnMMapList = IMG_FALSE;
+ if(!DoMapToUser(psOffsetStruct->psLinuxMemArea, ps_vma, 0))
+ {
+ goto unlock_and_return;
+ }
+
PVR_ASSERT(psOffsetStruct->ui32UserVAddr == 0);
psOffsetStruct->ui32UserVAddr = ps_vma->vm_start;
obj->driver_private = psOffsetStruct->psLinuxMemArea;
+
+ /* Compute the flush region (if necessary) inside the mmap mutex */
+ if(psOffsetStruct->psLinuxMemArea->bNeedsCacheInvalidate)
+ {
+ IMG_UINT32 ui32DummyByteSize;
+
+ DetermineUsersSizeAndByteOffset(psOffsetStruct->psLinuxMemArea,
+ &ui32DummyByteSize,
+ &ui32ByteOffset);
+
+ pvBase = (IMG_VOID *)ps_vma->vm_start + ui32ByteOffset;
+ psFlushMemArea = psOffsetStruct->psLinuxMemArea;
+
+ psOffsetStruct->psLinuxMemArea->bNeedsCacheInvalidate = IMG_FALSE;
+ }
+
+ /* Call the open routine to increment the usage count */
MMapVOpenNoLock(ps_vma, psOffsetStruct);
unlock_and_return:
LinuxUnLockMutex(&g_sMMapMutex);
+
+ if(psFlushMemArea)
+ {
+ OSInvalidateCPUCacheRangeKM(psFlushMemArea, ui32ByteOffset, pvBase,
+ psFlushMemArea->ui32ByteSize);
+ }
}
static struct omap_gem_vm_ops gem_ops = {
@@ -1411,6 +1413,13 @@ static struct omap_gem_vm_ops gem_ops = {
#if defined(DEBUG_LINUX_MMAP_AREAS)
+/*
+ * Lock MMap regions list (called on page start/stop while reading /proc/mmap)
+
+ * sfile : seq_file that handles /proc file
+ * start : TRUE if it's start, FALSE if it's stop
+ *
+*/
static void ProcSeqStartstopMMapRegistations(struct seq_file *sfile,IMG_BOOL start)
{
if(start)
@@ -1424,6 +1433,16 @@ static void ProcSeqStartstopMMapRegistations(struct seq_file *sfile,IMG_BOOL sta
}
+/*
+ * Convert offset (index from KVOffsetTable) to element
+ * (called when reading /proc/mmap file)
+
+ * sfile : seq_file that handles /proc file
+ * off : index into the KVOffsetTable from which to print
+ *
+ * returns void* : Pointer to element that will be dumped
+ *
+*/
static void* ProcSeqOff2ElementMMapRegistrations(struct seq_file *sfile, loff_t off)
{
LinuxMemArea *psLinuxMemArea;
@@ -1449,12 +1468,28 @@ static void* ProcSeqOff2ElementMMapRegistrations(struct seq_file *sfile, loff_t
return (void*)0;
}
+/*
+ * Gets next MMap element to show. (called when reading /proc/mmap file)
+
+ * sfile : seq_file that handles /proc file
+ * el : actual element
+ * off : index into the KVOffsetTable from which to print
+ *
+ * returns void* : Pointer to element to show (0 ends iteration)
+*/
static void* ProcSeqNextMMapRegistrations(struct seq_file *sfile,void* el,loff_t off)
{
return ProcSeqOff2ElementMMapRegistrations(sfile,off);
}
+/*
+ * Show MMap element (called when reading /proc/mmap file)
+
+ * sfile : seq_file that handles /proc file
+ * el : actual element
+ *
+*/
static void ProcSeqShowMMapRegistrations(struct seq_file *sfile, void *el)
{
KV_OFFSET_STRUCT *psOffsetStruct = (KV_OFFSET_STRUCT*)el;
@@ -1528,6 +1563,20 @@ static void ProcSeqShowMMapRegistrations(struct seq_file *sfile, void *el)
#endif
+/*!
+ *******************************************************************************
+
+ @Function PVRMMapRegisterArea
+
+ @Description
+
+ Register a memory area with the mmap code.
+
+ @input psLinuxMemArea : pointer to memory area.
+
+ @Return PVRSRV_OK, or PVRSRV_ERROR.
+
+ ******************************************************************************/
PVRSRV_ERROR
PVRMMapRegisterArea(LinuxMemArea *psLinuxMemArea)
{
@@ -1546,7 +1595,7 @@ PVRMMapRegisterArea(LinuxMemArea *psLinuxMemArea)
PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC || LinuxMemAreaRoot(psLinuxMemArea)->eAreaType != LINUX_MEM_AREA_SUB_ALLOC);
-
+ /* Check this mem area hasn't already been registered */
if(psLinuxMemArea->bMMapRegistered)
{
PVR_DPF((PVR_DBG_ERROR, "%s: psLinuxMemArea 0x%p is already registered",
@@ -1561,7 +1610,11 @@ PVRMMapRegisterArea(LinuxMemArea *psLinuxMemArea)
#if defined(DEBUG_LINUX_MMAP_AREAS)
g_ui32RegisteredAreas++;
-
+ /*
+ * Sub memory areas are excluded from g_ui32TotalByteSize so that we
+ * don't count memory twice, once for the parent and again for sub
+ * allocationis.
+ */
if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC)
{
g_ui32TotalByteSize += psLinuxMemArea->ui32ByteSize;
@@ -1577,6 +1630,20 @@ exit_unlock:
}
+/*!
+ *******************************************************************************
+
+ @Function PVRMMapRemoveRegisterArea
+
+ @Description
+
+ Unregister a memory area with the mmap code.
+
+ @input psLinuxMemArea : pointer to memory area.
+
+ @Return PVRSRV_OK, or PVRSRV_ERROR.
+
+ ******************************************************************************/
PVRSRV_ERROR
PVRMMapRemoveRegisteredArea(LinuxMemArea *psLinuxMemArea)
{
@@ -1592,12 +1659,19 @@ PVRMMapRemoveRegisteredArea(LinuxMemArea *psLinuxMemArea)
if (psOffsetStruct->ui32Mapped != 0)
{
PVR_DPF((PVR_DBG_ERROR, "%s: psOffsetStruct 0x%p for memory area 0x0x%p is still mapped; psOffsetStruct->ui32Mapped %u", __FUNCTION__, psOffsetStruct, psLinuxMemArea, psOffsetStruct->ui32Mapped));
+ dump_stack();
+ PVRSRVDumpRefCountCCB();
eError = PVRSRV_ERROR_STILL_MAPPED;
goto exit_unlock;
}
else
{
-
+ /*
+ * An offset structure is created when a call is made to get
+ * the mmap data for a physical mapping. If the data is never
+ * used for mmap, we will be left with an umapped offset
+ * structure.
+ */
PVR_DPF((PVR_DBG_WARNING, "%s: psOffsetStruct 0x%p was never mapped", __FUNCTION__, psOffsetStruct));
}
@@ -1626,6 +1700,20 @@ exit_unlock:
}
+/*!
+ *******************************************************************************
+
+ @Function LinuxMMapPerProcessConnect
+
+ @Description
+
+ Per-process mmap initialisation code.
+
+ @input psEnvPerProc : pointer to OS specific per-process data.
+
+ @Return PVRSRV_OK, or PVRSRV_ERROR.
+
+ ******************************************************************************/
PVRSRV_ERROR
LinuxMMapPerProcessConnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc)
{
@@ -1634,6 +1722,18 @@ LinuxMMapPerProcessConnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc)
return PVRSRV_OK;
}
+/*!
+ *******************************************************************************
+
+ @Function LinuxMMapPerProcessDisconnect
+
+ @Description
+
+ Per-process mmap deinitialisation code.
+
+ @input psEnvPerProc : pointer to OS specific per-process data.
+
+ ******************************************************************************/
IMG_VOID
LinuxMMapPerProcessDisconnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc)
{
@@ -1665,6 +1765,20 @@ LinuxMMapPerProcessDisconnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc)
}
+/*!
+ *******************************************************************************
+
+ @Function LinuxMMapPerProcessHandleOptions
+
+ @Description
+
+ Set secure handle options required by mmap code.
+
+ @input psHandleBase : pointer to handle base.
+
+ @Return PVRSRV_OK, or PVRSRV_ERROR.
+
+ ******************************************************************************/
PVRSRV_ERROR LinuxMMapPerProcessHandleOptions(PVRSRV_HANDLE_BASE *psHandleBase)
{
PVRSRV_ERROR eError;
@@ -1680,6 +1794,16 @@ PVRSRV_ERROR LinuxMMapPerProcessHandleOptions(PVRSRV_HANDLE_BASE *psHandleBase)
}
+/*!
+ *******************************************************************************
+
+ @Function PVRMMapInit
+
+ @Description
+
+ MMap initialisation code
+
+ ******************************************************************************/
IMG_VOID
PVRMMapInit(IMG_VOID)
{
@@ -1699,7 +1823,7 @@ PVRMMapInit(IMG_VOID)
ProcSeqOff2ElementMMapRegistrations,
ProcSeqStartstopMMapRegistations
);
-#endif
+#endif /* defined(DEBUG_LINUX_MMAP_AREAS) */
return;
error:
@@ -1708,6 +1832,16 @@ error:
}
+/*!
+ *******************************************************************************
+
+ @Function PVRMMapCleanup
+
+ @Description
+
+ Mmap deinitialisation code
+
+ ******************************************************************************/
IMG_VOID
PVRMMapCleanup(IMG_VOID)
{
@@ -1736,7 +1870,7 @@ PVRMMapCleanup(IMG_VOID)
#if defined(DEBUG_LINUX_MMAP_AREAS)
RemoveProcEntrySeq(g_ProcMMap);
-#endif
+#endif /* defined(DEBUG_LINUX_MMAP_AREAS) */
if(g_psMemmapCache)
{
diff --git a/sgx/services4/srvkm/env/linux/mmap.h b/sgx/services4/srvkm/env/linux/mmap.h
index 07d521b..bca8358 100644
--- a/sgx/services4/srvkm/env/linux/mmap.h
+++ b/sgx/services4/srvkm/env/linux/mmap.h
@@ -1,28 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Linux mmap interface declaration
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#if !defined(__MMAP_H__)
#define __MMAP_H__
@@ -31,68 +47,146 @@
#include <linux/list.h>
#if defined(VM_MIXEDMAP)
+/*
+ * Mixed maps allow us to avoid using raw PFN mappings (VM_PFNMAP) for
+ * pages without pages structures ("struct page"), giving us more
+ * freedom in choosing the mmap offset for mappings. Mixed maps also
+ * allow both the mmap and the wrap code to be simplified somewhat.
+ */
#define PVR_MAKE_ALL_PFNS_SPECIAL
#endif
#include "perproc.h"
#include "mm.h"
+/*
+ * This structure represents the relationship between an mmap2 file
+ * offset and a LinuxMemArea for a given process.
+ */
typedef struct KV_OFFSET_STRUCT_TAG
{
-
+ /*
+ * Mapping count. Incremented when the mapping is created, and
+ * if the mapping is inherited across a process fork.
+ */
IMG_UINT32 ui32Mapped;
-
+ /*
+ * Offset to be passed to mmap2 to map the associated memory area
+ * into user space. The offset may represent the page frame number
+ * of the first page in the area (if the area is physically
+ * contiguous), or it may represent the secure handle associated
+ * with the area.
+ */
IMG_UINT32 ui32MMapOffset;
IMG_UINT32 ui32RealByteSize;
-
+ /* Memory area associated with this offset structure */
LinuxMemArea *psLinuxMemArea;
#if !defined(PVR_MAKE_ALL_PFNS_SPECIAL)
-
+ /* ID of the thread that owns this structure */
IMG_UINT32 ui32TID;
#endif
-
+ /* ID of the process that owns this structure */
IMG_UINT32 ui32PID;
-
+ /*
+ * For offsets that represent actual page frame numbers, this structure
+ * is temporarily put on a list so that it can be found from the
+ * driver mmap entry point. This flag indicates the structure is
+ * on the list.
+ */
IMG_BOOL bOnMMapList;
-
+ /* Reference count for this structure */
IMG_UINT32 ui32RefCount;
-
+ /*
+ * User mode address of start of mapping. This is not necessarily the
+ * first user mode address of the memory area.
+ */
IMG_UINT32 ui32UserVAddr;
-
+ /* Extra entries to support proc filesystem debug info */
#if defined(DEBUG_LINUX_MMAP_AREAS)
const IMG_CHAR *pszName;
#endif
-
+ /* List entry field for MMap list */
struct list_head sMMapItem;
-
+ /* List entry field for per-memory area list */
struct list_head sAreaItem;
}KV_OFFSET_STRUCT, *PKV_OFFSET_STRUCT;
+/*!
+ *******************************************************************************
+ * @Function Mmap initialisation code
+ ******************************************************************************/
IMG_VOID PVRMMapInit(IMG_VOID);
+/*!
+ *******************************************************************************
+ * @Function Mmap de-initialisation code
+ ******************************************************************************/
IMG_VOID PVRMMapCleanup(IMG_VOID);
+/*!
+ *******************************************************************************
+ * @Function Registers a memory area with the mmap code
+ *
+ * @Input psLinuxMemArea
+ *
+ * @Return PVRSRV_ERROR status
+ ******************************************************************************/
PVRSRV_ERROR PVRMMapRegisterArea(LinuxMemArea *psLinuxMemArea);
+/*!
+ *******************************************************************************
+ * @Function Unregisters a memory area from the mmap code
+ *
+ * @Input psLinuxMemArea
+ *
+ * @Return PVRSRV_ERROR status
+ ******************************************************************************/
PVRSRV_ERROR PVRMMapRemoveRegisteredArea(LinuxMemArea *psLinuxMemArea);
+/*!
+ ******************************************************************************
+ * @Function When a userspace services client, requests to map a memory
+ * area to userspace, this function validates the request and
+ * returns the details that the client must use when calling mmap(2).
+ *
+ * @Input psPerProc Per process data.
+ * @Input hMHandle Handle associated with the memory to map.
+ * This is a (secure) handle to the OS specific
+ * memory handle structure (hOSMemHandle), or
+ * a handle to a structure that contains the
+ * memory handle.
+ * @Output pui32MMapOffset The page aligned offset that the client must
+ * pass to the mmap2 system call.
+ * @Output pui32ByteOffset The real mapping that will be created for the
+ * services client may have a different
+ * size/alignment from it request. This offset
+ * is returned to the client and should be added
+ * to virtual address returned from mmap2 to get
+ * the first address corresponding to its request.
+ * @Output pui32RealByteOffset The size that the mapping will really be,
+ * that the client must also pass to mmap/munmap.
+ *
+ * @Output pui32UserVAddr Pointer to returned user mode address of
+ * mapping.
+ * @Return PVRSRV_ERROR
+ ******************************************************************************/
PVRSRV_ERROR PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
#if defined (SUPPORT_SID_INTERFACE)
IMG_SID hMHandle,
@@ -104,6 +198,21 @@ PVRSRV_ERROR PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
IMG_UINT32 *pui32RealByteSize,
IMG_UINT32 *pui32UserVAddr);
+/*!
+ *******************************************************************************
+
+ @Function Release mmap data.
+
+ @Input psPerProc Per-process data.
+ @Input hMHandle Memory handle.
+
+ @Output pbMUnmap Flag that indicates whether an munmap is
+ required.
+ @Output pui32RealByteSize Location for size of mapping.
+ @Output pui32UserVAddr User mode address to munmap.
+
+ @Return PVRSRV_ERROR
+ ******************************************************************************/
PVRSRV_ERROR
PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
#if defined (SUPPORT_SID_INTERFACE)
@@ -115,12 +224,18 @@ PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc,
IMG_UINT32 *pui32RealByteSize,
IMG_UINT32 *pui32UserVAddr);
+/*!
+ *******************************************************************************
+ * @Function driver mmap entry point
+ *
+ * @Input pFile : user file structure
+ *
+ * @Input ps_vma : vm area structure
+ *
+ * @Return 0 for success, -errno for failure.
+ ******************************************************************************/
int PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma);
-IMG_VOID PVRMMapPrepareCpuToGpu(IMG_HANDLE hSmartCache);
-IMG_VOID PVRMMapPrepareGpuToCpu(IMG_HANDLE hSmartCache);
-IMG_HANDLE PVRMMapAllocateSmart(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo);
-IMG_VOID PVRMMapFreeSmart(IMG_HANDLE hSmartCache);
-#endif
+#endif /* __MMAP_H__ */
diff --git a/sgx/services4/srvkm/env/linux/module.c b/sgx/services4/srvkm/env/linux/module.c
index cda7c21..fe31e41 100644
--- a/sgx/services4/srvkm/env/linux/module.c
+++ b/sgx/services4/srvkm/env/linux/module.c
@@ -1,28 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Linux module setup
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include <linux/version.h>
@@ -35,13 +51,24 @@
#if defined(SUPPORT_DRI_DRM) && !defined(SUPPORT_DRI_DRM_EXTERNAL)
#define PVR_MOD_STATIC
#else
+ /*
+ * For LDM drivers, define PVR_LDM_MODULE to indicate generic LDM
+ * support is required, besides indicating the exact support
+ * required (e.g. platform, or PCI device).
+ */
#if defined(LDM_PLATFORM)
#define PVR_LDM_PLATFORM_MODULE
+ #define PVR_LDM_DEVICE_CLASS
#define PVR_LDM_MODULE
#else
#if defined(LDM_PCI)
+ #define PVR_LDM_DEVICE_CLASS
#define PVR_LDM_PCI_MODULE
#define PVR_LDM_MODULE
+ #else
+ #if defined(SYS_SHARES_WITH_3PKM)
+ #define PVR_LDM_DEVICE_CLASS
+ #endif
#endif
#endif
#if defined(SUPPORT_DRI_DRM_EXTERNAL)
@@ -72,11 +99,15 @@
#if defined(PVR_LDM_PLATFORM_MODULE)
#include <linux/platform_device.h>
-#endif
+#endif /* PVR_LDM_PLATFORM_MODULE */
#if defined(PVR_LDM_PCI_MODULE)
#include <linux/pci.h>
-#endif
+#endif /* PVR_LDM_PCI_MODULE */
+
+#if defined(PVR_LDM_DEVICE_CLASS)
+#include <linux/device.h>
+#endif /* PVR_LDM_DEVICE_CLASS */
#if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
#include <asm/uaccess.h>
@@ -102,38 +133,69 @@
#include "private_data.h"
#include "lock.h"
#include "linkage.h"
+#include "buffer_manager.h"
#if defined(SUPPORT_DRI_DRM)
#include "pvr_drm.h"
#endif
+/*
+ * DRVNAME is the name we use to register our driver.
+ * DEVNAME is the name we use to register actual device nodes.
+ */
#if defined(SUPPORT_DRI_DRM_EXTERNAL)
#define DRVNAME PVRSRV_MODNAME
#define DEVNAME PVRSRV_MODNAME
#else
-#define DRVNAME PVRSRV_MODNAME
+#if defined(PVR_LDM_MODULE)
+#define DRVNAME PVR_LDM_DRIVER_REGISTRATION_NAME
+#endif
#define DEVNAME PVRSRV_MODNAME
MODULE_SUPPORTED_DEVICE(DEVNAME);
#endif
+/*
+ * This is all module configuration stuff required by the linux kernel.
+ */
#if defined(PVRSRV_NEED_PVR_DPF)
#include <linux/moduleparam.h>
extern IMG_UINT32 gPVRDebugLevel;
module_param(gPVRDebugLevel, uint, 0644);
MODULE_PARM_DESC(gPVRDebugLevel, "Sets the level of debug output (default 0x7)");
-#endif
+#endif /* defined(PVRSRV_NEED_PVR_DPF) */
-
+#if defined(CONFIG_ION_OMAP)
+#include <linux/ion.h>
+#include <linux/omap_ion.h>
+extern struct ion_device *omap_ion_device;
+struct ion_client *gpsIONClient;
+EXPORT_SYMBOL(gpsIONClient);
+#endif /* defined(CONFIG_ION_OMAP) */
+
+/* PRQA S 3207 2 */ /* ignore 'not used' warning */
EXPORT_SYMBOL(PVRGetDisplayClassJTable);
EXPORT_SYMBOL(PVRGetBufferClassJTable);
#if defined(PVR_LDM_MODULE)
+/*
+ * Device class used for /sys entries (and udev device node creation)
+ */
static struct class *psPvrClass;
#endif
#if defined(SUPPORT_DRI_DRM_EXTERNAL) || !defined(SUPPORT_DRI_DRM)
+/*
+ * This is the major number we use for all nodes in /dev.
+ */
static int AssignedMajorNumber;
#endif
+/*
+ * These are the operations that will be associated with the device node
+ * we create.
+ *
+ * With gcc -W, specifying only the non-null members produces "missing
+ * initializer" warnings.
+*/
#if !defined(SUPPORT_DRI_DRM)
static int PVRSRVOpen(struct inode* pInode, struct file* pFile);
static int PVRSRVRelease(struct inode* pInode, struct file* pFile);
@@ -150,6 +212,7 @@ static struct file_operations pvrsrv_fops =
PVRSRV_LINUX_MUTEX gPVRSRVLock;
+/* PID of process being released */
IMG_UINT32 gui32ReleasePID;
#if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
@@ -161,12 +224,15 @@ static IMG_UINT32 gPVRPowerLevel;
#if defined(PVR_LDM_PLATFORM_MODULE)
#define LDM_DEV struct platform_device
#define LDM_DRV struct platform_driver
-#endif
+#endif /*PVR_LDM_PLATFORM_MODULE */
#if defined(PVR_LDM_PCI_MODULE)
#define LDM_DEV struct pci_dev
#define LDM_DRV struct pci_driver
-#endif
+#endif /* PVR_LDM_PCI_MODULE */
+/*
+ * This is the driver interface we support.
+ */
#if defined(PVR_LDM_PLATFORM_MODULE) && !defined(SUPPORT_DRI_DRM_EXTERNAL)
static int PVRSRVDriverRemove(LDM_DEV *device);
static int PVRSRVDriverProbe(LDM_DEV *device);
@@ -177,6 +243,7 @@ static int PVRSRVDriverProbe(LDM_DEV *device, const struct pci_device_id *id);
#endif
#if defined(PVR_LDM_PCI_MODULE)
+/* This structure is used by the Linux module code */
struct pci_device_id powervr_id_table[] __devinitdata = {
{PCI_DEVICE(SYS_SGX_DEV_VENDOR_ID, SYS_SGX_DEV_DEVICE_ID)},
#if defined (SYS_SGX_DEV1_DEVICE_ID)
@@ -238,6 +305,22 @@ static struct platform_device powervr_device = {
};
#endif
+/*!
+******************************************************************************
+
+ @Function PVRSRVDriverProbe
+
+ @Description
+
+ See whether a given device is really one we can drive. The platform bus
+ handler has already established that we should be able to service this device
+ because of the name match. We probably don't need to do anything else.
+
+ @input pDevice - the device for which a probe is requested
+
+ @Return 0 for success or <0 for an error.
+
+*****************************************************************************/
#if defined(PVR_LDM_PLATFORM_MODULE)
PVR_MOD_STATIC int PVRSRVDriverProbe(LDM_DEV *pDevice)
#endif
@@ -249,14 +332,19 @@ static int __devinit PVRSRVDriverProbe(LDM_DEV *pDevice, const struct pci_device
PVR_TRACE(("PVRSRVDriverProbe(pDevice=%p) (%s)", pDevice, pDevice->name));
-#if 0
-
+#if 0 /* INTEGRATION_POINT */
+ /* Some systems require device-specific system initialisation.
+ * E.g. this lets the OS track a device's dependencies on various
+ * system hardware.
+ *
+ * Note: some systems use this to enable HW that SysAcquireData
+ * will depend on, therefore it must be called first.
+ */
if (PerDeviceSysInitialise((IMG_PVOID)pDevice) != PVRSRV_OK)
{
return -EINVAL;
}
#endif
-
#if defined(PVR_LDM_PLATFORM_MODULE)
if (!pDevice->dev.platform_data)
{
@@ -264,21 +352,53 @@ static int __devinit PVRSRVDriverProbe(LDM_DEV *pDevice, const struct pci_device
}
#endif
+ /* SysInitialise only designed to be called once.
+ */
psSysData = SysAcquireDataNoCheck();
- if ( psSysData == IMG_NULL)
+ if (psSysData == IMG_NULL)
{
gpsPVRLDMDev = pDevice;
-
if (SysInitialise() != PVRSRV_OK)
{
return -ENODEV;
}
}
+#if defined(CONFIG_ION_OMAP)
+ gpsIONClient = ion_client_create(omap_ion_device,
+ 1 << ION_HEAP_TYPE_CARVEOUT |
+ 1 << OMAP_ION_HEAP_TYPE_TILER,
+ "pvr");
+ if (IS_ERR_OR_NULL(gpsIONClient))
+ {
+ PVR_DPF((PVR_DBG_ERROR, "PVRSRVDriverProbe: Couldn't create ion client"));
+ return PTR_ERR(gpsIONClient);
+ }
+#endif /* defined(CONFIG_ION_OMAP) */
+
return 0;
}
+/*!
+******************************************************************************
+
+ @Function PVRSRVDriverRemove
+
+ @Description
+
+ This call is the opposite of the probe call: it is called when the device is
+ being removed from the driver's control. See the file $KERNELDIR/drivers/
+ base/bus.c:device_release_driver() for the call to this function.
+
+ This is the correct place to clean up anything our driver did while it was
+ asoociated with the device.
+
+ @input pDevice - the device for which driver detachment is happening
+
+ @Return 0 for success or <0 for an error.
+
+*****************************************************************************/
#if defined (PVR_LDM_PLATFORM_MODULE)
PVR_MOD_STATIC int PVRSRVDriverRemove(LDM_DEV *pDevice)
#endif
@@ -290,6 +410,11 @@ static void __devexit PVRSRVDriverRemove(LDM_DEV *pDevice)
PVR_TRACE(("PVRSRVDriverRemove(pDevice=%p)", pDevice));
+#if defined(CONFIG_ION_OMAP)
+ ion_client_destroy(gpsIONClient);
+ gpsIONClient = IMG_NULL;
+#endif
+
SysAcquireData(&psSysData);
#if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
@@ -305,7 +430,8 @@ static void __devexit PVRSRVDriverRemove(LDM_DEV *pDevice)
gpsPVRLDMDev = IMG_NULL;
-#if 0
+#if 0 /* INTEGRATION_POINT */
+ /* See previous integration point for details. */
if (PerDeviceSysDeInitialise((IMG_PVOID)pDevice) != PVRSRV_OK)
{
return -EINVAL;
@@ -319,59 +445,216 @@ static void __devexit PVRSRVDriverRemove(LDM_DEV *pDevice)
return;
#endif
}
-#endif
+#endif /* defined(PVR_LDM_MODULE) */
+#if defined(PVR_LDM_MODULE) || defined(SUPPORT_DRI_DRM)
+static PVRSRV_LINUX_MUTEX gsPMMutex;
+static IMG_BOOL bDriverIsSuspended;
+static IMG_BOOL bDriverIsShutdown;
+#endif
#if defined(PVR_LDM_MODULE) || defined(PVR_DRI_DRM_PLATFORM_DEV)
+/*!
+******************************************************************************
+
+ @Function PVRSRVDriverShutdown
+
+ @Description
+
+ Suspend device operation for system shutdown. This is called as part of the
+ system halt/reboot process. The driver is put into a quiescent state by
+ setting the power state to D3.
+
+ @input pDevice - the device for which shutdown is requested
+
+ @Return nothing
+
+*****************************************************************************/
PVR_MOD_STATIC void PVRSRVDriverShutdown(LDM_DEV *pDevice)
{
PVR_TRACE(("PVRSRVDriverShutdown(pDevice=%p)", pDevice));
- (void) PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D3);
+ LinuxLockMutex(&gsPMMutex);
+
+ if (!bDriverIsShutdown && !bDriverIsSuspended)
+ {
+ /*
+ * Take the bridge mutex, and never release it, to stop
+ * processes trying to use the driver after it has been
+ * shutdown.
+ */
+ LinuxLockMutex(&gPVRSRVLock);
+
+ (void) PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D3);
+ }
+
+ bDriverIsShutdown = IMG_TRUE;
+
+ /* The bridge mutex is held on exit */
+ LinuxUnLockMutex(&gsPMMutex);
}
-#endif
+#endif /* defined(PVR_LDM_MODULE) || defined(PVR_DRI_DRM_PLATFORM_DEV) */
#if defined(PVR_LDM_MODULE) || defined(SUPPORT_DRI_DRM)
+/*!
+******************************************************************************
+
+ @Function PVRSRVDriverSuspend
+
+ @Description
+
+ For 2.6 kernels:
+ Suspend device operation. We always get three calls to this regardless of
+ the state (D1-D3) chosen. The order is SUSPEND_DISABLE, SUSPEND_SAVE_STATE
+ then SUSPEND_POWER_DOWN. We take action as soon as we get the disable call,
+ the other states not being handled by us yet.
+
+ For MontaVista 2.4 kernels:
+ This call gets made once only when someone does something like
+
+ # echo -e -n "suspend powerdown 0" >/sys.devices/legacy/pvrsrv0/power
+
+ The 3rd, numeric parameter (0) in the above has no relevence and is not
+ passed into us. The state parameter is always zero and the level parameter
+ is always SUSPEND_POWER_DOWN. Vive la difference!
+
+ @input pDevice - the device for which resume is requested
+
+ @Return 0 for success or <0 for an error.
+
+*****************************************************************************/
#if defined(SUPPORT_DRI_DRM) && !defined(PVR_DRI_DRM_PLATFORM_DEV)
+#if defined(SUPPORT_DRM_MODESET)
+int PVRSRVDriverSuspend(struct pci_dev *pDevice, pm_message_t state)
+#else
int PVRSRVDriverSuspend(struct drm_device *pDevice, pm_message_t state)
+#endif
#else
PVR_MOD_STATIC int PVRSRVDriverSuspend(LDM_DEV *pDevice, pm_message_t state)
#endif
{
+ int res = 0;
#if !(defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL) && !defined(SUPPORT_DRI_DRM))
PVR_TRACE(( "PVRSRVDriverSuspend(pDevice=%p)", pDevice));
- if (PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D3) != PVRSRV_OK)
+ LinuxLockMutex(&gsPMMutex);
+
+ if (!bDriverIsSuspended && !bDriverIsShutdown)
{
- return -EINVAL;
+ LinuxLockMutex(&gPVRSRVLock);
+
+ if (PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D3) == PVRSRV_OK)
+ {
+ /* The bridge mutex will be held until we resume */
+ bDriverIsSuspended = IMG_TRUE;
+ }
+ else
+ {
+ LinuxUnLockMutex(&gPVRSRVLock);
+ res = -EINVAL;
+ }
}
+
+ LinuxUnLockMutex(&gsPMMutex);
#endif
- return 0;
+ return res;
}
+/*!
+******************************************************************************
+
+ @Function PVRSRVDriverResume
+
+ @Description
+
+ Resume device operation following a lull due to earlier suspension. It is
+ implicit we're returning to D0 (fully operational) state. We always get three
+ calls to this using level thus: RESUME_POWER_ON, RESUME_RESTORE_STATE then
+ RESUME_ENABLE. On 2.6 kernels We don't do anything until we get the enable
+ call; on the MontaVista set-up we only ever get the RESUME_POWER_ON call.
+
+ @input pDevice - the device for which resume is requested
+
+ @Return 0 for success or <0 for an error.
+
+*****************************************************************************/
#if defined(SUPPORT_DRI_DRM) && !defined(PVR_DRI_DRM_PLATFORM_DEV)
+#if defined(SUPPORT_DRM_MODESET)
+int PVRSRVDriverResume(struct pci_dev *pDevice)
+#else
int PVRSRVDriverResume(struct drm_device *pDevice)
+#endif
#else
PVR_MOD_STATIC int PVRSRVDriverResume(LDM_DEV *pDevice)
#endif
{
+ int res = 0;
#if !(defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL) && !defined(SUPPORT_DRI_DRM))
PVR_TRACE(("PVRSRVDriverResume(pDevice=%p)", pDevice));
- if (PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D0) != PVRSRV_OK)
+ LinuxLockMutex(&gsPMMutex);
+
+ if (bDriverIsSuspended && !bDriverIsShutdown)
{
- return -EINVAL;
+ if (PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D0) == PVRSRV_OK)
+ {
+ bDriverIsSuspended = IMG_FALSE;
+ LinuxUnLockMutex(&gPVRSRVLock);
+ }
+ else
+ {
+ /* The bridge mutex is not released on failure */
+ res = -EINVAL;
+ }
}
+
+ LinuxUnLockMutex(&gsPMMutex);
#endif
- return 0;
+ return res;
}
-#endif
+#endif /* defined(PVR_LDM_MODULE) || defined(SUPPORT_DRI_DRM) */
#if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL) && !defined(SUPPORT_DRI_DRM)
+/*
+ * If PVR_LDM_PCI_MODULE is defined (and PVR_MANUAL_POWER_CONTROL is *NOT* defined),
+ * the device can be suspended and resumed without suspending/resuming the
+ * system, by writing values into the power/state sysfs file for the device.
+ * To suspend:
+ * echo -n 2 > power/state
+ * To Resume:
+ * echo -n 0 > power/state
+ *
+ * The problem with this approach is that the device is usually left
+ * powered up; it is the responsibility of the bus driver to remove
+ * the power.
+ *
+ * Defining PVR_MANUAL_POWER_CONTROL is intended to make it easier to
+ * debug power management issues, especially when power is really removed
+ * from the device. It is easier to debug the driver if it is not being
+ * suspended/resumed with the rest of the system.
+ *
+ * When PVR_MANUAL_POWER_CONTROL is defined, the following proc entry is
+ * created:
+ * /proc/pvr/power_control
+ * The driver suspend/resume entry points defined below no longer suspend or
+ * resume the device. To suspend the device, type the following:
+ * echo 2 > /proc/pvr/power_control
+ * To resume the device, type:
+ * echo 0 > /proc/pvr/power_control
+ *
+ * The following example shows how to suspend/resume the device independently
+ * of the rest of the system.
+ * Suspend the device:
+ * echo 2 > /proc/pvr/power_control
+ * Suspend the system. Then you should be able to suspend and resume
+ * as normal. To resume the device type the following:
+ * echo 0 > /proc/pvr/power_control
+ */
+
IMG_INT PVRProcSetPowerLevel(struct file *file, const IMG_CHAR *buffer, IMG_UINT32 count, IMG_VOID *data)
{
IMG_CHAR data_buffer[2];
@@ -418,6 +701,23 @@ void ProcSeqShowPowerLevel(struct seq_file *sfile,void* el)
#endif
+/*!
+******************************************************************************
+
+ @Function PVRSRVOpen
+
+ @Description
+
+ Release access the PVR services node - called when a file is closed, whether
+ at exit or using close(2) system call.
+
+ @input pInode - the inode for the file being openeded
+
+ @input pFile - the file handle data for the actual file being opened
+
+ @Return 0 for success or <0 for an error.
+
+*****************************************************************************/
#if defined(SUPPORT_DRI_DRM)
int PVRSRVOpen(struct drm_device unref__ *dev, struct drm_file *pFile)
#else
@@ -478,6 +778,23 @@ err_unlock:
}
+/*!
+******************************************************************************
+
+ @Function PVRSRVRelease
+
+ @Description
+
+ Release access the PVR services node - called when a file is closed, whether
+ at exit or using close(2) system call.
+
+ @input pInode - the inode for the file being released
+
+ @input pFile - the file handle data for the actual file being released
+
+ @Return 0 for success or <0 for an error.
+
+*****************************************************************************/
#if defined(SUPPORT_DRI_DRM)
void PVRSRVRelease(void *pvPrivData)
#else
@@ -485,6 +802,7 @@ static int PVRSRVRelease(struct inode unref__ * pInode, struct file *pFile)
#endif
{
PVRSRV_FILE_PRIVATE_DATA *psPrivateData;
+ int err = 0;
LinuxLockMutex(&gPVRSRVLock);
@@ -499,7 +817,40 @@ static int PVRSRVRelease(struct inode unref__ * pInode, struct file *pFile)
list_del(&psPrivateData->sDRMAuthListItem);
#endif
-
+ if(psPrivateData->hKernelMemInfo)
+ {
+ PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo;
+
+ /* Look up the meminfo we just exported */
+ if(PVRSRVLookupHandle(KERNEL_HANDLE_BASE,
+ (IMG_PVOID *)&psKernelMemInfo,
+ psPrivateData->hKernelMemInfo,
+ PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK)
+ {
+ PVR_DPF((PVR_DBG_ERROR, "%s: Failed to look up export handle", __FUNCTION__));
+ err = -EFAULT;
+ goto err_unlock;
+ }
+
+ /* Tell the XProc about the export if required */
+ if (psKernelMemInfo->sShareMemWorkaround.bInUse)
+ {
+ BM_XProcIndexRelease(psKernelMemInfo->sShareMemWorkaround.ui32ShareIndex);
+ }
+
+ /* This drops the psMemInfo refcount bumped on export */
+ if(FreeMemCallBackCommon(psKernelMemInfo, 0,
+ PVRSRV_FREE_CALLBACK_ORIGIN_EXTERNAL) != PVRSRV_OK)
+ {
+ PVR_DPF((PVR_DBG_ERROR, "%s: FreeMemCallBackCommon failed", __FUNCTION__));
+ err = -EFAULT;
+ goto err_unlock;
+ }
+ }
+
+ /* Usually this is the same as OSGetCurrentProcessIDKM(),
+ * but not necessarily (e.g. fork(), child closes last..)
+ */
gui32ReleasePID = psPrivateData->ui32OpenPID;
PVRSRVProcessDisconnect(psPrivateData->ui32OpenPID);
gui32ReleasePID = 0;
@@ -509,18 +860,56 @@ static int PVRSRVRelease(struct inode unref__ * pInode, struct file *pFile)
psPrivateData, psPrivateData->hBlockAlloc);
#if !defined(SUPPORT_DRI_DRM)
- set_private(pFile, IMG_NULL);
+ set_private(pFile, IMG_NULL); /*nulling shared pointer*/
#endif
}
+err_unlock:
LinuxUnLockMutex(&gPVRSRVLock);
-
-#if !defined(SUPPORT_DRI_DRM)
- return 0;
+#if defined(SUPPORT_DRI_DRM)
+ return;
+#else
+ return err;
#endif
}
+/*!
+******************************************************************************
+
+ @Function PVRCore_Init
+
+ @Description
+
+ Insert the driver into the kernel.
+
+ The device major number is allocated by the kernel dynamically. This means
+ that the device node (nominally /dev/pvrsrv) will need to be re-made at boot
+ time if the number changes between subsequent loads of the module. While the
+ number often stays constant between loads this is not guaranteed. The node
+ is made as root on the shell with:
+
+ mknod /dev/pvrsrv c nnn 0
+
+ where nnn is the major number found in /proc/devices for DEVNAME and also
+ reported by the PVR_DPF() - look at the boot log using dmesg' to see this).
+
+ Currently the auto-generated script /etc/init.d/rc.pvr handles creation of
+ the device. In other environments the device may be created either through
+ devfs or sysfs.
+
+ Readable proc-filesystem entries under /proc/pvr are created with
+ CreateProcEntries(). These can be read at runtime to get information about
+ the device (eg. 'cat /proc/pvr/vm')
+
+ __init places the function in a special memory section that the kernel frees
+ once the function has been run. Refer also to module_init() macro call below.
+
+ @input none
+
+ @Return none
+
+*****************************************************************************/
#if defined(SUPPORT_DRI_DRM)
int PVRCore_Init(void)
#else
@@ -535,11 +924,17 @@ static int __init PVRCore_Init(void)
#endif
#if !defined(SUPPORT_DRI_DRM)
-
+ /*
+ * Must come before attempting to print anything via Services.
+ * For DRM, the initialisation will already have been done.
+ */
PVRDPFInit();
#endif
PVR_TRACE(("PVRCore_Init"));
+#if defined(PVR_LDM_MODULE) || defined(SUPPORT_DRI_DRM)
+ LinuxInitMutex(&gsPMMutex);
+#endif
LinuxInitMutex(&gPVRSRVLock);
if (CreateProcEntries ())
@@ -586,7 +981,7 @@ static int __init PVRCore_Init(void)
goto init_failed;
}
#endif
-#endif
+#endif /* PVR_LDM_PLATFORM_MODULE */
#if defined(PVR_LDM_PCI_MODULE)
if ((error = pci_register_driver(&powervr_driver)) != 0)
@@ -595,10 +990,12 @@ static int __init PVRCore_Init(void)
goto init_failed;
}
-#endif
+#endif /* PVR_LDM_PCI_MODULE */
#else
-
+ /*
+ * Drivers using LDM, will call SysInitialise in the probe/attach code
+ */
if ((eError = SysInitialise()) != PVRSRV_OK)
{
error = -ENODEV;
@@ -611,7 +1008,7 @@ static int __init PVRCore_Init(void)
#endif
goto init_failed;
}
-#endif
+#endif /* !defined(PVR_LDM_MODULE) */
#if !defined(SUPPORT_DRI_DRM)
AssignedMajorNumber = register_chrdev(0, DEVNAME, &pvrsrv_fops);
@@ -625,10 +1022,13 @@ static int __init PVRCore_Init(void)
}
PVR_TRACE(("PVRCore_Init: major device %d", AssignedMajorNumber));
-#endif
+#endif /* !defined(SUPPORT_DRI_DRM) */
#if defined(PVR_LDM_MODULE)
-
+ /*
+ * This code (using GPL symbols) facilitates automatic device
+ * node creation on platforms with udev (or similar).
+ */
psPvrClass = class_create(THIS_MODULE, "pvr");
if (IS_ERR(psPvrClass))
@@ -641,7 +1041,7 @@ static int __init PVRCore_Init(void)
psDev = device_create(psPvrClass, NULL, MKDEV(AssignedMajorNumber, 0),
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26))
NULL,
-#endif
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)) */
DEVNAME);
if (IS_ERR(psDev))
{
@@ -649,7 +1049,7 @@ static int __init PVRCore_Init(void)
error = -EBUSY;
goto destroy_class;
}
-#endif
+#endif /* defined(PVR_LDM_DEVICE_CLASS) */
return 0;
@@ -674,8 +1074,8 @@ sys_deinit:
platform_driver_unregister(&powervr_driver);
#endif
-#else
-
+#else /* defined(PVR_LDM_MODULE) */
+ /* LDM drivers call SysDeinitialise during PVRSRVDriverRemove */
{
SYS_DATA *psSysData;
@@ -685,7 +1085,7 @@ sys_deinit:
(void) SysDeinitialise(psSysData);
}
}
-#endif
+#endif /* defined(PVR_LDM_MODULE) */
init_failed:
PVRMMapCleanup();
LinuxMMCleanup();
@@ -695,9 +1095,34 @@ init_failed:
return error;
-}
+} /*PVRCore_Init*/
+
+
+/*!
+*****************************************************************************
+
+ @Function PVRCore_Cleanup
+
+ @Description
+
+ Remove the driver from the kernel.
+ There's no way we can get out of being unloaded other than panicking; we
+ just do everything and plough on regardless of error.
+ __exit places the function in a special memory section that the kernel frees
+ once the function has been run. Refer also to module_exit() macro call below.
+
+ Note that the for LDM on MontaVista kernels, the positioning of the driver
+ de-registration is the opposite way around than would be suggested by the
+ registration case or the 2,6 kernel case. This is the correct way to do it
+ and the kernel panics if you change it. You have been warned.
+
+ @input none
+
+ @Return none
+
+*****************************************************************************/
#if defined(SUPPORT_DRI_DRM)
void PVRCore_Cleanup(void)
#else
@@ -721,17 +1146,17 @@ static void __exit PVRCore_Cleanup(void)
#if !defined(SUPPORT_DRI_DRM)
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22))
if (
-#endif
+#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)) */
unregister_chrdev((IMG_UINT)AssignedMajorNumber, DRVNAME)
#if !(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22))
;
-#else
+#else /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)) */
)
{
PVR_DPF((PVR_DBG_ERROR," can't unregister device major %d", AssignedMajorNumber));
}
-#endif
-#endif
+#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)) */
+#endif /* !defined(SUPPORT_DRI_DRM) */
#if defined(PVR_LDM_MODULE)
@@ -746,7 +1171,7 @@ static void __exit PVRCore_Cleanup(void)
platform_driver_unregister(&powervr_driver);
#endif
-#else
+#else /* defined(PVR_LDM_MODULE) */
#if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
if (gPVRPowerLevel != 0)
{
@@ -756,9 +1181,9 @@ static void __exit PVRCore_Cleanup(void)
}
}
#endif
-
+ /* LDM drivers call SysDeinitialise during PVRSRVDriverRemove */
(void) SysDeinitialise(psSysData);
-#endif
+#endif /* defined(PVR_LDM_MODULE) */
PVRMMapCleanup();
@@ -773,6 +1198,12 @@ static void __exit PVRCore_Cleanup(void)
PVR_TRACE(("PVRCore_Cleanup: unloading"));
}
+/*
+ * These macro calls define the initialisation and removal functions of the
+ * driver. Although they are prefixed `module_', they apply when compiling
+ * statically as well; in both cases they define the function the kernel will
+ * run to start/stop the driver.
+*/
#if !defined(SUPPORT_DRI_DRM)
module_init(PVRCore_Init);
module_exit(PVRCore_Cleanup);
diff --git a/sgx/services4/srvkm/env/linux/mutex.c b/sgx/services4/srvkm/env/linux/mutex.c
index 742fa03..84e2a74 100644
--- a/sgx/services4/srvkm/env/linux/mutex.c
+++ b/sgx/services4/srvkm/env/linux/mutex.c
@@ -1,28 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Linux mutex interface
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include <linux/version.h>
#include <linux/errno.h>
@@ -79,7 +95,7 @@ IMG_BOOL LinuxIsLockedMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
}
-#else
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) */
IMG_VOID LinuxInitMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
@@ -98,7 +114,9 @@ PVRSRV_ERROR LinuxLockMutexInterruptible(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
{
if(down_interruptible(&psPVRSRVMutex->sSemaphore) == -EINTR)
{
-
+ /* The process was sent a signal while waiting for the semaphore
+ * (e.g. a kill signal from userspace)
+ */
return PVRSRV_ERROR_MUTEX_INTERRUPTIBLE_ERROR;
}else{
atomic_dec(&psPVRSRVMutex->Count);
@@ -132,5 +150,5 @@ IMG_BOOL LinuxIsLockedMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
return (IMG_BOOL)iCount;
}
-#endif
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) */
diff --git a/sgx/services4/srvkm/env/linux/mutex.h b/sgx/services4/srvkm/env/linux/mutex.h
index 5e787b7..2c7d658 100644
--- a/sgx/services4/srvkm/env/linux/mutex.h
+++ b/sgx/services4/srvkm/env/linux/mutex.h
@@ -1,28 +1,45 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Linux mutex interface
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
+
#ifndef __INCLUDED_LINUX_MUTEX_H_
#define __INCLUDED_LINUX_MUTEX_H_
@@ -41,12 +58,16 @@
typedef struct mutex PVRSRV_LINUX_MUTEX;
-#else
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) */
typedef struct {
struct semaphore sSemaphore;
-
+ /* since Linux's struct semaphore is intended to be
+ * opaque we don't poke inside for the count and
+ * instead we track it outselves. (So we can implement
+ * LinuxIsLockedMutex)
+ */
atomic_t Count;
}PVRSRV_LINUX_MUTEX;
@@ -66,5 +87,5 @@ extern IMG_VOID LinuxUnLockMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex);
extern IMG_BOOL LinuxIsLockedMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex);
-#endif
+#endif /* __INCLUDED_LINUX_MUTEX_H_ */
diff --git a/sgx/services4/srvkm/env/linux/mutils.c b/sgx/services4/srvkm/env/linux/mutils.c
index a012cf5..9679ed7 100644
--- a/sgx/services4/srvkm/env/linux/mutils.c
+++ b/sgx/services4/srvkm/env/linux/mutils.c
@@ -1,28 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Linux memory interface support functions
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include <linux/version.h>
@@ -77,15 +93,23 @@ pvr_pat_entry(u64 pat, IMG_UINT index)
static IMG_VOID
PVRLinuxX86PATProbe(IMG_VOID)
{
-
- if (cpu_has_pat)
+ /*
+ * cpu_has_pat indicates whether PAT support is available on the CPU,
+ * but doesn't indicate if it has been enabled.
+ */
+ if (cpu_has_pat) /* PRQA S 3335 */ /* ignore 'no function declared' */
{
u64 pat;
IMG_UINT pat_index;
IMG_UINT pat_entry;
PVR_TRACE(("%s: PAT available", __FUNCTION__));
-
+ /*
+ * There is no Linux API for finding out if write combining
+ * is avaialable through the PAT, so we take the direct
+ * approach, and see if the PAT MSR contains a write combining
+ * entry.
+ */
rdmsrl(MSR_IA32_CR_PAT, pat);
PVR_TRACE(("%s: Top 32 bits of PAT: 0x%.8x", __FUNCTION__, (IMG_UINT)(pat >> 32)));
PVR_TRACE(("%s: Bottom 32 bits of PAT: 0x%.8x", __FUNCTION__, (IMG_UINT)(pat)));
@@ -110,21 +134,28 @@ PVRLinuxX86PATProbe(IMG_VOID)
{
PVR_TRACE(("%s: Write combining not available", __FUNCTION__));
}
-#else
+#else /* defined(SUPPORT_LINUX_X86_WRITECOMBINE) */
PVR_TRACE(("%s: Write combining disabled in driver build", __FUNCTION__));
-#endif
-#endif
+#endif /* defined(SUPPORT_LINUX_X86_WRITECOMBINE) */
+#endif /* DEBUG */
}
pgprot_t
pvr_pgprot_writecombine(pgprot_t prot)
{
-
-
+ /*
+ * It would be worth checking from time to time to see if a
+ * pgprot_writecombine function (or similar) is introduced on Linux for
+ * x86 processors. If so, this function, and PVRLinuxX86PATProbe can be
+ * removed, and a macro used to select between pgprot_writecombine and
+ * pgprot_noncached, dpending on the value for of
+ * SUPPORT_LINUX_X86_WRITECOMBINE.
+ */
+ /* PRQA S 0481,0482 2 */ /* scalar expressions */
return (g_write_combining_available) ?
__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_MASK) | _PAGE_CACHE_WC) : pgprot_noncached(prot);
}
-#endif
+#endif /* defined(SUPPORT_LINUX_X86_PAT) */
IMG_VOID
PVRLinuxMUtilsInit(IMG_VOID)
diff --git a/sgx/services4/srvkm/env/linux/mutils.h b/sgx/services4/srvkm/env/linux/mutils.h
index b2a8ba0..4921e60 100644
--- a/sgx/services4/srvkm/env/linux/mutils.h
+++ b/sgx/services4/srvkm/env/linux/mutils.h
@@ -1,29 +1,46 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Memory management support utils
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description Declares various memory management support functions
+ for Linux.
+@License Dual MIT/GPLv2
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#ifndef __IMG_LINUX_MUTILS_H__
#define __IMG_LINUX_MUTILS_H__
@@ -99,5 +116,5 @@
IMG_VOID PVRLinuxMUtilsInit(IMG_VOID);
-#endif
+#endif /* __IMG_LINUX_MUTILS_H__ */
diff --git a/sgx/services4/srvkm/env/linux/osfunc.c b/sgx/services4/srvkm/env/linux/osfunc.c
index 1fb99f2..4e4b3a0 100644
--- a/sgx/services4/srvkm/env/linux/osfunc.c
+++ b/sgx/services4/srvkm/env/linux/osfunc.c
@@ -1,28 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Environment related functions
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include <linux/version.h>
@@ -74,6 +90,15 @@
#include "event.h"
#include "linkage.h"
#include "pvr_uaccess.h"
+#include "lock.h"
+
+#if defined (SUPPORT_ION)
+#include "ion.h"
+#endif
+
+#if defined (CONFIG_X86_PAE)
+#error Physical Address Extension not supported with the driver
+#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
#define ON_EACH_CPU(func, info, wait) on_each_cpu(func, info, wait)
@@ -82,6 +107,13 @@
#endif
#if defined(PVR_LINUX_USING_WORKQUEUES) && !defined(CONFIG_PREEMPT)
+/*
+ * Services spins at certain points waiting for events (e.g. swap
+ * chain destrucion). If those events rely on workqueues running,
+ * it needs to be possible to preempt the waiting thread.
+ * Removing the need for CONFIG_PREEMPT will require adding preemption
+ * points at various points in Services.
+ */
#error "A preemptible Linux kernel is required when using workqueues"
#endif
@@ -89,7 +121,7 @@
#define EVENT_OBJECT_TIMEOUT_MS (2000)
#else
#define EVENT_OBJECT_TIMEOUT_MS (100)
-#endif
+#endif /* EMULATOR */
#if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
PVRSRV_ERROR OSAllocMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID *ppvCpuVAddr, IMG_HANDLE *phBlockAlloc)
@@ -102,7 +134,7 @@ PVRSRV_ERROR OSAllocMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOI
if (ui32Size > PAGE_SIZE)
{
-
+ /* Try to allocate the memory using vmalloc */
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
*ppvCpuVAddr = _VMallocWrapper(ui32Size, PVRSRV_HAP_CACHED, pszFilename, ui32Line);
#else
@@ -135,7 +167,7 @@ static inline int is_vmalloc_addr(const void *pvCpuVAddr)
return lAddr >= VMALLOC_START && lAddr < VMALLOC_END;
}
-#endif
+#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)) */
#if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
PVRSRV_ERROR OSFreeMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID pvCpuVAddr, IMG_HANDLE hBlockAlloc)
@@ -172,6 +204,9 @@ PVRSRV_ERROR
OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags,
IMG_UINT32 ui32Size,
IMG_UINT32 ui32PageSize,
+ IMG_PVOID pvPrivData,
+ IMG_UINT32 ui32PrivDataLength,
+ IMG_HANDLE hBMHandle,
IMG_VOID **ppvCpuVAddr,
IMG_HANDLE *phOSMemHandle)
{
@@ -180,7 +215,8 @@ OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags,
PVR_UNREFERENCED_PARAMETER(ui32PageSize);
#if 0
-
+ /* For debug: force all OSAllocPages allocations to have a kernel
+ * virtual address */
if(ui32AllocFlags & PVRSRV_HAP_SINGLE_PROCESS)
{
ui32AllocFlags &= ~PVRSRV_HAP_SINGLE_PROCESS;
@@ -188,6 +224,22 @@ OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags,
}
#endif
+ if(ui32AllocFlags & PVRSRV_MEM_ION)
+ {
+ /* We'll only see HAP_SINGLE_PROCESS with MEM_ION */
+ BUG_ON((ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK) != PVRSRV_HAP_SINGLE_PROCESS);
+
+ psLinuxMemArea = NewIONLinuxMemArea(ui32Size, ui32AllocFlags,
+ pvPrivData, ui32PrivDataLength);
+ if(!psLinuxMemArea)
+ {
+ return PVRSRV_ERROR_OUT_OF_MEMORY;
+ }
+
+ PVRMMapRegisterArea(psLinuxMemArea);
+ goto ExitSkipSwitch;
+ }
+
switch(ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK)
{
case PVRSRV_HAP_KERNEL_ONLY:
@@ -201,8 +253,9 @@ OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags,
}
case PVRSRV_HAP_SINGLE_PROCESS:
{
-
-
+ /* Currently PVRSRV_HAP_SINGLE_PROCESS implies that we dont need a
+ * kernel virtual mapping, but will need a user space virtual mapping */
+
psLinuxMemArea = NewAllocPagesLinuxMemArea(ui32Size, ui32AllocFlags);
if(!psLinuxMemArea)
{
@@ -214,10 +267,18 @@ OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags,
case PVRSRV_HAP_MULTI_PROCESS:
{
-
+ /* Currently PVRSRV_HAP_MULTI_PROCESS implies that we need a kernel
+ * virtual mapping and potentially multiple user space virtual
+ * mappings: Note: these eat into our limited kernel virtual
+ * address space. */
+
#if defined(VIVT_CACHE) || defined(__sh__)
-
- ui32AllocFlags &= ~(PVRSRV_HAP_CACHED|PVRSRV_HAP_SMART);
+ /* ARM9 caches are tagged with virtual pages, not physical. As we are going to
+ * share this memory in different address spaces, we don't want it to be cached.
+ * ARM11 has physical tagging, so we can cache this memory without fear of virtual
+ * address aliasing in the TLB, as long as the kernel supports cache colouring for
+ * VIPT architectures. */
+ ui32AllocFlags &= ~PVRSRV_HAP_CACHED;
#endif
psLinuxMemArea = NewVMallocLinuxMemArea(ui32Size, ui32AllocFlags);
if(!psLinuxMemArea)
@@ -234,6 +295,16 @@ OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags,
return PVRSRV_ERROR_INVALID_PARAMS;
}
+ /*
+ In case of sparse mapping we need to handle back to the BM as it
+ knows the mapping info
+ */
+ if (ui32AllocFlags & PVRSRV_MEM_SPARSE)
+ {
+ psLinuxMemArea->hBMHandle = hBMHandle;
+ }
+
+ExitSkipSwitch:
*ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea);
*phOSMemHandle = psLinuxMemArea;
@@ -302,7 +373,7 @@ OSGetSubMemHandle(IMG_HANDLE hOSMemHandle,
}
*phOSMemHandleRet = psLinuxMemArea;
-
+ /* KERNEL_ONLY areas are never mmapable. */
if(ui32Flags & PVRSRV_HAP_KERNEL_ONLY)
{
return PVRSRV_OK;
@@ -344,23 +415,6 @@ OSReleaseSubMemHandle(IMG_VOID *hOSMemHandle, IMG_UINT32 ui32Flags)
return PVRSRV_OK;
}
-IMG_VOID
-OSMemHandleRegisterSmart(IMG_VOID *hOSMemHandle, IMG_HANDLE hSmartCache)
-{
- LinuxMemArea *psLinuxMemArea = hOSMemHandle;
- psLinuxMemArea->hSmartCache = hSmartCache;
-}
-
-IMG_VOID
-OSMemHandleUnegisterSmart(IMG_VOID *hOSMemHandle, IMG_HANDLE hSmartCache)
-{
- LinuxMemArea *psLinuxMemArea = hOSMemHandle;
- if (psLinuxMemArea->hSmartCache == hSmartCache)
- {
- psLinuxMemArea->hSmartCache = NULL;
- }
-}
-
#if defined(SUPPORT_DRI_DRM_EXTERNAL)
IMG_VOID
@@ -388,7 +442,33 @@ OSMemHandleToCpuPAddr(IMG_VOID *hOSMemHandle, IMG_UINT32 ui32ByteOffset)
}
+IMG_BOOL OSMemHandleIsPhysContig(IMG_VOID *hOSMemHandle)
+{
+ LinuxMemArea *psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
+
+ PVR_ASSERT(psLinuxMemArea);
+ if(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_EXTERNAL_KV)
+ return psLinuxMemArea->uData.sExternalKV.bPhysContig;
+
+ return IMG_FALSE;
+}
+
+
+/*!
+******************************************************************************
+
+ @Function OSMemCopy
+
+ @Description Copies memory around
+
+ @Input pvDst - pointer to dst
+ @Output pvSrc - pointer to src
+ @Input ui32Size - bytes to copy
+
+ @Return none
+
+******************************************************************************/
IMG_VOID OSMemCopy(IMG_VOID *pvDst, IMG_VOID *pvSrc, IMG_UINT32 ui32Size)
{
#if defined(USE_UNOPTIMISED_MEMCPY)
@@ -407,6 +487,22 @@ IMG_VOID OSMemCopy(IMG_VOID *pvDst, IMG_VOID *pvSrc, IMG_UINT32 ui32Size)
}
+/*!
+******************************************************************************
+
+ @Function OSMemSet
+
+ @Description Function that does the same as the C memset() functions
+
+ @Modified *pvDest : pointer to start of buffer to be set
+
+ @Input ui8Value: value to set each byte to
+
+ @Input ui32Size : number of bytes to set
+
+ @Return IMG_VOID
+
+******************************************************************************/
IMG_VOID OSMemSet(IMG_VOID *pvDest, IMG_UINT8 ui8Value, IMG_UINT32 ui32Size)
{
#if defined(USE_UNOPTIMISED_MEMSET)
@@ -424,11 +520,21 @@ IMG_VOID OSMemSet(IMG_VOID *pvDest, IMG_UINT8 ui8Value, IMG_UINT32 ui32Size)
}
+/*!
+******************************************************************************
+ @Function OSStringCopy
+ @Description strcpy
+******************************************************************************/
IMG_CHAR *OSStringCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc)
{
return (strcpy(pszDest, pszSrc));
}
+/*!
+******************************************************************************
+ @Function OSSNPrintf
+ @Description snprintf
+******************************************************************************/
IMG_INT32 OSSNPrintf(IMG_CHAR *pStr, IMG_UINT32 ui32Size, const IMG_CHAR *pszFormat, ...)
{
va_list argList;
@@ -441,6 +547,19 @@ IMG_INT32 OSSNPrintf(IMG_CHAR *pStr, IMG_UINT32 ui32Size, const IMG_CHAR *pszFor
return iCount;
}
+/*!
+******************************************************************************
+
+ @Function OSBreakResourceLock
+
+ @Description unlocks an OS dependant resource
+
+ @Input phResource - pointer to OS dependent resource structure
+ @Input ui32ID - Lock value to look for
+
+ @Return
+
+******************************************************************************/
IMG_VOID OSBreakResourceLock (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID)
{
volatile IMG_UINT32 *pui32Access = (volatile IMG_UINT32 *)&psResource->ui32Lock;
@@ -464,6 +583,18 @@ IMG_VOID OSBreakResourceLock (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID)
}
+/*!
+******************************************************************************
+
+ @Function OSCreateResource
+
+ @Description creates a OS dependant resource object
+
+ @Input phResource - pointer to OS dependent resource
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSCreateResource(PVRSRV_RESOURCE *psResource)
{
psResource->ui32ID = 0;
@@ -473,6 +604,18 @@ PVRSRV_ERROR OSCreateResource(PVRSRV_RESOURCE *psResource)
}
+/*!
+******************************************************************************
+
+ @Function OSDestroyResource
+
+ @Description destroys an OS dependant resource object
+
+ @Input phResource - pointer to OS dependent resource
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSDestroyResource (PVRSRV_RESOURCE *psResource)
{
OSBreakResourceLock (psResource, psResource->ui32ID);
@@ -481,12 +624,26 @@ PVRSRV_ERROR OSDestroyResource (PVRSRV_RESOURCE *psResource)
}
+/*!
+******************************************************************************
+
+ @Function OSInitEnvData
+
+ @Description Allocates space for env specific data
+
+ @Input ppvEnvSpecificData - pointer to pointer in which to return
+ allocated data.
+ @Input ui32MMUMode - MMU mode.
+
+ @Return nothing
+
+******************************************************************************/
PVRSRV_ERROR OSInitEnvData(IMG_PVOID *ppvEnvSpecificData)
{
ENV_DATA *psEnvData;
PVRSRV_ERROR eError;
-
+ /* allocate env specific data */
eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), (IMG_VOID **)&psEnvData, IMG_NULL,
"Environment Data");
if (eError != PVRSRV_OK)
@@ -500,22 +657,34 @@ PVRSRV_ERROR OSInitEnvData(IMG_PVOID *ppvEnvSpecificData)
if (eError != PVRSRV_OK)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), psEnvData, IMG_NULL);
-
+ /*not nulling pointer, out of scope*/
return eError;
}
-
+ /* ISR installation flags */
psEnvData->bMISRInstalled = IMG_FALSE;
psEnvData->bLISRInstalled = IMG_FALSE;
-
+ /* copy structure back */
*ppvEnvSpecificData = psEnvData;
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSDeInitEnvData
+
+ @Description frees env specific data memory
+
+ @Input pvEnvSpecificData - pointer to private structure
+
+ @Return PVRSRV_OK on success else PVRSRV_ERROR_OUT_OF_MEMORY
+
+******************************************************************************/
PVRSRV_ERROR OSDeInitEnvData(IMG_PVOID pvEnvSpecificData)
{
ENV_DATA *psEnvData = (ENV_DATA*)pvEnvSpecificData;
@@ -527,20 +696,42 @@ PVRSRV_ERROR OSDeInitEnvData(IMG_PVOID pvEnvSpecificData)
psEnvData->pvBridgeData = IMG_NULL;
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), pvEnvSpecificData, IMG_NULL);
-
+ /*not nulling pointer, copy on stack*/
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSReleaseThreadQuanta
+ @Description
+ Releases thread quanta
+
+ @Return nothing
+
+******************************************************************************/
IMG_VOID OSReleaseThreadQuanta(IMG_VOID)
{
schedule();
}
+/*!
+******************************************************************************
+
+ @Function OSClockus
+
+ @Description
+ This function returns the clock in microseconds
+ @Input void
+
+ @Return - clock (us)
+
+******************************************************************************/
IMG_UINT32 OSClockus(IMG_VOID)
{
IMG_UINT32 time, j = jiffies;
@@ -563,25 +754,71 @@ IMG_VOID OSSleepms(IMG_UINT32 ui32Timems)
}
+/*!
+******************************************************************************
+
+ @Function OSFuncHighResTimerCreate
+ @Description
+ This function creates a high res timer who's handle is returned
+
+ @Input nothing
+
+ @Return handle
+
+******************************************************************************/
IMG_HANDLE OSFuncHighResTimerCreate(IMG_VOID)
{
-
+ /* We don't need a handle, but we must return non-NULL */
return (IMG_HANDLE) 1;
}
+/*!
+******************************************************************************
+
+ @Function OSFuncHighResTimerGetus
+
+ @Description
+ This function returns the current timestamp in us
+ @Input nothing
+
+ @Return handle
+
+******************************************************************************/
IMG_UINT32 OSFuncHighResTimerGetus(IMG_HANDLE hTimer)
{
return (IMG_UINT32) jiffies_to_usecs(jiffies);
}
+/*!
+******************************************************************************
+
+ @Function OSFuncHighResTimerDestroy
+ @Description
+ This function will destroy the high res timer
+
+ @Input nothing
+
+ @Return handle
+
+******************************************************************************/
IMG_VOID OSFuncHighResTimerDestroy(IMG_HANDLE hTimer)
{
PVR_UNREFERENCED_PARAMETER(hTimer);
}
+/*!
+******************************************************************************
+
+ @Function OSGetCurrentProcessIDKM
+
+ @Description Returns handle for current process
+
+ @Return ID of current process
+
+*****************************************************************************/
IMG_UINT32 OSGetCurrentProcessIDKM(IMG_VOID)
{
if (in_interrupt())
@@ -601,6 +838,16 @@ IMG_UINT32 OSGetCurrentProcessIDKM(IMG_VOID)
}
+/*!
+******************************************************************************
+
+ @Function OSGetPageSize
+
+ @Description gets page size
+
+ @Return page size
+
+******************************************************************************/
IMG_UINT32 OSGetPageSize(IMG_VOID)
{
#if defined(__sh__)
@@ -613,6 +860,16 @@ IMG_UINT32 OSGetPageSize(IMG_VOID)
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
+/*!
+******************************************************************************
+
+ @Function DeviceISRWrapper
+
+ @Description wrapper for Device ISR function to conform to ISR OS interface
+
+ @Return
+
+******************************************************************************/
static irqreturn_t DeviceISRWrapper(int irq, void *dev_id
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
, struct pt_regs *regs
@@ -649,6 +906,19 @@ out:
+/*!
+******************************************************************************
+
+ @Function SystemISRWrapper
+
+ @Description wrapper for System ISR function to conform to ISR OS interface
+
+ @Input Interrupt - NT interrupt object.
+ @Input Context - Context parameter
+
+ @Return
+
+******************************************************************************/
static irqreturn_t SystemISRWrapper(int irq, void *dev_id
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
, struct pt_regs *regs
@@ -682,6 +952,21 @@ out:
return bStatus ? IRQ_HANDLED : IRQ_NONE;
#endif
}
+/*!
+******************************************************************************
+
+ @Function OSInstallDeviceLISR
+
+ @Description Installs a Device ISR
+
+ @Input pvSysData
+ @Input ui32Irq - IRQ number
+ @Input pszISRName - ISR name
+ @Input pvDeviceNode - device node contains ISR function and data argument
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSInstallDeviceLISR(IMG_VOID *pvSysData,
IMG_UINT32 ui32Irq,
IMG_CHAR *pszISRName,
@@ -718,6 +1003,18 @@ PVRSRV_ERROR OSInstallDeviceLISR(IMG_VOID *pvSysData,
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSUninstallDeviceLISR
+
+ @Description Uninstalls a Device ISR
+
+ @Input pvSysData - sysdata
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSUninstallDeviceLISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -739,6 +1036,19 @@ PVRSRV_ERROR OSUninstallDeviceLISR(IMG_VOID *pvSysData)
}
+/*!
+******************************************************************************
+
+ @Function OSInstallSystemLISR
+
+ @Description Installs a System ISR
+
+ @Input psSysData
+ @Input ui32Irq - IRQ number
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSInstallSystemLISR(IMG_VOID *pvSysData, IMG_UINT32 ui32Irq)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -773,6 +1083,18 @@ PVRSRV_ERROR OSInstallSystemLISR(IMG_VOID *pvSysData, IMG_UINT32 ui32Irq)
}
+/*!
+******************************************************************************
+
+ @Function OSUninstallSystemLISR
+
+ @Description Uninstalls a System ISR
+
+ @Input psSysData
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSUninstallSystemLISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -794,6 +1116,18 @@ PVRSRV_ERROR OSUninstallSystemLISR(IMG_VOID *pvSysData)
}
#if defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE)
+/*!
+******************************************************************************
+
+ @Function MISRWrapper
+
+ @Description OS dependent MISR wrapper
+
+ @Input psSysData
+
+ @Return error status
+
+******************************************************************************/
static void MISRWrapper(
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
void *data
@@ -809,6 +1143,18 @@ static void MISRWrapper(
}
+/*!
+******************************************************************************
+
+ @Function OSInstallMISR
+
+ @Description Installs an OS dependent MISR
+
+ @Input psSysData
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -843,6 +1189,18 @@ PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData)
}
+/*!
+******************************************************************************
+
+ @Function OSUninstallMISR
+
+ @Description Uninstalls an OS dependent MISR
+
+ @Input psSysData
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -864,6 +1222,18 @@ PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData)
}
+/*!
+******************************************************************************
+
+ @Function OSScheduleMISR
+
+ @Description Schedules an OS dependent MISR
+
+ @Input pvSysData
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -876,8 +1246,20 @@ PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData)
return PVRSRV_OK;
}
-#else
+#else /* defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE) */
#if defined(PVR_LINUX_MISR_USING_WORKQUEUE)
+/*!
+******************************************************************************
+
+ @Function MISRWrapper
+
+ @Description OS dependent MISR wrapper
+
+ @Input psSysData
+
+ @Return error status
+
+******************************************************************************/
static void MISRWrapper(
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
void *data
@@ -893,6 +1275,18 @@ static void MISRWrapper(
}
+/*!
+******************************************************************************
+
+ @Function OSInstallMISR
+
+ @Description Installs an OS dependent MISR
+
+ @Input psSysData
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -919,6 +1313,18 @@ PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData)
}
+/*!
+******************************************************************************
+
+ @Function OSUninstallMISR
+
+ @Description Uninstalls an OS dependent MISR
+
+ @Input psSysData
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -940,6 +1346,18 @@ PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData)
}
+/*!
+******************************************************************************
+
+ @Function OSScheduleMISR
+
+ @Description Schedules an OS dependent MISR
+
+ @Input pvSysData
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -953,9 +1371,21 @@ PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData)
return PVRSRV_OK;
}
-#else
+#else /* #if defined(PVR_LINUX_MISR_USING_WORKQUEUE) */
+/*!
+******************************************************************************
+
+ @Function MISRWrapper
+
+ @Description OS dependent MISR wrapper
+
+ @Input psSysData
+
+ @Return error status
+
+******************************************************************************/
static void MISRWrapper(unsigned long data)
{
SYS_DATA *psSysData;
@@ -966,6 +1396,18 @@ static void MISRWrapper(unsigned long data)
}
+/*!
+******************************************************************************
+
+ @Function OSInstallMISR
+
+ @Description Installs an OS dependent MISR
+
+ @Input psSysData
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -987,6 +1429,18 @@ PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData)
}
+/*!
+******************************************************************************
+
+ @Function OSUninstallMISR
+
+ @Description Uninstalls an OS dependent MISR
+
+ @Input psSysData
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -1007,6 +1461,18 @@ PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData)
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSScheduleMISR
+
+ @Description Schedules an OS dependent MISR
+
+ @Input pvSysData
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = (SYS_DATA*)pvSysData;
@@ -1020,10 +1486,10 @@ PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData)
return PVRSRV_OK;
}
-#endif
-#endif
+#endif /* #if defined(PVR_LINUX_MISR_USING_WORKQUEUE) */
+#endif /* #if defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE) */
-#endif
+#endif /* #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) */
IMG_VOID OSPanic(IMG_VOID)
{
@@ -1035,6 +1501,19 @@ IMG_VOID OSPanic(IMG_VOID)
#else
#define OS_TAS(p) tas(p)
#endif
+/*!
+******************************************************************************
+
+ @Function OSLockResource
+
+ @Description locks an OS dependant Resource
+
+ @Input phResource - pointer to OS dependent Resource
+ @Input bBlock - do we want to block?
+
+ @Return error status
+
+******************************************************************************/
PVRSRV_ERROR OSLockResource ( PVRSRV_RESOURCE *psResource,
IMG_UINT32 ui32ID)
@@ -1050,6 +1529,18 @@ PVRSRV_ERROR OSLockResource ( PVRSRV_RESOURCE *psResource,
}
+/*!
+******************************************************************************
+
+ @Function OSUnlockResource
+
+ @Description unlocks an OS dependant resource
+
+ @Input phResource - pointer to OS dependent resource structure
+
+ @Return
+
+******************************************************************************/
PVRSRV_ERROR OSUnlockResource (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID)
{
volatile IMG_UINT32 *pui32Access = (volatile IMG_UINT32 *)&psResource->ui32Lock;
@@ -1080,6 +1571,18 @@ PVRSRV_ERROR OSUnlockResource (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID)
}
+/*!
+******************************************************************************
+
+ @Function OSIsResourceLocked
+
+ @Description tests if resource is locked
+
+ @Input phResource - pointer to OS dependent resource structure
+
+ @Return error status
+
+******************************************************************************/
IMG_BOOL OSIsResourceLocked (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID)
{
volatile IMG_UINT32 *pui32Access = (volatile IMG_UINT32 *)&psResource->ui32Lock;
@@ -1101,7 +1604,7 @@ PVRSRV_ERROR OSPowerLockWrap(IMG_BOOL bTryLock)
IMG_VOID OSPowerLockUnwrap (IMG_VOID)
{
}
-#endif
+#endif /* SYS_CUSTOM_POWERLOCK_WRAP */
IMG_CPU_PHYADDR OSMapLinToCPUPhys(IMG_HANDLE hOSMemHandle,
@@ -1114,8 +1617,6 @@ IMG_CPU_PHYADDR OSMapLinToCPUPhys(IMG_HANDLE hOSMemHandle,
PVR_ASSERT(hOSMemHandle != IMG_NULL);
-
-
psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
uiByteOffset = (IMG_UINTPTR_T)pvLinAddr - (IMG_UINTPTR_T)LinuxMemAreaToCpuVAddr(psLinuxMemArea);
@@ -1127,6 +1628,22 @@ IMG_CPU_PHYADDR OSMapLinToCPUPhys(IMG_HANDLE hOSMemHandle,
}
+/*!
+******************************************************************************
+
+ @Function OSMapPhysToLin
+
+ @Description Maps the physical memory into linear addr range
+
+ @Input BasePAddr : physical cpu address
+
+ @Input ui32Bytes - bytes to map
+
+ @Input ui32CacheType - cache type
+
+ @Return : Linear addr of mapping on success, else NULL
+
+ ******************************************************************************/
IMG_VOID *
OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr,
IMG_UINT32 ui32Bytes,
@@ -1135,7 +1652,11 @@ OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr,
{
if(ui32MappingFlags & PVRSRV_HAP_KERNEL_ONLY)
{
-
+ /*
+ * Provide some backwards compatibility, until all callers
+ * have been updated to pass a non-null OSMemHandle pointer.
+ * Such callers must not call OSMapLinToCPUPhys.
+ */
if(phOSMemHandle == IMG_NULL)
{
IMG_VOID *pvIORemapCookie;
@@ -1167,6 +1688,12 @@ OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr,
return IMG_NULL;
}
+/*!
+******************************************************************************
+ @Function OSUnMapPhysToLin
+ @Description Unmaps memory that was mapped with OSMapPhysToLin
+ @Return TRUE on success, else FALSE
+******************************************************************************/
IMG_BOOL
OSUnMapPhysToLin(IMG_VOID *pvLinAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32MappingFlags, IMG_HANDLE hOSMemHandle)
{
@@ -1198,6 +1725,12 @@ OSUnMapPhysToLin(IMG_VOID *pvLinAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32Mappi
return IMG_FALSE;
}
+/*!
+******************************************************************************
+ @Function RegisterExternalMem
+ @Description Registers external memory for user mode mapping
+ @Return TRUE on success, else FALSE, MemHandle out
+******************************************************************************/
static PVRSRV_ERROR
RegisterExternalMem(IMG_SYS_PHYADDR *pBasePAddr,
IMG_VOID *pvCPUVAddr,
@@ -1233,10 +1766,19 @@ RegisterExternalMem(IMG_SYS_PHYADDR *pBasePAddr,
}
case PVRSRV_HAP_MULTI_PROCESS:
{
-
+ /* Currently PVRSRV_HAP_MULTI_PROCESS implies that we need a kernel
+ * virtual mapping and potentially multiple user space virtual mappings.
+ * Beware that the kernel virtual address space is a limited resource.
+ */
#if defined(VIVT_CACHE) || defined(__sh__)
-
- ui32MappingFlags &= ~(PVRSRV_HAP_CACHED|PVRSRV_HAP_SMART);
+ /*
+ * ARM9 caches are tagged with virtual pages, not physical. As we are going to
+ * share this memory in different address spaces, we don't want it to be cached.
+ * ARM11 has physical tagging, so we can cache this memory without fear of virtual
+ * address aliasing in the TLB, as long as the kernel supports cache colouring for
+ * VIPT architectures.
+ */
+ ui32MappingFlags &= ~PVRSRV_HAP_CACHED;
#endif
psLinuxMemArea = NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr, ui32Bytes, bPhysContig, ui32MappingFlags);
@@ -1261,6 +1803,13 @@ RegisterExternalMem(IMG_SYS_PHYADDR *pBasePAddr,
}
+/*!
+******************************************************************************
+ @Function OSRegisterMem
+ @Description Registers external memory for user mode mapping
+ @Output phOSMemHandle - handle to registered memory
+ @Return TRUE on success, else FALSE
+******************************************************************************/
PVRSRV_ERROR
OSRegisterMem(IMG_CPU_PHYADDR BasePAddr,
IMG_VOID *pvCPUVAddr,
@@ -1280,6 +1829,12 @@ PVRSRV_ERROR OSRegisterDiscontigMem(IMG_SYS_PHYADDR *pBasePAddr, IMG_VOID *pvCPU
}
+/*!
+******************************************************************************
+ @Function OSUnRegisterMem
+ @Description UnRegisters external memory for user mode mapping
+ @Return TRUE on success, else FALSE
+******************************************************************************/
PVRSRV_ERROR
OSUnRegisterMem (IMG_VOID *pvCpuVAddr,
IMG_UINT32 ui32Bytes,
@@ -1326,17 +1881,27 @@ PVRSRV_ERROR OSUnRegisterDiscontigMem(IMG_VOID *pvCpuVAddr, IMG_UINT32 ui32Bytes
return OSUnRegisterMem(pvCpuVAddr, ui32Bytes, ui32Flags, hOSMemHandle);
}
+/*!
+******************************************************************************
+ @Function OSReservePhys
+ @Description Registers physical memory for user mode mapping
+ @Output ppvCpuVAddr
+ @Output phOsMemHandle handle to registered memory
+ @Return TRUE on success, else FALSE
+******************************************************************************/
PVRSRV_ERROR
OSReservePhys(IMG_CPU_PHYADDR BasePAddr,
IMG_UINT32 ui32Bytes,
IMG_UINT32 ui32MappingFlags,
+ IMG_HANDLE hBMHandle,
IMG_VOID **ppvCpuVAddr,
IMG_HANDLE *phOSMemHandle)
{
LinuxMemArea *psLinuxMemArea;
#if 0
-
+ /* For debug: force all OSReservePhys reservations to have a kernel
+ * virtual address */
if(ui32MappingFlags & PVRSRV_HAP_SINGLE_PROCESS)
{
ui32MappingFlags &= ~PVRSRV_HAP_SINGLE_PROCESS;
@@ -1348,7 +1913,10 @@ OSReservePhys(IMG_CPU_PHYADDR BasePAddr,
{
case PVRSRV_HAP_KERNEL_ONLY:
{
-
+ /* Currently PVRSRV_HAP_KERNEL_ONLY implies that a kernel virtual
+ * mapping is required for the allocation and no user virtual
+ * mappings are allowed: Note these eat into our limited kernel
+ * virtual address space */
psLinuxMemArea = NewIORemapLinuxMemArea(BasePAddr, ui32Bytes, ui32MappingFlags);
if(!psLinuxMemArea)
{
@@ -1358,7 +1926,8 @@ OSReservePhys(IMG_CPU_PHYADDR BasePAddr,
}
case PVRSRV_HAP_SINGLE_PROCESS:
{
-
+ /* Currently this implies that we dont need a kernel virtual
+ * mapping, but will need a user space virtual mapping */
psLinuxMemArea = NewIOLinuxMemArea(BasePAddr, ui32Bytes, ui32MappingFlags);
if(!psLinuxMemArea)
{
@@ -1369,10 +1938,19 @@ OSReservePhys(IMG_CPU_PHYADDR BasePAddr,
}
case PVRSRV_HAP_MULTI_PROCESS:
{
-
+ /* Currently PVRSRV_HAP_MULTI_PROCESS implies that we need a kernel
+ * virtual mapping and potentially multiple user space virtual mappings.
+ * Beware that the kernel virtual address space is a limited resource.
+ */
#if defined(VIVT_CACHE) || defined(__sh__)
-
- ui32MappingFlags &= ~(PVRSRV_HAP_CACHED|PVRSRV_HAP_SMART);
+ /*
+ * ARM9 caches are tagged with virtual pages, not physical. As we are going to
+ * share this memory in different address spaces, we don't want it to be cached.
+ * ARM11 has physical tagging, so we can cache this memory without fear of virtual
+ * address aliasing in the TLB, as long as the kernel supports cache colouring for
+ * VIPT architectures.
+ */
+ ui32MappingFlags &= ~PVRSRV_HAP_CACHED;
#endif
psLinuxMemArea = NewIORemapLinuxMemArea(BasePAddr, ui32Bytes, ui32MappingFlags);
if(!psLinuxMemArea)
@@ -1389,6 +1967,16 @@ OSReservePhys(IMG_CPU_PHYADDR BasePAddr,
return PVRSRV_ERROR_INVALID_FLAGS;
}
+ /*
+ In case of sparse mapping we need to handle back to the BM as it
+ knows the mapping info
+ */
+ if (ui32MappingFlags & PVRSRV_MEM_SPARSE)
+ {
+ PVR_ASSERT(hBMHandle != IMG_NULL);
+ psLinuxMemArea->hBMHandle = hBMHandle;
+ }
+
*phOSMemHandle = (IMG_HANDLE)psLinuxMemArea;
*ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea);
@@ -1397,6 +1985,12 @@ OSReservePhys(IMG_CPU_PHYADDR BasePAddr,
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+ @Function OSUnReservePhys
+ @Description UnRegisters physical memory for user mode mapping
+ @Return TRUE on success, else FALSE
+******************************************************************************/
PVRSRV_ERROR
OSUnReservePhys(IMG_VOID *pvCpuVAddr,
IMG_UINT32 ui32Bytes,
@@ -1441,6 +2035,14 @@ OSUnReservePhys(IMG_VOID *pvCpuVAddr,
}
+/*!
+******************************************************************************
+ @Function OSBaseAllocContigMemory
+ @Description Allocate a block of contiguous virtual non-paged memory.
+ @Input ui32Size - number of bytes to allocate
+ @Output ppvLinAddr - pointer to variable that will receive the linear address of buffer
+ @Return PVRSRV_OK if allocation successed else returns PVRSRV_ERROR_OUT_OF_MEMORY
+ **************************************************************************/
PVRSRV_ERROR OSBaseAllocContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR *pvLinAddr, IMG_CPU_PHYADDR *psPhysAddr)
{
#if !defined(NO_HARDWARE)
@@ -1451,6 +2053,13 @@ PVRSRV_ERROR OSBaseAllocContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR *pvLi
return PVRSRV_ERROR_OUT_OF_MEMORY;
#else
+/*
+ * On Linux, the returned virtual address should be used for CPU access,
+ * and not be remapped into the CPU virtual address using ioremap. The fact
+ * that the RAM is being managed by the kernel, and already has a virtual
+ * address, seems to lead to problems when the attributes of the memory are
+ * changed in the ioremap call (such as from cached to non-cached).
+ */
IMG_VOID *pvKernLinAddr;
#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
@@ -1468,10 +2077,16 @@ PVRSRV_ERROR OSBaseAllocContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR *pvLi
psPhysAddr->uiAddr = virt_to_phys(pvKernLinAddr);
return PVRSRV_OK;
-#endif
+#endif /* !defined(NO_HARDWARE) */
}
+/*!
+******************************************************************************
+ @Function OSBaseFreeContigMemory
+ @Description Frees memory allocated with OSBaseAllocContigMemory
+ @Input LinAddr - pointer to buffer allocated with OSBaseAllocContigMemory
+ **************************************************************************/
PVRSRV_ERROR OSBaseFreeContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR pvLinAddr, IMG_CPU_PHYADDR psPhysAddr)
{
#if !defined(NO_HARDWARE)
@@ -1489,6 +2104,25 @@ PVRSRV_ERROR OSBaseFreeContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR pvLinA
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSWriteHWReg
+
+ @Description
+
+ register access function
+
+ @input pvLinRegBaseAddr : lin addr of register block base
+
+ @input ui32Offset :
+
+ @input ui32Value :
+
+ @Return none
+
+******************************************************************************/
+
IMG_UINT32 OSReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset)
{
#if !defined(NO_HARDWARE)
@@ -1509,6 +2143,22 @@ IMG_VOID OSWriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UIN
#if defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14))
+/*!
+******************************************************************************
+
+ @Function OSPCISetDev
+
+ @Description
+
+ Set a PCI device for subsequent use.
+
+ @input pvPCICookie : Pointer to OS specific PCI structure/cookie
+
+ @input eFlags : Flags
+
+ @Return Pointer to PCI device handle
+
+******************************************************************************/
PVRSRV_PCI_DEV_HANDLE OSPCISetDev(IMG_VOID *pvPCICookie, HOST_PCI_INIT_FLAGS eFlags)
{
int err;
@@ -1534,26 +2184,26 @@ PVRSRV_PCI_DEV_HANDLE OSPCISetDev(IMG_VOID *pvPCICookie, HOST_PCI_INIT_FLAGS eFl
return IMG_NULL;
}
- if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER)
+ if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER) /* PRQA S 3358 */ /* misuse of enums */
{
pci_set_master(psPVRPCI->psPCIDev);
}
- if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_MSI)
+ if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_MSI) /* PRQA S 3358 */ /* misuse of enums */
{
#if defined(CONFIG_PCI_MSI)
err = pci_enable_msi(psPVRPCI->psPCIDev);
if (err != 0)
{
PVR_DPF((PVR_DBG_WARNING, "OSPCISetDev: Couldn't enable MSI (%d)", err));
- psPVRPCI->ePCIFlags &= ~HOST_PCI_INIT_FLAG_MSI;
+ psPVRPCI->ePCIFlags &= ~HOST_PCI_INIT_FLAG_MSI; /* PRQA S 1474,3358,4130 */ /* misuse of enums */
}
#else
PVR_DPF((PVR_DBG_WARNING, "OSPCISetDev: MSI support not enabled in the kernel"));
#endif
}
-
+ /* Initialise the PCI resource tracking array */
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
{
psPVRPCI->abPCIResourceInUse[i] = IMG_FALSE;
@@ -1562,6 +2212,24 @@ PVRSRV_PCI_DEV_HANDLE OSPCISetDev(IMG_VOID *pvPCICookie, HOST_PCI_INIT_FLAGS eFl
return (PVRSRV_PCI_DEV_HANDLE)psPVRPCI;
}
+/*!
+******************************************************************************
+
+ @Function OSPCIAcquireDev
+
+ @Description
+
+ Acquire a PCI device for subsequent use.
+
+ @input ui16VendorID : Vendor PCI ID
+
+ @input ui16VendorID : Device PCI ID
+
+ @input eFlags : Flags
+
+ @Return PVESRV_ERROR
+
+******************************************************************************/
PVRSRV_PCI_DEV_HANDLE OSPCIAcquireDev(IMG_UINT16 ui16VendorID, IMG_UINT16 ui16DeviceID, HOST_PCI_INIT_FLAGS eFlags)
{
struct pci_dev *psPCIDev;
@@ -1576,6 +2244,22 @@ PVRSRV_PCI_DEV_HANDLE OSPCIAcquireDev(IMG_UINT16 ui16VendorID, IMG_UINT16 ui16De
return OSPCISetDev((IMG_VOID *)psPCIDev, eFlags);
}
+/*!
+******************************************************************************
+
+ @Function OSPCIIRQ
+
+ @Description
+
+ Get the interrupt number for the device.
+
+ @input hPVRPCI : PCI device handle
+
+ @input pui32IRQ : Pointer to where the interrupt number should be returned
+
+ @Return PVESRV_ERROR
+
+******************************************************************************/
PVRSRV_ERROR OSPCIIRQ(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 *pui32IRQ)
{
PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI;
@@ -1585,6 +2269,7 @@ PVRSRV_ERROR OSPCIIRQ(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 *pui32IRQ)
return PVRSRV_OK;
}
+/* Functions supported by OSPCIAddrRangeFunc */
enum HOST_PCI_ADDR_RANGE_FUNC
{
HOST_PCI_ADDR_RANGE_FUNC_LEN,
@@ -1594,6 +2279,24 @@ enum HOST_PCI_ADDR_RANGE_FUNC
HOST_PCI_ADDR_RANGE_FUNC_RELEASE
};
+/*!
+******************************************************************************
+
+ @Function OSPCIAddrRangeFunc
+
+ @Description
+
+ Internal support function for various address range related functions
+
+ @input eFunc : Function to perform
+
+ @input hPVRPCI : PCI device handle
+
+ @input ui32Index : Address range index
+
+ @Return function dependent
+
+******************************************************************************/
static IMG_UINT32 OSPCIAddrRangeFunc(enum HOST_PCI_ADDR_RANGE_FUNC eFunc,
PVRSRV_PCI_DEV_HANDLE hPVRPCI,
IMG_UINT32 ui32Index)
@@ -1643,32 +2346,126 @@ static IMG_UINT32 OSPCIAddrRangeFunc(enum HOST_PCI_ADDR_RANGE_FUNC eFunc,
return 0;
}
+/*!
+******************************************************************************
+
+ @Function OSPCIAddrRangeLen
+
+ @Description
+
+ Returns length of a given address range length
+
+ @input hPVRPCI : PCI device handle
+
+ @input ui32Index : Address range index
+
+ @Return Length of address range, or 0 if no such range
+
+******************************************************************************/
IMG_UINT32 OSPCIAddrRangeLen(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index)
{
return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_LEN, hPVRPCI, ui32Index);
}
+/*!
+******************************************************************************
+
+ @Function OSPCIAddrRangeStart
+
+ @Description
+
+ Returns the start of a given address range
+
+ @input hPVRPCI : PCI device handle
+
+ @input ui32Index : Address range index
+
+ @Return Start of address range, or 0 if no such range
+
+******************************************************************************/
IMG_UINT32 OSPCIAddrRangeStart(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index)
{
return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_START, hPVRPCI, ui32Index);
}
+/*!
+******************************************************************************
+
+ @Function OSPCIAddrRangeEnd
+
+ @Description
+
+ Returns the end of a given address range
+
+ @input hPVRPCI : PCI device handle"ayy
+
+ @input ui32Index : Address range index
+
+ @Return End of address range, or 0 if no such range
+
+******************************************************************************/
IMG_UINT32 OSPCIAddrRangeEnd(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index)
{
return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_END, hPVRPCI, ui32Index);
}
+/*!
+******************************************************************************
+
+ @Function OSPCIRequestAddrRange
+
+ @Description
+
+ Request a given address range index for subsequent use
+
+ @input hPVRPCI : PCI device handle
+
+ @input ui32Index : Address range index
+
+ @Return PVESRV_ERROR
+
+******************************************************************************/
PVRSRV_ERROR OSPCIRequestAddrRange(PVRSRV_PCI_DEV_HANDLE hPVRPCI,
IMG_UINT32 ui32Index)
{
return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_REQUEST, hPVRPCI, ui32Index) == 0 ? PVRSRV_ERROR_PCI_CALL_FAILED : PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSPCIReleaseAddrRange
+
+ @Description
+
+ Release a given address range that is no longer being used
+
+ @input hPVRPCI : PCI device handle
+
+ @input ui32Index : Address range index
+
+ @Return PVESRV_ERROR
+
+******************************************************************************/
PVRSRV_ERROR OSPCIReleaseAddrRange(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index)
{
return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_RELEASE, hPVRPCI, ui32Index) == 0 ? PVRSRV_ERROR_PCI_CALL_FAILED : PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSPCIReleaseDev
+
+ @Description
+
+ Release a PCI device that is no longer being used
+
+ @input hPVRPCI : PCI device handle
+
+ @Return PVESRV_ERROR
+
+******************************************************************************/
PVRSRV_ERROR OSPCIReleaseDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
{
PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI;
@@ -1676,7 +2473,7 @@ PVRSRV_ERROR OSPCIReleaseDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
PVR_TRACE(("OSPCIReleaseDev"));
-
+ /* Release all PCI regions that are currently in use */
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
{
if (psPVRPCI->abPCIResourceInUse[i])
@@ -1688,14 +2485,14 @@ PVRSRV_ERROR OSPCIReleaseDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
}
#if defined(CONFIG_PCI_MSI)
- if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_MSI)
+ if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_MSI) /* PRQA S 3358 */ /* misuse of enums */
{
pci_disable_msi(psPVRPCI->psPCIDev);
}
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
- if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER)
+ if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER) /* PRQA S 3358 */ /* misuse of enums */
{
pci_clear_master(psPVRPCI->psPCIDev);
}
@@ -1703,11 +2500,25 @@ PVRSRV_ERROR OSPCIReleaseDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
pci_disable_device(psPVRPCI->psPCIDev);
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psPVRPCI), (IMG_VOID *)psPVRPCI, IMG_NULL);
-
+ /*not nulling pointer, copy on stack*/
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSPCISuspendDev
+
+ @Description
+
+ Prepare PCI device to be turned off by power management
+
+ @input hPVRPCI : PCI device handle
+
+ @Return PVESRV_ERROR
+
+******************************************************************************/
PVRSRV_ERROR OSPCISuspendDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
{
PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI;
@@ -1716,7 +2527,7 @@ PVRSRV_ERROR OSPCISuspendDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
PVR_TRACE(("OSPCISuspendDev"));
-
+ /* Release all PCI regions that are currently in use */
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
{
if (psPVRPCI->abPCIResourceInUse[i])
@@ -1753,6 +2564,24 @@ PVRSRV_ERROR OSPCISuspendDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSPCIResumeDev
+
+ @Description
+
+ Prepare a PCI device to be resumed by power management
+
+ @input hPVRPCI : PCI device handle
+
+ @input pvPCICookie : Pointer to OS specific PCI structure/cookie
+
+ @input eFlags : Flags
+
+ @Return PVESRV_ERROR
+
+******************************************************************************/
PVRSRV_ERROR OSPCIResumeDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
{
PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI;
@@ -1795,10 +2624,10 @@ PVRSRV_ERROR OSPCIResumeDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
return PVRSRV_ERROR_PCI_CALL_FAILED;
}
- if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER)
+ if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER) /* PRQA S 3358 */ /* misuse of enums */
pci_set_master(psPVRPCI->psPCIDev);
-
+ /* Restore the PCI resource tracking array */
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
{
if (psPVRPCI->abPCIResourceInUse[i])
@@ -1815,10 +2644,11 @@ PVRSRV_ERROR OSPCIResumeDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI)
return PVRSRV_OK;
}
-#endif
+#endif /* #if defined(CONFIG_PCI) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) */
#define OS_MAX_TIMERS 8
+/* Timer callback strucure used by OSAddTimer */
typedef struct TIMER_CALLBACK_DATA_TAG
{
IMG_BOOL bInUse;
@@ -1842,9 +2672,11 @@ static TIMER_CALLBACK_DATA sTimers[OS_MAX_TIMERS];
DEFINE_MUTEX(sTimerStructLock);
#else
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
+/* The lock is used to control access to sTimers */
+/* PRQA S 0671,0685 1 */ /* C99 macro not understood by QAC */
static spinlock_t sTimerStructLock = SPIN_LOCK_UNLOCKED;
#else
-static spinlock_t sTimerStructLock = __SPIN_LOCK_UNLOCKED(sTimerStructLock);
+static DEFINE_SPINLOCK(sTimerStructLock);
#endif
#endif
@@ -1853,14 +2685,28 @@ static void OSTimerCallbackBody(TIMER_CALLBACK_DATA *psTimerCBData)
if (!psTimerCBData->bActive)
return;
-
+ /* call timer callback */
psTimerCBData->pfnTimerFunc(psTimerCBData->pvData);
-
+ /* reset timer */
mod_timer(&psTimerCBData->sTimer, psTimerCBData->ui32Delay + jiffies);
}
+/*!
+******************************************************************************
+
+ @Function OSTimerCallbackWrapper
+
+ @Description
+
+ OS specific timer callback wrapper function
+
+ @Input ui32Data : timer callback data
+
+ @Return NONE
+
+******************************************************************************/
static IMG_VOID OSTimerCallbackWrapper(IMG_UINT32 ui32Data)
{
TIMER_CALLBACK_DATA *psTimerCBData = (TIMER_CALLBACK_DATA*)ui32Data;
@@ -1892,6 +2738,24 @@ static void OSTimerWorkQueueCallBack(struct work_struct *psWork)
}
#endif
+/*!
+******************************************************************************
+
+ @Function OSAddTimer
+
+ @Description
+
+ OS specific function to install a timer callback
+
+ @Input pfnTimerFunc : timer callback
+
+ @Input *pvData :callback data
+
+ @Input ui32MsTimeout: callback period
+
+ @Return IMG_HANDLE : valid handle success, NULL failure
+
+******************************************************************************/
IMG_HANDLE OSAddTimer(PFN_TIMER_FUNC pfnTimerFunc, IMG_VOID *pvData, IMG_UINT32 ui32MsTimeout)
{
TIMER_CALLBACK_DATA *psTimerCBData;
@@ -1900,14 +2764,14 @@ IMG_HANDLE OSAddTimer(PFN_TIMER_FUNC pfnTimerFunc, IMG_VOID *pvData, IMG_UINT32
unsigned long ulLockFlags;
#endif
-
+ /* check callback */
if(!pfnTimerFunc)
{
PVR_DPF((PVR_DBG_ERROR, "OSAddTimer: passed invalid callback"));
return IMG_NULL;
}
-
+ /* Allocate timer callback data structure */
#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
mutex_lock(&sTimerStructLock);
#else
@@ -1937,17 +2801,19 @@ IMG_HANDLE OSAddTimer(PFN_TIMER_FUNC pfnTimerFunc, IMG_VOID *pvData, IMG_UINT32
psTimerCBData->pvData = pvData;
psTimerCBData->bActive = IMG_FALSE;
-
-
-
+ /*
+ HZ = ticks per second
+ ui32MsTimeout = required ms delay
+ ticks = (Hz * ui32MsTimeout) / 1000
+ */
psTimerCBData->ui32Delay = ((HZ * ui32MsTimeout) < 1000)
? 1
: ((HZ * ui32MsTimeout) / 1000);
-
+ /* initialise object */
init_timer(&psTimerCBData->sTimer);
-
-
+ /* setup timer object */
+ /* PRQA S 0307,0563 1 */ /* ignore warning about inconpartible ptr casting */
psTimerCBData->sTimer.function = (IMG_VOID *)OSTimerCallbackWrapper;
psTimerCBData->sTimer.data = (IMG_UINT32)psTimerCBData;
@@ -1964,6 +2830,20 @@ static inline TIMER_CALLBACK_DATA *GetTimerStructure(IMG_HANDLE hTimer)
return &sTimers[ui32i];
}
+/*!
+******************************************************************************
+
+ @Function OSRemoveTimer
+
+ @Description
+
+ OS specific function to remove a timer callback
+
+ @Input hTimer : timer handle
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
PVRSRV_ERROR OSRemoveTimer (IMG_HANDLE hTimer)
{
TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
@@ -1971,13 +2851,27 @@ PVRSRV_ERROR OSRemoveTimer (IMG_HANDLE hTimer)
PVR_ASSERT(psTimerCBData->bInUse);
PVR_ASSERT(!psTimerCBData->bActive);
-
+ /* free timer callback data struct */
psTimerCBData->bInUse = IMG_FALSE;
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSEnableTimer
+
+ @Description
+
+ OS specific function to enable a timer callback
+
+ @Input hTimer : timer handle
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
PVRSRV_ERROR OSEnableTimer (IMG_HANDLE hTimer)
{
TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
@@ -1985,19 +2879,33 @@ PVRSRV_ERROR OSEnableTimer (IMG_HANDLE hTimer)
PVR_ASSERT(psTimerCBData->bInUse);
PVR_ASSERT(!psTimerCBData->bActive);
-
+ /* Start timer arming */
psTimerCBData->bActive = IMG_TRUE;
-
+ /* set the expire time */
psTimerCBData->sTimer.expires = psTimerCBData->ui32Delay + jiffies;
-
+ /* Add the timer to the list */
add_timer(&psTimerCBData->sTimer);
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+
+ @Function OSDisableTimer
+
+ @Description
+
+ OS specific function to disable a timer callback
+
+ @Input hTimer : timer handle
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
PVRSRV_ERROR OSDisableTimer (IMG_HANDLE hTimer)
{
TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer);
@@ -2005,7 +2913,7 @@ PVRSRV_ERROR OSDisableTimer (IMG_HANDLE hTimer)
PVR_ASSERT(psTimerCBData->bInUse);
PVR_ASSERT(psTimerCBData->bActive);
-
+ /* Stop timer from arming */
psTimerCBData->bActive = IMG_FALSE;
smp_mb();
@@ -2016,11 +2924,17 @@ PVRSRV_ERROR OSDisableTimer (IMG_HANDLE hTimer)
flush_scheduled_work();
#endif
-
+ /* remove timer */
del_timer_sync(&psTimerCBData->sTimer);
#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
-
+ /*
+ * This second flush is to catch the case where the timer ran
+ * before we managed to delete it, in which case, it will have
+ * queued more work for the workqueue. Since the bActive flag
+ * has been cleared, this second flush won't result in the
+ * timer being rearmed.
+ */
flush_workqueue(psTimerWorkQueue);
#endif
#if defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE)
@@ -2031,6 +2945,22 @@ PVRSRV_ERROR OSDisableTimer (IMG_HANDLE hTimer)
}
+/*!
+******************************************************************************
+
+ @Function OSEventObjectCreateKM
+
+ @Description
+
+ OS specific function to create an event object
+
+ @Input pszName : Globally unique event object name (if null name must be autogenerated)
+
+ @Output psEventObject : OS event object info structure
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
#if defined (SUPPORT_SID_INTERFACE)
PVRSRV_ERROR OSEventObjectCreateKM(const IMG_CHAR *pszName, PVRSRV_EVENTOBJECT_KM *psEventObject)
#else
@@ -2044,12 +2974,12 @@ PVRSRV_ERROR OSEventObjectCreateKM(const IMG_CHAR *pszName, PVRSRV_EVENTOBJECT *
{
if(pszName)
{
-
+ /* copy over the event object name */
strncpy(psEventObject->szName, pszName, EVENTOBJNAME_MAXLENGTH);
}
else
{
-
+ /* autogenerate a name */
static IMG_UINT16 ui16NameIndex = 0;
#if defined (SUPPORT_SID_INTERFACE)
snprintf(psEventObject->szName, EVENTOBJNAME_MAXLENGTH, "PVRSRV_EVENTOBJECT_KM_%d", ui16NameIndex++);
@@ -2075,6 +3005,20 @@ PVRSRV_ERROR OSEventObjectCreateKM(const IMG_CHAR *pszName, PVRSRV_EVENTOBJECT *
}
+/*!
+******************************************************************************
+
+ @Function OSEventObjectDestroyKM
+
+ @Description
+
+ OS specific function to destroy an event object
+
+ @Input psEventObject : OS event object info structure
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
#if defined (SUPPORT_SID_INTERFACE)
PVRSRV_ERROR OSEventObjectDestroyKM(PVRSRV_EVENTOBJECT_KM *psEventObject)
#else
@@ -2104,6 +3048,20 @@ PVRSRV_ERROR OSEventObjectDestroyKM(PVRSRV_EVENTOBJECT *psEventObject)
return eError;
}
+/*!
+******************************************************************************
+
+ @Function OSEventObjectWaitKM
+
+ @Description
+
+ OS specific function to wait for an event object. Called from client
+
+ @Input hOSEventKM : OS and kernel specific handle to event object
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
PVRSRV_ERROR OSEventObjectWaitKM(IMG_HANDLE hOSEventKM)
{
PVRSRV_ERROR eError;
@@ -2121,6 +3079,21 @@ PVRSRV_ERROR OSEventObjectWaitKM(IMG_HANDLE hOSEventKM)
return eError;
}
+/*!
+******************************************************************************
+
+ @Function OSEventObjectOpenKM
+
+ @Description
+
+ OS specific function to open an event object. Called from client
+
+ @Input psEventObject : Pointer to an event object
+ @Output phOSEvent : OS and kernel specific handle to event object
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
#if defined (SUPPORT_SID_INTERFACE)
PVRSRV_ERROR OSEventObjectOpenKM(PVRSRV_EVENTOBJECT_KM *psEventObject,
#else
@@ -2148,6 +3121,22 @@ PVRSRV_ERROR OSEventObjectOpenKM(PVRSRV_EVENTOBJECT *psEventObject,
return eError;
}
+/*!
+******************************************************************************
+
+ @Function OSEventObjectCloseKM
+
+ @Description
+
+ OS specific function to close an event object. Called from client
+
+ @Input psEventObject : Pointer to an event object
+ @OInput hOSEventKM : OS and kernel specific handle to event object
+
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
#if defined (SUPPORT_SID_INTERFACE)
PVRSRV_ERROR OSEventObjectCloseKM(PVRSRV_EVENTOBJECT_KM *psEventObject,
#else
@@ -2176,6 +3165,20 @@ PVRSRV_ERROR OSEventObjectCloseKM(PVRSRV_EVENTOBJECT *psEventObject,
}
+/*!
+******************************************************************************
+
+ @Function OSEventObjectSignalKM
+
+ @Description
+
+ OS specific function to 'signal' an event object. Called from L/MISR
+
+ @Input hOSEventKM : OS and kernel specific handle to event object
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
PVRSRV_ERROR OSEventObjectSignalKM(IMG_HANDLE hOSEventKM)
{
PVRSRV_ERROR eError;
@@ -2193,11 +3196,43 @@ PVRSRV_ERROR OSEventObjectSignalKM(IMG_HANDLE hOSEventKM)
return eError;
}
+/*!
+******************************************************************************
+
+ @Function OSProcHasPrivSrvInit
+
+ @Description
+
+ Does the process have sufficient privileges to initialise services?
+
+ @Input none
+
+ @Return IMG_BOOL :
+
+******************************************************************************/
IMG_BOOL OSProcHasPrivSrvInit(IMG_VOID)
{
return (capable(CAP_SYS_MODULE) != 0) ? IMG_TRUE : IMG_FALSE;
}
+/*!
+******************************************************************************
+
+ @Function OSCopyToUser
+
+ @Description
+
+ Copy a block of data into user space
+
+ @Input pvSrc
+
+ @Output pvDest
+
+ @Input ui32Bytes
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
PVRSRV_ERROR OSCopyToUser(IMG_PVOID pvProcess,
IMG_VOID *pvDest,
IMG_VOID *pvSrc,
@@ -2211,6 +3246,24 @@ PVRSRV_ERROR OSCopyToUser(IMG_PVOID pvProcess,
return PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY;
}
+/*!
+******************************************************************************
+
+ @Function OSCopyFromUser
+
+ @Description
+
+ Copy a block of data from the user space
+
+ @Output pvDest
+
+ @Input pvSrc
+
+ @Input ui32Bytes
+
+ @Return PVRSRV_ERROR :
+
+******************************************************************************/
PVRSRV_ERROR OSCopyFromUser( IMG_PVOID pvProcess,
IMG_VOID *pvDest,
IMG_VOID *pvSrc,
@@ -2224,6 +3277,24 @@ PVRSRV_ERROR OSCopyFromUser( IMG_PVOID pvProcess,
return PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY;
}
+/*!
+******************************************************************************
+
+ @Function OSAccessOK
+
+ @Description
+
+ Checks if a user space pointer is valide
+
+ @Input eVerification
+
+ @Input pvUserPtr
+
+ @Input ui32Bytes
+
+ @Return IMG_BOOL :
+
+******************************************************************************/
IMG_BOOL OSAccessOK(IMG_VERIFY_TEST eVerification, IMG_VOID *pvUserPtr, IMG_UINT32 ui32Bytes)
{
IMG_INT linuxType;
@@ -2264,6 +3335,28 @@ typedef struct _sWrapMemInfo_
} sWrapMemInfo;
+/*!
+******************************************************************************
+
+ @Function *CPUVAddrToPFN
+
+ @Description
+
+ Find the PFN associated with a given CPU virtual address, and return
+ the associated page structure, if it exists.
+ The page in question must be present (i.e. no fault handling required),
+ and must be writable. A get_page is done on the returned page structure.
+
+ @Input psVMArea - pointer to VM area structure
+ ulCPUVAddr - CPU virtual address
+ pulPFN - Pointer to returned PFN.
+ ppsPAge - Pointer to returned page structure pointer.
+
+ @Output *pulPFN - Set to PFN
+ *ppsPage - Pointer to the page structure if present, else NULL.
+ @Return IMG_TRUE if PFN lookup was succesful.
+
+******************************************************************************/
static IMG_BOOL CPUVAddrToPFN(struct vm_area_struct *psVMArea, IMG_UINT32 ulCPUVAddr, IMG_UINT32 *pulPFN, struct page **ppsPage)
{
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10))
@@ -2313,6 +3406,20 @@ static IMG_BOOL CPUVAddrToPFN(struct vm_area_struct *psVMArea, IMG_UINT32 ulCPUV
#endif
}
+/*!
+******************************************************************************
+
+ @Function OSReleasePhysPageAddr
+
+ @Description
+
+ Release wrapped memory.
+
+ @Input hOSWrapMem : Driver cookie
+
+ @Return PVRSRV_ERROR
+
+******************************************************************************/
PVRSRV_ERROR OSReleasePhysPageAddr(IMG_HANDLE hOSWrapMem)
{
sWrapMemInfo *psInfo = (sWrapMemInfo *)hOSWrapMem;
@@ -2341,7 +3448,12 @@ PVRSRV_ERROR OSReleasePhysPageAddr(IMG_HANDLE hOSWrapMem)
PVR_ASSERT(psPage != NULL);
-
+ /*
+ * If the number of pages mapped is not the same as
+ * the number of pages in the address range, then
+ * get_user_pages must have failed, so we are cleaning
+ * up after failure, and the pages can't be dirty.
+ */
if (psInfo->iNumPagesMapped == psInfo->iNumPages)
{
if (!PageReserved(psPage))
@@ -2387,6 +3499,59 @@ PVRSRV_ERROR OSReleasePhysPageAddr(IMG_HANDLE hOSWrapMem)
return PVRSRV_OK;
}
+#if defined(CONFIG_TI_TILER)
+
+static IMG_UINT32 CPUAddrToTilerPhy(IMG_UINT32 uiAddr)
+{
+ IMG_UINT32 ui32PhysAddr = 0;
+ pte_t *ptep, pte;
+ pgd_t *pgd;
+ pmd_t *pmd;
+
+ pgd = pgd_offset(current->mm, uiAddr);
+ if (pgd_none(*pgd) || pgd_bad(*pgd))
+ goto err_out;
+
+ pmd = pmd_offset(pgd, uiAddr);
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
+ goto err_out;
+
+ ptep = pte_offset_map(pmd, uiAddr);
+ if (!ptep)
+ goto err_out;
+
+ pte = *ptep;
+ if (!pte_present(pte))
+ goto err_out;
+
+ ui32PhysAddr = (pte & PAGE_MASK) | (~PAGE_MASK & uiAddr);
+
+ /* If the physAddr is not in the TILER physical range
+ * then we don't proceed.
+ */
+ if (ui32PhysAddr < 0x60000000 && ui32PhysAddr > 0x7fffffff)
+ {
+ PVR_DPF((PVR_DBG_ERROR, "CPUAddrToTilerPhy: Not in tiler range"));
+ ui32PhysAddr = 0;
+ goto err_out;
+ }
+
+err_out:
+ return ui32PhysAddr;
+}
+
+#endif /* defined(CONFIG_TI_TILER) */
+
+/*!
+******************************************************************************
+
+ @Function OSAcquirePhysPageAddr
+
+ @Description
+
+ @Return PVRSRV_ERROR
+
+******************************************************************************/
PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
IMG_UINT32 ui32Bytes,
IMG_SYS_PHYADDR *psSysPAddr,
@@ -2404,16 +3569,18 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
sWrapMemInfo *psInfo = NULL;
IMG_BOOL bHavePageStructs = IMG_FALSE;
IMG_BOOL bHaveNoPageStructs = IMG_FALSE;
- IMG_BOOL bPFNMismatch = IMG_FALSE;
IMG_BOOL bMMapSemHeld = IMG_FALSE;
PVRSRV_ERROR eError = PVRSRV_ERROR_OUT_OF_MEMORY;
-
+ /* Align start and end addresses to page boundaries */
ulStartAddr = ulStartAddrOrig & PAGE_MASK;
ulBeyondEndAddr = PAGE_ALIGN(ulBeyondEndAddrOrig);
ulAddrRange = ulBeyondEndAddr - ulStartAddr;
-
+ /*
+ * Check for address range calculation overflow, and attempts to wrap
+ * zero bytes.
+ */
if (ulBeyondEndAddr <= ulStartAddr)
{
PVR_DPF((PVR_DBG_ERROR,
@@ -2422,7 +3589,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
goto error;
}
-
+ /* Allocate information structure */
psInfo = kmalloc(sizeof(*psInfo), GFP_KERNEL);
if (psInfo == NULL)
{
@@ -2440,7 +3607,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
psInfo->iNumPages = (IMG_INT)(ulAddrRange >> PAGE_SHIFT);
psInfo->iPageOffset = (IMG_INT)(ulStartAddrOrig & ~PAGE_MASK);
-
+ /* Allocate physical address array */
psInfo->psPhysAddr = kmalloc((size_t)psInfo->iNumPages * sizeof(*psInfo->psPhysAddr), GFP_KERNEL);
if (psInfo->psPhysAddr == NULL)
{
@@ -2450,7 +3617,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
}
memset(psInfo->psPhysAddr, 0, (size_t)psInfo->iNumPages * sizeof(*psInfo->psPhysAddr));
-
+ /* Allocate page array */
psInfo->ppsPages = kmalloc((size_t)psInfo->iNumPages * sizeof(*psInfo->ppsPages), GFP_KERNEL);
if (psInfo->ppsPages == NULL)
{
@@ -2460,22 +3627,22 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
}
memset(psInfo->ppsPages, 0, (size_t)psInfo->iNumPages * sizeof(*psInfo->ppsPages));
-
+ /* Default error code from now on */
eError = PVRSRV_ERROR_BAD_MAPPING;
-
+ /* Set the mapping type to aid clean up */
psInfo->eType = WRAP_TYPE_GET_USER_PAGES;
-
+ /* Lock down user memory */
down_read(&current->mm->mmap_sem);
bMMapSemHeld = IMG_TRUE;
-
+ /* Get page list */
psInfo->iNumPagesMapped = get_user_pages(current, current->mm, ulStartAddr, psInfo->iNumPages, 1, 0, psInfo->ppsPages, NULL);
if (psInfo->iNumPagesMapped >= 0)
{
-
+ /* See if we got all the pages we wanted */
if (psInfo->iNumPagesMapped != psInfo->iNumPages)
{
PVR_TRACE(("OSAcquirePhysPageAddr: Couldn't map all the pages needed (wanted: %d, got %d)", psInfo->iNumPages, psInfo->iNumPagesMapped));
@@ -2483,7 +3650,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
goto error;
}
-
+ /* Build list of physical page addresses */
for (i = 0; i < psInfo->iNumPages; i++)
{
IMG_CPU_PHYADDR CPUPhysAddr;
@@ -2508,13 +3675,18 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
PVR_DPF((PVR_DBG_MESSAGE, "OSAcquirePhysPageAddr: get_user_pages failed (%d), using CPU page table", psInfo->iNumPagesMapped));
-
+ /* Reset some fields */
psInfo->eType = WRAP_TYPE_NULL;
psInfo->iNumPagesMapped = 0;
memset(psInfo->ppsPages, 0, (size_t)psInfo->iNumPages * sizeof(*psInfo->ppsPages));
-
-
+ /*
+ * get_user_pages didn't work. If this is due to the address range
+ * representing memory mapped I/O, then we'll look for the pages
+ * in the appropriate memory region of the process.
+ */
+
+ /* Set the mapping type to aid clean up */
psInfo->eType = WRAP_TYPE_FIND_VMA;
psVMArea = find_vma(current->mm, ulStartAddrOrig);
@@ -2529,7 +3701,10 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
psInfo->psVMArea = psVMArea;
#endif
-
+ /*
+ * find_vma locates a region with an end point past a given
+ * virtual address. So check the address is actually in the region.
+ */
if (ulStartAddrOrig < psVMArea->vm_start)
{
PVR_DPF((PVR_DBG_ERROR,
@@ -2537,7 +3712,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
goto error;
}
-
+ /* Now check the end address is in range */
if (ulBeyondEndAddrOrig > psVMArea->vm_end)
{
PVR_DPF((PVR_DBG_ERROR,
@@ -2545,7 +3720,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
goto error;
}
-
+ /* Does the region represent memory mapped I/O? */
if ((psVMArea->vm_flags & (VM_IO | VM_RESERVED)) != (VM_IO | VM_RESERVED))
{
PVR_DPF((PVR_DBG_ERROR,
@@ -2553,7 +3728,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
goto error;
}
-
+ /* We require read and write access */
if ((psVMArea->vm_flags & (VM_READ | VM_WRITE)) != (VM_READ | VM_WRITE))
{
PVR_DPF((PVR_DBG_ERROR,
@@ -2577,20 +3752,20 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
}
if (psInfo->ppsPages[i] == NULL)
{
+#if defined(CONFIG_TI_TILER)
+ /* This could be tiler memory.*/
+ IMG_UINT32 ui32TilerAddr = CPUAddrToTilerPhy(ulAddr);
+ if (ui32TilerAddr)
+ {
+ bHavePageStructs = IMG_TRUE;
+ psInfo->iNumPagesMapped++;
+ psInfo->psPhysAddr[i].uiAddr = ui32TilerAddr;
+ psSysPAddr[i].uiAddr = ui32TilerAddr;
+ continue;
+ }
+#endif /* defined(CONFIG_TI_TILER) */
bHaveNoPageStructs = IMG_TRUE;
-
-#if defined(VM_PFNMAP)
- if ((psVMArea->vm_flags & VM_PFNMAP) != 0)
- {
- IMG_UINT32 ulPFNRaw = ((ulAddr - psVMArea->vm_start) >> PAGE_SHIFT) + psVMArea->vm_pgoff;
-
- if (ulPFNRaw != ulPFN)
- {
- bPFNMismatch = IMG_TRUE;
- }
- }
-#endif
}
else
{
@@ -2631,7 +3806,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
if (!bHaveNoPageStructs)
{
-
+ /* The ideal case; every page has a page structure */
goto exit;
}
@@ -2644,34 +3819,21 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,
goto error;
}
- if (bPFNMismatch)
- {
- PVR_DPF((PVR_DBG_ERROR,
- "OSAcquirePhysPageAddr: PFN calculation mismatch for VM_PFNMAP region"));
- goto error;
- }
-
exit:
PVR_ASSERT(bMMapSemHeld);
up_read(&current->mm->mmap_sem);
-
+ /* Return the cookie */
*phOSWrapMem = (IMG_HANDLE)psInfo;
if (bHaveNoPageStructs)
{
- PVR_DPF((PVR_DBG_WARNING,
+ PVR_DPF((PVR_DBG_MESSAGE,
"OSAcquirePhysPageAddr: Region contains pages which can't be locked down (no page structures)"));
}
PVR_ASSERT(psInfo->eType != 0);
-#if 0
-
-
- OSCleanCPUCacheRangeKM(pvCPUVAddr, (IMG_VOID *)((IMG_CHAR *)pvCPUVAddr + ui32Bytes));
-#endif
-
return PVRSRV_OK;
error:
@@ -2687,52 +3849,96 @@ error:
}
typedef void (*InnerCacheOp_t)(const void *pvStart, const void *pvEnd);
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
-typedef void (*OuterCacheOp_t)(unsigned long ulStart, unsigned long ulEnd);
+
+#if defined(__arm__) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39))
+typedef void (*OuterCacheOp_t)(phys_addr_t uStart, phys_addr_t uEnd);
#else
-typedef void (*OuterCacheOp_t)(phys_addr_t ulStart, phys_addr_t ulEnd);
+typedef void (*OuterCacheOp_t)(unsigned long ulStart, unsigned long ulEnd);
#endif
#if defined(CONFIG_OUTER_CACHE)
-typedef unsigned long (*MemAreaToPhys_t)(LinuxMemArea *psLinuxMemArea,
+typedef IMG_BOOL (*MemAreaToPhys_t)(LinuxMemArea *psLinuxMemArea,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32PageNumOffset,
- IMG_UINT32 ui32PageNum);
+ IMG_UINT32 ui32PageNum,
+ unsigned long *pulStart);
-static unsigned long VMallocAreaToPhys(LinuxMemArea *psLinuxMemArea,
- IMG_VOID *pvRangeAddrStart,
- IMG_UINT32 ui32PageNumOffset,
- IMG_UINT32 ui32PageNum)
+static IMG_BOOL VMallocAreaToPhys(LinuxMemArea *psLinuxMemArea,
+ IMG_VOID *pvRangeAddrStart,
+ IMG_UINT32 ui32PageNumOffset,
+ IMG_UINT32 ui32PageNum,
+ unsigned long *pulStart)
{
- return vmalloc_to_pfn(pvRangeAddrStart + ui32PageNum * PAGE_SIZE) << PAGE_SHIFT;
+ *pulStart = vmalloc_to_pfn(pvRangeAddrStart + ui32PageNum * PAGE_SIZE) << PAGE_SHIFT;
+ return IMG_TRUE;
}
-static unsigned long ExternalKVAreaToPhys(LinuxMemArea *psLinuxMemArea,
- IMG_VOID *pvRangeAddrStart,
- IMG_UINT32 ui32PageNumOffset,
- IMG_UINT32 ui32PageNum)
+static IMG_BOOL ExternalKVAreaToPhys(LinuxMemArea *psLinuxMemArea,
+ IMG_VOID *pvRangeAddrStart,
+ IMG_UINT32 ui32PageNumOffset,
+ IMG_UINT32 ui32PageNum,
+ unsigned long *pulStart)
{
IMG_SYS_PHYADDR SysPAddr;
IMG_CPU_PHYADDR CpuPAddr;
SysPAddr = psLinuxMemArea->uData.sExternalKV.uPhysAddr.pSysPhysAddr[ui32PageNumOffset + ui32PageNum];
CpuPAddr = SysSysPAddrToCpuPAddr(SysPAddr);
- return CpuPAddr.uiAddr;
+ *pulStart = CpuPAddr.uiAddr;
+ return IMG_TRUE;
}
-static unsigned long AllocPagesAreaToPhys(LinuxMemArea *psLinuxMemArea,
- IMG_VOID *pvRangeAddrStart,
- IMG_UINT32 ui32PageNumOffset,
- IMG_UINT32 ui32PageNum)
+static IMG_BOOL AllocPagesAreaToPhys(LinuxMemArea *psLinuxMemArea,
+ IMG_VOID *pvRangeAddrStart,
+ IMG_UINT32 ui32PageNumOffset,
+ IMG_UINT32 ui32PageNum,
+ unsigned long *pulStart)
{
struct page *pPage;
- pPage = psLinuxMemArea->uData.sPageList.pvPageList[ui32PageNumOffset + ui32PageNum];
- return page_to_pfn(pPage) << PAGE_SHIFT;
+
+ pPage = psLinuxMemArea->uData.sPageList.ppsPageList[ui32PageNumOffset + ui32PageNum];
+ *pulStart = page_to_pfn(pPage) << PAGE_SHIFT;
+ return IMG_TRUE;
}
-#endif
+static IMG_BOOL AllocPagesSparseAreaToPhys(LinuxMemArea *psLinuxMemArea,
+ IMG_VOID *pvRangeAddrStart,
+ IMG_UINT32 ui32PageNumOffset,
+ IMG_UINT32 ui32PageNum,
+ unsigned long *pulStart)
+{
+ IMG_UINT32 ui32VirtOffset = (ui32PageNumOffset + ui32PageNum) << PAGE_SHIFT;
+ IMG_UINT32 ui32PhysOffset;
+ struct page *pPage;
+
+ if (BM_VirtOffsetToPhysical(psLinuxMemArea->hBMHandle, ui32VirtOffset, &ui32PhysOffset))
+ {
+ PVR_ASSERT(ui32PhysOffset <= ui32VirtOffset);
+ pPage = psLinuxMemArea->uData.sPageList.ppsPageList[ui32PhysOffset >> PAGE_SHIFT];
+ *pulStart = page_to_pfn(pPage) << PAGE_SHIFT;
+ return IMG_TRUE;
+ }
+
+ return IMG_FALSE;
+}
+
+
+static IMG_BOOL IONAreaToPhys(LinuxMemArea *psLinuxMemArea,
+ IMG_VOID *pvRangeAddrStart,
+ IMG_UINT32 ui32PageNumOffset,
+ IMG_UINT32 ui32PageNum,
+ unsigned long *pulStart)
+{
+ IMG_CPU_PHYADDR CpuPAddr;
+ CpuPAddr = psLinuxMemArea->uData.sIONTilerAlloc.pCPUPhysAddrs[ui32PageNumOffset + ui32PageNum];
+ *pulStart = CpuPAddr.uiAddr;
+ return IMG_TRUE;
+}
+
+#endif /* defined(CONFIG_OUTER_CACHE) */
+
+/* g_sMMapMutex must be held while this function is called */
-#ifndef __mips__
static
IMG_VOID *FindMMapBaseVAddr(struct list_head *psMMapOffsetStructList,
IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length)
@@ -2740,7 +3946,10 @@ IMG_VOID *FindMMapBaseVAddr(struct list_head *psMMapOffsetStructList,
PKV_OFFSET_STRUCT psOffsetStruct;
IMG_VOID *pvMinVAddr;
-
+ /* There's no kernel-virtual for this type of allocation, so if
+ * we're flushing it, it must be user-virtual, and therefore
+ * have a mapping.
+ */
list_for_each_entry(psOffsetStruct, psMMapOffsetStructList, sAreaItem)
{
if(OSGetCurrentProcessIDKM() != psOffsetStruct->ui32PID)
@@ -2748,7 +3957,7 @@ IMG_VOID *FindMMapBaseVAddr(struct list_head *psMMapOffsetStructList,
pvMinVAddr = (IMG_VOID *)psOffsetStruct->ui32UserVAddr;
-
+ /* Within permissible range */
if(pvRangeAddrStart >= pvMinVAddr &&
ui32Length <= psOffsetStruct->ui32RealByteSize)
return pvMinVAddr;
@@ -2757,8 +3966,42 @@ IMG_VOID *FindMMapBaseVAddr(struct list_head *psMMapOffsetStructList,
return IMG_NULL;
}
+extern PVRSRV_LINUX_MUTEX g_sMMapMutex;
+
+static inline void DoInnerCacheOp(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
+ IMG_VOID *pvRangeAddrStart,
+ IMG_UINT32 ui32Length,
+ InnerCacheOp_t pfnInnerCacheOp)
+{
+ LinuxMemArea *psLinuxMemArea = hOSMemHandle;
+
+ if (!psLinuxMemArea->hBMHandle)
+ {
+ pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
+ }
+ else
+ {
+ IMG_UINT32 ui32ByteRemain = ui32Length;
+ IMG_UINT32 ui32BytesToDo = PAGE_SIZE - (((IMG_UINT32) pvRangeAddrStart) & (~PAGE_MASK));
+ IMG_UINT8 *pbDo = (IMG_UINT8 *) pvRangeAddrStart;
+
+ while(ui32ByteRemain)
+ {
+ if (BM_MapPageAtOffset(psLinuxMemArea->hBMHandle, ui32ByteOffset + (ui32Length - ui32ByteRemain)))
+ {
+ pfnInnerCacheOp(pbDo, pbDo + ui32BytesToDo);
+ }
+ pbDo += ui32BytesToDo;
+ ui32ByteRemain -= ui32BytesToDo;
+ ui32BytesToDo = MIN(ui32ByteRemain, PAGE_SIZE);
+ }
+ }
+}
+
static
IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length,
InnerCacheOp_t pfnInnerCacheOp,
@@ -2776,8 +4019,10 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle,
PVR_ASSERT(psLinuxMemArea != IMG_NULL);
- ui32AreaLength = psLinuxMemArea->ui32ByteSize;
+ LinuxLockMutex(&g_sMMapMutex);
+
psMMapOffsetStructList = &psLinuxMemArea->sMMapOffsetStructList;
+ ui32AreaLength = psLinuxMemArea->ui32ByteSize;
PVR_ASSERT(ui32Length <= ui32AreaLength);
@@ -2787,7 +4032,7 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle,
psLinuxMemArea = psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea;
}
-
+ /* Recursion surely isn't possible? */
PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC);
switch(psLinuxMemArea->eAreaType)
@@ -2798,63 +4043,84 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle,
{
pvMinVAddr = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress + ui32AreaOffset;
-
+ /* Outside permissible range */
if(pvRangeAddrStart < pvMinVAddr)
goto err_blocked;
- pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
+ DoInnerCacheOp(hOSMemHandle,
+ ui32ByteOffset,
+ pvRangeAddrStart,
+ ui32Length,
+ pfnInnerCacheOp);
}
else
{
-
-
+ /* If this isn't a vmalloc address, assume we're flushing by
+ * user-virtual. Compute the mmap base vaddr and use this to
+ * compute the offset in vmalloc space.
+ */
pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList,
pvRangeAddrStart, ui32Length);
if(!pvMinVAddr)
goto err_blocked;
- pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
+ DoInnerCacheOp(hOSMemHandle,
+ ui32ByteOffset,
+ pvRangeAddrStart,
+ ui32Length,
+ pfnInnerCacheOp);
#if defined(CONFIG_OUTER_CACHE)
-
+ /*
+ * We don't need to worry about cache aliasing here because
+ * we have already flushed the virtually-indexed caches (L1
+ * etc.) by the supplied user-virtual addresses.
+ *
+ * The vmalloc address will only be used to determine
+ * affected physical pages for outer cache flushing.
+ */
pvRangeAddrStart = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress +
(ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr);
}
pfnMemAreaToPhys = VMallocAreaToPhys;
-#else
+#else /* defined(CONFIG_OUTER_CACHE) */
}
-#endif
+#endif /* defined(CONFIG_OUTER_CACHE) */
break;
}
case LINUX_MEM_AREA_EXTERNAL_KV:
{
-
+ /* We'll only see bPhysContig for frame buffers, and we shouldn't
+ * be flushing those (they're write combined or uncached).
+ */
if (psLinuxMemArea->uData.sExternalKV.bPhysContig == IMG_TRUE)
{
PVR_DPF((PVR_DBG_WARNING, "%s: Attempt to flush contiguous external memory", __func__));
-
goto err_blocked;
}
-
+ /* If it has a kernel virtual address, something odd has happened.
+ * We expect EXTERNAL_KV _only_ from the wrapping of ALLOC_PAGES.
+ */
if (psLinuxMemArea->uData.sExternalKV.pvExternalKV != IMG_NULL)
{
PVR_DPF((PVR_DBG_WARNING, "%s: Attempt to flush external memory with a kernel virtual address", __func__));
-
goto err_blocked;
}
-
-
pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList,
pvRangeAddrStart, ui32Length);
if(!pvMinVAddr)
goto err_blocked;
- pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
+ DoInnerCacheOp(hOSMemHandle,
+ ui32ByteOffset,
+ pvRangeAddrStart,
+ ui32Length,
+ pfnInnerCacheOp);
#if defined(CONFIG_OUTER_CACHE)
ui32PageNumOffset = ((ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr)) >> PAGE_SHIFT;
@@ -2863,6 +4129,26 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle,
break;
}
+ case LINUX_MEM_AREA_ION:
+ {
+ pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList,
+ pvRangeAddrStart, ui32Length);
+ if(!pvMinVAddr)
+ goto err_blocked;
+
+ DoInnerCacheOp(hOSMemHandle,
+ ui32ByteOffset,
+ pvRangeAddrStart,
+ ui32Length,
+ pfnInnerCacheOp);
+
+#if defined(CONFIG_OUTER_CACHE)
+ ui32PageNumOffset = ((ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr)) >> PAGE_SHIFT;
+ pfnMemAreaToPhys = IONAreaToPhys;
+#endif
+ break;
+ }
+
case LINUX_MEM_AREA_ALLOC_PAGES:
{
pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList,
@@ -2870,11 +4156,22 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle,
if(!pvMinVAddr)
goto err_blocked;
- pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
+ DoInnerCacheOp(hOSMemHandle,
+ ui32ByteOffset,
+ pvRangeAddrStart,
+ ui32Length,
+ pfnInnerCacheOp);
#if defined(CONFIG_OUTER_CACHE)
ui32PageNumOffset = ((ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr)) >> PAGE_SHIFT;
- pfnMemAreaToPhys = AllocPagesAreaToPhys;
+ if (psLinuxMemArea->hBMHandle)
+ {
+ pfnMemAreaToPhys = AllocPagesSparseAreaToPhys;
+ }
+ else
+ {
+ pfnMemAreaToPhys = AllocPagesAreaToPhys;
+ }
#endif
break;
}
@@ -2883,35 +4180,41 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle,
PVR_DBG_BREAK;
}
+ LinuxUnLockMutex(&g_sMMapMutex);
+
#if defined(CONFIG_OUTER_CACHE)
PVR_ASSERT(pfnMemAreaToPhys != IMG_NULL);
-
+ /* Outer caches need some more work, to get a list of physical addresses */
{
unsigned long ulStart, ulEnd, ulLength, ulStartOffset, ulEndOffset;
IMG_UINT32 i, ui32NumPages;
+ IMG_BOOL bValidPage;
-
+ /* Length and offsets of flush region WRT page alignment */
ulLength = (unsigned long)ui32Length;
ulStartOffset = ((unsigned long)pvRangeAddrStart) & (PAGE_SIZE - 1);
ulEndOffset = ((unsigned long)pvRangeAddrStart + ulLength) & (PAGE_SIZE - 1);
-
+ /* The affected pages, rounded up */
ui32NumPages = (ulStartOffset + ulLength + PAGE_SIZE - 1) >> PAGE_SHIFT;
for(i = 0; i < ui32NumPages; i++)
{
- ulStart = pfnMemAreaToPhys(psLinuxMemArea, pvRangeAddrStart,
- ui32PageNumOffset, i);
- ulEnd = ulStart + PAGE_SIZE;
-
- if(i == ui32NumPages - 1 && ulEndOffset != 0)
- ulEnd = ulStart + ulEndOffset;
-
- if(i == 0)
- ulStart += ulStartOffset;
-
- pfnOuterCacheOp(ulStart, ulEnd);
+ bValidPage = pfnMemAreaToPhys(psLinuxMemArea, pvRangeAddrStart,
+ ui32PageNumOffset, i, &ulStart);
+ if (bValidPage)
+ {
+ ulEnd = ulStart + PAGE_SIZE;
+
+ if(i == ui32NumPages - 1 && ulEndOffset != 0)
+ ulEnd = ulStart + ulEndOffset;
+
+ if(i == 0)
+ ulStart += ulStartOffset;
+
+ pfnOuterCacheOp(ulStart, ulEnd);
+ }
}
}
#endif
@@ -2923,11 +4226,10 @@ err_blocked:
"%p-%p (type %d)", __func__,
pvRangeAddrStart, pvRangeAddrStart + ui32Length,
psLinuxMemArea->eAreaType));
+ LinuxUnLockMutex(&g_sMMapMutex);
return IMG_FALSE;
}
-#endif
-
#if defined(__i386__)
#define ROUND_UP(x,a) (((x) + (a) - 1) & ~((a) - 1))
@@ -2949,13 +4251,15 @@ static void x86_flush_cache_range(const void *pvStart, const void *pvEnd)
mb();
for(pbBase = pbStart; pbBase < pbEnd; pbBase += boot_cpu_data.x86_clflush_size)
+ {
clflush(pbBase);
+ }
mb();
}
IMG_VOID OSCleanCPUCacheKM(IMG_VOID)
{
-
+ /* No clean feature on x86 */
ON_EACH_CPU(per_cpu_cache_flush, NULL, 1);
}
@@ -2965,33 +4269,36 @@ IMG_VOID OSFlushCPUCacheKM(IMG_VOID)
}
IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
-
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
+ /* Write-back and invalidate */
+ return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, pvRangeAddrStart, ui32Length,
x86_flush_cache_range, IMG_NULL);
}
IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
-
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
+ /* No clean feature on x86 */
+ return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, pvRangeAddrStart, ui32Length,
x86_flush_cache_range, IMG_NULL);
}
IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
-
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
+ /* No invalidate-only support */
+ return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, pvRangeAddrStart, ui32Length,
x86_flush_cache_range, IMG_NULL);
}
-#else
+#else /* defined(__i386__) */
#if defined(__arm__)
@@ -3003,25 +4310,35 @@ static void per_cpu_cache_flush(void *arg)
IMG_VOID OSCleanCPUCacheKM(IMG_VOID)
{
-
+ /* No full (inner) cache clean op */
ON_EACH_CPU(per_cpu_cache_flush, NULL, 1);
-#if defined(CONFIG_OUTER_CACHE) && !defined(PVR_NO_FULL_CACHE_OPS)
- outer_clean_all();
+#if defined(CONFIG_OUTER_CACHE)
+ outer_clean_range(0, ULONG_MAX);
#endif
}
IMG_VOID OSFlushCPUCacheKM(IMG_VOID)
{
ON_EACH_CPU(per_cpu_cache_flush, NULL, 1);
-#if defined(CONFIG_OUTER_CACHE) && !defined(PVR_NO_FULL_CACHE_OPS)
+#if defined(CONFIG_OUTER_CACHE) && \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
+ /* To use the "deferred flush" (not clean) DDK feature you need a kernel
+ * implementation of outer_flush_all() for ARM CPUs with an outer cache
+ * controller (e.g. PL310, common with Cortex A9 and later).
+ *
+ * Reference DDKs don't require this functionality, as they will only
+ * clean the cache, never flush (clean+invalidate) it.
+ */
outer_flush_all();
#endif
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
static inline size_t pvr_dmac_range_len(const void *pvStart, const void *pvEnd)
{
return (size_t)((char *)pvEnd - (char *)pvStart);
}
+#endif
static void pvr_dmac_inv_range(const void *pvStart, const void *pvEnd)
{
@@ -3042,90 +4359,244 @@ static void pvr_dmac_clean_range(const void *pvStart, const void *pvEnd)
}
IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
+ return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset,
+ pvRangeAddrStart, ui32Length,
dmac_flush_range, outer_flush_range);
}
IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
- IMG_BOOL retval = IMG_TRUE;
+ IMG_BOOL retval = IMG_TRUE;
#if defined(CONFIG_OUTER_CACHE) && !defined(PVR_NO_FULL_CACHE_OPS)
if (ui32Length > PVR_FULL_CACHE_OP_THRESHOLD)
OSCleanCPUCacheKM();
else
#endif
{
- retval = CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
+ retval = CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset,
+ pvRangeAddrStart, ui32Length,
pvr_dmac_clean_range, outer_clean_range);
}
return retval;
}
IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
+ return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset,
+ pvRangeAddrStart, ui32Length,
pvr_dmac_inv_range, outer_inv_range);
}
-#else
+#else /* defined(__arm__) */
#if defined(__mips__)
+/*
+ * dmac cache functions are supposed to be used for dma
+ * memory which comes from dma-able memory. However examining
+ * the implementation of dmac cache functions and experimenting,
+ * can assert that dmac functions are safe to use for high-mem
+ * memory as well for our OS{Clean/Flush/Invalidate}Cache functions
+ *
+ */
+
IMG_VOID OSCleanCPUCacheKM(IMG_VOID)
{
-
+ /* dmac functions flush full cache if size is larger than
+ * p-cache size. This is a workaround for the fact that
+ * __flush_cache_all is not an exported symbol. Please
+ * replace with custom function if available in latest
+ * version of linux being used.
+ * Arbitrary large number (1MB) which should be larger than
+ * mips p-cache sizes for some time in future.
+ * */
dma_cache_wback(0, 0x100000);
}
IMG_VOID OSFlushCPUCacheKM(IMG_VOID)
{
-
+ /* dmac functions flush full cache if size is larger than
+ * p-cache size. This is a workaround for the fact that
+ * __flush_cache_all is not an exported symbol. Please
+ * replace with custom function if available in latest
+ * version of linux being used.
+ * Arbitrary large number (1MB) which should be larger than
+ * mips p-cache sizes for some time in future.
+ * */
dma_cache_wback_inv(0, 0x100000);
}
+static inline IMG_UINT32 pvr_dma_range_len(const void *pvStart, const void *pvEnd)
+{
+ return (IMG_UINT32)((char *)pvEnd - (char *)pvStart);
+}
+
+static void pvr_dma_cache_wback_inv(const void *pvStart, const void *pvEnd)
+{
+ dma_cache_wback_inv((IMG_UINTPTR_T)pvStart, pvr_dma_range_len(pvStart, pvEnd));
+}
+
+static void pvr_dma_cache_wback(const void *pvStart, const void *pvEnd)
+{
+ dma_cache_wback((IMG_UINTPTR_T)pvStart, pvr_dma_range_len(pvStart, pvEnd));
+}
+
+static void pvr_dma_cache_inv(const void *pvStart, const void *pvEnd)
+{
+ dma_cache_inv((IMG_UINTPTR_T)pvStart, pvr_dma_range_len(pvStart, pvEnd));
+}
+
IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
- if (ui32Length)
- dma_cache_wback_inv((IMG_UINTPTR_T)pvRangeAddrStart, ui32Length);
- return IMG_TRUE;
+ return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset,
+ pvRangeAddrStart, ui32Length,
+ pvr_dma_cache_wback_inv, IMG_NULL);
}
IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
- if (ui32Length)
- dma_cache_wback((IMG_UINTPTR_T)pvRangeAddrStart, ui32Length);
- return IMG_TRUE;
+ return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset,
+ pvRangeAddrStart, ui32Length,
+ pvr_dma_cache_wback, IMG_NULL);
}
IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+ IMG_UINT32 ui32ByteOffset,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
- if (ui32Length)
- dma_cache_inv((IMG_UINTPTR_T)pvRangeAddrStart, ui32Length);
- return IMG_TRUE;
+ return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset,
+ pvRangeAddrStart, ui32Length,
+ pvr_dma_cache_inv, IMG_NULL);
}
-#else
+#else /* defined(__mips__) */
#error "Implement CPU cache flush/clean/invalidate primitives for this CPU!"
-#endif
+#endif /* defined(__mips__) */
+
+#endif /* defined(__arm__) */
+
+#endif /* defined(__i386__) */
+
+typedef struct _AtomicStruct
+{
+ atomic_t RefCount;
+} AtomicStruct;
+
+PVRSRV_ERROR OSAtomicAlloc(IMG_PVOID *ppvRefCount)
+{
+ AtomicStruct *psRefCount;
+
+ psRefCount = kmalloc(sizeof(AtomicStruct), GFP_KERNEL);
+ if (psRefCount == NULL)
+ {
+ return PVRSRV_ERROR_OUT_OF_MEMORY;
+ }
+ atomic_set(&psRefCount->RefCount, 0);
+
+ *ppvRefCount = psRefCount;
+ return PVRSRV_OK;
+}
+
+IMG_VOID OSAtomicFree(IMG_PVOID pvRefCount)
+{
+ AtomicStruct *psRefCount = pvRefCount;
+
+ PVR_ASSERT(atomic_read(&psRefCount->RefCount) == 0);
+ kfree(psRefCount);
+}
+
+IMG_VOID OSAtomicInc(IMG_PVOID pvRefCount)
+{
+ AtomicStruct *psRefCount = pvRefCount;
+
+ atomic_inc(&psRefCount->RefCount);
+}
+
+IMG_BOOL OSAtomicDecAndTest(IMG_PVOID pvRefCount)
+{
+ AtomicStruct *psRefCount = pvRefCount;
+
+ return atomic_dec_and_test(&psRefCount->RefCount) ? IMG_TRUE:IMG_FALSE;
+}
+
+IMG_UINT32 OSAtomicRead(IMG_PVOID pvRefCount)
+{
+ AtomicStruct *psRefCount = pvRefCount;
+
+ return (IMG_UINT32) atomic_read(&psRefCount->RefCount);
+}
+
+IMG_VOID OSReleaseBridgeLock(IMG_VOID)
+{
+ LinuxUnLockMutex(&gPVRSRVLock);
+}
+
+IMG_VOID OSReacquireBridgeLock(IMG_VOID)
+{
+ LinuxLockMutex(&gPVRSRVLock);
+}
+
+typedef struct _OSTime
+{
+ unsigned long ulTime;
+} OSTime;
+
+PVRSRV_ERROR OSTimeCreateWithUSOffset(IMG_PVOID *pvRet, IMG_UINT32 ui32USOffset)
+{
+ OSTime *psOSTime;
+
+ psOSTime = kmalloc(sizeof(OSTime), GFP_KERNEL);
+ if (psOSTime == IMG_NULL)
+ {
+ return PVRSRV_ERROR_OUT_OF_MEMORY;
+ }
+
+ psOSTime->ulTime = usecs_to_jiffies(jiffies_to_usecs(jiffies) + ui32USOffset);
+ *pvRet = psOSTime;
+ return PVRSRV_OK;
+}
+
-#endif
+IMG_BOOL OSTimeHasTimePassed(IMG_PVOID pvData)
+{
+ OSTime *psOSTime = pvData;
+
+ if (time_is_before_jiffies(psOSTime->ulTime))
+ {
+ return IMG_TRUE;
+ }
+ return IMG_FALSE;
+}
+
+IMG_VOID OSTimeDestroy(IMG_PVOID pvData)
+{
+ kfree(pvData);
+}
-#endif
+IMG_VOID OSGetCurrentProcessNameKM(IMG_CHAR *pszName, IMG_UINT32 ui32Size)
+{
+ strncpy(pszName, current->comm, MIN(ui32Size,TASK_COMM_LEN));
+}
+/* One time osfunc initialisation */
PVRSRV_ERROR PVROSFuncInit(IMG_VOID)
{
#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
@@ -3152,11 +4623,30 @@ PVRSRV_ERROR PVROSFuncInit(IMG_VOID)
}
}
#endif
+
+#if defined (SUPPORT_ION)
+ {
+ PVRSRV_ERROR eError;
+
+ eError = IonInit();
+ if (eError != PVRSRV_OK)
+ {
+ PVR_DPF((PVR_DBG_ERROR, "%s: IonInit failed", __FUNCTION__));
+ }
+ }
+#endif
return PVRSRV_OK;
}
+/*
+ * Osfunc deinitialisation.
+ * Note that PVROSFuncInit may not have been called
+ */
IMG_VOID PVROSFuncDeInit(IMG_VOID)
{
+#if defined (SUPPORT_ION)
+ IonDeinit();
+#endif
#if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES)
if (psTimerWorkQueue != NULL)
{
diff --git a/sgx/services4/srvkm/env/linux/osperproc.c b/sgx/services4/srvkm/env/linux/osperproc.c
index 6b57dfc..5116c36 100644
--- a/sgx/services4/srvkm/env/linux/osperproc.c
+++ b/sgx/services4/srvkm/env/linux/osperproc.c
@@ -1,35 +1,55 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Linux specific per process data functions
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include "services_headers.h"
#include "osperproc.h"
#include "env_perproc.h"
#include "proc.h"
+#if defined (SUPPORT_ION)
+#include "linux/ion.h"
+extern struct ion_device *psIonDev;
+#endif
extern IMG_UINT32 gui32ReleasePID;
PVRSRV_ERROR OSPerProcessPrivateDataInit(IMG_HANDLE *phOsPrivateData)
@@ -57,14 +77,28 @@ PVRSRV_ERROR OSPerProcessPrivateDataInit(IMG_HANDLE *phOsPrivateData)
psEnvPerProc->hBlockAlloc = hBlockAlloc;
-
+ /* Linux specific mmap processing */
LinuxMMapPerProcessConnect(psEnvPerProc);
#if defined(SUPPORT_DRI_DRM) && defined(PVR_SECURE_DRM_AUTH_EXPORT)
-
+ /* Linked list of PVRSRV_FILE_PRIVATE_DATA structures */
INIT_LIST_HEAD(&psEnvPerProc->sDRMAuthListHead);
#endif
-
+#if defined(SUPPORT_ION)
+ OSSNPrintf(psEnvPerProc->azIonClientName, ION_CLIENT_NAME_SIZE, "pvr_ion_client-%d", OSGetCurrentProcessIDKM());
+ psEnvPerProc->psIONClient =
+ ion_client_create(psIonDev,
+ 1 << ION_HEAP_TYPE_SYSTEM_CONTIG |
+ 1 << ION_HEAP_TYPE_SYSTEM,
+ psEnvPerProc->azIonClientName);
+
+ if (IS_ERR_OR_NULL(psEnvPerProc->psIONClient))
+ {
+ PVR_DPF((PVR_DBG_ERROR, "OSPerProcessPrivateDataInit: Couldn't create "
+ "ion client for per process data"));
+ return PVRSRV_ERROR_OUT_OF_MEMORY;
+ }
+#endif /* SUPPORT_ION */
return PVRSRV_OK;
}
@@ -80,17 +114,17 @@ PVRSRV_ERROR OSPerProcessPrivateDataDeInit(IMG_HANDLE hOsPrivateData)
psEnvPerProc = (PVRSRV_ENV_PER_PROCESS_DATA *)hOsPrivateData;
-
+ /* Linux specific mmap processing */
LinuxMMapPerProcessDisconnect(psEnvPerProc);
-
+ /* Remove per process /proc entries */
RemovePerProcessProcDir(psEnvPerProc);
eError = OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
sizeof(PVRSRV_ENV_PER_PROCESS_DATA),
hOsPrivateData,
psEnvPerProc->hBlockAlloc);
-
+ /*not nulling pointer, copy on stack*/
if (eError != PVRSRV_OK)
{
diff --git a/sgx/services4/srvkm/env/linux/pdump.c b/sgx/services4/srvkm/env/linux/pdump.c
index 13d9b0d..192640f 100644
--- a/sgx/services4/srvkm/env/linux/pdump.c
+++ b/sgx/services4/srvkm/env/linux/pdump.c
@@ -1,28 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Parameter dump macro target routines
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#if defined (SUPPORT_SGX) || defined (SUPPORT_VGX)
#if defined (PDUMP)
@@ -30,7 +46,7 @@
#include <asm/atomic.h>
#include <stdarg.h>
#if defined (SUPPORT_SGX)
-#include "sgxdefs.h"
+#include "sgxdefs.h" /* Is this still needed? */
#endif
#include "services_headers.h"
@@ -39,14 +55,14 @@
#include "dbgdrvif.h"
#if defined (SUPPORT_SGX)
-#include "sgxmmu.h"
+#include "sgxmmu.h"/* Is this still needed? */
#endif
#include "mm.h"
#include "pdump_km.h"
#include "pdump_int.h"
-#include <linux/kernel.h>
-#include <linux/string.h>
+#include <linux/kernel.h> // sprintf
+#include <linux/string.h> // strncpy, strlen
static IMG_BOOL PDumpWriteString2 (IMG_CHAR * pszString, IMG_UINT32 ui32Flags);
static IMG_BOOL PDumpWriteILock (PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32Count, IMG_UINT32 ui32Flags);
@@ -56,6 +72,9 @@ static IMG_VOID DbgSetMarker (PDBG_STREAM psStream, IMG_UINT32 ui32Marker);
#define PDUMP_DATAMASTER_PIXEL (1)
#define PDUMP_DATAMASTER_EDM (3)
+/*
+ Maximum file size to split output files
+*/
#define MAX_FILE_SIZE 0x40000000
static atomic_t gsPDumpSuspended = ATOMIC_INIT(0);
@@ -87,13 +106,14 @@ static PDBG_PDUMP_STATE gsDBGPdumpState = {{IMG_NULL}, 0, IMG_NULL, IMG_NULL, IM
-IMG_VOID DBGDrvGetServiceTable(IMG_VOID **fn_table);
-
static inline IMG_BOOL PDumpSuspended(IMG_VOID)
{
return (atomic_read(&gsPDumpSuspended) != 0) ? IMG_TRUE : IMG_FALSE;
}
+/*!
+ * \name PDumpOSGetScriptString
+ */
PVRSRV_ERROR PDumpOSGetScriptString(IMG_HANDLE *phScript,
IMG_UINT32 *pui32MaxLen)
{
@@ -106,6 +126,9 @@ PVRSRV_ERROR PDumpOSGetScriptString(IMG_HANDLE *phScript,
return PVRSRV_OK;
}
+/*!
+ * \name PDumpOSGetMessageString
+ */
PVRSRV_ERROR PDumpOSGetMessageString(IMG_CHAR **ppszMsg,
IMG_UINT32 *pui32MaxLen)
{
@@ -118,6 +141,9 @@ PVRSRV_ERROR PDumpOSGetMessageString(IMG_CHAR **ppszMsg,
return PVRSRV_OK;
}
+/*!
+ * \name PDumpOSGetFilenameString
+ */
PVRSRV_ERROR PDumpOSGetFilenameString(IMG_CHAR **ppszFile,
IMG_UINT32 *pui32MaxLen)
{
@@ -130,11 +156,17 @@ PVRSRV_ERROR PDumpOSGetFilenameString(IMG_CHAR **ppszFile,
return PVRSRV_OK;
}
+/*!
+ * \name PDumpOSWriteString2
+ */
IMG_BOOL PDumpOSWriteString2(IMG_HANDLE hScript, IMG_UINT32 ui32Flags)
{
return PDumpWriteString2(hScript, ui32Flags);
}
+/*!
+ * \name PDumpOSBufprintf
+ */
PVRSRV_ERROR PDumpOSBufprintf(IMG_HANDLE hBuf, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR* pszFormat, ...)
{
IMG_CHAR* pszBuf = hBuf;
@@ -147,7 +179,7 @@ PVRSRV_ERROR PDumpOSBufprintf(IMG_HANDLE hBuf, IMG_UINT32 ui32ScriptSizeMax, IMG
va_end(vaArgs);
- if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1)
+ if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) /* glibc >= 2.1 or glibc 2.0 */
{
PVR_DPF((PVR_DBG_ERROR, "Buffer overflow detected, pdump output may be incomplete."));
@@ -160,13 +192,16 @@ PVRSRV_ERROR PDumpOSBufprintf(IMG_HANDLE hBuf, IMG_UINT32 ui32ScriptSizeMax, IMG
return PVRSRV_OK;
}
+/*!
+ * \name PDumpOSVSprintf
+ */
PVRSRV_ERROR PDumpOSVSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR* pszFormat, PDUMP_va_list vaArgs)
{
IMG_INT32 n;
n = vsnprintf(pszComment, ui32ScriptSizeMax, pszFormat, vaArgs);
- if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1)
+ if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) /* glibc >= 2.1 or glibc 2.0 */
{
PVR_DPF((PVR_DBG_ERROR, "Buffer overflow detected, pdump output may be incomplete."));
@@ -176,13 +211,19 @@ PVRSRV_ERROR PDumpOSVSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax,
return PVRSRV_OK;
}
+/*!
+ * \name PDumpOSDebugPrintf
+ */
IMG_VOID PDumpOSDebugPrintf(IMG_CHAR* pszFormat, ...)
{
PVR_UNREFERENCED_PARAMETER(pszFormat);
-
+ /* FIXME: Implement using services PVR_DBG or otherwise with kprintf */
}
+/*!
+ * \name PDumpOSSprintf
+ */
PVRSRV_ERROR PDumpOSSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR *pszFormat, ...)
{
IMG_INT32 n;
@@ -194,7 +235,7 @@ PVRSRV_ERROR PDumpOSSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax,
va_end(vaArgs);
- if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1)
+ if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) /* glibc >= 2.1 or glibc 2.0 */
{
PVR_DPF((PVR_DBG_ERROR, "Buffer overflow detected, pdump output may be incomplete."));
@@ -204,6 +245,9 @@ PVRSRV_ERROR PDumpOSSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax,
return PVRSRV_OK;
}
+/*!
+ * \name PDumpOSBuflen
+ */
IMG_UINT32 PDumpOSBuflen(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMax)
{
IMG_CHAR* pszBuf = hBuffer;
@@ -216,15 +260,18 @@ IMG_UINT32 PDumpOSBuflen(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMax)
return(ui32Count);
}
+/*!
+ * \name PDumpOSVerifyLineEnding
+ */
IMG_VOID PDumpOSVerifyLineEnding(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMax)
{
IMG_UINT32 ui32Count;
IMG_CHAR* pszBuf = hBuffer;
-
+ /* strlen */
ui32Count = PDumpOSBuflen(hBuffer, ui32BufferSizeMax);
-
+ /* Put \r \n sequence at the end if it isn't already there */
if ((ui32Count >= 1) && (pszBuf[ui32Count-1] != '\n') && (ui32Count<ui32BufferSizeMax))
{
pszBuf[ui32Count] = '\n';
@@ -240,22 +287,34 @@ IMG_VOID PDumpOSVerifyLineEnding(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMa
}
}
+/*!
+ * \name PDumpOSGetStream
+ */
IMG_HANDLE PDumpOSGetStream(IMG_UINT32 ePDumpStream)
{
return (IMG_HANDLE)gsDBGPdumpState.psStream[ePDumpStream];
}
+/*!
+ * \name PDumpOSGetStreamOffset
+ */
IMG_UINT32 PDumpOSGetStreamOffset(IMG_UINT32 ePDumpStream)
{
PDBG_STREAM psStream = gsDBGPdumpState.psStream[ePDumpStream];
return gpfnDbgDrv->pfnGetStreamOffset(psStream);
}
+/*!
+ * \name PDumpOSGetParamFileNum
+ */
IMG_UINT32 PDumpOSGetParamFileNum(IMG_VOID)
{
return gsDBGPdumpState.ui32ParamFileNum;
}
+/*!
+ * \name PDumpOSWriteString
+ */
IMG_BOOL PDumpOSWriteString(IMG_HANDLE hStream,
IMG_UINT8 *psui8Data,
IMG_UINT32 ui32Size,
@@ -268,14 +327,21 @@ IMG_BOOL PDumpOSWriteString(IMG_HANDLE hStream,
ui32Flags);
}
+/*!
+ * \name PDumpOSCheckForSplitting
+ */
IMG_VOID PDumpOSCheckForSplitting(IMG_HANDLE hStream, IMG_UINT32 ui32Size, IMG_UINT32 ui32Flags)
{
-
+ /* File size limit not implemented for this OS.
+ */
PVR_UNREFERENCED_PARAMETER(hStream);
PVR_UNREFERENCED_PARAMETER(ui32Size);
PVR_UNREFERENCED_PARAMETER(ui32Flags);
}
+/*!
+ * \name PDumpOSJTInitialised
+ */
IMG_BOOL PDumpOSJTInitialised(IMG_VOID)
{
if(gpfnDbgDrv)
@@ -285,11 +351,17 @@ IMG_BOOL PDumpOSJTInitialised(IMG_VOID)
return IMG_FALSE;
}
+/*!
+ * \name PDumpOSIsSuspended
+ */
inline IMG_BOOL PDumpOSIsSuspended(IMG_VOID)
{
return (atomic_read(&gsPDumpSuspended) != 0) ? IMG_TRUE : IMG_FALSE;
}
+/*!
+ * \name PDumpOSCPUVAddrToDevPAddr
+ */
IMG_VOID PDumpOSCPUVAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType,
IMG_HANDLE hOSMemHandle,
IMG_UINT32 ui32Offset,
@@ -300,19 +372,23 @@ IMG_VOID PDumpOSCPUVAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType,
IMG_CPU_PHYADDR sCpuPAddr;
PVR_UNREFERENCED_PARAMETER(pui8LinAddr);
- PVR_UNREFERENCED_PARAMETER(ui32PageSize);
+ PVR_UNREFERENCED_PARAMETER(ui32PageSize); /* for when no assert */
-
+ /* Caller must now alway supply hOSMemHandle, even though we only (presently)
+ use it here in the linux implementation */
PVR_ASSERT (hOSMemHandle != IMG_NULL);
sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset);
PVR_ASSERT((sCpuPAddr.uiAddr & (ui32PageSize - 1)) == 0);
-
+ /* convert CPU physical addr to device physical */
*psDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr);
}
+/*!
+ * \name PDumpOSCPUVAddrToPhysPages
+ */
IMG_VOID PDumpOSCPUVAddrToPhysPages(IMG_HANDLE hOSMemHandle,
IMG_UINT32 ui32Offset,
IMG_PUINT8 pui8LinAddr,
@@ -321,7 +397,9 @@ IMG_VOID PDumpOSCPUVAddrToPhysPages(IMG_HANDLE hOSMemHandle,
{
if(hOSMemHandle)
{
-
+ /*
+ * If a Services memory handle is provided then use it.
+ */
IMG_CPU_PHYADDR sCpuPAddr;
PVR_UNREFERENCED_PARAMETER(pui8LinAddr);
@@ -338,6 +416,9 @@ IMG_VOID PDumpOSCPUVAddrToPhysPages(IMG_HANDLE hOSMemHandle,
}
}
+/*!
+ * \name PDumpOSDebugDriverWrite
+ */
IMG_UINT32 PDumpOSDebugDriverWrite( PDBG_STREAM psStream,
PDUMP_DDWMODE eDbgDrvWriteMode,
IMG_UINT8 *pui8Data,
@@ -365,29 +446,43 @@ IMG_UINT32 PDumpOSDebugDriverWrite( PDBG_STREAM psStream,
return 0xFFFFFFFFU;
}
+/*!
+ * \name PDumpOSReleaseExecution
+ */
IMG_VOID PDumpOSReleaseExecution(IMG_VOID)
{
OSReleaseThreadQuanta();
}
+/**************************************************************************
+ * Function Name : PDumpInit
+ * Outputs : None
+ * Returns :
+ * Description : Reset connection to vldbgdrv
+ * Then try to connect to PDUMP streams
+**************************************************************************/
IMG_VOID PDumpInit(IMG_VOID)
{
IMG_UINT32 i;
DBGKM_CONNECT_NOTIFIER sConnectNotifier;
-
+ /* If we tried this earlier, then we might have connected to the driver
+ * But if pdump.exe was running then the stream connected would fail
+ */
if (!gpfnDbgDrv)
{
- DBGDrvGetServiceTable((IMG_VOID **)&gpfnDbgDrv);
+ DBGDrvGetServiceTable(&gpfnDbgDrv);
-
+ // If something failed then no point in trying to connect streams
if (gpfnDbgDrv == IMG_NULL)
{
return;
}
-
+ /*
+ * Pass the connection notify callback
+ */
sConnectNotifier.pfnConnectNotifier = &PDumpConnectionNotify;
gpfnDbgDrv->pfnSetConnectNotifier(sConnectNotifier);
@@ -457,7 +552,9 @@ init_failed:
gsDBGPdumpState.pszMsg = IMG_NULL;
}
-
+ /*
+ * Remove the connection notify callback
+ */
sConnectNotifier.pfnConnectNotifier = 0;
gpfnDbgDrv->pfnSetConnectNotifier(sConnectNotifier);
@@ -493,13 +590,22 @@ IMG_VOID PDumpDeInit(IMG_VOID)
gsDBGPdumpState.pszMsg = IMG_NULL;
}
-
+ /*
+ * Remove the connection notify callback
+ */
sConnectNotifier.pfnConnectNotifier = 0;
gpfnDbgDrv->pfnSetConnectNotifier(sConnectNotifier);
gpfnDbgDrv = IMG_NULL;
}
+/**************************************************************************
+ * Function Name : PDumpStartInitPhaseKM
+ * Inputs : None
+ * Outputs : None
+ * Returns : None
+ * Description : Resume init phase state
+**************************************************************************/
PVRSRV_ERROR PDumpStartInitPhaseKM(IMG_VOID)
{
IMG_UINT32 i;
@@ -515,6 +621,13 @@ PVRSRV_ERROR PDumpStartInitPhaseKM(IMG_VOID)
return PVRSRV_OK;
}
+/**************************************************************************
+ * Function Name : PDumpStopInitPhaseKM
+ * Inputs : None
+ * Outputs : None
+ * Returns : None
+ * Description : End init phase state
+**************************************************************************/
PVRSRV_ERROR PDumpStopInitPhaseKM(IMG_VOID)
{
IMG_UINT32 i;
@@ -531,12 +644,26 @@ PVRSRV_ERROR PDumpStopInitPhaseKM(IMG_VOID)
return PVRSRV_OK;
}
+/**************************************************************************
+ * Function Name : PDumpIsLastCaptureFrameKM
+ * Inputs : None
+ * Outputs : None
+ * Returns : True or false
+ * Description : Tests whether the current frame is being pdumped
+**************************************************************************/
IMG_BOOL PDumpIsLastCaptureFrameKM(IMG_VOID)
{
return gpfnDbgDrv->pfnIsLastCaptureFrame(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2]);
}
+/**************************************************************************
+ * Function Name : PDumpIsCaptureFrameKM
+ * Inputs : None
+ * Outputs : None
+ * Returns : True or false
+ * Description : Tests whether the current frame is being pdumped
+**************************************************************************/
IMG_BOOL PDumpOSIsCaptureFrameKM(IMG_VOID)
{
if (PDumpSuspended())
@@ -546,6 +673,13 @@ IMG_BOOL PDumpOSIsCaptureFrameKM(IMG_VOID)
return gpfnDbgDrv->pfnIsCaptureFrame(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2], IMG_FALSE);
}
+/**************************************************************************
+ * Function Name : PDumpSetFrameKM
+ * Inputs : None
+ * Outputs : None
+ * Returns : None
+ * Description : Sets a frame
+**************************************************************************/
PVRSRV_ERROR PDumpOSSetFrameKM(IMG_UINT32 ui32Frame)
{
IMG_UINT32 ui32Stream;
@@ -562,12 +696,30 @@ PVRSRV_ERROR PDumpOSSetFrameKM(IMG_UINT32 ui32Frame)
}
+/*****************************************************************************
+ FUNCTION : PDumpWriteString2
+
+ PURPOSE :
+
+ PARAMETERS :
+
+ RETURNS :
+*****************************************************************************/
static IMG_BOOL PDumpWriteString2(IMG_CHAR * pszString, IMG_UINT32 ui32Flags)
{
return PDumpWriteILock(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2], (IMG_UINT8 *) pszString, strlen(pszString), ui32Flags);
}
+/*****************************************************************************
+ FUNCTION : PDumpWriteILock
+
+ PURPOSE : Writes, making sure it all goes...
+
+ PARAMETERS :
+
+ RETURNS :
+*****************************************************************************/
static IMG_BOOL PDumpWriteILock(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32Count, IMG_UINT32 ui32Flags)
{
IMG_UINT32 ui32Written = 0;
@@ -578,7 +730,9 @@ static IMG_BOOL PDumpWriteILock(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_U
}
-
+ /*
+ Set the stream marker to split output files
+ */
if (psStream == gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2])
{
@@ -604,11 +758,31 @@ static IMG_BOOL PDumpWriteILock(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_U
return IMG_TRUE;
}
+/*****************************************************************************
+ FUNCTION : DbgSetFrame
+
+ PURPOSE : Sets the frame in the stream
+
+ PARAMETERS : psStream - Stream pointer
+ ui32Frame - Frame number to set
+
+ RETURNS : None
+*****************************************************************************/
static IMG_VOID DbgSetFrame(PDBG_STREAM psStream, IMG_UINT32 ui32Frame)
{
gpfnDbgDrv->pfnSetFrame(psStream, ui32Frame);
}
+/*****************************************************************************
+ FUNCTION : DbgSetMarker
+
+ PURPOSE : Sets the marker of the stream to split output files
+
+ PARAMETERS : psStream - Stream pointer
+ ui32Marker - Marker number to set
+
+ RETURNS : None
+*****************************************************************************/
static IMG_VOID DbgSetMarker(PDBG_STREAM psStream, IMG_UINT32 ui32Marker)
{
gpfnDbgDrv->pfnSetMarker(psStream, ui32Marker);
@@ -624,5 +798,8 @@ IMG_VOID PDumpResumeKM(IMG_VOID)
atomic_dec(&gsPDumpSuspended);
}
-#endif
-#endif
+#endif /* #if defined (PDUMP) */
+#endif /* #if defined (SUPPORT_SGX) */
+/*****************************************************************************
+ End of file (PDUMP.C)
+*****************************************************************************/
diff --git a/sgx/services4/srvkm/env/linux/private_data.h b/sgx/services4/srvkm/env/linux/private_data.h
index a460798..1b0f045 100644
--- a/sgx/services4/srvkm/env/linux/private_data.h
+++ b/sgx/services4/srvkm/env/linux/private_data.h
@@ -1,28 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Linux private data structure
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#ifndef __INCLUDED_PRIVATE_DATA_H_
#define __INCLUDED_PRIVATE_DATA_H_
@@ -32,12 +48,23 @@
#include <drm/drmP.h>
#endif
+/* This structure is required in the rare case that a process creates
+ * a connection to services, but before closing the file descriptor,
+ * does a fork(). This fork() will duplicate the file descriptor in the
+ * child process. If the parent process dies before the child, this can
+ * cause the PVRSRVRelease() method to be called in a different process
+ * context than the original PVRSRVOpen(). This is bad because we need
+ * to update the per-process data reference count and/or free the
+ * per-process data. So we must keep a record of which PID's per-process
+ * data to inspect during ->release().
+ */
+
typedef struct
{
-
+ /* PID that created this services connection */
IMG_UINT32 ui32OpenPID;
-
+ /* Global kernel MemInfo handle */
#if defined (SUPPORT_SID_INTERFACE)
IMG_SID hKernelMemInfo;
#else
@@ -45,22 +72,22 @@ typedef struct
#endif
#if defined(SUPPORT_DRI_DRM) && defined(PVR_SECURE_DRM_AUTH_EXPORT)
-
+ /* The private data is on a list in the per-process data structure */
struct list_head sDRMAuthListItem;
struct drm_file *psDRMFile;
#endif
#if defined(SUPPORT_MEMINFO_IDS)
-
+ /* Globally unique "stamp" for kernel MemInfo */
IMG_UINT64 ui64Stamp;
-#endif
+#endif /* defined(SUPPORT_MEMINFO_IDS) */
-
+ /* Accounting for OSAllocMem */
IMG_HANDLE hBlockAlloc;
#if defined(SUPPORT_DRI_DRM_EXT)
- IMG_PVOID pPriv;
+ IMG_PVOID pPriv; /*private data for extending this struct*/
#endif
}
PVRSRV_FILE_PRIVATE_DATA;
@@ -97,5 +124,5 @@ static inline void set_private(struct file *file, PVRSRV_FILE_PRIVATE_DATA *priv
#endif
-#endif
+#endif /* __INCLUDED_PRIVATE_DATA_H_ */
diff --git a/sgx/services4/srvkm/env/linux/proc.c b/sgx/services4/srvkm/env/linux/proc.c
index 1df8aff..3b48c9e 100644
--- a/sgx/services4/srvkm/env/linux/proc.c
+++ b/sgx/services4/srvkm/env/linux/proc.c
@@ -1,28 +1,47 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Proc files implementation.
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description Functions for creating and reading proc filesystem entries.
+ Proc filesystem support must be built into the kernel for
+ these functions to be any use.
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include <linux/version.h>
@@ -52,6 +71,7 @@
#include "lists.h"
+// The proc entry for our /proc/pvr directory
static struct proc_dir_entry * dir;
static const IMG_CHAR PVRProcDirRoot[] = "pvr";
@@ -98,6 +118,28 @@ static void ProcSeqShowVersion(struct seq_file *sfile,void* el);
static void ProcSeqShowSysNodes(struct seq_file *sfile,void* el);
static void* ProcSeqOff2ElementSysNodes(struct seq_file * sfile, loff_t off);
+/*!
+******************************************************************************
+
+ @Function : printAppend
+
+ @Description
+
+ Print into the supplied buffer at the specified offset remaining within
+ the specified total buffer size.
+
+ @Input size : the total size of the buffer
+
+ @Input off : the offset into the buffer to start printing
+
+ @Input format : the printf format string
+
+ @Input ... : format args
+
+ @Return : The number of chars now in the buffer (original value of 'off'
+ plus number of chars added); 'size' if full.
+
+*****************************************************************************/
off_t printAppend(IMG_CHAR * buffer, size_t size, off_t off, const IMG_CHAR * format, ...)
{
IMG_INT n;
@@ -109,10 +151,13 @@ off_t printAppend(IMG_CHAR * buffer, size_t size, off_t off, const IMG_CHAR * fo
n = vsnprintf (buffer+off, space, format, ap);
va_end (ap);
-
+ /* According to POSIX, n is greater than or equal to the size available if
+ * the print would have overflowed the buffer. Other platforms may
+ * return -1 if printing was truncated.
+ */
if (n >= (IMG_INT)space || n < 0)
{
-
+ /* Ensure final string is terminated */
buffer[size - 1] = 0;
return (off_t)(size - 1);
}
@@ -123,16 +168,50 @@ off_t printAppend(IMG_CHAR * buffer, size_t size, off_t off, const IMG_CHAR * fo
}
+/*!
+******************************************************************************
+
+ @Function : ProcSeq1ElementOff2Element
+
+ @Description
+
+ Heleper Offset -> Element function for /proc files with only one entry
+ without header.
+
+ @Input sfile : seq_file object related to /proc/ file
+
+ @Input off : the offset into the buffer (id of object)
+
+ @Return : Pointer to element to be shown.
+
+*****************************************************************************/
void* ProcSeq1ElementOff2Element(struct seq_file *sfile, loff_t off)
{
PVR_UNREFERENCED_PARAMETER(sfile);
-
+ // Return anything that is not PVR_RPOC_SEQ_START_TOKEN and NULL
if(!off)
return (void*)2;
return NULL;
}
+/*!
+******************************************************************************
+
+ @Function : ProcSeq1ElementHeaderOff2Element
+
+ @Description
+
+ Heleper Offset -> Element function for /proc files with only one entry
+ with header.
+
+ @Input sfile : seq_file object related to /proc/ file
+
+ @Input off : the offset into the buffer (id of object)
+
+ @Return : Pointer to element to be shown.
+
+*****************************************************************************/
void* ProcSeq1ElementHeaderOff2Element(struct seq_file *sfile, loff_t off)
{
PVR_UNREFERENCED_PARAMETER(sfile);
@@ -142,7 +221,7 @@ void* ProcSeq1ElementHeaderOff2Element(struct seq_file *sfile, loff_t off)
return PVR_PROC_SEQ_START_TOKEN;
}
-
+ // Return anything that is not PVR_RPOC_SEQ_START_TOKEN and NULL
if(off == 1)
return (void*)2;
@@ -150,6 +229,22 @@ void* ProcSeq1ElementHeaderOff2Element(struct seq_file *sfile, loff_t off)
}
+/*!
+******************************************************************************
+
+ @Function : pvr_proc_open
+
+ @Description
+ File opening function passed to proc_dir_entry->proc_fops for /proc entries
+ created by CreateProcReadEntrySeq.
+
+ @Input inode : inode entry of opened /proc file
+
+ @Input file : file entry of opened /proc file
+
+ @Return : 0 if no errors
+
+*****************************************************************************/
static IMG_INT pvr_proc_open(struct inode *inode,struct file *file)
{
IMG_INT ret = seq_open(file, &pvr_proc_seq_operations);
@@ -157,11 +252,22 @@ static IMG_INT pvr_proc_open(struct inode *inode,struct file *file)
struct seq_file *seq = (struct seq_file*)file->private_data;
struct proc_dir_entry* pvr_proc_entry = PDE(inode);
-
+ /* Add pointer to handlers to seq_file structure */
seq->private = pvr_proc_entry->data;
return ret;
}
+/*!
+******************************************************************************
+
+ @Function : pvr_proc_write
+
+ @Description
+ File writing function passed to proc_dir_entry->proc_fops for /proc files.
+ It's exacly the same function that is used as default one (->fs/proc/generic.c),
+ it calls proc_dir_entry->write_proc for writing procedure.
+
+*****************************************************************************/
static ssize_t pvr_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
@@ -178,6 +284,23 @@ static ssize_t pvr_proc_write(struct file *file, const char __user *buffer,
}
+/*!
+******************************************************************************
+
+ @Function : pvr_proc_seq_start
+
+ @Description
+ Seq_file start function. Detailed description of seq_file workflow can
+ be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html.
+ This function ises off2element handler.
+
+ @Input proc_seq_file : sequence file entry
+
+ @Input pos : offset within file (id of entry)
+
+ @Return : Pointer to element from we start enumeration (0 ends it)
+
+*****************************************************************************/
static void *pvr_proc_seq_start (struct seq_file *proc_seq_file, loff_t *pos)
{
PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private;
@@ -186,6 +309,20 @@ static void *pvr_proc_seq_start (struct seq_file *proc_seq_file, loff_t *pos)
return handlers->off2element(proc_seq_file, *pos);
}
+/*!
+******************************************************************************
+
+ @Function : pvr_proc_seq_stop
+
+ @Description
+ Seq_file stop function. Detailed description of seq_file workflow can
+ be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html.
+
+ @Input proc_seq_file : sequence file entry
+
+ @Input v : current element pointer
+
+*****************************************************************************/
static void pvr_proc_seq_stop (struct seq_file *proc_seq_file, void *v)
{
PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private;
@@ -195,6 +332,25 @@ static void pvr_proc_seq_stop (struct seq_file *proc_seq_file, void *v)
handlers->startstop(proc_seq_file, IMG_FALSE);
}
+/*!
+******************************************************************************
+
+ @Function : pvr_proc_seq_next
+
+ @Description
+ Seq_file next element function. Detailed description of seq_file workflow can
+ be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html.
+ It uses supplied 'next' handler for fetching next element (or 0 if there is no one)
+
+ @Input proc_seq_file : sequence file entry
+
+ @Input pos : offset within file (id of entry)
+
+ @Input v : current element pointer
+
+ @Return : next element pointer (or 0 if end)
+
+*****************************************************************************/
static void *pvr_proc_seq_next (struct seq_file *proc_seq_file, void *v, loff_t *pos)
{
PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private;
@@ -204,6 +360,23 @@ static void *pvr_proc_seq_next (struct seq_file *proc_seq_file, void *v, loff_t
return handlers->off2element(proc_seq_file, *pos);
}
+/*!
+******************************************************************************
+
+ @Function : pvr_proc_seq_show
+
+ @Description
+ Seq_file show element function. Detailed description of seq_file workflow can
+ be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html.
+ It call proper 'show' handler to show (dump) current element using seq_* functions
+
+ @Input proc_seq_file : sequence file entry
+
+ @Input v : current element pointer
+
+ @Return : 0 if everything is OK
+
+*****************************************************************************/
static int pvr_proc_seq_show (struct seq_file *proc_seq_file, void *v)
{
PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private;
@@ -213,6 +386,38 @@ static int pvr_proc_seq_show (struct seq_file *proc_seq_file, void *v)
+/*!
+******************************************************************************
+
+ @Function : CreateProcEntryInDirSeq
+
+ @Description
+
+ Create a file under the given directory. These dynamic files can be used at
+ runtime to get or set information about the device. Whis version uses seq_file
+ interface
+
+ @Input pdir : parent directory
+
+ @Input name : the name of the file to create
+
+ @Input data : aditional data that will be passed to handlers
+
+ @Input next_handler : the function to call to provide the next element. OPTIONAL, if not
+ supplied, then off2element function is used instead
+
+ @Input show_handler : the function to call to show element
+
+ @Input off2element_handler : the function to call when it is needed to translate offest to element
+
+ @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL.
+
+ @Input whandler : the function to interpret writes from the user
+
+ @Return Ptr to proc entry , 0 for failure
+
+
+*****************************************************************************/
static struct proc_dir_entry* CreateProcEntryInDirSeq(
struct proc_dir_entry *pdir,
const IMG_CHAR * name,
@@ -259,7 +464,7 @@ static struct proc_dir_entry* CreateProcEntryInDirSeq(
file->proc_fops = &pvr_proc_operations;
file->write_proc = whandler;
-
+ /* Pass the handlers */
file->data = kmalloc(sizeof(PVR_PROC_SEQ_HANDLERS), GFP_KERNEL);
if(file->data)
{
@@ -279,6 +484,35 @@ static struct proc_dir_entry* CreateProcEntryInDirSeq(
}
+/*!
+******************************************************************************
+
+ @Function : CreateProcReadEntrySeq
+
+ @Description
+
+ Create a file under /proc/pvr. These dynamic files can be used at runtime
+ to get information about the device. Creation WILL fail if proc support is
+ not compiled into the kernel. That said, the Linux kernel is not even happy
+ to build without /proc support these days. This version uses seq_file structure
+ for handling content generation.
+
+ @Input name : the name of the file to create
+
+ @Input data : aditional data that will be passed to handlers
+
+ @Input next_handler : the function to call to provide the next element. OPTIONAL, if not
+ supplied, then off2element function is used instead
+
+ @Input show_handler : the function to call to show element
+
+ @Input off2element_handler : the function to call when it is needed to translate offest to element
+
+ @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL.
+
+ @Return Ptr to proc entry , 0 for failure
+
+*****************************************************************************/
struct proc_dir_entry* CreateProcReadEntrySeq (
const IMG_CHAR * name,
IMG_VOID* data,
@@ -297,6 +531,40 @@ struct proc_dir_entry* CreateProcReadEntrySeq (
NULL);
}
+/*!
+******************************************************************************
+
+ @Function : CreateProcEntrySeq
+
+ @Description
+
+ @Description
+
+ Create a file under /proc/pvr. These dynamic files can be used at runtime
+ to get information about the device. Creation WILL fail if proc support is
+ not compiled into the kernel. That said, the Linux kernel is not even happy
+ to build without /proc support these days. This version uses seq_file structure
+ for handling content generation and is fuller than CreateProcReadEntrySeq (it
+ supports write access);
+
+ @Input name : the name of the file to create
+
+ @Input data : aditional data that will be passed to handlers
+
+ @Input next_handler : the function to call to provide the next element. OPTIONAL, if not
+ supplied, then off2element function is used instead
+
+ @Input show_handler : the function to call to show element
+
+ @Input off2element_handler : the function to call when it is needed to translate offest to element
+
+ @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL.
+
+ @Input whandler : the function to interpret writes from the user
+
+ @Return Ptr to proc entry , 0 for failure
+
+*****************************************************************************/
struct proc_dir_entry* CreateProcEntrySeq (
const IMG_CHAR * name,
IMG_VOID* data,
@@ -321,6 +589,37 @@ struct proc_dir_entry* CreateProcEntrySeq (
+/*!
+******************************************************************************
+
+ @Function : CreatePerProcessProcEntrySeq
+
+ @Description
+
+ Create a file under /proc/pvr/<current process ID>. Apart from the
+ directory where the file is created, this works the same way as
+ CreateProcEntry. It's seq_file version.
+
+
+
+ @Input name : the name of the file to create
+
+ @Input data : aditional data that will be passed to handlers
+
+ @Input next_handler : the function to call to provide the next element. OPTIONAL, if not
+ supplied, then off2element function is used instead
+
+ @Input show_handler : the function to call to show element
+
+ @Input off2element_handler : the function to call when it is needed to translate offest to element
+
+ @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL.
+
+ @Input whandler : the function to interpret writes from the user
+
+ @Return Ptr to proc entry , 0 for failure
+
+*****************************************************************************/
struct proc_dir_entry* CreatePerProcessProcEntrySeq (
const IMG_CHAR * name,
IMG_VOID* data,
@@ -379,6 +678,20 @@ struct proc_dir_entry* CreatePerProcessProcEntrySeq (
}
+/*!
+******************************************************************************
+
+ @Function : RemoveProcEntrySeq
+
+ @Description
+
+ Remove a single node (created using *Seq function) under /proc/pvr.
+
+ @Input proc_entry : structure returned by Create function.
+
+ @Return nothing
+
+*****************************************************************************/
IMG_VOID RemoveProcEntrySeq( struct proc_dir_entry* proc_entry )
{
if (dir)
@@ -393,6 +706,22 @@ IMG_VOID RemoveProcEntrySeq( struct proc_dir_entry* proc_entry )
}
}
+/*!
+******************************************************************************
+
+ @Function : RemovePerProcessProcEntry Seq
+
+ @Description
+
+ Remove a single node under the per process proc directory (created by *Seq function).
+
+ Remove a single node (created using *Seq function) under /proc/pvr.
+
+ @Input proc_entry : structure returned by Create function.
+
+ @Return nothing
+
+*****************************************************************************/
IMG_VOID RemovePerProcessProcEntrySeq(struct proc_dir_entry* proc_entry)
{
PVRSRV_ENV_PER_PROCESS_DATA *psPerProc;
@@ -420,10 +749,46 @@ IMG_VOID RemovePerProcessProcEntrySeq(struct proc_dir_entry* proc_entry)
}
}
+/*!
+******************************************************************************
+
+ @Function : pvr_read_proc_vm
+
+ @Description
+
+ When the user accesses the proc filesystem entry for the device, we are
+ called here to create the content for the 'file'. We can print anything we
+ want here. If the info we want to return is too big for one page ('count'
+ chars), we return successive chunks on each call. For a number of ways of
+ achieving this, refer to proc_file_read() in linux/fs/proc/generic.c.
+
+ Here, as we are accessing lists of information, we output '1' in '*start' to
+ instruct proc to advance 'off' by 1 on each call. The number of chars placed
+ in the buffer is returned. Multiple calls are made here by the proc
+ filesystem until we set *eof. We can return zero without setting eof to
+ instruct proc to flush 'page' (causing it to be printed) if there is not
+ enough space left (eg for a complete line).
+
+ @Input page : where to write the output
+
+ @Input start : memory location into which should be written next offset
+ to read from.
+
+ @Input off : the offset into the /proc file being read
+
+ @Input count : the size of the buffer 'page'
+
+ @Input eof : memory location into which 1 should be written when at EOF
+
+ @Input data : data specific to this /proc file entry
+
+ @Return : length of string written to page
+
+*****************************************************************************/
static IMG_INT pvr_read_proc(IMG_CHAR *page, IMG_CHAR **start, off_t off,
IMG_INT count, IMG_INT *eof, IMG_VOID *data)
{
-
+ /* PRQA S 0307 1 */ /* ignore warning about casting to different pointer type */
pvr_read_proc_t *pprn = (pvr_read_proc_t *)data;
off_t len = pprn (page, (size_t)count, off);
@@ -433,9 +798,9 @@ static IMG_INT pvr_read_proc(IMG_CHAR *page, IMG_CHAR **start, off_t off,
len = 0;
*eof = 1;
}
- else if (!len)
+ else if (!len) /* not enough space in the buffer */
{
- *start = (IMG_CHAR *) 0;
+ *start = (IMG_CHAR *) 0; /* don't advance the offset */
}
else
{
@@ -446,6 +811,27 @@ static IMG_INT pvr_read_proc(IMG_CHAR *page, IMG_CHAR **start, off_t off,
}
+/*!
+******************************************************************************
+
+ @Function : CreateProcEntryInDir
+
+ @Description
+
+ Create a file under the given directory. These dynamic files can be used at
+ runtime to get or set information about the device.
+
+ @Input pdir : parent directory
+
+ @Input name : the name of the file to create
+
+ @Input rhandler : the function to supply the content
+
+ @Input whandler : the function to interpret writes from the user
+
+ @Return success code : 0 or -errno.
+
+*****************************************************************************/
static IMG_INT CreateProcEntryInDir(struct proc_dir_entry *pdir, const IMG_CHAR * name, read_proc_t rhandler, write_proc_t whandler, IMG_VOID *data)
{
struct proc_dir_entry * file;
@@ -492,12 +878,54 @@ static IMG_INT CreateProcEntryInDir(struct proc_dir_entry *pdir, const IMG_CHAR
}
+/*!
+******************************************************************************
+
+ @Function : CreateProcEntry
+
+ @Description
+
+ Create a file under /proc/pvr. These dynamic files can be used at runtime
+ to get or set information about the device.
+
+ This interface is fuller than CreateProcReadEntry, and supports write access;
+ it is really just a wrapper for the native linux functions.
+
+ @Input name : the name of the file to create under /proc/pvr
+
+ @Input rhandler : the function to supply the content
+
+ @Input whandler : the function to interpret writes from the user
+
+ @Return success code : 0 or -errno.
+
+*****************************************************************************/
IMG_INT CreateProcEntry(const IMG_CHAR * name, read_proc_t rhandler, write_proc_t whandler, IMG_VOID *data)
{
return CreateProcEntryInDir(dir, name, rhandler, whandler, data);
}
+/*!
+******************************************************************************
+
+ @Function : CreatePerProcessProcEntry
+
+ @Description
+
+ Create a file under /proc/pvr/<current process ID>. Apart from the
+ directory where the file is created, this works the same way as
+ CreateProcEntry.
+
+ @Input name : the name of the file to create under the per process /proc directory
+
+ @Input rhandler : the function to supply the content
+
+ @Input whandler : the function to interpret writes from the user
+
+ @Return success code : 0 or -errno.
+
+*****************************************************************************/
IMG_INT CreatePerProcessProcEntry(const IMG_CHAR * name, read_proc_t rhandler, write_proc_t whandler, IMG_VOID *data)
{
PVRSRV_ENV_PER_PROCESS_DATA *psPerProc;
@@ -549,6 +977,25 @@ IMG_INT CreatePerProcessProcEntry(const IMG_CHAR * name, read_proc_t rhandler, w
}
+/*!
+******************************************************************************
+
+ @Function : CreateProcReadEntry
+
+ @Description
+
+ Create a file under /proc/pvr. These dynamic files can be used at runtime
+ to get information about the device. Creation WILL fail if proc support is
+ not compiled into the kernel. That said, the Linux kernel is not even happy
+ to build without /proc support these days.
+
+ @Input name : the name of the file to create
+
+ @Input handler : the function to call to provide the content
+
+ @Return 0 for success, -errno for failure
+
+*****************************************************************************/
IMG_INT CreateProcReadEntry(const IMG_CHAR * name, pvr_read_proc_t handler)
{
struct proc_dir_entry * file;
@@ -560,7 +1007,7 @@ IMG_INT CreateProcReadEntry(const IMG_CHAR * name, pvr_read_proc_t handler)
return -ENOMEM;
}
-
+ /* PRQA S 0307 1 */ /* ignore warning about casting to different pointer type */
file = create_proc_read_entry (name, S_IFREG | S_IRUGO, dir, pvr_read_proc, (IMG_VOID *)handler);
if (file)
@@ -577,6 +1024,23 @@ IMG_INT CreateProcReadEntry(const IMG_CHAR * name, pvr_read_proc_t handler)
}
+/*!
+******************************************************************************
+
+ @Function : CreateProcEntries
+
+ @Description
+
+ Create a directory /proc/pvr and the necessary entries within it. These
+ dynamic files can be used at runtime to get information about the device.
+ Creation might fail if proc support is not compiled into the kernel or if
+ there is no memory
+
+ @Input none
+
+ @Return nothing
+
+*****************************************************************************/
IMG_INT CreateProcEntries(IMG_VOID)
{
dir = proc_mkdir (PVRProcDirRoot, NULL);
@@ -631,6 +1095,20 @@ IMG_INT CreateProcEntries(IMG_VOID)
}
+/*!
+******************************************************************************
+
+ @Function : RemoveProcEntry
+
+ @Description
+
+ Remove a single node under /proc/pvr.
+
+ @Input name : the name of the node to remove
+
+ @Return nothing
+
+*****************************************************************************/
IMG_VOID RemoveProcEntry(const IMG_CHAR * name)
{
if (dir)
@@ -641,6 +1119,20 @@ IMG_VOID RemoveProcEntry(const IMG_CHAR * name)
}
+/*!
+******************************************************************************
+
+ @Function : RemovePerProcessProcEntry
+
+ @Description
+
+ Remove a single node under the per process proc directory.
+
+ @Input name : the name of the node to remove
+
+ @Return nothing
+
+*****************************************************************************/
IMG_VOID RemovePerProcessProcEntry(const IMG_CHAR *name)
{
PVRSRV_ENV_PER_PROCESS_DATA *psPerProc;
@@ -666,6 +1158,20 @@ IMG_VOID RemovePerProcessProcEntry(const IMG_CHAR *name)
}
+/*!
+******************************************************************************
+
+ @Function : RemovePerProcessProcDir
+
+ @Description
+
+ Remove the per process directorty under /proc/pvr.
+
+ @Input psPerProc : environment specific per process data
+
+ @Return nothing
+
+*****************************************************************************/
IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psPerProc)
{
if (psPerProc->psProcDir)
@@ -680,13 +1186,28 @@ IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psPerProc)
}
}
+/*!
+******************************************************************************
+
+ @Function : RemoveProcEntries
+
+ Description
+
+ Proc filesystem entry deletion - Remove all proc filesystem entries for
+ the driver.
+
+ @Input none
+
+ @Return nothing
+
+*****************************************************************************/
IMG_VOID RemoveProcEntries(IMG_VOID)
{
#ifdef DEBUG
RemoveProcEntrySeq( g_pProcDebugLevel );
#ifdef PVR_MANUAL_POWER_CONTROL
RemoveProcEntrySeq( g_pProcPowerLevel );
-#endif
+#endif /* PVR_MANUAL_POWER_CONTROL */
#endif
RemoveProcEntrySeq(g_pProcQueue);
@@ -703,6 +1224,14 @@ IMG_VOID RemoveProcEntries(IMG_VOID)
remove_proc_entry(PVRProcDirRoot, NULL);
}
+/*****************************************************************************
+ FUNCTION : ProcSeqShowVersion
+
+ PURPOSE : Print the content of version to /proc file
+
+ PARAMETERS : sfile - /proc seq_file
+ el - Element to print
+*****************************************************************************/
static void ProcSeqShowVersion(struct seq_file *sfile,void* el)
{
SYS_DATA *psSysData;
@@ -726,6 +1255,24 @@ static void ProcSeqShowVersion(struct seq_file *sfile,void* el)
seq_printf( sfile, "System Version String: %s\n", pszSystemVersionString);
}
+/*!
+******************************************************************************
+
+ @Function procDumpSysNodes (plus deviceTypeToString and deviceClassToString)
+
+ @Description
+
+ Format the contents of /proc/pvr/nodes
+
+ @Input buf : where to place format contents data.
+
+ @Input size : the size of the buffer into which to place data
+
+ @Input off : how far into the file we are.
+
+ @Return amount of data placed in buffer, 0, or END_OF_FILE :
+
+******************************************************************************/
static const IMG_CHAR *deviceTypeToString(PVRSRV_DEVICE_TYPE deviceType)
{
switch (deviceType)
@@ -781,6 +1328,14 @@ static IMG_VOID* DecOffPsDev_AnyVaCb(PVRSRV_DEVICE_NODE *psNode, va_list va)
}
}
+/*****************************************************************************
+ FUNCTION : ProcSeqShowSysNodes
+
+ PURPOSE : Print the content of version to /proc file
+
+ PARAMETERS : sfile - /proc seq_file
+ el - Element to print
+*****************************************************************************/
static void ProcSeqShowSysNodes(struct seq_file *sfile,void* el)
{
PVRSRV_DEVICE_NODE *psDevNode;
@@ -807,6 +1362,16 @@ static void ProcSeqShowSysNodes(struct seq_file *sfile,void* el)
psDevNode->hResManContext);
}
+/*****************************************************************************
+ FUNCTION : ProcSeqOff2ElementSysNodes
+
+ PURPOSE : Transale offset to element (/proc stuff)
+
+ PARAMETERS : sfile - /proc seq_file
+ off - the offset into the buffer
+
+ RETURNS : element to print
+*****************************************************************************/
static void* ProcSeqOff2ElementSysNodes(struct seq_file * sfile, loff_t off)
{
SYS_DATA *psSysData;
@@ -822,14 +1387,17 @@ static void* ProcSeqOff2ElementSysNodes(struct seq_file * sfile, loff_t off)
psSysData = SysAcquireDataNoCheck();
if (psSysData != IMG_NULL)
{
-
+ /* Find Dev Node */
psDevNode = (PVRSRV_DEVICE_NODE*)
List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
DecOffPsDev_AnyVaCb,
&off);
}
-
+ /* Return anything that is not PVR_RPOC_SEQ_START_TOKEN and NULL */
return (void*)psDevNode;
}
+/*****************************************************************************
+ End of file (proc.c)
+*****************************************************************************/
diff --git a/sgx/services4/srvkm/env/linux/proc.h b/sgx/services4/srvkm/env/linux/proc.h
index 2066d71..67cded7 100644
--- a/sgx/services4/srvkm/env/linux/proc.h
+++ b/sgx/services4/srvkm/env/linux/proc.h
@@ -1,35 +1,53 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Proc interface definition.
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description Functions for creating and reading proc filesystem entries.
+ Refer to proc.c
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#ifndef __SERVICES_PROC_H__
#define __SERVICES_PROC_H__
-#include <asm/system.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
+#include <asm/system.h> // va_list etc
+#include <linux/proc_fs.h> // read_proc_t etc
+#include <linux/seq_file.h> // seq_file
#define END_OF_FILE (off_t) -1
@@ -51,8 +69,10 @@ typedef struct _PVR_PROC_SEQ_HANDLERS_ {
} PVR_PROC_SEQ_HANDLERS;
+/** off2element function for elements with only ONE element (no header) */
void* ProcSeq1ElementOff2Element(struct seq_file *sfile, loff_t off);
+/** off2element function for elements with only ONE element (+ header) */
void* ProcSeq1ElementHeaderOff2Element(struct seq_file *sfile, loff_t off);
off_t printAppend(IMG_CHAR * buffer, size_t size, off_t off, const IMG_CHAR * format, ...)
diff --git a/sgx/services4/srvkm/env/linux/pvr_bridge_k.c b/sgx/services4/srvkm/env/linux/pvr_bridge_k.c
index 373b586..037b4c9 100644
--- a/sgx/services4/srvkm/env/linux/pvr_bridge_k.c
+++ b/sgx/services4/srvkm/env/linux/pvr_bridge_k.c
@@ -1,28 +1,46 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title PVR Bridge Module (kernel side)
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description Receives calls from the user portion of services and
+ despatches them to functions in the kernel portion.
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include "img_defs.h"
#include "services.h"
@@ -36,6 +54,8 @@
#include "linkage.h"
#include "pvr_bridge_km.h"
#include "pvr_uaccess.h"
+#include "refcount.h"
+#include "buffer_manager.h"
#if defined(SUPPORT_DRI_DRM)
#include <drm/drmP.h>
@@ -45,10 +65,12 @@
#endif
#endif
+/* VGX: */
#if defined(SUPPORT_VGX)
#include "vgx_bridge.h"
#endif
+/* SGX: */
#if defined(SUPPORT_SGX)
#include "sgx_bridge.h"
#endif
@@ -69,7 +91,7 @@ extern PVRSRV_LINUX_MUTEX gPVRSRVLock;
#if defined(SUPPORT_MEMINFO_IDS)
static IMG_UINT64 ui64Stamp;
-#endif
+#endif /* defined(SUPPORT_MEMINFO_IDS) */
PVRSRV_ERROR
LinuxBridgeInit(IMG_VOID)
@@ -103,6 +125,13 @@ LinuxBridgeDeInit(IMG_VOID)
#if defined(DEBUG_BRIDGE_KM)
+/*
+ * Lock MMap regions list (called on page start/stop while reading /proc/mmap)
+ *
+ * sfile : seq_file that handles /proc file
+ * start : TRUE if it's start, FALSE if it's stop
+ *
+ */
static void ProcSeqStartstopBridgeStats(struct seq_file *sfile,IMG_BOOL start)
{
if(start)
@@ -116,6 +145,16 @@ static void ProcSeqStartstopBridgeStats(struct seq_file *sfile,IMG_BOOL start)
}
+/*
+ * Convert offset (index from KVOffsetTable) to element
+ * (called when reading /proc/mmap file)
+
+ * sfile : seq_file that handles /proc file
+ * off : index into the KVOffsetTable from which to print
+ *
+ * returns void* : Pointer to element that will be dumped
+ *
+*/
static void* ProcSeqOff2ElementBridgeStats(struct seq_file *sfile, loff_t off)
{
if(!off)
@@ -132,12 +171,28 @@ static void* ProcSeqOff2ElementBridgeStats(struct seq_file *sfile, loff_t off)
return (void*)&g_BridgeDispatchTable[off-1];
}
+/*
+ * Gets next MMap element to show. (called when reading /proc/mmap file)
+
+ * sfile : seq_file that handles /proc file
+ * el : actual element
+ * off : index into the KVOffsetTable from which to print
+ *
+ * returns void* : Pointer to element to show (0 ends iteration)
+*/
static void* ProcSeqNextBridgeStats(struct seq_file *sfile,void* el,loff_t off)
{
return ProcSeqOff2ElementBridgeStats(sfile,off);
}
+/*
+ * Show MMap element (called when reading /proc/mmap file)
+
+ * sfile : seq_file that handles /proc file
+ * el : actual element
+ *
+*/
static void ProcSeqShowBridgeStats(struct seq_file *sfile,void* el)
{
PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *psEntry = ( PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY*)el;
@@ -172,7 +227,7 @@ static void ProcSeqShowBridgeStats(struct seq_file *sfile,void* el)
psEntry->ui32CopyToUserTotalBytes);
}
-#endif
+#endif /* DEBUG_BRIDGE_KM */
#if defined(SUPPORT_DRI_DRM)
@@ -211,7 +266,9 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig
goto unlock_and_return;
}
-
+ /* FIXME - Currently the CopyFromUserWrapper which collects stats about
+ * how much data is shifted to/from userspace isn't available to us
+ * here. */
if(OSCopyFromUser(IMG_NULL,
psBridgePackageKM,
psBridgePackageUM,
@@ -249,7 +306,7 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig
}
else
{
-
+ /* lookup per-process data for this process */
psPerProc = PVRSRVPerProcessData(ui32PID);
if(psPerProc == IMG_NULL)
{
@@ -328,7 +385,13 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig
break;
}
-
+ /*
+ * The DRM file structure we are using for Services
+ * is not one that DRI authentication was done on.
+ * Look for an authenticated file structure for
+ * this process, making sure the DRM master is the
+ * same as ours.
+ */
psEnvPerProc = (PVRSRV_ENV_PER_PROCESS_DATA *)PVRSRVProcessPrivateData(psPerProc);
if (psEnvPerProc == IMG_NULL)
{
@@ -362,7 +425,7 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig
default:
break;
}
-#endif
+#endif /* defined(SUPPORT_DRI_DRM) && defined(PVR_SECURE_DRM_AUTH_EXPORT) */
#if defined(SUPPORT_DRI_DRM_EXTERNAL)
{
@@ -384,15 +447,40 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig
PVRSRV_BRIDGE_OUT_EXPORTDEVICEMEM *psExportDeviceMemOUT =
(PVRSRV_BRIDGE_OUT_EXPORTDEVICEMEM *)psBridgePackageKM->pvParamOut;
PVRSRV_FILE_PRIVATE_DATA *psPrivateData = get_private(pFile);
+ IMG_HANDLE hMemInfo;
+ PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo;
- if (pvr_get_user(psPrivateData->hKernelMemInfo, &psExportDeviceMemOUT->hMemInfo) != 0)
+ if (pvr_get_user(hMemInfo, &psExportDeviceMemOUT->hMemInfo) != 0)
{
err = -EFAULT;
goto unlock_and_return;
}
+
+ /* Look up the meminfo we just exported */
+ if(PVRSRVLookupHandle(KERNEL_HANDLE_BASE,
+ (IMG_PVOID *)&psKernelMemInfo,
+ hMemInfo,
+ PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK)
+ {
+ PVR_DPF((PVR_DBG_ERROR, "%s: Failed to look up export handle", __FUNCTION__));
+ err = -EFAULT;
+ goto unlock_and_return;
+ }
+
+ /* Bump the refcount; decremented on release of the fd */
+ PVRSRVKernelMemInfoIncRef(psKernelMemInfo);
+
+ /* Tell the XProc about the export if required */
+ if (psKernelMemInfo->sShareMemWorkaround.bInUse)
+ {
+ BM_XProcIndexAcquire(psKernelMemInfo->sShareMemWorkaround.ui32ShareIndex);
+ }
+
+ psPrivateData->hKernelMemInfo = hMemInfo;
#if defined(SUPPORT_MEMINFO_IDS)
psPrivateData->ui64Stamp = ++ui64Stamp;
+ psKernelMemInfo->ui64Stamp = psPrivateData->ui64Stamp;
if (pvr_put_user(psPrivateData->ui64Stamp, &psExportDeviceMemOUT->ui64Stamp) != 0)
{
err = -EFAULT;
@@ -404,6 +492,7 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig
#if defined(SUPPORT_MEMINFO_IDS)
case PVRSRV_BRIDGE_MAP_DEV_MEMORY:
+ case PVRSRV_BRIDGE_MAP_DEV_MEMORY_2:
{
PVRSRV_BRIDGE_OUT_MAP_DEV_MEMORY *psMapDeviceMemoryOUT =
(PVRSRV_BRIDGE_OUT_MAP_DEV_MEMORY *)psBridgePackageKM->pvParamOut;
@@ -427,7 +516,7 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig
}
break;
}
-#endif
+#endif /* defined(SUPPORT_MEMINFO_IDS) */
default:
break;
diff --git a/sgx/services4/srvkm/env/linux/pvr_debug.c b/sgx/services4/srvkm/env/linux/pvr_debug.c
index 7690875..ad3e32b 100644
--- a/sgx/services4/srvkm/env/linux/pvr_debug.c
+++ b/sgx/services4/srvkm/env/linux/pvr_debug.c
@@ -1,28 +1,45 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Debug Functionality
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description Provides kernel side Debug Functionality
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#include <linux/version.h>
@@ -38,7 +55,7 @@
#include <linux/hardirq.h>
#include <linux/module.h>
#include <linux/spinlock.h>
-#include <linux/string.h>
+#include <linux/string.h> // strncpy, strlen
#include <stdarg.h>
#include "img_types.h"
#include "servicesext.h"
@@ -49,6 +66,10 @@
#include "linkage.h"
#include "pvr_uaccess.h"
+#if !defined(CONFIG_PREEMPT)
+#define PVR_DEBUG_ALWAYS_USE_SPINLOCK
+#endif
+
static IMG_BOOL VBAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz,
const IMG_CHAR* pszFormat, va_list VArgs)
IMG_FORMAT_PRINTF(3, 0);
@@ -62,67 +83,96 @@ static IMG_BOOL BAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz,
const IMG_CHAR *pszFormat, ...)
IMG_FORMAT_PRINTF(3, 4);
+/* NOTE: Must NOT be static! Used in module.c.. */
IMG_UINT32 gPVRDebugLevel =
(DBGPRIV_FATAL | DBGPRIV_ERROR | DBGPRIV_WARNING);
-#endif
+#endif /* defined(PVRSRV_NEED_PVR_DPF) || defined(PVRSRV_NEED_PVR_TRACE) */
#define PVR_MAX_MSG_LEN PVR_MAX_DEBUG_MESSAGE_LEN
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+/* Message buffer for non-IRQ messages */
static IMG_CHAR gszBufferNonIRQ[PVR_MAX_MSG_LEN + 1];
+#endif
+/* Message buffer for IRQ messages */
static IMG_CHAR gszBufferIRQ[PVR_MAX_MSG_LEN + 1];
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+/* The lock is used to control access to gszBufferNonIRQ */
static PVRSRV_LINUX_MUTEX gsDebugMutexNonIRQ;
+#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
+/* The lock is used to control access to gszBufferIRQ */
+/* PRQA S 0671,0685 1 */ /* ignore warnings about C99 style initialisation */
static spinlock_t gsDebugLockIRQ = SPIN_LOCK_UNLOCKED;
#else
-static spinlock_t gsDebugLockIRQ = __SPIN_LOCK_UNLOCKED(gsDebugLockIRQ);
+static DEFINE_SPINLOCK(gsDebugLockIRQ);
#endif
-#if !defined (USE_SPIN_LOCK)
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+#if !defined (USE_SPIN_LOCK) /* to keep QAC happy */
#define USE_SPIN_LOCK (in_interrupt() || !preemptible())
#endif
+#endif
static inline void GetBufferLock(unsigned long *pulLockFlags)
{
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
if (USE_SPIN_LOCK)
+#endif
{
spin_lock_irqsave(&gsDebugLockIRQ, *pulLockFlags);
}
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
else
{
LinuxLockMutex(&gsDebugMutexNonIRQ);
}
+#endif
}
static inline void ReleaseBufferLock(unsigned long ulLockFlags)
{
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
if (USE_SPIN_LOCK)
+#endif
{
spin_unlock_irqrestore(&gsDebugLockIRQ, ulLockFlags);
}
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
else
{
LinuxUnLockMutex(&gsDebugMutexNonIRQ);
}
+#endif
}
static inline void SelectBuffer(IMG_CHAR **ppszBuf, IMG_UINT32 *pui32BufSiz)
{
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
if (USE_SPIN_LOCK)
+#endif
{
*ppszBuf = gszBufferIRQ;
*pui32BufSiz = sizeof(gszBufferIRQ);
}
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
else
{
*ppszBuf = gszBufferNonIRQ;
*pui32BufSiz = sizeof(gszBufferNonIRQ);
}
+#endif
}
+/*
+ * Append a string to a buffer using formatted conversion.
+ * The function takes a variable number of arguments, pointed
+ * to by the var args list.
+ */
static IMG_BOOL VBAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR* pszFormat, va_list VArgs)
{
IMG_UINT32 ui32Used;
@@ -136,15 +186,27 @@ static IMG_BOOL VBAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR
i32Len = vsnprintf(&pszBuf[ui32Used], ui32Space, pszFormat, VArgs);
pszBuf[ui32BufSiz - 1] = 0;
-
+ /* Return true if string was truncated */
return (i32Len < 0 || i32Len >= (IMG_INT32)ui32Space) ? IMG_TRUE : IMG_FALSE;
}
+/* Actually required for ReleasePrintf too */
+
IMG_VOID PVRDPFInit(IMG_VOID)
{
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
LinuxInitMutex(&gsDebugMutexNonIRQ);
+#endif
}
+/*!
+******************************************************************************
+ @Function PVRSRVReleasePrintf
+ @Description To output an important message to the user in release builds
+ @Input pszFormat - The message format string
+ @Input ... - Zero or more arguments for use by the format string
+ @Return None
+ ******************************************************************************/
IMG_VOID PVRSRVReleasePrintf(const IMG_CHAR *pszFormat, ...)
{
va_list vaArgs;
@@ -173,18 +235,16 @@ IMG_VOID PVRSRVReleasePrintf(const IMG_CHAR *pszFormat, ...)
}
-#if defined(PVRSRV_NEED_PVR_ASSERT)
-
-IMG_VOID PVRSRVDebugAssertFail(const IMG_CHAR* pszFile, IMG_UINT32 uLine)
-{
- PVRSRVDebugPrintf(DBGPRIV_FATAL, pszFile, uLine, "Debug assertion failed!");
- BUG();
-}
-
-#endif
-
#if defined(PVRSRV_NEED_PVR_TRACE)
+/*!
+******************************************************************************
+ @Function PVRTrace
+ @Description To output a debug message to the user
+ @Input pszFormat - The message format string
+ @Input ... - Zero or more arguments for use by the format string
+ @Return None
+ ******************************************************************************/
IMG_VOID PVRSRVTrace(const IMG_CHAR* pszFormat, ...)
{
va_list VArgs;
@@ -214,10 +274,15 @@ IMG_VOID PVRSRVTrace(const IMG_CHAR* pszFormat, ...)
va_end(VArgs);
}
-#endif
+#endif /* defined(PVRSRV_NEED_PVR_TRACE) */
#if defined(PVRSRV_NEED_PVR_DPF)
+/*
+ * Append a string to a buffer using formatted conversion.
+ * The function takes a variable number of arguments, calling
+ * VBAppend to do the actual work.
+ */
static IMG_BOOL BAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR *pszFormat, ...)
{
va_list VArgs;
@@ -232,6 +297,17 @@ static IMG_BOOL BAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR
return bTrunc;
}
+/*!
+******************************************************************************
+ @Function PVRSRVDebugPrintf
+ @Description To output a debug message to the user
+ @Input uDebugLevel - The current debug level
+ @Input pszFile - The source file generating the message
+ @Input uLine - The line of the source file
+ @Input pszFormat - The message format string
+ @Input ... - Zero or more arguments for use by the format string
+ @Return None
+ ******************************************************************************/
IMG_VOID PVRSRVDebugPrintf (
IMG_UINT32 ui32DebugLevel,
const IMG_CHAR* pszFullFileName,
@@ -260,7 +336,7 @@ IMG_VOID PVRSRVDebugPrintf (
GetBufferLock(&ulLockFlags);
-
+ /* Add in the level of warning */
if (bTrace == IMG_FALSE)
{
switch(ui32DebugLevel)
@@ -308,21 +384,22 @@ IMG_VOID PVRSRVDebugPrintf (
}
else
{
-
+ /* Traces don't need a location */
if (bTrace == IMG_FALSE)
{
#ifdef DEBUG_LOG_PATH_TRUNCATE
-
+ /* Buffer for rewriting filepath in log messages */
static IMG_CHAR szFileNameRewrite[PVR_MAX_FILEPATH_LEN];
IMG_CHAR* pszTruncIter;
IMG_CHAR* pszTruncBackInter;
-
+ /* Truncate path (DEBUG_LOG_PATH_TRUNCATE shoud be set to EURASIA env var)*/
if (strlen(pszFullFileName) > strlen(DEBUG_LOG_PATH_TRUNCATE)+1)
pszFileName = pszFullFileName + strlen(DEBUG_LOG_PATH_TRUNCATE)+1;
-
+ /* Try to find '/../' entries and remove it together with
+ previous entry. Repeat unit all removed */
strncpy(szFileNameRewrite, pszFileName,PVR_MAX_FILEPATH_LEN);
if(strlen(szFileNameRewrite) == PVR_MAX_FILEPATH_LEN-1) {
@@ -334,7 +411,7 @@ IMG_VOID PVRSRVDebugPrintf (
while(*pszTruncIter++ != 0)
{
IMG_CHAR* pszNextStartPoint;
-
+ /* Find '/../' pattern */
if(
!( ( *pszTruncIter == '/' && (pszTruncIter-4 >= szFileNameRewrite) ) &&
( *(pszTruncIter-1) == '.') &&
@@ -342,7 +419,7 @@ IMG_VOID PVRSRVDebugPrintf (
( *(pszTruncIter-3) == '/') )
) continue;
-
+ /* Find previous '/' */
pszTruncBackInter = pszTruncIter - 3;
while(*(--pszTruncBackInter) != '/')
{
@@ -350,19 +427,19 @@ IMG_VOID PVRSRVDebugPrintf (
}
pszNextStartPoint = pszTruncBackInter;
-
+ /* Remove found region */
while(*pszTruncIter != 0)
{
*pszTruncBackInter++ = *pszTruncIter++;
}
*pszTruncBackInter = 0;
-
+ /* Start again */
pszTruncIter = pszNextStartPoint;
}
pszFileName = szFileNameRewrite;
-
+ /* Remove first '/' if exist (it's always relative path */
if(*pszFileName == '/') pszFileName++;
#endif
@@ -373,7 +450,7 @@ IMG_VOID PVRSRVDebugPrintf (
{
pszFileName = pszLeafName;
}
-#endif
+#endif /* __sh__ */
if (BAppend(pszBuf, ui32BufSiz, " [%u, %s]", ui32Line, pszFileName))
{
@@ -396,16 +473,16 @@ IMG_VOID PVRSRVDebugPrintf (
}
}
-#endif
+#endif /* PVRSRV_NEED_PVR_DPF */
#if defined(DEBUG)
IMG_INT PVRDebugProcSetLevel(struct file *file, const IMG_CHAR *buffer, IMG_UINT32 count, IMG_VOID *data)
{
-#define _PROC_SET_BUFFER_SZ 2
+#define _PROC_SET_BUFFER_SZ 6
IMG_CHAR data_buffer[_PROC_SET_BUFFER_SZ];
- if (count != _PROC_SET_BUFFER_SZ)
+ if (count > _PROC_SET_BUFFER_SZ)
{
return -EINVAL;
}
@@ -415,7 +492,9 @@ IMG_INT PVRDebugProcSetLevel(struct file *file, const IMG_CHAR *buffer, IMG_UINT
return -EINVAL;
if (data_buffer[count - 1] != '\n')
return -EINVAL;
- gPVRDebugLevel = data_buffer[0] - '0';
+ if (sscanf(data_buffer, "%i", &gPVRDebugLevel) == 0)
+ return -EINVAL;
+ gPVRDebugLevel &= (1 << DBGPRIV_DBGLEVEL_COUNT) - 1;
}
return (count);
}
@@ -425,4 +504,4 @@ void ProcSeqShowDebugLevel(struct seq_file *sfile,void* el)
seq_printf(sfile, "%u\n", gPVRDebugLevel);
}
-#endif
+#endif /* defined(DEBUG) */
diff --git a/sgx/services4/srvkm/env/linux/pvr_drm.c b/sgx/services4/srvkm/env/linux/pvr_drm.c
index 620c158..c955bcf 100644
--- a/sgx/services4/srvkm/env/linux/pvr_drm.c
+++ b/sgx/services4/srvkm/env/linux/pvr_drm.c
@@ -1,29 +1,45 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
-
+/*************************************************************************/ /*!
+@Title PowerVR drm driver
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description linux module setup
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#if defined(SUPPORT_DRI_DRM)
#include <linux/version.h>
@@ -44,8 +60,9 @@
#include <drm/drmP.h>
#include <drm/drm.h>
-#ifdef SUPPORT_DRI_DRM_EXTERNAL
+#if defined(SUPPORT_DRI_DRM_EXTERNAL)
# include <linux/omap_drm.h>
+# include <linux/omap_drv.h>
#endif
#include "img_defs.h"
@@ -107,20 +124,20 @@ static struct platform_device_id asPlatIdList[] = {
{}
};
#endif
-#else
+#else /* defined(PVR_DRI_DRM_PLATFORM_DEV) */
static struct pci_device_id asPciIdList[] = {
#if defined(PVR_DRI_DRM_NOT_PCI)
{1, 1, 1, 1, 0, 0, 0},
-#else
+#else /* defined(PVR_DRI_DRM_NOT_PCI) */
{SYS_SGX_DEV_VENDOR_ID, SYS_SGX_DEV_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
#if defined(SYS_SGX_DEV1_DEVICE_ID)
{SYS_SGX_DEV_VENDOR_ID, SYS_SGX_DEV1_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-#endif
-#endif
+#endif /* defined(SYS_SGX_DEV1_DEVICE_ID) */
+#endif /* defined(PVR_DRI_DRM_NOT_PCI) */
{0}
};
-#endif
-#endif
+#endif /* defined(PVR_DRI_DRM_PLATFORM_DEV) */
+#endif /* !defined(SUPPORT_DRI_DRM_EXT) */
DRI_DRM_STATIC int
PVRSRVDrmLoad(struct drm_device *dev, unsigned long flags)
@@ -145,7 +162,7 @@ PVRSRVDrmLoad(struct drm_device *dev, unsigned long flags)
goto exit;
}
#endif
-
+ /* Module initialisation */
iRes = PVRCore_Init();
if (iRes != 0)
{
@@ -268,7 +285,10 @@ PVRSRVDrmRelease(struct inode *inode, struct file *filp)
if (ret != 0)
{
-
+ /*
+ * An error means drm_release didn't call drm_lastclose,
+ * but it will have freed file_priv.
+ */
PVR_DPF((PVR_DBG_ERROR, "%s : drm_release failed: %d",
__FUNCTION__, ret));
}
@@ -352,13 +372,6 @@ PVRDRM_Display_ioctl(struct drm_device *dev, void *arg, struct drm_file *pFile)
#endif
#if !defined(SUPPORT_DRI_DRM_EXT)
-
-#if defined(DRM_IOCTL_DEF)
-#define PVR_DRM_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF(DRM_##ioctl, _func, _flags)
-#else
-#define PVR_DRM_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF_DRV(ioctl, _func, _flags)
-#endif
-
struct drm_ioctl_desc sPVRDrmIoctls[] = {
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35))
DRM_IOCTL_DEF(PVR_DRM_SRVKM_IOCTL, PVRSRV_BridgeDispatchKM, PVR_DRM_UNLOCKED),
@@ -403,7 +416,7 @@ static struct omap_drm_plugin plugin = {
.num_ioctls = ARRAY_SIZE(sPVRDrmIoctls),
.ioctl_base = 0, /* initialized when plugin is registered */
};
-#else
+#else /* defined(SUPPORT_DRI_DRM_EXTERNAL) */
static struct drm_driver sPVRDrmDriver =
{
#if defined(PVR_DRI_DRM_PLATFORM_DEV)
@@ -419,10 +432,8 @@ static struct drm_driver sPVRDrmDriver =
.suspend = PVRSRVDriverSuspend,
.resume = PVRSRVDriverResume,
#endif
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37))
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
-#endif
.ioctls = sPVRDrmIoctls,
.fops =
{
@@ -482,7 +493,7 @@ PVRSRVDrmRemove(struct platform_device *pDevice)
return 0;
}
-#endif
+#endif
static int __init PVRSRVDrmInit(void)
{
@@ -491,7 +502,7 @@ static int __init PVRSRVDrmInit(void)
#if !defined(SUPPORT_DRI_DRM_EXTERNAL)
sPVRDrmDriver.num_ioctls = pvr_max_ioctl;
#endif
-
+
PVRDPFInit();
#if defined(PVR_DRI_DRM_NOT_PCI)
@@ -533,9 +544,14 @@ static void __exit PVRSRVDrmExit(void)
#endif
}
+/*
+ * These macro calls define the initialisation and removal functions of the
+ * driver. Although they are prefixed `module_', they apply when compiling
+ * statically as well; in both cases they define the function the kernel will
+ * run to start/stop the driver.
+*/
module_init(PVRSRVDrmInit);
module_exit(PVRSRVDrmExit);
-#endif
-#endif
-
+#endif
+#endif
diff --git a/sgx/services4/srvkm/env/linux/pvr_drm.h b/sgx/services4/srvkm/env/linux/pvr_drm.h
index 9d79602..5418c6d 100644
--- a/sgx/services4/srvkm/env/linux/pvr_drm.h
+++ b/sgx/services4/srvkm/env/linux/pvr_drm.h
@@ -1,29 +1,45 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title PowerVR drm driver
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description drm module
+@License Dual MIT/GPLv2
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#if !defined(__PVR_DRM_H__)
#define __PVR_DRM_H__
@@ -57,6 +73,7 @@ int PVRSRV_BridgeDispatchKM(struct drm_device *dev, void *arg, struct drm_file *
#if defined(SUPPORT_DRI_DRM_EXT)
#define DRI_DRM_STATIC
+/*Exported functions to common drm layer*/
int PVRSRVDrmLoad(struct drm_device *dev, unsigned long flags);
int PVRSRVDrmUnload(struct drm_device *dev);
int PVRSRVDrmOpen(struct drm_device *dev, struct drm_file *file);
@@ -70,7 +87,7 @@ int PVRDRMUnprivCmd(struct drm_device *dev, IMG_VOID *arg, struct drm_file *pFil
int PVRDRM_Dummy_ioctl(struct drm_device *dev, IMG_VOID *arg, struct drm_file *pFile);
#else
#define DRI_DRM_STATIC static
-#endif
+#endif /* defined(SUPPORT_DRI_DRM_EXT) */
#if defined(DISPLAY_CONTROLLER)
extern int PVR_DRM_MAKENAME(DISPLAY_CONTROLLER, _Init)(struct drm_device *);
@@ -102,6 +119,7 @@ IMG_INT dbgdrv_ioctl(struct drm_device *dev, IMG_VOID *arg, struct drm_file *pFi
#define DRM_IOCTL_PVR_UNPRIV DRM_IO(DRM_COMMAND_BASE + DRM_PVR_UNPRIV)
#define DRM_IOCTL_PVR_DBGDRV DRM_IO(DRM_COMMAND_BASE + DRM_PVR_DBGDRV)
#endif
+
#endif
#endif
diff --git a/sgx/services4/srvkm/env/linux/pvr_uaccess.h b/sgx/services4/srvkm/env/linux/pvr_uaccess.h
index 6e7f1d3..31c218b 100644
--- a/sgx/services4/srvkm/env/linux/pvr_uaccess.h
+++ b/sgx/services4/srvkm/env/linux/pvr_uaccess.h
@@ -1,29 +1,44 @@
-/**********************************************************************
- *
- * Copyright (C) Imagination Technologies Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful but, except
- * as otherwise stated in writing, without any warranty; without even the
- * implied warranty of merchantability or fitness for a particular purpose.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * Imagination Technologies Ltd. <gpl-support@imgtec.com>
- * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Utility functions for user space access
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/ /**************************************************************************/
#ifndef __PVR_UACCESS_H__
#define __PVR_UACCESS_H__
@@ -53,7 +68,10 @@ static inline unsigned long pvr_copy_to_user(void __user *pvTo, const void *pvFr
static inline unsigned long pvr_copy_from_user(void *pvTo, const void __user *pvFrom, unsigned long ulBytes)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33))
-
+ /*
+ * The compile time correctness checking introduced for copy_from_user in
+ * Linux 2.6.33 isn't fully comaptible with our usage of the function.
+ */
if (access_ok(VERIFY_READ, pvFrom, ulBytes))
{
return __copy_from_user(pvTo, pvFrom, ulBytes);
@@ -67,5 +85,5 @@ static inline unsigned long pvr_copy_from_user(void *pvTo, const void __user *pv
#define pvr_put_user put_user
#define pvr_get_user get_user
-#endif
+#endif /* __PVR_UACCESS_H__ */