From 4713ddfef267393154536ce3f4edb8ae3c5d6d72 Mon Sep 17 00:00:00 2001 From: Luc Verhaegen Date: Fri, 11 Mar 2011 15:02:47 +0100 Subject: [PATCH] gpu: pvr: pdumpfs: add Kconfig and debugfs pdump mode handling 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 Signed-off-by: Imre Deak --- pvr/Kconfig | 29 ++++++- pvr/pvr_debug.h | 4 + pvr/pvr_debugfs.c | 42 +++++----- pvr/pvr_debugfs.h | 2 + pvr/pvr_pdumpfs.c | 190 +++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 243 insertions(+), 24 deletions(-) diff --git a/pvr/Kconfig b/pvr/Kconfig index 84a8c48..bcbc8a4 100644 --- a/pvr/Kconfig +++ b/pvr/Kconfig @@ -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 diff --git a/pvr/pvr_debug.h b/pvr/pvr_debug.h index a886a8c..ee4e77b 100644 --- a/pvr/pvr_debug.h +++ b/pvr/pvr_debug.h @@ -114,4 +114,8 @@ static inline void pvr_dbg_cleanup(void) {}; #endif +#ifdef CONFIG_DEBUG_FS +extern struct dentry *pvr_debugfs_dir; +#endif + #endif diff --git a/pvr/pvr_debugfs.c b/pvr/pvr_debugfs.c index 3c3b30a..81761cd 100644 --- a/pvr/pvr_debugfs.c +++ b/pvr/pvr_debugfs.c @@ -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); diff --git a/pvr/pvr_debugfs.h b/pvr/pvr_debugfs.h index 72bf34b..32aa38b 100644 --- a/pvr/pvr_debugfs.h +++ b/pvr/pvr_debugfs.h @@ -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); diff --git a/pvr/pvr_pdumpfs.c b/pvr/pvr_pdumpfs.c index 8be0dd2..c5400f8 100644 --- a/pvr/pvr_pdumpfs.c +++ b/pvr/pvr_pdumpfs.c @@ -17,6 +17,8 @@ */ #include +#include +#include #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(); } -- 2.39.5