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