meego-device-adaptation import version
[sgx.git] / pvr / queue.c
1 /**********************************************************************
2  *
3  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful but, except
10  * as otherwise stated in writing, without any warranty; without even the
11  * implied warranty of merchantability or fitness for a particular purpose.
12  * See the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
24  *
25  ******************************************************************************/
26
27 #include "services_headers.h"
28
29 #include "proc.h"
30
31 static int QueuePrintCommands(struct PVRSRV_QUEUE_INFO *psQueue, char *buffer,
32                               size_t size)
33 {
34         off_t off = 0;
35         int cmds = 0;
36         u32 ui32ReadOffset = psQueue->ui32ReadOffset;
37         u32 ui32WriteOffset = psQueue->ui32WriteOffset;
38         struct PVRSRV_COMMAND *psCmd;
39
40         while (ui32ReadOffset != ui32WriteOffset) {
41                 psCmd = (struct PVRSRV_COMMAND *)((u32) psQueue->pvLinQueueKM +
42                                         ui32ReadOffset);
43
44                 off = printAppend(buffer, size, off,
45                         "%p %p  %5u  %6u  %3u  %5u   %2u   %2u    %3u  \n",
46                                 psQueue, psCmd, psCmd->ui32ProcessID,
47                                 psCmd->CommandType, psCmd->ui32CmdSize,
48                                 psCmd->ui32DevIndex, psCmd->ui32DstSyncCount,
49                                 psCmd->ui32SrcSyncCount, psCmd->ui32DataSize);
50
51                 ui32ReadOffset += psCmd->ui32CmdSize;
52                 ui32ReadOffset &= psQueue->ui32QueueSize - 1;
53                 cmds++;
54         }
55         if (cmds == 0)
56                 off = printAppend(buffer, size, off, "%p <empty>\n", psQueue);
57         return off;
58 }
59
60 off_t QueuePrintQueues(char *buffer, size_t size, off_t off)
61 {
62         struct SYS_DATA *psSysData;
63         struct PVRSRV_QUEUE_INFO *psQueue;
64
65         if (SysAcquireData(&psSysData) != PVRSRV_OK)
66                 return END_OF_FILE;
67
68         if (!off)
69                 return printAppend(buffer, size, 0,
70                         "Command Queues\nQueue    CmdPtr      "
71                            "Pid Command Size DevInd  DSC  SSC  #Data ...\n");
72
73         for (psQueue = psSysData->psQueueList; --off && psQueue;
74              psQueue = psQueue->psNextKM)
75                 ;
76
77         return psQueue ?
78                 QueuePrintCommands(psQueue, buffer, size) : END_OF_FILE;
79 }
80
81 #define GET_SPACE_IN_CMDQ(psQueue)                                      \
82         (((psQueue->ui32ReadOffset - psQueue->ui32WriteOffset) +        \
83           (psQueue->ui32QueueSize - 1)) & (psQueue->ui32QueueSize - 1))
84
85 #define UPDATE_QUEUE_WOFF(psQueue, ui32Size)                               \
86         psQueue->ui32WriteOffset = (psQueue->ui32WriteOffset + ui32Size) & \
87         (psQueue->ui32QueueSize - 1);
88
89 #define SYNCOPS_STALE(ui32OpsComplete, ui32OpsPending)                  \
90         (ui32OpsComplete >= ui32OpsPending)
91
92 static u32 NearestPower2(u32 ui32Value)
93 {
94         u32 ui32Temp, ui32Result = 1;
95
96         if (!ui32Value)
97                 return 0;
98
99         ui32Temp = ui32Value - 1;
100         while (ui32Temp) {
101                 ui32Result <<= 1;
102                 ui32Temp >>= 1;
103         }
104
105         return ui32Result;
106 }
107
108 enum PVRSRV_ERROR PVRSRVCreateCommandQueueKM(u32 ui32QueueSize,
109                                  struct PVRSRV_QUEUE_INFO **ppsQueueInfo)
110 {
111         struct PVRSRV_QUEUE_INFO *psQueueInfo;
112         u32 ui32Power2QueueSize = NearestPower2(ui32QueueSize);
113         struct SYS_DATA *psSysData;
114         enum PVRSRV_ERROR eError;
115         void *hMemBlock;
116
117         eError = SysAcquireData(&psSysData);
118         if (eError != PVRSRV_OK)
119                 return eError;
120
121         if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
122                        sizeof(struct PVRSRV_QUEUE_INFO),
123                        (void **) &psQueueInfo, &hMemBlock) != PVRSRV_OK) {
124                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateCommandQueueKM: "
125                                         "Failed to alloc queue struct");
126                 goto ErrorExit;
127         }
128         OSMemSet(psQueueInfo, 0, sizeof(struct PVRSRV_QUEUE_INFO));
129
130         psQueueInfo->hMemBlock[0] = hMemBlock;
131         psQueueInfo->ui32ProcessID = OSGetCurrentProcessIDKM();
132
133         if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
134                        ui32Power2QueueSize + PVRSRV_MAX_CMD_SIZE,
135                        &psQueueInfo->pvLinQueueKM, &hMemBlock) != PVRSRV_OK) {
136                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateCommandQueueKM: "
137                                         "Failed to alloc queue buffer");
138                 goto ErrorExit;
139         }
140
141         psQueueInfo->hMemBlock[1] = hMemBlock;
142         psQueueInfo->pvLinQueueUM = psQueueInfo->pvLinQueueKM;
143
144         PVR_ASSERT(psQueueInfo->ui32ReadOffset == 0);
145         PVR_ASSERT(psQueueInfo->ui32WriteOffset == 0);
146
147         psQueueInfo->ui32QueueSize = ui32Power2QueueSize;
148
149         if (psSysData->psQueueList == NULL) {
150                 eError = OSCreateResource(&psSysData->sQProcessResource);
151                 if (eError != PVRSRV_OK)
152                         goto ErrorExit;
153         }
154
155         if (OSLockResource(&psSysData->sQProcessResource,
156                            KERNEL_ID) != PVRSRV_OK)
157                 goto ErrorExit;
158
159         psQueueInfo->psNextKM = psSysData->psQueueList;
160         psSysData->psQueueList = psQueueInfo;
161
162         if (OSUnlockResource(&psSysData->sQProcessResource, KERNEL_ID) !=
163             PVRSRV_OK)
164                 goto ErrorExit;
165
166         *ppsQueueInfo = psQueueInfo;
167
168         return PVRSRV_OK;
169
170 ErrorExit:
171
172         if (psQueueInfo) {
173                 if (psQueueInfo->pvLinQueueKM)
174                         OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
175                                   psQueueInfo->ui32QueueSize,
176                                   psQueueInfo->pvLinQueueKM,
177                                   psQueueInfo->hMemBlock[1]);
178
179                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
180                           sizeof(struct PVRSRV_QUEUE_INFO),
181                           psQueueInfo, psQueueInfo->hMemBlock[0]);
182         }
183
184         return PVRSRV_ERROR_GENERIC;
185 }
186
187 enum PVRSRV_ERROR PVRSRVDestroyCommandQueueKM(
188                                 struct PVRSRV_QUEUE_INFO *psQueueInfo)
189 {
190         struct PVRSRV_QUEUE_INFO *psQueue;
191         struct SYS_DATA *psSysData;
192         enum PVRSRV_ERROR eError;
193         IMG_BOOL bTimeout = IMG_TRUE;
194
195         eError = SysAcquireData(&psSysData);
196         if (eError != PVRSRV_OK)
197                 return eError;
198
199         psQueue = psSysData->psQueueList;
200
201         LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) {
202                 if (psQueueInfo->ui32ReadOffset ==
203                     psQueueInfo->ui32WriteOffset) {
204                         bTimeout = IMG_FALSE;
205                         break;
206                 }
207                 OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT);
208         }
209         END_LOOP_UNTIL_TIMEOUT();
210
211         if (bTimeout) {
212                 PVR_DPF(PVR_DBG_ERROR,
213                          "PVRSRVDestroyCommandQueueKM : Failed to empty queue");
214                 eError = PVRSRV_ERROR_CANNOT_FLUSH_QUEUE;
215                 goto ErrorExit;
216         }
217
218         eError = OSLockResource(&psSysData->sQProcessResource, KERNEL_ID);
219         if (eError != PVRSRV_OK)
220                 goto ErrorExit;
221
222         if (psQueue == psQueueInfo) {
223                 psSysData->psQueueList = psQueueInfo->psNextKM;
224
225                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
226                           psQueueInfo->ui32QueueSize,
227                           psQueueInfo->pvLinQueueKM, psQueueInfo->hMemBlock[1]);
228                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
229                           sizeof(struct PVRSRV_QUEUE_INFO),
230                           psQueueInfo, psQueueInfo->hMemBlock[0]);
231         } else {
232                 while (psQueue) {
233                         if (psQueue->psNextKM == psQueueInfo) {
234                                 psQueue->psNextKM = psQueueInfo->psNextKM;
235
236                                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
237                                           psQueueInfo->ui32QueueSize,
238                                           psQueueInfo->pvLinQueueKM,
239                                           psQueueInfo->hMemBlock[1]);
240                                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
241                                           sizeof(struct PVRSRV_QUEUE_INFO),
242                                           psQueueInfo,
243                                           psQueueInfo->hMemBlock[0]);
244                                 break;
245                         }
246                         psQueue = psQueue->psNextKM;
247                 }
248
249                 if (!psQueue) {
250                         eError =
251                             OSUnlockResource(&psSysData->sQProcessResource,
252                                              KERNEL_ID);
253                         if (eError != PVRSRV_OK)
254                                 goto ErrorExit;
255                         eError = PVRSRV_ERROR_INVALID_PARAMS;
256                         goto ErrorExit;
257                 }
258         }
259
260         eError = OSUnlockResource(&psSysData->sQProcessResource, KERNEL_ID);
261         if (eError != PVRSRV_OK)
262                 goto ErrorExit;
263
264         if (psSysData->psQueueList == NULL) {
265                 eError = OSDestroyResource(&psSysData->sQProcessResource);
266                 if (eError != PVRSRV_OK)
267                         goto ErrorExit;
268         }
269
270 ErrorExit:
271
272         return eError;
273 }
274
275 enum PVRSRV_ERROR PVRSRVGetQueueSpaceKM(struct PVRSRV_QUEUE_INFO *psQueue,
276                                     u32 ui32ParamSize, void **ppvSpace)
277 {
278         IMG_BOOL bTimeout = IMG_TRUE;
279
280         ui32ParamSize = (ui32ParamSize + 3) & 0xFFFFFFFC;
281
282         if (ui32ParamSize > PVRSRV_MAX_CMD_SIZE) {
283                 PVR_DPF(PVR_DBG_WARNING,
284                          "PVRSRVGetQueueSpace: max command size is %d bytes",
285                          PVRSRV_MAX_CMD_SIZE);
286                 return PVRSRV_ERROR_CMD_TOO_BIG;
287         }
288
289         LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) {
290                 if (GET_SPACE_IN_CMDQ(psQueue) > ui32ParamSize) {
291                         bTimeout = IMG_FALSE;
292                         break;
293                 }
294                 OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT);
295         }
296         END_LOOP_UNTIL_TIMEOUT();
297
298         if (bTimeout == IMG_TRUE) {
299                 *ppvSpace = NULL;
300
301                 return PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE;
302         } else {
303                 *ppvSpace = (void *)(psQueue->ui32WriteOffset +
304                                                 (u32)psQueue->pvLinQueueUM);
305         }
306
307         return PVRSRV_OK;
308 }
309
310 enum PVRSRV_ERROR PVRSRVInsertCommandKM(struct PVRSRV_QUEUE_INFO *psQueue,
311                                    struct PVRSRV_COMMAND **ppsCommand,
312                                    u32 ui32DevIndex, u16 CommandType,
313                                    u32 ui32DstSyncCount,
314                                    struct PVRSRV_KERNEL_SYNC_INFO *apsDstSync[],
315                                    u32 ui32SrcSyncCount,
316                                    struct PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[],
317                                    u32 ui32DataByteSize)
318 {
319         enum PVRSRV_ERROR eError;
320         struct PVRSRV_COMMAND *psCommand;
321         u32 ui32CommandSize;
322         u32 i;
323
324         ui32DataByteSize = (ui32DataByteSize + 3) & 0xFFFFFFFC;
325
326         ui32CommandSize = sizeof(struct PVRSRV_COMMAND) +
327             ((ui32DstSyncCount + ui32SrcSyncCount) *
328              sizeof(struct PVRSRV_SYNC_OBJECT)) + ui32DataByteSize;
329
330         eError = PVRSRVGetQueueSpaceKM(psQueue, ui32CommandSize,
331                                   (void **) &psCommand);
332         if (eError != PVRSRV_OK)
333                 return eError;
334
335         psCommand->ui32ProcessID = OSGetCurrentProcessIDKM();
336
337         psCommand->ui32CmdSize = ui32CommandSize;
338         psCommand->ui32DevIndex = ui32DevIndex;
339         psCommand->CommandType = CommandType;
340         psCommand->ui32DstSyncCount = ui32DstSyncCount;
341         psCommand->ui32SrcSyncCount = ui32SrcSyncCount;
342         psCommand->psDstSync =
343             (struct PVRSRV_SYNC_OBJECT *)(((u8 *) psCommand) +
344                                     sizeof(struct PVRSRV_COMMAND));
345
346         psCommand->psSrcSync =
347             (struct PVRSRV_SYNC_OBJECT *)(((u8 *) psCommand->psDstSync) +
348                                     (ui32DstSyncCount *
349                                      sizeof(struct PVRSRV_SYNC_OBJECT)));
350
351         psCommand->pvData =
352             (struct PVRSRV_SYNC_OBJECT *)(((u8 *) psCommand->psSrcSync) +
353                                     (ui32SrcSyncCount *
354                                      sizeof(struct PVRSRV_SYNC_OBJECT)));
355
356         psCommand->ui32DataSize = ui32DataByteSize;
357
358         for (i = 0; i < ui32DstSyncCount; i++) {
359                 psCommand->psDstSync[i].psKernelSyncInfoKM = apsDstSync[i];
360                 psCommand->psDstSync[i].ui32WriteOpsPending =
361                     PVRSRVGetWriteOpsPending(apsDstSync[i], IMG_FALSE);
362                 psCommand->psDstSync[i].ui32ReadOpsPending =
363                     PVRSRVGetReadOpsPending(apsDstSync[i], IMG_FALSE);
364         }
365
366         for (i = 0; i < ui32SrcSyncCount; i++) {
367                 psCommand->psSrcSync[i].psKernelSyncInfoKM = apsSrcSync[i];
368                 psCommand->psSrcSync[i].ui32WriteOpsPending =
369                     PVRSRVGetWriteOpsPending(apsSrcSync[i], IMG_TRUE);
370                 psCommand->psSrcSync[i].ui32ReadOpsPending =
371                     PVRSRVGetReadOpsPending(apsSrcSync[i], IMG_TRUE);
372         }
373
374         *ppsCommand = psCommand;
375
376         return PVRSRV_OK;
377 }
378
379 enum PVRSRV_ERROR PVRSRVSubmitCommandKM(struct PVRSRV_QUEUE_INFO *psQueue,
380                                     struct PVRSRV_COMMAND *psCommand)
381 {
382
383         if (psCommand->ui32DstSyncCount > 0) {
384                 psCommand->psDstSync = (struct PVRSRV_SYNC_OBJECT *)
385                                         (((u8 *)psQueue->pvLinQueueKM) +
386                                          psQueue->ui32WriteOffset +
387                                          sizeof(struct PVRSRV_COMMAND));
388         }
389
390         if (psCommand->ui32SrcSyncCount > 0) {
391                 psCommand->psSrcSync = (struct PVRSRV_SYNC_OBJECT *)
392                                         (((u8 *)psQueue->pvLinQueueKM) +
393                                         psQueue->ui32WriteOffset +
394                                         sizeof(struct PVRSRV_COMMAND) +
395                                         (psCommand->ui32DstSyncCount *
396                                            sizeof(struct PVRSRV_SYNC_OBJECT)));
397         }
398
399         psCommand->pvData = (struct PVRSRV_SYNC_OBJECT *)
400                         (((u8 *)psQueue->pvLinQueueKM) +
401                          psQueue->ui32WriteOffset +
402                          sizeof(struct PVRSRV_COMMAND) +
403                          (psCommand->ui32DstSyncCount *
404                                 sizeof(struct PVRSRV_SYNC_OBJECT)) +
405                          (psCommand->ui32SrcSyncCount *
406                                 sizeof(struct PVRSRV_SYNC_OBJECT)));
407
408         UPDATE_QUEUE_WOFF(psQueue, psCommand->ui32CmdSize);
409
410         return PVRSRV_OK;
411 }
412
413 static enum PVRSRV_ERROR PVRSRVProcessCommand(struct SYS_DATA *psSysData,
414                                   struct PVRSRV_COMMAND *psCommand,
415                                   IMG_BOOL bFlush)
416 {
417         struct PVRSRV_SYNC_OBJECT *psWalkerObj;
418         struct PVRSRV_SYNC_OBJECT *psEndObj;
419         u32 i;
420         struct COMMAND_COMPLETE_DATA *psCmdCompleteData;
421         enum PVRSRV_ERROR eError = PVRSRV_OK;
422         u32 ui32WriteOpsComplete;
423         u32 ui32ReadOpsComplete;
424
425         psWalkerObj = psCommand->psDstSync;
426         psEndObj = psWalkerObj + psCommand->ui32DstSyncCount;
427         while (psWalkerObj < psEndObj) {
428                 struct PVRSRV_SYNC_DATA *psSyncData =
429                     psWalkerObj->psKernelSyncInfoKM->psSyncData;
430
431                 ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete;
432                 ui32ReadOpsComplete = psSyncData->ui32ReadOpsComplete;
433
434                 if ((ui32WriteOpsComplete != psWalkerObj->ui32WriteOpsPending)
435                     || (ui32ReadOpsComplete !=
436                         psWalkerObj->ui32ReadOpsPending)) {
437                         if (!bFlush ||
438                             !SYNCOPS_STALE(ui32WriteOpsComplete,
439                                            psWalkerObj->ui32WriteOpsPending) ||
440                             !SYNCOPS_STALE(ui32ReadOpsComplete,
441                                            psWalkerObj->ui32ReadOpsPending)) {
442                                 return PVRSRV_ERROR_FAILED_DEPENDENCIES;
443                         }
444                 }
445
446                 psWalkerObj++;
447         }
448
449         psWalkerObj = psCommand->psSrcSync;
450         psEndObj = psWalkerObj + psCommand->ui32SrcSyncCount;
451         while (psWalkerObj < psEndObj) {
452                 struct PVRSRV_SYNC_DATA *psSyncData =
453                     psWalkerObj->psKernelSyncInfoKM->psSyncData;
454
455                 ui32ReadOpsComplete = psSyncData->ui32ReadOpsComplete;
456                 ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete;
457
458                 if ((ui32WriteOpsComplete !=
459                      psWalkerObj->ui32WriteOpsPending) ||
460                     (ui32ReadOpsComplete !=
461                         psWalkerObj->ui32ReadOpsPending)) {
462                         if (!bFlush &&
463                             SYNCOPS_STALE(ui32WriteOpsComplete,
464                                           psWalkerObj->ui32WriteOpsPending) &&
465                             SYNCOPS_STALE(ui32ReadOpsComplete,
466                                         psWalkerObj->ui32ReadOpsPending)) {
467                                 PVR_DPF(PVR_DBG_WARNING,
468                         "PVRSRVProcessCommand: Stale syncops psSyncData:0x%x "
469                         "ui32WriteOpsComplete:0x%x ui32WriteOpsPending:0x%x",
470                                          psSyncData, ui32WriteOpsComplete,
471                                          psWalkerObj->ui32WriteOpsPending);
472                         }
473
474                         if (!bFlush ||
475                             !SYNCOPS_STALE(ui32WriteOpsComplete,
476                                            psWalkerObj->ui32WriteOpsPending) ||
477                             !SYNCOPS_STALE(ui32ReadOpsComplete,
478                                            psWalkerObj->ui32ReadOpsPending)) {
479                                 return PVRSRV_ERROR_FAILED_DEPENDENCIES;
480                         }
481                 }
482                 psWalkerObj++;
483         }
484
485         if (psCommand->ui32DevIndex >= SYS_DEVICE_COUNT) {
486                 PVR_DPF(PVR_DBG_ERROR,
487                          "PVRSRVProcessCommand: invalid DeviceType 0x%x",
488                          psCommand->ui32DevIndex);
489                 return PVRSRV_ERROR_INVALID_PARAMS;
490         }
491
492         psCmdCompleteData =
493             psSysData->ppsCmdCompleteData[psCommand->ui32DevIndex][psCommand->
494                                                                    CommandType];
495         if (psCmdCompleteData->bInUse)
496
497                 return PVRSRV_ERROR_FAILED_DEPENDENCIES;
498
499         psCmdCompleteData->bInUse = IMG_TRUE;
500
501         psCmdCompleteData->ui32DstSyncCount = psCommand->ui32DstSyncCount;
502         for (i = 0; i < psCommand->ui32DstSyncCount; i++)
503                 psCmdCompleteData->psDstSync[i] = psCommand->psDstSync[i];
504
505         psCmdCompleteData->ui32SrcSyncCount = psCommand->ui32SrcSyncCount;
506         for (i = 0; i < psCommand->ui32SrcSyncCount; i++)
507                 psCmdCompleteData->psSrcSync[i] = psCommand->psSrcSync[i];
508
509         if (psSysData->ppfnCmdProcList[psCommand->ui32DevIndex]
510                                       [psCommand->CommandType]((void *)
511                                            psCmdCompleteData,
512                                            psCommand->ui32DataSize,
513                                            psCommand->pvData) == IMG_FALSE) {
514                 psCmdCompleteData->bInUse = IMG_FALSE;
515                 eError = PVRSRV_ERROR_CMD_NOT_PROCESSED;
516         }
517
518         return eError;
519 }
520
521 enum PVRSRV_ERROR PVRSRVProcessQueues(u32 ui32CallerID, IMG_BOOL bFlush)
522 {
523         struct PVRSRV_QUEUE_INFO *psQueue;
524         struct SYS_DATA *psSysData;
525         struct PVRSRV_COMMAND *psCommand;
526         struct PVRSRV_DEVICE_NODE *psDeviceNode;
527         enum PVRSRV_ERROR eError;
528
529         eError = SysAcquireData(&psSysData);
530         if (eError != PVRSRV_OK)
531                 return eError;
532
533         psSysData->bReProcessQueues = IMG_FALSE;
534
535         eError = OSLockResource(&psSysData->sQProcessResource, ui32CallerID);
536         if (eError != PVRSRV_OK) {
537                 psSysData->bReProcessQueues = IMG_TRUE;
538
539                 if (ui32CallerID == ISR_ID) {
540                         if (bFlush) {
541                                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVProcessQueues: "
542                                         "Couldn't acquire queue processing "
543                                         "lock for FLUSH");
544                         } else {
545                                 PVR_DPF(PVR_DBG_MESSAGE,
546                                                 "PVRSRVProcessQueues: "
547                                                 "Couldn't acquire queue "
548                                                 "processing lock");
549                         }
550                 } else {
551                         PVR_DPF(PVR_DBG_MESSAGE, "PVRSRVProcessQueues: "
552                                 "Queue processing lock-acquire failed "
553                                 "when called from the Services driver.");
554                         PVR_DPF(PVR_DBG_MESSAGE,
555                                 "This is due to MISR queue processing "
556                                 "being interrupted by the Services driver.");
557                 }
558
559                 return PVRSRV_OK;
560         }
561
562         psQueue = psSysData->psQueueList;
563
564         if (!psQueue) {
565                 PVR_DPF(PVR_DBG_MESSAGE,
566                          "No Queues installed - cannot process commands");
567         }
568
569         if (bFlush)
570                 PVRSRVSetDCState(DC_STATE_FLUSH_COMMANDS);
571
572         while (psQueue) {
573                 while (psQueue->ui32ReadOffset != psQueue->ui32WriteOffset) {
574                         psCommand = (struct PVRSRV_COMMAND *)((u32) psQueue->
575                                         pvLinQueueKM + psQueue->ui32ReadOffset);
576
577                         if (PVRSRVProcessCommand(psSysData, psCommand, bFlush)
578                             == PVRSRV_OK) {
579                                 UPDATE_QUEUE_ROFF(psQueue,
580                                                   psCommand->ui32CmdSize)
581                                 if (bFlush)
582                                         continue;
583                         }
584                         break;
585                 }
586                 psQueue = psQueue->psNextKM;
587         }
588
589         if (bFlush)
590                 PVRSRVSetDCState(DC_STATE_NO_FLUSH_COMMANDS);
591
592         psDeviceNode = psSysData->psDeviceNodeList;
593         while (psDeviceNode != NULL) {
594                 if (psDeviceNode->bReProcessDeviceCommandComplete &&
595                     psDeviceNode->pfnDeviceCommandComplete != NULL) {
596                         (*psDeviceNode->
597                          pfnDeviceCommandComplete) (psDeviceNode);
598                 }
599                 psDeviceNode = psDeviceNode->psNext;
600         }
601
602         OSUnlockResource(&psSysData->sQProcessResource, ui32CallerID);
603
604         if (psSysData->bReProcessQueues)
605                 return PVRSRV_ERROR_PROCESSING_BLOCKED;
606
607         return PVRSRV_OK;
608 }
609
610 void PVRSRVCommandCompleteKM(void *hCmdCookie, IMG_BOOL bScheduleMISR)
611 {
612         u32 i;
613         struct COMMAND_COMPLETE_DATA *psCmdCompleteData =
614             (struct COMMAND_COMPLETE_DATA *)hCmdCookie;
615         struct SYS_DATA *psSysData;
616
617         if (SysAcquireData(&psSysData) != PVRSRV_OK)
618                 return;
619
620         for (i = 0; i < psCmdCompleteData->ui32DstSyncCount; i++) {
621                 psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->psSyncData->
622                     ui32WriteOpsComplete++;
623         }
624
625         for (i = 0; i < psCmdCompleteData->ui32SrcSyncCount; i++) {
626                 psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->psSyncData->
627                     ui32ReadOpsComplete++;
628         }
629
630         psCmdCompleteData->bInUse = IMG_FALSE;
631
632         PVRSRVCommandCompleteCallbacks();
633
634         if (bScheduleMISR)
635                 OSScheduleMISR(psSysData);
636 }
637
638 void PVRSRVCommandCompleteCallbacks(void)
639 {
640         struct SYS_DATA *psSysData;
641         struct PVRSRV_DEVICE_NODE *psDeviceNode;
642
643         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
644                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVCommandCompleteCallbacks: "
645                                         "SysAcquireData failed");
646                 return;
647         }
648
649         psDeviceNode = psSysData->psDeviceNodeList;
650         while (psDeviceNode != NULL) {
651                 if (psDeviceNode->pfnDeviceCommandComplete != NULL)
652                         (*psDeviceNode->pfnDeviceCommandComplete)(psDeviceNode);
653                 psDeviceNode = psDeviceNode->psNext;
654         }
655 }
656
657 enum PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(u32 ui32DevIndex,
658                              IMG_BOOL (**ppfnCmdProcList)(void *, u32, void *),
659                              u32 ui32MaxSyncsPerCmd[][2], u32 ui32CmdCount)
660 {
661         struct SYS_DATA *psSysData;
662         enum PVRSRV_ERROR eError;
663         u32 i;
664         u32 ui32AllocSize;
665         IMG_BOOL (**ppfnCmdProc)(void *, u32, void *);
666         struct COMMAND_COMPLETE_DATA *psCmdCompleteData;
667
668         if (ui32DevIndex >= SYS_DEVICE_COUNT) {
669                 PVR_DPF(PVR_DBG_ERROR,
670                          "PVRSRVRegisterCmdProcListKM: invalid DeviceType 0x%x",
671                          ui32DevIndex);
672                 return PVRSRV_ERROR_INVALID_PARAMS;
673         }
674
675         eError = SysAcquireData(&psSysData);
676         if (eError != PVRSRV_OK) {
677                 PVR_DPF(PVR_DBG_ERROR,
678                          "PVRSRVRegisterCmdProcListKM: SysAcquireData failed");
679                 return eError;
680         }
681
682         eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, ui32CmdCount *
683                                      sizeof(IMG_BOOL (*)(void *, u32, void *)),
684                             (void **)&psSysData->ppfnCmdProcList[ui32DevIndex],
685                             NULL);
686         if (eError != PVRSRV_OK) {
687                 PVR_DPF(PVR_DBG_ERROR,
688                          "PVRSRVRegisterCmdProcListKM: Failed to alloc queue");
689                 return eError;
690         }
691
692         ppfnCmdProc = psSysData->ppfnCmdProcList[ui32DevIndex];
693
694         for (i = 0; i < ui32CmdCount; i++)
695                 ppfnCmdProc[i] = ppfnCmdProcList[i];
696
697         ui32AllocSize = ui32CmdCount * sizeof(struct COMMAND_COMPLETE_DATA *);
698         eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
699                             ui32AllocSize,
700                             (void **) &psSysData->
701                             ppsCmdCompleteData[ui32DevIndex], NULL);
702         if (eError != PVRSRV_OK) {
703                 PVR_DPF(PVR_DBG_ERROR,
704                         "PVRSRVRegisterCmdProcListKM: Failed to alloc CC data");
705                 goto ErrorExit;
706         }
707
708         /* clear the list to ensure that we don't try to access uninitialised
709          * pointer in the 'error' execution path */
710         OSMemSet(psSysData->ppsCmdCompleteData[ui32DevIndex], 0x00,
711                  ui32AllocSize);
712
713         for (i = 0; i < ui32CmdCount; i++) {
714                 ui32AllocSize = sizeof(struct COMMAND_COMPLETE_DATA)
715                     + ((ui32MaxSyncsPerCmd[i][0] + ui32MaxSyncsPerCmd[i][1])
716                        * sizeof(struct PVRSRV_SYNC_OBJECT));
717
718                 eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
719                                     ui32AllocSize,
720                                     (void **)&psSysData->
721                                             ppsCmdCompleteData[ui32DevIndex][i],
722                                     NULL);
723                 if (eError != PVRSRV_OK) {
724                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterCmdProcListKM: "
725                                                 "Failed to alloc cmd %d",
726                                  i);
727                         goto ErrorExit;
728                 }
729
730                 OSMemSet(psSysData->ppsCmdCompleteData[ui32DevIndex][i], 0x00,
731                          ui32AllocSize);
732
733                 psCmdCompleteData =
734                     psSysData->ppsCmdCompleteData[ui32DevIndex][i];
735
736                 psCmdCompleteData->psDstSync = (struct PVRSRV_SYNC_OBJECT *)
737                      (((u32) psCmdCompleteData) +
738                                         sizeof(struct COMMAND_COMPLETE_DATA));
739                 psCmdCompleteData->psSrcSync = (struct PVRSRV_SYNC_OBJECT *)
740                      (((u32) psCmdCompleteData->psDstSync) +
741                                         (sizeof(struct PVRSRV_SYNC_OBJECT) *
742                                                  ui32MaxSyncsPerCmd[i][0]));
743                 psCmdCompleteData->ui32AllocSize = ui32AllocSize;
744         }
745
746         return PVRSRV_OK;
747
748 ErrorExit:
749
750         if (psSysData->ppsCmdCompleteData[ui32DevIndex] != NULL) {
751                 for (i = 0; i < ui32CmdCount; i++) {
752                         if (psSysData->ppsCmdCompleteData[ui32DevIndex][i] !=
753                             NULL) {
754                                 psCmdCompleteData =
755                                     psSysData->
756                                             ppsCmdCompleteData[ui32DevIndex][i];
757                                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
758                                           psCmdCompleteData->ui32AllocSize,
759                                           psCmdCompleteData, NULL);
760                         }
761                 }
762
763                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
764                           ui32CmdCount * sizeof(struct COMMAND_COMPLETE_DATA *),
765                           psSysData->ppsCmdCompleteData[ui32DevIndex],
766                           NULL);
767         }
768
769         if (psSysData->ppfnCmdProcList[ui32DevIndex] != NULL) {
770                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, 0,
771                           psSysData->ppfnCmdProcList[ui32DevIndex], NULL);
772         }
773
774         return eError;
775 }
776
777 enum PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(u32 ui32DevIndex, u32 ui32CmdCount)
778 {
779         struct SYS_DATA *psSysData;
780         enum PVRSRV_ERROR eError;
781         u32 i;
782
783         if (ui32DevIndex >= SYS_DEVICE_COUNT) {
784                 PVR_DPF(PVR_DBG_ERROR,
785                          "PVRSRVRemoveCmdProcListKM: invalid DeviceType 0x%x",
786                          ui32DevIndex);
787                 return PVRSRV_ERROR_INVALID_PARAMS;
788         }
789
790         eError = SysAcquireData(&psSysData);
791         if (eError != PVRSRV_OK) {
792                 PVR_DPF(PVR_DBG_ERROR,
793                          "PVRSRVRemoveCmdProcListKM: SysAcquireData failed");
794                 return eError;
795         }
796
797         if (psSysData->ppsCmdCompleteData[ui32DevIndex] == NULL) {
798                 PVR_DPF(PVR_DBG_ERROR,
799                          "PVRSRVRemoveCmdProcListKM: Invalid command array");
800                 return PVRSRV_ERROR_INVALID_PARAMS;
801         } else {
802                 for (i = 0; i < ui32CmdCount; i++) {
803
804                         if (psSysData->ppsCmdCompleteData[ui32DevIndex][i] !=
805                             NULL) {
806                                 struct COMMAND_COMPLETE_DATA *
807                                         psCmdCompleteData = psSysData->
808                                         ppsCmdCompleteData[ui32DevIndex][i];
809                                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
810                                           psCmdCompleteData->ui32AllocSize,
811                                           psCmdCompleteData, NULL);
812                         }
813                 }
814
815                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
816                           ui32CmdCount * sizeof(struct COMMAND_COMPLETE_DATA *),
817                           psSysData->ppsCmdCompleteData[ui32DevIndex], NULL);
818         }
819
820         if (psSysData->ppfnCmdProcList[ui32DevIndex] != NULL) {
821                 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
822                           ui32CmdCount *
823                                 sizeof(IMG_BOOL (*)(void *, u32, void *)),
824                           psSysData->ppfnCmdProcList[ui32DevIndex], NULL);
825         }
826
827         return PVRSRV_OK;
828 }