gpu: pvr: pdumpfs: start storing pdump data
authorLuc Verhaegen <Luc.Verhaegen@basyskom.de>
Fri, 11 Mar 2011 14:02:50 +0000 (15:02 +0100)
committerGrazvydas Ignotas <notasas@gmail.com>
Sun, 20 May 2012 18:43:04 +0000 (21:43 +0300)
Page based allocation, with built in copy_from_user to minimise buffer
copies. Up to 2040 pages of data are kept per frame, if this amount is
exceeded, an error message is printed, and a new frame is created
automatically.

Parameter data is stored inside the same stream as script data, but
is encapsulated in "BIN %08X:"..."-- BIN END".

Signed-off-by: Luc Verhaegen <Luc.Verhaegen@basyskom.de>
Signed-off-by: Imre Deak <imre.deak@nokia.com>
pvr/pvr_pdump.c
pvr/pvr_pdumpfs.c

index 6966d01..007b9c7 100644 (file)
@@ -91,13 +91,21 @@ pdump_print(u32 flags, char *format, ...)
 static enum PVRSRV_ERROR
 pdump_dump(u32 flags, void *buffer, u32 size, bool from_user)
 {
+       enum PVRSRV_ERROR eError;
+
        if (PDumpSuspended())
                return PVRSRV_OK;
 
        if (!pdumpfs_flags_check(flags))
                return PVRSRV_OK;
 
-       return pdumpfs_write_data(buffer, size, from_user);
+       pdump_print(flags, "BIN 0x%08X:", size);
+
+       eError = pdumpfs_write_data(buffer, size, from_user);
+
+       pdump_print(flags, "-- BIN END\r\n");
+
+       return eError;
 }
 
 void PDumpCommentKM(char *pszComment, u32 ui32Flags)
index e16e4f7..5caca90 100644 (file)
@@ -43,11 +43,17 @@ static enum pdumpfs_mode pdumpfs_mode =
 #endif
        ;
 
+#define FRAME_PAGE_COUNT 2040
+
 struct pdumpfs_frame {
        struct pdumpfs_frame *next;
 
        u32 pid;
        u32 number;
+
+       size_t offset;
+       int page_count;
+       unsigned long pages[FRAME_PAGE_COUNT];
 };
 
 static u32 frame_count_max = CONFIG_PVR_PDUMP_INITIAL_MAX_FRAME_COUNT;
@@ -72,9 +78,14 @@ frame_create(void)
 static void
 frame_destroy(struct pdumpfs_frame *frame)
 {
+       int i;
+
        if (!frame)
                return;
 
+       for (i = 0; i < frame->page_count; i++)
+               free_page(frame->pages[i]);
+
        kfree(frame);
 }
 
@@ -180,14 +191,101 @@ pdumpfs_flags_check(u32 flags)
        return ret;
 }
 
+static size_t
+pdumpfs_frame_write_low(void *buffer, size_t size, bool from_user)
+{
+       struct pdumpfs_frame *frame = frame_current;
+       size_t ret = 0;
+
+       while (size) {
+               size_t count = size;
+               size_t offset = frame->offset & ~PAGE_MASK;
+               unsigned long page;
+
+               if (!offset) {
+                       if (frame->page_count >= FRAME_PAGE_COUNT) {
+                               pr_err("%s: Frame size overrun.\n", __func__);
+                               return -ENOMEM;
+                       }
+
+                       page = __get_free_page(GFP_KERNEL);
+                       if (!page) {
+                               pr_err("%s: failed to get free page.\n",
+                                      __func__);
+                               return -ENOMEM;
+                       }
+
+                       frame->pages[frame->page_count] = page;
+                       frame->page_count++;
+               } else
+                       page =
+                               frame->pages[frame->page_count - 1];
+
+               if (count > (PAGE_SIZE - offset))
+                       count = PAGE_SIZE - offset;
+
+               if (from_user) {
+                       if (copy_from_user(((u8 *) page) + offset,
+                                          (void __user __force *) buffer,
+                                          count))
+                               return -EINVAL;
+               } else
+                       memcpy(((u8 *) page) + offset, buffer, count);
+
+               buffer += count;
+               size -= count;
+               ret += count;
+               frame->offset += count;
+       }
+       return ret;
+}
+
+static size_t
+pdumpfs_frame_write(void *buffer, size_t size, bool from_user)
+{
+       size_t ret;
+
+       if ((frame_current->offset + size) > (PAGE_SIZE * FRAME_PAGE_COUNT)) {
+               u32 pid = OSGetCurrentProcessIDKM();
+               struct task_struct *task;
+
+               pr_err("Frame overrun!!!\n");
+
+               ret = frame_new(pid, -1);
+               if (ret)
+                       return ret;
+
+               rcu_read_lock();
+               task = pid_task(find_vpid(pid), PIDTYPE_PID);
+
+#define FRAME_OVERRUN_MESSAGE "-- Starting forced frame caused by "
+               pdumpfs_frame_write_low(FRAME_OVERRUN_MESSAGE,
+                                       sizeof(FRAME_OVERRUN_MESSAGE), false);
+               pdumpfs_frame_write_low(task->comm, strlen(task->comm), false);
+               pdumpfs_frame_write_low("\r\n", 2, false);
+
+               pr_err("%s: Frame size overrun, caused by %d (%s)\n",
+                      __func__, pid, task->comm);
+
+               rcu_read_unlock();
+       }
+
+       return pdumpfs_frame_write_low(buffer, size, from_user);
+}
+
 enum PVRSRV_ERROR
 pdumpfs_write_data(void *buffer, size_t size, bool from_user)
 {
        mutex_lock(pdumpfs_mutex);
 
+       size = pdumpfs_frame_write(buffer, size, from_user);
+
        mutex_unlock(pdumpfs_mutex);
 
-       return PVRSRV_OK;
+       if ((size >= 0) || (size == -ENOMEM))
+               return PVRSRV_OK;
+       else
+               return PVRSRV_ERROR_GENERIC;
 }
 
 void
@@ -195,6 +293,8 @@ pdumpfs_write_string(char *string)
 {
        mutex_lock(pdumpfs_mutex);
 
+       pdumpfs_frame_write(string, strlen(string), false);
+
        mutex_unlock(pdumpfs_mutex);
 }