gpu: pvr: fix missing return value warning when CONFIG_BUG=n
[sgx.git] / pvr / pvr_debugfs.c
index ed2c795..32ca6c3 100644 (file)
@@ -40,6 +40,7 @@
 #include "mmu.h"
 #include "bridged_support.h"
 #include "mm.h"
+#include "pvr_trace_cmd.h"
 
 struct dentry *pvr_debugfs_dir;
 static u32 pvr_reset;
@@ -100,7 +101,7 @@ exit:
        return r;
 }
 
-static int pvr_debugfs_set(void *data, u64 val)
+static int pvr_debugfs_reset_wrapper(void *data, u64 val)
 {
        u32 *var = data;
 
@@ -108,9 +109,12 @@ static int pvr_debugfs_set(void *data, u64 val)
                return pvr_debugfs_reset(data, val);
 
        BUG();
+
+       return -EFAULT;
 }
 
-DEFINE_SIMPLE_ATTRIBUTE(pvr_debugfs_fops, NULL, pvr_debugfs_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(pvr_debugfs_reset_fops, NULL,
+                       pvr_debugfs_reset_wrapper, "%llu\n");
 
 #ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
 /*
@@ -124,7 +128,7 @@ struct edm_buf_info {
        char data[1];
 };
 
-static size_t
+size_t
 edm_trace_print(struct PVRSRV_SGXDEV_INFO *sdev, char *dst, size_t dst_len)
 {
        u32 *buf_start;
@@ -139,8 +143,12 @@ edm_trace_print(struct PVRSRV_SGXDEV_INFO *sdev, char *dst, size_t dst_len)
 
        buf = sdev->psKernelEDMStatusBufferMemInfo->pvLinAddrKM;
 
-       p += scnprintf(dst + p, dst_len - p,
-                     "Last SGX microkernel status code: 0x%x\n", *buf);
+       if (dst)
+               p += scnprintf(dst + p, dst_len - p,
+                             "Last SGX microkernel status code: 0x%x\n", *buf);
+       else
+               printk(KERN_DEBUG "Last SGX microkernel status code: 0x%x\n",
+                               *buf);
        buf++;
        wr_ofs = *buf;
        buf++;
@@ -152,9 +160,13 @@ edm_trace_print(struct PVRSRV_SGXDEV_INFO *sdev, char *dst, size_t dst_len)
 
        /* Dump the status values */
        for (i = 0; i < SGXMK_TRACE_BUFFER_SIZE; i++) {
-               p += scnprintf(dst + p, dst_len - p,
-                             "%3d %08X %08X %08X %08X\n",
-                             i, buf[2], buf[3], buf[1], buf[0]);
+               if (dst)
+                       p += scnprintf(dst + p, dst_len - p,
+                                     "%3d %08X %08X %08X %08X\n",
+                                     i, buf[2], buf[3], buf[1], buf[0]);
+               else
+                       printk(KERN_DEBUG "%3d %08X %08X %08X %08X\n",
+                                     i, buf[2], buf[3], buf[1], buf[0]);
                buf += 4;
                if (buf >= buf_end)
                        buf = buf_start;
@@ -224,6 +236,225 @@ static const struct file_operations pvr_debugfs_edm_fops = {
 };
 #endif /* PVRSRV_USSE_EDM_STATUS_DEBUG */
 
+#ifdef CONFIG_PVR_TRACE_CMD
+
+static void *trcmd_str_buf;
+static u8 *trcmd_snapshot;
+static size_t trcmd_snapshot_size;
+static int trcmd_open_cnt;
+
+static int pvr_dbg_trcmd_open(struct inode *inode, struct file *file)
+{
+       int r;
+
+       if (trcmd_open_cnt)
+               return -EBUSY;
+
+       trcmd_open_cnt++;
+
+       trcmd_str_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!trcmd_str_buf) {
+               trcmd_open_cnt--;
+
+               return -ENOMEM;
+       }
+
+       pvr_trcmd_lock();
+
+       r = pvr_trcmd_create_snapshot(&trcmd_snapshot, &trcmd_snapshot_size);
+       if (r < 0) {
+               pvr_trcmd_unlock();
+               kfree(trcmd_str_buf);
+               trcmd_open_cnt--;
+
+               return r;
+       }
+
+       pvr_trcmd_unlock();
+
+       return 0;
+}
+
+static int pvr_dbg_trcmd_release(struct inode *inode, struct file *file)
+{
+       pvr_trcmd_destroy_snapshot(trcmd_snapshot);
+       kfree(trcmd_str_buf);
+       trcmd_open_cnt--;
+
+       return 0;
+}
+
+static ssize_t pvr_dbg_trcmd_read(struct file *file, char __user *buffer,
+                                 size_t count, loff_t *ppos)
+{
+       ssize_t ret;
+
+       ret = pvr_trcmd_print(trcmd_str_buf, max_t(size_t, PAGE_SIZE, count),
+                             trcmd_snapshot, trcmd_snapshot_size, ppos);
+       if (copy_to_user(buffer, trcmd_str_buf, ret))
+               return -EFAULT;
+
+       return ret;
+}
+
+static const struct file_operations pvr_dbg_trcmd_fops = {
+       .owner          = THIS_MODULE,
+       .open           = pvr_dbg_trcmd_open,
+       .release        = pvr_dbg_trcmd_release,
+       .read           = pvr_dbg_trcmd_read,
+};
+#endif
+
+/*
+ * llseek helper.
+ */
+static loff_t
+pvr_debugfs_llseek_helper(struct file *filp, loff_t offset, int whence,
+                         loff_t max)
+{
+       loff_t f_pos;
+
+       switch (whence) {
+       case SEEK_SET:
+               if ((offset > max) || (offset < 0))
+                       f_pos = -EINVAL;
+               else
+                       f_pos = offset;
+               break;
+       case SEEK_CUR:
+               if (((filp->f_pos + offset) > max) ||
+                   ((filp->f_pos + offset) < 0))
+                       f_pos = -EINVAL;
+               else
+                       f_pos = filp->f_pos + offset;
+               break;
+       case SEEK_END:
+               if ((offset > 0) ||
+                   (offset < -max))
+                       f_pos = -EINVAL;
+               else
+                       f_pos = max + offset;
+               break;
+       default:
+               f_pos = -EINVAL;
+               break;
+       }
+
+       if (f_pos >= 0)
+               filp->f_pos = f_pos;
+
+       return f_pos;
+}
+
+/*
+ * One shot register dump.
+ *
+ * Only in D0 can we read all registers. Our driver currently only does either
+ * D0 or D3. In D3 any register read results in a SIGBUS. There is a possibility
+ * that in D1 or possibly D2 all registers apart from [0xA08:0xA4C] can be read.
+ */
+static int
+pvr_debugfs_regs_open(struct inode *inode, struct file *filp)
+{
+       struct PVRSRV_DEVICE_NODE *node;
+       struct PVRSRV_SGXDEV_INFO *dev;
+       enum PVRSRV_ERROR error;
+       u32 *regs;
+       int i, ret = 0;
+
+       regs = (u32 *) __get_free_page(GFP_KERNEL);
+       if (!regs)
+               return -ENOMEM;
+
+       pvr_lock();
+
+       if (pvr_is_disabled()) {
+               ret = -ENODEV;
+               goto exit;
+       }
+
+       node = get_sgx_node();
+       if (!node) {
+               ret = -ENODEV;
+               goto exit;
+       }
+       dev = node->pvDevice;
+
+       error = PVRSRVSetDevicePowerStateKM(node->sDevId.ui32DeviceIndex,
+                                           PVRSRV_POWER_STATE_D0);
+       if (error != PVRSRV_OK) {
+               ret = -EIO;
+               goto exit;
+       }
+
+       for (i = 0; i < 1024; i++)
+               regs[i] = readl(dev->pvRegsBaseKM + 4 * i);
+
+       filp->private_data = regs;
+
+       SGXTestActivePowerEvent(node);
+
+ exit:
+       pvr_unlock();
+
+       return ret;
+}
+
+static int
+pvr_debugfs_regs_release(struct inode *inode, struct file *filp)
+{
+       free_page((unsigned long) filp->private_data);
+
+       return 0;
+}
+
+#define REGS_DUMP_LINE_SIZE 17
+#define REGS_DUMP_FORMAT "0x%03X 0x%08X\n"
+
+static loff_t
+pvr_debugfs_regs_llseek(struct file *filp, loff_t offset, int whence)
+{
+       return pvr_debugfs_llseek_helper(filp, offset, whence,
+                                        1024 * REGS_DUMP_LINE_SIZE);
+}
+
+static ssize_t
+pvr_debugfs_regs_read(struct file *filp, char __user *buf, size_t size,
+                     loff_t *f_pos)
+{
+       char tmp[REGS_DUMP_LINE_SIZE + 1];
+       u32 *regs = filp->private_data;
+       int i;
+
+       if ((*f_pos < 0) || (size < (sizeof(tmp) - 1)))
+               return 0;
+
+       i = ((int) *f_pos) / (sizeof(tmp) - 1);
+       if (i >= 1024)
+               return 0;
+
+       size = snprintf(tmp, sizeof(tmp), REGS_DUMP_FORMAT, i * 4, regs[i]);
+
+       if (size > 0) {
+               if (copy_to_user(buf, tmp + *f_pos - (i * (sizeof(tmp) - 1)),
+                                size))
+                       return -EFAULT;
+
+               *f_pos += size;
+               return size;
+       } else
+               return 0;
+}
+
+static const struct file_operations pvr_debugfs_regs_fops = {
+       .owner = THIS_MODULE,
+       .llseek = pvr_debugfs_regs_llseek,
+       .read = pvr_debugfs_regs_read,
+       .open = pvr_debugfs_regs_open,
+       .release = pvr_debugfs_regs_release,
+};
+
+
 /*
  *
  * HW Recovery dumping support.
@@ -275,7 +506,7 @@ hwrec_registers_dump(struct PVRSRV_SGXDEV_INFO *psDevInfo)
 }
 
 static void
-hwrec_pages_free(size_t *size, u32 *pages)
+hwrec_pages_free(size_t *size, unsigned long *pages)
 {
        int i;
 
@@ -291,8 +522,8 @@ hwrec_pages_free(size_t *size, u32 *pages)
 }
 
 static int
-hwrec_pages_write(u8 *buffer, size_t size, size_t *current_size, u32 *pages,
-                 int array_size)
+hwrec_pages_write(u8 *buffer, size_t size, size_t *current_size,
+                 unsigned long *pages, int array_size)
 {
        size_t ret = 0;
 
@@ -362,7 +593,7 @@ hwrec_mem_print(char *format, ...)
  * Render status buffer dumping.
  */
 static size_t hwrec_status_size;
-static u32 hwrec_status_pages[1024];
+static unsigned long hwrec_status_pages[1024];
 
 static int
 hwrec_status_write(char *buffer, size_t size)
@@ -405,7 +636,8 @@ static void add_uniq_items(struct render_state_buf_list *dst,
 
                for (j = 0; j < dst->cnt; j++) {
                        if (sbinf->buf_id == dst->info[j].buf_id) {
-                               if (memcmp(sbinf, &dst->info[j], sizeof(sbinf)))
+                               if (memcmp(sbinf, &dst->info[j],
+                                          sizeof(*sbinf)))
                                        dst->info[j].type |= BUF_DESC_CORRUPT;
                                break;
                        }
@@ -673,43 +905,6 @@ hwrec_file_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static loff_t
-hwrec_llseek_helper(struct file *filp, loff_t offset, int whence, loff_t max)
-{
-       loff_t f_pos;
-
-       switch (whence) {
-       case SEEK_SET:
-               if ((offset > max) || (offset < 0))
-                       f_pos = -EINVAL;
-               else
-                       f_pos = offset;
-               break;
-       case SEEK_CUR:
-               if (((filp->f_pos + offset) > max) ||
-                   ((filp->f_pos + offset) < 0))
-                       f_pos = -EINVAL;
-               else
-                       f_pos = filp->f_pos + offset;
-               break;
-       case SEEK_END:
-               if ((offset > 0) ||
-                   (offset < -max))
-                       f_pos = -EINVAL;
-               else
-                       f_pos = max + offset;
-               break;
-       default:
-               f_pos = -EINVAL;
-               break;
-       }
-
-       if (f_pos >= 0)
-               filp->f_pos = f_pos;
-
-       return f_pos;
-}
-
 /*
  * Provides a hwrec timestamp for unique dumping.
  */
@@ -806,8 +1001,6 @@ static const struct file_operations hwrec_event_fops = {
 /*
  * Reads out all readable registers.
  */
-#define HWREC_REGS_LINE_SIZE 17
-
 static loff_t
 hwrec_regs_llseek(struct file *filp, loff_t offset, int whence)
 {
@@ -816,8 +1009,8 @@ hwrec_regs_llseek(struct file *filp, loff_t offset, int whence)
        mutex_lock(hwrec_mutex);
 
        if (hwrec_registers)
-               f_pos = hwrec_llseek_helper(filp, offset, whence,
-                                           1024 * HWREC_REGS_LINE_SIZE);
+               f_pos = pvr_debugfs_llseek_helper(filp, offset, whence,
+                                                 1024 * REGS_DUMP_LINE_SIZE);
        else
                f_pos = 0;
 
@@ -830,7 +1023,7 @@ static ssize_t
 hwrec_regs_read(struct file *filp, char __user *buf, size_t size,
                loff_t *f_pos)
 {
-       char tmp[HWREC_REGS_LINE_SIZE + 1];
+       char tmp[REGS_DUMP_LINE_SIZE + 1];
        int i;
 
        if ((*f_pos < 0) || (size < (sizeof(tmp) - 1)))
@@ -845,7 +1038,7 @@ hwrec_regs_read(struct file *filp, char __user *buf, size_t size,
        if (!hwrec_registers)
                size = 0;
        else
-               size = snprintf(tmp, sizeof(tmp), "0x%03X 0x%08X\n", i * 4,
+               size = snprintf(tmp, sizeof(tmp), REGS_DUMP_FORMAT, i * 4,
                                hwrec_registers[i]);
 
        mutex_unlock(hwrec_mutex);
@@ -882,8 +1075,8 @@ hwrec_mem_llseek(struct file *filp, loff_t offset, int whence)
        mutex_lock(hwrec_mutex);
 
        if (hwrec_mem_size)
-               f_pos = hwrec_llseek_helper(filp, offset, whence,
-                                           hwrec_mem_size);
+               f_pos = pvr_debugfs_llseek_helper(filp, offset, whence,
+                                                 hwrec_mem_size);
        else
                f_pos = 0;
 
@@ -944,8 +1137,8 @@ hwrec_edm_llseek(struct file *filp, loff_t offset, int whence)
        mutex_lock(hwrec_mutex);
 
        if (hwrec_edm_buf)
-               f_pos = hwrec_llseek_helper(filp, offset, whence,
-                                           hwrec_edm_buf->len);
+               f_pos = pvr_debugfs_llseek_helper(filp, offset, whence,
+                                                 hwrec_edm_buf->len);
        else
                f_pos = 0;
 
@@ -994,8 +1187,8 @@ hwrec_status_llseek(struct file *filp, loff_t offset, int whence)
        mutex_lock(hwrec_mutex);
 
        if (hwrec_status_size)
-               f_pos = hwrec_llseek_helper(filp, offset, whence,
-                                           hwrec_status_size);
+               f_pos = pvr_debugfs_llseek_helper(filp, offset, whence,
+                                                 hwrec_status_size);
        else
                f_pos = 0;
 
@@ -1055,7 +1248,7 @@ int pvr_debugfs_init(void)
                return -ENODEV;
 
        if (!debugfs_create_file("reset_sgx", S_IWUSR, pvr_debugfs_dir,
-                                &pvr_reset, &pvr_debugfs_fops)) {
+                                &pvr_reset, &pvr_debugfs_reset_fops)) {
                debugfs_remove(pvr_debugfs_dir);
                return -ENODEV;
        }
@@ -1067,6 +1260,19 @@ int pvr_debugfs_init(void)
                return -ENODEV;
        }
 #endif
+#ifdef CONFIG_PVR_TRACE_CMD
+       if (!debugfs_create_file("command_trace", S_IRUGO, pvr_debugfs_dir,
+                                NULL, &pvr_dbg_trcmd_fops)) {
+               debugfs_remove_recursive(pvr_debugfs_dir);
+               return -ENODEV;
+       }
+#endif
+
+       if (!debugfs_create_file("registers", S_IRUSR, pvr_debugfs_dir, NULL,
+                                &pvr_debugfs_regs_fops)) {
+               debugfs_remove(pvr_debugfs_dir);
+               return -ENODEV;
+       }
 
        if (!debugfs_create_file("hwrec_event", S_IRUSR, pvr_debugfs_dir, NULL,
                                 &hwrec_event_fops)) {