Merged mga branch with trunk
[platform/upstream/libdrm.git] / linux / proc.c
1 /* proc.c -- /proc support for DRM -*- linux-c -*-
2  * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
3  * Revised: Sun Feb 13 23:41:04 2000 by kevin@precisioninsight.com
4  *
5  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  * 
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  * 
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26  * 
27  * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/proc.c,v 1.6 2000/02/23 04:47:30 martin Exp $
28  *
29  */
30
31 #define __NO_VERSION__
32 #include "drmP.h"
33
34 static struct proc_dir_entry *drm_root     = NULL;
35 static struct proc_dir_entry *drm_dev_root = NULL;
36 static char                  drm_slot_name[64];
37
38 static int         drm_name_info(char *buf, char **start, off_t offset,
39                                  int len, int *eof, void *data);
40 static int         drm_vm_info(char *buf, char **start, off_t offset,
41                                int len, int *eof, void *data);
42 static int         drm_clients_info(char *buf, char **start, off_t offset,
43                                     int len, int *eof, void *data);
44 static int         drm_queues_info(char *buf, char **start, off_t offset,
45                                    int len, int *eof, void *data);
46 static int         drm_bufs_info(char *buf, char **start, off_t offset,
47                                  int len, int *eof, void *data);
48 #if DRM_DEBUG_CODE
49 static int         drm_vma_info(char *buf, char **start, off_t offset,
50                                 int len, int *eof, void *data);
51 #endif
52 #if DRM_DMA_HISTOGRAM
53 static int         drm_histo_info(char *buf, char **start, off_t offset,
54                                   int len, int *eof, void *data);
55 #endif
56
57 struct drm_proc_list {
58         const char *name;
59         int        (*f)(char *, char **, off_t, int, int *, void *);
60 } drm_proc_list[] = {
61         { "name",    drm_name_info    },
62         { "mem",     drm_mem_info     },
63         { "vm",      drm_vm_info      },
64         { "clients", drm_clients_info },
65         { "queues",  drm_queues_info  },
66         { "bufs",    drm_bufs_info    },
67 #if DRM_DEBUG_CODE
68         { "vma",     drm_vma_info     },
69 #endif
70 #if DRM_DMA_HISTOGRAM
71         { "histo",   drm_histo_info   },
72 #endif
73 };
74 #define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
75
76 int drm_proc_init(drm_device_t *dev)
77 {
78         struct proc_dir_entry *ent;
79         int                   i, j;
80
81         drm_root = create_proc_entry("dri", S_IFDIR, NULL);
82         if (!drm_root) {
83                 DRM_ERROR("Cannot create /proc/dri\n");
84                 return -1;
85         }
86
87                                 /* Instead of doing this search, we should
88                                    add some global support for /proc/dri. */
89         for (i = 0; i < 8; i++) {
90                 sprintf(drm_slot_name, "dri/%d", i);
91                 drm_dev_root = create_proc_entry(drm_slot_name, S_IFDIR, NULL);
92                 if (!drm_dev_root) {
93                         DRM_ERROR("Cannot create /proc/%s\n", drm_slot_name);
94                         remove_proc_entry("dri", NULL);
95                 }
96                 if (drm_dev_root->nlink == 2) break;
97                 drm_dev_root = NULL;
98         }
99         if (!drm_dev_root) {
100                 DRM_ERROR("Cannot find slot in /proc/dri\n");
101                 return -1;
102         }
103
104         for (i = 0; i < DRM_PROC_ENTRIES; i++) {
105                 ent = create_proc_entry(drm_proc_list[i].name,
106                                         S_IFREG|S_IRUGO, drm_dev_root);
107                 if (!ent) {
108                         DRM_ERROR("Cannot create /proc/%s/%s\n",
109                                   drm_slot_name, drm_proc_list[i].name);
110                         for (j = 0; j < i; j++)
111                                 remove_proc_entry(drm_proc_list[i].name,
112                                                   drm_dev_root);
113                         remove_proc_entry(drm_slot_name, NULL);
114                         remove_proc_entry("dri", NULL);
115                         return -1;
116                 }
117                 ent->read_proc = drm_proc_list[i].f;
118                 ent->data      = dev;
119         }
120
121         return 0;
122 }
123
124
125 int drm_proc_cleanup(void)
126 {
127         int i;
128         
129         if (drm_root) {
130                 if (drm_dev_root) {
131                         for (i = 0; i < DRM_PROC_ENTRIES; i++) {
132                                 remove_proc_entry(drm_proc_list[i].name,
133                                                   drm_dev_root);
134                         }
135                         remove_proc_entry(drm_slot_name, NULL);
136                 }
137                 remove_proc_entry("dri", NULL);
138                 remove_proc_entry(DRM_NAME, NULL);
139         }
140         drm_root = drm_dev_root = NULL;
141         return 0;
142 }
143
144 static int drm_name_info(char *buf, char **start, off_t offset, int len,
145                          int *eof, void *data)
146 {
147         drm_device_t *dev = (drm_device_t *)data;
148
149         if (offset > 0) return 0; /* no partial requests */
150         len  = 0;
151         *eof = 1;
152
153         if (dev->unique) {
154                 DRM_PROC_PRINT("%s 0x%x %s\n",
155                                dev->name, dev->device, dev->unique);
156         } else {
157                 DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device);
158         }
159         return len;
160 }
161
162 static int _drm_vm_info(char *buf, char **start, off_t offset, int len,
163                         int *eof, void *data)
164 {
165         drm_device_t *dev = (drm_device_t *)data;
166         drm_map_t    *map;
167                                 /* Hardcoded from _DRM_FRAME_BUFFER,
168                                    _DRM_REGISTERS, _DRM_SHM, and
169                                    _DRM_AGP. */
170         const char   *types[] = { "FB", "REG", "SHM", "AGP" };
171         const char   *type;
172         int          i;
173
174         if (offset > 0) return 0; /* no partial requests */
175         len  = 0;
176         *eof = 1;
177         DRM_PROC_PRINT("slot     offset       size type flags    "
178                        "address mtrr\n\n");
179         for (i = 0; i < dev->map_count; i++) {
180                 map = dev->maplist[i];
181                 if (map->type < 0 || map->type > 3) type = "??";
182                 else                                type = types[map->type];
183                 DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
184                                i,
185                                map->offset,
186                                map->size,
187                                type,
188                                map->flags,
189                                (unsigned long)map->handle);
190                 if (map->mtrr < 0) {
191                         DRM_PROC_PRINT("none\n");
192                 } else {
193                         DRM_PROC_PRINT("%4d\n", map->mtrr);
194                 }
195         }
196
197         return len;
198 }
199
200 static int drm_vm_info(char *buf, char **start, off_t offset, int len,
201                        int *eof, void *data)
202 {
203         drm_device_t *dev = (drm_device_t *)data;
204         int          ret;
205
206         down(&dev->struct_sem);
207         ret = _drm_vm_info(buf, start, offset, len, eof, data);
208         up(&dev->struct_sem);
209         return ret;
210 }
211
212
213 static int _drm_queues_info(char *buf, char **start, off_t offset, int len,
214                             int *eof, void *data)
215 {
216         drm_device_t *dev = (drm_device_t *)data;
217         int          i;
218         drm_queue_t  *q;
219
220         if (offset > 0) return 0; /* no partial requests */
221         len  = 0;
222         *eof = 1;
223         DRM_PROC_PRINT("  ctx/flags   use   fin"
224                        "   blk/rw/rwf  wait    flushed     queued"
225                        "      locks\n\n");
226         for (i = 0; i < dev->queue_count; i++) {
227                 q = dev->queuelist[i];
228                 atomic_inc(&q->use_count);
229                 DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
230                                    "%5d/0x%03x %5d %5d"
231                                    " %5d/%c%c/%c%c%c %5d %10d %10d %10d\n",
232                                    i,
233                                    q->flags,
234                                    atomic_read(&q->use_count),
235                                    atomic_read(&q->finalization),
236                                    atomic_read(&q->block_count),
237                                    atomic_read(&q->block_read) ? 'r' : '-',
238                                    atomic_read(&q->block_write) ? 'w' : '-',
239                                    waitqueue_active(&q->read_queue) ? 'r':'-',
240                                    waitqueue_active(&q->write_queue) ? 'w':'-',
241                                    waitqueue_active(&q->flush_queue) ? 'f':'-',
242                                    DRM_BUFCOUNT(&q->waitlist),
243                                    atomic_read(&q->total_flushed),
244                                    atomic_read(&q->total_queued),
245                                    atomic_read(&q->total_locks));
246                 atomic_dec(&q->use_count);
247         }
248         
249         return len;
250 }
251
252 static int drm_queues_info(char *buf, char **start, off_t offset, int len,
253                            int *eof, void *data)
254 {
255         drm_device_t *dev = (drm_device_t *)data;
256         int          ret;
257
258         down(&dev->struct_sem);
259         ret = _drm_queues_info(buf, start, offset, len, eof, data);
260         up(&dev->struct_sem);
261         return ret;
262 }
263
264 /* drm_bufs_info is called whenever a process reads
265    /dev/drm/<dev>/bufs. */
266
267 static int _drm_bufs_info(char *buf, char **start, off_t offset, int len,
268                           int *eof, void *data)
269 {
270         drm_device_t     *dev = (drm_device_t *)data;
271         drm_device_dma_t *dma = dev->dma;
272         int              i;
273
274         if (!dma)       return 0;
275         if (offset > 0) return 0; /* no partial requests */
276         len  = 0;
277         *eof = 1;
278         DRM_PROC_PRINT(" o     size count  free  segs pages    kB\n\n");
279         for (i = 0; i <= DRM_MAX_ORDER; i++) {
280                 if (dma->bufs[i].buf_count)
281                         DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
282                                        i,
283                                        dma->bufs[i].buf_size,
284                                        dma->bufs[i].buf_count,
285                                        atomic_read(&dma->bufs[i]
286                                                    .freelist.count),
287                                        dma->bufs[i].seg_count,
288                                        dma->bufs[i].seg_count
289                                        *(1 << dma->bufs[i].page_order),
290                                        (dma->bufs[i].seg_count
291                                         * (1 << dma->bufs[i].page_order))
292                                        * PAGE_SIZE / 1024);
293         }
294         DRM_PROC_PRINT("\n");
295         for (i = 0; i < dma->buf_count; i++) {
296                 if (i && !(i%32)) DRM_PROC_PRINT("\n");
297                 DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
298         }
299         DRM_PROC_PRINT("\n");
300
301         return len;
302 }
303
304 static int drm_bufs_info(char *buf, char **start, off_t offset, int len,
305                          int *eof, void *data)
306 {
307         drm_device_t *dev = (drm_device_t *)data;
308         int          ret;
309
310         down(&dev->struct_sem);
311         ret = _drm_bufs_info(buf, start, offset, len, eof, data);
312         up(&dev->struct_sem);
313         return ret;
314 }
315
316
317 static int _drm_clients_info(char *buf, char **start, off_t offset, int len,
318                              int *eof, void *data)
319 {
320         drm_device_t *dev = (drm_device_t *)data;
321         drm_file_t   *priv;
322
323         if (offset > 0) return 0; /* no partial requests */
324         len  = 0;
325         *eof = 1;
326         DRM_PROC_PRINT("a dev   pid    uid      magic     ioctls\n\n");
327         for (priv = dev->file_first; priv; priv = priv->next) {
328                 DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
329                                priv->authenticated ? 'y' : 'n',
330                                priv->minor,
331                                priv->pid,
332                                priv->uid,
333                                priv->magic,
334                                priv->ioctl_count);
335         }
336
337         return len;
338 }
339
340 static int drm_clients_info(char *buf, char **start, off_t offset, int len,
341                             int *eof, void *data)
342 {
343         drm_device_t *dev = (drm_device_t *)data;
344         int          ret;
345
346         down(&dev->struct_sem);
347         ret = _drm_clients_info(buf, start, offset, len, eof, data);
348         up(&dev->struct_sem);
349         return ret;
350 }
351
352 #if DRM_DEBUG_CODE
353
354 static int _drm_vma_info(char *buf, char **start, off_t offset, int len,
355                          int *eof, void *data)
356 {
357         drm_device_t          *dev = (drm_device_t *)data;
358         drm_vma_entry_t       *pt;
359         pgd_t                 *pgd;
360         pmd_t                 *pmd;
361         pte_t                 *pte;
362         unsigned long         i;
363         struct vm_area_struct *vma;
364         unsigned long         address;
365 #if defined(__i386__)
366         unsigned int          pgprot;
367 #endif
368
369         if (offset > 0) return 0; /* no partial requests */
370         len  = 0;
371         *eof = 1;
372         DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
373                        atomic_read(&dev->vma_count),
374                        high_memory, virt_to_phys(high_memory));
375         for (pt = dev->vmalist; pt; pt = pt->next) {
376                 if (!(vma = pt->vma)) continue;
377                 DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
378                                pt->pid,
379                                vma->vm_start,
380                                vma->vm_end,
381                                vma->vm_flags & VM_READ     ? 'r' : '-',
382                                vma->vm_flags & VM_WRITE    ? 'w' : '-',
383                                vma->vm_flags & VM_EXEC     ? 'x' : '-',
384                                vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
385                                vma->vm_flags & VM_LOCKED   ? 'l' : '-',
386                                vma->vm_flags & VM_IO       ? 'i' : '-',
387                                VM_OFFSET(vma));
388                 
389 #if defined(__i386__)
390                 pgprot = pgprot_val(vma->vm_page_prot);
391                 DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
392                                pgprot & _PAGE_PRESENT  ? 'p' : '-',
393                                pgprot & _PAGE_RW       ? 'w' : 'r',
394                                pgprot & _PAGE_USER     ? 'u' : 's',
395                                pgprot & _PAGE_PWT      ? 't' : 'b',
396                                pgprot & _PAGE_PCD      ? 'u' : 'c',
397                                pgprot & _PAGE_ACCESSED ? 'a' : '-',
398                                pgprot & _PAGE_DIRTY    ? 'd' : '-',
399                                pgprot & _PAGE_PSE      ? 'm' : 'k',
400                                pgprot & _PAGE_GLOBAL   ? 'g' : 'l' );
401 #endif          
402                 DRM_PROC_PRINT("\n");
403                 for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
404                         pgd = pgd_offset(vma->vm_mm, i);
405                         pmd = pmd_offset(pgd, i);
406                         pte = pte_offset(pmd, i);
407                         if (pte_present(*pte)) {
408                                 address = __pa(pte_page(*pte))
409                                         + (i & (PAGE_SIZE-1));
410                                 DRM_PROC_PRINT("      0x%08lx -> 0x%08lx"
411                                                " %c%c%c%c%c\n",
412                                                i,
413                                                address,
414                                                pte_read(*pte)  ? 'r' : '-',
415                                                pte_write(*pte) ? 'w' : '-',
416                                                pte_exec(*pte)  ? 'x' : '-',
417                                                pte_dirty(*pte) ? 'd' : '-',
418                                                pte_young(*pte) ? 'a' : '-' );
419                         } else {
420                                 DRM_PROC_PRINT("      0x%08lx\n", i);
421                         }
422                 }
423         }
424         
425         return len;
426 }
427
428 static int drm_vma_info(char *buf, char **start, off_t offset, int len,
429                         int *eof, void *data)
430 {
431         drm_device_t *dev = (drm_device_t *)data;
432         int          ret;
433
434         down(&dev->struct_sem);
435         ret = _drm_vma_info(buf, start, offset, len, eof, data);
436         up(&dev->struct_sem);
437         return ret;
438 }
439 #endif
440
441
442 #if DRM_DMA_HISTOGRAM
443 static int _drm_histo_info(char *buf, char **start, off_t offset, int len,
444                            int *eof, void *data)
445 {
446         drm_device_t     *dev = (drm_device_t *)data;
447         drm_device_dma_t *dma = dev->dma;
448         int              i;
449         unsigned long    slot_value = DRM_DMA_HISTOGRAM_INITIAL;
450         unsigned long    prev_value = 0;
451         drm_buf_t        *buffer;
452
453         if (offset > 0) return 0; /* no partial requests */
454         len  = 0;
455         *eof = 1;
456
457         DRM_PROC_PRINT("general statistics:\n");
458         DRM_PROC_PRINT("total    %10u\n", atomic_read(&dev->histo.total));
459         DRM_PROC_PRINT("open     %10u\n", atomic_read(&dev->total_open));
460         DRM_PROC_PRINT("close    %10u\n", atomic_read(&dev->total_close));
461         DRM_PROC_PRINT("ioctl    %10u\n", atomic_read(&dev->total_ioctl));
462         DRM_PROC_PRINT("irq      %10u\n", atomic_read(&dev->total_irq));
463         DRM_PROC_PRINT("ctx      %10u\n", atomic_read(&dev->total_ctx));
464         
465         DRM_PROC_PRINT("\nlock statistics:\n");
466         DRM_PROC_PRINT("locks    %10u\n", atomic_read(&dev->total_locks));
467         DRM_PROC_PRINT("unlocks  %10u\n", atomic_read(&dev->total_unlocks));
468         DRM_PROC_PRINT("contends %10u\n", atomic_read(&dev->total_contends));
469         DRM_PROC_PRINT("sleeps   %10u\n", atomic_read(&dev->total_sleeps));
470
471
472         if (dma) {
473                 DRM_PROC_PRINT("\ndma statistics:\n");
474                 DRM_PROC_PRINT("prio     %10u\n",
475                                atomic_read(&dma->total_prio));
476                 DRM_PROC_PRINT("bytes    %10u\n",
477                                atomic_read(&dma->total_bytes));
478                 DRM_PROC_PRINT("dmas     %10u\n",
479                                atomic_read(&dma->total_dmas));
480                 DRM_PROC_PRINT("missed:\n");
481                 DRM_PROC_PRINT("  dma    %10u\n",
482                                atomic_read(&dma->total_missed_dma));
483                 DRM_PROC_PRINT("  lock   %10u\n",
484                                atomic_read(&dma->total_missed_lock));
485                 DRM_PROC_PRINT("  free   %10u\n",
486                                atomic_read(&dma->total_missed_free));
487                 DRM_PROC_PRINT("  sched  %10u\n",
488                                atomic_read(&dma->total_missed_sched));
489                 DRM_PROC_PRINT("tried    %10u\n",
490                                atomic_read(&dma->total_tried));
491                 DRM_PROC_PRINT("hit      %10u\n",
492                                atomic_read(&dma->total_hit));
493                 DRM_PROC_PRINT("lost     %10u\n",
494                                atomic_read(&dma->total_lost));
495                 
496                 buffer = dma->next_buffer;
497                 if (buffer) {
498                         DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx);
499                 } else {
500                         DRM_PROC_PRINT("next_buffer    none\n");
501                 }
502                 buffer = dma->this_buffer;
503                 if (buffer) {
504                         DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx);
505                 } else {
506                         DRM_PROC_PRINT("this_buffer    none\n");
507                 }
508         }
509         
510
511         DRM_PROC_PRINT("\nvalues:\n");
512         if (dev->lock.hw_lock) {
513                 DRM_PROC_PRINT("lock           0x%08x\n",
514                                dev->lock.hw_lock->lock);
515         } else {
516                 DRM_PROC_PRINT("lock                 none\n");
517         }
518         DRM_PROC_PRINT("context_flag   0x%08x\n", dev->context_flag);
519         DRM_PROC_PRINT("interrupt_flag 0x%08x\n", dev->interrupt_flag);
520         DRM_PROC_PRINT("dma_flag       0x%08x\n", dev->dma_flag);
521
522         DRM_PROC_PRINT("queue_count    %10d\n",  dev->queue_count);
523         DRM_PROC_PRINT("last_context   %10d\n",  dev->last_context);
524         DRM_PROC_PRINT("last_switch    %10lu\n", dev->last_switch);
525         DRM_PROC_PRINT("last_checked   %10d\n",  dev->last_checked);
526                 
527         
528         DRM_PROC_PRINT("\n                     q2d        d2c        c2f"
529                        "        q2c        q2f        dma        sch"
530                        "        ctx       lacq       lhld\n\n");
531         for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) {
532                 DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u"
533                                " %10u %10u %10u %10u %10u\n",
534                                i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ",
535                                i == DRM_DMA_HISTOGRAM_SLOTS - 1
536                                ? prev_value : slot_value ,
537                                
538                                atomic_read(&dev->histo
539                                            .queued_to_dispatched[i]),
540                                atomic_read(&dev->histo
541                                            .dispatched_to_completed[i]),
542                                atomic_read(&dev->histo
543                                            .completed_to_freed[i]),
544                                
545                                atomic_read(&dev->histo
546                                            .queued_to_completed[i]),
547                                atomic_read(&dev->histo
548                                            .queued_to_freed[i]),
549                                atomic_read(&dev->histo.dma[i]),
550                                atomic_read(&dev->histo.schedule[i]),
551                                atomic_read(&dev->histo.ctx[i]),
552                                atomic_read(&dev->histo.lacq[i]),
553                                atomic_read(&dev->histo.lhld[i]));
554                 prev_value = slot_value;
555                 slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value);
556         }
557         return len;
558 }
559
560 static int drm_histo_info(char *buf, char **start, off_t offset, int len,
561                           int *eof, void *data)
562 {
563         drm_device_t *dev = (drm_device_t *)data;
564         int          ret;
565
566         down(&dev->struct_sem);
567         ret = _drm_histo_info(buf, start, offset, len, eof, data);
568         up(&dev->struct_sem);
569         return ret;
570 }
571 #endif