1 /*************************************************************************/ /*!
3 @Title Functions for creating debugfs directories and entries.
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @License Dual MIT/GPLv2
7 The contents of this file are subject to the MIT license as set out below.
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:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
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.
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.
31 This License is also included in this distribution in the file called
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 */ /**************************************************************************/
43 #include <linux/module.h>
44 #include <linux/slab.h>
46 #include "pvr_debug.h"
47 #include "pvr_debugfs.h"
50 #define PVR_DEBUGFS_DIR_NAME "pvr"
52 /* Define to set the PVR_DPF debug output level for pvr_debugfs.
53 * Normally, leave this set to PVR_DBGDRIV_MESSAGE, but when debugging
54 * you can temporarily change this to PVR_DBG_ERROR.
56 #if defined(PVRSRV_NEED_PVR_DPF)
57 #define PVR_DEBUGFS_PVR_DPF_LEVEL PVR_DBGDRIV_MESSAGE
59 #define PVR_DEBUGFS_PVR_DPF_LEVEL 0
62 static struct dentry *gpsPVRDebugFSEntryDir = NULL;
64 /* Lock used when adjusting refCounts and deleting entries */
65 static struct mutex gDebugFSLock;
67 /*************************************************************************/ /*!
68 Statistic entry read functions
69 */ /**************************************************************************/
71 typedef struct _PVR_DEBUGFS_DRIVER_STAT_
74 OS_STATS_PRINT_FUNC *pfnStatsPrint;
75 PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC *pfnIncStatMemRefCount;
76 PVRSRV_DEC_STAT_MEM_REFCOUNT_FUNC *pfnDecStatMemRefCount;
77 IMG_UINT32 ui32RefCount;
78 PVR_DEBUGFS_ENTRY_DATA *pvDebugFSEntry;
79 } PVR_DEBUGFS_DRIVER_STAT;
81 typedef struct _PVR_DEBUGFS_DIR_DATA_
84 PVR_DEBUGFS_DIR_DATA *psParentDir;
85 IMG_UINT32 ui32RefCount;
86 } PVR_DEBUGFS_DIR_DATA;
88 typedef struct _PVR_DEBUGFS_ENTRY_DATA_
90 struct dentry *psEntry;
91 PVR_DEBUGFS_DIR_DATA *psParentDir;
92 IMG_UINT32 ui32RefCount;
93 PVR_DEBUGFS_DRIVER_STAT *psStatData;
94 } PVR_DEBUGFS_ENTRY_DATA;
96 typedef struct _PVR_DEBUGFS_PRIV_DATA_
98 struct seq_operations *psReadOps;
99 PVRSRV_ENTRY_WRITE_FUNC *pfnWrite;
102 PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry;
103 } PVR_DEBUGFS_PRIV_DATA;
105 static void _RefDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry);
106 static void _UnrefAndMaybeDestroyDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry);
107 static void _UnrefAndMaybeDestroyDirEntryWhileLocked(PVR_DEBUGFS_DIR_DATA *psDirEntry);
108 static IMG_BOOL _RefDebugFSEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry);
109 static void _UnrefAndMaybeDestroyDebugFSEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry);
110 static IMG_BOOL _RefStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry);
111 static IMG_BOOL _UnrefAndMaybeDestroyStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry);
113 static void _StatsSeqPrintf(void *pvFile, const IMG_CHAR *pszFormat, ...)
115 IMG_CHAR szBuffer[PVR_MAX_DEBUG_MESSAGE_LEN];
118 va_start(ArgList, pszFormat);
119 vsnprintf(szBuffer, PVR_MAX_DEBUG_MESSAGE_LEN, pszFormat, ArgList);
120 seq_printf((struct seq_file *)pvFile, "%s", szBuffer);
124 static void *_DebugFSStatisticSeqStart(struct seq_file *psSeqFile, loff_t *puiPosition)
126 PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)psSeqFile->private;
130 if (psStatData->pvData)
132 /* take reference on psStatData (for duration of stat iteration) */
133 if (!_RefStatEntry((void*)psStatData))
135 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called for '%s' but failed to take ref on stat entry, returning -EIO(%d)", __FUNCTION__, psStatData->pvDebugFSEntry->psEntry->d_iname, -EIO));
141 /* NB This is valid if the stat has no structure associated with it (eg. driver_stats, which prints totals stored in a number of global vars) */
144 if (*puiPosition == 0)
151 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called when psStatData is NULL", __FUNCTION__));
157 static void _DebugFSStatisticSeqStop(struct seq_file *psSeqFile, void *pvData)
159 PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)psSeqFile->private;
160 PVR_UNREFERENCED_PARAMETER(pvData);
164 /* drop ref taken on stat memory, and if it is now zero, be sure we don't try to read it again */
165 if ((psStatData->ui32RefCount > 0) && (psStatData->pvData))
167 /* drop reference on psStatData (held for duration of stat iteration) */
168 _UnrefAndMaybeDestroyStatEntry((void*)psStatData);
172 if (psStatData->ui32RefCount > 0)
174 /* psStatData->pvData is NULL */
175 /* NB This is valid if the stat has no structure associated with it (eg. driver_stats, which prints totals stored in a number of global vars) */
177 if (psStatData->pvData)
179 /* psStatData->ui32RefCount is zero */
180 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called when psStatData->ui32RefCount is %d", __FUNCTION__, psStatData->ui32RefCount));
186 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called when psStatData is NULL", __FUNCTION__));
190 static void *_DebugFSStatisticSeqNext(struct seq_file *psSeqFile,
194 PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)psSeqFile->private;
195 PVR_UNREFERENCED_PARAMETER(pvData);
199 if (psStatData->pvData)
207 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called with puiPosition NULL", __FUNCTION__));
212 /* psStatData->pvData is NULL */
213 /* NB This is valid if the stat has no structure associated with it (eg. driver_stats, which prints totals stored in a number of global vars) */
218 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called when psStatData is NULL", __FUNCTION__));
224 static int _DebugFSStatisticSeqShow(struct seq_file *psSeqFile, void *pvData)
226 PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)pvData;
228 if (psStatData != NULL)
230 psStatData->pfnStatsPrint((void*)psSeqFile, psStatData->pvData, _StatsSeqPrintf);
235 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called when psStatData is NULL, returning -ENODATA(%d)", __FUNCTION__, -ENODATA));
241 static struct seq_operations gsDebugFSStatisticReadOps =
243 .start = _DebugFSStatisticSeqStart,
244 .stop = _DebugFSStatisticSeqStop,
245 .next = _DebugFSStatisticSeqNext,
246 .show = _DebugFSStatisticSeqShow,
250 /*************************************************************************/ /*!
252 */ /**************************************************************************/
254 static int _DebugFSFileOpen(struct inode *psINode, struct file *psFile)
256 PVR_DEBUGFS_PRIV_DATA *psPrivData;
258 IMG_BOOL bRefRet = IMG_FALSE;
259 PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry = NULL;
262 psPrivData = (PVR_DEBUGFS_PRIV_DATA *)psINode->i_private;
266 /* Check that psPrivData is still valid to use */
267 if (psPrivData->bValid)
269 psDebugFSEntry = psPrivData->psDebugFSEntry;
271 /* Take ref on stat entry before opening seq file - this ref will be dropped if we
272 * fail to open the seq file or when we close it
276 bRefRet = _RefDebugFSEntry(psDebugFSEntry);
279 iResult = seq_open(psFile, psPrivData->psReadOps);
282 struct seq_file *psSeqFile = psFile->private_data;
284 psSeqFile->private = psPrivData->pvData;
288 /* Drop ref if we failed to open seq file */
289 _UnrefAndMaybeDestroyDebugFSEntry(psDebugFSEntry);
290 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to seq_open psFile, returning %d", __FUNCTION__, iResult));
300 static int _DebugFSFileClose(struct inode *psINode, struct file *psFile)
303 PVR_DEBUGFS_PRIV_DATA *psPrivData = (PVR_DEBUGFS_PRIV_DATA *)psINode->i_private;
304 PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry = NULL;
308 psDebugFSEntry = psPrivData->psDebugFSEntry;
310 iResult = seq_release(psINode, psFile);
313 _UnrefAndMaybeDestroyDebugFSEntry(psDebugFSEntry);
318 static ssize_t _DebugFSFileWrite(struct file *psFile,
319 const char __user *pszBuffer,
323 struct inode *psINode = psFile->f_path.dentry->d_inode;
324 PVR_DEBUGFS_PRIV_DATA *psPrivData = (PVR_DEBUGFS_PRIV_DATA *)psINode->i_private;
326 if (psPrivData->pfnWrite == NULL)
328 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called for file '%s', which does not have pfnWrite defined, returning -EIO(%d)", __FUNCTION__, psFile->f_path.dentry->d_iname, -EIO));
332 return psPrivData->pfnWrite(pszBuffer, uiCount, *puiPosition, psPrivData->pvData);
335 static const struct file_operations gsPVRDebugFSFileOps =
337 .owner = THIS_MODULE,
338 .open = _DebugFSFileOpen,
340 .write = _DebugFSFileWrite,
342 .release = _DebugFSFileClose,
346 /*************************************************************************/ /*!
348 */ /**************************************************************************/
350 /*************************************************************************/ /*!
351 @Function PVRDebugFSInit
352 @Description Initialise PVR debugfs support. This should be called before
353 using any PVRDebugFS functions.
354 @Return int On success, returns 0. Otherwise, returns an
356 */ /**************************************************************************/
357 int PVRDebugFSInit(void)
359 PVR_ASSERT(gpsPVRDebugFSEntryDir == NULL);
361 mutex_init(&gDebugFSLock);
363 gpsPVRDebugFSEntryDir = debugfs_create_dir(PVR_DEBUGFS_DIR_NAME, NULL);
364 if (gpsPVRDebugFSEntryDir == NULL)
366 PVR_DPF((PVR_DBG_ERROR,
367 "%s: Cannot create '%s' debugfs root directory",
368 __FUNCTION__, PVR_DEBUGFS_DIR_NAME));
376 /*************************************************************************/ /*!
377 @Function PVRDebugFSDeInit
378 @Description Deinitialise PVR debugfs support. This should be called only
379 if PVRDebugFSInit() has already been called. All debugfs
380 directories and entries should be removed otherwise this
383 */ /**************************************************************************/
384 void PVRDebugFSDeInit(void)
386 debugfs_remove(gpsPVRDebugFSEntryDir);
387 gpsPVRDebugFSEntryDir = NULL;
388 mutex_destroy(&gDebugFSLock);
391 /*************************************************************************/ /*!
392 @Function PVRDebugFSCreateEntryDir
393 @Description Create a directory for debugfs entries that will be located
394 under the root directory, as created by
395 PVRDebugFSCreateEntries().
396 @Input pszName String containing the name for the directory.
397 @Input psParentDir The parent directory in which to create the new
398 directory. This should either be NULL, meaning it
399 should be created in the root directory, or a
400 pointer to a directory as returned by this
402 @Output ppsNewDir On success, points to the newly created
404 @Return int On success, returns 0. Otherwise, returns an
406 */ /**************************************************************************/
407 int PVRDebugFSCreateEntryDir(IMG_CHAR *pszName,
408 PVR_DEBUGFS_DIR_DATA *psParentDir,
409 PVR_DEBUGFS_DIR_DATA **ppsNewDir)
411 PVR_DEBUGFS_DIR_DATA *psNewDir;
413 PVR_ASSERT(gpsPVRDebugFSEntryDir != NULL);
415 if (pszName == NULL || ppsNewDir == NULL)
417 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid param", __FUNCTION__));
421 psNewDir = OSAllocMemstatMem(sizeof(*psNewDir));
423 if (psNewDir == IMG_NULL)
425 PVR_DPF((PVR_DBG_ERROR,
426 "%s: Cannot allocate memory for '%s' pvr_debugfs structure",
427 __FUNCTION__, pszName));
431 psNewDir->psParentDir = psParentDir;
432 psNewDir->psDir = debugfs_create_dir(pszName, (psNewDir->psParentDir) ? psNewDir->psParentDir->psDir : gpsPVRDebugFSEntryDir);
434 if (psNewDir->psDir == NULL)
436 PVR_DPF((PVR_DBG_ERROR,
437 "%s: Cannot create '%s' debugfs directory",
438 __FUNCTION__, pszName));
440 OSFreeMemstatMem(psNewDir);
444 *ppsNewDir = psNewDir;
445 psNewDir->ui32RefCount = 1;
447 /* if parent directory is not gpsPVRDebugFSEntryDir, increment its refCount */
448 if (psNewDir->psParentDir)
450 _RefDirEntry(psNewDir->psParentDir);
455 /*************************************************************************/ /*!
456 @Function PVRDebugFSRemoveEntryDir
457 @Description Remove a directory that was created by
458 PVRDebugFSCreateEntryDir(). Any directories or files created
459 under the directory being removed should be removed first.
460 @Input psDir Pointer representing the directory to be removed.
462 */ /**************************************************************************/
463 void PVRDebugFSRemoveEntryDir(PVR_DEBUGFS_DIR_DATA *psDir)
465 _UnrefAndMaybeDestroyDirEntry(psDir);
468 /*************************************************************************/ /*!
469 @Function PVRDebugFSCreateEntry
470 @Description Create an entry in the specified directory.
471 @Input pszName String containing the name for the entry.
472 @Input psParentDir Pointer from PVRDebugFSCreateEntryDir()
473 representing the directory in which to create
474 the entry or NULL for the root directory.
475 @Input psReadOps Pointer to structure containing the necessary
476 functions to read from the entry.
477 @Input pfnWrite Callback function used to write to the entry.
478 @Input pvData Private data to be passed to the read
479 functions, in the seq_file private member, and
480 the write function callback.
481 @Output ppsNewEntry On success, points to the newly created entry.
482 @Return int On success, returns 0. Otherwise, returns an
484 */ /**************************************************************************/
485 int PVRDebugFSCreateEntry(const char *pszName,
486 PVR_DEBUGFS_DIR_DATA *psParentDir,
487 struct seq_operations *psReadOps,
488 PVRSRV_ENTRY_WRITE_FUNC *pfnWrite,
490 PVR_DEBUGFS_ENTRY_DATA **ppsNewEntry)
492 PVR_DEBUGFS_PRIV_DATA *psPrivData;
493 PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry;
494 struct dentry *psEntry;
497 PVR_ASSERT(gpsPVRDebugFSEntryDir != NULL);
499 psPrivData = OSAllocMemstatMem(sizeof(*psPrivData));
500 if (psPrivData == NULL)
504 psDebugFSEntry = OSAllocMemstatMem(sizeof(*psDebugFSEntry));
505 if (psDebugFSEntry == NULL)
507 OSFreeMemstatMem(psPrivData);
511 psPrivData->psReadOps = psReadOps;
512 psPrivData->pfnWrite = pfnWrite;
513 psPrivData->pvData = (void*)pvData;
514 psPrivData->bValid = IMG_TRUE;
515 /* Store ptr to debugFSEntry in psPrivData, so a ref can be taken on it
516 * when the client opens a file */
517 psPrivData->psDebugFSEntry = psDebugFSEntry;
521 if (psReadOps != NULL)
526 if (pfnWrite != NULL)
531 psDebugFSEntry->psParentDir = psParentDir;
532 psDebugFSEntry->ui32RefCount = 1;
533 psDebugFSEntry->psStatData = (PVR_DEBUGFS_DRIVER_STAT*)pvData;
535 if (psDebugFSEntry->psParentDir)
537 /* increment refCount of parent directory */
538 _RefDirEntry(psDebugFSEntry->psParentDir);
541 psEntry = debugfs_create_file(pszName,
543 (psParentDir != NULL) ? psParentDir->psDir : gpsPVRDebugFSEntryDir,
545 &gsPVRDebugFSFileOps);
548 PVR_DPF((PVR_DBG_ERROR,
549 "%s: Cannot create debugfs '%s' file",
550 __FUNCTION__, pszName));
552 return PTR_ERR(psEntry);
555 psDebugFSEntry->psEntry = psEntry;
556 *ppsNewEntry = (void*)psDebugFSEntry;
561 /*************************************************************************/ /*!
562 @Function PVRDebugFSRemoveEntry
563 @Description Removes an entry that was created by PVRDebugFSCreateEntry().
564 @Input psDebugFSEntry Pointer representing the entry to be removed.
566 */ /**************************************************************************/
567 void PVRDebugFSRemoveEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry)
569 _UnrefAndMaybeDestroyDebugFSEntry(psDebugFSEntry);
572 /*************************************************************************/ /*!
573 @Function PVRDebugFSCreateStatisticEntry
574 @Description Create a statistic entry in the specified directory.
575 @Input pszName String containing the name for the entry.
576 @Input psDir Pointer from PVRDebugFSCreateEntryDir()
577 representing the directory in which to create
578 the entry or NULL for the root directory.
579 @Input pfnStatsPrint A callback function used to print all the
580 statistics when reading from the statistic
582 @Input pfnIncStatMemRefCount A callback function used take a
583 reference on the memory backing the
585 @Input pfnDecStatMemRefCount A callback function used drop a
586 reference on the memory backing the
588 @Input pvData Private data to be passed to the provided
591 @Return PVR_DEBUGFS_DRIVER_STAT* On success, a pointer representing
592 the newly created statistic entry.
594 */ /**************************************************************************/
595 PVR_DEBUGFS_DRIVER_STAT *PVRDebugFSCreateStatisticEntry(const char *pszName,
596 PVR_DEBUGFS_DIR_DATA *psDir,
597 OS_STATS_PRINT_FUNC *pfnStatsPrint,
598 PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC *pfnIncStatMemRefCount,
599 PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC *pfnDecStatMemRefCount,
602 PVR_DEBUGFS_DRIVER_STAT *psStatData;
603 PVR_DEBUGFS_ENTRY_DATA * psDebugFSEntry;
607 if (pszName == NULL || pfnStatsPrint == NULL)
611 if ((pfnIncStatMemRefCount != NULL || pfnDecStatMemRefCount != NULL) && pvData == NULL)
616 psStatData = OSAllocMemstatZMem(sizeof(*psStatData));
617 if (psStatData == NULL)
622 psStatData->pvData = pvData;
623 psStatData->pfnStatsPrint = pfnStatsPrint;
624 psStatData->pfnIncStatMemRefCount = pfnIncStatMemRefCount;
625 psStatData->pfnDecStatMemRefCount = pfnDecStatMemRefCount;
626 psStatData->ui32RefCount = 1;
628 iResult = PVRDebugFSCreateEntry(pszName,
630 &gsDebugFSStatisticReadOps,
636 OSFreeMemstatMem(psStatData);
639 psStatData->pvDebugFSEntry = (void*)psDebugFSEntry;
641 if (pfnIncStatMemRefCount)
643 /* call function to take reference on the memory holding the stat */
644 psStatData->pfnIncStatMemRefCount((void*)psStatData->pvData);
647 psDebugFSEntry->ui32RefCount = 1;
652 /*************************************************************************/ /*!
653 @Function PVRDebugFSRemoveStatisticEntry
654 @Description Removes a statistic entry that was created by
655 PVRDebugFSCreateStatisticEntry().
656 @Input psStatEntry Pointer representing the statistic entry to be
659 */ /**************************************************************************/
660 void PVRDebugFSRemoveStatisticEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry)
662 /* drop reference on pvStatEntry*/
663 _UnrefAndMaybeDestroyStatEntry(psStatEntry);
666 static void _RefDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry)
668 mutex_lock(&gDebugFSLock);
670 if (psDirEntry->ui32RefCount > 0)
672 /* Increment refCount */
673 psDirEntry->ui32RefCount++;
677 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called to ref psDirEntry '%s' when ui32RefCount is zero", __FUNCTION__, psDirEntry->psDir->d_iname));
680 mutex_unlock(&gDebugFSLock);
683 static void _UnrefAndMaybeDestroyDirEntryWhileLocked(PVR_DEBUGFS_DIR_DATA *psDirEntry)
685 if (psDirEntry->ui32RefCount > 0)
687 /* Decrement refCount and free if now zero */
688 if (--psDirEntry->ui32RefCount == 0)
690 /* if parent directory is not gpsPVRDebugFSEntryDir, decrement its refCount */
691 debugfs_remove(psDirEntry->psDir);
692 if (psDirEntry->psParentDir)
694 _UnrefAndMaybeDestroyDirEntryWhileLocked(psDirEntry->psParentDir);
696 OSFreeMemstatMem(psDirEntry);
701 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called to unref psDirEntry '%s' when ui32RefCount is zero", __FUNCTION__, psDirEntry->psDir->d_iname));
705 static void _UnrefAndMaybeDestroyDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry)
707 mutex_lock(&gDebugFSLock);
709 if (psDirEntry->ui32RefCount > 0)
711 /* Decrement refCount and free if now zero */
712 if (--psDirEntry->ui32RefCount == 0)
714 /* if parent directory is not gpsPVRDebugFSEntryDir, decrement its refCount */
715 debugfs_remove(psDirEntry->psDir);
716 if (psDirEntry->psParentDir)
718 _UnrefAndMaybeDestroyDirEntryWhileLocked(psDirEntry->psParentDir);
720 OSFreeMemstatMem(psDirEntry);
725 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called to unref psDirEntry '%s' when ui32RefCount is zero", __FUNCTION__, psDirEntry->psDir->d_iname));
728 mutex_unlock(&gDebugFSLock);
731 static IMG_BOOL _RefDebugFSEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry)
733 IMG_BOOL bResult = IMG_FALSE;
735 PVR_ASSERT(psDebugFSEntry != NULL);
737 mutex_lock(&gDebugFSLock);
739 bResult = (psDebugFSEntry->ui32RefCount > 0);
742 /* Increment refCount of psDebugFSEntry */
743 psDebugFSEntry->ui32RefCount++;
746 mutex_unlock(&gDebugFSLock);
751 static void _UnrefAndMaybeDestroyDebugFSEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry)
753 mutex_lock(&gDebugFSLock);
754 /* Decrement refCount of psDebugFSEntry, and free if now zero */
755 PVR_ASSERT(psDebugFSEntry != IMG_NULL);
757 if (psDebugFSEntry->ui32RefCount > 0)
759 if (--psDebugFSEntry->ui32RefCount == 0)
761 struct dentry *psEntry = psDebugFSEntry->psEntry;
765 /* Free any private data that was provided to debugfs_create_file() */
766 if (psEntry->d_inode->i_private != NULL)
768 PVR_DEBUGFS_PRIV_DATA *psPrivData = (PVR_DEBUGFS_PRIV_DATA*)psDebugFSEntry->psEntry->d_inode->i_private;
770 psPrivData->bValid = IMG_FALSE;
771 psPrivData->psDebugFSEntry = NULL;
772 OSFreeMemstatMem(psEntry->d_inode->i_private);
774 debugfs_remove(psEntry);
776 /* decrement refcount of parent directory */
777 if (psDebugFSEntry->psParentDir)
779 _UnrefAndMaybeDestroyDirEntryWhileLocked(psDebugFSEntry->psParentDir);
782 /* now free the memory allocated for psDebugFSEntry */
783 OSFreeMemstatMem(psDebugFSEntry);
788 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called to unref psDebugFSEntry '%s' when ui32RefCount is zero", __FUNCTION__, psDebugFSEntry->psEntry->d_iname));
791 mutex_unlock(&gDebugFSLock);
794 static IMG_BOOL _RefStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry)
796 IMG_BOOL bResult = IMG_FALSE;
798 PVR_ASSERT(psStatEntry != NULL);
800 mutex_lock(&gDebugFSLock);
802 bResult = (psStatEntry->ui32RefCount > 0);
805 /* Increment refCount of psStatEntry */
806 psStatEntry->ui32RefCount++;
810 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called to ref psStatEntry '%s' when ui32RefCount is zero", __FUNCTION__, psStatEntry->pvDebugFSEntry->psEntry->d_iname));
813 mutex_unlock(&gDebugFSLock);
818 static IMG_BOOL _UnrefAndMaybeDestroyStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry)
822 PVR_ASSERT(psStatEntry != IMG_NULL);
824 mutex_lock(&gDebugFSLock);
826 bResult = (psStatEntry->ui32RefCount > 0);
830 /* Decrement refCount of psStatData, and free if now zero */
831 if (--psStatEntry->ui32RefCount == 0)
833 mutex_unlock(&gDebugFSLock);
835 if (psStatEntry->pvDebugFSEntry)
837 _UnrefAndMaybeDestroyDebugFSEntry((PVR_DEBUGFS_ENTRY_DATA*)psStatEntry->pvDebugFSEntry);
839 if (psStatEntry->pfnDecStatMemRefCount)
841 /* call function to drop reference on the memory holding the stat */
842 psStatEntry->pfnDecStatMemRefCount((void*)psStatEntry->pvData);
847 mutex_unlock(&gDebugFSLock);
852 PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called to unref psStatEntry '%s' when ui32RefCount is zero", __FUNCTION__, psStatEntry->pvDebugFSEntry->psEntry->d_iname));
853 mutex_unlock(&gDebugFSLock);