gpu: pvr: pdumpfs: add Kconfig and debugfs pdump mode handling
authorLuc Verhaegen <libv@codethink.co.uk>
Fri, 11 Mar 2011 14:02:47 +0000 (15:02 +0100)
committerGrazvydas Ignotas <notasas@gmail.com>
Sun, 20 May 2012 18:43:04 +0000 (21:43 +0300)
This adds the pvr/pdump debugfs subdirectory, and adds two files there:
mode and modes_possible. The modes_possible file is read-only and
lists the different modes (disabled, standard, full). The mode file
is where we read and set the current mode.

Kconfig now provides an option to select the initial mode pdump
is in.

Signed-off-by: Luc Verhaegen <libv@codethink.co.uk>
Signed-off-by: Imre Deak <imre.deak@nokia.com>
pvr/Kconfig
pvr/pvr_debug.h
pvr/pvr_debugfs.c
pvr/pvr_debugfs.h
pvr/pvr_pdumpfs.c

index 84a8c48..bcbc8a4 100644 (file)
@@ -26,8 +26,35 @@ config PVR_DEBUG_EXTRA
 
 config PVR_DEBUG_PDUMP
        bool "PDUMP debug support"
-       depends on PVR
+       depends on PVR && DEBUG_FS && PVR_DEBUG_EXTRA
        default n
+       help
+           This enables Pdump logging.
+
+choice
+       prompt "Pdump initial debugging mode"
+       depends on PVR_DEBUG_PDUMP
+       default PVR_PDUMP_MODE_STANDARD
+
+config PVR_PDUMP_MODE_DISABLED
+       bool "Disabled"
+       help
+           In this pdump mode, no information will be captured.
+
+config PVR_PDUMP_MODE_STANDARD
+       bool "Standard"
+       help
+           This PDumpmode catches some of the information generated by both
+           kernel and pvr userspace.
+
+config PVR_PDUMP_MODE_FULL
+       bool "Full"
+       help
+           This PDumpmode catches all information generated by both kernel
+           and pvr userspace. This mode is needed for allowing Imagination
+           Technologies to run a pdump log through their simulator.
+
+endchoice
 
 config PVR_EDM_DEBUG
        depends on PVR
index a886a8c..ee4e77b 100644 (file)
@@ -114,4 +114,8 @@ static inline void pvr_dbg_cleanup(void) {};
 
 #endif
 
+#ifdef CONFIG_DEBUG_FS
+extern struct dentry *pvr_debugfs_dir;
+#endif
+
 #endif
index 3c3b30a..81761cd 100644 (file)
@@ -41,7 +41,7 @@
 #include "bridged_support.h"
 #include "mm.h"
 
-static struct dentry *debugfs_dir;
+struct dentry *pvr_debugfs_dir;
 static u32 pvr_reset;
 
 /*
@@ -1049,61 +1049,61 @@ int pvr_debugfs_init(void)
 {
        mutex_init(hwrec_mutex);
 
-       debugfs_dir = debugfs_create_dir("pvr", NULL);
-       if (!debugfs_dir)
+       pvr_debugfs_dir = debugfs_create_dir("pvr", NULL);
+       if (!pvr_debugfs_dir)
                return -ENODEV;
 
-       if (!debugfs_create_file("reset_sgx", S_IWUSR, debugfs_dir, &pvr_reset,
-                                &pvr_debugfs_fops)) {
-               debugfs_remove(debugfs_dir);
+       if (!debugfs_create_file("reset_sgx", S_IWUSR, pvr_debugfs_dir,
+                                &pvr_reset, &pvr_debugfs_fops)) {
+               debugfs_remove(pvr_debugfs_dir);
                return -ENODEV;
        }
 
 #ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
-       if (!debugfs_create_file("edm_trace", S_IRUGO, debugfs_dir, NULL,
+       if (!debugfs_create_file("edm_trace", S_IRUGO, pvr_debugfs_dir, NULL,
                                 &pvr_debugfs_edm_fops)) {
-               debugfs_remove_recursive(debugfs_dir);
+               debugfs_remove_recursive(pvr_debugfs_dir);
                return -ENODEV;
        }
 #endif
 
-       if (!debugfs_create_file("hwrec_event", S_IRUSR, debugfs_dir, NULL,
+       if (!debugfs_create_file("hwrec_event", S_IRUSR, pvr_debugfs_dir, NULL,
                                 &hwrec_event_fops)) {
-               debugfs_remove_recursive(debugfs_dir);
+               debugfs_remove_recursive(pvr_debugfs_dir);
                return -ENODEV;
        }
 
-       if (!debugfs_create_file("hwrec_time", S_IRUSR, debugfs_dir, NULL,
+       if (!debugfs_create_file("hwrec_time", S_IRUSR, pvr_debugfs_dir, NULL,
                                 &hwrec_time_fops)) {
-               debugfs_remove_recursive(debugfs_dir);
+               debugfs_remove_recursive(pvr_debugfs_dir);
                return -ENODEV;
        }
 
-       if (!debugfs_create_file("hwrec_regs", S_IRUSR, debugfs_dir, NULL,
+       if (!debugfs_create_file("hwrec_regs", S_IRUSR, pvr_debugfs_dir, NULL,
                                 &hwrec_regs_fops)) {
-               debugfs_remove_recursive(debugfs_dir);
+               debugfs_remove_recursive(pvr_debugfs_dir);
                return -ENODEV;
        }
 
 #ifdef CONFIG_PVR_DEBUG
-       if (!debugfs_create_file("hwrec_mem", S_IRUSR, debugfs_dir, NULL,
+       if (!debugfs_create_file("hwrec_mem", S_IRUSR, pvr_debugfs_dir, NULL,
                                 &hwrec_mem_fops)) {
-               debugfs_remove_recursive(debugfs_dir);
+               debugfs_remove_recursive(pvr_debugfs_dir);
                return -ENODEV;
        }
 #endif /* CONFIG_PVR_DEBUG */
 
 #ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
-       if (!debugfs_create_file("hwrec_edm", S_IRUSR, debugfs_dir, NULL,
+       if (!debugfs_create_file("hwrec_edm", S_IRUSR, pvr_debugfs_dir, NULL,
                                 &hwrec_edm_fops)) {
-               debugfs_remove_recursive(debugfs_dir);
+               debugfs_remove_recursive(pvr_debugfs_dir);
                return -ENODEV;
        }
 #endif
 
-       if (!debugfs_create_file("hwrec_status", S_IRUSR, debugfs_dir, NULL,
+       if (!debugfs_create_file("hwrec_status", S_IRUSR, pvr_debugfs_dir, NULL,
                                 &hwrec_status_fops)) {
-               debugfs_remove_recursive(debugfs_dir);
+               debugfs_remove_recursive(pvr_debugfs_dir);
                return -ENODEV;
        }
 
@@ -1112,7 +1112,7 @@ int pvr_debugfs_init(void)
 
 void pvr_debugfs_cleanup(void)
 {
-       debugfs_remove_recursive(debugfs_dir);
+       debugfs_remove_recursive(pvr_debugfs_dir);
 
        if (hwrec_registers)
                free_page((u32) hwrec_registers);
index 72bf34b..32aa38b 100644 (file)
@@ -24,6 +24,8 @@
 #error Error: debugfs header included but CONFIG_DEBUG_FS is not defined!
 #endif
 
+extern struct dentry *pvr_debugfs_dir;
+
 int pvr_debugfs_init(void);
 void pvr_debugfs_cleanup(void);
 
index 8be0dd2..c5400f8 100644 (file)
@@ -17,6 +17,8 @@
  */
 
 #include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
 
 #include "img_defs.h"
 #include "services_headers.h"
@@ -31,7 +33,16 @@ enum pdumpfs_mode {
        PDUMPFS_MODE_FULL,
 };
 
-static enum pdumpfs_mode pdumpfs_mode = PDUMPFS_MODE_DISABLED;
+static enum pdumpfs_mode pdumpfs_mode =
+#if defined(CONFIG_PVR_PDUMP_MODE_STANDARD)
+       PDUMPFS_MODE_STANDARD
+#elif defined(CONFIG_PVR_PDUMP_MODE_FULL)
+       PDUMPFS_MODE_FULL
+#else
+       PDUMPFS_MODE_DISABLED
+#endif
+       ;
+
 static u32 pdumpfs_frame_number;
 
 void
@@ -102,16 +113,191 @@ pdumpfs_write_string(char *string)
        mutex_unlock(pdumpfs_mutex);
 }
 
+/*
+ * DebugFS entries.
+ */
+static const struct {
+       char *name;
+       enum pdumpfs_mode mode;
+} pdumpfs_modes[] = {
+       {"disabled",   PDUMPFS_MODE_DISABLED},
+       {"standard",   PDUMPFS_MODE_STANDARD},
+       {"full",       PDUMPFS_MODE_FULL},
+       {NULL, PDUMPFS_MODE_DISABLED}
+};
+
+static ssize_t
+pdumpfs_mode_read(struct file *filp, char __user *buf, size_t size,
+                 loff_t *f_pos)
+{
+       char tmp[16];
+       int i;
+
+       tmp[0] = 0;
+
+       mutex_lock(pdumpfs_mutex);
+
+       for (i = 0; pdumpfs_modes[i].name; i++)
+               if (pdumpfs_modes[i].mode == pdumpfs_mode)
+                       snprintf(tmp, sizeof(tmp), "%s\n",
+                                pdumpfs_modes[i].name);
+
+       mutex_unlock(pdumpfs_mutex);
+
+       if (strlen(tmp) < *f_pos)
+               return 0;
+
+       if ((strlen(tmp) + 1) < (*f_pos + size))
+               size = strlen(tmp) + 1 - *f_pos;
+
+       if (copy_to_user(buf, tmp + *f_pos, size))
+               return -EFAULT;
+
+       *f_pos += size;
+       return size;
+}
+
+static ssize_t
+pdumpfs_mode_write(struct file *filp, const char __user *buf, size_t size,
+                  loff_t *f_pos)
+{
+       static char tmp[16];
+       int i;
+
+       if (*f_pos > sizeof(tmp))
+               return -EINVAL;
+
+       if (size > (sizeof(tmp) - *f_pos))
+               size = sizeof(tmp) - *f_pos;
+
+       if (copy_from_user(tmp + *f_pos, buf, size))
+               return -EFAULT;
+
+       *f_pos += size;
+
+       mutex_lock(pdumpfs_mutex);
+
+       for (i = 0; pdumpfs_modes[i].name; i++)
+               if (!strnicmp(tmp, pdumpfs_modes[i].name,
+                             strlen(pdumpfs_modes[i].name))) {
+                       pdumpfs_mode = pdumpfs_modes[i].mode;
+                       mutex_unlock(pdumpfs_mutex);
+                       return size;
+               }
+
+       mutex_unlock(pdumpfs_mutex);
+       return -EINVAL;
+}
+
+static const struct file_operations pdumpfs_mode_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .read = pdumpfs_mode_read,
+       .write = pdumpfs_mode_write,
+};
+
+static ssize_t
+pdumpfs_modes_possible_read(struct file *filp, char __user *buf, size_t size,
+                           loff_t *f_pos)
+{
+       unsigned int i, skip = *f_pos, pos = 0;
+
+       for (i = 0; pdumpfs_modes[i].name; i++) {
+               if (i) { /* space */
+                       if (skip)
+                               skip--;
+                       else if (size > pos) {
+                               if (copy_to_user(buf + pos, " ", 1))
+                                       return -EFAULT;
+                               pos++;
+                       }
+               }
+
+               if (size) {
+                       int len = strlen(pdumpfs_modes[i].name);
+
+                       if (skip >= len) {
+                               skip -= len;
+                       } else if (size > pos) {
+                               len = min(len - skip, size - pos);
+
+                               if (copy_to_user(buf + pos,
+                                                pdumpfs_modes[i].name + skip,
+                                                len))
+                                       return -EFAULT;
+
+                               skip = 0;
+                               pos += len;
+                       }
+               }
+       }
+
+       *f_pos += pos;
+       return pos;
+}
+
+static const struct file_operations pdumpfs_modes_possible_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .read = pdumpfs_modes_possible_read,
+};
+
+static struct dentry *pdumpfs_dir;
+
+static void
+pdumpfs_file_create(const char *name, mode_t mode,
+                   const struct file_operations *fops)
+{
+       struct dentry *tmp = NULL;
+
+       tmp = debugfs_create_file(name, mode, pdumpfs_dir, NULL, fops);
+       if (!tmp)
+               pr_err("%s: failed to create pvr/%s file.\n", __func__, name);
+}
+
+static int
+pdumpfs_fs_init(void)
+{
+       if (!pvr_debugfs_dir) {
+               pr_err("%s: debugfs pvr/ directory does not exist.\n",
+                      __func__);
+               return -ENOENT;
+       }
+
+       pdumpfs_dir = debugfs_create_dir("pdump", pvr_debugfs_dir);
+       if (!pdumpfs_dir) {
+               pr_err("%s: failed to create top level directory.\n",
+                      __func__);
+               return -ENOENT;
+       }
+
+       pdumpfs_file_create("mode", S_IRUSR | S_IWUSR,
+                           &pdumpfs_mode_fops);
+       pdumpfs_file_create("modes_possible", S_IRUSR,
+                           &pdumpfs_modes_possible_fops);
+
+       return 0;
+}
+
+static void
+pdumpfs_fs_destroy(void)
+{
+       if (pdumpfs_dir)
+               debugfs_remove_recursive(pdumpfs_dir);
+}
+
 int
 pdumpfs_init(void)
 {
        mutex_init(pdumpfs_mutex);
 
+       pdumpfs_fs_init();
+
        return 0;
 }
 
 void
 pdumpfs_cleanup(void)
 {
-
+       pdumpfs_fs_destroy();
 }