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