summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/nvreftrack
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2009-12-11 15:30:30 -0800
committerGary King <gking@nvidia.com>2009-12-11 15:30:30 -0800
commit2b33969303fcceb83afb460c40c5bbaeb717a7cd (patch)
treecb185610f53295bd79bdfb6372531af5cf0f125f /arch/arm/mach-tegra/nvreftrack
parent3e2b5f7d7557b44e8abd68accb24099478d8245e (diff)
tegra: add NvRefTrack
brings over NvRefTrack implementation from Perforce
Diffstat (limited to 'arch/arm/mach-tegra/nvreftrack')
-rw-r--r--arch/arm/mach-tegra/nvreftrack/Makefile10
-rw-r--r--arch/arm/mach-tegra/nvreftrack/nvreftrack.c631
2 files changed, 641 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/nvreftrack/Makefile b/arch/arm/mach-tegra/nvreftrack/Makefile
new file mode 100644
index 000000000000..bc282172bad0
--- /dev/null
+++ b/arch/arm/mach-tegra/nvreftrack/Makefile
@@ -0,0 +1,10 @@
+ccflags-y += -DNV_IS_AVP=0
+ccflags-y += -DNV_OAL=0
+ccflags-y += -DNV_USE_FUSE_CLOCK_ENABLE=0
+ifeq ($(CONFIG_MACH_TEGRA_GENERIC_DEBUG),y)
+ccflags-y += -DNV_DEBUG=1
+else
+ccflags-y += -DNV_DEBUG=0
+endif
+
+obj-y += nvreftrack.o
diff --git a/arch/arm/mach-tegra/nvreftrack/nvreftrack.c b/arch/arm/mach-tegra/nvreftrack/nvreftrack.c
new file mode 100644
index 000000000000..961a75d8b465
--- /dev/null
+++ b/arch/arm/mach-tegra/nvreftrack/nvreftrack.c
@@ -0,0 +1,631 @@
+/*
+ * Copyright (c) 2009 NVIDIA Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NVIDIA Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "nvreftrack.h"
+#include "nvos.h"
+#include "nvassert.h"
+
+#define NVRT_MAX_PACKAGES 8
+#define NVRT_MAX_OBJ_TYPES_PER_PACKAGE 8
+#define NVRT_CLIENT_SIZE_INCR 16
+#define NVRT_OBJ_SIZE_INCR 128
+
+typedef struct
+{
+ // linked list next ptr (live and free objects)
+ NvU32 NextObj;
+ // the opaque ptr identifier of the object
+ void* Ptr;
+} NvRtObj;
+
+typedef struct
+{
+ union
+ {
+ // linked list next ptr for free list, -1 == none
+ NvU32 NextFree;
+ // in use client refcount, -1 == cleaning up
+ NvS32 RefCount;
+ } State;
+
+ void* UserData;
+
+ // lists of objects per obj type. array size can't
+ // be determined compile time so this is not declared
+ //NvU32 Objs[];
+} NvRtClient;
+
+typedef struct NvRtRec
+{
+ NvOsMutexHandle Mutex;
+
+ NvU32 NumPackages;
+ NvU32 MaxTypesPerPkg;
+ NvU32* ObjTypeIdxLUT;
+ NvU32 NumObjTypes;
+
+ NvU8* ClientArr;
+ NvU32 ClientArrSize;
+ NvU32 FreeClientList;
+
+ NvRtObj* ObjArr;
+ NvU32 ObjArrSize;
+ NvU32 FreeObjList;
+} NvRt;
+
+static NV_INLINE NvU32
+NvRtClientSize(NvRt* Rt)
+{
+ return sizeof(NvRtClient) + Rt->NumObjTypes*sizeof(NvU32);
+}
+
+static NV_INLINE NvRtClient*
+GetClient(NvRt* Rt, NvU32 Idx)
+{
+ void* ptr = (void*)(Rt->ClientArr + Idx*NvRtClientSize(Rt));
+ return (NvRtClient*)ptr;
+}
+
+static NV_INLINE NvU32
+GetObjTypeIdx(NvRt* Rt, NvU32 Package, NvU32 Type)
+{
+ NvU32 LutIdx = Package*Rt->MaxTypesPerPkg + Type;
+ NvU32 Idx;
+
+ Idx = Rt->ObjTypeIdxLUT[LutIdx];
+ NV_ASSERT(Idx != (NvU32)-1);
+
+ return Idx;
+}
+
+static NV_INLINE NvU32*
+GetObjListHead(NvRt* Rt, NvU32 ClientIdx, NvU32 ObjIdx)
+{
+ NvRtClient* Client = GetClient(Rt, ClientIdx);
+ NvU32* Objs = (NvU32*)(Client + 1);
+ return Objs + ObjIdx;
+}
+
+// Temporary wrapper for realloc as the linux kernel nvos doesn't
+// implement NvOsRealloc
+static NV_INLINE void*
+NvRtRealloc(void* old, size_t size, size_t oldsize)
+{
+#if NVOS_IS_LINUX_KERNEL
+ void* ret;
+
+ if (!size)
+ {
+ if (old) NvOsFree(old);
+ return NULL;
+ }
+
+ ret = NvOsAlloc(size);
+
+ if (ret && old)
+ {
+ NV_ASSERT(oldsize > 0);
+
+ NvOsMemcpy(ret, old, NV_MIN(size, oldsize));
+ NvOsFree(old);
+ }
+
+ return ret;
+#else
+ return NvOsRealloc(old, size);
+#endif
+}
+
+NvError NvRtCreate(
+ NvU32 NumPackages,
+ const NvU32* NumObjTypesPerPackage,
+ NvRtHandle* RtOut)
+{
+ NvRtHandle Ctx;
+ NvU32 i;
+
+ if (NumPackages == 0)
+ {
+ NV_ASSERT(!"Zero packages is not allowed");
+ return NvError_BadParameter;
+ }
+
+ if (NumPackages > NVRT_MAX_PACKAGES)
+ {
+ NV_ASSERT(!"NumPackages exceeds NVRT_MAX_PACKAGES");
+ return NvError_BadParameter;
+ }
+
+ Ctx = NvOsAlloc(sizeof(NvRt));
+ if (!Ctx) return NvError_InsufficientMemory;
+ NvOsMemset(Ctx, 0, sizeof(NvRt));
+
+ Ctx->FreeClientList = -1;
+ Ctx->FreeObjList = -1;
+ Ctx->NumPackages = NumPackages;
+
+ for (i = 0; i < NumPackages; i++)
+ {
+ if (NumObjTypesPerPackage[i] >
+ NVRT_MAX_OBJ_TYPES_PER_PACKAGE)
+ {
+ NV_ASSERT(!"Too many object types");
+ NvOsFree(Ctx);
+ return NvError_BadParameter;
+ }
+
+ Ctx->NumObjTypes += NumObjTypesPerPackage[i];
+
+ if (NumObjTypesPerPackage[i] > Ctx->MaxTypesPerPkg)
+ Ctx->MaxTypesPerPkg = NumObjTypesPerPackage[i];
+ }
+
+ if (Ctx->MaxTypesPerPkg)
+ {
+ NvU32 idx = 0;
+
+ Ctx->ObjTypeIdxLUT = NvOsAlloc(sizeof(NvU32)*Ctx->MaxTypesPerPkg*NumPackages);
+ if (!Ctx->ObjTypeIdxLUT)
+ {
+ NvOsFree(Ctx);
+ return NvError_InsufficientMemory;
+ }
+
+ for (i = 0; i < NumPackages; i++)
+ {
+ NvU32 start = i*Ctx->MaxTypesPerPkg;
+ NvU32 j = 0;
+
+ for (; j < NumObjTypesPerPackage[i]; j++)
+ {
+ Ctx->ObjTypeIdxLUT[start+j] = idx++;
+ }
+ for (; j < Ctx->MaxTypesPerPkg; j++)
+ {
+ Ctx->ObjTypeIdxLUT[start+j] = (NvU32)-1;
+ }
+ }
+ }
+
+ if (NvOsMutexCreate(&Ctx->Mutex) != NvSuccess)
+ {
+ NvOsFree(Ctx->ObjTypeIdxLUT);
+ NvOsFree(Ctx);
+ return NvError_InsufficientMemory;
+ }
+
+ *RtOut = Ctx;
+ return NvSuccess;
+}
+
+void NvRtDestroy(NvRtHandle Rt)
+{
+ NvOsMutexDestroy(Rt->Mutex);
+ NvOsFree(Rt->ObjTypeIdxLUT);
+ NvOsFree(Rt);
+}
+
+NvError NvRtRegisterClient(
+ NvRtHandle Rt,
+ NvRtClientHandle* ClientOut)
+{
+ NvOsMutexLock(Rt->Mutex);
+
+ // Allocate new clients if necessary
+
+ if (Rt->FreeClientList == -1)
+ {
+ NvU8* NewArr;
+ NvU32 NewSize;
+ NvU32 i;
+
+ // Grow array by increment
+
+ NewSize = Rt->ClientArrSize + NVRT_CLIENT_SIZE_INCR;
+ NewArr = NvRtRealloc(Rt->ClientArr,
+ NvRtClientSize(Rt)*NewSize,
+ NvRtClientSize(Rt)*Rt->ClientArrSize);
+ if (NewArr == NULL)
+ {
+ NvOsMutexUnlock(Rt->Mutex);
+ return NvError_InsufficientMemory;
+ }
+ Rt->ClientArr = NewArr;
+
+ // Initialize new clients and create free list
+
+ for (i = Rt->ClientArrSize; i < NewSize; i++)
+ {
+ NvRtClient* c = GetClient(Rt, i);
+ NvU32* objs = (NvU32*)(c+1);
+ NvU32 j;
+
+ c->State.NextFree = (i == NewSize-1) ? -1 : i+1;
+
+ for (j = 0; j < Rt->NumObjTypes; j++)
+ objs[j] = -1;
+ }
+
+ Rt->FreeClientList = Rt->ClientArrSize;
+ Rt->ClientArrSize = NewSize;
+ }
+
+ NV_ASSERT(Rt->FreeClientList != -1);
+
+ {
+ NvU32 ClientIdx = Rt->FreeClientList;
+ NvRtClient* Client = GetClient(Rt, ClientIdx);
+
+ Rt->FreeClientList = Client->State.NextFree;
+
+ NvOsMutexUnlock(Rt->Mutex);
+
+ // Initialize client
+
+ Client->State.RefCount = 1;
+ Client->UserData = NULL;
+
+ *ClientOut = ClientIdx + 1;
+ }
+
+ return NvSuccess;
+}
+
+NvError NvRtAddClientRef(
+ NvRtHandle Rt,
+ NvRtClientHandle ClientHandle)
+{
+ NvRtClient* Client;
+ NvU32 ClientIdx = ClientHandle - 1;
+ NvError Ret = NvSuccess;
+
+ NV_ASSERT(ClientHandle != 0);
+ NV_ASSERT(ClientHandle <= Rt->ClientArrSize);
+
+ NvOsMutexLock(Rt->Mutex);
+
+ Client = GetClient(Rt, ClientIdx);
+
+ if (Client->State.RefCount < 1)
+ Ret = NvError_InvalidState;
+ else
+ Client->State.RefCount++;
+
+ NvOsMutexUnlock(Rt->Mutex);
+
+ return Ret;
+}
+
+NvBool NvRtUnregisterClient(
+ NvRtHandle Rt,
+ NvRtClientHandle ClientHandle)
+{
+ NvRtClient* Client;
+ NvU32 ClientIdx = ClientHandle - 1;
+ NvU32* Objs;
+ NvU32 i;
+
+ NV_ASSERT(ClientHandle != 0);
+ NV_ASSERT(ClientHandle <= Rt->ClientArrSize);
+
+ NvOsMutexLock(Rt->Mutex);
+
+ Client = GetClient(Rt, ClientIdx);
+ Client->State.RefCount--;
+
+ if (Client->State.RefCount >= 0)
+ {
+ NvBool DoClean = (Client->State.RefCount == 0);
+ NvOsMutexUnlock(Rt->Mutex);
+ return DoClean;
+ }
+
+ Objs = (NvU32*)(Client+1);
+
+ // Check that object references are free'd
+
+ for (i = Rt->NumObjTypes; i != 0; i--)
+ {
+ NvU32 Idx = i - 1;
+ NvU32 Cur = Objs[Idx];
+
+ // The caller should free all object referenced before
+ // unregistering. Assert that this is so.
+
+ NV_ASSERT(Cur == -1 || !"Leaked object reference");
+
+ // In release builds free at least our state for the leaked
+ // objects. There's nothing we can do about the leaked objects.
+
+ while (Cur != -1)
+ {
+ NvRtObj* Obj = &Rt->ObjArr[Cur];
+ NvU32 Next = Obj->NextObj;
+
+ Obj->NextObj = Rt->FreeObjList;
+ Rt->FreeObjList = Cur;
+ Cur = Next;
+ }
+
+ Objs[Idx] = -1;
+ }
+
+ // Release client
+
+ Client->State.NextFree = Rt->FreeClientList;
+ Rt->FreeClientList = ClientIdx;
+
+ NvOsMutexUnlock(Rt->Mutex);
+
+ return NV_FALSE;
+}
+
+void NvRtSetClientUserData(
+ NvRtHandle Rt,
+ NvRtClientHandle ClientHandle,
+ void* UserData)
+{
+ NvRtClient* Client;
+ NvU32 ClientIdx = ClientHandle - 1;
+
+ NV_ASSERT(ClientHandle != 0);
+ NV_ASSERT(ClientHandle <= Rt->ClientArrSize);
+
+ NvOsMutexLock(Rt->Mutex);
+
+ Client = GetClient(Rt, ClientIdx);
+ Client->UserData = UserData;
+
+ NvOsMutexUnlock(Rt->Mutex);
+}
+
+void* NvRtGetClientUserData(
+ NvRtHandle Rt,
+ NvRtClientHandle ClientHandle)
+{
+ NvRtClient* Client;
+ NvU32 ClientIdx = ClientHandle - 1;
+ void* UserData;
+
+ NV_ASSERT(ClientHandle != 0);
+ NV_ASSERT(ClientHandle <= Rt->ClientArrSize);
+
+ NvOsMutexLock(Rt->Mutex);
+
+ Client = GetClient(Rt, ClientIdx);
+ UserData = Client->UserData;
+
+ NvOsMutexUnlock(Rt->Mutex);
+
+ return UserData;
+}
+
+NvError NvRtAllocObjRef(
+ const NvDispatchCtx* Ctx,
+ NvRtObjRefHandle* Out)
+{
+ NvRt* Rt = Ctx->Rt;
+ NvU32 ObjIdx;
+ NvRtObj* Obj;
+
+ NvOsMutexLock(Rt->Mutex);
+
+ // Allocate new space if necessary
+
+ if (Rt->FreeObjList == -1)
+ {
+ NvRtObj* NewArr;
+ NvRtObj* Cur;
+ NvU32 NewSize;
+ NvU32 i;
+
+ // Grow array by increment
+
+ NewSize = Rt->ObjArrSize + NVRT_OBJ_SIZE_INCR;
+ NewArr = NvRtRealloc(Rt->ObjArr,
+ sizeof(NvRtObj)*NewSize,
+ sizeof(NvRtObj)*Rt->ObjArrSize);
+ if (NewArr == NULL)
+ {
+ NvOsMutexUnlock(Rt->Mutex);
+ return NvError_InsufficientMemory;
+ }
+
+ // Create free list
+
+ Cur = NewArr + Rt->ObjArrSize;
+ for (i = Rt->ObjArrSize + 1; i < NewSize; i++)
+ {
+ Cur->NextObj = i;
+ Cur++;
+ }
+ Cur->NextObj = -1;
+
+ // Store new values
+
+ Rt->ObjArr = NewArr;
+ Rt->FreeObjList = Rt->ObjArrSize;
+ Rt->ObjArrSize = NewSize;
+ }
+
+ NV_ASSERT(Rt->FreeObjList != -1);
+
+ ObjIdx = Rt->FreeObjList;
+ Obj = &Rt->ObjArr[ObjIdx];
+ Rt->FreeObjList = Obj->NextObj;
+
+ Obj->NextObj = -1;
+ Obj->Ptr = NULL;
+
+ NvOsMutexUnlock(Rt->Mutex);
+
+ *Out = ObjIdx + 1;
+ return NvSuccess;
+}
+
+void NvRtDiscardObjRef(
+ const NvDispatchCtx* Ctx,
+ NvRtObjRefHandle ObjRef)
+{
+ NvRt* Rt = Ctx->Rt;
+ NvRtObj* Obj;
+
+ if (!ObjRef--) return;
+
+ NvOsMutexLock(Rt->Mutex);
+
+ Obj = &Rt->ObjArr[ObjRef];
+
+ NV_ASSERT(Obj->NextObj == -1);
+ NV_ASSERT(Obj->Ptr == NULL);
+
+ Obj->NextObj = Rt->FreeObjList;
+ Rt->FreeObjList = ObjRef;
+
+ NvOsMutexUnlock(Rt->Mutex);
+}
+
+void NvRtStoreObjRef(
+ const NvDispatchCtx* Ctx,
+ NvRtObjRefHandle ObjRef,
+ NvU32 ObjType,
+ void* ObjPtr)
+{
+ NvRt* Rt = Ctx->Rt;
+ NvU32 ClientIdx = Ctx->Client - 1;
+ NvU32 ObjTypeIdx = GetObjTypeIdx(Rt, Ctx->PackageIdx, ObjType);
+ NvRtObj* Obj;
+ NvU32* List;
+
+ NV_ASSERT(ClientIdx < Rt->ClientArrSize);
+
+ if (ObjPtr == NULL)
+ {
+ NV_ASSERT(!"Bad object ptr");
+ return;
+ }
+
+ if (!ObjRef--)
+ {
+ NV_ASSERT(!"Bad object ref handle");
+ return;
+ }
+
+ NvOsMutexLock(Rt->Mutex);
+
+ Obj = &Rt->ObjArr[ObjRef];
+
+ NV_ASSERT(Obj->NextObj == -1);
+ NV_ASSERT(Obj->Ptr == NULL);
+
+ List = GetObjListHead(Rt, ClientIdx, ObjTypeIdx);
+
+ Obj->NextObj = *List;
+ Obj->Ptr = ObjPtr;
+
+ *List = ObjRef;
+
+ NvOsMutexUnlock(Rt->Mutex);
+}
+
+void* NvRtFreeObjRef(
+ const NvDispatchCtx* Ctx,
+ NvU32 ObjType,
+ void* ObjPtr)
+{
+ NvRt* Rt = Ctx->Rt;
+ NvU32 ClientIdx = Ctx->Client - 1;
+ NvU32 ObjTypeIdx = GetObjTypeIdx(Rt, Ctx->PackageIdx, ObjType);
+ NvU32 PrevIdx;
+ NvU32 CurIdx;
+ NvU32* List;
+ void* RetVal = NULL;
+
+ NV_ASSERT(ClientIdx < Rt->ClientArrSize);
+
+ NvOsMutexLock(Rt->Mutex);
+
+ List = GetObjListHead(Rt, ClientIdx, ObjTypeIdx);
+ CurIdx = *List;
+ PrevIdx = -1;
+
+ // If user requested to find a specific object look it up
+
+ if (ObjPtr != NULL)
+ {
+ while (CurIdx != -1)
+ {
+ NvRtObj* Obj = &Rt->ObjArr[CurIdx];
+
+ if (Obj->Ptr == ObjPtr) break;
+
+ PrevIdx = CurIdx;
+ CurIdx = Obj->NextObj;
+ }
+
+ // User should not ask to free non-existent objects
+
+ if (CurIdx == -1)
+ {
+ NV_ASSERT(!"Trying to free non-existent object reference");
+ NvOsMutexUnlock(Rt->Mutex);
+ return NULL;
+ }
+ }
+
+ // If we have an object, free it
+
+ if (CurIdx != -1)
+ {
+ NvRtObj* Obj = &Rt->ObjArr[CurIdx];
+
+ RetVal = Obj->Ptr;
+
+ if (PrevIdx == -1)
+ {
+ *List = Obj->NextObj;
+ }
+ else
+ {
+ NvRtObj* PrevObj = &Rt->ObjArr[PrevIdx];
+ PrevObj->NextObj = Obj->NextObj;
+ }
+
+ Obj->Ptr = NULL;
+ Obj->NextObj = Rt->FreeObjList;
+ Rt->FreeObjList = CurIdx;
+ }
+
+ NvOsMutexUnlock(Rt->Mutex);
+
+ return RetVal;
+}