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