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
#endif
+#ifdef CONFIG_DEBUG_FS
+extern struct dentry *pvr_debugfs_dir;
+#endif
+
#endif
#include "bridged_support.h"
#include "mm.h"
-static struct dentry *debugfs_dir;
+struct dentry *pvr_debugfs_dir;
static u32 pvr_reset;
/*
{
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;
}
void pvr_debugfs_cleanup(void)
{
- debugfs_remove_recursive(debugfs_dir);
+ debugfs_remove_recursive(pvr_debugfs_dir);
if (hwrec_registers)
free_page((u32) hwrec_registers);
#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);
*/
#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
#include "img_defs.h"
#include "services_headers.h"
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
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();
}