RK3368 GPU: Rogue N Init.
[firefly-linux-kernel-4.4.55.git] / drivers / staging / imgtec / rogue / pvr_notifier.c
1 /*************************************************************************/ /*!
2 @File
3 @Title          PowerVR notifier interface
4 @Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @License        Dual MIT/GPLv2
6
7 The contents of this file are subject to the MIT license as set out below.
8
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 Alternatively, the contents of this file may be used under the terms of
20 the GNU General Public License Version 2 ("GPL") in which case the provisions
21 of GPL are applicable instead of those above.
22
23 If you wish to allow use of your version of this file only under the terms of
24 GPL, and not to allow others to use your version of this file under the terms
25 of the MIT license, indicate your decision by deleting the provisions above
26 and replace them with the notice and other provisions required by GPL as set
27 out in the file called "GPL-COPYING" included in this distribution. If you do
28 not delete the provisions above, a recipient may use your version of this file
29 under the terms of either the MIT license or GPL.
30
31 This License is also included in this distribution in the file called
32 "MIT-COPYING".
33
34 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
35 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
36 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
37 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
38 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
39 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 */ /**************************************************************************/
42
43 #include "allocmem.h"
44 #include "device.h"
45 #include "dllist.h"
46 #include "img_defs.h"
47 #include "osfunc.h"
48 #include "pvr_notifier.h"
49 #include "pvrsrv.h"
50 #include "pvrversion.h"
51
52
53 /*************************************************************************/ /*!
54 Command Complete Notifier Interface
55 */ /**************************************************************************/
56
57 typedef struct PVRSRV_CMDCOMP_NOTIFY_TAG
58 {
59         PVRSRV_CMDCOMP_HANDLE   hCmdCompHandle;
60         PFN_CMDCOMP_NOTIFY              pfnCmdCompleteNotify;
61         DLLIST_NODE                             sListNode;
62 } PVRSRV_CMDCOMP_NOTIFY;
63
64 /* Head of the list of callbacks called when command complete happens */
65 static DLLIST_NODE g_sCmdCompNotifyHead;
66 static POSWR_LOCK g_hCmdCompNotifyLock;
67
68 PVRSRV_ERROR
69 PVRSRVCmdCompleteInit(void)
70 {
71         PVRSRV_ERROR eError;
72
73         eError = OSWRLockCreate(&g_hCmdCompNotifyLock);
74         if (eError != PVRSRV_OK)
75         {
76                 return eError;
77         }
78
79         dllist_init(&g_sCmdCompNotifyHead);
80
81         return PVRSRV_OK;
82 }
83
84 void
85 PVRSRVCmdCompleteDeinit(void)
86 {
87         /* Check that all notify function have been unregistered */
88         if (!dllist_is_empty(&g_sCmdCompNotifyHead))
89         {
90                 PDLLIST_NODE psNode;
91
92                 PVR_DPF((PVR_DBG_ERROR,
93                                  "%s: Command complete notify list is not empty!", __func__));
94
95                 /* Clean up any stragglers */
96                 psNode = dllist_get_next_node(&g_sCmdCompNotifyHead);
97                 while (psNode)
98                 {
99                         PVRSRV_CMDCOMP_NOTIFY *psNotify;
100
101                         dllist_remove_node(psNode);
102                         
103                         psNotify = IMG_CONTAINER_OF(psNode, PVRSRV_CMDCOMP_NOTIFY, sListNode);
104                         OSFreeMem(psNotify);
105
106                         psNode = dllist_get_next_node(&g_sCmdCompNotifyHead);
107                 }
108         }
109
110         if (g_hCmdCompNotifyLock)
111         {
112                 OSWRLockDestroy(g_hCmdCompNotifyLock);
113         }
114 }
115
116 PVRSRV_ERROR
117 PVRSRVRegisterCmdCompleteNotify(IMG_HANDLE *phNotify,
118                                                                 PFN_CMDCOMP_NOTIFY pfnCmdCompleteNotify,
119                                                                 PVRSRV_CMDCOMP_HANDLE hCmdCompHandle)
120 {
121         PVRSRV_CMDCOMP_NOTIFY *psNotify;
122
123         if (!phNotify || !pfnCmdCompleteNotify || !hCmdCompHandle)
124         {
125                 PVR_DPF((PVR_DBG_ERROR, "%s: Bad arguments (%p, %p, %p)",
126                                  __func__, phNotify, pfnCmdCompleteNotify, hCmdCompHandle));
127                 return PVRSRV_ERROR_INVALID_PARAMS;
128         }
129
130         psNotify = OSAllocMem(sizeof(*psNotify));
131         if (!psNotify)
132         {
133                 PVR_DPF((PVR_DBG_ERROR,
134                                  "%s: Not enough memory to allocate CmdCompleteNotify function",
135                                  __func__));
136                 return PVRSRV_ERROR_OUT_OF_MEMORY;              
137         }
138
139         /* Set-up the notify data */
140         psNotify->hCmdCompHandle = hCmdCompHandle;
141         psNotify->pfnCmdCompleteNotify = pfnCmdCompleteNotify;
142
143         /* Add it to the list of Notify functions */
144         OSWRLockAcquireWrite(g_hCmdCompNotifyLock);
145         dllist_add_to_tail(&g_sCmdCompNotifyHead, &psNotify->sListNode);
146         OSWRLockReleaseWrite(g_hCmdCompNotifyLock);
147
148         *phNotify = psNotify;
149
150         return PVRSRV_OK;
151 }
152
153 PVRSRV_ERROR
154 PVRSRVUnregisterCmdCompleteNotify(IMG_HANDLE hNotify)
155 {
156         PVRSRV_CMDCOMP_NOTIFY *psNotify;
157
158         psNotify = (PVRSRV_CMDCOMP_NOTIFY *) hNotify;
159         if (!psNotify)
160         {
161                 PVR_DPF((PVR_DBG_ERROR," %s: Bad arguments (%p)", __func__, hNotify));
162                 return PVRSRV_ERROR_INVALID_PARAMS;
163         }
164
165         OSWRLockAcquireWrite(g_hCmdCompNotifyLock);
166         dllist_remove_node(&psNotify->sListNode);
167         OSWRLockReleaseWrite(g_hCmdCompNotifyLock);
168
169         OSFreeMem(psNotify);
170
171         return PVRSRV_OK;
172 }
173
174 void
175 PVRSRVCheckStatus(PVRSRV_CMDCOMP_HANDLE hCmdCompCallerHandle)
176 {
177         PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
178 #if !defined(NO_HARDWARE)
179         DLLIST_NODE *psNode, *psNext;
180 #endif
181
182         /* Call notify callbacks to check if blocked work items can now proceed */
183 #if !defined(NO_HARDWARE)
184         OSWRLockAcquireRead(g_hCmdCompNotifyLock);
185         dllist_foreach_node(&g_sCmdCompNotifyHead, psNode, psNext)
186         {
187                 PVRSRV_CMDCOMP_NOTIFY *psNotify =
188                         IMG_CONTAINER_OF(psNode, PVRSRV_CMDCOMP_NOTIFY, sListNode);
189
190                 if (hCmdCompCallerHandle != psNotify->hCmdCompHandle)
191                 {
192                         psNotify->pfnCmdCompleteNotify(psNotify->hCmdCompHandle);
193                 }
194         }
195         OSWRLockReleaseRead(g_hCmdCompNotifyLock);
196 #endif
197
198         if (psPVRSRVData->hGlobalEventObject)
199         {
200                 OSEventObjectSignal(psPVRSRVData->hGlobalEventObject);
201         }
202 }
203
204 /*************************************************************************/ /*!
205 Debug Notifier Interface
206 */ /**************************************************************************/
207
208 typedef struct DEBUG_REQUEST_ENTRY_TAG
209 {
210         IMG_UINT32              ui32RequesterID;
211         DLLIST_NODE             sListHead;
212 } DEBUG_REQUEST_ENTRY;
213
214 typedef struct DEBUG_REQUEST_TABLE_TAG
215 {
216         POSWR_LOCK                              hLock;
217         IMG_UINT32                              ui32RequestCount;
218         DEBUG_REQUEST_ENTRY             asEntry[1];
219 } DEBUG_REQUEST_TABLE;
220
221 typedef struct DEBUG_REQUEST_NOTIFY_TAG
222 {
223         PVRSRV_DEVICE_NODE              *psDevNode;
224         PVRSRV_DBGREQ_HANDLE    hDbgRequestHandle;
225         PFN_DBGREQ_NOTIFY               pfnDbgRequestNotify;
226         IMG_UINT32                              ui32RequesterID;
227         DLLIST_NODE                             sListNode;
228 } DEBUG_REQUEST_NOTIFY;
229
230
231 PVRSRV_ERROR
232 PVRSRVRegisterDbgTable(PVRSRV_DEVICE_NODE *psDevNode, IMG_UINT32 *paui32Table,
233                                            IMG_UINT32 ui32Length)
234 {
235         DEBUG_REQUEST_TABLE *psDebugTable;
236         IMG_UINT32 i;
237         PVRSRV_ERROR eError;
238
239         if (psDevNode->hDebugTable)
240         {
241                 return PVRSRV_ERROR_DBGTABLE_ALREADY_REGISTERED;
242         }
243
244         psDebugTable = OSAllocMem(sizeof(DEBUG_REQUEST_TABLE) +
245                                                           (sizeof(DEBUG_REQUEST_ENTRY) * (ui32Length-1)));
246         if (!psDebugTable)
247         {
248                 return PVRSRV_ERROR_OUT_OF_MEMORY;
249         }
250
251         eError = OSWRLockCreate(&psDebugTable->hLock);
252         if (eError != PVRSRV_OK)
253         {
254                 goto ErrorFreeDebugTable;
255         }
256
257         psDebugTable->ui32RequestCount = ui32Length;
258
259         /* Init the list heads */
260         for (i = 0; i < ui32Length; i++)
261         {
262                 psDebugTable->asEntry[i].ui32RequesterID = paui32Table[i];
263                 dllist_init(&psDebugTable->asEntry[i].sListHead);
264         }
265
266         psDevNode->hDebugTable = (IMG_HANDLE *) psDebugTable;
267
268         return PVRSRV_OK;
269
270 ErrorFreeDebugTable:
271         OSFreeMem(psDebugTable);
272         psDebugTable = NULL;
273
274         return eError;
275 }
276
277 void
278 PVRSRVUnregisterDbgTable(PVRSRV_DEVICE_NODE *psDevNode)
279 {
280         DEBUG_REQUEST_TABLE *psDebugTable;
281         IMG_UINT32 i;
282
283         PVR_ASSERT(psDevNode->hDebugTable);
284         psDebugTable = (DEBUG_REQUEST_TABLE *) psDevNode->hDebugTable;
285         psDevNode->hDebugTable = NULL;
286
287         for (i = 0; i < psDebugTable->ui32RequestCount; i++)
288         {
289                 if (!dllist_is_empty(&psDebugTable->asEntry[i].sListHead))
290                 {
291                         PVR_DPF((PVR_DBG_ERROR, "%s: Found registered callback(s) on %d",
292                                          __func__, i));
293                 }
294         }
295
296         OSWRLockDestroy(psDebugTable->hLock);
297         psDebugTable->hLock = NULL;
298
299         OSFreeMem(psDebugTable);
300 }
301
302 PVRSRV_ERROR
303 PVRSRVRegisterDbgRequestNotify(IMG_HANDLE *phNotify,
304                                                            PVRSRV_DEVICE_NODE *psDevNode,
305                                                            PFN_DBGREQ_NOTIFY pfnDbgRequestNotify,
306                                                            IMG_UINT32 ui32RequesterID,
307                                                            PVRSRV_DBGREQ_HANDLE hDbgRequestHandle)
308 {
309         DEBUG_REQUEST_TABLE *psDebugTable;
310         DEBUG_REQUEST_NOTIFY *psNotify;
311         PDLLIST_NODE psHead = NULL;
312         IMG_UINT32 i;
313         PVRSRV_ERROR eError;
314
315         if (!phNotify || !psDevNode || !pfnDbgRequestNotify)
316         {
317                 PVR_DPF((PVR_DBG_ERROR, "%s: Bad arguments (%p, %p, %p)",
318                                  __func__, phNotify, psDevNode, pfnDbgRequestNotify));
319                 return PVRSRV_ERROR_INVALID_PARAMS;
320         }
321
322         psDebugTable = (DEBUG_REQUEST_TABLE *) psDevNode->hDebugTable;
323
324         PVR_ASSERT(psDebugTable);
325
326         psNotify = OSAllocMem(sizeof(*psNotify));
327         if (!psNotify)
328         {
329                 PVR_DPF((PVR_DBG_ERROR,
330                                  "%s: Not enough memory to allocate DbgRequestNotify structure",
331                                  __func__));
332                 return PVRSRV_ERROR_OUT_OF_MEMORY;
333         }
334
335         /* Set-up the notify data */
336         psNotify->psDevNode = psDevNode;
337         psNotify->hDbgRequestHandle = hDbgRequestHandle;
338         psNotify->pfnDbgRequestNotify = pfnDbgRequestNotify;
339         psNotify->ui32RequesterID = ui32RequesterID;
340
341         /* Lock down all the lists */
342         OSWRLockAcquireWrite(psDebugTable->hLock);
343
344         /* Find which list to add it to */
345         for (i = 0; i < psDebugTable->ui32RequestCount; i++)
346         {
347                 if (psDebugTable->asEntry[i].ui32RequesterID == ui32RequesterID)
348                 {
349                         psHead = &psDebugTable->asEntry[i].sListHead;
350                 }
351         }
352
353         if (!psHead)
354         {
355                 PVR_DPF((PVR_DBG_ERROR,"%s: Failed to find debug requester", __func__));
356                 eError = PVRSRV_ERROR_INVALID_PARAMS;
357                 goto ErrorReleaseLock;
358         }
359
360         /* Add it to the list of Notify functions */
361         dllist_add_to_tail(psHead, &psNotify->sListNode);
362
363         /* Unlock the lists */
364         OSWRLockReleaseWrite(psDebugTable->hLock);
365
366         *phNotify = psNotify;
367
368         return PVRSRV_OK;
369
370 ErrorReleaseLock:
371         OSWRLockReleaseWrite(psDebugTable->hLock);
372         OSFreeMem(psNotify);
373
374         return eError;
375 }
376
377 PVRSRV_ERROR
378 PVRSRVUnregisterDbgRequestNotify(IMG_HANDLE hNotify)
379 {
380         DEBUG_REQUEST_NOTIFY *psNotify = (DEBUG_REQUEST_NOTIFY *) hNotify;
381         DEBUG_REQUEST_TABLE *psDebugTable;
382
383         if (!psNotify)
384         {
385                 PVR_DPF((PVR_DBG_ERROR, "%s: Bad arguments (%p)", __func__, hNotify));
386                 return PVRSRV_ERROR_INVALID_PARAMS;
387         }
388
389         psDebugTable = (DEBUG_REQUEST_TABLE *) psNotify->psDevNode->hDebugTable;
390
391         OSWRLockAcquireWrite(psDebugTable->hLock);
392         dllist_remove_node(&psNotify->sListNode);
393         OSWRLockReleaseWrite(psDebugTable->hLock);
394
395         OSFreeMem(psNotify);
396
397         return PVRSRV_OK;
398 }
399
400 void
401 PVRSRVDebugRequest(PVRSRV_DEVICE_NODE *psDevNode,
402                                    IMG_UINT32 ui32VerbLevel,
403                                    DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
404                                    void *pvDumpDebugFile)
405 {
406         PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
407         DEBUG_REQUEST_TABLE *psDebugTable =
408                 (DEBUG_REQUEST_TABLE *) psDevNode->hDebugTable;
409         static const IMG_CHAR *apszVerbosityTable[] = { "Low", "Medium", "High" };
410         const IMG_CHAR *szVerbosityLevel;
411         IMG_UINT32 i;
412         IMG_UINT32 j;
413
414         static_assert(IMG_ARR_NUM_ELEMS(apszVerbosityTable) == DEBUG_REQUEST_VERBOSITY_MAX+1,
415                       "Incorrect number of verbosity levels");
416
417         PVR_ASSERT(psDebugTable);
418
419         if (!pfnDumpDebugPrintf)
420         {
421                 /*
422                  * Only dump the call stack to the kernel log if the debug text is going
423                  * there.
424                  */
425                 OSDumpStack();
426         }
427
428         OSWRLockAcquireRead(psDebugTable->hLock);
429
430         if (ui32VerbLevel < IMG_ARR_NUM_ELEMS(apszVerbosityTable))
431         {
432                 szVerbosityLevel = apszVerbosityTable[ui32VerbLevel];
433         }
434         else
435         {
436                 szVerbosityLevel = "unknown";
437                 PVR_ASSERT(!"Invalid verbosity level received");
438         }
439
440         PVR_DUMPDEBUG_LOG("------------[ PVR DBG: START (%s) ]------------",
441                         szVerbosityLevel);
442
443         PVR_DUMPDEBUG_LOG("DDK info: %s (%s) %s",
444                                            PVRVERSION_STRING, PVR_BUILD_TYPE, PVR_BUILD_DIR);
445         PVR_DUMPDEBUG_LOG("Time now: %015llu", OSClockus64());
446
447         switch (psPVRSRVData->eServicesState)
448         {
449                 case PVRSRV_SERVICES_STATE_OK:
450                         PVR_DUMPDEBUG_LOG("Services State: OK");
451                         break;
452                 case PVRSRV_SERVICES_STATE_BAD:
453                         PVR_DUMPDEBUG_LOG("Services State: BAD");
454                         break;
455                 default:
456                         PVR_DUMPDEBUG_LOG("Services State: UNKNOWN (%d)",
457                                                            psPVRSRVData->eServicesState);
458                         break;
459         }
460
461         /* For each verbosity level */
462         for (j = 0; j <= ui32VerbLevel; j++)
463         {
464                 /* For each requester */
465                 for (i = 0; i < psDebugTable->ui32RequestCount; i++)
466                 {
467                         DLLIST_NODE *psNode;
468                         DLLIST_NODE *psNext;
469
470                         dllist_foreach_node(&psDebugTable->asEntry[i].sListHead, psNode, psNext)
471                         {
472                                 DEBUG_REQUEST_NOTIFY *psNotify =
473                                         IMG_CONTAINER_OF(psNode, DEBUG_REQUEST_NOTIFY, sListNode);
474                                 psNotify->pfnDbgRequestNotify(psNotify->hDbgRequestHandle, j,
475                                                                 pfnDumpDebugPrintf, pvDumpDebugFile);
476                         }
477                 }
478         }
479
480         PVR_DUMPDEBUG_LOG("------------[ PVR DBG: END ]------------");
481         OSWRLockReleaseRead(psDebugTable->hLock);
482 }