1 /*************************************************************************/ /*!
2 @Title Kernel side command queue functions
3 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
4 @License Dual MIT/GPLv2
6 The contents of this file are subject to the MIT license as set out below.
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
18 Alternatively, the contents of this file may be used under the terms of
19 the GNU General Public License Version 2 ("GPL") in which case the provisions
20 of GPL are applicable instead of those above.
22 If you wish to allow use of your version of this file only under the terms of
23 GPL, and not to allow others to use your version of this file under the terms
24 of the MIT license, indicate your decision by deleting the provisions above
25 and replace them with the notice and other provisions required by GPL as set
26 out in the file called "GPL-COPYING" included in this distribution. If you do
27 not delete the provisions above, a recipient may use your version of this file
28 under the terms of either the MIT license or GPL.
30 This License is also included in this distribution in the file called
31 "MIT-COPYING".
33 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
34 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
35 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
37 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
38 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 */ /**************************************************************************/
42 #include "services_headers.h"
43 #include "pvr_bridge_km.h"
45 #include "lists.h"
46 #include "ttrace.h"
48 #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)
49 #include <linux/version.h>
50 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))
51 #include <linux/sw_sync.h>
52 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0))
53 #include <../drivers/staging/android/sw_sync.h>
54 #else
55 #include <../drivers/dma-buf/sync_debug.h>
56 #endif
58 #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)
59 #include "pvrsrv_sync_server.h"
60 #endif
62 #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
63 #include <linux/list.h>
64 #include <linux/workqueue.h>
66 typedef struct _PVR_QUEUE_SYNC_KERNEL_SYNC_INFO_
67 {
68 /* Base services sync info structure */
69 PVRSRV_KERNEL_SYNC_INFO *psBase;
71 struct list_head sHead;
72 } PVR_QUEUE_SYNC_KERNEL_SYNC_INFO;
74 static IMG_BOOL PVRSyncIsSyncInfoInUse(PVRSRV_KERNEL_SYNC_INFO *psSyncInfo)
75 {
76 return !(psSyncInfo->psSyncData->ui32WriteOpsPending == psSyncInfo->psSyncData->ui32WriteOpsComplete &&
77 psSyncInfo->psSyncData->ui32ReadOpsPending == psSyncInfo->psSyncData->ui32ReadOpsComplete &&
78 psSyncInfo->psSyncData->ui32ReadOps2Pending == psSyncInfo->psSyncData->ui32ReadOps2Complete);
79 }
81 /* Defer Workqueue for releasing command kernel sync info */
82 static struct workqueue_struct *gpsWorkQueue;
84 /* Linux work struct for workqueue. */
85 static struct work_struct gsWork;
87 /* The "defer-free" sync object list. */
88 static LIST_HEAD(gSyncInfoFreeList);
89 static DEFINE_SPINLOCK(gSyncInfoFreeListLock);
91 static void PVRSyncWorkQueueFunction(struct work_struct *data)
92 {
93 struct list_head sFreeList, *psEntry, *n;
94 PVR_QUEUE_SYNC_KERNEL_SYNC_INFO *psSyncInfo;
96 INIT_LIST_HEAD(&sFreeList);
97 spin_lock(&gSyncInfoFreeListLock);
98 list_for_each_safe(psEntry, n, &gSyncInfoFreeList)
99 {
100 psSyncInfo = container_of(psEntry, PVR_QUEUE_SYNC_KERNEL_SYNC_INFO, sHead);
102 if(!PVRSyncIsSyncInfoInUse(psSyncInfo->psBase))
103 list_move_tail(psEntry, &sFreeList);
104 }
105 spin_unlock(&gSyncInfoFreeListLock);
107 list_for_each_safe(psEntry, n, &sFreeList)
108 {
109 psSyncInfo = container_of(psEntry, PVR_QUEUE_SYNC_KERNEL_SYNC_INFO, sHead);
111 list_del(psEntry);
113 PVRSRVKernelSyncInfoDecRef(psSyncInfo->psBase, IMG_NULL);
114 }
115 }
116 #endif
118 #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
119 static struct sync_fence *AllocQueueFence(struct sw_sync_timeline *psTimeline, IMG_UINT32 ui32FenceValue, const char *szName)
120 {
121 struct sync_fence *psFence = IMG_NULL;
122 struct sync_pt *psPt;
124 psPt = sw_sync_pt_create(psTimeline, ui32FenceValue);
125 if(psPt)
126 {
127 psFence = sync_fence_create(szName, psPt);
128 if(!psFence)
129 {
130 sync_pt_free(psPt);
131 }
132 }
134 return psFence;
135 }
136 #endif /* defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) */
138 #endif /* defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE) */
140 /*
141 * The number of commands of each type which can be in flight at once.
142 */
144 #define DC_MAX_SUPPORTED_QUEUES 1
145 #if defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED)
146 #define DC_NUM_COMMANDS_PER_QUEUE 2
147 #else
148 #define DC_NUM_COMMANDS_PER_QUEUE 1
149 #endif
151 #define DC_NUM_COMMANDS_PER_TYPE (DC_NUM_COMMANDS_PER_QUEUE * DC_MAX_SUPPORTED_QUEUES)
153 static IMG_UINT32 ui32NoOfSwapchainCreated = 0;
155 /*
156 * List of private command processing function pointer tables and command
157 * complete tables for a device in the system.
158 * Each table is allocated when the device registers its private command
159 * processing functions.
160 */
161 typedef struct _DEVICE_COMMAND_DATA_
162 {
163 PFN_CMD_PROC pfnCmdProc;
164 PCOMMAND_COMPLETE_DATA apsCmdCompleteData[DC_NUM_COMMANDS_PER_TYPE];
165 IMG_UINT32 ui32CCBOffset;
166 IMG_UINT32 ui32MaxDstSyncCount; /*!< Maximum number of dest syncs */
167 IMG_UINT32 ui32MaxSrcSyncCount; /*!< Maximum number of source syncs */
168 } DEVICE_COMMAND_DATA;
171 #if defined(__linux__) && defined(__KERNEL__)
173 #include "proc.h"
175 /*****************************************************************************
176 FUNCTION : ProcSeqShowQueue
178 PURPOSE : Print the content of queue element to /proc file
179 (See env/linux/proc.c:CreateProcReadEntrySeq)
181 PARAMETERS : sfile - /proc seq_file
182 el - Element to print
183 *****************************************************************************/
184 void ProcSeqShowQueue(struct seq_file *sfile,void* el)
185 {
186 PVRSRV_QUEUE_INFO *psQueue = (PVRSRV_QUEUE_INFO*)el;
187 IMG_INT cmds = 0;
188 IMG_SIZE_T uReadOffset;
189 IMG_SIZE_T uWriteOffset;
190 PVRSRV_COMMAND *psCmd;
192 if(el == PVR_PROC_SEQ_START_TOKEN)
193 {
194 seq_printf( sfile,
195 "Command Queues\n"
196 "Queue CmdPtr Pid Command Size DevInd DSC SSC #Data ...\n");
197 return;
198 }
200 uReadOffset = psQueue->uReadOffset;
201 uWriteOffset = psQueue->uWriteOffset;
203 while (uReadOffset != uWriteOffset)
204 {
205 psCmd= (PVRSRV_COMMAND *)((IMG_UINTPTR_T)psQueue->pvLinQueueKM + uReadOffset);
207 seq_printf(sfile, "%p %p %5u %6u %3" SIZE_T_FMT_LEN "u %5u %2u %2u %3" SIZE_T_FMT_LEN "u \n",
208 psQueue,
209 psCmd,
210 psCmd->ui32ProcessID,
211 psCmd->CommandType,
212 psCmd->uCmdSize,
213 psCmd->ui32DevIndex,
214 psCmd->ui32DstSyncCount,
215 psCmd->ui32SrcSyncCount,
216 psCmd->uDataSize);
217 {
218 IMG_UINT32 i;
219 for (i = 0; i < psCmd->ui32SrcSyncCount; i++)
220 {
221 PVRSRV_SYNC_DATA *psSyncData = psCmd->psSrcSync[i].psKernelSyncInfoKM->psSyncData;
222 seq_printf(sfile, " Sync %u: ROP/ROC: 0x%x/0x%x WOP/WOC: 0x%x/0x%x ROC-VA: 0x%x WOC-VA: 0x%x\n",
223 i,
224 psCmd->psSrcSync[i].ui32ReadOps2Pending,
225 psSyncData->ui32ReadOps2Complete,
226 psCmd->psSrcSync[i].ui32WriteOpsPending,
227 psSyncData->ui32WriteOpsComplete,
228 psCmd->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
229 psCmd->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr);
230 }
231 }
233 /* taken from UPDATE_QUEUE_ROFF in queue.h */
234 uReadOffset += psCmd->uCmdSize;
235 uReadOffset &= psQueue->uQueueSize - 1;
236 cmds++;
237 }
239 if (cmds == 0)
240 {
241 seq_printf(sfile, "%p <empty>\n", psQueue);
242 }
243 }
245 /*****************************************************************************
246 FUNCTION : ProcSeqOff2ElementQueue
248 PURPOSE : Transale offset to element (/proc stuff)
250 PARAMETERS : sfile - /proc seq_file
251 off - the offset into the buffer
253 RETURNS : element to print
254 *****************************************************************************/
255 void* ProcSeqOff2ElementQueue(struct seq_file * sfile, loff_t off)
256 {
257 PVRSRV_QUEUE_INFO *psQueue = IMG_NULL;
258 SYS_DATA *psSysData;
260 PVR_UNREFERENCED_PARAMETER(sfile);
262 if(!off)
263 {
264 return PVR_PROC_SEQ_START_TOKEN;
265 }
268 psSysData = SysAcquireDataNoCheck();
269 if (psSysData != IMG_NULL)
270 {
271 for (psQueue = psSysData->psQueueList; (((--off) > 0) && (psQueue != IMG_NULL)); psQueue = psQueue->psNextKM);
272 }
274 return psQueue;
275 }
276 #endif /* __linux__ && __KERNEL__ */
278 /*!
279 * Macro to return space in given command queue
280 */
281 #define GET_SPACE_IN_CMDQ(psQueue) \
282 ((((psQueue)->uReadOffset - (psQueue)->uWriteOffset) \
283 + ((psQueue)->uQueueSize - 1)) & ((psQueue)->uQueueSize - 1))
285 /*!
286 * Macro to Write Offset in given command queue
287 */
288 #define UPDATE_QUEUE_WOFF(psQueue, uSize) \
289 (psQueue)->uWriteOffset = ((psQueue)->uWriteOffset + (uSize)) \
290 & ((psQueue)->uQueueSize - 1);
292 /*!
293 * Check if an ops complete value has gone past the pending value.
294 * This can happen when dummy processing multiple operations, e.g. hardware recovery.
295 */
296 #define SYNCOPS_STALE(ui32OpsComplete, ui32OpsPending) \
297 ((ui32OpsComplete) >= (ui32OpsPending))
299 /*!
300 ****************************************************************************
301 @Function : PVRSRVGetWriteOpsPending
303 @Description : Gets the next operation to wait for in a sync object
305 @Input : psSyncInfo - pointer to sync information struct
306 @Input : bIsReadOp - Is this a read or write op
308 @Return : Next op value
309 *****************************************************************************/
310 #ifdef INLINE_IS_PRAGMA
311 #pragma inline(PVRSRVGetWriteOpsPending)
312 #endif
313 static INLINE
314 IMG_UINT32 PVRSRVGetWriteOpsPending(PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, IMG_BOOL bIsReadOp)
315 {
316 IMG_UINT32 ui32WriteOpsPending;
318 if(bIsReadOp)
319 {
320 ui32WriteOpsPending = psSyncInfo->psSyncData->ui32WriteOpsPending;
321 }
322 else
323 {
324 /*
325 Note: This needs to be atomic and is provided the
326 kernel driver is single threaded (non-rentrant)
327 */
328 ui32WriteOpsPending = SyncTakeWriteOp(psSyncInfo, SYNC_OP_CLASS_QUEUE);
329 }
331 return ui32WriteOpsPending;
332 }
334 /*!
335 *****************************************************************************
336 @Function : PVRSRVGetReadOpsPending
338 @Description : Gets the number of pending read ops
340 @Input : psSyncInfo - pointer to sync information struct
341 @Input : bIsReadOp - Is this a read or write op
343 @Return : Next op value
344 *****************************************************************************/
345 #ifdef INLINE_IS_PRAGMA
346 #pragma inline(PVRSRVGetReadOpsPending)
347 #endif
348 static INLINE
349 IMG_UINT32 PVRSRVGetReadOpsPending(PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, IMG_BOOL bIsReadOp)
350 {
351 IMG_UINT32 ui32ReadOpsPending;
353 if(bIsReadOp)
354 {
355 ui32ReadOpsPending = SyncTakeReadOp2(psSyncInfo, SYNC_OP_CLASS_QUEUE);
356 }
357 else
358 {
359 ui32ReadOpsPending = psSyncInfo->psSyncData->ui32ReadOps2Pending;
360 }
362 return ui32ReadOpsPending;
363 }
365 static IMG_VOID QueueDumpCmdComplete(COMMAND_COMPLETE_DATA *psCmdCompleteData,
366 IMG_UINT32 i,
367 IMG_BOOL bIsSrc)
368 {
369 PVRSRV_SYNC_OBJECT *psSyncObject;
371 psSyncObject = bIsSrc ? psCmdCompleteData->psSrcSync : psCmdCompleteData->psDstSync;
373 if (psCmdCompleteData->bInUse)
374 {
375 PVR_LOG(("\t%s %u: ROC DevVAddr:0x%X ROP:0x%x ROC:0x%x, WOC DevVAddr:0x%X WOP:0x%x WOC:0x%x",
376 bIsSrc ? "SRC" : "DEST", i,
377 psSyncObject[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
378 psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32ReadOps2Pending,
379 psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32ReadOps2Complete,
380 psSyncObject[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
381 psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32WriteOpsPending,
382 psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32WriteOpsComplete))
383 }
384 else
385 {
386 PVR_LOG(("\t%s %u: (Not in use)", bIsSrc ? "SRC" : "DEST", i))
387 }
388 }
391 static IMG_VOID QueueDumpDebugInfo_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode)
392 {
393 if (psDeviceNode->sDevId.eDeviceClass == PVRSRV_DEVICE_CLASS_DISPLAY)
394 {
395 IMG_UINT32 ui32CmdCounter, ui32SyncCounter;
396 SYS_DATA *psSysData;
397 DEVICE_COMMAND_DATA *psDeviceCommandData;
398 PCOMMAND_COMPLETE_DATA psCmdCompleteData;
400 SysAcquireData(&psSysData);
402 psDeviceCommandData = psSysData->apsDeviceCommandData[psDeviceNode->sDevId.ui32DeviceIndex];
404 if (psDeviceCommandData != IMG_NULL)
405 {
406 for (ui32CmdCounter = 0; ui32CmdCounter < DC_NUM_COMMANDS_PER_TYPE; ui32CmdCounter++)
407 {
408 psCmdCompleteData = psDeviceCommandData[DC_FLIP_COMMAND].apsCmdCompleteData[ui32CmdCounter];
410 PVR_LOG(("Flip Command Complete Data %u for display device %u:",
411 ui32CmdCounter, psDeviceNode->sDevId.ui32DeviceIndex))
413 for (ui32SyncCounter = 0;
414 ui32SyncCounter < psCmdCompleteData->ui32SrcSyncCount;
415 ui32SyncCounter++)
416 {
417 QueueDumpCmdComplete(psCmdCompleteData, ui32SyncCounter, IMG_TRUE);
418 }
420 for (ui32SyncCounter = 0;
421 ui32SyncCounter < psCmdCompleteData->ui32DstSyncCount;
422 ui32SyncCounter++)
423 {
424 QueueDumpCmdComplete(psCmdCompleteData, ui32SyncCounter, IMG_FALSE);
425 }
426 }
427 }
428 else
429 {
430 PVR_LOG(("There is no Command Complete Data for display device %u", psDeviceNode->sDevId.ui32DeviceIndex))
431 }
432 }
433 }
436 IMG_VOID QueueDumpDebugInfo(IMG_VOID)
437 {
438 SYS_DATA *psSysData;
439 SysAcquireData(&psSysData);
440 List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList, &QueueDumpDebugInfo_ForEachCb);
441 }
444 /*****************************************************************************
445 Kernel-side functions of User->Kernel transitions
446 ******************************************************************************/
448 static IMG_SIZE_T NearestPower2(IMG_SIZE_T uValue)
449 {
450 IMG_SIZE_T uTemp, uResult = 1;
452 if(!uValue)
453 return 0;
455 uTemp = uValue - 1;
456 while(uTemp)
457 {
458 uResult <<= 1;
459 uTemp >>= 1;
460 }
462 return uResult;
463 }
466 /*!
467 ******************************************************************************
469 @Function PVRSRVCreateCommandQueueKM
471 @Description
472 Creates a new command queue into which render/blt commands etc can be
473 inserted.
475 @Input uQueueSize :
477 @Output ppsQueueInfo :
479 @Return PVRSRV_ERROR :
481 ******************************************************************************/
482 IMG_EXPORT
483 PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateCommandQueueKM(IMG_SIZE_T uQueueSize,
484 PVRSRV_QUEUE_INFO **ppsQueueInfo)
485 {
486 PVRSRV_QUEUE_INFO *psQueueInfo;
487 IMG_SIZE_T uPower2QueueSize = NearestPower2(uQueueSize);
488 SYS_DATA *psSysData;
489 PVRSRV_ERROR eError;
490 IMG_HANDLE hMemBlock;
492 if (ui32NoOfSwapchainCreated >= DC_NUM_COMMANDS_PER_TYPE)
493 {
494 PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateCommandQueueKM: Swapchain already exists, increment DC_MAX_SUPPORTED_QUEUES to support more than one swapchain"));
495 return PVRSRV_ERROR_FLIP_CHAIN_EXISTS;
496 }
498 SysAcquireData(&psSysData);
500 /* allocate an internal queue info structure */
501 eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
502 sizeof(PVRSRV_QUEUE_INFO),
503 (IMG_VOID **)&psQueueInfo, &hMemBlock,
504 "Queue Info");
505 if (eError != PVRSRV_OK)
506 {
507 PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateCommandQueueKM: Failed to alloc queue struct"));
508 goto ErrorExit;
509 }
510 OSMemSet(psQueueInfo, 0, sizeof(PVRSRV_QUEUE_INFO));
512 psQueueInfo->hMemBlock[0] = hMemBlock;
513 psQueueInfo->ui32ProcessID = OSGetCurrentProcessIDKM();
515 /* allocate the command queue buffer - allow for overrun */
516 eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
517 uPower2QueueSize + PVRSRV_MAX_CMD_SIZE,
518 &psQueueInfo->pvLinQueueKM, &hMemBlock,
519 "Command Queue");
520 if (eError != PVRSRV_OK)
521 {
522 PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateCommandQueueKM: Failed to alloc queue buffer"));
523 goto ErrorExit;
524 }
526 psQueueInfo->hMemBlock[1] = hMemBlock;
527 psQueueInfo->pvLinQueueUM = psQueueInfo->pvLinQueueKM;
529 /* Sanity check: Should be zeroed by OSMemSet */
530 PVR_ASSERT(psQueueInfo->uReadOffset == 0);
531 PVR_ASSERT(psQueueInfo->uWriteOffset == 0);
533 psQueueInfo->uQueueSize = uPower2QueueSize;
535 #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
536 psQueueInfo->pvTimeline = sw_sync_timeline_create("pvr_queue_proc");
537 if(psQueueInfo->pvTimeline == IMG_NULL)
538 {
539 PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateCommandQueueKM: sw_sync_timeline_create() failed"));
540 goto ErrorExit;
541 }
542 #endif
544 /* if this is the first q, create a lock resource for the q list */
545 if (psSysData->psQueueList == IMG_NULL)
546 {
547 eError = OSCreateResource(&psSysData->sQProcessResource);
548 if (eError != PVRSRV_OK)
549 {
550 goto ErrorExit;
551 }
552 }
554 /* Ensure we don't corrupt queue list, by blocking access */
555 #if !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__)
556 eError = OSLockResourceAndBlockMISR(&psSysData->sQProcessResource,
557 KERNEL_ID);
558 #else /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
559 eError = OSLockResource(&psSysData->sQProcessResource,
560 KERNEL_ID);
561 #endif /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
562 if (eError != PVRSRV_OK)
563 {
564 goto ErrorExit;
565 }
567 psQueueInfo->psNextKM = psSysData->psQueueList;
568 psSysData->psQueueList = psQueueInfo;
570 #if !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__)
571 eError = OSUnlockResourceAndUnblockMISR(&psSysData->sQProcessResource, KERNEL_ID);
572 #else /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
573 eError = OSUnlockResource(&psSysData->sQProcessResource, KERNEL_ID);
574 #endif /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
575 if (eError != PVRSRV_OK)
576 {
577 goto ErrorExit;
578 }
580 *ppsQueueInfo = psQueueInfo;
582 #if (defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)) && defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
583 if(!ui32NoOfSwapchainCreated)
584 {
585 gpsWorkQueue = create_freezable_workqueue("flip_pvr_sync_workqueue");
586 if(!gpsWorkQueue)
587 {
588 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to create flip_pvr_sync workqueue", __func__));
589 goto ErrorExit;
590 }
591 INIT_WORK(&gsWork, PVRSyncWorkQueueFunction);
592 }
593 #endif
594 ui32NoOfSwapchainCreated++;
596 return PVRSRV_OK;
598 ErrorExit:
600 if(psQueueInfo)
601 {
602 if(psQueueInfo->pvLinQueueKM)
603 {
604 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
605 psQueueInfo->uQueueSize,
606 psQueueInfo->pvLinQueueKM,
607 psQueueInfo->hMemBlock[1]);
608 psQueueInfo->pvLinQueueKM = IMG_NULL;
609 }
611 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
612 sizeof(PVRSRV_QUEUE_INFO),
613 psQueueInfo,
614 psQueueInfo->hMemBlock[0]);
615 /*not nulling pointer, out of scope*/
616 }
618 return eError;
619 }
622 /*!
623 ******************************************************************************
625 @Function PVRSRVDestroyCommandQueueKM
627 @Description Destroys a command queue
629 @Input psQueueInfo :
631 @Return PVRSRV_ERROR
633 ******************************************************************************/
634 IMG_EXPORT
635 PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyCommandQueueKM(PVRSRV_QUEUE_INFO *psQueueInfo)
636 {
637 PVRSRV_QUEUE_INFO *psQueue;
638 SYS_DATA *psSysData;
639 PVRSRV_ERROR eError;
640 IMG_BOOL bTimeout = IMG_TRUE;
642 SysAcquireData(&psSysData);
644 psQueue = psSysData->psQueueList;
646 /* PRQA S 3415,4109 1 */ /* macro format critical - leave alone */
647 LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
648 {
649 if(psQueueInfo->uReadOffset == psQueueInfo->uWriteOffset)
650 {
651 bTimeout = IMG_FALSE;
652 break;
653 }
654 OSSleepms(1);
655 } END_LOOP_UNTIL_TIMEOUT();
657 if (bTimeout)
658 {
659 /* The command queue could not be flushed within the timeout period.
660 Allow the queue to be destroyed before returning the error code. */
661 PVR_DPF((PVR_DBG_ERROR,"PVRSRVDestroyCommandQueueKM : Failed to empty queue"));
662 eError = PVRSRV_ERROR_CANNOT_FLUSH_QUEUE;
663 goto ErrorExit;
664 }
666 /* Ensure we don't corrupt queue list, by blocking access */
667 #if !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__)
668 eError = OSLockResourceAndBlockMISR(&psSysData->sQProcessResource,
669 KERNEL_ID);
670 #else /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
671 eError = OSLockResource(&psSysData->sQProcessResource,
672 KERNEL_ID);
673 #endif /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
674 if (eError != PVRSRV_OK)
675 {
676 goto ErrorExit;
677 }
679 ui32NoOfSwapchainCreated--;
681 #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
682 sync_timeline_destroy(psQueueInfo->pvTimeline);
683 #endif
685 if(psQueue == psQueueInfo)
686 {
687 psSysData->psQueueList = psQueueInfo->psNextKM;
689 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
690 NearestPower2(psQueueInfo->uQueueSize) + PVRSRV_MAX_CMD_SIZE,
691 psQueueInfo->pvLinQueueKM,
692 psQueueInfo->hMemBlock[1]);
693 psQueueInfo->pvLinQueueKM = IMG_NULL;
694 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
695 sizeof(PVRSRV_QUEUE_INFO),
696 psQueueInfo,
697 psQueueInfo->hMemBlock[0]);
698 /* PRQA S 3199 1 */ /* see note */
699 psQueueInfo = IMG_NULL; /*it's a copy on stack, but null it because the function doesn't end right here*/
700 }
701 else
702 {
703 while(psQueue)
704 {
705 if(psQueue->psNextKM == psQueueInfo)
706 {
707 psQueue->psNextKM = psQueueInfo->psNextKM;
709 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
710 psQueueInfo->uQueueSize,
711 psQueueInfo->pvLinQueueKM,
712 psQueueInfo->hMemBlock[1]);
713 psQueueInfo->pvLinQueueKM = IMG_NULL;
714 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
715 sizeof(PVRSRV_QUEUE_INFO),
716 psQueueInfo,
717 psQueueInfo->hMemBlock[0]);
718 /* PRQA S 3199 1 */ /* see note */
719 psQueueInfo = IMG_NULL; /*it's a copy on stack, but null it because the function doesn't end right here*/
720 break;
721 }
722 psQueue = psQueue->psNextKM;
723 }
725 if(!psQueue)
726 {
727 #if !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__)
728 eError = OSUnlockResourceAndUnblockMISR(&psSysData->sQProcessResource, KERNEL_ID);
729 #else /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
730 eError = OSUnlockResource(&psSysData->sQProcessResource, KERNEL_ID);
731 #endif /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
732 if (eError != PVRSRV_OK)
733 {
734 goto ErrorExit;
735 }
736 eError = PVRSRV_ERROR_INVALID_PARAMS;
737 goto ErrorExit;
738 }
739 }
741 /* unlock the Q list lock resource */
742 #if !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__)
743 eError = OSUnlockResourceAndUnblockMISR(&psSysData->sQProcessResource, KERNEL_ID);
744 #else /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
745 eError = OSUnlockResource(&psSysData->sQProcessResource, KERNEL_ID);
746 #endif /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
747 if (eError != PVRSRV_OK)
748 {
749 goto ErrorExit;
750 }
752 /* if the Q list is now empty, destroy the Q list lock resource */
753 if (psSysData->psQueueList == IMG_NULL)
754 {
755 eError = OSDestroyResource(&psSysData->sQProcessResource);
756 if (eError != PVRSRV_OK)
757 {
758 goto ErrorExit;
759 }
760 }
762 #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) && defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
763 if(!ui32NoOfSwapchainCreated && gpsWorkQueue)
764 {
765 destroy_workqueue(gpsWorkQueue);
766 }
767 #endif
768 ErrorExit:
770 return eError;
771 }
774 /*!
775 *****************************************************************************
777 @Function : PVRSRVGetQueueSpaceKM
779 @Description : Waits for queue access rights and checks for available space in
780 queue for task param structure
782 @Input : psQueue - pointer to queue information struct
783 @Input : ui32ParamSize - size of task data structure
784 @Output : ppvSpace
786 @Return : PVRSRV_ERROR
787 *****************************************************************************/
788 IMG_EXPORT
789 PVRSRV_ERROR IMG_CALLCONV PVRSRVGetQueueSpaceKM(PVRSRV_QUEUE_INFO *psQueue,
790 IMG_SIZE_T uParamSize,
791 IMG_VOID **ppvSpace)
792 {
793 /* round to 4byte units */
794 uParamSize = (uParamSize + 3) & 0xFFFFFFFC;
796 if (uParamSize > PVRSRV_MAX_CMD_SIZE)
797 {
798 PVR_DPF((PVR_DBG_WARNING,"PVRSRVGetQueueSpace: max command size is %d bytes", PVRSRV_MAX_CMD_SIZE));
799 return PVRSRV_ERROR_CMD_TOO_BIG;
800 }
802 if (GET_SPACE_IN_CMDQ(psQueue) > uParamSize)
803 {
804 *ppvSpace = (IMG_VOID *)((IMG_UINTPTR_T)psQueue->pvLinQueueUM + psQueue->uWriteOffset);
805 }
806 else
807 {
808 *ppvSpace = IMG_NULL;
809 return PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE;
810 }
812 return PVRSRV_OK;
813 }
816 /*!
817 *****************************************************************************
818 @Function PVRSRVInsertCommandKM
820 @Description :
821 command insertion utility
822 - waits for space in the queue for a new command
823 - fills in generic command information
824 - returns a pointer to the caller who's expected to then fill
825 in the private data.
826 The caller should follow PVRSRVInsertCommand with PVRSRVSubmitCommand
827 which will update the queue's write offset so the command can be
828 executed.
830 @Input psQueue : pointer to queue information struct
832 @Output ppvCmdData : holds pointer to space in queue for private cmd data
834 @Return PVRSRV_ERROR
835 *****************************************************************************/
836 IMG_EXPORT
837 PVRSRV_ERROR IMG_CALLCONV PVRSRVInsertCommandKM(PVRSRV_QUEUE_INFO *psQueue,
838 PVRSRV_COMMAND **ppsCommand,
839 IMG_UINT32 ui32DevIndex,
840 IMG_UINT16 CommandType,
841 IMG_UINT32 ui32DstSyncCount,
842 PVRSRV_KERNEL_SYNC_INFO *apsDstSync[],
843 IMG_UINT32 ui32SrcSyncCount,
844 PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[],
845 IMG_SIZE_T uDataByteSize,
846 PFN_QUEUE_COMMAND_COMPLETE pfnCommandComplete,
847 IMG_HANDLE hCallbackData,
848 IMG_HANDLE *phFence)
849 {
850 PVRSRV_ERROR eError;
851 PVRSRV_COMMAND *psCommand;
852 IMG_SIZE_T uCommandSize;
853 IMG_UINT32 i;
854 SYS_DATA *psSysData;
855 DEVICE_COMMAND_DATA *psDeviceCommandData;
857 #if !(defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE))
858 PVR_UNREFERENCED_PARAMETER(phFence);
859 #endif
861 /* Check that we've got enough space in our command complete data for this command */
862 SysAcquireData(&psSysData);
863 psDeviceCommandData = psSysData->apsDeviceCommandData[ui32DevIndex];
865 if ((psDeviceCommandData[CommandType].ui32MaxDstSyncCount < ui32DstSyncCount) ||
866 (psDeviceCommandData[CommandType].ui32MaxSrcSyncCount < ui32SrcSyncCount))
867 {
868 PVR_DPF((PVR_DBG_ERROR, "PVRSRVInsertCommandKM: Too many syncs"));
869 return PVRSRV_ERROR_INVALID_PARAMS;
870 }
872 /* Round up to nearest 32 bit size so pointer arithmetic works */
873 uDataByteSize = (uDataByteSize + 3UL) & ~3UL;
875 /* calc. command size */
876 uCommandSize = sizeof(PVRSRV_COMMAND)
877 + ((ui32DstSyncCount + ui32SrcSyncCount) * sizeof(PVRSRV_SYNC_OBJECT))
878 + uDataByteSize;
880 /* wait for space in queue */
881 eError = PVRSRVGetQueueSpaceKM (psQueue, uCommandSize, (IMG_VOID**)&psCommand);
882 if(eError != PVRSRV_OK)
883 {
884 return eError;
885 }
887 #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
888 if(phFence != IMG_NULL)
889 {
890 struct sync_fence *psRetireFence, *psCleanupFence;
892 /* New command? New timeline target */
893 psQueue->ui32FenceValue++;
895 psRetireFence = AllocQueueFence(psQueue->pvTimeline, psQueue->ui32FenceValue, "pvr_queue_retire");
896 if(!psRetireFence)
897 {
898 PVR_DPF((PVR_DBG_ERROR, "PVRSRVInsertCommandKM: sync_fence_create() failed"));
899 psQueue->ui32FenceValue--;
900 return PVRSRV_ERROR_INVALID_PARAMS;
901 }
903 /* This similar to the retire fence, except that it is destroyed
904 * when a display command completes, rather than at the whim of
905 * userspace. It is used to keep the timeline alive.
906 */
907 psCleanupFence = AllocQueueFence(psQueue->pvTimeline, psQueue->ui32FenceValue, "pvr_queue_cleanup");
908 if(!psCleanupFence)
909 {
910 PVR_DPF((PVR_DBG_ERROR, "PVRSRVInsertCommandKM: sync_fence_create() #2 failed"));
911 sync_fence_put(psRetireFence);
912 psQueue->ui32FenceValue--;
913 return PVRSRV_ERROR_INVALID_PARAMS;
914 }
916 psCommand->pvCleanupFence = psCleanupFence;
917 psCommand->pvTimeline = psQueue->pvTimeline;
918 *phFence = psRetireFence;
919 }
920 else
921 {
922 psCommand->pvTimeline = IMG_NULL;
923 psCommand->pvCleanupFence = IMG_NULL;
924 }
925 #elif defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)
926 if(phFence != IMG_NULL)
927 {
928 struct fence *psRetireFence, *psCleanupFence;
930 SyncSWGetTimelineObj(psQueue->i32TimelineFd, &psCommand->pvTimeline);
931 if(psCommand->pvTimeline == IMG_NULL)
932 {
933 PVR_DPF((PVR_DBG_ERROR,"PVRSRVInsertCommandKM: timeline get failed"));
934 return PVRSRV_ERROR_STREAM_ERROR;
935 }
937 /* New command? New timeline target */
938 psQueue->ui32FenceValue++;
940 psRetireFence = SyncSWTimelineFenceCreateKM(psQueue->i32TimelineFd, psQueue->ui32FenceValue, "pvr_queue_retire");
941 if(!psRetireFence)
942 {
943 PVR_DPF((PVR_DBG_ERROR, "PVRSRVInsertCommandKM: sync_file_create() failed"));
944 psQueue->ui32FenceValue--;
945 return PVRSRV_ERROR_INVALID_PARAMS;
946 }
948 /* This similar to the retire fence, except that it is destroyed
949 * when a display command completes, rather than at the whim of
950 * userspace. It is used to keep the timeline alive.
951 */
952 psCleanupFence = SyncSWTimelineFenceCreateKM(psQueue->i32TimelineFd, psQueue->ui32FenceValue, "pvr_queue_cleanup");
953 if(!psCleanupFence)
954 {
955 PVR_DPF((PVR_DBG_ERROR, "PVRSRVInsertCommandKM: sync_file_create() #2 failed"));
956 SyncSWTimelineFenceReleaseKM(psRetireFence);
957 psQueue->ui32FenceValue--;
958 return PVRSRV_ERROR_INVALID_PARAMS;
959 }
961 psCommand->pvCleanupFence = psCleanupFence;
962 *phFence = psRetireFence;
963 }
964 else
965 {
966 psCommand->pvTimeline = IMG_NULL;
967 psCommand->pvCleanupFence = IMG_NULL;
968 }
970 #endif /* defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) */
972 psCommand->ui32ProcessID = OSGetCurrentProcessIDKM();
974 /* setup the command */
975 psCommand->uCmdSize = uCommandSize; /* this may change if cmd shrinks */
976 psCommand->ui32DevIndex = ui32DevIndex;
977 psCommand->CommandType = CommandType;
978 psCommand->ui32DstSyncCount = ui32DstSyncCount;
979 psCommand->ui32SrcSyncCount = ui32SrcSyncCount;
980 /* override QAC warning about stricter pointers */
981 /* PRQA S 3305 END_PTR_ASSIGNMENTS */
982 psCommand->psDstSync = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psCommand) + sizeof(PVRSRV_COMMAND));
985 psCommand->psSrcSync = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psCommand->psDstSync)
986 + (ui32DstSyncCount * sizeof(PVRSRV_SYNC_OBJECT)));
988 psCommand->pvData = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psCommand->psSrcSync)
989 + (ui32SrcSyncCount * sizeof(PVRSRV_SYNC_OBJECT)));
990 /* PRQA L:END_PTR_ASSIGNMENTS */
992 psCommand->uDataSize = uDataByteSize;/* this may change if cmd shrinks */
994 psCommand->pfnCommandComplete = pfnCommandComplete;
995 psCommand->hCallbackData = hCallbackData;
997 PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_START, QUEUE_TOKEN_INSERTKM);
998 PVR_TTRACE_UI32(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_NONE,
999 QUEUE_TOKEN_COMMAND_TYPE, CommandType);
1001 /* setup dst sync objects and their sync dependencies */
1002 for (i=0; i<ui32DstSyncCount; i++)
1003 {
1004 #if (defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)) && defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
1005 PVR_QUEUE_SYNC_KERNEL_SYNC_INFO *psQueueSync = (PVR_QUEUE_SYNC_KERNEL_SYNC_INFO*)kmalloc(sizeof(PVR_QUEUE_SYNC_KERNEL_SYNC_INFO),GFP_KERNEL);
1006 psQueueSync->psBase = apsDstSync[i];
1007 spin_lock(&gSyncInfoFreeListLock);
1008 list_add_tail(&psQueueSync->sHead, &gSyncInfoFreeList);
1009 spin_unlock(&gSyncInfoFreeListLock);
1010 #endif
1011 PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_DST_SYNC,
1012 apsDstSync[i], PVRSRV_SYNCOP_SAMPLE);
1014 psCommand->psDstSync[i].psKernelSyncInfoKM = apsDstSync[i];
1015 psCommand->psDstSync[i].ui32WriteOpsPending = PVRSRVGetWriteOpsPending(apsDstSync[i], IMG_FALSE);
1016 psCommand->psDstSync[i].ui32ReadOps2Pending = PVRSRVGetReadOpsPending(apsDstSync[i], IMG_FALSE);
1018 PVRSRVKernelSyncInfoIncRef(apsDstSync[i], IMG_NULL);
1020 PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVInsertCommandKM: Dst %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x",
1021 i, psCommand->psDstSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
1022 psCommand->psDstSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
1023 psCommand->psDstSync[i].ui32ReadOps2Pending,
1024 psCommand->psDstSync[i].ui32WriteOpsPending));
1025 }
1027 /* setup src sync objects and their sync dependencies */
1028 for (i=0; i<ui32SrcSyncCount; i++)
1029 {
1030 #if (defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)) && defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
1031 PVR_QUEUE_SYNC_KERNEL_SYNC_INFO *psQueueSync = (PVR_QUEUE_SYNC_KERNEL_SYNC_INFO*)kmalloc(sizeof(PVR_QUEUE_SYNC_KERNEL_SYNC_INFO),GFP_KERNEL);
1032 psQueueSync->psBase = apsSrcSync[i];
1033 spin_lock(&gSyncInfoFreeListLock);
1034 list_add_tail(&psQueueSync->sHead, &gSyncInfoFreeList);
1035 spin_unlock(&gSyncInfoFreeListLock);
1036 #endif
1038 PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_DST_SYNC,
1039 apsSrcSync[i], PVRSRV_SYNCOP_SAMPLE);
1041 psCommand->psSrcSync[i].psKernelSyncInfoKM = apsSrcSync[i];
1042 psCommand->psSrcSync[i].ui32WriteOpsPending = PVRSRVGetWriteOpsPending(apsSrcSync[i], IMG_TRUE);
1043 psCommand->psSrcSync[i].ui32ReadOps2Pending = PVRSRVGetReadOpsPending(apsSrcSync[i], IMG_TRUE);
1045 PVRSRVKernelSyncInfoIncRef(apsSrcSync[i], IMG_NULL);
1047 PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVInsertCommandKM: Src %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x",
1048 i, psCommand->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
1049 psCommand->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
1050 psCommand->psSrcSync[i].ui32ReadOps2Pending,
1051 psCommand->psSrcSync[i].ui32WriteOpsPending));
1052 }
1053 PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_END, QUEUE_TOKEN_INSERTKM);
1055 /* return pointer to caller to fill out private data */
1056 *ppsCommand = psCommand;
1058 return PVRSRV_OK;
1059 }
1062 /*!
1063 *******************************************************************************
1064 @Function : PVRSRVSubmitCommandKM
1066 @Description :
1067 updates the queue's write offset so the command can be executed.
1069 @Input : psQueue - queue command is in
1070 @Input : psCommand
1072 @Return : PVRSRV_ERROR
1073 ******************************************************************************/
1074 IMG_EXPORT
1075 PVRSRV_ERROR IMG_CALLCONV PVRSRVSubmitCommandKM(PVRSRV_QUEUE_INFO *psQueue,
1076 PVRSRV_COMMAND *psCommand)
1077 {
1078 /* override QAC warnings about stricter pointers */
1079 /* PRQA S 3305 END_PTR_ASSIGNMENTS2 */
1080 /* patch pointers in the command to be kernel pointers */
1081 if (psCommand->ui32DstSyncCount > 0)
1082 {
1083 psCommand->psDstSync = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psQueue->pvLinQueueKM)
1084 + psQueue->uWriteOffset + sizeof(PVRSRV_COMMAND));
1085 }
1087 if (psCommand->ui32SrcSyncCount > 0)
1088 {
1089 psCommand->psSrcSync = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psQueue->pvLinQueueKM)
1090 + psQueue->uWriteOffset + sizeof(PVRSRV_COMMAND)
1091 + (psCommand->ui32DstSyncCount * sizeof(PVRSRV_SYNC_OBJECT)));
1092 }
1094 psCommand->pvData = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psQueue->pvLinQueueKM)
1095 + psQueue->uWriteOffset + sizeof(PVRSRV_COMMAND)
1096 + (psCommand->ui32DstSyncCount * sizeof(PVRSRV_SYNC_OBJECT))
1097 + (psCommand->ui32SrcSyncCount * sizeof(PVRSRV_SYNC_OBJECT)));
1099 /* PRQA L:END_PTR_ASSIGNMENTS2 */
1101 /* update write offset before releasing access lock */
1102 UPDATE_QUEUE_WOFF(psQueue, psCommand->uCmdSize);
1104 return PVRSRV_OK;
1105 }
1107 /*!
1108 ******************************************************************************
1110 @Function CheckIfSyncIsQueued
1112 @Description Check if the specificed sync object is already queued and
1113 can safely be given to the display controller.
1114 This check is required as a 3rd party displayclass device can
1115 have several flips "in flight" and we need to ensure that we
1116 keep their pipeline full and don't deadlock waiting for them
1117 to complete an operation on a surface.
1119 @Input psSysData : system data
1120 @Input psCmdData : COMMAND_COMPLETE_DATA structure
1122 @Return PVRSRV_ERROR
1124 ******************************************************************************/
1125 static
1126 PVRSRV_ERROR CheckIfSyncIsQueued(PVRSRV_SYNC_OBJECT *psSync, COMMAND_COMPLETE_DATA *psCmdData)
1127 {
1128 IMG_UINT32 k;
1130 if (psCmdData->bInUse)
1131 {
1132 for (k=0;k<psCmdData->ui32SrcSyncCount;k++)
1133 {
1134 if (psSync->psKernelSyncInfoKM == psCmdData->psSrcSync[k].psKernelSyncInfoKM)
1135 {
1136 PVRSRV_SYNC_DATA *psSyncData = psSync->psKernelSyncInfoKM->psSyncData;
1137 IMG_UINT32 ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete;
1139 /*
1140 We still need to ensure that we don't we don't give a command
1141 to the display controller if writes are outstanding on it
1142 */
1143 if (ui32WriteOpsComplete == psSync->ui32WriteOpsPending)
1144 {
1145 return PVRSRV_OK;
1146 }
1147 else
1148 {
1149 if (SYNCOPS_STALE(ui32WriteOpsComplete, psSync->ui32WriteOpsPending))
1150 {
1151 PVR_DPF((PVR_DBG_WARNING,
1152 "CheckIfSyncIsQueued: Stale syncops psSyncData:0x%p ui32WriteOpsComplete:0x%x ui32WriteOpsPending:0x%x",
1153 psSyncData, ui32WriteOpsComplete, psSync->ui32WriteOpsPending));
1154 return PVRSRV_OK;
1155 }
1156 }
1157 }
1158 }
1159 }
1160 return PVRSRV_ERROR_FAILED_DEPENDENCIES;
1161 }
1163 /*!
1164 ******************************************************************************
1166 @Function PVRSRVProcessCommand
1168 @Description Tries to process a command
1170 @Input psSysData : system data
1171 @Input psCommand : PVRSRV_COMMAND structure
1172 @Input bFlush : Check for stale dependencies (only used for HW recovery)
1174 @Return PVRSRV_ERROR
1176 ******************************************************************************/
1177 static
1178 PVRSRV_ERROR PVRSRVProcessCommand(SYS_DATA *psSysData,
1179 PVRSRV_COMMAND *psCommand,
1180 IMG_BOOL bFlush)
1181 {
1182 PVRSRV_SYNC_OBJECT *psWalkerObj;
1183 PVRSRV_SYNC_OBJECT *psEndObj;
1184 IMG_UINT32 i;
1185 COMMAND_COMPLETE_DATA *psCmdCompleteData;
1186 PVRSRV_ERROR eError = PVRSRV_OK;
1187 IMG_UINT32 ui32WriteOpsComplete;
1188 IMG_UINT32 ui32ReadOpsComplete;
1189 DEVICE_COMMAND_DATA *psDeviceCommandData;
1190 IMG_UINT32 ui32CCBOffset;
1192 /* satisfy sync dependencies on the DST(s) */
1193 psWalkerObj = psCommand->psDstSync;
1194 psEndObj = psWalkerObj + psCommand->ui32DstSyncCount;
1195 while (psWalkerObj < psEndObj)
1196 {
1197 PVRSRV_SYNC_DATA *psSyncData = psWalkerObj->psKernelSyncInfoKM->psSyncData;
1199 ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete;
1200 ui32ReadOpsComplete = psSyncData->ui32ReadOps2Complete;
1201 /* fail if reads or writes are not up to date */
1202 if ((ui32WriteOpsComplete != psWalkerObj->ui32WriteOpsPending)
1203 || (ui32ReadOpsComplete != psWalkerObj->ui32ReadOps2Pending))
1204 {
1205 if (!bFlush ||
1206 !SYNCOPS_STALE(ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending) ||
1207 !SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOps2Pending))
1208 {
1209 return PVRSRV_ERROR_FAILED_DEPENDENCIES;
1210 }
1211 }
1213 psWalkerObj++;
1214 }
1216 /* satisfy sync dependencies on the SRC(s) */
1217 psWalkerObj = psCommand->psSrcSync;
1218 psEndObj = psWalkerObj + psCommand->ui32SrcSyncCount;
1219 while (psWalkerObj < psEndObj)
1220 {
1221 PVRSRV_SYNC_DATA *psSyncData = psWalkerObj->psKernelSyncInfoKM->psSyncData;
1223 ui32ReadOpsComplete = psSyncData->ui32ReadOps2Complete;
1224 ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete;
1225 /* fail if writes are not up to date */
1226 if ((ui32WriteOpsComplete != psWalkerObj->ui32WriteOpsPending)
1227 || (ui32ReadOpsComplete != psWalkerObj->ui32ReadOps2Pending))
1228 {
1229 if (!bFlush &&
1230 SYNCOPS_STALE(ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending) &&
1231 SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOps2Pending))
1232 {
1233 PVR_DPF((PVR_DBG_WARNING,
1234 "PVRSRVProcessCommand: Stale syncops psSyncData:0x%p ui32WriteOpsComplete:0x%x ui32WriteOpsPending:0x%x",
1235 psSyncData, ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending));
1236 }
1238 if (!bFlush ||
1239 !SYNCOPS_STALE(ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending) ||
1240 !SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOps2Pending))
1241 {
1242 IMG_UINT32 j;
1243 PVRSRV_ERROR eError;
1244 IMG_BOOL bFound = IMG_FALSE;
1246 psDeviceCommandData = psSysData->apsDeviceCommandData[psCommand->ui32DevIndex];
1247 for (j=0;j<DC_NUM_COMMANDS_PER_TYPE;j++)
1248 {
1249 eError = CheckIfSyncIsQueued(psWalkerObj, psDeviceCommandData[psCommand->CommandType].apsCmdCompleteData[j]);
1251 if (eError == PVRSRV_OK)
1252 {
1253 bFound = IMG_TRUE;
1254 }
1255 }
1256 if (!bFound)
1257 return PVRSRV_ERROR_FAILED_DEPENDENCIES;
1258 }
1259 }
1260 psWalkerObj++;
1261 }
1263 /* validate device type */
1264 if (psCommand->ui32DevIndex >= SYS_DEVICE_COUNT)
1265 {
1266 PVR_DPF((PVR_DBG_ERROR,
1267 "PVRSRVProcessCommand: invalid DeviceType 0x%x",
1268 psCommand->ui32DevIndex));
1269 return PVRSRV_ERROR_INVALID_PARAMS;
1270 }
1272 /* fish out the appropriate storage structure for the duration of the command */
1273 psDeviceCommandData = psSysData->apsDeviceCommandData[psCommand->ui32DevIndex];
1274 ui32CCBOffset = psDeviceCommandData[psCommand->CommandType].ui32CCBOffset;
1275 psCmdCompleteData = psDeviceCommandData[psCommand->CommandType].apsCmdCompleteData[ui32CCBOffset];
1276 if (psCmdCompleteData->bInUse)
1277 {
1278 /* can use this to protect against concurrent execution of same command */
1279 return PVRSRV_ERROR_FAILED_DEPENDENCIES;
1280 }
1282 /* mark the structure as in use */
1283 psCmdCompleteData->bInUse = IMG_TRUE;
1285 /* copy src updates over */
1286 psCmdCompleteData->ui32DstSyncCount = psCommand->ui32DstSyncCount;
1287 for (i=0; i<psCommand->ui32DstSyncCount; i++)
1288 {
1289 psCmdCompleteData->psDstSync[i] = psCommand->psDstSync[i];
1291 PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVProcessCommand: Dst %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x (CCB:%u)",
1292 i, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
1293 psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
1294 psCmdCompleteData->psDstSync[i].ui32ReadOps2Pending,
1295 psCmdCompleteData->psDstSync[i].ui32WriteOpsPending,
1296 ui32CCBOffset));
1297 }
1299 psCmdCompleteData->pfnCommandComplete = psCommand->pfnCommandComplete;
1300 psCmdCompleteData->hCallbackData = psCommand->hCallbackData;
1302 #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)
1303 psCmdCompleteData->pvCleanupFence = psCommand->pvCleanupFence;
1304 psCmdCompleteData->pvTimeline = psCommand->pvTimeline;
1305 #endif
1307 /* copy dst updates over */
1308 psCmdCompleteData->ui32SrcSyncCount = psCommand->ui32SrcSyncCount;
1309 for (i=0; i<psCommand->ui32SrcSyncCount; i++)
1310 {
1311 psCmdCompleteData->psSrcSync[i] = psCommand->psSrcSync[i];
1313 PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVProcessCommand: Src %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x (CCB:%u)",
1314 i, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
1315 psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
1316 psCmdCompleteData->psSrcSync[i].ui32ReadOps2Pending,
1317 psCmdCompleteData->psSrcSync[i].ui32WriteOpsPending,
1318 ui32CCBOffset));
1319 }
1321 /*
1322 call the cmd specific handler:
1323 it should:
1324 - check the cmd specific dependencies
1325 - setup private cmd complete structure
1326 - execute cmd on HW
1327 - store psCmdCompleteData `cookie' and later pass as
1328 argument to Generic Command Complete Callback
1330 n.b. ui32DataSize (packet size) is useful for packet validation
1331 */
1332 if (psDeviceCommandData[psCommand->CommandType].pfnCmdProc((IMG_HANDLE)psCmdCompleteData,
1333 (IMG_UINT32)psCommand->uDataSize,
1334 psCommand->pvData) == IMG_FALSE)
1335 {
1336 /*
1337 clean-up:
1338 free cmd complete structure
1339 */
1340 psCmdCompleteData->bInUse = IMG_FALSE;
1341 eError = PVRSRV_ERROR_CMD_NOT_PROCESSED;
1342 PVR_LOG(("Failed to submit command from queue processor, this could cause sync wedge!"));
1343 }
1344 else
1345 {
1346 /* Increment the CCB offset */
1347 psDeviceCommandData[psCommand->CommandType].ui32CCBOffset = (ui32CCBOffset + 1) % DC_NUM_COMMANDS_PER_TYPE;
1348 }
1350 return eError;
1351 }
1354 static IMG_VOID PVRSRVProcessQueues_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode)
1355 {
1356 if (psDeviceNode->bReProcessDeviceCommandComplete &&
1357 psDeviceNode->pfnDeviceCommandComplete != IMG_NULL)
1358 {
1359 (*psDeviceNode->pfnDeviceCommandComplete)(psDeviceNode);
1360 }
1361 }
1363 /*!
1364 ******************************************************************************
1366 @Function PVRSRVProcessQueues
1368 @Description Tries to process a command from each Q
1370 @input ui32CallerID - used to distinguish between async ISR/DPC type calls
1371 the synchronous services driver
1372 @input bFlush - flush commands with stale dependencies (only used for HW recovery)
1374 @Return PVRSRV_ERROR
1376 ******************************************************************************/
1378 IMG_EXPORT
1379 PVRSRV_ERROR PVRSRVProcessQueues(IMG_BOOL bFlush)
1380 {
1381 PVRSRV_QUEUE_INFO *psQueue;
1382 SYS_DATA *psSysData;
1383 PVRSRV_COMMAND *psCommand;
1384 /* PVRSRV_DEVICE_NODE *psDeviceNode;*/
1386 SysAcquireData(&psSysData);
1388 /* Ensure we don't corrupt queue list, by blocking access. This is required for OSs where
1389 multiple ISR threads may exist simultaneously (eg WinXP DPC routines)
1390 */
1391 if (psSysData->psQueueList == IMG_NULL)
1392 {
1393 PVR_DPF((PVR_DBG_MESSAGE,"No Queues installed - cannot process commands"));
1394 return PVRSRV_OK;
1395 }
1397 #if !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__)
1398 while (OSLockResourceAndBlockMISR(&psSysData->sQProcessResource, ISR_ID) != PVRSRV_OK)
1399 #else /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
1400 while (OSLockResource(&psSysData->sQProcessResource, ISR_ID) != PVRSRV_OK)
1401 #endif /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
1402 {
1403 OSWaitus(1);
1404 };
1406 psQueue = psSysData->psQueueList;
1408 if(!psQueue)
1409 {
1410 PVR_DPF((PVR_DBG_MESSAGE,"No Queues installed - cannot process commands"));
1411 }
1413 if (bFlush)
1414 {
1415 PVRSRVSetDCState(DC_STATE_FLUSH_COMMANDS);
1416 }
1418 while (psQueue)
1419 {
1420 while (psQueue->uReadOffset != psQueue->uWriteOffset)
1421 {
1422 psCommand = (PVRSRV_COMMAND*)((IMG_UINTPTR_T)psQueue->pvLinQueueKM + psQueue->uReadOffset);
1424 if (PVRSRVProcessCommand(psSysData, psCommand, bFlush) == PVRSRV_OK)
1425 {
1426 /* processed cmd so update queue */
1427 UPDATE_QUEUE_ROFF(psQueue, psCommand->uCmdSize)
1428 continue;
1429 }
1431 break;
1432 }
1433 psQueue = psQueue->psNextKM;
1434 }
1436 if (bFlush)
1437 {
1438 PVRSRVSetDCState(DC_STATE_NO_FLUSH_COMMANDS);
1439 }
1441 /* Re-process command complete handlers if necessary. */
1442 List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList,
1443 &PVRSRVProcessQueues_ForEachCb);
1445 #if !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__)
1446 OSUnlockResourceAndUnblockMISR(&psSysData->sQProcessResource, ISR_ID);
1447 #else /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
1448 OSUnlockResource(&psSysData->sQProcessResource, ISR_ID);
1449 #endif /* !defined(PVR_LINUX_USING_WORKQUEUES) && defined(__linux__) */
1451 return PVRSRV_OK;
1452 }
1454 #if defined(SYS_OMAP_HAS_DVFS_FRAMEWORK)
1455 extern void sgxfreq_notif_sgx_frame_done(void);
1456 #endif /* (SYS_OMAP4_HAS_DVFS_FRAMEWORK) */
1458 /*!
1459 ******************************************************************************
1461 @Function PVRSRVCommandCompleteKM
1463 @Description Updates non-private command complete sync objects
1465 @Input hCmdCookie : command cookie
1466 @Input bScheduleMISR : boolean to schedule MISR
1468 @Return PVRSRV_ERROR
1470 ******************************************************************************/
1471 IMG_EXPORT
1472 IMG_VOID PVRSRVCommandCompleteKM(IMG_HANDLE hCmdCookie,
1473 IMG_BOOL bScheduleMISR)
1474 {
1475 IMG_UINT32 i;
1476 COMMAND_COMPLETE_DATA *psCmdCompleteData = (COMMAND_COMPLETE_DATA *)hCmdCookie;
1477 SYS_DATA *psSysData;
1479 #if defined(SYS_OMAP_HAS_DVFS_FRAMEWORK)
1480 sgxfreq_notif_sgx_frame_done();
1481 #endif /* (SYS_OMAP_HAS_DVFS_FRAMEWORK) */
1483 SysAcquireData(&psSysData);
1485 PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_COMP_START,
1486 QUEUE_TOKEN_COMMAND_COMPLETE);
1488 /* update DST(s) syncs */
1489 for (i=0; i<psCmdCompleteData->ui32DstSyncCount; i++)
1490 {
1491 psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->psSyncData->ui32WriteOpsComplete++;
1493 #if !((defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)) && defined(DEBUG_LINUX_MEMORY_ALLOCATIONS))
1494 PVRSRVKernelSyncInfoDecRef(psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM, IMG_NULL);
1495 #endif
1497 PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_UPDATE_DST,
1498 psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM,
1499 PVRSRV_SYNCOP_COMPLETE);
1501 PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVCommandCompleteKM: Dst %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x",
1502 i, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
1503 psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
1504 psCmdCompleteData->psDstSync[i].ui32ReadOps2Pending,
1505 psCmdCompleteData->psDstSync[i].ui32WriteOpsPending));
1506 }
1508 /* update SRC(s) syncs */
1509 for (i=0; i<psCmdCompleteData->ui32SrcSyncCount; i++)
1510 {
1511 psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->psSyncData->ui32ReadOps2Complete++;
1513 #if !((defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)) && defined(DEBUG_LINUX_MEMORY_ALLOCATIONS))
1514 PVRSRVKernelSyncInfoDecRef(psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM, IMG_NULL);
1515 #endif
1517 PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_UPDATE_SRC,
1518 psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM,
1519 PVRSRV_SYNCOP_COMPLETE);
1521 PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVCommandCompleteKM: Src %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x",
1522 i, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
1523 psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
1524 psCmdCompleteData->psSrcSync[i].ui32ReadOps2Pending,
1525 psCmdCompleteData->psSrcSync[i].ui32WriteOpsPending));
1526 }
1528 #if (defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) || defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)) && defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
1529 if(psCmdCompleteData->ui32DstSyncCount || psCmdCompleteData->ui32SrcSyncCount)
1530 {
1531 /* Add work to worker thread for checking and freeing of kernel sync */
1532 queue_work(gpsWorkQueue, &gsWork);
1533 }
1534 #endif
1536 PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_COMP_END,
1537 QUEUE_TOKEN_COMMAND_COMPLETE);
1539 if (psCmdCompleteData->pfnCommandComplete)
1540 {
1541 psCmdCompleteData->pfnCommandComplete(psCmdCompleteData->hCallbackData);
1542 }
1544 #if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
1545 if(psCmdCompleteData->pvTimeline)
1546 {
1547 sw_sync_timeline_inc(psCmdCompleteData->pvTimeline, 1);
1548 sync_fence_put(psCmdCompleteData->pvCleanupFence);
1549 }
1550 #elif defined(PVR_ANDROID_NATIVE_WINDOW_HAS_FENCE)
1551 if(psCmdCompleteData->pvTimeline)
1552 {
1553 SyncSWTimelineAdvanceKM(psCmdCompleteData->pvTimeline);
1554 SyncSWTimelineReleaseKM(psCmdCompleteData->pvTimeline);
1555 psCmdCompleteData->pvTimeline = IMG_NULL;
1557 psCmdCompleteData->pvCleanupFence = IMG_NULL;
1558 }
1559 #endif /* defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC) */
1561 /* free command complete storage */
1562 psCmdCompleteData->bInUse = IMG_FALSE;
1564 /* FIXME: This may cause unrelated devices to be woken up. */
1565 PVRSRVScheduleDeviceCallbacks();
1567 if(bScheduleMISR)
1568 {
1569 OSScheduleMISR(psSysData);
1570 }
1571 }
1574 /*!
1575 ******************************************************************************
1577 @Function PVRSRVRegisterCmdProcListKM
1579 @Description
1581 registers a list of private command processing functions with the Command
1582 Queue Manager
1584 @Input ui32DevIndex : device index
1586 @Input ppfnCmdProcList : function ptr table of private command processors
1588 @Input ui32MaxSyncsPerCmd : max number of syncobjects used by command
1590 @Input ui32CmdCount : number of entries in function ptr table
1592 @Return PVRSRV_ERROR
1594 ******************************************************************************/
1595 IMG_EXPORT
1596 PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(IMG_UINT32 ui32DevIndex,
1597 PFN_CMD_PROC *ppfnCmdProcList,
1598 IMG_UINT32 ui32MaxSyncsPerCmd[][2],
1599 IMG_UINT32 ui32CmdCount)
1600 {
1601 SYS_DATA *psSysData;
1602 PVRSRV_ERROR eError;
1603 IMG_UINT32 ui32CmdCounter, ui32CmdTypeCounter;
1604 IMG_SIZE_T ui32AllocSize;
1605 DEVICE_COMMAND_DATA *psDeviceCommandData;
1606 COMMAND_COMPLETE_DATA *psCmdCompleteData;
1608 /* validate device type */
1609 if(ui32DevIndex >= SYS_DEVICE_COUNT)
1610 {
1611 PVR_DPF((PVR_DBG_ERROR,
1612 "PVRSRVRegisterCmdProcListKM: invalid DeviceType 0x%x",
1613 ui32DevIndex));
1614 return PVRSRV_ERROR_INVALID_PARAMS;
1615 }
1617 /* acquire system data structure */
1618 SysAcquireData(&psSysData);
1620 /* array of pointers for each command store */
1621 ui32AllocSize = ui32CmdCount * sizeof(*psDeviceCommandData);
1622 eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
1623 ui32AllocSize,
1624 (IMG_VOID **)&psDeviceCommandData, IMG_NULL,
1625 "Array of Pointers for Command Store");
1626 if (eError != PVRSRV_OK)
1627 {
1628 PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterCmdProcListKM: Failed to alloc CC data"));
1629 goto ErrorExit;
1630 }
1632 psSysData->apsDeviceCommandData[ui32DevIndex] = psDeviceCommandData;
1634 for (ui32CmdTypeCounter = 0; ui32CmdTypeCounter < ui32CmdCount; ui32CmdTypeCounter++)
1635 {
1636 psDeviceCommandData[ui32CmdTypeCounter].pfnCmdProc = ppfnCmdProcList[ui32CmdTypeCounter];
1637 psDeviceCommandData[ui32CmdTypeCounter].ui32CCBOffset = 0;
1638 psDeviceCommandData[ui32CmdTypeCounter].ui32MaxDstSyncCount = ui32MaxSyncsPerCmd[ui32CmdTypeCounter][0];
1639 psDeviceCommandData[ui32CmdTypeCounter].ui32MaxSrcSyncCount = ui32MaxSyncsPerCmd[ui32CmdTypeCounter][1];
1640 for (ui32CmdCounter = 0; ui32CmdCounter < DC_NUM_COMMANDS_PER_TYPE; ui32CmdCounter++)
1641 {
1642 /*
1643 allocate storage for the sync update on command complete
1644 */
1645 ui32AllocSize = sizeof(COMMAND_COMPLETE_DATA) /* space for one GENERIC_CMD_COMPLETE */
1646 + ((ui32MaxSyncsPerCmd[ui32CmdTypeCounter][0]
1647 + ui32MaxSyncsPerCmd[ui32CmdTypeCounter][1])
1648 * sizeof(PVRSRV_SYNC_OBJECT)); /* space for max sync objects */
1650 eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
1651 ui32AllocSize,
1652 (IMG_VOID **)&psCmdCompleteData,
1653 IMG_NULL,
1654 "Command Complete Data");
1655 if (eError != PVRSRV_OK)
1656 {
1657 PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterCmdProcListKM: Failed to alloc cmd %d", ui32CmdTypeCounter));
1658 goto ErrorExit;
1659 }
1661 psDeviceCommandData[ui32CmdTypeCounter].apsCmdCompleteData[ui32CmdCounter] = psCmdCompleteData;
1663 /* clear memory */
1664 OSMemSet(psCmdCompleteData, 0x00, ui32AllocSize);
1666 /* setup sync pointers */
1667 psCmdCompleteData->psDstSync = (PVRSRV_SYNC_OBJECT*)
1668 (((IMG_UINTPTR_T)psCmdCompleteData)
1669 + sizeof(COMMAND_COMPLETE_DATA));
1670 psCmdCompleteData->psSrcSync = (PVRSRV_SYNC_OBJECT*)
1671 (((IMG_UINTPTR_T)psCmdCompleteData->psDstSync)
1672 + (sizeof(PVRSRV_SYNC_OBJECT) * ui32MaxSyncsPerCmd[ui32CmdTypeCounter][0]));
1674 psCmdCompleteData->ui32AllocSize = (IMG_UINT32)ui32AllocSize;
1675 }
1676 }
1678 return PVRSRV_OK;
1680 ErrorExit:
1682 /* clean-up if things went wrong */
1683 if (PVRSRVRemoveCmdProcListKM(ui32DevIndex, ui32CmdCount) != PVRSRV_OK)
1684 {
1685 PVR_DPF((PVR_DBG_ERROR,
1686 "PVRSRVRegisterCmdProcListKM: Failed to clean up after error, device 0x%x",
1687 ui32DevIndex));
1688 }
1690 return eError;
1691 }
1694 /*!
1695 ******************************************************************************
1697 @Function PVRSRVRemoveCmdProcListKM
1699 @Description
1701 removes a list of private command processing functions and data from the
1702 Queue Manager
1704 @Input ui32DevIndex : device index
1706 @Input ui32CmdCount : number of entries in function ptr table
1708 @Return PVRSRV_ERROR
1710 ******************************************************************************/
1711 IMG_EXPORT
1712 PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(IMG_UINT32 ui32DevIndex,
1713 IMG_UINT32 ui32CmdCount)
1714 {
1715 SYS_DATA *psSysData;
1716 IMG_UINT32 ui32CmdTypeCounter, ui32CmdCounter;
1717 DEVICE_COMMAND_DATA *psDeviceCommandData;
1718 COMMAND_COMPLETE_DATA *psCmdCompleteData;
1719 IMG_SIZE_T ui32AllocSize;
1721 /* validate device type */
1722 if(ui32DevIndex >= SYS_DEVICE_COUNT)
1723 {
1724 PVR_DPF((PVR_DBG_ERROR,
1725 "PVRSRVRemoveCmdProcListKM: invalid DeviceType 0x%x",
1726 ui32DevIndex));
1727 return PVRSRV_ERROR_INVALID_PARAMS;
1728 }
1730 /* acquire system data structure */
1731 SysAcquireData(&psSysData);
1733 psDeviceCommandData = psSysData->apsDeviceCommandData[ui32DevIndex];
1734 if(psDeviceCommandData != IMG_NULL)
1735 {
1736 for (ui32CmdTypeCounter = 0; ui32CmdTypeCounter < ui32CmdCount; ui32CmdTypeCounter++)
1737 {
1738 for (ui32CmdCounter = 0; ui32CmdCounter < DC_NUM_COMMANDS_PER_TYPE; ui32CmdCounter++)
1739 {
1740 psCmdCompleteData = psDeviceCommandData[ui32CmdTypeCounter].apsCmdCompleteData[ui32CmdCounter];
1742 /* free the cmd complete structure array entries */
1743 if (psCmdCompleteData != IMG_NULL)
1744 {
1745 PVR_ASSERT(psCmdCompleteData->bInUse == IMG_FALSE);
1746 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, psCmdCompleteData->ui32AllocSize,
1747 psCmdCompleteData, IMG_NULL);
1748 psDeviceCommandData[ui32CmdTypeCounter].apsCmdCompleteData[ui32CmdCounter] = IMG_NULL;
1749 }
1750 }
1751 }
1753 /* free the cmd complete structure array for the device */
1754 ui32AllocSize = ui32CmdCount * sizeof(*psDeviceCommandData);
1755 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, ui32AllocSize, psDeviceCommandData, IMG_NULL);
1756 psSysData->apsDeviceCommandData[ui32DevIndex] = IMG_NULL;
1757 }
1759 return PVRSRV_OK;
1760 }
1762 /******************************************************************************
1763 End of file (queue.c)
1764 ******************************************************************************/