aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorAlistair Strachan <alistair.strachan@imgtec.com>2012-06-14 10:08:18 +0100
committerAndroid Partner Code Review <android-gerrit-partner@google.com>2012-06-14 21:36:42 -0700
commitca5c535e1e9cae41831adae5a29a76f848f7f792 (patch)
treece4884871e95ef05346a5b91c4037cfb2fcf84bb /drivers/gpu
parentfb49c21c25ded40a7616268d0be84422ceb0f709 (diff)
downloadkernel_samsung_crespo-ca5c535e1e9cae41831adae5a29a76f848f7f792.zip
kernel_samsung_crespo-ca5c535e1e9cae41831adae5a29a76f848f7f792.tar.gz
kernel_samsung_crespo-ca5c535e1e9cae41831adae5a29a76f848f7f792.tar.bz2
gpu: pvr: Add thread safety checks to SGX MMU code.
The SGX MMU code was not designed to be used from multiple driver threads. One theory is that somehow the driver does sometimes use the MMU code from multiple threads, which could cause corruption of meta data. We must allow PID 1 through because the kernel uses this ID before userspace is up, and the module_init code interacts with the MMU subsystem. Otherwise, check that the outer bridge lock is held. If it is held, check the PID of the caller matches the PID holding the bridge lock. Change-Id: I35f42f251316b158576e5d853f8099e24942b4f2
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/pvr/mutex.c16
-rw-r--r--drivers/gpu/pvr/sgx/mmu.c93
2 files changed, 107 insertions, 2 deletions
diff --git a/drivers/gpu/pvr/mutex.c b/drivers/gpu/pvr/mutex.c
index 742fa03..aedc8d0 100644
--- a/drivers/gpu/pvr/mutex.c
+++ b/drivers/gpu/pvr/mutex.c
@@ -37,10 +37,13 @@
#include <services.h>
#include "mutex.h"
-
+#include "osfunc.h"
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
+extern PVRSRV_LINUX_MUTEX gPVRSRVLock;
+IMG_UINT32 ui32BridgeLockPID = 0;
+
IMG_VOID LinuxInitMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
{
mutex_init(psPVRSRVMutex);
@@ -49,6 +52,8 @@ IMG_VOID LinuxInitMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
IMG_VOID LinuxLockMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
{
mutex_lock(psPVRSRVMutex);
+ if(psPVRSRVMutex == &gPVRSRVLock)
+ ui32BridgeLockPID = OSGetCurrentProcessIDKM();
}
PVRSRV_ERROR LinuxLockMutexInterruptible(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
@@ -59,17 +64,24 @@ PVRSRV_ERROR LinuxLockMutexInterruptible(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
}
else
{
+ if(psPVRSRVMutex == &gPVRSRVLock)
+ ui32BridgeLockPID = OSGetCurrentProcessIDKM();
return PVRSRV_OK;
}
}
IMG_INT32 LinuxTryLockMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
{
- return mutex_trylock(psPVRSRVMutex);
+ IMG_UINT32 err = mutex_trylock(psPVRSRVMutex);
+ if(psPVRSRVMutex == &gPVRSRVLock)
+ ui32BridgeLockPID = OSGetCurrentProcessIDKM();
+ return err;
}
IMG_VOID LinuxUnLockMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex)
{
+ if(psPVRSRVMutex == &gPVRSRVLock)
+ ui32BridgeLockPID = 0;
mutex_unlock(psPVRSRVMutex);
}
diff --git a/drivers/gpu/pvr/sgx/mmu.c b/drivers/gpu/pvr/sgx/mmu.c
index 9d124f5..d4c7e0b 100644
--- a/drivers/gpu/pvr/sgx/mmu.c
+++ b/drivers/gpu/pvr/sgx/mmu.c
@@ -39,6 +39,8 @@
#include "sgx_bridge_km.h"
#include "pdump_osfunc.h"
+extern IMG_UINT32 ui32BridgeLockPID;
+
#define UINT32_MAX_VALUE 0xFFFFFFFFUL
#define SGX_MAX_PD_ENTRIES (1<<(SGX_FEATURE_ADDRESS_SPACE_SIZE - SGX_MMU_PT_SHIFT - SGX_MMU_PAGE_SHIFT))
@@ -733,6 +735,12 @@ _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOS
SysAcquireData(&psSysData);
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
ui32PDIndex = pMMUHeap->psDevArena->BaseDevVAddr.uiAddr >> pMMUHeap->ui32PDShift;
@@ -912,6 +920,13 @@ _DeferredFreePageTables (MMU_HEAP *pMMUHeap)
IMG_UINT32 *pui32Tmp;
IMG_UINT32 j;
#endif
+
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
#if defined(PDUMP)
PDUMPCOMMENT("Free PTs (MMU Context ID == %u, PDBaseIndex == %u, PT count == 0x%x)",
pMMUHeap->psMMUContext->ui32PDumpMMUContextID,
@@ -981,6 +996,12 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT
IMG_UINT32 ui32ModifiedCachelines[BRN31620_CACHE_FLUSH_INDEX_SIZE];
#endif
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
#if SGX_FEATURE_ADDRESS_SPACE_SIZE < 32
PVR_ASSERT(DevVAddr.uiAddr < (1<<SGX_FEATURE_ADDRESS_SPACE_SIZE));
@@ -1993,6 +2014,12 @@ MMU_Finalise (MMU_CONTEXT *psMMUContext)
MMU_CONTEXT *psMMUContextList = (MMU_CONTEXT*)psDevInfo->pvMMUContextList;
#endif
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
SysAcquireData(&psSysData);
#if defined(PDUMP)
@@ -2194,6 +2221,12 @@ MMU_InsertHeap(MMU_CONTEXT *psMMUContext, MMU_HEAP *psMMUHeap)
IMG_BOOL bInvalidateDirectoryCache = IMG_FALSE;
#endif
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
pui32PDCpuVAddr += psMMUHeap->psDevArena->BaseDevVAddr.uiAddr >> psMMUHeap->ui32PDShift;
pui32KernelPDCpuVAddr += psMMUHeap->psDevArena->BaseDevVAddr.uiAddr >> psMMUHeap->ui32PDShift;
@@ -2270,6 +2303,12 @@ MMU_UnmapPagesAndFreePTs (MMU_HEAP *psMMUHeap,
IMG_UINT32 *pui32Tmp;
IMG_BOOL bInvalidateDirectoryCache = IMG_FALSE;
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
#if !defined (PDUMP)
PVR_UNREFERENCED_PARAMETER(hUniqueTag);
#endif
@@ -2405,6 +2444,12 @@ MMU_Create (MMU_CONTEXT *psMMUContext,
PVR_UNREFERENCED_PARAMETER(ppsMMUAttrib);
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
PVR_ASSERT (psDevArena != IMG_NULL);
if (psDevArena == IMG_NULL)
@@ -2594,6 +2639,12 @@ ErrorFreeHeap:
IMG_VOID
MMU_Delete (MMU_HEAP *pMMUHeap)
{
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
if (pMMUHeap != IMG_NULL)
{
PVR_DPF ((PVR_DBG_MESSAGE, "MMU_Delete"));
@@ -2633,6 +2684,12 @@ MMU_Alloc (MMU_HEAP *pMMUHeap,
{
IMG_BOOL bStatus;
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
PVR_DPF ((PVR_DBG_MESSAGE,
"MMU_Alloc: uSize=0x%x, flags=0x%x, align=0x%x",
uSize, uFlags, uDevVAddrAlignment));
@@ -2698,6 +2755,12 @@ MMU_Free (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT32 ui32Size)
{
PVR_ASSERT (pMMUHeap != IMG_NULL);
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
if (pMMUHeap == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR, "MMU_Free: invalid parameter"));
@@ -2834,6 +2897,12 @@ MMU_MapPage (MMU_HEAP *pMMUHeap,
IMG_UINT32 ui32MMUFlags = 0;
MMU_PT_INFO **ppsPTInfoList;
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
PVR_ASSERT((DevPAddr.uiAddr & pMMUHeap->ui32DataPageMask) == 0);
@@ -2942,6 +3011,12 @@ MMU_MapScatter (MMU_HEAP *pMMUHeap,
IMG_UINT32 uCount, i;
IMG_DEV_PHYADDR DevPAddr;
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
PVR_ASSERT (pMMUHeap != IMG_NULL);
#if defined(PDUMP)
@@ -2991,6 +3066,12 @@ MMU_MapPages (MMU_HEAP *pMMUHeap,
IMG_UINT32 ui32VAdvance;
IMG_UINT32 ui32PAdvance;
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
PVR_ASSERT (pMMUHeap != IMG_NULL);
PVR_DPF ((PVR_DBG_MESSAGE, "MMU_MapPages: heap:%s, heap_id:%d devVAddr=%08X, SysPAddr=%08X, size=0x%x",
@@ -3058,6 +3139,12 @@ MMU_MapShadow (MMU_HEAP *pMMUHeap,
IMG_UINT32 ui32VAdvance;
IMG_UINT32 ui32PAdvance;
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
#if !defined (PDUMP)
PVR_UNREFERENCED_PARAMETER(hUniqueTag);
#endif
@@ -3147,6 +3234,12 @@ MMU_UnmapPages (MMU_HEAP *psMMUHeap,
IMG_UINT32 ui32PTIndex;
IMG_UINT32 *pui32Tmp;
+ if(OSGetCurrentProcessIDKM() != 1 && ui32BridgeLockPID != OSGetCurrentProcessIDKM())
+ {
+ PVR_DPF((PVR_DBG_ERROR, "ERROR!!: MMU code used by pid %u but bridge lock from pid %u", OSGetCurrentProcessIDKM(), ui32BridgeLockPID));
+ PVR_ASSERT(0);
+ }
+
#if !defined (PDUMP)
PVR_UNREFERENCED_PARAMETER(hUniqueTag);
#endif