Maemo patchset 20101501+0m5
[h-e-n] / drivers / gpu / pvr / pb.c
diff --git a/drivers/gpu/pvr/pb.c b/drivers/gpu/pvr/pb.c
new file mode 100644 (file)
index 0000000..1df3a39
--- /dev/null
@@ -0,0 +1,444 @@
+/**********************************************************************
+ *
+ * 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 <stddef.h>
+
+#include "services_headers.h"
+#include "sgxapi_km.h"
+#include "sgxinfo.h"
+#include "sgxinfokm.h"
+#include "pvr_bridge_km.h"
+#include "sgx_bridge_km.h"
+#include "pdump_km.h"
+
+
+static struct RESMAN_ITEM *psResItemCreateSharedPB;
+static struct PVRSRV_PER_PROCESS_DATA *psPerProcCreateSharedPB;
+
+static enum PVRSRV_ERROR SGXCleanupSharedPBDescCallback(void *pvParam,
+                                                  u32 ui32Param);
+static enum PVRSRV_ERROR SGXCleanupSharedPBDescCreateLockCallback(void *pvParam,
+                                                            u32 ui32Param);
+
+enum PVRSRV_ERROR SGXFindSharedPBDescKM(
+            struct PVRSRV_PER_PROCESS_DATA *psPerProc,
+            void *hDevCookie, IMG_BOOL bLockOnFailure,
+            u32 ui32TotalPBSize, void **phSharedPBDesc,
+            struct PVRSRV_KERNEL_MEM_INFO **ppsSharedPBDescKernelMemInfo,
+            struct PVRSRV_KERNEL_MEM_INFO **ppsHWPBDescKernelMemInfo,
+            struct PVRSRV_KERNEL_MEM_INFO **ppsBlockKernelMemInfo,
+            struct PVRSRV_KERNEL_MEM_INFO ***pppsSharedPBDescSubKernelMemInfos,
+            u32 *ui32SharedPBDescSubKernelMemInfosCount)
+{
+       struct PVRSRV_STUB_PBDESC *psStubPBDesc;
+       struct PVRSRV_KERNEL_MEM_INFO **ppsSharedPBDescSubKernelMemInfos = NULL;
+       struct PVRSRV_SGXDEV_INFO *psSGXDevInfo;
+       enum PVRSRV_ERROR eError = PVRSRV_ERROR_GENERIC;
+
+       psSGXDevInfo = ((struct PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice;
+
+       psStubPBDesc = psSGXDevInfo->psStubPBDescListKM;
+       if (psStubPBDesc != NULL) {
+               if (psStubPBDesc->ui32TotalPBSize != ui32TotalPBSize)
+                       PVR_DPF(PVR_DBG_WARNING, "SGXFindSharedPBDescKM: "
+                               "Shared PB requested with different size "
+                               "(0x%x) from existing shared PB (0x%x) - "
+                               "requested size ignored",
+                                ui32TotalPBSize,
+                                psStubPBDesc->ui32TotalPBSize);
+               {
+                       u32 i;
+                       struct RESMAN_ITEM *psResItem;
+
+                       if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
+                                      sizeof(struct PVRSRV_KERNEL_MEM_INFO *)*
+                                      psStubPBDesc->ui32SubKernelMemInfosCount,
+                                      (void **) &
+                                      ppsSharedPBDescSubKernelMemInfos,
+                                      NULL) != PVRSRV_OK) {
+                               PVR_DPF(PVR_DBG_ERROR, "SGXFindSharedPBDescKM:"
+                                               " OSAllocMem failed");
+                               eError = PVRSRV_ERROR_OUT_OF_MEMORY;
+                               goto ExitNotFound;
+                       }
+
+                       psResItem = ResManRegisterRes(psPerProc->hResManContext,
+                                             RESMAN_TYPE_SHARED_PB_DESC,
+                                             psStubPBDesc,
+                                             0,
+                                             &SGXCleanupSharedPBDescCallback);
+
+                       if (psResItem == NULL) {
+                               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                                 sizeof(struct PVRSRV_KERNEL_MEM_INFO *)*
+                                 psStubPBDesc->ui32SubKernelMemInfosCount,
+                                 ppsSharedPBDescSubKernelMemInfos, NULL);
+
+                               PVR_DPF(PVR_DBG_ERROR, "SGXFindSharedPBDescKM:"
+                                       " ResManRegisterRes failed");
+
+                               eError = PVRSRV_ERROR_GENERIC;
+                               goto ExitNotFound;
+                       }
+
+                       *ppsSharedPBDescKernelMemInfo =
+                           psStubPBDesc->psSharedPBDescKernelMemInfo;
+                       *ppsHWPBDescKernelMemInfo =
+                           psStubPBDesc->psHWPBDescKernelMemInfo;
+                       *ppsBlockKernelMemInfo =
+                           psStubPBDesc->psBlockKernelMemInfo;
+
+                       *ui32SharedPBDescSubKernelMemInfosCount =
+                           psStubPBDesc->ui32SubKernelMemInfosCount;
+
+                       *pppsSharedPBDescSubKernelMemInfos =
+                           ppsSharedPBDescSubKernelMemInfos;
+
+                       for (i = 0;
+                            i < psStubPBDesc->ui32SubKernelMemInfosCount;
+                            i++)
+                               ppsSharedPBDescSubKernelMemInfos[i] =
+                                   psStubPBDesc->ppsSubKernelMemInfos[i];
+
+                       psStubPBDesc->ui32RefCount++;
+                       *phSharedPBDesc = (void *) psResItem;
+                       return PVRSRV_OK;
+               }
+       }
+
+       eError = PVRSRV_OK;
+       if (bLockOnFailure) {
+               if (psResItemCreateSharedPB == NULL) {
+                       psResItemCreateSharedPB =
+                           ResManRegisterRes(psPerProc->hResManContext,
+                                    RESMAN_TYPE_SHARED_PB_DESC_CREATE_LOCK,
+                                    psPerProc, 0,
+                                    &SGXCleanupSharedPBDescCreateLockCallback);
+
+                       if (psResItemCreateSharedPB == NULL) {
+                               PVR_DPF(PVR_DBG_ERROR, "SGXFindSharedPBDescKM:"
+                                       " ResManRegisterRes failed");
+
+                               eError = PVRSRV_ERROR_GENERIC;
+                               goto ExitNotFound;
+                       }
+                       PVR_ASSERT(psPerProcCreateSharedPB == NULL);
+                       psPerProcCreateSharedPB = psPerProc;
+               } else {
+                       eError = PVRSRV_ERROR_PROCESSING_BLOCKED;
+               }
+       }
+ExitNotFound:
+       *phSharedPBDesc = NULL;
+
+       return eError;
+}
+
+static enum PVRSRV_ERROR
+SGXCleanupSharedPBDescKM(struct PVRSRV_STUB_PBDESC *psStubPBDescIn)
+{
+       struct PVRSRV_STUB_PBDESC **ppsStubPBDesc;
+       u32 i;
+       struct PVRSRV_SGXDEV_INFO *psSGXDevInfo;
+
+       psSGXDevInfo = (struct PVRSRV_SGXDEV_INFO *)
+               ((struct PVRSRV_DEVICE_NODE *)psStubPBDescIn->hDevCookie)->
+                                                               pvDevice;
+
+       for (ppsStubPBDesc = (struct PVRSRV_STUB_PBDESC **)
+                       &psSGXDevInfo->psStubPBDescListKM;
+            *ppsStubPBDesc != NULL;
+            ppsStubPBDesc = &(*ppsStubPBDesc)->psNext) {
+               struct PVRSRV_STUB_PBDESC *psStubPBDesc = *ppsStubPBDesc;
+
+               if (psStubPBDesc == psStubPBDescIn) {
+                       psStubPBDesc->ui32RefCount--;
+                       PVR_ASSERT((s32) psStubPBDesc->ui32RefCount >= 0);
+
+                       if (psStubPBDesc->ui32RefCount == 0) {
+                               struct PVRSRV_SGX_HOST_CTL *psSGXHostCtl =
+                                       (struct PVRSRV_SGX_HOST_CTL *)
+                                               psSGXDevInfo->psSGXHostCtl;
+#if defined(PDUMP)
+                               void *hUniqueTag = MAKEUNIQUETAG(
+                                      psSGXDevInfo->psKernelSGXHostCtlMemInfo);
+#endif
+                               psSGXHostCtl->sTAHWPBDesc.uiAddr = 0;
+                               psSGXHostCtl->s3DHWPBDesc.uiAddr = 0;
+
+                               PDUMPCOMMENT("TA/3D CCB Control - "
+                                            "Reset HW PBDesc records");
+                               PDUMPMEM(NULL,
+                                       psSGXDevInfo->psKernelSGXHostCtlMemInfo,
+                                       offsetof(struct PVRSRV_SGX_HOST_CTL,
+                                                       sTAHWPBDesc),
+                                       sizeof(struct IMG_DEV_VIRTADDR),
+                                       PDUMP_FLAGS_CONTINUOUS, hUniqueTag);
+                               PDUMPMEM(NULL,
+                                       psSGXDevInfo->psKernelSGXHostCtlMemInfo,
+                                       offsetof(struct PVRSRV_SGX_HOST_CTL,
+                                                       s3DHWPBDesc),
+                                       sizeof(struct IMG_DEV_VIRTADDR),
+                                       PDUMP_FLAGS_CONTINUOUS, hUniqueTag);
+
+                               *ppsStubPBDesc = psStubPBDesc->psNext;
+
+                               for (i = 0;
+                                  i < psStubPBDesc->ui32SubKernelMemInfosCount;
+                                  i++)
+                                       PVRSRVFreeDeviceMemKM(psStubPBDesc->
+                                                                  hDevCookie,
+                                        psStubPBDesc->ppsSubKernelMemInfos[i]);
+
+                               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                                       sizeof(struct PVRSRV_KERNEL_MEM_INFO *)*
+                                         psStubPBDesc->
+                                               ui32SubKernelMemInfosCount,
+                                         psStubPBDesc->ppsSubKernelMemInfos,
+                                         NULL);
+
+                               PVRSRVFreeSharedSysMemoryKM(psStubPBDesc->
+                                               psBlockKernelMemInfo);
+
+                               PVRSRVFreeDeviceMemKM(psStubPBDesc->hDevCookie,
+                                               psStubPBDesc->
+                                               psHWPBDescKernelMemInfo);
+
+                               PVRSRVFreeSharedSysMemoryKM(psStubPBDesc->
+                                               psSharedPBDescKernelMemInfo);
+
+                               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                                            sizeof(struct PVRSRV_STUB_PBDESC),
+                                            psStubPBDesc, NULL);
+
+                       }
+                       return PVRSRV_OK;
+               }
+       }
+
+       return PVRSRV_ERROR_INVALID_PARAMS;
+}
+
+static enum PVRSRV_ERROR SGXCleanupSharedPBDescCallback(void *pvParam,
+                                                       u32 ui32Param)
+{
+       struct PVRSRV_STUB_PBDESC *psStubPBDesc =
+                                       (struct PVRSRV_STUB_PBDESC *)pvParam;
+
+       PVR_UNREFERENCED_PARAMETER(ui32Param);
+
+       return SGXCleanupSharedPBDescKM(psStubPBDesc);
+}
+
+static enum PVRSRV_ERROR SGXCleanupSharedPBDescCreateLockCallback(void *pvParam,
+                                                            u32 ui32Param)
+{
+#ifdef DEBUG
+       struct PVRSRV_PER_PROCESS_DATA *psPerProc =
+           (struct PVRSRV_PER_PROCESS_DATA *)pvParam;
+#else
+       PVR_UNREFERENCED_PARAMETER(pvParam);
+#endif
+
+       PVR_UNREFERENCED_PARAMETER(ui32Param);
+
+       PVR_ASSERT(psPerProc == psPerProcCreateSharedPB);
+
+       psPerProcCreateSharedPB = NULL;
+       psResItemCreateSharedPB = NULL;
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR SGXUnrefSharedPBDescKM(void *hSharedPBDesc)
+{
+       PVR_ASSERT(hSharedPBDesc != NULL);
+
+       ResManFreeResByPtr(hSharedPBDesc);
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR SGXAddSharedPBDescKM(
+       struct PVRSRV_PER_PROCESS_DATA *psPerProc,
+       void *hDevCookie,
+       struct PVRSRV_KERNEL_MEM_INFO *psSharedPBDescKernelMemInfo,
+       struct PVRSRV_KERNEL_MEM_INFO *psHWPBDescKernelMemInfo,
+       struct PVRSRV_KERNEL_MEM_INFO *psBlockKernelMemInfo,
+       u32 ui32TotalPBSize, void **phSharedPBDesc,
+       struct PVRSRV_KERNEL_MEM_INFO **ppsSharedPBDescSubKernelMemInfos,
+       u32 ui32SharedPBDescSubKernelMemInfosCount)
+{
+       struct PVRSRV_STUB_PBDESC *psStubPBDesc = NULL;
+       enum PVRSRV_ERROR eRet = PVRSRV_ERROR_GENERIC;
+       u32 i;
+       struct PVRSRV_SGXDEV_INFO *psSGXDevInfo;
+       struct RESMAN_ITEM *psResItem;
+
+       if (psPerProcCreateSharedPB != psPerProc) {
+               goto NoAdd;
+       } else {
+               PVR_ASSERT(psResItemCreateSharedPB != NULL);
+
+               ResManFreeResByPtr(psResItemCreateSharedPB);
+
+               PVR_ASSERT(psResItemCreateSharedPB == NULL);
+               PVR_ASSERT(psPerProcCreateSharedPB == NULL);
+       }
+
+       psSGXDevInfo = (struct PVRSRV_SGXDEV_INFO *)
+               ((struct PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice;
+
+       psStubPBDesc = psSGXDevInfo->psStubPBDescListKM;
+       if (psStubPBDesc != NULL) {
+               if (psStubPBDesc->ui32TotalPBSize != ui32TotalPBSize)
+                       PVR_DPF(PVR_DBG_WARNING, "SGXAddSharedPBDescKM: "
+                               "Shared PB requested with different size "
+                               "(0x%x) from existing shared PB (0x%x) - "
+                               "requested size ignored",
+                                ui32TotalPBSize,
+                                psStubPBDesc->ui32TotalPBSize);
+
+               {
+
+                       psResItem = ResManRegisterRes(psPerProc->hResManContext,
+                                             RESMAN_TYPE_SHARED_PB_DESC,
+                                             psStubPBDesc, 0,
+                                             &SGXCleanupSharedPBDescCallback);
+                       if (psResItem == NULL) {
+                               PVR_DPF(PVR_DBG_ERROR,
+                                        "SGXAddSharedPBDescKM: "
+                                        "Failed to register existing shared "
+                                        "PBDesc with the resource manager");
+                               goto NoAddKeepPB;
+                       }
+
+                       psStubPBDesc->ui32RefCount++;
+
+                       *phSharedPBDesc = (void *) psResItem;
+                       eRet = PVRSRV_OK;
+                       goto NoAddKeepPB;
+               }
+       }
+
+       if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                      sizeof(struct PVRSRV_STUB_PBDESC),
+                      (void **)&psStubPBDesc, NULL) != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "SGXAddSharedPBDescKM: Failed to alloc "
+                        "StubPBDesc");
+               eRet = PVRSRV_ERROR_OUT_OF_MEMORY;
+               goto NoAdd;
+       }
+
+       psStubPBDesc->ppsSubKernelMemInfos = NULL;
+
+       if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                      sizeof(struct PVRSRV_KERNEL_MEM_INFO *) *
+                                       ui32SharedPBDescSubKernelMemInfosCount,
+                      (void **)&psStubPBDesc->ppsSubKernelMemInfos, NULL) !=
+                       PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "SGXAddSharedPBDescKM: "
+                        "Failed to alloc "
+                        "StubPBDesc->ppsSubKernelMemInfos");
+               eRet = PVRSRV_ERROR_OUT_OF_MEMORY;
+               goto NoAdd;
+       }
+
+       if (PVRSRVDissociateMemFromResmanKM(psSharedPBDescKernelMemInfo)
+           != PVRSRV_OK)
+               goto NoAdd;
+
+       if (PVRSRVDissociateMemFromResmanKM(psHWPBDescKernelMemInfo)
+           != PVRSRV_OK)
+               goto NoAdd;
+
+       if (PVRSRVDissociateMemFromResmanKM(psBlockKernelMemInfo)
+           != PVRSRV_OK)
+               goto NoAdd;
+
+       psStubPBDesc->ui32RefCount = 1;
+       psStubPBDesc->ui32TotalPBSize = ui32TotalPBSize;
+       psStubPBDesc->psSharedPBDescKernelMemInfo = psSharedPBDescKernelMemInfo;
+       psStubPBDesc->psHWPBDescKernelMemInfo = psHWPBDescKernelMemInfo;
+       psStubPBDesc->psBlockKernelMemInfo = psBlockKernelMemInfo;
+
+       psStubPBDesc->ui32SubKernelMemInfosCount =
+           ui32SharedPBDescSubKernelMemInfosCount;
+       for (i = 0; i < ui32SharedPBDescSubKernelMemInfosCount; i++) {
+               psStubPBDesc->ppsSubKernelMemInfos[i] =
+                   ppsSharedPBDescSubKernelMemInfos[i];
+               if (PVRSRVDissociateMemFromResmanKM
+                   (ppsSharedPBDescSubKernelMemInfos[i])
+                   != PVRSRV_OK) {
+                       PVR_DPF(PVR_DBG_ERROR, "SGXAddSharedPBDescKM: "
+                                "Failed to dissociate shared PBDesc "
+                                "from process");
+                       goto NoAdd;
+               }
+       }
+
+       psResItem = ResManRegisterRes(psPerProc->hResManContext,
+                                     RESMAN_TYPE_SHARED_PB_DESC,
+                                     psStubPBDesc,
+                                     0, &SGXCleanupSharedPBDescCallback);
+       if (psResItem == NULL) {
+               PVR_DPF(PVR_DBG_ERROR, "SGXAddSharedPBDescKM: "
+                        "Failed to register shared PBDesc "
+                        " with the resource manager");
+               goto NoAdd;
+       }
+       psStubPBDesc->hDevCookie = hDevCookie;
+
+       psStubPBDesc->psNext = psSGXDevInfo->psStubPBDescListKM;
+       psSGXDevInfo->psStubPBDescListKM = psStubPBDesc;
+
+       *phSharedPBDesc = (void *) psResItem;
+
+       return PVRSRV_OK;
+
+NoAdd:
+       if (psStubPBDesc) {
+               if (psStubPBDesc->ppsSubKernelMemInfos)
+                       OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                                 sizeof(struct PVRSRV_KERNEL_MEM_INFO *) *
+                                       ui32SharedPBDescSubKernelMemInfosCount,
+                                 psStubPBDesc->ppsSubKernelMemInfos, NULL);
+               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                         sizeof(struct PVRSRV_STUB_PBDESC), psStubPBDesc,
+                         NULL);
+       }
+
+NoAddKeepPB:
+       for (i = 0; i < ui32SharedPBDescSubKernelMemInfosCount; i++)
+               PVRSRVFreeDeviceMemKM(hDevCookie,
+                                     ppsSharedPBDescSubKernelMemInfos[i]);
+
+       PVRSRVFreeSharedSysMemoryKM(psSharedPBDescKernelMemInfo);
+       PVRSRVFreeDeviceMemKM(hDevCookie, psHWPBDescKernelMemInfo);
+
+       PVRSRVFreeSharedSysMemoryKM(psBlockKernelMemInfo);
+
+       return eRet;
+}