gpu: pvr: add debugfs interface for the command trace
[sgx.git] / pvr / pvr_debugfs.c
1 /*
2  * Copyright (c) 2010-2011 Imre Deak <imre.deak@nokia.com>
3  * Copyright (c) 2010-2011 Luc Verhaegen <libv@codethink.co.uk>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19
20 /*
21  *
22  * Debugfs interface living in pvr/ subdirectory.
23  *
24  */
25 #include <linux/kernel.h>
26 #include <linux/debugfs.h>
27 #include <linux/vmalloc.h>
28 #include <linux/mutex.h>
29 #include <linux/uaccess.h>
30 #include <linux/io.h>
31
32 #include "img_types.h"
33 #include "servicesext.h"
34 #include "services.h"
35 #include "sgxinfokm.h"
36 #include "syscommon.h"
37 #include "pvr_bridge_km.h"
38 #include "sgxutils.h"
39 #include "pvr_debugfs.h"
40 #include "mmu.h"
41 #include "bridged_support.h"
42 #include "mm.h"
43 #include "pvr_trace_cmd.h"
44
45 struct dentry *pvr_debugfs_dir;
46 static u32 pvr_reset;
47
48 /*
49  *
50  */
51 static struct PVRSRV_DEVICE_NODE *get_sgx_node(void)
52 {
53         struct SYS_DATA *sysdata;
54         struct PVRSRV_DEVICE_NODE *node;
55
56         if (SysAcquireData(&sysdata) != PVRSRV_OK)
57                 return NULL;
58
59         for (node = sysdata->psDeviceNodeList; node; node = node->psNext)
60                 if (node->sDevId.eDeviceType == PVRSRV_DEVICE_TYPE_SGX)
61                         break;
62
63         return node;
64 }
65
66 static int pvr_debugfs_reset(void *data, u64 val)
67 {
68         struct PVRSRV_DEVICE_NODE *node;
69         enum PVRSRV_ERROR err;
70         int r = 0;
71
72         if (val != 1)
73                 return 0;
74
75         pvr_lock();
76
77         if (pvr_is_disabled()) {
78                 r = -ENODEV;
79                 goto exit;
80         }
81
82         node = get_sgx_node();
83         if (!node) {
84                 r =  -ENODEV;
85                 goto exit;
86         }
87
88         err = PVRSRVSetDevicePowerStateKM(node->sDevId.ui32DeviceIndex,
89                                           PVRSRV_POWER_STATE_D0);
90         if (err != PVRSRV_OK) {
91                 r = -EIO;
92                 goto exit;
93         }
94
95         HWRecoveryResetSGX(node, __func__);
96
97         SGXTestActivePowerEvent(node);
98 exit:
99         pvr_unlock();
100
101         return r;
102 }
103
104 static int pvr_debugfs_set(void *data, u64 val)
105 {
106         u32 *var = data;
107
108         if (var == &pvr_reset)
109                 return pvr_debugfs_reset(data, val);
110
111         BUG();
112 }
113
114 DEFINE_SIMPLE_ATTRIBUTE(pvr_debugfs_fops, NULL, pvr_debugfs_set, "%llu\n");
115
116 #ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
117 /*
118  *
119  */
120 #define SGXMK_TRACE_BUFFER_SIZE                                 512
121 #define SGXMK_TRACE_BUF_STR_LEN                                 80
122
123 struct edm_buf_info {
124         size_t len;
125         char data[1];
126 };
127
128 size_t
129 edm_trace_print(struct PVRSRV_SGXDEV_INFO *sdev, char *dst, size_t dst_len)
130 {
131         u32 *buf_start;
132         u32 *buf_end;
133         u32 *buf;
134         size_t p = 0;
135         size_t wr_ofs;
136         int i;
137
138         if (!sdev->psKernelEDMStatusBufferMemInfo)
139                 return 0;
140
141         buf = sdev->psKernelEDMStatusBufferMemInfo->pvLinAddrKM;
142
143         if (dst)
144                 p += scnprintf(dst + p, dst_len - p,
145                               "Last SGX microkernel status code: 0x%x\n", *buf);
146         else
147                 printk(KERN_DEBUG "Last SGX microkernel status code: 0x%x\n",
148                                 *buf);
149         buf++;
150         wr_ofs = *buf;
151         buf++;
152
153         buf_start = buf;
154         buf_end = buf + SGXMK_TRACE_BUFFER_SIZE * 4;
155
156         buf += wr_ofs * 4;
157
158         /* Dump the status values */
159         for (i = 0; i < SGXMK_TRACE_BUFFER_SIZE; i++) {
160                 if (dst)
161                         p += scnprintf(dst + p, dst_len - p,
162                                       "%3d %08X %08X %08X %08X\n",
163                                       i, buf[2], buf[3], buf[1], buf[0]);
164                 else
165                         printk(KERN_DEBUG "%3d %08X %08X %08X %08X\n",
166                                       i, buf[2], buf[3], buf[1], buf[0]);
167                 buf += 4;
168                 if (buf >= buf_end)
169                         buf = buf_start;
170         }
171
172         return p > dst_len ? dst_len : p;
173 }
174
175 static struct edm_buf_info *
176 pvr_edm_buffer_create(struct PVRSRV_SGXDEV_INFO *sgx_info)
177 {
178         struct edm_buf_info *bi;
179         size_t size;
180
181         /* Take a snapshot of the EDM trace buffer */
182         size = SGXMK_TRACE_BUFFER_SIZE * SGXMK_TRACE_BUF_STR_LEN;
183         bi = vmalloc(sizeof(*bi) + size);
184         if (!bi) {
185                 pr_err("%s: vmalloc failed!\n", __func__);
186                 return NULL;
187         }
188
189         bi->len = edm_trace_print(sgx_info, bi->data, size);
190
191         return bi;
192 }
193
194 static void
195 pvr_edm_buffer_destroy(struct edm_buf_info *edm)
196 {
197         vfree(edm);
198 }
199
200 static int pvr_debugfs_edm_open(struct inode *inode, struct file *file)
201 {
202         struct PVRSRV_DEVICE_NODE *node;
203
204         node = get_sgx_node();
205
206         file->private_data = pvr_edm_buffer_create(node->pvDevice);
207         if (!file->private_data)
208                 return -ENOMEM;
209
210         return 0;
211 }
212
213 static int pvr_debugfs_edm_release(struct inode *inode, struct file *file)
214 {
215         pvr_edm_buffer_destroy(file->private_data);
216
217         return 0;
218 }
219
220 static ssize_t pvr_debugfs_edm_read(struct file *file, char __user *buffer,
221                                 size_t count, loff_t *ppos)
222 {
223         struct edm_buf_info *bi = file->private_data;
224
225         return simple_read_from_buffer(buffer, count, ppos, bi->data, bi->len);
226 }
227
228 static const struct file_operations pvr_debugfs_edm_fops = {
229         .owner          = THIS_MODULE,
230         .open           = pvr_debugfs_edm_open,
231         .read           = pvr_debugfs_edm_read,
232         .release        = pvr_debugfs_edm_release,
233 };
234 #endif /* PVRSRV_USSE_EDM_STATUS_DEBUG */
235
236 #ifdef CONFIG_PVR_TRACE_CMD
237
238 static void *trcmd_str_buf;
239 static u8 *trcmd_snapshot;
240 static size_t trcmd_snapshot_size;
241 static int trcmd_open_cnt;
242
243 static int pvr_dbg_trcmd_open(struct inode *inode, struct file *file)
244 {
245         int r;
246
247         if (trcmd_open_cnt)
248                 return -EBUSY;
249
250         trcmd_open_cnt++;
251
252         trcmd_str_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
253         if (!trcmd_str_buf) {
254                 trcmd_open_cnt--;
255
256                 return -ENOMEM;
257         }
258
259         pvr_trcmd_lock();
260
261         r = pvr_trcmd_create_snapshot(&trcmd_snapshot, &trcmd_snapshot_size);
262         if (r < 0) {
263                 pvr_trcmd_unlock();
264                 kfree(trcmd_str_buf);
265                 trcmd_open_cnt--;
266
267                 return r;
268         }
269
270         pvr_trcmd_unlock();
271
272         return 0;
273 }
274
275 static int pvr_dbg_trcmd_release(struct inode *inode, struct file *file)
276 {
277         pvr_trcmd_destroy_snapshot(trcmd_snapshot);
278         kfree(trcmd_str_buf);
279         trcmd_open_cnt--;
280
281         return 0;
282 }
283
284 static ssize_t pvr_dbg_trcmd_read(struct file *file, char __user *buffer,
285                                   size_t count, loff_t *ppos)
286 {
287         ssize_t ret;
288
289         ret = pvr_trcmd_print(trcmd_str_buf, max_t(size_t, PAGE_SIZE, count),
290                               trcmd_snapshot, trcmd_snapshot_size, ppos);
291         if (copy_to_user(buffer, trcmd_str_buf, ret))
292                 return -EFAULT;
293
294         return ret;
295 }
296
297 static const struct file_operations pvr_dbg_trcmd_fops = {
298         .owner          = THIS_MODULE,
299         .open           = pvr_dbg_trcmd_open,
300         .release        = pvr_dbg_trcmd_release,
301         .read           = pvr_dbg_trcmd_read,
302 };
303 #endif
304
305 /*
306  *
307  * HW Recovery dumping support.
308  *
309  */
310 static struct mutex hwrec_mutex[1];
311 static struct timeval hwrec_time;
312 static int hwrec_open_count;
313 static DECLARE_WAIT_QUEUE_HEAD(hwrec_wait_queue);
314 static int hwrec_event;
315
316 /* add extra locking to keep us from overwriting things during dumping. */
317 static int hwrec_event_open_count;
318 static int hwrec_event_file_lock;
319
320 /* While these could get moved into PVRSRV_SGXDEV_INFO, the more future-proof
321  * way of handling hw recovery events is by providing 1 single hwrecovery dump
322  * at a time, and adding a hwrec_info debugfs file with: process information,
323  * general driver information, and the instance of the (then multicore) pvr
324  * where the hwrec event happened.
325  */
326 static u32 *hwrec_registers;
327
328 #ifdef CONFIG_PVR_DEBUG
329 static size_t hwrec_mem_size;
330 #define HWREC_MEM_PAGES (4 * PAGE_SIZE)
331 static unsigned long hwrec_mem_pages[HWREC_MEM_PAGES];
332 #endif /* CONFIG_PVR_DEBUG */
333
334 #ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
335 static struct edm_buf_info *hwrec_edm_buf;
336 #endif
337
338 static void
339 hwrec_registers_dump(struct PVRSRV_SGXDEV_INFO *psDevInfo)
340 {
341         int i;
342
343         if (!hwrec_registers) {
344                 hwrec_registers = (u32 *) __get_free_page(GFP_KERNEL);
345                 if (!hwrec_registers) {
346                         pr_err("%s: failed to get free page.\n", __func__);
347                         return;
348                 }
349         }
350
351         for (i = 0; i < 1024; i++)
352                 hwrec_registers[i] = readl(psDevInfo->pvRegsBaseKM + 4 * i);
353 }
354
355 static void
356 hwrec_pages_free(size_t *size, u32 *pages)
357 {
358         int i;
359
360         if (!(*size))
361                 return;
362
363         for (i = 0; (i * PAGE_SIZE) < *size; i++) {
364                 free_page(pages[i]);
365                 pages[i] = 0;
366         }
367
368         *size = 0;
369 }
370
371 static int
372 hwrec_pages_write(u8 *buffer, size_t size, size_t *current_size, u32 *pages,
373                   int array_size)
374 {
375         size_t ret = 0;
376
377         while (size) {
378                 size_t count = size;
379                 size_t offset = *current_size & ~PAGE_MASK;
380                 int page = *current_size / PAGE_SIZE;
381
382                 if (!offset) {
383                         if (((*current_size) / PAGE_SIZE) >= array_size) {
384                                 pr_err("%s: Size overrun!\n", __func__);
385                                 return -ENOMEM;
386                         }
387
388                         pages[page] = __get_free_page(GFP_KERNEL);
389                         if (!pages[page]) {
390                                 pr_err("%s: failed to get free page.\n",
391                                        __func__);
392                                 return -ENOMEM;
393                         }
394                 }
395
396                 if (count > (PAGE_SIZE - offset))
397                         count = PAGE_SIZE - offset;
398
399                 memcpy(((u8 *) pages[page]) + offset, buffer, count);
400
401                 buffer += count;
402                 size -= count;
403                 ret += count;
404                 *current_size += count;
405         }
406
407         return ret;
408 }
409
410 #ifdef CONFIG_PVR_DEBUG
411 static void
412 hwrec_mem_free(void)
413 {
414         hwrec_pages_free(&hwrec_mem_size, hwrec_mem_pages);
415 }
416
417 int
418 hwrec_mem_write(u8 *buffer, size_t size)
419 {
420         return hwrec_pages_write(buffer, size, &hwrec_mem_size,
421                                  hwrec_mem_pages, ARRAY_SIZE(hwrec_mem_pages));
422 }
423
424 int
425 hwrec_mem_print(char *format, ...)
426 {
427         char tmp[25];
428         va_list ap;
429         size_t size;
430
431         va_start(ap, format);
432         size = vscnprintf(tmp, sizeof(tmp), format, ap);
433         va_end(ap);
434
435         return hwrec_mem_write(tmp, size);
436 }
437 #endif /* CONFIG_PVR_DEBUG */
438
439 /*
440  * Render status buffer dumping.
441  */
442 static size_t hwrec_status_size;
443 static u32 hwrec_status_pages[1024];
444
445 static int
446 hwrec_status_write(char *buffer, size_t size)
447 {
448         return hwrec_pages_write(buffer, size, &hwrec_status_size,
449                                  hwrec_status_pages,
450                                  ARRAY_SIZE(hwrec_status_pages));
451 }
452
453 static void
454 hwrec_status_free(void)
455 {
456         hwrec_pages_free(&hwrec_status_size, hwrec_status_pages);
457 }
458
459 static int
460 hwrec_status_print(char *format, ...)
461 {
462         char tmp[25];
463         va_list ap;
464         size_t size;
465
466         va_start(ap, format);
467         size = vscnprintf(tmp, sizeof(tmp), format, ap);
468         va_end(ap);
469
470         return hwrec_status_write(tmp, size);
471 }
472
473 #define BUF_DESC_CORRUPT        (1 << 31)
474
475 static void add_uniq_items(struct render_state_buf_list *dst,
476                            const struct render_state_buf_list *src)
477 {
478         int i;
479
480         for (i = 0; i < src->cnt; i++) {
481                 const struct render_state_buf_info *sbinf = &src->info[i];
482                 int j;
483
484                 for (j = 0; j < dst->cnt; j++) {
485                         if (sbinf->buf_id == dst->info[j].buf_id) {
486                                 if (memcmp(sbinf, &dst->info[j],
487                                            sizeof(*sbinf)))
488                                         dst->info[j].type |= BUF_DESC_CORRUPT;
489                                 break;
490                         }
491                 }
492                 if (j == dst->cnt) {
493                         /* Bound for cnt is guaranteed by the caller */
494                         dst->info[dst->cnt] = *sbinf;
495                         dst->cnt++;
496                 }
497         }
498 }
499
500 static struct render_state_buf_list *create_merged_uniq_list(
501                 struct render_state_buf_list **bl_set, int set_size)
502 {
503         int i;
504         struct render_state_buf_list *dbl;
505         size_t size;
506
507         /*
508          * Create a buf list big enough to contain all elements from each
509          * list in bl_set.
510          */
511         size = offsetof(struct render_state_buf_list, info[0]);
512         for (i = 0; i < set_size; i++) {
513                 if (!bl_set[i])
514                         continue;
515                 size += bl_set[i]->cnt * sizeof(bl_set[i]->info[0]);
516         }
517         if (!size)
518                 return NULL;
519         dbl = kmalloc(size, GFP_KERNEL);
520         if (!dbl)
521                 return NULL;
522
523         dbl->cnt = 0;
524         for (i = 0; i < set_size; i++) {
525                 if (bl_set[i])
526                         add_uniq_items(dbl, bl_set[i]);
527         }
528
529         return dbl;
530 }
531
532 static void *vmap_buf(struct PVRSRV_PER_PROCESS_DATA *proc,
533                         u32 handle, off_t offset, size_t size)
534 {
535         struct PVRSRV_KERNEL_MEM_INFO *minfo;
536         struct LinuxMemArea *mem_area;
537         enum PVRSRV_ERROR err;
538         unsigned start_ofs;
539         unsigned end_ofs;
540         int pg_cnt;
541         struct page **pages;
542         void *map = NULL;
543         int i;
544
545         if (offset & PAGE_MASK)
546                 return NULL;
547
548         err = PVRSRVLookupHandle(proc->psHandleBase, (void **)&minfo,
549                                 (void *)handle, PVRSRV_HANDLE_TYPE_MEM_INFO);
550         if (err != PVRSRV_OK)
551                 return NULL;
552         if (minfo->pvLinAddrKM)
553                 return minfo->pvLinAddrKM;
554
555         err = PVRSRVLookupOSMemHandle(proc->psHandleBase, (void *)&mem_area,
556                                         (void *)handle);
557         if (err != PVRSRV_OK)
558                 return NULL;
559
560         start_ofs = offset & PAGE_MASK;
561         end_ofs = PAGE_ALIGN(offset + size);
562         pg_cnt = (end_ofs - start_ofs) >> PAGE_SHIFT;
563         pages = kmalloc(pg_cnt * sizeof(pages[0]), GFP_KERNEL);
564         if (!pages)
565                 return NULL;
566         for (i = 0; i < pg_cnt; i++) {
567                 unsigned pfn;
568
569                 pfn = LinuxMemAreaToCpuPFN(mem_area, start_ofs);
570                 if (!pfn_valid(pfn))
571                         goto err;
572                 pages[i] = pfn_to_page(pfn);
573                 start_ofs += PAGE_SIZE;
574         }
575         map = vmap(pages, pg_cnt, VM_MAP, PAGE_KERNEL);
576         map += offset;
577 err:
578         kfree(pages);
579
580         return map;
581 }
582
583 static void vunmap_buf(struct PVRSRV_PER_PROCESS_DATA *proc,
584                         u32 handle, void *map)
585 {
586         struct PVRSRV_KERNEL_MEM_INFO *minfo;
587         enum PVRSRV_ERROR err;
588
589         err = PVRSRVLookupHandle(proc->psHandleBase, (void **)&minfo,
590                                 (void *)handle, PVRSRV_HANDLE_TYPE_MEM_INFO);
591         if (err != PVRSRV_OK)
592                 return;
593         if (minfo->pvLinAddrKM)
594                 return;
595         vunmap((void *)(((unsigned long)map) & PAGE_MASK));
596 }
597
598 static void dump_buf(void *start, size_t size, u32 type)
599 {
600         char *corr = "";
601
602         if (type & BUF_DESC_CORRUPT) {
603                 type &= ~BUF_DESC_CORRUPT;
604                 corr = "(corrupt)";
605         }
606         hwrec_status_print("<type %d%s size %d>\n", type, corr, size);
607         hwrec_status_write(start, size);
608 }
609
610 static struct render_state_buf_list *get_state_buf_list(
611                         struct PVRSRV_PER_PROCESS_DATA *proc,
612                         u32 handle, off_t offset)
613 {
614         struct PVRSRV_KERNEL_MEM_INFO *container;
615         struct render_state_buf_list *buf;
616         enum PVRSRV_ERROR err;
617
618         err = PVRSRVLookupHandle(proc->psHandleBase, (void **)&container,
619                                 (void *)handle, PVRSRV_HANDLE_TYPE_MEM_INFO);
620         if (err != PVRSRV_OK)
621                 return NULL;
622         if (!container->pvLinAddrKM)
623                 return NULL;
624         if (offset + sizeof(*buf) > container->ui32AllocSize)
625                 return NULL;
626
627         buf = container->pvLinAddrKM + offset;
628
629         if (buf->cnt > ARRAY_SIZE(buf->info))
630                 return NULL;
631
632         return buf;
633 }
634
635 static void dump_state_buf_list(struct PVRSRV_PER_PROCESS_DATA *proc,
636                                 struct render_state_buf_list *bl)
637 {
638         int i;
639
640         if (!bl->cnt)
641                 return;
642
643         pr_info("Dumping %d render state buffers\n", bl->cnt);
644         for (i = 0; i < bl->cnt; i++) {
645                 struct render_state_buf_info *binfo;
646                 void *map;
647
648                 binfo = &bl->info[i];
649
650                 map = vmap_buf(proc, binfo->buf_id, binfo->offset, binfo->size);
651                 if (!map)
652                         continue;
653                 dump_buf(map, binfo->size, binfo->type);
654
655                 vunmap_buf(proc, binfo->buf_id, map);
656         }
657 }
658
659 static void dump_sgx_state_bufs(struct PVRSRV_PER_PROCESS_DATA *proc,
660                                 struct PVRSRV_SGXDEV_INFO *dev_info)
661 {
662         struct SGXMKIF_HOST_CTL __iomem *hctl = dev_info->psSGXHostCtl;
663         struct render_state_buf_list *bl_set[2] = { NULL };
664         struct render_state_buf_list *mbl;
665         u32 handle_ta;
666         u32 handle_3d;
667
668         if (!proc)
669                 return;
670
671         handle_ta = readl(&hctl->render_state_buf_ta_handle);
672         handle_3d = readl(&hctl->render_state_buf_3d_handle);
673         bl_set[0] = get_state_buf_list(proc, handle_ta,
674                                         dev_info->state_buf_ofs);
675         /*
676          * The two buf list can be the same if the TA and 3D phases used the
677          * same context at the time of the HWrec. In this case just ignore
678          * one of them.
679          */
680         if (handle_ta != handle_3d)
681                 bl_set[1] = get_state_buf_list(proc, handle_3d,
682                                         dev_info->state_buf_ofs);
683         mbl = create_merged_uniq_list(bl_set, ARRAY_SIZE(bl_set));
684         if (!mbl)
685                 return;
686
687         dump_state_buf_list(proc, mbl);
688         kfree(mbl);
689 }
690
691 void
692 pvr_hwrec_dump(struct PVRSRV_PER_PROCESS_DATA *proc_data,
693                struct PVRSRV_SGXDEV_INFO *psDevInfo)
694 {
695         mutex_lock(hwrec_mutex);
696
697         if (hwrec_open_count || hwrec_event_file_lock) {
698                 pr_err("%s: previous hwrec dump is still locked!\n", __func__);
699                 mutex_unlock(hwrec_mutex);
700                 return;
701         }
702
703         do_gettimeofday(&hwrec_time);
704         pr_info("HW Recovery dump generated at %010ld%06ld\n",
705                 hwrec_time.tv_sec, hwrec_time.tv_usec);
706
707         hwrec_registers_dump(psDevInfo);
708
709 #ifdef CONFIG_PVR_DEBUG
710         hwrec_mem_free();
711         mmu_hwrec_mem_dump(psDevInfo);
712 #endif /* CONFIG_PVR_DEBUG */
713
714 #ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
715         if (hwrec_edm_buf)
716                 pvr_edm_buffer_destroy(hwrec_edm_buf);
717         hwrec_edm_buf = pvr_edm_buffer_create(psDevInfo);
718 #endif
719
720         hwrec_status_free();
721         dump_sgx_state_bufs(proc_data, psDevInfo);
722
723         hwrec_event = 1;
724
725         mutex_unlock(hwrec_mutex);
726
727         wake_up_interruptible(&hwrec_wait_queue);
728 }
729
730 /*
731  * helpers.
732  */
733 static int
734 hwrec_file_open(struct inode *inode, struct file *filp)
735 {
736         mutex_lock(hwrec_mutex);
737
738         hwrec_open_count++;
739
740         mutex_unlock(hwrec_mutex);
741         return 0;
742 }
743
744 static int
745 hwrec_file_release(struct inode *inode, struct file *filp)
746 {
747         mutex_lock(hwrec_mutex);
748
749         hwrec_open_count--;
750
751         mutex_unlock(hwrec_mutex);
752         return 0;
753 }
754
755 static loff_t
756 hwrec_llseek_helper(struct file *filp, loff_t offset, int whence, loff_t max)
757 {
758         loff_t f_pos;
759
760         switch (whence) {
761         case SEEK_SET:
762                 if ((offset > max) || (offset < 0))
763                         f_pos = -EINVAL;
764                 else
765                         f_pos = offset;
766                 break;
767         case SEEK_CUR:
768                 if (((filp->f_pos + offset) > max) ||
769                     ((filp->f_pos + offset) < 0))
770                         f_pos = -EINVAL;
771                 else
772                         f_pos = filp->f_pos + offset;
773                 break;
774         case SEEK_END:
775                 if ((offset > 0) ||
776                     (offset < -max))
777                         f_pos = -EINVAL;
778                 else
779                         f_pos = max + offset;
780                 break;
781         default:
782                 f_pos = -EINVAL;
783                 break;
784         }
785
786         if (f_pos >= 0)
787                 filp->f_pos = f_pos;
788
789         return f_pos;
790 }
791
792 /*
793  * Provides a hwrec timestamp for unique dumping.
794  */
795 static ssize_t
796 hwrec_time_read(struct file *filp, char __user *buf, size_t size,
797                 loff_t *f_pos)
798 {
799         char tmp[20];
800
801         mutex_lock(hwrec_mutex);
802         snprintf(tmp, sizeof(tmp), "%010ld%06ld",
803                  hwrec_time.tv_sec, hwrec_time.tv_usec);
804         mutex_unlock(hwrec_mutex);
805
806         return simple_read_from_buffer(buf, size, f_pos, tmp, strlen(tmp));
807 }
808
809 static const struct file_operations hwrec_time_fops = {
810         .owner = THIS_MODULE,
811         .llseek = no_llseek,
812         .read = hwrec_time_read,
813         .open = hwrec_file_open,
814         .release = hwrec_file_release,
815 };
816
817 /*
818  * Blocks the reader until a HWRec happens.
819  */
820 static int
821 hwrec_event_open(struct inode *inode, struct file *filp)
822 {
823         int ret;
824
825         mutex_lock(hwrec_mutex);
826
827         if (hwrec_event_open_count)
828                 ret = -EUSERS;
829         else {
830                 hwrec_event_open_count++;
831                 ret = 0;
832         }
833
834         mutex_unlock(hwrec_mutex);
835
836         return ret;
837 }
838
839 static int
840 hwrec_event_release(struct inode *inode, struct file *filp)
841 {
842         mutex_lock(hwrec_mutex);
843
844         hwrec_event_open_count--;
845
846         mutex_unlock(hwrec_mutex);
847
848         return 0;
849 }
850
851
852 static ssize_t
853 hwrec_event_read(struct file *filp, char __user *buf, size_t size,
854                  loff_t *f_pos)
855 {
856         int ret = 0;
857
858         mutex_lock(hwrec_mutex);
859
860         hwrec_event_file_lock = 0;
861
862         mutex_unlock(hwrec_mutex);
863
864         ret = wait_event_interruptible(hwrec_wait_queue, hwrec_event);
865         if (!ret) {
866                 mutex_lock(hwrec_mutex);
867
868                 hwrec_event = 0;
869                 hwrec_event_file_lock = 1;
870
871                 mutex_unlock(hwrec_mutex);
872         }
873
874         return ret;
875 }
876
877 static const struct file_operations hwrec_event_fops = {
878         .owner = THIS_MODULE,
879         .llseek = no_llseek,
880         .read = hwrec_event_read,
881         .open = hwrec_event_open,
882         .release = hwrec_event_release,
883 };
884
885 /*
886  * Reads out all readable registers.
887  */
888 #define HWREC_REGS_LINE_SIZE 17
889
890 static loff_t
891 hwrec_regs_llseek(struct file *filp, loff_t offset, int whence)
892 {
893         loff_t f_pos;
894
895         mutex_lock(hwrec_mutex);
896
897         if (hwrec_registers)
898                 f_pos = hwrec_llseek_helper(filp, offset, whence,
899                                             1024 * HWREC_REGS_LINE_SIZE);
900         else
901                 f_pos = 0;
902
903         mutex_unlock(hwrec_mutex);
904
905         return f_pos;
906 }
907
908 static ssize_t
909 hwrec_regs_read(struct file *filp, char __user *buf, size_t size,
910                 loff_t *f_pos)
911 {
912         char tmp[HWREC_REGS_LINE_SIZE + 1];
913         int i;
914
915         if ((*f_pos < 0) || (size < (sizeof(tmp) - 1)))
916                 return 0;
917
918         i = ((int) *f_pos) / (sizeof(tmp) - 1);
919         if (i >= 1024)
920                 return 0;
921
922         mutex_lock(hwrec_mutex);
923
924         if (!hwrec_registers)
925                 size = 0;
926         else
927                 size = snprintf(tmp, sizeof(tmp), "0x%03X 0x%08X\n", i * 4,
928                                 hwrec_registers[i]);
929
930         mutex_unlock(hwrec_mutex);
931
932         if (size > 0) {
933                 if (copy_to_user(buf, tmp + *f_pos - (i * (sizeof(tmp) - 1)),
934                                  size))
935                         return -EFAULT;
936
937                 *f_pos += size;
938                 return size;
939         } else
940                 return 0;
941 }
942
943 static const struct file_operations hwrec_regs_fops = {
944         .owner = THIS_MODULE,
945         .llseek = hwrec_regs_llseek,
946         .read = hwrec_regs_read,
947         .open = hwrec_file_open,
948         .release = hwrec_file_release,
949 };
950
951 #ifdef CONFIG_PVR_DEBUG
952 /*
953  * Provides a full context dump: page directory, page tables, and all mapped
954  * pages.
955  */
956 static loff_t
957 hwrec_mem_llseek(struct file *filp, loff_t offset, int whence)
958 {
959         loff_t f_pos;
960
961         mutex_lock(hwrec_mutex);
962
963         if (hwrec_mem_size)
964                 f_pos = hwrec_llseek_helper(filp, offset, whence,
965                                             hwrec_mem_size);
966         else
967                 f_pos = 0;
968
969         mutex_unlock(hwrec_mutex);
970
971         return f_pos;
972 }
973
974 static ssize_t
975 hwrec_mem_read(struct file *filp, char __user *buf, size_t size,
976                loff_t *f_pos)
977 {
978         mutex_lock(hwrec_mutex);
979
980         if ((*f_pos >= 0) && (*f_pos < hwrec_mem_size)) {
981                 int page, offset;
982
983                 size = min(size, (size_t) hwrec_mem_size - (size_t) *f_pos);
984
985                 page = (*f_pos) / PAGE_SIZE;
986                 offset = (*f_pos) & ~PAGE_MASK;
987
988                 size = min(size, (size_t) PAGE_SIZE - offset);
989
990                 if (copy_to_user(buf,
991                                  ((u8 *) hwrec_mem_pages[page]) + offset,
992                                  size)) {
993                         mutex_unlock(hwrec_mutex);
994                         return -EFAULT;
995                 }
996         } else
997                 size = 0;
998
999         mutex_unlock(hwrec_mutex);
1000
1001         *f_pos += size;
1002         return size;
1003 }
1004
1005 static const struct file_operations hwrec_mem_fops = {
1006         .owner = THIS_MODULE,
1007         .llseek = hwrec_mem_llseek,
1008         .read = hwrec_mem_read,
1009         .open = hwrec_file_open,
1010         .release = hwrec_file_release,
1011 };
1012 #endif /* CONFIG_PVR_DEBUG */
1013
1014 /*
1015  * Read out edm trace created before HW recovery reset.
1016  */
1017 #ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
1018 static loff_t
1019 hwrec_edm_llseek(struct file *filp, loff_t offset, int whence)
1020 {
1021         loff_t f_pos;
1022
1023         mutex_lock(hwrec_mutex);
1024
1025         if (hwrec_edm_buf)
1026                 f_pos = hwrec_llseek_helper(filp, offset, whence,
1027                                             hwrec_edm_buf->len);
1028         else
1029                 f_pos = 0;
1030
1031         mutex_unlock(hwrec_mutex);
1032
1033         return f_pos;
1034 }
1035
1036 static ssize_t
1037 hwrec_edm_read(struct file *filp, char __user *buf, size_t size,
1038                loff_t *f_pos)
1039 {
1040         ssize_t ret;
1041
1042         mutex_lock(hwrec_mutex);
1043
1044         if (hwrec_edm_buf)
1045                 ret = simple_read_from_buffer(buf, size, f_pos,
1046                                               hwrec_edm_buf->data,
1047                                               hwrec_edm_buf->len);
1048         else
1049                 ret = 0;
1050
1051         mutex_unlock(hwrec_mutex);
1052
1053         return ret;
1054 }
1055
1056 static const struct file_operations hwrec_edm_fops = {
1057         .owner = THIS_MODULE,
1058         .llseek = hwrec_edm_llseek,
1059         .read = hwrec_edm_read,
1060         .open = hwrec_file_open,
1061         .release = hwrec_file_release,
1062 };
1063 #endif /* PVRSRV_USSE_EDM_STATUS_DEBUG */
1064
1065 /*
1066  * Provides a dump of the TA and 3D status buffers.
1067  */
1068 static loff_t
1069 hwrec_status_llseek(struct file *filp, loff_t offset, int whence)
1070 {
1071         loff_t f_pos;
1072
1073         mutex_lock(hwrec_mutex);
1074
1075         if (hwrec_status_size)
1076                 f_pos = hwrec_llseek_helper(filp, offset, whence,
1077                                             hwrec_status_size);
1078         else
1079                 f_pos = 0;
1080
1081         mutex_unlock(hwrec_mutex);
1082
1083         return f_pos;
1084 }
1085
1086 static ssize_t
1087 hwrec_status_read(struct file *filp, char __user *buf, size_t size,
1088                loff_t *f_pos)
1089 {
1090         mutex_lock(hwrec_mutex);
1091
1092         if ((*f_pos >= 0) && (*f_pos < hwrec_status_size)) {
1093                 int page, offset;
1094
1095                 size = min(size, (size_t) hwrec_status_size - (size_t) *f_pos);
1096
1097                 page = (*f_pos) / PAGE_SIZE;
1098                 offset = (*f_pos) & ~PAGE_MASK;
1099
1100                 size = min(size, (size_t) PAGE_SIZE - offset);
1101
1102                 if (copy_to_user(buf,
1103                                  ((u8 *) hwrec_status_pages[page]) + offset,
1104                                  size)) {
1105                         mutex_unlock(hwrec_mutex);
1106                         return -EFAULT;
1107                 }
1108         } else
1109                 size = 0;
1110
1111         mutex_unlock(hwrec_mutex);
1112
1113         *f_pos += size;
1114         return size;
1115 }
1116
1117 static const struct file_operations hwrec_status_fops = {
1118         .owner = THIS_MODULE,
1119         .llseek = hwrec_status_llseek,
1120         .read = hwrec_status_read,
1121         .open = hwrec_file_open,
1122         .release = hwrec_file_release,
1123 };
1124
1125 /*
1126  *
1127  */
1128 int pvr_debugfs_init(void)
1129 {
1130         mutex_init(hwrec_mutex);
1131
1132         pvr_debugfs_dir = debugfs_create_dir("pvr", NULL);
1133         if (!pvr_debugfs_dir)
1134                 return -ENODEV;
1135
1136         if (!debugfs_create_file("reset_sgx", S_IWUSR, pvr_debugfs_dir,
1137                                  &pvr_reset, &pvr_debugfs_fops)) {
1138                 debugfs_remove(pvr_debugfs_dir);
1139                 return -ENODEV;
1140         }
1141
1142 #ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
1143         if (!debugfs_create_file("edm_trace", S_IRUGO, pvr_debugfs_dir, NULL,
1144                                  &pvr_debugfs_edm_fops)) {
1145                 debugfs_remove_recursive(pvr_debugfs_dir);
1146                 return -ENODEV;
1147         }
1148 #endif
1149 #ifdef CONFIG_PVR_TRACE_CMD
1150         if (!debugfs_create_file("command_trace", S_IRUGO, pvr_debugfs_dir,
1151                                  NULL, &pvr_dbg_trcmd_fops)) {
1152                 debugfs_remove_recursive(pvr_debugfs_dir);
1153                 return -ENODEV;
1154         }
1155 #endif
1156         if (!debugfs_create_file("hwrec_event", S_IRUSR, pvr_debugfs_dir, NULL,
1157                                  &hwrec_event_fops)) {
1158                 debugfs_remove_recursive(pvr_debugfs_dir);
1159                 return -ENODEV;
1160         }
1161
1162         if (!debugfs_create_file("hwrec_time", S_IRUSR, pvr_debugfs_dir, NULL,
1163                                  &hwrec_time_fops)) {
1164                 debugfs_remove_recursive(pvr_debugfs_dir);
1165                 return -ENODEV;
1166         }
1167
1168         if (!debugfs_create_file("hwrec_regs", S_IRUSR, pvr_debugfs_dir, NULL,
1169                                  &hwrec_regs_fops)) {
1170                 debugfs_remove_recursive(pvr_debugfs_dir);
1171                 return -ENODEV;
1172         }
1173
1174 #ifdef CONFIG_PVR_DEBUG
1175         if (!debugfs_create_file("hwrec_mem", S_IRUSR, pvr_debugfs_dir, NULL,
1176                                  &hwrec_mem_fops)) {
1177                 debugfs_remove_recursive(pvr_debugfs_dir);
1178                 return -ENODEV;
1179         }
1180 #endif /* CONFIG_PVR_DEBUG */
1181
1182 #ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
1183         if (!debugfs_create_file("hwrec_edm", S_IRUSR, pvr_debugfs_dir, NULL,
1184                                  &hwrec_edm_fops)) {
1185                 debugfs_remove_recursive(pvr_debugfs_dir);
1186                 return -ENODEV;
1187         }
1188 #endif
1189
1190         if (!debugfs_create_file("hwrec_status", S_IRUSR, pvr_debugfs_dir, NULL,
1191                                  &hwrec_status_fops)) {
1192                 debugfs_remove_recursive(pvr_debugfs_dir);
1193                 return -ENODEV;
1194         }
1195
1196         return 0;
1197 }
1198
1199 void pvr_debugfs_cleanup(void)
1200 {
1201         debugfs_remove_recursive(pvr_debugfs_dir);
1202
1203         if (hwrec_registers)
1204                 free_page((u32) hwrec_registers);
1205
1206 #ifdef CONFIG_PVR_DEBUG
1207         hwrec_mem_free();
1208 #endif /* CONFIG_PVR_DEBUG */
1209
1210 #ifdef PVRSRV_USSE_EDM_STATUS_DEBUG
1211         if (hwrec_edm_buf)
1212                 pvr_edm_buffer_destroy(hwrec_edm_buf);
1213 #endif
1214
1215         hwrec_status_free();
1216 }