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