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