summaryrefslogtreecommitdiffstats
path: root/pvr-source/services4/srvkm/env/linux/pvr_debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'pvr-source/services4/srvkm/env/linux/pvr_debug.c')
-rw-r--r--pvr-source/services4/srvkm/env/linux/pvr_debug.c506
1 files changed, 506 insertions, 0 deletions
diff --git a/pvr-source/services4/srvkm/env/linux/pvr_debug.c b/pvr-source/services4/srvkm/env/linux/pvr_debug.c
new file mode 100644
index 0000000..04e42ad
--- /dev/null
+++ b/pvr-source/services4/srvkm/env/linux/pvr_debug.c
@@ -0,0 +1,506 @@
+/*************************************************************************/ /*!
+@Title Debug Functionality
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@Description Provides kernel side Debug Functionality
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/ /**************************************************************************/
+
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+#endif
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/hardirq.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/string.h> // strncpy, strlen
+#include <stdarg.h>
+#include "img_types.h"
+#include "servicesext.h"
+#include "pvr_debug.h"
+#include "srvkm.h"
+#include "proc.h"
+#include "mutex.h"
+#include "linkage.h"
+#include "pvr_uaccess.h"
+
+#if !defined(CONFIG_PREEMPT)
+#define PVR_DEBUG_ALWAYS_USE_SPINLOCK
+#endif
+
+static IMG_BOOL VBAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz,
+ const IMG_CHAR* pszFormat, va_list VArgs)
+ IMG_FORMAT_PRINTF(3, 0);
+
+
+#if defined(PVRSRV_NEED_PVR_DPF)
+
+#define PVR_MAX_FILEPATH_LEN 256
+
+static IMG_BOOL BAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz,
+ const IMG_CHAR *pszFormat, ...)
+ IMG_FORMAT_PRINTF(3, 4);
+
+/* NOTE: Must NOT be static! Used in module.c.. */
+IMG_UINT32 gPVRDebugLevel =
+ (DBGPRIV_FATAL | DBGPRIV_ERROR | DBGPRIV_WARNING);
+
+#endif /* defined(PVRSRV_NEED_PVR_DPF) || defined(PVRSRV_NEED_PVR_TRACE) */
+
+#define PVR_MAX_MSG_LEN PVR_MAX_DEBUG_MESSAGE_LEN
+
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+/* Message buffer for non-IRQ messages */
+static IMG_CHAR gszBufferNonIRQ[PVR_MAX_MSG_LEN + 1];
+#endif
+
+/* Message buffer for IRQ messages */
+static IMG_CHAR gszBufferIRQ[PVR_MAX_MSG_LEN + 1];
+
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+/* The lock is used to control access to gszBufferNonIRQ */
+static PVRSRV_LINUX_MUTEX gsDebugMutexNonIRQ;
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
+/* The lock is used to control access to gszBufferIRQ */
+/* PRQA S 0671,0685 1 */ /* ignore warnings about C99 style initialisation */
+static spinlock_t gsDebugLockIRQ = SPIN_LOCK_UNLOCKED;
+#else
+static DEFINE_SPINLOCK(gsDebugLockIRQ);
+#endif
+
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+#if !defined (USE_SPIN_LOCK) /* to keep QAC happy */
+#define USE_SPIN_LOCK (in_interrupt() || !preemptible())
+#endif
+#endif
+
+static inline void GetBufferLock(unsigned long *pulLockFlags)
+{
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+ if (USE_SPIN_LOCK)
+#endif
+ {
+ spin_lock_irqsave(&gsDebugLockIRQ, *pulLockFlags);
+ }
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+ else
+ {
+ LinuxLockMutex(&gsDebugMutexNonIRQ);
+ }
+#endif
+}
+
+static inline void ReleaseBufferLock(unsigned long ulLockFlags)
+{
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+ if (USE_SPIN_LOCK)
+#endif
+ {
+ spin_unlock_irqrestore(&gsDebugLockIRQ, ulLockFlags);
+ }
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+ else
+ {
+ LinuxUnLockMutex(&gsDebugMutexNonIRQ);
+ }
+#endif
+}
+
+static inline void SelectBuffer(IMG_CHAR **ppszBuf, IMG_UINT32 *pui32BufSiz)
+{
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+ if (USE_SPIN_LOCK)
+#endif
+ {
+ *ppszBuf = gszBufferIRQ;
+ *pui32BufSiz = sizeof(gszBufferIRQ);
+ }
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+ else
+ {
+ *ppszBuf = gszBufferNonIRQ;
+ *pui32BufSiz = sizeof(gszBufferNonIRQ);
+ }
+#endif
+}
+
+/*
+ * Append a string to a buffer using formatted conversion.
+ * The function takes a variable number of arguments, pointed
+ * to by the var args list.
+ */
+static IMG_BOOL VBAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR* pszFormat, va_list VArgs)
+{
+ IMG_UINT32 ui32Used;
+ IMG_UINT32 ui32Space;
+ IMG_INT32 i32Len;
+
+ ui32Used = strlen(pszBuf);
+ BUG_ON(ui32Used >= ui32BufSiz);
+ ui32Space = ui32BufSiz - ui32Used;
+
+ i32Len = vsnprintf(&pszBuf[ui32Used], ui32Space, pszFormat, VArgs);
+ pszBuf[ui32BufSiz - 1] = 0;
+
+ /* Return true if string was truncated */
+ return (i32Len < 0 || i32Len >= (IMG_INT32)ui32Space) ? IMG_TRUE : IMG_FALSE;
+}
+
+/* Actually required for ReleasePrintf too */
+
+IMG_VOID PVRDPFInit(IMG_VOID)
+{
+#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK)
+ LinuxInitMutex(&gsDebugMutexNonIRQ);
+#endif
+}
+
+/*!
+******************************************************************************
+ @Function PVRSRVReleasePrintf
+ @Description To output an important message to the user in release builds
+ @Input pszFormat - The message format string
+ @Input ... - Zero or more arguments for use by the format string
+ @Return None
+ ******************************************************************************/
+IMG_VOID PVRSRVReleasePrintf(const IMG_CHAR *pszFormat, ...)
+{
+ va_list vaArgs;
+ unsigned long ulLockFlags = 0;
+ IMG_CHAR *pszBuf;
+ IMG_UINT32 ui32BufSiz;
+
+ SelectBuffer(&pszBuf, &ui32BufSiz);
+
+ va_start(vaArgs, pszFormat);
+
+ GetBufferLock(&ulLockFlags);
+ strncpy (pszBuf, "PVR_K: ", (ui32BufSiz -1));
+
+ if (VBAppend(pszBuf, ui32BufSiz, pszFormat, vaArgs))
+ {
+ printk(KERN_INFO "PVR_K:(Message Truncated): %s\n", pszBuf);
+ }
+ else
+ {
+ printk(KERN_INFO "%s\n", pszBuf);
+ }
+
+ ReleaseBufferLock(ulLockFlags);
+ va_end(vaArgs);
+
+}
+
+#if defined(PVRSRV_NEED_PVR_TRACE)
+
+/*!
+******************************************************************************
+ @Function PVRTrace
+ @Description To output a debug message to the user
+ @Input pszFormat - The message format string
+ @Input ... - Zero or more arguments for use by the format string
+ @Return None
+ ******************************************************************************/
+IMG_VOID PVRSRVTrace(const IMG_CHAR* pszFormat, ...)
+{
+ va_list VArgs;
+ unsigned long ulLockFlags = 0;
+ IMG_CHAR *pszBuf;
+ IMG_UINT32 ui32BufSiz;
+
+ SelectBuffer(&pszBuf, &ui32BufSiz);
+
+ va_start(VArgs, pszFormat);
+
+ GetBufferLock(&ulLockFlags);
+
+ strncpy(pszBuf, "PVR: ", (ui32BufSiz -1));
+
+ if (VBAppend(pszBuf, ui32BufSiz, pszFormat, VArgs))
+ {
+ printk(KERN_INFO "PVR_K:(Message Truncated): %s\n", pszBuf);
+ }
+ else
+ {
+ printk(KERN_INFO "%s\n", pszBuf);
+ }
+
+ ReleaseBufferLock(ulLockFlags);
+
+ va_end(VArgs);
+}
+
+#endif /* defined(PVRSRV_NEED_PVR_TRACE) */
+
+#if defined(PVRSRV_NEED_PVR_DPF)
+
+/*
+ * Append a string to a buffer using formatted conversion.
+ * The function takes a variable number of arguments, calling
+ * VBAppend to do the actual work.
+ */
+static IMG_BOOL BAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR *pszFormat, ...)
+{
+ va_list VArgs;
+ IMG_BOOL bTrunc;
+
+ va_start (VArgs, pszFormat);
+
+ bTrunc = VBAppend(pszBuf, ui32BufSiz, pszFormat, VArgs);
+
+ va_end (VArgs);
+
+ return bTrunc;
+}
+
+/*!
+******************************************************************************
+ @Function PVRSRVDebugPrintf
+ @Description To output a debug message to the user
+ @Input uDebugLevel - The current debug level
+ @Input pszFile - The source file generating the message
+ @Input uLine - The line of the source file
+ @Input pszFormat - The message format string
+ @Input ... - Zero or more arguments for use by the format string
+ @Return None
+ ******************************************************************************/
+IMG_VOID PVRSRVDebugPrintf (
+ IMG_UINT32 ui32DebugLevel,
+ const IMG_CHAR* pszFullFileName,
+ IMG_UINT32 ui32Line,
+ const IMG_CHAR* pszFormat,
+ ...
+ )
+{
+ IMG_BOOL bTrace;
+ const IMG_CHAR *pszFileName = pszFullFileName;
+ IMG_CHAR *pszLeafName;
+
+
+ bTrace = (IMG_BOOL)(ui32DebugLevel & DBGPRIV_CALLTRACE) ? IMG_TRUE : IMG_FALSE;
+
+ if (gPVRDebugLevel & ui32DebugLevel)
+ {
+ va_list vaArgs;
+ unsigned long ulLockFlags = 0;
+ IMG_CHAR *pszBuf;
+ IMG_UINT32 ui32BufSiz;
+
+ SelectBuffer(&pszBuf, &ui32BufSiz);
+
+ va_start(vaArgs, pszFormat);
+
+ GetBufferLock(&ulLockFlags);
+
+ /* Add in the level of warning */
+ if (bTrace == IMG_FALSE)
+ {
+ switch(ui32DebugLevel)
+ {
+ case DBGPRIV_FATAL:
+ {
+ strncpy (pszBuf, "PVR_K:(Fatal): ", (ui32BufSiz -1));
+ break;
+ }
+ case DBGPRIV_ERROR:
+ {
+ strncpy (pszBuf, "PVR_K:(Error): ", (ui32BufSiz -1));
+ break;
+ }
+ case DBGPRIV_WARNING:
+ {
+ strncpy (pszBuf, "PVR_K:(Warning): ", (ui32BufSiz -1));
+ break;
+ }
+ case DBGPRIV_MESSAGE:
+ {
+ strncpy (pszBuf, "PVR_K:(Message): ", (ui32BufSiz -1));
+ break;
+ }
+ case DBGPRIV_VERBOSE:
+ {
+ strncpy (pszBuf, "PVR_K:(Verbose): ", (ui32BufSiz -1));
+ break;
+ }
+ default:
+ {
+ strncpy (pszBuf, "PVR_K:(Unknown message level)", (ui32BufSiz -1));
+ break;
+ }
+ }
+ }
+ else
+ {
+ strncpy (pszBuf, "PVR_K: ", (ui32BufSiz -1));
+ }
+
+ if (VBAppend(pszBuf, ui32BufSiz, pszFormat, vaArgs))
+ {
+ printk(KERN_INFO "PVR_K:(Message Truncated): %s\n", pszBuf);
+ }
+ else
+ {
+ /* Traces don't need a location */
+ if (bTrace == IMG_FALSE)
+ {
+#ifdef DEBUG_LOG_PATH_TRUNCATE
+ /* Buffer for rewriting filepath in log messages */
+ static IMG_CHAR szFileNameRewrite[PVR_MAX_FILEPATH_LEN];
+
+ IMG_CHAR* pszTruncIter;
+ IMG_CHAR* pszTruncBackInter;
+
+ /* Truncate path (DEBUG_LOG_PATH_TRUNCATE shoud be set to EURASIA env var)*/
+ if (strlen(pszFullFileName) > strlen(DEBUG_LOG_PATH_TRUNCATE)+1)
+ pszFileName = pszFullFileName + strlen(DEBUG_LOG_PATH_TRUNCATE)+1;
+
+ /* Try to find '/../' entries and remove it together with
+ previous entry. Repeat unit all removed */
+ strncpy(szFileNameRewrite, pszFileName,PVR_MAX_FILEPATH_LEN);
+
+ if(strlen(szFileNameRewrite) == PVR_MAX_FILEPATH_LEN-1) {
+ IMG_CHAR szTruncateMassage[] = "FILENAME TRUNCATED";
+ strcpy(szFileNameRewrite + (PVR_MAX_FILEPATH_LEN - 1 - strlen(szTruncateMassage)), szTruncateMassage);
+ }
+
+ pszTruncIter = szFileNameRewrite;
+ while(*pszTruncIter++ != 0)
+ {
+ IMG_CHAR* pszNextStartPoint;
+ /* Find '/../' pattern */
+ if(
+ !( ( *pszTruncIter == '/' && (pszTruncIter-4 >= szFileNameRewrite) ) &&
+ ( *(pszTruncIter-1) == '.') &&
+ ( *(pszTruncIter-2) == '.') &&
+ ( *(pszTruncIter-3) == '/') )
+ ) continue;
+
+ /* Find previous '/' */
+ pszTruncBackInter = pszTruncIter - 3;
+ while(*(--pszTruncBackInter) != '/')
+ {
+ if(pszTruncBackInter <= szFileNameRewrite) break;
+ }
+ pszNextStartPoint = pszTruncBackInter;
+
+ /* Remove found region */
+ while(*pszTruncIter != 0)
+ {
+ *pszTruncBackInter++ = *pszTruncIter++;
+ }
+ *pszTruncBackInter = 0;
+
+ /* Start again */
+ pszTruncIter = pszNextStartPoint;
+ }
+
+ pszFileName = szFileNameRewrite;
+ /* Remove first '/' if exist (it's always relative path */
+ if(*pszFileName == '/') pszFileName++;
+#endif
+
+#if !defined(__sh__)
+ pszLeafName = (IMG_CHAR *)strrchr (pszFileName, '\\');
+
+ if (pszLeafName)
+ {
+ pszFileName = pszLeafName;
+ }
+#endif /* __sh__ */
+
+ if (BAppend(pszBuf, ui32BufSiz, " [%u, %s]", ui32Line, pszFileName))
+ {
+ printk(KERN_INFO "PVR_K:(Message Truncated): %s\n", pszBuf);
+ }
+ else
+ {
+ printk(KERN_INFO "%s\n", pszBuf);
+ }
+ }
+ else
+ {
+ printk(KERN_INFO "%s\n", pszBuf);
+ }
+ }
+
+ ReleaseBufferLock(ulLockFlags);
+
+ va_end (vaArgs);
+ }
+}
+
+#endif /* PVRSRV_NEED_PVR_DPF */
+
+#if defined(DEBUG)
+
+IMG_INT PVRDebugProcSetLevel(struct file *file, const IMG_CHAR *buffer, IMG_UINT32 count, IMG_VOID *data)
+{
+#define _PROC_SET_BUFFER_SZ 6
+ IMG_CHAR data_buffer[_PROC_SET_BUFFER_SZ];
+
+ if (count > _PROC_SET_BUFFER_SZ)
+ {
+ return -EINVAL;
+ }
+ else
+ {
+ if (pvr_copy_from_user(data_buffer, buffer, count))
+ return -EINVAL;
+ if (data_buffer[count - 1] != '\n')
+ return -EINVAL;
+ if (sscanf(data_buffer, "%i", &gPVRDebugLevel) == 0)
+ return -EINVAL;
+ gPVRDebugLevel &= (1 << DBGPRIV_DBGLEVEL_COUNT) - 1;
+ }
+ return (count);
+}
+
+void ProcSeqShowDebugLevel(struct seq_file *sfile,void* el)
+{
+ seq_printf(sfile, "%u\n", gPVRDebugLevel);
+}
+
+#endif /* defined(DEBUG) */