aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/pvr/perproc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/pvr/perproc.c')
-rw-r--r--drivers/gpu/pvr/perproc.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/perproc.c b/drivers/gpu/pvr/perproc.c
new file mode 100644
index 00000000000..d0d4f4cc806
--- /dev/null
+++ b/drivers/gpu/pvr/perproc.c
@@ -0,0 +1,266 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 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
+ *
+ ******************************************************************************/
+
+#include "services_headers.h"
+#include "resman.h"
+#include "handle.h"
+#include "perproc.h"
+#include "osperproc.h"
+
+#define HASH_TAB_INIT_SIZE 32
+
+static struct HASH_TABLE *psHashTab;
+
+static enum PVRSRV_ERROR FreePerProcessData(
+ struct PVRSRV_PER_PROCESS_DATA *psPerProc)
+{
+ enum PVRSRV_ERROR eError;
+ u32 uiPerProc;
+
+ PVR_ASSERT(psPerProc != NULL);
+
+ if (psPerProc == NULL) {
+ PVR_DPF(PVR_DBG_ERROR,
+ "FreePerProcessData: invalid parameter");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ uiPerProc = HASH_Remove(psHashTab, (u32)psPerProc->ui32PID);
+ if (uiPerProc == 0) {
+ PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
+ "Couldn't find process in per-process data hash table");
+
+ PVR_ASSERT(psPerProc->ui32PID == 0);
+ } else {
+ PVR_ASSERT((struct PVRSRV_PER_PROCESS_DATA *)
+ uiPerProc == psPerProc);
+ PVR_ASSERT(((struct PVRSRV_PER_PROCESS_DATA *)uiPerProc)->
+ ui32PID == psPerProc->ui32PID);
+ }
+
+ if (psPerProc->psHandleBase != NULL) {
+ eError = PVRSRVFreeHandleBase(psPerProc->psHandleBase);
+ if (eError != PVRSRV_OK) {
+ PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
+ "Couldn't free handle base for process (%d)",
+ eError);
+ return eError;
+ }
+ }
+
+ if (psPerProc->hPerProcData != NULL) {
+ eError =
+ PVRSRVReleaseHandle(KERNEL_HANDLE_BASE,
+ psPerProc->hPerProcData,
+ PVRSRV_HANDLE_TYPE_PERPROC_DATA);
+
+ if (eError != PVRSRV_OK) {
+ PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
+ "Couldn't release per-process data handle (%d)",
+ eError);
+ return eError;
+ }
+ }
+
+ eError = OSPerProcessPrivateDataDeInit(psPerProc->hOsPrivateData);
+ if (eError != PVRSRV_OK) {
+ PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
+ "OSPerProcessPrivateDataDeInit failed (%d)",
+ eError);
+ return eError;
+ }
+
+ OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), psPerProc,
+ psPerProc->hBlockAlloc);
+
+ return PVRSRV_OK;
+}
+
+struct PVRSRV_PER_PROCESS_DATA *PVRSRVPerProcessData(u32 ui32PID)
+{
+ struct PVRSRV_PER_PROCESS_DATA *psPerProc;
+
+ PVR_ASSERT(psHashTab != NULL);
+
+ psPerProc =
+ (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab,
+ (u32) ui32PID);
+ return psPerProc;
+}
+
+enum PVRSRV_ERROR PVRSRVPerProcessDataConnect(u32 ui32PID)
+{
+ struct PVRSRV_PER_PROCESS_DATA *psPerProc;
+ void *hBlockAlloc;
+ enum PVRSRV_ERROR eError = PVRSRV_OK;
+
+ PVR_ASSERT(psHashTab != NULL);
+
+ psPerProc = (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab,
+ (u32)ui32PID);
+ if (psPerProc == NULL) {
+ eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+ sizeof(*psPerProc), (void **)&psPerProc,
+ &hBlockAlloc);
+ if (eError != PVRSRV_OK) {
+ PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
+ "Couldn't allocate per-process data (%d)",
+ eError);
+ return eError;
+ }
+ OSMemSet(psPerProc, 0, sizeof(*psPerProc));
+ psPerProc->hBlockAlloc = hBlockAlloc;
+
+ if (!HASH_Insert(psHashTab, (u32) ui32PID, (u32)psPerProc)) {
+ PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
+ "Couldn't insert per-process data into hash table");
+ eError = PVRSRV_ERROR_GENERIC;
+ goto failure;
+ }
+
+ psPerProc->ui32PID = ui32PID;
+ psPerProc->ui32RefCount = 0;
+
+ eError =
+ OSPerProcessPrivateDataInit(&psPerProc->hOsPrivateData);
+ if (eError != PVRSRV_OK) {
+ PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
+ "OSPerProcessPrivateDataInit failed (%d)",
+ eError);
+ goto failure;
+ }
+
+ eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE,
+ &psPerProc->hPerProcData,
+ psPerProc,
+ PVRSRV_HANDLE_TYPE_PERPROC_DATA,
+ PVRSRV_HANDLE_ALLOC_FLAG_NONE);
+ if (eError != PVRSRV_OK) {
+ PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
+ "Couldn't allocate handle for per-process data (%d)",
+ eError);
+ goto failure;
+ }
+
+ eError = PVRSRVAllocHandleBase(&psPerProc->psHandleBase);
+ if (eError != PVRSRV_OK) {
+ PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
+ "Couldn't allocate handle base for process (%d)",
+ eError);
+ goto failure;
+ }
+
+ eError = OSPerProcessSetHandleOptions(psPerProc->psHandleBase);
+ if (eError != PVRSRV_OK) {
+ PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
+ "Couldn't set handle options (%d)",
+ eError);
+ goto failure;
+ }
+
+ eError =
+ PVRSRVResManConnect(psPerProc, &psPerProc->hResManContext);
+ if (eError != PVRSRV_OK) {
+ PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
+ "Couldn't register with the resource manager");
+ goto failure;
+ }
+ }
+
+ psPerProc->ui32RefCount++;
+ PVR_DPF(PVR_DBG_MESSAGE,
+ "PVRSRVPerProcessDataConnect: Process 0x%x has ref-count %d",
+ ui32PID, psPerProc->ui32RefCount);
+
+ return eError;
+
+failure:
+ (void)FreePerProcessData(psPerProc);
+ return eError;
+}
+
+void PVRSRVPerProcessDataDisconnect(u32 ui32PID)
+{
+ enum PVRSRV_ERROR eError;
+ struct PVRSRV_PER_PROCESS_DATA *psPerProc;
+
+ PVR_ASSERT(psHashTab != NULL);
+
+ psPerProc = (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab,
+ (u32)ui32PID);
+ if (psPerProc == NULL) {
+ PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataDealloc: "
+ "Couldn't locate per-process data for PID %u",
+ ui32PID);
+ } else {
+ psPerProc->ui32RefCount--;
+ if (psPerProc->ui32RefCount == 0) {
+ PVR_DPF(PVR_DBG_MESSAGE,
+ "PVRSRVPerProcessDataDisconnect: "
+ "Last close from process 0x%x received",
+ ui32PID);
+
+ PVRSRVResManDisconnect(psPerProc->hResManContext,
+ IMG_FALSE);
+
+ eError = FreePerProcessData(psPerProc);
+ if (eError != PVRSRV_OK)
+ PVR_DPF(PVR_DBG_ERROR,
+ "PVRSRVPerProcessDataDisconnect: "
+ "Error freeing per-process data");
+ }
+ }
+
+ eError = PVRSRVPurgeHandles(KERNEL_HANDLE_BASE);
+ if (eError != PVRSRV_OK)
+ PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataDisconnect: "
+ "Purge of global handle pool failed (%d)",
+ eError);
+}
+
+enum PVRSRV_ERROR PVRSRVPerProcessDataInit(void)
+{
+ PVR_ASSERT(psHashTab == NULL);
+
+ psHashTab = HASH_Create(HASH_TAB_INIT_SIZE);
+ if (psHashTab == NULL) {
+ PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataInit: "
+ "Couldn't create per-process data hash table");
+ return PVRSRV_ERROR_GENERIC;
+ }
+
+ return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVPerProcessDataDeInit(void)
+{
+ if (psHashTab != NULL) {
+ HASH_Delete(psHashTab);
+ psHashTab = NULL;
+ }
+
+ return PVRSRV_OK;
+}