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