1 /**********************************************************************
3 * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
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.
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.
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.
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
21 * Contact Information:
22 * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23 * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
25 ******************************************************************************/
27 #include <linux/version.h>
28 #include <linux/sched.h>
29 #include <linux/hardirq.h>
31 #include <linux/semaphore.h>
33 #include "services_headers.h"
36 static DEFINE_SEMAPHORE(lock);
38 #define ACQUIRE_SYNC_OBJ do { \
39 if (in_interrupt()) { \
40 printk(KERN_ERR "ISR cannot take RESMAN mutex\n"); \
45 #define RELEASE_SYNC_OBJ up(&lock)
48 #define RESMAN_SIGNATURE 0x12345678
51 #ifdef CONFIG_PVR_DEBUG
54 struct RESMAN_ITEM **ppsThis;
55 struct RESMAN_ITEM *psNext;
63 enum PVRSRV_ERROR (*pfnFreeResource)(void *pvParam, u32 ui32Param);
66 struct RESMAN_CONTEXT {
67 #ifdef CONFIG_PVR_DEBUG
70 struct RESMAN_CONTEXT **ppsThis;
71 struct RESMAN_CONTEXT *psNext;
72 struct PVRSRV_PER_PROCESS_DATA *psPerProc;
73 struct RESMAN_ITEM *psResItemList;
78 struct RESMAN_CONTEXT *psContextList;
81 static struct RESMAN_LIST *gpsResList;
83 #define PRINT_RESLIST(x, y, z)
85 static void FreeResourceByPtr(struct RESMAN_ITEM *psItem,
86 IMG_BOOL bExecuteCallback);
88 static int FreeResourceByCriteria(struct RESMAN_CONTEXT *psContext,
89 u32 ui32SearchCriteria,
90 u32 ui32ResType, void *pvParam,
92 IMG_BOOL bExecuteCallback);
94 #ifdef CONFIG_PVR_DEBUG_EXTRA
95 static void ValidateResList(struct RESMAN_LIST *psResList);
96 #define VALIDATERESLIST() ValidateResList(gpsResList)
98 #define VALIDATERESLIST()
101 enum PVRSRV_ERROR ResManInit(void)
103 if (gpsResList == NULL) {
105 if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
107 (void **) &gpsResList,
109 return PVRSRV_ERROR_OUT_OF_MEMORY;
111 gpsResList->psContextList = NULL;
119 void ResManDeInit(void)
121 if (gpsResList != NULL)
122 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*gpsResList),
126 enum PVRSRV_ERROR PVRSRVResManConnect(void *hPerProc,
127 struct RESMAN_CONTEXT **phResManContext)
129 enum PVRSRV_ERROR eError;
130 struct RESMAN_CONTEXT *psResManContext;
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");
147 #ifdef CONFIG_PVR_DEBUG
148 psResManContext->ui32Signature = RESMAN_SIGNATURE;
150 psResManContext->psResItemList = NULL;
151 psResManContext->psPerProc = hPerProc;
153 psResManContext->psNext = gpsResList->psContextList;
154 psResManContext->ppsThis = &gpsResList->psContextList;
155 gpsResList->psContextList = psResManContext;
156 if (psResManContext->psNext)
157 psResManContext->psNext->ppsThis = &(psResManContext->psNext);
163 *phResManContext = psResManContext;
168 static inline bool warn_unfreed_res(void)
170 return !(current->flags & PF_SIGNALED);
173 static int free_one_res(struct RESMAN_CONTEXT *ctx, u32 restype)
177 freed = FreeResourceByCriteria(ctx, RESMAN_CRITERIA_RESTYPE, restype,
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);
187 void PVRSRVResManDisconnect(struct RESMAN_CONTEXT *ctx, IMG_BOOL bKernelContext)
194 PRINT_RESLIST(gpsResList, ctx, IMG_TRUE);
196 if (!bKernelContext) {
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);
217 if (i && warn_unfreed_res())
218 pr_warning("pvr: %s: cleaning up %d "
219 "unfreed resources\n",
223 PVR_ASSERT(ctx->psResItemList == NULL);
225 *(ctx->ppsThis) = ctx->psNext;
227 ctx->psNext->ppsThis = ctx->ppsThis;
229 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RESMAN_CONTEXT),
234 PRINT_RESLIST(gpsResList, ctx, IMG_FALSE);
239 struct RESMAN_ITEM *ResManRegisterRes(struct RESMAN_CONTEXT *psResManContext,
240 u32 ui32ResType, void *pvParam,
242 enum PVRSRV_ERROR (*pfnFreeResource)
243 (void *pvParam, u32 ui32Param))
245 struct RESMAN_ITEM *psNewResItem;
247 PVR_ASSERT(psResManContext != NULL);
248 PVR_ASSERT(ui32ResType != 0);
250 if (psResManContext == NULL) {
251 PVR_DPF(PVR_DBG_ERROR, "ResManRegisterRes: "
252 "invalid parameter - psResManContext");
253 return (struct RESMAN_ITEM *)NULL;
260 PVR_DPF(PVR_DBG_MESSAGE, "ResManRegisterRes: register resource "
261 "Context 0x%x, ResType 0x%x, pvParam 0x%x, ui32Param 0x%x, "
263 psResManContext, ui32ResType, (u32) pvParam,
264 ui32Param, pfnFreeResource);
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");
274 return (struct RESMAN_ITEM *)NULL;
277 #ifdef CONFIG_PVR_DEBUG
278 psNewResItem->ui32Signature = RESMAN_SIGNATURE;
280 psNewResItem->ui32ResType = ui32ResType;
281 psNewResItem->pvParam = pvParam;
282 psNewResItem->ui32Param = ui32Param;
283 psNewResItem->pfnFreeResource = pfnFreeResource;
284 psNewResItem->ui32Flags = 0;
286 psNewResItem->ppsThis = &psResManContext->psResItemList;
287 psNewResItem->psNext = psResManContext->psResItemList;
288 psResManContext->psResItemList = psNewResItem;
289 if (psNewResItem->psNext)
290 psNewResItem->psNext->ppsThis = &psNewResItem->psNext;
299 void ResManFreeResByPtr(struct RESMAN_ITEM *psResItem)
303 PVR_DPF(PVR_DBG_MESSAGE,
304 "ResManFreeResByPtr: freeing resource at %08X", psResItem);
310 FreeResourceByPtr(psResItem, IMG_TRUE);
317 void ResManFreeResByCriteria(struct RESMAN_CONTEXT *psResManContext,
318 u32 ui32SearchCriteria, u32 ui32ResType,
319 void *pvParam, u32 ui32Param)
321 PVR_ASSERT(psResManContext != NULL);
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);
332 (void)FreeResourceByCriteria(psResManContext, ui32SearchCriteria,
333 ui32ResType, pvParam, ui32Param,
341 enum PVRSRV_ERROR ResManDissociateRes(struct RESMAN_ITEM *psResItem,
342 struct RESMAN_CONTEXT *psNewResManContext)
344 PVR_ASSERT(psResItem != NULL);
346 if (psResItem == NULL) {
347 PVR_DPF(PVR_DBG_ERROR,
348 "ResManDissociateRes: invalid parameter - psResItem");
350 return PVRSRV_ERROR_INVALID_PARAMS;
352 #ifdef CONFIG_PVR_DEBUG
353 PVR_ASSERT(psResItem->ui32Signature == RESMAN_SIGNATURE);
356 if (psNewResManContext != NULL) {
357 if (psResItem->psNext)
358 psResItem->psNext->ppsThis = psResItem->ppsThis;
359 *psResItem->ppsThis = psResItem->psNext;
361 psResItem->ppsThis = &psNewResManContext->psResItemList;
362 psResItem->psNext = psNewResManContext->psResItemList;
363 psNewResManContext->psResItemList = psResItem;
364 if (psResItem->psNext)
365 psResItem->psNext->ppsThis = &psResItem->psNext;
367 FreeResourceByPtr(psResItem, IMG_FALSE);
373 enum PVRSRV_ERROR ResManFindResourceByPtr(
374 struct RESMAN_CONTEXT *psResManContext,
375 struct RESMAN_ITEM *psItem)
377 struct RESMAN_ITEM *psCurItem;
379 PVR_ASSERT(psResManContext != NULL);
380 PVR_ASSERT(psItem != NULL);
382 if ((psItem == NULL) || (psResManContext == NULL)) {
383 PVR_DPF(PVR_DBG_ERROR,
384 "ResManFindResourceByPtr: invalid parameter");
386 return PVRSRV_ERROR_INVALID_PARAMS;
388 #ifdef CONFIG_PVR_DEBUG
389 PVR_ASSERT(psItem->ui32Signature == RESMAN_SIGNATURE);
394 PVR_DPF(PVR_DBG_MESSAGE,
395 "FindResourceByPtr: psItem=%08X, psItem->psNext=%08X",
396 psItem, psItem->psNext);
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",
402 psItem->ui32ResType, (u32) psItem->pvParam,
403 psItem->ui32Param, psItem->pfnFreeResource,
406 psCurItem = psResManContext->psResItemList;
408 while (psCurItem != NULL) {
409 if (psCurItem != psItem) {
410 psCurItem = psCurItem->psNext;
419 return PVRSRV_ERROR_NOT_OWNER;
422 static void FreeResourceByPtr(struct RESMAN_ITEM *psItem,
423 IMG_BOOL bExecuteCallback)
425 PVR_ASSERT(psItem->ui32Signature == RESMAN_SIGNATURE);
427 PVR_DPF(PVR_DBG_MESSAGE,
428 "FreeResourceByPtr: psItem=%08X, psItem->psNext=%08X",
429 psItem, psItem->psNext);
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,
439 psItem->psNext->ppsThis = psItem->ppsThis;
440 *psItem->ppsThis = psItem->psNext;
444 if (bExecuteCallback &&
445 psItem->pfnFreeResource(psItem->pvParam, psItem->ui32Param) !=
447 PVR_DPF(PVR_DBG_ERROR, "FreeResourceByPtr: "
448 "ERROR calling FreeResource function");
452 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RESMAN_ITEM), psItem,
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)
460 struct RESMAN_ITEM *item;
462 for (item = res_ctx->psResItemList; item; item = item->psNext) {
463 if ((crit & RESMAN_CRITERIA_RESTYPE) &&
464 item->ui32ResType != res_type)
466 else if ((crit & RESMAN_CRITERIA_PVOID_PARAM) &&
467 item->pvParam != ppar)
469 else if ((crit & RESMAN_CRITERIA_UI32_PARAM) &&
470 item->ui32Param != upar)
479 struct RESMAN_CONTEXT *pvr_get_resman_ctx(void *resource)
481 struct RESMAN_CONTEXT *ctx;
483 for (ctx = gpsResList->psContextList; ctx; ctx = ctx->psNext) {
484 struct RESMAN_ITEM *item;
486 item = find_res_by_crit(ctx, RESMAN_CRITERIA_PVOID_PARAM,
494 struct PVRSRV_PER_PROCESS_DATA *pvr_get_proc_by_ctx(struct RESMAN_CONTEXT *ctx)
496 return ctx->psPerProc;
499 static int FreeResourceByCriteria(struct RESMAN_CONTEXT *psResManContext,
500 u32 ui32SearchCriteria, u32 ui32ResType,
501 void *pvParam, u32 ui32Param,
502 IMG_BOOL bExecuteCallback)
504 struct RESMAN_ITEM *item;
508 item = find_res_by_crit(psResManContext,
509 ui32SearchCriteria, ui32ResType,
512 FreeResourceByPtr(item, bExecuteCallback);
520 #ifdef CONFIG_PVR_DEBUG_EXTRA
521 static void ValidateResList(struct RESMAN_LIST *psResList)
523 struct RESMAN_ITEM *psCurItem, **ppsThisItem;
524 struct RESMAN_CONTEXT *psCurContext, **ppsThisContext;
526 if (psResList == NULL) {
527 PVR_DPF(PVR_DBG_MESSAGE,
528 "ValidateResList: resman not initialised yet");
532 psCurContext = psResList->psContextList;
533 ppsThisContext = &psResList->psContextList;
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);
545 psCurItem = psCurContext->psResItemList;
546 ppsThisItem = &psCurContext->psResItemList;
547 while (psCurItem != NULL) {
548 PVR_ASSERT(psCurItem->ui32Signature ==
550 if (psCurItem->ppsThis != ppsThisItem) {
551 PVR_DPF(PVR_DBG_WARNING, "psCurItem=%08X "
552 "psCurItem->ppsThis=%08X "
553 "psCurItem->psNext=%08X "
555 psCurItem, psCurItem->ppsThis,
556 psCurItem->psNext, ppsThisItem);
557 PVR_ASSERT(psCurItem->ppsThis == ppsThisItem);
560 ppsThisItem = &psCurItem->psNext;
561 psCurItem = psCurItem->psNext;
564 ppsThisContext = &psCurContext->psNext;
565 psCurContext = psCurContext->psNext;