1 /*************************************************************************/ /*!
3 @Title RGX Workload Estimation Functionality
5 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
6 @Description Kernel mode workload estimation functionality.
7 @License Dual MIT/GPLv2
9 The contents of this file are subject to the MIT license as set out below.
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
21 Alternatively, the contents of this file may be used under the terms of
22 the GNU General Public License Version 2 ("GPL") in which case the provisions
23 of GPL are applicable instead of those above.
25 If you wish to allow use of your version of this file only under the terms of
26 GPL, and not to allow others to use your version of this file under the terms
27 of the MIT license, indicate your decision by deleting the provisions above
28 and replace them with the notice and other provisions required by GPL as set
29 out in the file called "GPL-COPYING" included in this distribution. If you do
30 not delete the provisions above, a recipient may use your version of this file
31 under the terms of either the MIT license or GPL.
33 This License is also included in this distribution in the file called
36 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
37 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
38 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
39 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
40 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
41 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
42 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 */ /**************************************************************************/
45 #include "rgxworkest.h"
46 #include "rgxfwutils.h"
47 #include "rgxdevice.h"
50 #include "pvr_debug.h"
52 #define ROUND_DOWN_TO_NEAREST_1024(number) (((number) >> 10) << 10)
54 void WorkEstRCInit(WORKEST_HOST_DATA *psWorkEstData)
56 /* Create hash tables for workload matching */
57 psWorkEstData->sWorkloadMatchingDataTA.psWorkloadDataHash =
58 HASH_Create_Extended(WORKLOAD_HASH_SIZE,
59 sizeof(RGX_WORKLOAD_TA3D *),
61 (HASH_KEY_COMP *)&WorkEstHashCompareTA3D);
63 /* Create a lock to protect the hash table */
64 WorkEstHashLockCreate(&(psWorkEstData->sWorkloadMatchingDataTA.psWorkEstHashLock));
66 psWorkEstData->sWorkloadMatchingData3D.psWorkloadDataHash =
67 HASH_Create_Extended(WORKLOAD_HASH_SIZE,
68 sizeof(RGX_WORKLOAD_TA3D *),
70 (HASH_KEY_COMP *)&WorkEstHashCompareTA3D);
72 /* Create a lock to protect the hash tables */
73 WorkEstHashLockCreate(&(psWorkEstData->sWorkloadMatchingData3D.psWorkEstHashLock));
76 void WorkEstRCDeInit(WORKEST_HOST_DATA *psWorkEstData,
77 PVRSRV_RGXDEV_INFO *psDevInfo)
79 HASH_TABLE *psWorkloadDataHash;
80 RGX_WORKLOAD_TA3D *pasWorkloadHashKeys;
81 RGX_WORKLOAD_TA3D *psWorkloadHashKey;
83 IMG_UINT64 *paui64WorkloadCycleData;
85 pasWorkloadHashKeys = psWorkEstData->sWorkloadMatchingDataTA.asWorkloadHashKeys;
86 paui64WorkloadCycleData = psWorkEstData->sWorkloadMatchingDataTA.aui64HashCycleData;
87 psWorkloadDataHash = psWorkEstData->sWorkloadMatchingDataTA.psWorkloadDataHash;
89 if(psWorkloadDataHash)
91 for(ui32i = 0; ui32i < WORKLOAD_HASH_SIZE; ui32i++)
93 if(paui64WorkloadCycleData[ui32i] > 0)
95 psWorkloadHashKey = &pasWorkloadHashKeys[ui32i];
96 HASH_Remove_Extended(psWorkloadDataHash,
97 (uintptr_t*)&psWorkloadHashKey);
101 HASH_Delete(psWorkloadDataHash);
104 /* Remove the hash lock */
105 WorkEstHashLockDestroy(psWorkEstData->sWorkloadMatchingDataTA.psWorkEstHashLock);
107 pasWorkloadHashKeys = psWorkEstData->sWorkloadMatchingData3D.asWorkloadHashKeys;
108 paui64WorkloadCycleData = psWorkEstData->sWorkloadMatchingData3D.aui64HashCycleData;
109 psWorkloadDataHash = psWorkEstData->sWorkloadMatchingData3D.psWorkloadDataHash;
111 if(psWorkloadDataHash)
113 for(ui32i = 0; ui32i < WORKLOAD_HASH_SIZE; ui32i++)
115 if(paui64WorkloadCycleData[ui32i] > 0)
117 psWorkloadHashKey = &pasWorkloadHashKeys[ui32i];
118 HASH_Remove_Extended(psWorkloadDataHash,
119 (uintptr_t*)&psWorkloadHashKey);
123 HASH_Delete(psWorkloadDataHash);
126 /* Remove the hash lock */
127 WorkEstHashLockDestroy(psWorkEstData->sWorkloadMatchingData3D.psWorkEstHashLock);
132 IMG_BOOL WorkEstHashCompareTA3D(size_t uKeySize,
136 RGX_WORKLOAD_TA3D *psWorkload1;
137 RGX_WORKLOAD_TA3D *psWorkload2;
141 psWorkload1 = *((RGX_WORKLOAD_TA3D **)pKey1);
142 psWorkload2 = *((RGX_WORKLOAD_TA3D **)pKey2);
144 PVR_ASSERT(psWorkload1);
145 PVR_ASSERT(psWorkload2);
147 if(psWorkload1->ui32RenderTargetSize == psWorkload2->ui32RenderTargetSize
148 && psWorkload1->ui32NumberOfDrawCalls == psWorkload2->ui32NumberOfDrawCalls
149 && psWorkload1->ui32NumberOfIndices == psWorkload2->ui32NumberOfIndices
150 && psWorkload1->ui32NumberOfMRTs == psWorkload2->ui32NumberOfMRTs)
152 /* This is added to allow this memory to be freed */
153 *(uintptr_t*)pKey2 = *(uintptr_t*)pKey1;
160 static inline IMG_UINT32 WorkEstDoHash(IMG_UINT32 ui32Input)
162 IMG_UINT32 ui32HashPart;
164 ui32HashPart = ui32Input;
165 ui32HashPart += (ui32HashPart << 12);
166 ui32HashPart ^= (ui32HashPart >> 22);
167 ui32HashPart += (ui32HashPart << 4);
168 ui32HashPart ^= (ui32HashPart >> 9);
169 ui32HashPart += (ui32HashPart << 10);
170 ui32HashPart ^= (ui32HashPart >> 2);
171 ui32HashPart += (ui32HashPart << 7);
172 ui32HashPart ^= (ui32HashPart >> 12);
177 IMG_UINT32 WorkEstHashFuncTA3D(size_t uKeySize, void *pKey, IMG_UINT32 uHashTabLen)
179 RGX_WORKLOAD_TA3D *psWorkload = *((RGX_WORKLOAD_TA3D**)pKey);
180 IMG_UINT32 ui32HashKey = 0;
181 PVR_UNREFERENCED_PARAMETER(uHashTabLen);
182 PVR_UNREFERENCED_PARAMETER(uKeySize);
184 ui32HashKey += WorkEstDoHash(psWorkload->ui32RenderTargetSize);
185 ui32HashKey += WorkEstDoHash(psWorkload->ui32NumberOfDrawCalls);
186 ui32HashKey += WorkEstDoHash(psWorkload->ui32NumberOfIndices);
187 ui32HashKey += WorkEstDoHash(psWorkload->ui32NumberOfMRTs);
192 PVRSRV_ERROR WorkEstPrepare(PVRSRV_RGXDEV_INFO *psDevInfo,
193 WORKEST_HOST_DATA *psWorkEstHostData,
194 WORKLOAD_MATCHING_DATA *psWorkloadMatchingData,
195 IMG_UINT32 ui32RenderTargetSize,
196 IMG_UINT32 ui32NumberOfDrawCalls,
197 IMG_UINT32 ui32NumberOfIndices,
198 IMG_UINT32 ui32NumberOfMRTs,
199 IMG_UINT64 ui64DeadlineInus,
200 RGXFWIF_WORKEST_KICK_DATA *psWorkEstKickData)
203 RGX_WORKLOAD_TA3D *psWorkloadCharacteristics;
204 IMG_UINT64 *pui64CyclePrediction;
205 POS_LOCK psWorkEstHashLock;
206 IMG_UINT64 ui64WorkloadDeadlineInus = ui64DeadlineInus;
207 IMG_UINT64 ui64CurrentTime;
208 HASH_TABLE *psWorkloadDataHash;
209 WORKEST_RETURN_DATA *psReturnData;
211 if(psDevInfo == NULL)
213 PVR_DPF((PVR_DBG_ERROR,"WorkEstPrepare: Device Info not available"));
214 return PVRSRV_ERROR_INVALID_PARAMS;
217 if(psDevInfo->bWorkEstEnabled != IMG_TRUE)
219 /* No error message to avoid excessive messages */
223 if(psWorkEstHostData == NULL)
225 PVR_DPF((PVR_DBG_ERROR,
226 "WorkEstPrepare: Host data not available"));
227 return PVRSRV_ERROR_INVALID_PARAMS;
230 if(psWorkloadMatchingData == NULL)
232 PVR_DPF((PVR_DBG_ERROR,
233 "WorkEstPrepare: Workload Matching Data not available"));
234 return PVRSRV_ERROR_INVALID_PARAMS;
237 psWorkloadDataHash = psWorkloadMatchingData->psWorkloadDataHash;
238 if(psWorkloadDataHash == NULL)
240 PVR_DPF((PVR_DBG_ERROR,"WorkEstPrepare: Hash Table not available"));
241 return PVRSRV_ERROR_INVALID_PARAMS;
244 psWorkEstHashLock = psWorkloadMatchingData->psWorkEstHashLock;
245 if(psWorkEstHashLock == NULL)
247 PVR_DPF((PVR_DBG_ERROR,
248 "WorkEstPrepare: Hash lock not available"
250 eError = PVRSRV_ERROR_UNABLE_TO_RETRIEVE_HASH_VALUE;
254 eError = OSClockMonotonicus64(&ui64CurrentTime);
255 if(eError != PVRSRV_OK)
257 PVR_DPF((PVR_DBG_ERROR,
258 "WorkEstPrepare: Unable to access System Monotonic clock"));
259 PVR_ASSERT(eError == PVRSRV_OK);
263 #if defined(SUPPORT_PDVFS)
264 psDevInfo->psDeviceNode->psDevConfig->sDVFS.sPDVFSData.bWorkInFrame = IMG_TRUE;
267 /* Set up data for the return path to process the workload */
269 /* Any host side data needed for the return path is stored in an array and
270 * only the array's index is passed to and from the firmware. This is a
271 * similar abstraction to using handles but is optimised for this case.
274 &psDevInfo->asReturnData[psDevInfo->ui32ReturnDataWO];
276 /* The index for the specific data is passed to the FW */
277 psWorkEstKickData->ui64ReturnDataIndex = psDevInfo->ui32ReturnDataWO;
279 psDevInfo->ui32ReturnDataWO =
280 (psDevInfo->ui32ReturnDataWO + 1) & RETURN_DATA_ARRAY_WRAP_MASK;
282 /* The workload characteristics are needed in the return data for the
283 * matching of future workloads via the hash.
285 psWorkloadCharacteristics = &psReturnData->sWorkloadCharacteristics;
286 psWorkloadCharacteristics->ui32RenderTargetSize = ui32RenderTargetSize;
287 psWorkloadCharacteristics->ui32NumberOfDrawCalls = ui32NumberOfDrawCalls;
288 psWorkloadCharacteristics->ui32NumberOfIndices = ui32NumberOfIndices;
289 psWorkloadCharacteristics->ui32NumberOfMRTs = ui32NumberOfMRTs;
291 /* The matching data is needed as it holds the hash data. */
292 psReturnData->psWorkloadMatchingData = psWorkloadMatchingData;
294 /* The host data for the completion updates */
295 psReturnData->psWorkEstHostData = psWorkEstHostData;
296 if(ui64WorkloadDeadlineInus > ui64CurrentTime)
298 /* This is rounded to reduce multiple deadlines with a minor spread
299 * flooding the fw workload array.
301 psWorkEstKickData->ui64DeadlineInus =
302 ROUND_DOWN_TO_NEAREST_1024(ui64WorkloadDeadlineInus);
306 /* If the deadline has already passed assign as zero to suggest full
309 psWorkEstKickData->ui64DeadlineInus = 0;
312 /* Acquire the lock to access hash */
313 OSLockAcquire(psWorkEstHashLock);
315 /* Check if there is a prediction for this workload */
316 pui64CyclePrediction =
317 (IMG_UINT64*) HASH_Retrieve(psWorkloadDataHash,
318 (uintptr_t)psWorkloadCharacteristics);
321 OSLockRelease(psWorkEstHashLock);
323 if(pui64CyclePrediction != NULL)
325 /* Cycle prediction is available, store this prediction */
326 psWorkEstKickData->ui64CyclesPrediction = *pui64CyclePrediction;
330 /* There is no prediction */
331 psWorkEstKickData->ui64CyclesPrediction = 0;
337 PVRSRV_ERROR WorkEstWorkloadFinished(PVRSRV_RGXDEV_INFO *psDevInfo,
338 RGXFWIF_WORKEST_FWCCB_CMD *psReturnCmd)
340 RGX_WORKLOAD_TA3D *psWorkloadCharacteristics;
341 RGX_WORKLOAD_TA3D *pasWorkloadHashKeys;
342 IMG_UINT64 *paui64HashCycleData;
343 IMG_UINT32 *pui32HashArrayWO;
344 RGX_WORKLOAD_TA3D *psWorkloadHashKey;
345 IMG_UINT64 *pui64CyclesTaken;
346 HASH_TABLE *psWorkloadHash;
347 WORKLOAD_MATCHING_DATA *psWorkloadMatchingData;
348 POS_LOCK psWorkEstHashLock;
349 IMG_BOOL bHashSucess;
350 WORKEST_RETURN_DATA *psReturnData;
351 WORKEST_HOST_DATA *psWorkEstHostData;
352 PVRSRV_ERROR eError = PVRSRV_OK;
354 if(psDevInfo->bWorkEstEnabled != IMG_TRUE)
356 /* No error message to avoid excessive messages */
360 if(psReturnCmd == NULL)
362 PVR_DPF((PVR_DBG_ERROR,
363 "WorkEstFinished: Missing Return Command"));
364 return PVRSRV_ERROR_INVALID_PARAMS;
367 if(psReturnCmd->ui64ReturnDataIndex >= RETURN_DATA_ARRAY_SIZE)
369 PVR_DPF((PVR_DBG_ERROR,
370 "WorkEstFinished: Handle Reference Out of Bounds"));
371 return PVRSRV_ERROR_INVALID_PARAMS;
374 /* Retrieve the return data for this workload */
375 psReturnData = &psDevInfo->asReturnData[psReturnCmd->ui64ReturnDataIndex];
377 psWorkEstHostData = psReturnData->psWorkEstHostData;
379 if(psWorkEstHostData == NULL)
381 PVR_DPF((PVR_DBG_ERROR,
382 "WorkEstFinished: Missing host data"));
383 eError = PVRSRV_ERROR_INVALID_PARAMS;
387 psWorkloadCharacteristics = &psReturnData->sWorkloadCharacteristics;
389 if(psWorkloadCharacteristics == NULL)
391 PVR_DPF((PVR_DBG_ERROR,
392 "WorkEstFinished: Missing workload characteristics"));
393 eError = PVRSRV_ERROR_INVALID_PARAMS;
397 psWorkloadMatchingData = psReturnData->psWorkloadMatchingData;
399 psWorkloadHash = psWorkloadMatchingData->psWorkloadDataHash;
400 if(psWorkloadHash == NULL)
402 PVR_DPF((PVR_DBG_ERROR,
403 "WorkEstFinished: Missing hash"));
404 eError = PVRSRV_ERROR_INVALID_PARAMS;
408 psWorkEstHashLock = psWorkloadMatchingData->psWorkEstHashLock;
409 if(psWorkEstHashLock == NULL)
411 PVR_DPF((PVR_DBG_ERROR,
412 "WorkEstFinished: Missing hash lock"));
413 eError = PVRSRV_ERROR_INVALID_PARAMS;
417 OSLockAcquire(psWorkEstHashLock);
420 (IMG_UINT64*) HASH_Remove_Extended(psWorkloadHash,
421 (uintptr_t*)&psWorkloadCharacteristics);
423 pui32HashArrayWO = &(psWorkloadMatchingData->ui32HashArrayWO);
424 paui64HashCycleData = psWorkloadMatchingData->aui64HashCycleData;
425 pasWorkloadHashKeys = psWorkloadMatchingData->asWorkloadHashKeys;
427 /* Remove the oldest Hash data before it becomes overwritten */
428 if(paui64HashCycleData[*pui32HashArrayWO] > 0)
430 psWorkloadHashKey = &pasWorkloadHashKeys[*pui32HashArrayWO];
431 HASH_Remove_Extended(psWorkloadHash,
432 (uintptr_t*)&psWorkloadHashKey);
435 if(pui64CyclesTaken == NULL)
437 /* There is no existing entry for these characteristics. */
438 pasWorkloadHashKeys[*pui32HashArrayWO] = *psWorkloadCharacteristics;
440 paui64HashCycleData[*pui32HashArrayWO] = psReturnCmd->ui64CyclesTaken;
445 (*pui64CyclesTaken + psReturnCmd->ui64CyclesTaken)/2;
447 pasWorkloadHashKeys[*pui32HashArrayWO] = *psWorkloadCharacteristics;
449 paui64HashCycleData[*pui32HashArrayWO] = *pui64CyclesTaken;
451 /* Set the old value to 0 so it is known to be invalid */
452 *pui64CyclesTaken = 0;
456 bHashSucess = HASH_Insert((HASH_TABLE*)(psWorkloadHash),
457 (uintptr_t)&pasWorkloadHashKeys[*pui32HashArrayWO],
458 (uintptr_t)&paui64HashCycleData[*pui32HashArrayWO]);
459 PVR_ASSERT(bHashSucess);
461 if(*pui32HashArrayWO == WORKLOAD_HASH_SIZE-1)
463 *pui32HashArrayWO = 0;
467 (*pui32HashArrayWO)++;
470 OSLockRelease(psWorkEstHashLock);
474 /* Update the received counter so that the FW is able to check as to whether
475 * all the workloads connected to a render context are finished.
477 psWorkEstHostData->ui32WorkEstCCBReceived++;
481 void WorkEstHashLockCreate(POS_LOCK *psWorkEstHashLock)
483 if(*psWorkEstHashLock == NULL)
485 OSLockCreate(psWorkEstHashLock, LOCK_TYPE_DISPATCH);
490 void WorkEstHashLockDestroy(POS_LOCK sWorkEstHashLock)
492 if(sWorkEstHashLock != NULL)
494 OSLockDestroy(sWorkEstHashLock);
495 sWorkEstHashLock = NULL;
500 void WorkEstCheckFirmwareCCB(PVRSRV_RGXDEV_INFO *psDevInfo)
502 RGXFWIF_WORKEST_FWCCB_CMD *psFwCCBCmd;
504 RGXFWIF_CCB_CTL *psFWCCBCtl = psDevInfo->psWorkEstFirmwareCCBCtl;
505 IMG_UINT8 *psFWCCB = psDevInfo->psWorkEstFirmwareCCB;
507 while (psFWCCBCtl->ui32ReadOffset != psFWCCBCtl->ui32WriteOffset)
509 /* Point to the next command */
510 psFwCCBCmd = ((RGXFWIF_WORKEST_FWCCB_CMD *)psFWCCB) + psFWCCBCtl->ui32ReadOffset;
512 WorkEstWorkloadFinished(psDevInfo, psFwCCBCmd);
514 /* Update read offset */
515 psFWCCBCtl->ui32ReadOffset = (psFWCCBCtl->ui32ReadOffset + 1) & psFWCCBCtl->ui32WrapMask;