/*! ****************************************************************************** @Function PVRSRVTimeTraceInit @Description Initialise the timed trace subsystem. @Return Error ******************************************************************************/ PVRSRV_ERROR PVRSRVTimeTraceInit(IMG_VOID) { g_psBufferTable = HASH_Create(TIME_TRACE_HASH_TABLE_SIZE); /* Create hash table to store the per process buffers in */ if (!g_psBufferTable) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVTimeTraceInit: Error creating hash table")); return PVRSRV_ERROR_OUT_OF_MEMORY; } /* Create the kernel buffer */ PVRSRVTimeTraceBufferCreate(KERNEL_ID); g_psTimer = OSFuncHighResTimerCreate(); if (!g_psTimer) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVTimeTraceInit: Error creating timer")); return PVRSRV_ERROR_INIT_FAILURE; } return PVRSRV_OK; }
/*! ****************************************************************************** @Function PVRSRVPerProcessDataConnect @Description Allocate per-process data area, or increment refcount if one already exists for this PID. @Input ui32PID - process ID ppsPerProc - Pointer to per-process data area @Return PVRSRV_ERROR ******************************************************************************/ PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flags) { PVRSRV_PER_PROCESS_DATA *psPerProc; IMG_HANDLE hBlockAlloc; PVRSRV_ERROR eError = PVRSRV_OK; if (psHashTab == IMG_NULL) { return PVRSRV_ERROR_INIT_FAILURE; } /* Look for existing per-process data area */ psPerProc = (PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, (IMG_UINTPTR_T)ui32PID); if (psPerProc == IMG_NULL) { /* Allocate per-process data area */ eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), (IMG_PVOID *)&psPerProc, &hBlockAlloc, "Per Process Data"); 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, (IMG_UINTPTR_T)ui32PID, (IMG_UINTPTR_T)psPerProc)) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't insert per-process data into hash table")); eError = PVRSRV_ERROR_INSERT_HASH_TABLE_DATA_FAILED; goto failure; } psPerProc->ui32PID = ui32PID; psPerProc->ui32RefCount = 0; #if defined(SUPPORT_PDUMP_MULTI_PROCESS) if (ui32Flags == SRV_FLAGS_PDUMP_ACTIVE) { psPerProc->bPDumpActive = IMG_TRUE; } #else PVR_UNREFERENCED_PARAMETER(ui32Flags); #endif /* Call environment specific per process init function */ eError = OSPerProcessPrivateDataInit(&psPerProc->hOsPrivateData); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: OSPerProcessPrivateDataInit failed (%d)", eError)); goto failure; } /* Allocate a handle for the per-process data area */ 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; } /* Allocate handle base for this process */ 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; } /* Set per-process handle options */ eError = OSPerProcessSetHandleOptions(psPerProc->psHandleBase); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't set handle options (%d)", eError)); goto failure; } /* Create a resource manager context for the process */ eError = PVRSRVResManConnect(psPerProc, &psPerProc->hResManContext); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't register with the resource manager")); goto failure; } #if defined (TTRACE) PVRSRVTimeTraceBufferCreate(ui32PID); #endif } psPerProc->ui32RefCount++; PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVPerProcessDataConnect: Process 0x%x has ref-count %d", ui32PID, psPerProc->ui32RefCount)); return eError; failure: (IMG_VOID)FreePerProcessData(psPerProc); return eError; }
/*! ****************************************************************************** @Function PVRSRVTimeTraceAllocItem @Description Allocate a trace item from the buffer of the current process @Output ppsTraceItem : Pointer to allocated trace item @Input ui32Size : Size of data packet to be allocated @Return none ******************************************************************************/ static IMG_VOID PVRSRVTimeTraceAllocItem(IMG_UINT32 **pui32Item, IMG_UINT32 ui32Size) { IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM(); IMG_UINT32 ui32AllocOffset; sTimeTraceBuffer *psBuffer = (sTimeTraceBuffer *) HASH_Retrieve(g_psBufferTable, (IMG_UINTPTR_T) ui32PID); /* The caller only asks for extra data space */ ui32Size += PVRSRV_TRACE_ITEM_SIZE; /* Always round to 32-bit */ ui32Size = ((ui32Size - 1) & (~0x3)) + 0x04; if (!psBuffer) { PVRSRV_ERROR eError; PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVTimeTraceAllocItem: Creating buffer for PID %u", (IMG_UINT32) ui32PID)); eError = PVRSRVTimeTraceBufferCreate(ui32PID); if (eError != PVRSRV_OK) { *pui32Item = IMG_NULL; PVR_DPF((PVR_DBG_ERROR, "PVRSRVTimeTraceAllocItem: Failed to create buffer")); return; } psBuffer = (sTimeTraceBuffer *) HASH_Retrieve(g_psBufferTable, (IMG_UINTPTR_T) ui32PID); if (psBuffer == IMG_NULL) { *pui32Item = NULL; PVR_DPF((PVR_DBG_ERROR, "PVRSRVTimeTraceAllocItem: Failed to retrieve buffer")); return; } } /* Can't allocate more then buffer size */ if (ui32Size >= TIME_TRACE_BUFFER_SIZE) { *pui32Item = NULL; PVR_DPF((PVR_DBG_ERROR, "PVRSRVTimeTraceAllocItem: Error trace item too large (%d)", ui32Size)); return; } /* FIXME: Enter critical section? */ /* Always ensure we have enough space to write a padding message */ if ((psBuffer->ui32Woff + ui32Size + PVRSRV_TRACE_ITEM_SIZE) > TIME_TRACE_BUFFER_SIZE) { IMG_UINT32 *ui32WriteEOB = (IMG_UINT32 *) &psBuffer->pui8Data[psBuffer->ui32Woff]; IMG_UINT32 ui32Remain = TIME_TRACE_BUFFER_SIZE - psBuffer->ui32Woff; /* Not enough space at the end of the buffer, back to the start */ *ui32WriteEOB++ = WRITE_HEADER(GROUP, PVRSRV_TRACE_GROUP_PADDING); *ui32WriteEOB++ = 0; /* Don't need timestamp */ *ui32WriteEOB++ = 0; /* Don't need UID */ *ui32WriteEOB = WRITE_HEADER(SIZE, (ui32Remain - PVRSRV_TRACE_ITEM_SIZE)); psBuffer->ui32ByteCount += ui32Remain; psBuffer->ui32Woff = ui32AllocOffset = 0; } else ui32AllocOffset = psBuffer->ui32Woff; psBuffer->ui32Woff = psBuffer->ui32Woff + ui32Size; psBuffer->ui32ByteCount += ui32Size; /* This allocation will start overwritting past our read pointer, move the read pointer along */ while (psBuffer->ui32ByteCount > TIME_TRACE_BUFFER_SIZE) { IMG_UINT32 *psReadItem = (IMG_UINT32 *) &psBuffer->pui8Data[psBuffer->ui32Roff]; IMG_UINT32 ui32ReadSize; ui32ReadSize = PVRSRVTimeTraceItemSize(psReadItem); psBuffer->ui32Roff = (psBuffer->ui32Roff + ui32ReadSize) & (TIME_TRACE_BUFFER_SIZE - 1); psBuffer->ui32ByteCount -= ui32ReadSize; } *pui32Item = (IMG_UINT32 *) &psBuffer->pui8Data[ui32AllocOffset]; /* FIXME: Exit critical section? */ }