]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.c
gpu: vivante: Update driver from Freescale 3.10.53-1.1-ga BSP
[karo-tx-linux.git] / drivers / mxc / gpu-viv / hal / os / linux / kernel / gc_hal_kernel_debugfs.c
1 /****************************************************************************
2 *
3 *    Copyright (C) 2005 - 2014 by Vivante Corp.
4 *
5 *    This program is free software; you can redistribute it and/or modify
6 *    it under the terms of the GNU General Public License as published by
7 *    the Free Software Foundation; either version 2 of the license, or
8 *    (at your option) any later version.
9 *
10 *    This program is distributed in the hope that it will be useful,
11 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 *    GNU General Public License for more details.
14 *
15 *    You should have received a copy of the GNU General Public License
16 *    along with this program; if not write to the Free Software
17 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 *****************************************************************************/
20
21
22 #ifdef MODULE
23 #include <linux/module.h>
24 #endif
25 #include <linux/init.h>
26 #include <linux/debugfs.h>
27 #include <linux/slab.h>
28 #ifdef MODVERSIONS
29 #include <linux/modversions.h>
30 #endif
31 #include <linux/stddef.h>
32 #include <linux/sched.h>
33 #include <linux/kernel.h>
34 #include <linux/timer.h>
35 #include <linux/delay.h>
36 #include <linux/errno.h>
37 #include <linux/mutex.h>
38 #include <linux/vmalloc.h>
39 #include <linux/types.h>
40 #include <linux/fs.h>
41 #include <linux/poll.h>
42 #include <asm/uaccess.h>
43 #include <linux/completion.h>
44 #include <linux/seq_file.h>
45 #include "gc_hal_kernel_linux.h"
46 #include "gc_hal_kernel.h"
47
48 /*
49    Prequsite:
50
51    1) Debugfs feature must be enabled in the kernel.
52        1.a) You can enable this, in the compilation of the uImage, all you have to do is, In the "make menuconfig" part,
53        you have to enable the debugfs in the kernel hacking part of the menu.
54
55    HOW TO USE:
56    1) insert the driver with the following option logFileSize, Ex: insmod galcore.ko ...... logFileSize=10240
57    This gives a circular buffer of 10 MB
58
59    2)Usually after inserting the driver, the debug file system is mounted under /sys/kernel/debug/
60
61         2.a)If the debugfs is not mounted, you must do "mount -t debugfs none /sys/kernel/debug"
62
63    3) To read what is being printed in the debugfs file system:
64         Ex : cat /sys/kernel/debug/gc/galcore_trace
65
66    4)To write into the debug file system from user side :
67         Ex: echo "hello" > cat /sys/kernel/debug/gc/galcore_trace
68
69    5)To write into debugfs from kernel side, Use the function called gckDEBUGFS_Print
70
71    How to Get Video Memory Usage:
72    1) Select a process whose video memory usage can be dump, no need to reset it until <pid> is needed to be change.
73         echo <pid>  > /sys/kernel/debug/gc/vidmem
74
75    2) Get video memory usage.
76         cat /sys/kernel/debug/gc/vidmem
77
78    USECASE Kernel Dump:
79
80    1) Go to /hal/inc/gc_hal_options.h, and enable the following flags:
81         - #   define gcdDUMP                              1
82         - #   define gcdDUMP_IN_KERNEL          1
83         - #   define gcdDUMP_COMMAND          1
84
85     2) Go to /hal/kernel/gc_hal_kernel_command.c and disable the following flag
86         -#define gcdSIMPLE_COMMAND_DUMP  0
87
88     3) Compile the driver
89     4) insmod it with the logFileSize option
90     5) Run an application
91     6) You can get the dump by cat /sys/kernel/debug/gpu/galcore_trace
92
93  */
94
95 /**/
96 typedef va_list gctDBGARGS ;
97 #define gcmkARGS_START(argument, pointer)   va_start(argument, pointer)
98 #define gcmkARGS_END(argument)                        va_end(argument)
99
100 #define gcmkDEBUGFS_PRINT(ArgumentSize, Message) \
101   { \
102       gctDBGARGS __arguments__; \
103       gcmkARGS_START(__arguments__, Message); \
104       _debugfs_res = _DebugFSPrint(ArgumentSize, Message, &__arguments__);\
105       gcmkARGS_END(__arguments__); \
106   }
107
108 /* Debug File System Node Struct. */
109 struct _gcsDEBUGFS_Node
110 {
111     /*wait queues for read and write operations*/
112 #if defined(DECLARE_WAIT_QUEUE_HEAD)
113     wait_queue_head_t read_q , write_q ;
114 #else
115     struct wait_queue *read_q , *write_q ;
116 #endif
117     struct dentry *parent ; /*parent directory*/
118     struct dentry *filen ; /*filename*/
119     struct dentry *vidmem;
120     struct semaphore sem ; /* mutual exclusion semaphore */
121     char *data ; /* The circular buffer data */
122     int size ; /* Size of the buffer pointed to by 'data' */
123     int refcount ; /* Files that have this buffer open */
124     int read_point ; /* Offset in circ. buffer of oldest data */
125     int write_point ; /* Offset in circ. buffer of newest data */
126     int offset ; /* Byte number of read_point in the stream */
127     struct _gcsDEBUGFS_Node *next ;
128 };
129
130 /* amount of data in the queue */
131 #define gcmkNODE_QLEN(node) ( (node)->write_point >= (node)->read_point ? \
132          (node)->write_point - (node)->read_point : \
133          (node)->size - (node)->read_point + (node)->write_point)
134
135 /* byte number of the last byte in the queue */
136 #define gcmkNODE_FIRST_EMPTY_BYTE(node) ((node)->offset + gcmkNODE_QLEN(node))
137
138 /*Synchronization primitives*/
139 #define gcmkNODE_READQ(node) (&((node)->read_q))
140 #define gcmkNODE_WRITEQ(node) (&((node)->write_q))
141 #define gcmkNODE_SEM(node) (&((node)->sem))
142
143 /*Utilities*/
144 #define gcmkMIN(x, y) ((x) < (y) ? (x) : y)
145
146 /*Debug File System Struct*/
147 typedef struct _gcsDEBUGFS_
148 {
149     gcsDEBUGFS_Node* linkedlist ;
150     gcsDEBUGFS_Node* currentNode ;
151     int isInited ;
152 } gcsDEBUGFS_ ;
153
154 /*debug file system*/
155 static gcsDEBUGFS_ gc_dbgfs ;
156
157 static int gc_debugfs_open(struct inode *inode, struct file *file)
158 {
159     gcsINFO_NODE *node = inode->i_private;
160
161     return single_open(file, node->info->show, node);
162 }
163
164 static const struct file_operations gc_debugfs_operations = {
165     .owner = THIS_MODULE,
166     .open = gc_debugfs_open,
167     .read = seq_read,
168     .llseek = seq_lseek,
169     .release = single_release,
170 };
171
172 gceSTATUS
173 gckDEBUGFS_DIR_Init(
174     IN gckDEBUGFS_DIR Dir,
175     IN struct dentry *root,
176     IN gctCONST_STRING Name
177     )
178 {
179     Dir->root = debugfs_create_dir(Name, root);
180
181     if (!Dir->root)
182     {
183         return gcvSTATUS_NOT_SUPPORTED;
184     }
185
186     INIT_LIST_HEAD(&Dir->nodeList);
187
188     return gcvSTATUS_OK;
189 }
190
191 gceSTATUS
192 gckDEBUGFS_DIR_CreateFiles(
193     IN gckDEBUGFS_DIR Dir,
194     IN gcsINFO * List,
195     IN int count,
196     IN gctPOINTER Data
197     )
198 {
199     int i;
200     gcsINFO_NODE * node;
201     gceSTATUS status;
202
203     for (i = 0; i < count; i++)
204     {
205         /* Create a node. */
206         node = (gcsINFO_NODE *)kzalloc(sizeof(gcsINFO_NODE), GFP_KERNEL);
207
208         node->info   = &List[i];
209         node->device = Data;
210
211         /* Bind to a file. TODO: clean up when fail. */
212         node->entry = debugfs_create_file(
213             List[i].name, S_IRUGO|S_IWUSR, Dir->root, node, &gc_debugfs_operations);
214
215         if (!node->entry)
216         {
217             gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
218         }
219
220         list_add(&(node->head), &(Dir->nodeList));
221     }
222
223     return gcvSTATUS_OK;
224
225 OnError:
226     gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(Dir, List, count));
227     return status;
228 }
229
230 gceSTATUS
231 gckDEBUGFS_DIR_RemoveFiles(
232     IN gckDEBUGFS_DIR Dir,
233     IN gcsINFO * List,
234     IN int count
235     )
236 {
237     int i;
238     gcsINFO_NODE * node;
239     gcsINFO_NODE * temp;
240
241     for (i = 0; i < count; i++)
242     {
243         list_for_each_entry_safe(node, temp, &Dir->nodeList, head)
244         {
245             if (node->info == &List[i])
246             {
247                 debugfs_remove(node->entry);
248                 list_del(&node->head);
249                 kfree(node);
250             }
251         }
252     }
253
254     return gcvSTATUS_OK;
255 }
256
257 void
258 gckDEBUGFS_DIR_Deinit(
259     IN gckDEBUGFS_DIR Dir
260     )
261 {
262     if (Dir->root != NULL)
263     {
264         debugfs_remove(Dir->root);
265         Dir->root = NULL;
266     }
267 }
268
269 /*******************************************************************************
270  **
271  **        READ & WRITE FUNCTIONS (START)
272  **
273  *******************************************************************************/
274
275 /*******************************************************************************
276  **
277  **  _ReadFromNode
278  **
279  **    1) reading bytes out of a circular buffer with wraparound.
280  **    2)returns caddr_t, pointer to data read, which the caller must free.
281  **    3) length is (a pointer to) the number of bytes to be read, which will be set by this function to
282  **        be the number of bytes actually returned
283  **
284  *******************************************************************************/
285 static caddr_t
286 _ReadFromNode (
287                 gcsDEBUGFS_Node* Node ,
288                 size_t *Length ,
289                 loff_t *Offset
290                 )
291 {
292     caddr_t retval ;
293     int bytes_copied = 0 , n , start_point , remaining ;
294
295     /* is the user trying to read data that has already scrolled off? */
296     if ( *Offset < Node->offset )
297     {
298         *Offset = Node->offset ;
299     }
300
301     /* is the user trying to read past EOF? */
302     if ( *Offset >= gcmkNODE_FIRST_EMPTY_BYTE ( Node ) )
303     {
304         return NULL ;
305     }
306
307     /* find the smaller of the total bytes we have available and what
308      * the user is asking for */
309
310     *Length = gcmkMIN ( *Length , gcmkNODE_FIRST_EMPTY_BYTE ( Node ) - *Offset ) ;
311
312     remaining = * Length ;
313
314     /* figure out where to start based on user's Offset */
315     start_point = Node->read_point + ( *Offset - Node->offset ) ;
316
317     start_point = start_point % Node->size ;
318
319     /* allocate memory to return */
320     if ( ( retval = kmalloc ( sizeof (char ) * remaining , GFP_KERNEL ) ) == NULL )
321         return NULL ;
322
323     /* copy the (possibly noncontiguous) data to our buffer */
324     while ( remaining )
325     {
326         n = gcmkMIN ( remaining , Node->size - start_point ) ;
327         memcpy ( retval + bytes_copied , Node->data + start_point , n ) ;
328         bytes_copied += n ;
329         remaining -= n ;
330         start_point = ( start_point + n ) % Node->size ;
331     }
332
333     /* advance user's file pointer */
334     *Offset += * Length ;
335
336     return retval ;
337 }
338
339 /*******************************************************************************
340  **
341  **  _WriteToNode
342  **
343  ** 1) writes to a circular buffer with wraparound.
344  ** 2)in case of an overflow, it overwrites the oldest unread data.
345  **
346  *********************************************************************************/
347 static void
348 _WriteToNode (
349                gcsDEBUGFS_Node* Node ,
350                caddr_t Buf ,
351                int Length
352                )
353 {
354     int bytes_copied = 0 ;
355     int overflow = 0 ;
356     int n ;
357
358     if ( Length + gcmkNODE_QLEN ( Node ) >= ( Node->size - 1 ) )
359     {
360         overflow = 1 ;
361
362         /* in case of overflow, figure out where the new buffer will
363          * begin.  we start by figuring out where the current buffer ENDS:
364          * node->parent->offset +  gcmkNODE_QLEN.    we then advance the end-offset
365          * by the Length of the current write, and work backwards to
366          * figure out what the oldest unoverwritten data will be (i.e.,
367          * size of the buffer). */
368         Node->offset = Node->offset + gcmkNODE_QLEN ( Node ) + Length
369                 - Node->size + 1 ;
370     }
371
372     while ( Length )
373     {
374         /* how many contiguous bytes are available from the write point to
375          * the end of the circular buffer? */
376         n = gcmkMIN ( Length , Node->size - Node->write_point ) ;
377         memcpy ( Node->data + Node->write_point , Buf + bytes_copied , n ) ;
378         bytes_copied += n ;
379         Length -= n ;
380         Node->write_point = ( Node->write_point + n ) % Node->size ;
381     }
382
383     /* if there is an overflow, reset the read point to read whatever is
384      * the oldest data that we have, that has not yet been
385      * overwritten. */
386     if ( overflow )
387     {
388         Node->read_point = ( Node->write_point + 1 ) % Node->size ;
389     }
390 }
391
392 /*******************************************************************************
393  **
394  **         PRINTING UTILITY (START)
395  **
396  *******************************************************************************/
397
398 /*******************************************************************************
399  **
400  **  _GetArgumentSize
401  **
402  **
403  *******************************************************************************/
404 static gctINT
405 _GetArgumentSize (
406                    IN gctCONST_STRING Message
407                    )
408 {
409     gctINT i , count ;
410
411     for ( i = 0 , count = 0 ; Message[i] ; i += 1 )
412     {
413         if ( Message[i] == '%' )
414         {
415             count += 1 ;
416         }
417     }
418     return count * sizeof (unsigned int ) ;
419 }
420
421 /*******************************************************************************
422  **
423  ** _AppendString
424  **
425  **
426  *******************************************************************************/
427 static ssize_t
428 _AppendString (
429                 IN gcsDEBUGFS_Node* Node ,
430                 IN gctCONST_STRING String ,
431                 IN int Length
432                 )
433 {
434     caddr_t message = NULL ;
435     int n ;
436
437     /* if the message is longer than the buffer, just take the beginning
438      * of it, in hopes that the reader (if any) will have time to read
439      * before we wrap around and obliterate it */
440     n = gcmkMIN ( Length , Node->size - 1 ) ;
441
442     /* make sure we have the memory for it */
443     if ( ( message = kmalloc ( n , GFP_KERNEL ) ) == NULL )
444         return - ENOMEM ;
445
446     /* copy into our temp buffer */
447     memcpy ( message , String , n ) ;
448
449     /* now copy it into the circular buffer and free our temp copy */
450     _WriteToNode ( Node , message , n ) ;
451     kfree ( message ) ;
452     return n ;
453 }
454
455 /*******************************************************************************
456  **
457  ** _DebugFSPrint
458  **
459  **
460  *******************************************************************************/
461 static ssize_t
462 _DebugFSPrint (
463                 IN unsigned int ArgumentSize ,
464                 IN const char* Message ,
465                 IN gctDBGARGS * Arguments
466
467                 )
468 {
469     char buffer[MAX_LINE_SIZE] ;
470     int len ;
471     ssize_t res=0;
472
473    if(in_interrupt())
474     {
475         return - ERESTARTSYS ;
476     }
477
478     if(down_interruptible( gcmkNODE_SEM ( gc_dbgfs.currentNode ) ) )
479     {
480          return - ERESTARTSYS ;
481     }
482     len = vsnprintf ( buffer , sizeof (buffer ) , Message , *( va_list * ) Arguments ) ;
483     buffer[len] = '\0' ;
484
485     /* Add end-of-line if missing. */
486     if ( buffer[len - 1] != '\n' )
487     {
488         buffer[len ++] = '\n' ;
489         buffer[len] = '\0' ;
490     }
491     res = _AppendString ( gc_dbgfs.currentNode , buffer , len ) ;
492     up ( gcmkNODE_SEM ( gc_dbgfs.currentNode ) ) ;
493     wake_up_interruptible ( gcmkNODE_READQ ( gc_dbgfs.currentNode ) ) ; /* blocked in read*/
494     return res;
495 }
496
497 /*******************************************************************************
498  **
499  **                     LINUX SYSTEM FUNCTIONS (START)
500  **
501  *******************************************************************************/
502
503 /*******************************************************************************
504  **
505  **  find the vivlog structure associated with an inode.
506  **      returns a    pointer to the structure if found, NULL if not found
507  **
508  *******************************************************************************/
509 static gcsDEBUGFS_Node*
510 _GetNodeInfo (
511                IN struct inode *Inode
512                )
513 {
514     gcsDEBUGFS_Node* node ;
515
516     if ( Inode == NULL )
517         return NULL ;
518
519     for ( node = gc_dbgfs.linkedlist ; node != NULL ; node = node->next )
520         if ( node->filen->d_inode->i_ino == Inode->i_ino )
521             return node ;
522
523     return NULL ;
524 }
525
526 /*******************************************************************************
527  **
528  **   _DebugFSRead
529  **
530  *******************************************************************************/
531 static ssize_t
532 _DebugFSRead (
533                struct file *file ,
534                char __user * buffer ,
535                size_t length ,
536                loff_t * offset
537                )
538 {
539     int retval ;
540     caddr_t data_to_return ;
541     gcsDEBUGFS_Node* node ;
542     /* get the metadata about this emlog */
543     if ( ( node = _GetNodeInfo ( file->f_dentry->d_inode ) ) == NULL )
544     {
545         printk ( "debugfs_read: record not found\n" ) ;
546         return - EIO ;
547     }
548
549     if ( down_interruptible ( gcmkNODE_SEM ( node ) ) )
550     {
551         return - ERESTARTSYS ;
552     }
553
554     /* wait until there's data available (unless we do nonblocking reads) */
555     while ( *offset >= gcmkNODE_FIRST_EMPTY_BYTE ( node ) )
556     {
557         up ( gcmkNODE_SEM ( node ) ) ;
558         if ( file->f_flags & O_NONBLOCK )
559         {
560             return - EAGAIN ;
561         }
562         if ( wait_event_interruptible ( ( *( gcmkNODE_READQ ( node ) ) ) , ( *offset < gcmkNODE_FIRST_EMPTY_BYTE ( node ) ) ) )
563         {
564             return - ERESTARTSYS ; /* signal: tell the fs layer to handle it */
565         }
566         /* otherwise loop, but first reacquire the lock */
567         if ( down_interruptible ( gcmkNODE_SEM ( node ) ) )
568         {
569             return - ERESTARTSYS ;
570         }
571     }
572     data_to_return = _ReadFromNode ( node , &length , offset ) ;
573     if ( data_to_return == NULL )
574     {
575         retval = 0 ;
576         goto unlock ;
577     }
578     if ( copy_to_user ( buffer , data_to_return , length ) > 0 )
579     {
580         retval = - EFAULT ;
581     }
582     else
583     {
584         retval = length ;
585     }
586     kfree ( data_to_return ) ;
587 unlock:
588     up ( gcmkNODE_SEM ( node ) ) ;
589     wake_up_interruptible ( gcmkNODE_WRITEQ ( node ) ) ;
590     return retval ;
591 }
592
593 /*******************************************************************************
594  **
595  **_DebugFSWrite
596  **
597  *******************************************************************************/
598 static ssize_t
599 _DebugFSWrite (
600                 struct file *file ,
601                 const char __user * buffer ,
602                 size_t length ,
603                 loff_t * offset
604                 )
605 {
606     caddr_t message = NULL ;
607     int n ;
608     gcsDEBUGFS_Node*node ;
609
610     /* get the metadata about this log */
611     if ( ( node = _GetNodeInfo ( file->f_dentry->d_inode ) ) == NULL )
612     {
613         return - EIO ;
614     }
615
616     if ( down_interruptible ( gcmkNODE_SEM ( node ) ) )
617     {
618         return - ERESTARTSYS ;
619     }
620
621     /* if the message is longer than the buffer, just take the beginning
622      * of it, in hopes that the reader (if any) will have time to read
623      * before we wrap around and obliterate it */
624     n = gcmkMIN ( length , node->size - 1 ) ;
625
626     /* make sure we have the memory for it */
627     if ( ( message = kmalloc ( n , GFP_KERNEL ) ) == NULL )
628     {
629         up ( gcmkNODE_SEM ( node ) ) ;
630         return - ENOMEM ;
631     }
632
633
634     /* copy into our temp buffer */
635     if ( copy_from_user ( message , buffer , n ) > 0 )
636     {
637         up ( gcmkNODE_SEM ( node ) ) ;
638         kfree ( message ) ;
639         return - EFAULT ;
640     }
641
642     /* now copy it into the circular buffer and free our temp copy */
643     _WriteToNode ( node , message , n ) ;
644
645     kfree ( message ) ;
646     up ( gcmkNODE_SEM ( node ) ) ;
647
648     /* wake up any readers that might be waiting for the data.  we call
649      * schedule in the vague hope that a reader will run before the
650      * writer's next write, to avoid losing data. */
651     wake_up_interruptible ( gcmkNODE_READQ ( node ) ) ;
652
653     return n ;
654 }
655
656 int dumpProcess = 0;
657
658 void
659 _PrintCounter(
660     struct seq_file *file,
661     gcsDATABASE_COUNTERS * counter,
662     gctCONST_STRING Name
663     )
664 {
665     seq_printf(file,"Counter: %s\n", Name);
666
667     seq_printf(file,"%-9s%10s","", "All");
668
669     seq_printf(file, "\n");
670
671     seq_printf(file,"%-9s","Current");
672
673     seq_printf(file,"%10lld", counter->bytes);
674
675     seq_printf(file, "\n");
676
677     seq_printf(file,"%-9s","Maximum");
678
679     seq_printf(file,"%10lld", counter->maxBytes);
680
681     seq_printf(file, "\n");
682
683     seq_printf(file,"%-9s","Total");
684
685     seq_printf(file,"%10lld", counter->totalBytes);
686
687     seq_printf(file, "\n");
688 }
689
690 void
691 _ShowCounters(
692     struct seq_file *file,
693     gcsDATABASE_PTR database
694     )
695 {
696     gctUINT i = 0;
697     gcsDATABASE_COUNTERS * counter;
698     gcsDATABASE_COUNTERS * nonPaged;
699
700     static gctCONST_STRING surfaceTypes[] = {
701         "UNKNOWN",
702         "Index",
703         "Vertex",
704         "Texture",
705         "RT",
706         "Depth",
707         "Bitmap",
708         "TS",
709         "Image",
710         "Mask",
711         "Scissor",
712         "HZDepth",
713     };
714
715     /* Get pointer to counters. */
716     counter = &database->vidMem;
717
718     nonPaged = &database->nonPaged;
719
720     seq_printf(file,"Counter: vidMem (for each surface type)\n");
721
722     seq_printf(file,"%-9s%10s","", "All");
723
724     for (i = 1; i < gcvSURF_NUM_TYPES; i++)
725     {
726         counter = &database->vidMemType[i];
727
728         seq_printf(file, "%10s",surfaceTypes[i]);
729     }
730
731     seq_printf(file, "\n");
732
733     seq_printf(file,"%-9s","Current");
734
735     seq_printf(file,"%10lld", database->vidMem.bytes);
736
737     for (i = 1; i < gcvSURF_NUM_TYPES; i++)
738     {
739         counter = &database->vidMemType[i];
740
741         seq_printf(file,"%10lld", counter->bytes);
742     }
743
744     seq_printf(file, "\n");
745
746     seq_printf(file,"%-9s","Maximum");
747
748     seq_printf(file,"%10lld", database->vidMem.maxBytes);
749
750     for (i = 1; i < gcvSURF_NUM_TYPES; i++)
751     {
752         counter = &database->vidMemType[i];
753
754         seq_printf(file,"%10lld", counter->maxBytes);
755     }
756
757     seq_printf(file, "\n");
758
759     seq_printf(file,"%-9s","Total");
760
761     seq_printf(file,"%10lld", database->vidMem.totalBytes);
762
763     for (i = 1; i < gcvSURF_NUM_TYPES; i++)
764     {
765         counter = &database->vidMemType[i];
766
767         seq_printf(file,"%10lld", counter->totalBytes);
768     }
769
770     seq_printf(file, "\n");
771
772     seq_printf(file,"Counter: vidMem (for each pool)\n");
773
774     seq_printf(file,"%-9s%10s","", "All");
775
776     for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++)
777     {
778         seq_printf(file, "%10d", i);
779     }
780
781     seq_printf(file, "\n");
782
783     seq_printf(file,"%-9s","Current");
784
785     seq_printf(file,"%10lld", database->vidMem.bytes);
786
787     for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++)
788     {
789         counter = &database->vidMemPool[i];
790
791         seq_printf(file,"%10lld", counter->bytes);
792     }
793
794     seq_printf(file, "\n");
795
796     seq_printf(file,"%-9s","Maximum");
797
798     seq_printf(file,"%10lld", database->vidMem.maxBytes);
799
800     for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++)
801     {
802         counter = &database->vidMemPool[i];
803
804         seq_printf(file,"%10lld", counter->maxBytes);
805     }
806
807     seq_printf(file, "\n");
808
809     seq_printf(file,"%-9s","Total");
810
811     seq_printf(file,"%10lld", database->vidMem.totalBytes);
812
813     for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++)
814     {
815         counter = &database->vidMemPool[i];
816
817         seq_printf(file,"%10lld", counter->totalBytes);
818     }
819
820     seq_printf(file, "\n");
821
822     /* Print nonPaged. */
823     _PrintCounter(file, &database->nonPaged, "nonPaged");
824     _PrintCounter(file, &database->contiguous, "contiguous");
825     _PrintCounter(file, &database->mapUserMemory, "mapUserMemory");
826     _PrintCounter(file, &database->mapMemory, "mapMemory");
827 }
828
829 gckKERNEL
830 _GetValidKernel(
831     gckGALDEVICE Device
832 );
833 static int vidmem_show(struct seq_file *file, void *unused)
834 {
835     gceSTATUS status;
836     gcsDATABASE_PTR database;
837     gckGALDEVICE device = file->private;
838
839     gckKERNEL kernel = _GetValidKernel(device);
840     if(kernel == gcvNULL)
841     {
842         return 0;
843     }
844
845     /* Find the database. */
846     gcmkONERROR(
847         gckKERNEL_FindDatabase(kernel, dumpProcess, gcvFALSE, &database));
848
849     seq_printf(file, "VidMem Usage (Process %d):\n", dumpProcess);
850
851     _ShowCounters(file, database);
852
853     return 0;
854
855 OnError:
856     return 0;
857 }
858
859 static int
860 vidmem_open(
861     struct inode *inode,
862     struct file *file
863     )
864 {
865     return single_open(file, vidmem_show, inode->i_private);
866 }
867
868 static ssize_t
869 vidmem_write(
870     struct file *file,
871     const char __user *buf,
872     size_t count,
873     loff_t *pos
874     )
875 {
876     dumpProcess = simple_strtol(buf, NULL, 0);
877     return count;
878 }
879
880 /*******************************************************************************
881  **
882  ** File Operations Table
883  **
884  *******************************************************************************/
885 static const struct file_operations debugfs_operations = {
886                                                           .owner = THIS_MODULE ,
887                                                           .read = _DebugFSRead ,
888                                                           .write = _DebugFSWrite ,
889 } ;
890
891 static const struct file_operations vidmem_operations = {
892     .owner = THIS_MODULE ,
893     .open = vidmem_open,
894     .read = seq_read,
895     .write = vidmem_write,
896     .llseek = seq_lseek,
897 } ;
898
899 /*******************************************************************************
900  **
901  **                             INTERFACE FUNCTIONS (START)
902  **
903  *******************************************************************************/
904
905 /*******************************************************************************
906  **
907  **  gckDEBUGFS_IsEnabled
908  **
909  **
910  **  INPUT:
911  **
912  **  OUTPUT:
913  **
914  *******************************************************************************/
915
916
917 gctINT
918 gckDEBUGFS_IsEnabled ( void )
919 {
920     return gc_dbgfs.isInited ;
921 }
922 /*******************************************************************************
923  **
924  **  gckDEBUGFS_Initialize
925  **
926  **
927  **  INPUT:
928  **
929  **  OUTPUT:
930  **
931  *******************************************************************************/
932
933 gctINT
934 gckDEBUGFS_Initialize ( void )
935 {
936     if ( ! gc_dbgfs.isInited )
937     {
938         gc_dbgfs.linkedlist = gcvNULL ;
939         gc_dbgfs.currentNode = gcvNULL ;
940         gc_dbgfs.isInited = 1 ;
941     }
942     return gc_dbgfs.isInited ;
943 }
944 /*******************************************************************************
945  **
946  **  gckDEBUGFS_Terminate
947  **
948  **
949  **  INPUT:
950  **
951  **  OUTPUT:
952  **
953  *******************************************************************************/
954
955 gctINT
956 gckDEBUGFS_Terminate ( void )
957 {
958     gcsDEBUGFS_Node * next = gcvNULL ;
959     gcsDEBUGFS_Node * temp = gcvNULL ;
960     if ( gc_dbgfs.isInited )
961     {
962         temp = gc_dbgfs.linkedlist ;
963         while ( temp != gcvNULL )
964         {
965             next = temp->next ;
966             gckDEBUGFS_FreeNode ( temp ) ;
967             kfree ( temp ) ;
968             temp = next ;
969         }
970         gc_dbgfs.isInited = 0 ;
971     }
972     return 0 ;
973 }
974
975
976 /*******************************************************************************
977  **
978  **  gckDEBUGFS_CreateNode
979  **
980  **
981  **  INPUT:
982  **
983  **  OUTPUT:
984  **
985  **     gckDEBUGFS_FreeNode * Device
986  **          Pointer to a variable receiving the gcsDEBUGFS_Node object pointer on
987  **          success.
988  *********************************************************************************/
989
990 gctINT
991 gckDEBUGFS_CreateNode (
992     IN gctPOINTER Device,
993     IN gctINT SizeInKB ,
994     IN struct dentry * Root ,
995     IN gctCONST_STRING NodeName ,
996     OUT gcsDEBUGFS_Node **Node
997     )
998 {
999     gcsDEBUGFS_Node*node ;
1000     /* allocate space for our metadata and initialize it */
1001     if ( ( node = kmalloc ( sizeof (gcsDEBUGFS_Node ) , GFP_KERNEL ) ) == NULL )
1002         goto struct_malloc_failed ;
1003
1004     /*Zero it out*/
1005     memset ( node , 0 , sizeof (gcsDEBUGFS_Node ) ) ;
1006
1007     /*Init the sync primitives*/
1008 #if defined(DECLARE_WAIT_QUEUE_HEAD)
1009     init_waitqueue_head ( gcmkNODE_READQ ( node ) ) ;
1010 #else
1011     init_waitqueue ( gcmkNODE_READQ ( node ) ) ;
1012 #endif
1013
1014 #if defined(DECLARE_WAIT_QUEUE_HEAD)
1015     init_waitqueue_head ( gcmkNODE_WRITEQ ( node ) ) ;
1016 #else
1017     init_waitqueue ( gcmkNODE_WRITEQ ( node ) ) ;
1018 #endif
1019     sema_init ( gcmkNODE_SEM ( node ) , 1 ) ;
1020     /*End the sync primitives*/
1021
1022     /*creating the debug file system*/
1023     node->parent = Root;
1024
1025     if (SizeInKB)
1026     {
1027         /* figure out how much of a buffer this should be and allocate the buffer */
1028         node->size = 1024 * SizeInKB ;
1029         if ( ( node->data = ( char * ) vmalloc ( sizeof (char ) * node->size ) ) == NULL )
1030             goto data_malloc_failed ;
1031
1032         /*creating the file*/
1033         node->filen = debugfs_create_file(NodeName, S_IRUGO|S_IWUSR, node->parent, NULL,
1034                                           &debugfs_operations);
1035     }
1036
1037     node->vidmem
1038         = debugfs_create_file("vidmem", S_IRUGO|S_IWUSR, node->parent, Device, &vidmem_operations);
1039
1040     /* add it to our linked list */
1041     node->next = gc_dbgfs.linkedlist ;
1042     gc_dbgfs.linkedlist = node ;
1043
1044
1045     /* pass the struct back */
1046     *Node = node ;
1047     return 0 ;
1048
1049
1050 data_malloc_failed:
1051     kfree ( node ) ;
1052 struct_malloc_failed:
1053     return - ENOMEM ;
1054 }
1055
1056 /*******************************************************************************
1057  **
1058  **  gckDEBUGFS_FreeNode
1059  **
1060  **
1061  **  INPUT:
1062  **
1063  **  OUTPUT:
1064  **
1065  *******************************************************************************/
1066 void
1067 gckDEBUGFS_FreeNode (
1068                              IN gcsDEBUGFS_Node * Node
1069                              )
1070 {
1071
1072     gcsDEBUGFS_Node **ptr ;
1073
1074     if ( Node == NULL )
1075     {
1076         printk ( "null passed to free_vinfo\n" ) ;
1077         return ;
1078     }
1079
1080     down ( gcmkNODE_SEM ( Node ) ) ;
1081     /*free data*/
1082     vfree ( Node->data ) ;
1083
1084     /*Close Debug fs*/
1085     if (Node->vidmem)
1086     {
1087         debugfs_remove(Node->vidmem);
1088     }
1089
1090     if ( Node->filen )
1091     {
1092         debugfs_remove ( Node->filen ) ;
1093     }
1094
1095     /* now delete the node from the linked list */
1096     ptr = & ( gc_dbgfs.linkedlist ) ;
1097     while ( *ptr != Node )
1098     {
1099         if ( ! *ptr )
1100         {
1101             printk ( "corrupt info list!\n" ) ;
1102             break ;
1103         }
1104         else
1105             ptr = & ( ( **ptr ).next ) ;
1106     }
1107     *ptr = Node->next ;
1108     up ( gcmkNODE_SEM ( Node ) ) ;
1109 }
1110
1111 /*******************************************************************************
1112  **
1113  **   gckDEBUGFS_SetCurrentNode
1114  **
1115  **
1116  **  INPUT:
1117  **
1118  **  OUTPUT:
1119  **
1120  *******************************************************************************/
1121 void
1122 gckDEBUGFS_SetCurrentNode (
1123                                    IN gcsDEBUGFS_Node * Node
1124                                    )
1125 {
1126     gc_dbgfs.currentNode = Node ;
1127 }
1128
1129 /*******************************************************************************
1130  **
1131  **   gckDEBUGFS_GetCurrentNode
1132  **
1133  **
1134  **  INPUT:
1135  **
1136  **  OUTPUT:
1137  **
1138  *******************************************************************************/
1139 void
1140 gckDEBUGFS_GetCurrentNode (
1141                                    OUT gcsDEBUGFS_Node ** Node
1142                                    )
1143 {
1144     *Node = gc_dbgfs.currentNode ;
1145 }
1146
1147 /*******************************************************************************
1148  **
1149  **   gckDEBUGFS_Print
1150  **
1151  **
1152  **  INPUT:
1153  **
1154  **  OUTPUT:
1155  **
1156  *******************************************************************************/
1157 ssize_t
1158 gckDEBUGFS_Print (
1159                           IN gctCONST_STRING Message ,
1160                           ...
1161                           )
1162 {
1163     ssize_t _debugfs_res;
1164     gcmkDEBUGFS_PRINT ( _GetArgumentSize ( Message ) , Message ) ;
1165     return _debugfs_res;
1166 }