gpu: pvr: pdumpfs: add stream_frames debugfs entry
[sgx.git] / pvr / resman.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 <linux/version.h>
28 #include <linux/sched.h>
29 #include <linux/hardirq.h>
30
31 #include <linux/semaphore.h>
32
33 #include "services_headers.h"
34 #include "resman.h"
35
36 static DEFINE_SEMAPHORE(lock);
37
38 #define ACQUIRE_SYNC_OBJ  do {                                             \
39                 if (in_interrupt()) {                                      \
40                         printk(KERN_ERR "ISR cannot take RESMAN mutex\n"); \
41                         BUG();                                             \
42         } else                                                          \
43                         down(&lock);                                       \
44 } while (0)
45 #define RELEASE_SYNC_OBJ up(&lock)
46
47
48 #define RESMAN_SIGNATURE 0x12345678
49
50 struct RESMAN_ITEM {
51 #ifdef CONFIG_PVR_DEBUG
52         u32 ui32Signature;
53 #endif
54         struct RESMAN_ITEM **ppsThis;
55         struct RESMAN_ITEM *psNext;
56
57         u32 ui32Flags;
58         u32 ui32ResType;
59
60         void *pvParam;
61         u32 ui32Param;
62
63         enum PVRSRV_ERROR (*pfnFreeResource)(void *pvParam, u32 ui32Param);
64 };
65
66 struct RESMAN_CONTEXT {
67 #ifdef CONFIG_PVR_DEBUG
68         u32 ui32Signature;
69 #endif
70         struct RESMAN_CONTEXT **ppsThis;
71         struct RESMAN_CONTEXT *psNext;
72         struct PVRSRV_PER_PROCESS_DATA *psPerProc;
73         struct RESMAN_ITEM *psResItemList;
74
75 };
76
77 struct RESMAN_LIST {
78         struct RESMAN_CONTEXT *psContextList;
79 };
80
81 static struct RESMAN_LIST *gpsResList;
82
83 #define PRINT_RESLIST(x, y, z)
84
85 static void FreeResourceByPtr(struct RESMAN_ITEM *psItem,
86                                            IMG_BOOL bExecuteCallback);
87
88 static int FreeResourceByCriteria(struct RESMAN_CONTEXT *psContext,
89                                            u32 ui32SearchCriteria,
90                                            u32 ui32ResType, void *pvParam,
91                                            u32 ui32Param,
92                                            IMG_BOOL bExecuteCallback);
93
94 #ifdef CONFIG_PVR_DEBUG_EXTRA
95 static void ValidateResList(struct RESMAN_LIST *psResList);
96 #define VALIDATERESLIST() ValidateResList(gpsResList)
97 #else
98 #define VALIDATERESLIST()
99 #endif
100
101 enum PVRSRV_ERROR ResManInit(void)
102 {
103         if (gpsResList == NULL) {
104
105                 if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
106                                sizeof(*gpsResList),
107                                (void **) &gpsResList,
108                                NULL) != PVRSRV_OK)
109                         return PVRSRV_ERROR_OUT_OF_MEMORY;
110
111                 gpsResList->psContextList = NULL;
112
113                 VALIDATERESLIST();
114         }
115
116         return PVRSRV_OK;
117 }
118
119 void ResManDeInit(void)
120 {
121         if (gpsResList != NULL)
122                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*gpsResList),
123                           gpsResList, NULL);
124 }
125
126 enum PVRSRV_ERROR PVRSRVResManConnect(void *hPerProc,
127                                  struct RESMAN_CONTEXT **phResManContext)
128 {
129         enum PVRSRV_ERROR eError;
130         struct RESMAN_CONTEXT *psResManContext;
131
132         ACQUIRE_SYNC_OBJ;
133
134         VALIDATERESLIST();
135
136         eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psResManContext),
137                             (void **) &psResManContext, NULL);
138         if (eError != PVRSRV_OK) {
139                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVResManConnect: "
140                                 "ERROR allocating new RESMAN context struct");
141
142                 VALIDATERESLIST();
143                 RELEASE_SYNC_OBJ;
144
145                 return eError;
146         }
147 #ifdef CONFIG_PVR_DEBUG
148         psResManContext->ui32Signature = RESMAN_SIGNATURE;
149 #endif
150         psResManContext->psResItemList = NULL;
151         psResManContext->psPerProc = hPerProc;
152
153         psResManContext->psNext = gpsResList->psContextList;
154         psResManContext->ppsThis = &gpsResList->psContextList;
155         gpsResList->psContextList = psResManContext;
156         if (psResManContext->psNext)
157                 psResManContext->psNext->ppsThis = &(psResManContext->psNext);
158
159         VALIDATERESLIST();
160
161         RELEASE_SYNC_OBJ;
162
163         *phResManContext = psResManContext;
164
165         return PVRSRV_OK;
166 }
167
168 static inline bool warn_unfreed_res(void)
169 {
170         return !(current->flags & PF_SIGNALED);
171 }
172
173 static int free_one_res(struct RESMAN_CONTEXT *ctx, u32 restype)
174 {
175         int freed;
176
177         freed = FreeResourceByCriteria(ctx, RESMAN_CRITERIA_RESTYPE, restype,
178                                         NULL, 0, IMG_TRUE);
179         if (freed && warn_unfreed_res())
180                 PVR_DPF(DBGPRIV_WARNING, "pvr: %s: cleaning up %d "
181                            "unfreed resource of type %d\n",
182                            current->comm, freed, restype);
183
184         return freed;
185 }
186
187 void PVRSRVResManDisconnect(struct RESMAN_CONTEXT *ctx, IMG_BOOL bKernelContext)
188 {
189
190         ACQUIRE_SYNC_OBJ;
191
192         VALIDATERESLIST();
193
194         PRINT_RESLIST(gpsResList, ctx, IMG_TRUE);
195
196         if (!bKernelContext) {
197                 int i = 0;
198
199                 i += free_one_res(ctx, RESMAN_TYPE_OS_USERMODE_MAPPING);
200                 i += free_one_res(ctx, RESMAN_TYPE_EVENT_OBJECT);
201                 i += free_one_res(ctx, RESMAN_TYPE_HW_RENDER_CONTEXT);
202                 i += free_one_res(ctx, RESMAN_TYPE_HW_TRANSFER_CONTEXT);
203                 i += free_one_res(ctx, RESMAN_TYPE_HW_2D_CONTEXT);
204                 i += free_one_res(ctx, RESMAN_TYPE_TRANSFER_CONTEXT);
205                 i += free_one_res(ctx, RESMAN_TYPE_SHARED_PB_DESC_CREATE_LOCK);
206                 i += free_one_res(ctx, RESMAN_TYPE_SHARED_PB_DESC);
207                 i += free_one_res(ctx, RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN);
208                 i += free_one_res(ctx, RESMAN_TYPE_DISPLAYCLASS_DEVICE);
209                 i += free_one_res(ctx, RESMAN_TYPE_BUFFERCLASS_DEVICE);
210                 i += free_one_res(ctx, RESMAN_TYPE_DEVICECLASSMEM_MAPPING);
211                 i += free_one_res(ctx, RESMAN_TYPE_DEVICEMEM_WRAP);
212                 i += free_one_res(ctx, RESMAN_TYPE_DEVICEMEM_MAPPING);
213                 i += free_one_res(ctx, RESMAN_TYPE_KERNEL_DEVICEMEM_ALLOCATION);
214                 i += free_one_res(ctx, RESMAN_TYPE_DEVICEMEM_ALLOCATION);
215                 i += free_one_res(ctx, RESMAN_TYPE_DEVICEMEM_CONTEXT);
216
217                 if (i && warn_unfreed_res())
218                         pr_warning("pvr: %s: cleaning up %d "
219                                    "unfreed resources\n",
220                                    current->comm, i);
221         }
222
223         PVR_ASSERT(ctx->psResItemList == NULL);
224
225         *(ctx->ppsThis) = ctx->psNext;
226         if (ctx->psNext)
227                 ctx->psNext->ppsThis = ctx->ppsThis;
228
229         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RESMAN_CONTEXT),
230                   ctx, NULL);
231
232         VALIDATERESLIST();
233
234         PRINT_RESLIST(gpsResList, ctx, IMG_FALSE);
235
236         RELEASE_SYNC_OBJ;
237 }
238
239 struct RESMAN_ITEM *ResManRegisterRes(struct RESMAN_CONTEXT *psResManContext,
240                                       u32 ui32ResType, void *pvParam,
241                                       u32 ui32Param,
242                                       enum PVRSRV_ERROR (*pfnFreeResource)
243                                                 (void *pvParam, u32 ui32Param))
244 {
245         struct RESMAN_ITEM *psNewResItem;
246
247         PVR_ASSERT(psResManContext != NULL);
248         PVR_ASSERT(ui32ResType != 0);
249
250         if (psResManContext == NULL) {
251                 PVR_DPF(PVR_DBG_ERROR, "ResManRegisterRes: "
252                                         "invalid parameter - psResManContext");
253                 return (struct RESMAN_ITEM *)NULL;
254         }
255
256         ACQUIRE_SYNC_OBJ;
257
258         VALIDATERESLIST();
259
260         PVR_DPF(PVR_DBG_MESSAGE, "ResManRegisterRes: register resource "
261                  "Context 0x%x, ResType 0x%x, pvParam 0x%x, ui32Param 0x%x, "
262                  "FreeFunc %08X",
263                  psResManContext, ui32ResType, (u32) pvParam,
264                  ui32Param, pfnFreeResource);
265
266         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
267                        sizeof(struct RESMAN_ITEM), (void **) &psNewResItem,
268                        NULL) != PVRSRV_OK) {
269                 PVR_DPF(PVR_DBG_ERROR, "ResManRegisterRes: "
270                          "ERROR allocating new resource item");
271
272                 RELEASE_SYNC_OBJ;
273
274                 return (struct RESMAN_ITEM *)NULL;
275         }
276
277 #ifdef CONFIG_PVR_DEBUG
278         psNewResItem->ui32Signature = RESMAN_SIGNATURE;
279 #endif
280         psNewResItem->ui32ResType = ui32ResType;
281         psNewResItem->pvParam = pvParam;
282         psNewResItem->ui32Param = ui32Param;
283         psNewResItem->pfnFreeResource = pfnFreeResource;
284         psNewResItem->ui32Flags = 0;
285
286         psNewResItem->ppsThis = &psResManContext->psResItemList;
287         psNewResItem->psNext = psResManContext->psResItemList;
288         psResManContext->psResItemList = psNewResItem;
289         if (psNewResItem->psNext)
290                 psNewResItem->psNext->ppsThis = &psNewResItem->psNext;
291
292         VALIDATERESLIST();
293
294         RELEASE_SYNC_OBJ;
295
296         return psNewResItem;
297 }
298
299 void ResManFreeResByPtr(struct RESMAN_ITEM *psResItem)
300 {
301         BUG_ON(!psResItem);
302
303         PVR_DPF(PVR_DBG_MESSAGE,
304                  "ResManFreeResByPtr: freeing resource at %08X", psResItem);
305
306         ACQUIRE_SYNC_OBJ;
307
308         VALIDATERESLIST();
309
310         FreeResourceByPtr(psResItem, IMG_TRUE);
311
312         VALIDATERESLIST();
313
314         RELEASE_SYNC_OBJ;
315 }
316
317 void ResManFreeResByCriteria(struct RESMAN_CONTEXT *psResManContext,
318                                 u32 ui32SearchCriteria, u32 ui32ResType,
319                                 void *pvParam, u32 ui32Param)
320 {
321         PVR_ASSERT(psResManContext != NULL);
322
323         ACQUIRE_SYNC_OBJ;
324
325         VALIDATERESLIST();
326
327         PVR_DPF(PVR_DBG_MESSAGE, "ResManFreeResByCriteria: "
328                 "Context 0x%x, Criteria 0x%x, Type 0x%x, Addr 0x%x, Param 0x%x",
329                  psResManContext, ui32SearchCriteria, ui32ResType,
330                  (u32) pvParam, ui32Param);
331
332         (void)FreeResourceByCriteria(psResManContext, ui32SearchCriteria,
333                                         ui32ResType, pvParam, ui32Param,
334                                         IMG_TRUE);
335
336         VALIDATERESLIST();
337
338         RELEASE_SYNC_OBJ;
339 }
340
341 enum PVRSRV_ERROR ResManDissociateRes(struct RESMAN_ITEM *psResItem,
342                              struct RESMAN_CONTEXT *psNewResManContext)
343 {
344         PVR_ASSERT(psResItem != NULL);
345
346         if (psResItem == NULL) {
347                 PVR_DPF(PVR_DBG_ERROR,
348                          "ResManDissociateRes: invalid parameter - psResItem");
349                 PVR_DBG_BREAK;
350                 return PVRSRV_ERROR_INVALID_PARAMS;
351         }
352 #ifdef CONFIG_PVR_DEBUG
353         PVR_ASSERT(psResItem->ui32Signature == RESMAN_SIGNATURE);
354 #endif
355
356         if (psNewResManContext != NULL) {
357                 if (psResItem->psNext)
358                         psResItem->psNext->ppsThis = psResItem->ppsThis;
359                 *psResItem->ppsThis = psResItem->psNext;
360
361                 psResItem->ppsThis = &psNewResManContext->psResItemList;
362                 psResItem->psNext = psNewResManContext->psResItemList;
363                 psNewResManContext->psResItemList = psResItem;
364                 if (psResItem->psNext)
365                         psResItem->psNext->ppsThis = &psResItem->psNext;
366         } else {
367                 FreeResourceByPtr(psResItem, IMG_FALSE);
368         }
369
370         return PVRSRV_OK;
371 }
372
373 enum PVRSRV_ERROR ResManFindResourceByPtr(
374                                         struct RESMAN_CONTEXT *psResManContext,
375                                         struct RESMAN_ITEM *psItem)
376 {
377         struct RESMAN_ITEM *psCurItem;
378
379         PVR_ASSERT(psResManContext != NULL);
380         PVR_ASSERT(psItem != NULL);
381
382         if ((psItem == NULL) || (psResManContext == NULL)) {
383                 PVR_DPF(PVR_DBG_ERROR,
384                          "ResManFindResourceByPtr: invalid parameter");
385                 PVR_DBG_BREAK;
386                 return PVRSRV_ERROR_INVALID_PARAMS;
387         }
388 #ifdef CONFIG_PVR_DEBUG
389         PVR_ASSERT(psItem->ui32Signature == RESMAN_SIGNATURE);
390 #endif
391
392         ACQUIRE_SYNC_OBJ;
393
394         PVR_DPF(PVR_DBG_MESSAGE,
395                  "FindResourceByPtr: psItem=%08X, psItem->psNext=%08X",
396                  psItem, psItem->psNext);
397
398         PVR_DPF(PVR_DBG_MESSAGE,
399                  "FindResourceByPtr: Resource Ctx 0x%x, Type 0x%x, Addr 0x%x, "
400                  "Param 0x%x, FnCall %08X, Flags 0x%x",
401                  psResManContext,
402                  psItem->ui32ResType, (u32) psItem->pvParam,
403                  psItem->ui32Param, psItem->pfnFreeResource,
404                  psItem->ui32Flags);
405
406         psCurItem = psResManContext->psResItemList;
407
408         while (psCurItem != NULL) {
409                 if (psCurItem != psItem) {
410                         psCurItem = psCurItem->psNext;
411                 } else {
412                         RELEASE_SYNC_OBJ;
413                         return PVRSRV_OK;
414                 }
415         }
416
417         RELEASE_SYNC_OBJ;
418
419         return PVRSRV_ERROR_NOT_OWNER;
420 }
421
422 static void FreeResourceByPtr(struct RESMAN_ITEM *psItem,
423                                       IMG_BOOL bExecuteCallback)
424 {
425         PVR_ASSERT(psItem->ui32Signature == RESMAN_SIGNATURE);
426
427         PVR_DPF(PVR_DBG_MESSAGE,
428                  "FreeResourceByPtr: psItem=%08X, psItem->psNext=%08X",
429                  psItem, psItem->psNext);
430
431         PVR_DPF(PVR_DBG_MESSAGE,
432                  "FreeResourceByPtr: Type 0x%x, Addr 0x%x, "
433                  "Param 0x%x, FnCall %08X, Flags 0x%x",
434                  psItem->ui32ResType, (u32) psItem->pvParam,
435                  psItem->ui32Param, psItem->pfnFreeResource,
436                  psItem->ui32Flags);
437
438         if (psItem->psNext)
439                 psItem->psNext->ppsThis = psItem->ppsThis;
440         *psItem->ppsThis = psItem->psNext;
441
442         RELEASE_SYNC_OBJ;
443
444         if (bExecuteCallback &&
445             psItem->pfnFreeResource(psItem->pvParam, psItem->ui32Param) !=
446                         PVRSRV_OK)
447                 PVR_DPF(PVR_DBG_ERROR, "FreeResourceByPtr: "
448                                         "ERROR calling FreeResource function");
449
450         ACQUIRE_SYNC_OBJ;
451
452         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RESMAN_ITEM), psItem,
453                   NULL);
454 }
455
456 static struct RESMAN_ITEM *find_res_by_crit(struct RESMAN_CONTEXT *res_ctx,
457                                             u32 crit, u32 res_type,
458                                             void *ppar, u32 upar)
459 {
460         struct RESMAN_ITEM *item;
461
462         for (item = res_ctx->psResItemList; item; item = item->psNext) {
463                 if ((crit & RESMAN_CRITERIA_RESTYPE) &&
464                     item->ui32ResType != res_type)
465                         continue;
466                 else if ((crit & RESMAN_CRITERIA_PVOID_PARAM) &&
467                          item->pvParam != ppar)
468                         continue;
469                 else if ((crit & RESMAN_CRITERIA_UI32_PARAM) &&
470                          item->ui32Param != upar)
471                         continue;
472
473                 break;
474         }
475
476         return item;
477 }
478
479 struct RESMAN_CONTEXT *pvr_get_resman_ctx(void *resource)
480 {
481         struct RESMAN_CONTEXT *ctx;
482
483         for (ctx = gpsResList->psContextList; ctx; ctx = ctx->psNext) {
484                 struct RESMAN_ITEM *item;
485
486                 item = find_res_by_crit(ctx, RESMAN_CRITERIA_PVOID_PARAM,
487                                         0, resource, 0);
488                 if (item)
489                         return ctx;
490         }
491         return NULL;
492 }
493
494 struct PVRSRV_PER_PROCESS_DATA *pvr_get_proc_by_ctx(struct RESMAN_CONTEXT *ctx)
495 {
496         return ctx->psPerProc;
497 }
498
499 static int FreeResourceByCriteria(struct RESMAN_CONTEXT *psResManContext,
500                                 u32 ui32SearchCriteria, u32 ui32ResType,
501                                 void *pvParam, u32 ui32Param,
502                                 IMG_BOOL bExecuteCallback)
503 {
504         struct RESMAN_ITEM *item;
505         int freed = 0;
506
507         do {
508                 item = find_res_by_crit(psResManContext,
509                                         ui32SearchCriteria, ui32ResType,
510                                         pvParam, ui32Param);
511                 if (item) {
512                         FreeResourceByPtr(item, bExecuteCallback);
513                         freed++;
514                 }
515         } while (item);
516
517         return freed;
518 }
519
520 #ifdef CONFIG_PVR_DEBUG_EXTRA
521 static void ValidateResList(struct RESMAN_LIST *psResList)
522 {
523         struct RESMAN_ITEM *psCurItem, **ppsThisItem;
524         struct RESMAN_CONTEXT *psCurContext, **ppsThisContext;
525
526         if (psResList == NULL) {
527                 PVR_DPF(PVR_DBG_MESSAGE,
528                          "ValidateResList: resman not initialised yet");
529                 return;
530         }
531
532         psCurContext = psResList->psContextList;
533         ppsThisContext = &psResList->psContextList;
534
535         while (psCurContext != NULL) {
536                 PVR_ASSERT(psCurContext->ui32Signature == RESMAN_SIGNATURE);
537                 if (psCurContext->ppsThis != ppsThisContext) {
538                         PVR_DPF(PVR_DBG_WARNING, "psCC=%08X "
539                              "psCC->ppsThis=%08X psCC->psNext=%08X ppsTC=%08X",
540                                  psCurContext, psCurContext->ppsThis,
541                                  psCurContext->psNext, ppsThisContext);
542                         PVR_ASSERT(psCurContext->ppsThis == ppsThisContext);
543                 }
544
545                 psCurItem = psCurContext->psResItemList;
546                 ppsThisItem = &psCurContext->psResItemList;
547                 while (psCurItem != NULL) {
548                         PVR_ASSERT(psCurItem->ui32Signature ==
549                                    RESMAN_SIGNATURE);
550                         if (psCurItem->ppsThis != ppsThisItem) {
551                                 PVR_DPF(PVR_DBG_WARNING, "psCurItem=%08X "
552                                         "psCurItem->ppsThis=%08X "
553                                         "psCurItem->psNext=%08X "
554                                         "ppsThisItem=%08X",
555                                          psCurItem, psCurItem->ppsThis,
556                                          psCurItem->psNext, ppsThisItem);
557                                 PVR_ASSERT(psCurItem->ppsThis == ppsThisItem);
558                         }
559
560                         ppsThisItem = &psCurItem->psNext;
561                         psCurItem = psCurItem->psNext;
562                 }
563
564                 ppsThisContext = &psCurContext->psNext;
565                 psCurContext = psCurContext->psNext;
566         }
567 }
568 #endif