IMG_EXPORT PVRSRV_ERROR PVRSRVRGXCreateComputeContextKM(CONNECTION_DATA *psConnection, PVRSRV_DEVICE_NODE *psDeviceNode, IMG_UINT32 ui32Priority, IMG_DEV_VIRTADDR sMCUFenceAddr, IMG_UINT32 ui32FrameworkCommandSize, IMG_PBYTE pbyFrameworkCommand, IMG_HANDLE hMemCtxPrivData, RGX_SERVER_COMPUTE_CONTEXT **ppsComputeContext) { PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; DEVMEM_MEMDESC *psFWMemContextMemDesc = RGXGetFWMemDescFromMemoryContextHandle(hMemCtxPrivData); RGX_SERVER_COMPUTE_CONTEXT *psComputeContext; RGX_COMMON_CONTEXT_INFO sInfo; PVRSRV_ERROR eError = PVRSRV_OK; /* Prepare cleanup struct */ *ppsComputeContext = IMG_NULL; psComputeContext = OSAllocMem(sizeof(*psComputeContext)); if (psComputeContext == IMG_NULL) { return PVRSRV_ERROR_OUT_OF_MEMORY; } OSMemSet(psComputeContext, 0, sizeof(*psComputeContext)); psComputeContext->psDeviceNode = psDeviceNode; /* Allocate cleanup sync */ eError = SyncPrimAlloc(psDeviceNode->hSyncPrimContext, &psComputeContext->psSync); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateComputeContextKM: Failed to allocate cleanup sync (0x%x)", eError)); goto fail_syncalloc; } /* Allocate device memory for the firmware GPU context suspend state. Note: the FW reads/writes the state to memory by accessing the GPU register interface. */ PDUMPCOMMENT("Allocate RGX firmware compute context suspend state"); eError = DevmemFwAllocate(psDevInfo, sizeof(RGXFWIF_COMPUTECTX_STATE), RGX_FWCOMCTX_ALLOCFLAGS, "ComputeContextState", &psComputeContext->psFWComputeContextStateMemDesc); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateComputeContextKM: Failed to allocate firmware GPU context suspend state (%u)", eError)); goto fail_contextsuspendalloc; } /* * Create the FW framework buffer */ eError = PVRSRVRGXFrameworkCreateKM(psDeviceNode, &psComputeContext->psFWFrameworkMemDesc, ui32FrameworkCommandSize); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateComputeContextKM: Failed to allocate firmware GPU framework state (%u)", eError)); goto fail_frameworkcreate; } /* Copy the Framework client data into the framework buffer */ eError = PVRSRVRGXFrameworkCopyCommand(psComputeContext->psFWFrameworkMemDesc, pbyFrameworkCommand, ui32FrameworkCommandSize); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateComputeContextKM: Failed to populate the framework buffer (%u)", eError)); goto fail_frameworkcopy; } sInfo.psFWFrameworkMemDesc = psComputeContext->psFWFrameworkMemDesc; sInfo.psMCUFenceAddr = &sMCUFenceAddr; eError = FWCommonContextAllocate(psConnection, psDeviceNode, "CDM", IMG_NULL, 0, psFWMemContextMemDesc, psComputeContext->psFWComputeContextStateMemDesc, RGX_CCB_SIZE_LOG2, ui32Priority, &sInfo, &psComputeContext->psServerCommonContext); if (eError != PVRSRV_OK) { goto fail_contextalloc; } { PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; dllist_add_to_tail(&(psDevInfo->sComputeCtxtListHead), &(psComputeContext->sListNode)); } *ppsComputeContext = psComputeContext; return PVRSRV_OK; fail_contextalloc: fail_frameworkcopy: DevmemFwFree(psComputeContext->psFWFrameworkMemDesc); fail_frameworkcreate: DevmemFwFree(psComputeContext->psFWComputeContextStateMemDesc); fail_contextsuspendalloc: SyncPrimFree(psComputeContext->psSync); fail_syncalloc: OSFreeMem(psComputeContext); return eError; }
/* * PVRSRVCreateTransferContextKM */ IMG_EXPORT PVRSRV_ERROR PVRSRVRGXCreateTransferContextKM(CONNECTION_DATA *psConnection, PVRSRV_DEVICE_NODE *psDeviceNode, IMG_UINT32 ui32Priority, IMG_DEV_VIRTADDR sMCUFenceAddr, IMG_UINT32 ui32FrameworkCommandSize, IMG_PBYTE pabyFrameworkCommand, IMG_HANDLE hMemCtxPrivData, RGX_SERVER_TQ_CONTEXT **ppsTransferContext) { RGX_SERVER_TQ_CONTEXT *psTransferContext; DEVMEM_MEMDESC *psFWMemContextMemDesc = RGXGetFWMemDescFromMemoryContextHandle(hMemCtxPrivData); RGX_COMMON_CONTEXT_INFO sInfo; PVRSRV_ERROR eError = PVRSRV_OK; /* Allocate the server side structure */ psTransferContext = OSAllocMem(sizeof(*psTransferContext)); if (psTransferContext == IMG_NULL) { return PVRSRV_ERROR_OUT_OF_MEMORY; } OSMemSet(psTransferContext, 0, sizeof(*psTransferContext)); *ppsTransferContext = psTransferContext; psTransferContext->psDeviceNode = psDeviceNode; /* Allocate cleanup sync */ eError = SyncPrimAlloc(psDeviceNode->hSyncPrimContext, &psTransferContext->psCleanupSync); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateTransferContextKM: Failed to allocate cleanup sync (0x%x)", eError)); goto fail_syncalloc; } /* * Create the FW framework buffer */ eError = PVRSRVRGXFrameworkCreateKM(psDeviceNode, &psTransferContext->psFWFrameworkMemDesc, ui32FrameworkCommandSize); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateTransferContextKM: Failed to allocate firmware GPU framework state (%u)", eError)); goto fail_frameworkcreate; } /* Copy the Framework client data into the framework buffer */ eError = PVRSRVRGXFrameworkCopyCommand(psTransferContext->psFWFrameworkMemDesc, pabyFrameworkCommand, ui32FrameworkCommandSize); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateTransferContextKM: Failed to populate the framework buffer (%u)", eError)); goto fail_frameworkcopy; } sInfo.psFWFrameworkMemDesc = psTransferContext->psFWFrameworkMemDesc; sInfo.psMCUFenceAddr = &sMCUFenceAddr; eError = _Create3DTransferContext(psConnection, psDeviceNode, psFWMemContextMemDesc, ui32Priority, &sInfo, &psTransferContext->s3DData); if (eError != PVRSRV_OK) { goto fail_3dtransfercontext; } psTransferContext->ui32Flags |= RGX_SERVER_TQ_CONTEXT_FLAGS_3D; eError = _Create2DTransferContext(psConnection, psDeviceNode, psFWMemContextMemDesc, ui32Priority, &sInfo, &psTransferContext->s2DData); if (eError != PVRSRV_OK) { goto fail_2dtransfercontext; } psTransferContext->ui32Flags |= RGX_SERVER_TQ_CONTEXT_FLAGS_2D; { PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; dllist_add_to_tail(&(psDevInfo->sTransferCtxtListHead), &(psTransferContext->sListNode)); } return PVRSRV_OK; fail_2dtransfercontext: _Destroy3DTransferContext(&psTransferContext->s3DData, psTransferContext->psDeviceNode, psTransferContext->psCleanupSync); fail_3dtransfercontext: fail_frameworkcopy: DevmemFwFree(psTransferContext->psFWFrameworkMemDesc); fail_frameworkcreate: SyncPrimFree(psTransferContext->psCleanupSync); fail_syncalloc: OSFreeMem(psTransferContext); PVR_ASSERT(eError != PVRSRV_OK); return eError; }
/* * RGXRegisterMemoryContext */ PVRSRV_ERROR RGXRegisterMemoryContext(PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT *psMMUContext, IMG_HANDLE *hPrivData) { PVRSRV_ERROR eError; PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; DEVMEM_FLAGS_T uiFWMemContextMemAllocFlags; RGXFWIF_FWMEMCONTEXT *psFWMemContext; DEVMEM_MEMDESC *psFWMemContextMemDesc; SERVER_MMU_CONTEXT *psServerMMUContext; if (psDevInfo->psKernelMMUCtx == IMG_NULL) { /* * This must be the creation of the Kernel memory context. Take a copy * of the MMU context for use when programming the BIF. */ psDevInfo->psKernelMMUCtx = psMMUContext; } else { psServerMMUContext = OSAllocMem(sizeof(*psServerMMUContext)); if (psServerMMUContext == IMG_NULL) { eError = PVRSRV_ERROR_OUT_OF_MEMORY; goto fail_alloc_server_ctx; } psServerMMUContext->psDevInfo = psDevInfo; /* * This FW MemContext is only mapped into kernel for initialisation purposes. * Otherwise this allocation is only used by the FW. * Therefore the GPU cache doesn't need coherency, * and write-combine is suffice on the CPU side (WC buffer will be flushed at any kick) */ uiFWMemContextMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(META_CACHED) | PVRSRV_MEMALLOCFLAG_GPU_READABLE | PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | PVRSRV_MEMALLOCFLAG_GPU_CACHE_INCOHERENT | PVRSRV_MEMALLOCFLAG_CPU_READABLE | PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | PVRSRV_MEMALLOCFLAG_CPU_WRITE_COMBINE | PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE; /* Allocate device memory for the firmware memory context for the new application. */ PDUMPCOMMENT("Allocate RGX firmware memory context"); /* FIXME: why cache-consistent? */ eError = DevmemFwAllocate(psDevInfo, sizeof(*psFWMemContext), uiFWMemContextMemAllocFlags, "FirmwareMemoryContext", &psFWMemContextMemDesc); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"RGXRegisterMemoryContext: Failed to allocate firmware memory context (%u)", eError)); goto fail_alloc_fw_ctx; } /* Temporarily map the firmware memory context to the kernel. */ eError = DevmemAcquireCpuVirtAddr(psFWMemContextMemDesc, (IMG_VOID **)&psFWMemContext); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"RGXRegisterMemoryContext: Failed to map firmware memory context (%u)", eError)); goto fail_acquire_cpu_addr; } /* * Write the new memory context's page catalogue into the firmware memory * context for the client. */ eError = MMU_AcquireBaseAddr(psMMUContext, &psFWMemContext->sPCDevPAddr); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"RGXRegisterMemoryContext: Failed to acquire Page Catalogue address (%u)", eError)); DevmemReleaseCpuVirtAddr(psFWMemContextMemDesc); goto fail_acquire_base_addr; } /* * Set default values for the rest of the structure. */ psFWMemContext->uiPageCatBaseRegID = -1; psFWMemContext->uiBreakpointAddr = 0; psFWMemContext->uiBPHandlerAddr = 0; psFWMemContext->uiBreakpointCtl = 0; #if defined(SUPPORT_GPUVIRT_VALIDATION) { IMG_UINT32 ui32OSid = 0, ui32OSidReg = 0; MMU_GetOSids(psMMUContext, &ui32OSid, &ui32OSidReg); psFWMemContext->ui32OSid = ui32OSidReg; } #endif #if defined(PDUMP) { IMG_CHAR aszName[PMR_MAX_MEMSPNAME_SYMB_ADDR_LENGTH_DEFAULT]; IMG_DEVMEM_OFFSET_T uiOffset = 0; /* * Dump the Mem context allocation */ DevmemPDumpLoadMem(psFWMemContextMemDesc, 0, sizeof(*psFWMemContext), PDUMP_FLAGS_CONTINUOUS); /* * Obtain a symbolic addr of the mem context structure */ eError = DevmemPDumpPageCatBaseToSAddr(psFWMemContextMemDesc, &uiOffset, aszName, PMR_MAX_MEMSPNAME_SYMB_ADDR_LENGTH_DEFAULT); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"RGXRegisterMemoryContext: Failed to generate a Dump Page Catalogue address (%u)", eError)); DevmemReleaseCpuVirtAddr(psFWMemContextMemDesc); goto fail_pdump_cat_base_addr; } /* * Dump the Page Cat tag in the mem context (symbolic address) */ eError = MMU_PDumpWritePageCatBase(psMMUContext, aszName, uiOffset, 8, /* 64-bit register write */ 0, 0, 0); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"RGXRegisterMemoryContext: Failed to acquire Page Catalogue address (%u)", eError)); DevmemReleaseCpuVirtAddr(psFWMemContextMemDesc); goto fail_pdump_cat_base; } } #endif /* * Release kernel address acquired above. */ DevmemReleaseCpuVirtAddr(psFWMemContextMemDesc); /* * Store the process information for this device memory context * for use with the host page-fault analysis. */ psServerMMUContext->uiPID = OSGetCurrentProcessID(); psServerMMUContext->psMMUContext = psMMUContext; psServerMMUContext->psFWMemContextMemDesc = psFWMemContextMemDesc; if (OSSNPrintf(psServerMMUContext->szProcessName, RGXMEM_SERVER_MMU_CONTEXT_MAX_NAME, "%s", OSGetCurrentProcessName()) == RGXMEM_SERVER_MMU_CONTEXT_MAX_NAME) { psServerMMUContext->szProcessName[RGXMEM_SERVER_MMU_CONTEXT_MAX_NAME-1] = '\0'; } OSWRLockAcquireWrite(psDevInfo->hMemoryCtxListLock); dllist_add_to_tail(&psDevInfo->sMemoryContextList, &psServerMMUContext->sNode); OSWRLockReleaseWrite(psDevInfo->hMemoryCtxListLock); MMU_SetDeviceData(psMMUContext, psFWMemContextMemDesc); *hPrivData = psServerMMUContext; } return PVRSRV_OK; #if defined(PDUMP) fail_pdump_cat_base: fail_pdump_cat_base_addr: MMU_ReleaseBaseAddr(IMG_NULL); #endif fail_acquire_base_addr: /* Done before jumping to the fail point as the release is done before exit */ fail_acquire_cpu_addr: DevmemFwFree(psServerMMUContext->psFWMemContextMemDesc); fail_alloc_fw_ctx: OSFreeMem(psServerMMUContext); fail_alloc_server_ctx: PVR_ASSERT(eError != PVRSRV_OK); return eError; }