gpu: pvr: add option for extra debugging information
[sgx.git] / pvr / sgxutils.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 <stddef.h>
28
29 #include "sgxdefs.h"
30 #include "services_headers.h"
31 #include "buffer_manager.h"
32 #include "sgxapi_km.h"
33 #include "sgxinfo.h"
34 #include "sgxinfokm.h"
35 #include "sysconfig.h"
36 #include "pdump_km.h"
37 #include "mmu.h"
38 #include "pvr_bridge_km.h"
39 #include "sgx_bridge_km.h"
40 #include "osfunc.h"
41 #include "pvr_debug.h"
42 #include "sgxutils.h"
43
44 #include <linux/tty.h>
45 #include <linux/io.h>
46
47 static void SGXPostActivePowerEvent(struct PVRSRV_DEVICE_NODE *psDeviceNode,
48                                      u32 ui32CallerID)
49 {
50         struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
51         struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl =
52                                              psDevInfo->psSGXHostCtl;
53         u32 l;
54
55         l = readl(&psSGXHostCtl->ui32NumActivePowerEvents);
56         l++;
57         writel(l, &psSGXHostCtl->ui32NumActivePowerEvents);
58
59         l = readl(&psSGXHostCtl->ui32PowerStatus);
60         if (l & PVRSRV_USSE_EDM_POWMAN_POWEROFF_RESTART_IMMEDIATE) {
61                 if (ui32CallerID == ISR_ID)
62                         psDeviceNode->bReProcessDeviceCommandComplete =
63                             IMG_TRUE;
64                 else
65                         SGXScheduleProcessQueuesKM(psDeviceNode);
66         }
67 }
68
69 void SGXTestActivePowerEvent(struct PVRSRV_DEVICE_NODE *psDeviceNode,
70                                  u32 ui32CallerID)
71 {
72         enum PVRSRV_ERROR eError = PVRSRV_OK;
73         struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
74         struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = psDevInfo->psSGXHostCtl;
75         u32 l;
76
77         l = readl(&psSGXHostCtl->ui32InterruptFlags);
78         if (!(l & PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER))
79                 return;
80
81         l = readl(&psSGXHostCtl->ui32InterruptClearFlags);
82         if (l & PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER)
83                 return;
84
85         /* Microkernel is idle and is requesting to be powered down. */
86         l = readl(&psSGXHostCtl->ui32InterruptClearFlags);
87         l |= PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER;
88         writel(l, &psSGXHostCtl->ui32InterruptClearFlags);
89
90         PDUMPSUSPEND();
91
92         eError = PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.
93                                         ui32DeviceIndex,
94                                         PVRSRV_POWER_STATE_D3,
95                                         ui32CallerID, IMG_FALSE);
96         if (eError == PVRSRV_OK)
97                 SGXPostActivePowerEvent(psDeviceNode, ui32CallerID);
98         if (eError == PVRSRV_ERROR_RETRY) {
99                 l = readl(&psSGXHostCtl->ui32InterruptClearFlags);
100                 l &= ~PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER;
101                 writel(l, &psSGXHostCtl->ui32InterruptClearFlags);
102                 eError = PVRSRV_OK;
103         }
104
105         PDUMPRESUME();
106
107         if (eError != PVRSRV_OK)
108                 PVR_DPF(PVR_DBG_ERROR, "SGXTestActivePowerEvent error:%lu",
109                                         eError);
110 }
111
112 static inline struct SGXMKIF_COMMAND *SGXAcquireKernelCCBSlot(
113                                         struct PVRSRV_SGX_CCB_INFO *psCCB)
114 {
115         LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) {
116                 if (((*psCCB->pui32WriteOffset + 1) & 255) !=
117                     *psCCB->pui32ReadOffset) {
118                         return &psCCB->psCommands[*psCCB->pui32WriteOffset];
119                 }
120         }
121         END_LOOP_UNTIL_TIMEOUT();
122
123         return NULL;
124 }
125
126 enum PVRSRV_ERROR SGXScheduleCCBCommand(struct PVRSRV_SGXDEV_INFO *psDevInfo,
127                                         enum SGXMKIF_COMMAND_TYPE eCommandType,
128                                         struct SGXMKIF_COMMAND *psCommandData,
129                                         u32 ui32CallerID, u32 ui32PDumpFlags)
130 {
131         struct PVRSRV_SGX_CCB_INFO *psKernelCCB;
132         enum PVRSRV_ERROR eError = PVRSRV_OK;
133         struct SGXMKIF_COMMAND *psSGXCommand;
134 #if defined(PDUMP)
135         void *pvDumpCommand;
136 #else
137         PVR_UNREFERENCED_PARAMETER(ui32CallerID);
138         PVR_UNREFERENCED_PARAMETER(ui32PDumpFlags);
139 #endif
140
141         psKernelCCB = psDevInfo->psKernelCCBInfo;
142
143         psSGXCommand = SGXAcquireKernelCCBSlot(psKernelCCB);
144
145         if (!psSGXCommand) {
146                 eError = PVRSRV_ERROR_TIMEOUT;
147                 goto Exit;
148         }
149
150         psCommandData->ui32Data[2] = psDevInfo->ui32CacheControl;
151
152 #if defined(PDUMP)
153
154         psDevInfo->sPDContext.ui32CacheControl |= psDevInfo->ui32CacheControl;
155 #endif
156
157         psDevInfo->ui32CacheControl = 0;
158
159         *psSGXCommand = *psCommandData;
160
161         switch (eCommandType) {
162         case SGXMKIF_COMMAND_EDM_KICK:
163                 psSGXCommand->ui32ServiceAddress =
164                     psDevInfo->ui32HostKickAddress;
165                 break;
166         case SGXMKIF_COMMAND_REQUEST_SGXMISCINFO:
167                 psSGXCommand->ui32ServiceAddress =
168                     psDevInfo->ui32GetMiscInfoAddress;
169                 break;
170         case SGXMKIF_COMMAND_VIDEO_KICK:
171         default:
172                 PVR_DPF(PVR_DBG_ERROR,
173                          "SGXScheduleCCBCommandKM: Unknown command type: %d",
174                          eCommandType);
175                 eError = PVRSRV_ERROR_GENERIC;
176                 goto Exit;
177         }
178
179 #if defined(PDUMP)
180         if (ui32CallerID != ISR_ID) {
181                 PDUMPCOMMENTWITHFLAGS(0,
182                                       "Poll for space in the Kernel CCB\r\n");
183                 PDUMPMEMPOL(psKernelCCB->psCCBCtlMemInfo,
184                             offsetof(struct PVRSRV_SGX_CCB_CTL, ui32ReadOffset),
185                             (psKernelCCB->ui32CCBDumpWOff + 1) & 0xff, 0xff,
186                             PDUMP_POLL_OPERATOR_NOTEQUAL, IMG_FALSE, IMG_FALSE,
187                             MAKEUNIQUETAG(psKernelCCB->psCCBCtlMemInfo));
188
189                 PDUMPCOMMENTWITHFLAGS(0, "Kernel CCB command\r\n");
190                 pvDumpCommand =
191                     (void *)((u8 *)psKernelCCB->psCCBMemInfo->
192                                   pvLinAddrKM +
193                                   (*psKernelCCB->pui32WriteOffset *
194                               sizeof(struct SGXMKIF_COMMAND)));
195
196                 PDUMPMEM(pvDumpCommand,
197                          psKernelCCB->psCCBMemInfo,
198                          psKernelCCB->ui32CCBDumpWOff *
199                          sizeof(struct SGXMKIF_COMMAND),
200                          sizeof(struct SGXMKIF_COMMAND), ui32PDumpFlags,
201                          MAKEUNIQUETAG(psKernelCCB->psCCBMemInfo));
202
203                 PDUMPMEM(&psDevInfo->sPDContext.ui32CacheControl,
204                          psKernelCCB->psCCBMemInfo,
205                          psKernelCCB->ui32CCBDumpWOff *
206                          sizeof(struct SGXMKIF_COMMAND) +
207                          offsetof(struct SGXMKIF_COMMAND, ui32Data[2]),
208                          sizeof(u32), ui32PDumpFlags,
209                          MAKEUNIQUETAG(psKernelCCB->psCCBMemInfo));
210
211                 if (PDumpIsCaptureFrameKM() ||
212                     ((ui32PDumpFlags & PDUMP_FLAGS_CONTINUOUS) != 0))
213                         psDevInfo->sPDContext.ui32CacheControl = 0;
214         }
215 #endif
216         *psKernelCCB->pui32WriteOffset =
217             (*psKernelCCB->pui32WriteOffset + 1) & 255;
218
219 #if defined(PDUMP)
220         if (ui32CallerID != ISR_ID) {
221                 if (PDumpIsCaptureFrameKM() ||
222                     ((ui32PDumpFlags & PDUMP_FLAGS_CONTINUOUS) != 0))
223                         psKernelCCB->ui32CCBDumpWOff =
224                             (psKernelCCB->ui32CCBDumpWOff + 1) & 0xFF;
225
226                 PDUMPCOMMENTWITHFLAGS(0, "Kernel CCB write offset\r\n");
227                 PDUMPMEM(&psKernelCCB->ui32CCBDumpWOff,
228                          psKernelCCB->psCCBCtlMemInfo,
229                          offsetof(struct PVRSRV_SGX_CCB_CTL, ui32WriteOffset),
230                          sizeof(u32), ui32PDumpFlags,
231                          MAKEUNIQUETAG(psKernelCCB->psCCBCtlMemInfo));
232                 PDUMPCOMMENTWITHFLAGS(0, "Kernel CCB event kicker\r\n");
233                 PDUMPMEM(&psKernelCCB->ui32CCBDumpWOff,
234                          psDevInfo->psKernelCCBEventKickerMemInfo, 0,
235                          sizeof(u32), ui32PDumpFlags,
236                          MAKEUNIQUETAG(psDevInfo->
237                                        psKernelCCBEventKickerMemInfo));
238                 PDUMPCOMMENTWITHFLAGS(0, "Event kick\r\n");
239                 PDUMPREGWITHFLAGS(SGX_MP_CORE_SELECT(EUR_CR_EVENT_KICK, 0),
240                                   EUR_CR_EVENT_KICK_NOW_MASK, 0);
241         }
242 #endif
243         *psDevInfo->pui32KernelCCBEventKicker =
244             (*psDevInfo->pui32KernelCCBEventKicker + 1) & 0xFF;
245         OSWriteHWReg(psDevInfo->pvRegsBaseKM,
246                      SGX_MP_CORE_SELECT(EUR_CR_EVENT_KICK, 0),
247                      EUR_CR_EVENT_KICK_NOW_MASK);
248
249 #if defined(NO_HARDWARE)
250
251         *psKernelCCB->pui32ReadOffset =
252             (*psKernelCCB->pui32ReadOffset + 1) & 255;
253 #endif
254
255 Exit:
256         return eError;
257 }
258
259 enum PVRSRV_ERROR SGXScheduleCCBCommandKM(
260                         struct PVRSRV_DEVICE_NODE *psDeviceNode,
261                         enum SGXMKIF_COMMAND_TYPE eCommandType,
262                         struct SGXMKIF_COMMAND *psCommandData,
263                         u32 ui32CallerID, u32 ui32PDumpFlags)
264 {
265         enum PVRSRV_ERROR eError;
266         struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
267
268         PDUMPSUSPEND();
269
270         eError =
271             PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.ui32DeviceIndex,
272                                         PVRSRV_POWER_STATE_D0, ui32CallerID,
273                                         IMG_TRUE);
274
275         PDUMPRESUME();
276
277         if (eError == PVRSRV_OK) {
278                 psDeviceNode->bReProcessDeviceCommandComplete = IMG_FALSE;
279         } else {
280                 if (eError == PVRSRV_ERROR_RETRY) {
281                         if (ui32CallerID == ISR_ID) {
282                                 psDeviceNode->bReProcessDeviceCommandComplete =
283                                     IMG_TRUE;
284                                 eError = PVRSRV_OK;
285                         } else {
286
287                         }
288                 } else
289                         PVR_DPF(PVR_DBG_ERROR, "SGXScheduleCCBCommandKM "
290                                         "failed to acquire lock - "
291                                          "ui32CallerID:%ld eError:%lu",
292                                          ui32CallerID, eError);
293                 return eError;
294         }
295
296         eError = SGXScheduleCCBCommand(psDevInfo, eCommandType, psCommandData,
297                                   ui32CallerID, ui32PDumpFlags);
298
299         PVRSRVPowerUnlock(ui32CallerID);
300
301         if (ui32CallerID != ISR_ID)
302                 SGXTestActivePowerEvent(psDeviceNode, ui32CallerID);
303
304         return eError;
305 }
306
307 enum PVRSRV_ERROR SGXScheduleProcessQueuesKM(struct PVRSRV_DEVICE_NODE
308                                              *psDeviceNode)
309 {
310         enum PVRSRV_ERROR eError;
311         struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
312         struct SGXMKIF_HOST_CTL *psHostCtl =
313             psDevInfo->psKernelSGXHostCtlMemInfo->pvLinAddrKM;
314         u32 ui32PowerStatus;
315         struct SGXMKIF_COMMAND sCommand = { 0 };
316
317         ui32PowerStatus = psHostCtl->ui32PowerStatus;
318         if ((ui32PowerStatus & PVRSRV_USSE_EDM_POWMAN_NO_WORK) != 0)
319                 return PVRSRV_OK;
320
321         sCommand.ui32Data[0] = PVRSRV_CCBFLAGS_PROCESS_QUEUESCMD;
322         eError =
323             SGXScheduleCCBCommandKM(psDeviceNode, SGXMKIF_COMMAND_EDM_KICK,
324                                     &sCommand, ISR_ID, 0);
325         if (eError != PVRSRV_OK) {
326                 PVR_DPF(PVR_DBG_ERROR, "SGXScheduleProcessQueuesKM failed "
327                                         "to schedule CCB command: %lu",
328                          eError);
329                 return PVRSRV_ERROR_GENERIC;
330         }
331
332         return PVRSRV_OK;
333 }
334
335 IMG_BOOL SGXIsDevicePowered(struct PVRSRV_DEVICE_NODE *psDeviceNode)
336 {
337         return PVRSRVIsDevicePowered(psDeviceNode->sDevId.ui32DeviceIndex);
338 }
339
340 enum PVRSRV_ERROR SGXGetInternalDevInfoKM(void *hDevCookie,
341                                               struct SGX_INTERNAL_DEVINFO
342                                               *psSGXInternalDevInfo)
343 {
344         struct PVRSRV_SGXDEV_INFO *psDevInfo = (struct PVRSRV_SGXDEV_INFO *)
345                         ((struct PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice;
346
347         psSGXInternalDevInfo->ui32Flags = psDevInfo->ui32Flags;
348         psSGXInternalDevInfo->bForcePTOff = (IMG_BOOL)psDevInfo->bForcePTOff;
349
350         psSGXInternalDevInfo->hHostCtlKernelMemInfoHandle =
351             (void *)psDevInfo->psKernelSGXHostCtlMemInfo;
352
353         return PVRSRV_OK;
354 }
355
356 #if defined(PDUMP) && !defined(EDM_USSE_HWDEBUG)
357 #define PDUMP_SGX_CLEANUP
358 #endif
359
360 void SGXCleanupRequest(struct PVRSRV_DEVICE_NODE *psDeviceNode,
361                                   struct IMG_DEV_VIRTADDR *psHWDataDevVAddr,
362                                   u32 ui32ResManRequestFlag)
363 {
364         struct PVRSRV_SGXDEV_INFO *psSGXDevInfo =
365             (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
366         struct PVRSRV_KERNEL_MEM_INFO *psSGXHostCtlMemInfo =
367             psSGXDevInfo->psKernelSGXHostCtlMemInfo;
368         struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl =
369             (struct SGXMKIF_HOST_CTL __iomem __force *)
370                                         psSGXHostCtlMemInfo->pvLinAddrKM;
371 #if defined(PDUMP_SGX_CLEANUP)
372         void *hUniqueTag = MAKEUNIQUETAG(psSGXHostCtlMemInfo);
373 #endif
374         u32 l;
375
376         if (readl(&psSGXHostCtl->ui32PowerStatus) &
377              PVRSRV_USSE_EDM_POWMAN_NO_WORK) {
378                 ;
379         } else {
380                 if (psSGXDevInfo->ui32CacheControl &
381                     SGX_BIF_INVALIDATE_PDCACHE) {
382                         l = readl(&psSGXHostCtl->ui32ResManFlags);
383                         l |= PVRSRV_USSE_EDM_RESMAN_CLEANUP_INVALPD;
384                         writel(l, &psSGXHostCtl->ui32ResManFlags);
385
386                         psSGXDevInfo->ui32CacheControl ^=
387                             SGX_BIF_INVALIDATE_PDCACHE;
388                 }
389                 if (psSGXDevInfo->ui32CacheControl &
390                     SGX_BIF_INVALIDATE_PTCACHE) {
391                         l = readl(&psSGXHostCtl->ui32ResManFlags);
392                         l |= PVRSRV_USSE_EDM_RESMAN_CLEANUP_INVALPT;
393                         writel(l, &psSGXHostCtl->ui32ResManFlags);
394
395                         psSGXDevInfo->ui32CacheControl ^=
396                             SGX_BIF_INVALIDATE_PTCACHE;
397                 }
398
399                 if (psHWDataDevVAddr == NULL)
400                         writel(0, &psSGXHostCtl->sResManCleanupData.uiAddr);
401                 else
402                         writel(psHWDataDevVAddr->uiAddr,
403                                 &psSGXHostCtl->sResManCleanupData.uiAddr);
404
405                 l = readl(&psSGXHostCtl->ui32ResManFlags);
406                 l |= ui32ResManRequestFlag;
407                 writel(l, &psSGXHostCtl->ui32ResManFlags);
408
409 #if defined(PDUMP_SGX_CLEANUP)
410
411                 PDUMPCOMMENTWITHFLAGS(0,
412                     "TA/3D CCB Control - Request clean-up event on uKernel...");
413                 PDUMPMEM(NULL, psSGXHostCtlMemInfo,
414                          offsetof(struct SGXMKIF_HOST_CTL,
415                                   sResManCleanupData.uiAddr), sizeof(u32), 0,
416                          hUniqueTag);
417                 PDUMPMEM(&ui32ResManRequestFlag, psSGXHostCtlMemInfo,
418                          offsetof(struct SGXMKIF_HOST_CTL, ui32ResManFlags),
419                          sizeof(u32), 0, hUniqueTag);
420 #else
421                 PDUMPCOMMENTWITHFLAGS(0, "Clean-up event on uKernel disabled");
422 #endif
423
424                 SGXScheduleProcessQueuesKM(psDeviceNode);
425
426 #if !defined(NO_HARDWARE)
427                 if (PollForValueKM(&psSGXHostCtl->ui32ResManFlags,
428                      PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE,
429                      PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE,
430                      MAX_HW_TIME_US / WAIT_TRY_COUNT,
431                      WAIT_TRY_COUNT) != PVRSRV_OK) {
432                         PVR_DPF(PVR_DBG_ERROR, "SGXCleanupRequest: "
433                                          "Wait for uKernel to clean up failed");
434                         PVR_DBG_BREAK;
435                 }
436 #endif
437
438 #if defined(PDUMP_SGX_CLEANUP)
439
440                 PDUMPCOMMENTWITHFLAGS(0, "TA/3D CCB Control - "
441                                    "Wait for clean-up request to complete...");
442                 PDUMPMEMPOL(psSGXHostCtlMemInfo,
443                             offsetof(struct SGXMKIF_HOST_CTL, ui32ResManFlags),
444                             PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE,
445                             PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE,
446                             PDUMP_POLL_OPERATOR_EQUAL, IMG_FALSE, IMG_FALSE,
447                             hUniqueTag);
448 #endif
449
450                 l = readl(&psSGXHostCtl->ui32ResManFlags);
451                 l &= ~ui32ResManRequestFlag;
452                 writel(l, &psSGXHostCtl->ui32ResManFlags);
453
454                 l = readl(&psSGXHostCtl->ui32ResManFlags);
455                 l &= ~PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE;
456                 writel(l, &psSGXHostCtl->ui32ResManFlags);
457
458 #if defined(PDUMP_SGX_CLEANUP)
459                 PDUMPMEM(NULL, psSGXHostCtlMemInfo,
460                          offsetof(struct SGXMKIF_HOST_CTL, ui32ResManFlags),
461                          sizeof(u32), 0, hUniqueTag);
462 #endif
463         }
464 }
465
466 struct SGX_HW_RENDER_CONTEXT_CLEANUP {
467         struct PVRSRV_DEVICE_NODE *psDeviceNode;
468         struct IMG_DEV_VIRTADDR sHWRenderContextDevVAddr;
469         void *hBlockAlloc;
470         struct RESMAN_ITEM *psResItem;
471 };
472
473 static enum PVRSRV_ERROR SGXCleanupHWRenderContextCallback(void *pvParam,
474                                                       u32 ui32Param)
475 {
476         struct SGX_HW_RENDER_CONTEXT_CLEANUP *psCleanup = pvParam;
477
478         PVR_UNREFERENCED_PARAMETER(ui32Param);
479
480         SGXCleanupRequest(psCleanup->psDeviceNode,
481                           &psCleanup->sHWRenderContextDevVAddr,
482                           PVRSRV_USSE_EDM_RESMAN_CLEANUP_RC_REQUEST);
483
484         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
485                   sizeof(struct SGX_HW_RENDER_CONTEXT_CLEANUP),
486                   psCleanup, psCleanup->hBlockAlloc);
487
488         return PVRSRV_OK;
489 }
490
491 struct SGX_HW_TRANSFER_CONTEXT_CLEANUP {
492         struct PVRSRV_DEVICE_NODE *psDeviceNode;
493         struct IMG_DEV_VIRTADDR sHWTransferContextDevVAddr;
494         void *hBlockAlloc;
495         struct RESMAN_ITEM *psResItem;
496 };
497
498 static enum PVRSRV_ERROR SGXCleanupHWTransferContextCallback(void *pvParam,
499                                                         u32 ui32Param)
500 {
501         struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *psCleanup =
502             (struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *)pvParam;
503
504         PVR_UNREFERENCED_PARAMETER(ui32Param);
505
506         SGXCleanupRequest(psCleanup->psDeviceNode,
507                           &psCleanup->sHWTransferContextDevVAddr,
508                           PVRSRV_USSE_EDM_RESMAN_CLEANUP_TC_REQUEST);
509
510         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
511                   sizeof(struct SGX_HW_TRANSFER_CONTEXT_CLEANUP),
512                   psCleanup, psCleanup->hBlockAlloc);
513
514         return PVRSRV_OK;
515 }
516
517 void *SGXRegisterHWRenderContextKM(void *psDeviceNode,
518                             struct IMG_DEV_VIRTADDR *psHWRenderContextDevVAddr,
519                             struct PVRSRV_PER_PROCESS_DATA *psPerProc)
520 {
521         enum PVRSRV_ERROR eError;
522         void *hBlockAlloc;
523         struct SGX_HW_RENDER_CONTEXT_CLEANUP *psCleanup;
524         struct RESMAN_ITEM *psResItem;
525
526         eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
527                             sizeof(struct SGX_HW_RENDER_CONTEXT_CLEANUP),
528                             (void **) &psCleanup, &hBlockAlloc);
529
530         if (eError != PVRSRV_OK) {
531                 PVR_DPF(PVR_DBG_ERROR,
532                         "SGXRegisterHWRenderContextKM: "
533                         "Couldn't allocate memory for struct "
534                         "SGX_HW_RENDER_CONTEXT_CLEANUP structure");
535                 return NULL;
536         }
537
538         psCleanup->hBlockAlloc = hBlockAlloc;
539         psCleanup->psDeviceNode = psDeviceNode;
540         psCleanup->sHWRenderContextDevVAddr = *psHWRenderContextDevVAddr;
541
542         psResItem = ResManRegisterRes(psPerProc->hResManContext,
543                                       RESMAN_TYPE_HW_RENDER_CONTEXT,
544                                       (void *) psCleanup,
545                                       0, &SGXCleanupHWRenderContextCallback);
546
547         if (psResItem == NULL) {
548                 PVR_DPF(PVR_DBG_ERROR, "SGXRegisterHWRenderContextKM: "
549                                         "ResManRegisterRes failed");
550                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
551                           sizeof(struct SGX_HW_RENDER_CONTEXT_CLEANUP),
552                           psCleanup, psCleanup->hBlockAlloc);
553
554                 return NULL;
555         }
556
557         psCleanup->psResItem = psResItem;
558
559         return (void *)psCleanup;
560 }
561
562 enum PVRSRV_ERROR SGXUnregisterHWRenderContextKM(void *hHWRenderContext)
563 {
564         struct SGX_HW_RENDER_CONTEXT_CLEANUP *psCleanup;
565
566         PVR_ASSERT(hHWRenderContext != NULL);
567
568         psCleanup = (struct SGX_HW_RENDER_CONTEXT_CLEANUP *)hHWRenderContext;
569
570         if (psCleanup == NULL) {
571                 PVR_DPF(PVR_DBG_ERROR,
572                          "SGXUnregisterHWRenderContextKM: invalid parameter");
573                 return PVRSRV_ERROR_INVALID_PARAMS;
574         }
575
576         ResManFreeResByPtr(psCleanup->psResItem);
577
578         return PVRSRV_OK;
579 }
580
581 void *SGXRegisterHWTransferContextKM(void *psDeviceNode,
582                       struct IMG_DEV_VIRTADDR *psHWTransferContextDevVAddr,
583                       struct PVRSRV_PER_PROCESS_DATA *psPerProc)
584 {
585         enum PVRSRV_ERROR eError;
586         void *hBlockAlloc;
587         struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *psCleanup;
588         struct RESMAN_ITEM *psResItem;
589
590         eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
591                             sizeof(struct SGX_HW_TRANSFER_CONTEXT_CLEANUP),
592                             (void **) &psCleanup, &hBlockAlloc);
593
594         if (eError != PVRSRV_OK) {
595                 PVR_DPF(PVR_DBG_ERROR,
596                         "SGXRegisterHWTransferContextKM: "
597                         "Couldn't allocate memory for struct "
598                         "SGX_HW_TRANSFER_CONTEXT_CLEANUP structure");
599                 return NULL;
600         }
601
602         psCleanup->hBlockAlloc = hBlockAlloc;
603         psCleanup->psDeviceNode = psDeviceNode;
604         psCleanup->sHWTransferContextDevVAddr = *psHWTransferContextDevVAddr;
605
606         psResItem = ResManRegisterRes(psPerProc->hResManContext,
607                                       RESMAN_TYPE_HW_TRANSFER_CONTEXT,
608                                       psCleanup,
609                                       0, &SGXCleanupHWTransferContextCallback);
610
611         if (psResItem == NULL) {
612                 PVR_DPF(PVR_DBG_ERROR, "SGXRegisterHWTransferContextKM: "
613                                                 "ResManRegisterRes failed");
614                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
615                           sizeof(struct SGX_HW_TRANSFER_CONTEXT_CLEANUP),
616                           psCleanup, psCleanup->hBlockAlloc);
617
618                 return NULL;
619         }
620
621         psCleanup->psResItem = psResItem;
622
623         return (void *)psCleanup;
624 }
625
626 enum PVRSRV_ERROR SGXUnregisterHWTransferContextKM(void *hHWTransferContext)
627 {
628         struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *psCleanup;
629
630         PVR_ASSERT(hHWTransferContext != NULL);
631
632         psCleanup =
633             (struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *)hHWTransferContext;
634
635         if (psCleanup == NULL) {
636                 PVR_DPF(PVR_DBG_ERROR, "SGXUnregisterHWTransferContextKM: "
637                                                 "invalid parameter");
638                 return PVRSRV_ERROR_INVALID_PARAMS;
639         }
640
641         ResManFreeResByPtr(psCleanup->psResItem);
642
643         return PVRSRV_OK;
644 }
645
646 static inline IMG_BOOL SGX2DQuerySyncOpsComplete(
647                                 struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo,
648                                 u32 ui32ReadOpsPending, u32 ui32WriteOpsPending)
649 {
650         struct PVRSRV_SYNC_DATA *psSyncData = psSyncInfo->psSyncData;
651
652         return (IMG_BOOL)((psSyncData->ui32ReadOpsComplete >=
653                                 ui32ReadOpsPending) &&
654                            (psSyncData->ui32WriteOpsComplete >=
655                                 ui32WriteOpsPending));
656 }
657
658 enum PVRSRV_ERROR SGX2DQueryBlitsCompleteKM(
659                                     struct PVRSRV_SGXDEV_INFO *psDevInfo,
660                                     struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo,
661                                     IMG_BOOL bWaitForComplete)
662 {
663         u32 ui32ReadOpsPending, ui32WriteOpsPending;
664
665         PVR_UNREFERENCED_PARAMETER(psDevInfo);
666
667         PVR_DPF(PVR_DBG_CALLTRACE, "SGX2DQueryBlitsCompleteKM: Start");
668
669         ui32ReadOpsPending = psSyncInfo->psSyncData->ui32ReadOpsPending;
670         ui32WriteOpsPending = psSyncInfo->psSyncData->ui32WriteOpsPending;
671
672         if (SGX2DQuerySyncOpsComplete
673             (psSyncInfo, ui32ReadOpsPending, ui32WriteOpsPending)) {
674
675                 PVR_DPF(PVR_DBG_CALLTRACE,
676                          "SGX2DQueryBlitsCompleteKM: No wait. Blits complete.");
677                 return PVRSRV_OK;
678         }
679
680         if (!bWaitForComplete) {
681
682                 PVR_DPF(PVR_DBG_CALLTRACE,
683                          "SGX2DQueryBlitsCompleteKM: No wait. Ops pending.");
684                 return PVRSRV_ERROR_CMD_NOT_PROCESSED;
685         }
686
687         PVR_DPF(PVR_DBG_MESSAGE,
688                  "SGX2DQueryBlitsCompleteKM: Ops pending. Start polling.");
689         LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) {
690                 OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT);
691
692                 if (SGX2DQuerySyncOpsComplete
693                     (psSyncInfo, ui32ReadOpsPending, ui32WriteOpsPending)) {
694
695                         PVR_DPF(PVR_DBG_CALLTRACE,
696                                         "SGX2DQueryBlitsCompleteKM: "
697                                         "Wait over.  Blits complete.");
698                         return PVRSRV_OK;
699                 }
700         }
701         END_LOOP_UNTIL_TIMEOUT();
702
703         PVR_DPF(PVR_DBG_ERROR,
704                  "SGX2DQueryBlitsCompleteKM: Timed out. Ops pending.");
705
706 #if defined(CONFIG_PVR_DEBUG_EXTRA)
707         {
708                 struct PVRSRV_SYNC_DATA *psSyncData = psSyncInfo->psSyncData;
709
710                 PVR_TRACE("SGX2DQueryBlitsCompleteKM: "
711                            "Syncinfo: %p, Syncdata: %p",
712                            psSyncInfo, psSyncData);
713
714                 PVR_TRACE("SGX2DQueryBlitsCompleteKM: "
715                            "Read ops complete: %d, Read ops pending: %d",
716                            psSyncData->ui32ReadOpsComplete,
717                            psSyncData->ui32ReadOpsPending);
718                 PVR_TRACE("SGX2DQueryBlitsCompleteKM: "
719                           "Write ops complete: %d, Write ops pending: %d",
720                           psSyncData->ui32WriteOpsComplete,
721                           psSyncData->ui32WriteOpsPending);
722
723         }
724 #endif
725         return PVRSRV_ERROR_TIMEOUT;
726 }
727
728 void SGXFlushHWRenderTargetKM(void *psDeviceNode,
729                               struct IMG_DEV_VIRTADDR sHWRTDataSetDevVAddr)
730 {
731         PVR_ASSERT(sHWRTDataSetDevVAddr.uiAddr);
732
733         SGXCleanupRequest((struct PVRSRV_DEVICE_NODE *)psDeviceNode,
734                           &sHWRTDataSetDevVAddr,
735                           PVRSRV_USSE_EDM_RESMAN_CLEANUP_RT_REQUEST);
736 }
737
738 u32 SGXConvertTimeStamp(struct PVRSRV_SGXDEV_INFO *psDevInfo, u32 ui32TimeWraps,
739                         u32 ui32Time)
740 {
741         u64 ui64Clocks;
742         u32 ui32Clocksx16;
743
744         ui64Clocks = ((u64) ui32TimeWraps * psDevInfo->ui32uKernelTimerClock) +
745             (psDevInfo->ui32uKernelTimerClock -
746              (ui32Time & EUR_CR_EVENT_TIMER_VALUE_MASK));
747         ui32Clocksx16 = (u32) (ui64Clocks / 16);
748
749         return ui32Clocksx16;
750 }