Merge with 2.3.99-pre1.
[linux-2.6/linux-mips.git] / drivers / char / drm / proc.c
blob4d5d1a964b4fb8fe93a8873b535e14080fa51993
1 /* proc.c -- /proc support for DRM -*- linux-c -*-
2 * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
26 * Authors:
27 * Rickard E. (Rik) Faith <faith@precisioninsight.com>
31 #define __NO_VERSION__
32 #include "drmP.h"
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];
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
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
74 #define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
76 int drm_proc_init(drm_device_t *dev)
78 struct proc_dir_entry *ent;
79 int i, j;
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;
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);
96 if (drm_dev_root->nlink == 2) break;
97 drm_dev_root = NULL;
99 if (!drm_dev_root) {
100 DRM_ERROR("Cannot find slot in /proc/dri\n");
101 return -1;
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;
117 ent->read_proc = drm_proc_list[i].f;
118 ent->data = dev;
121 return 0;
125 int drm_proc_cleanup(void)
127 int i;
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);
135 remove_proc_entry(drm_slot_name, NULL);
137 remove_proc_entry("dri", NULL);
138 remove_proc_entry(DRM_NAME, NULL);
140 drm_root = drm_dev_root = NULL;
141 return 0;
144 static int drm_name_info(char *buf, char **start, off_t offset, int len,
145 int *eof, void *data)
147 drm_device_t *dev = (drm_device_t *)data;
149 if (offset > 0) return 0; /* no partial requests */
150 len = 0;
151 *eof = 1;
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);
159 return len;
162 static int _drm_vm_info(char *buf, char **start, off_t offset, int len,
163 int *eof, void *data)
165 drm_device_t *dev = (drm_device_t *)data;
166 drm_map_t *map;
167 const char *types[] = { "FB", "REG", "SHM" };
168 const char *type;
169 int i;
171 if (offset > 0) return 0; /* no partial requests */
172 len = 0;
173 *eof = 1;
174 DRM_PROC_PRINT("slot offset size type flags "
175 "address mtrr\n\n");
176 for (i = 0; i < dev->map_count; i++) {
177 map = dev->maplist[i];
178 if (map->type < 0 || map->type > 2) type = "??";
179 else type = types[map->type];
180 DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ",
182 map->offset,
183 map->size,
184 type,
185 map->flags,
186 (unsigned long)map->handle);
187 if (map->mtrr < 0) {
188 DRM_PROC_PRINT("none\n");
189 } else {
190 DRM_PROC_PRINT("%4d\n", map->mtrr);
194 return len;
197 static int drm_vm_info(char *buf, char **start, off_t offset, int len,
198 int *eof, void *data)
200 drm_device_t *dev = (drm_device_t *)data;
201 int ret;
203 down(&dev->struct_sem);
204 ret = _drm_vm_info(buf, start, offset, len, eof, data);
205 up(&dev->struct_sem);
206 return ret;
210 static int _drm_queues_info(char *buf, char **start, off_t offset, int len,
211 int *eof, void *data)
213 drm_device_t *dev = (drm_device_t *)data;
214 int i;
215 drm_queue_t *q;
217 if (offset > 0) return 0; /* no partial requests */
218 len = 0;
219 *eof = 1;
220 DRM_PROC_PRINT(" ctx/flags use fin"
221 " blk/rw/rwf wait flushed queued"
222 " locks\n\n");
223 for (i = 0; i < dev->queue_count; i++) {
224 q = dev->queuelist[i];
225 atomic_inc(&q->use_count);
226 DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
227 "%5d/0x%03x %5d %5d"
228 " %5d/%c%c/%c%c%c %5d %10d %10d %10d\n",
230 q->flags,
231 atomic_read(&q->use_count),
232 atomic_read(&q->finalization),
233 atomic_read(&q->block_count),
234 atomic_read(&q->block_read) ? 'r' : '-',
235 atomic_read(&q->block_write) ? 'w' : '-',
236 waitqueue_active(&q->read_queue) ? 'r':'-',
237 waitqueue_active(&q->write_queue) ? 'w':'-',
238 waitqueue_active(&q->flush_queue) ? 'f':'-',
239 DRM_BUFCOUNT(&q->waitlist),
240 atomic_read(&q->total_flushed),
241 atomic_read(&q->total_queued),
242 atomic_read(&q->total_locks));
243 atomic_dec(&q->use_count);
246 return len;
249 static int drm_queues_info(char *buf, char **start, off_t offset, int len,
250 int *eof, void *data)
252 drm_device_t *dev = (drm_device_t *)data;
253 int ret;
255 down(&dev->struct_sem);
256 ret = _drm_queues_info(buf, start, offset, len, eof, data);
257 up(&dev->struct_sem);
258 return ret;
261 /* drm_bufs_info is called whenever a process reads
262 /dev/drm/<dev>/bufs. */
264 static int _drm_bufs_info(char *buf, char **start, off_t offset, int len,
265 int *eof, void *data)
267 drm_device_t *dev = (drm_device_t *)data;
268 drm_device_dma_t *dma = dev->dma;
269 int i;
271 if (!dma) return 0;
272 if (offset > 0) return 0; /* no partial requests */
273 len = 0;
274 *eof = 1;
275 DRM_PROC_PRINT(" o size count free segs pages kB\n\n");
276 for (i = 0; i <= DRM_MAX_ORDER; i++) {
277 if (dma->bufs[i].buf_count)
278 DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
280 dma->bufs[i].buf_size,
281 dma->bufs[i].buf_count,
282 atomic_read(&dma->bufs[i]
283 .freelist.count),
284 dma->bufs[i].seg_count,
285 dma->bufs[i].seg_count
286 *(1 << dma->bufs[i].page_order),
287 (dma->bufs[i].seg_count
288 * (1 << dma->bufs[i].page_order))
289 * PAGE_SIZE / 1024);
291 DRM_PROC_PRINT("\n");
292 for (i = 0; i < dma->buf_count; i++) {
293 if (i && !(i%32)) DRM_PROC_PRINT("\n");
294 DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
296 DRM_PROC_PRINT("\n");
298 return len;
301 static int drm_bufs_info(char *buf, char **start, off_t offset, int len,
302 int *eof, void *data)
304 drm_device_t *dev = (drm_device_t *)data;
305 int ret;
307 down(&dev->struct_sem);
308 ret = _drm_bufs_info(buf, start, offset, len, eof, data);
309 up(&dev->struct_sem);
310 return ret;
314 static int _drm_clients_info(char *buf, char **start, off_t offset, int len,
315 int *eof, void *data)
317 drm_device_t *dev = (drm_device_t *)data;
318 drm_file_t *priv;
320 if (offset > 0) return 0; /* no partial requests */
321 len = 0;
322 *eof = 1;
323 DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n");
324 for (priv = dev->file_first; priv; priv = priv->next) {
325 DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
326 priv->authenticated ? 'y' : 'n',
327 priv->minor,
328 priv->pid,
329 priv->uid,
330 priv->magic,
331 priv->ioctl_count);
334 return len;
337 static int drm_clients_info(char *buf, char **start, off_t offset, int len,
338 int *eof, void *data)
340 drm_device_t *dev = (drm_device_t *)data;
341 int ret;
343 down(&dev->struct_sem);
344 ret = _drm_clients_info(buf, start, offset, len, eof, data);
345 up(&dev->struct_sem);
346 return ret;
349 #if DRM_DEBUG_CODE
351 static int _drm_vma_info(char *buf, char **start, off_t offset, int len,
352 int *eof, void *data)
354 drm_device_t *dev = (drm_device_t *)data;
355 drm_vma_entry_t *pt;
356 pgd_t *pgd;
357 pmd_t *pmd;
358 pte_t *pte;
359 unsigned long i;
360 struct vm_area_struct *vma;
361 unsigned long address;
362 #if defined(__i386__)
363 unsigned int pgprot;
364 #endif
366 if (offset > 0) return 0; /* no partial requests */
367 len = 0;
368 *eof = 1;
369 DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
370 atomic_read(&dev->vma_count),
371 high_memory, virt_to_phys(high_memory));
372 for (pt = dev->vmalist; pt; pt = pt->next) {
373 if (!(vma = pt->vma)) continue;
374 DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
375 pt->pid,
376 vma->vm_start,
377 vma->vm_end,
378 vma->vm_flags & VM_READ ? 'r' : '-',
379 vma->vm_flags & VM_WRITE ? 'w' : '-',
380 vma->vm_flags & VM_EXEC ? 'x' : '-',
381 vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
382 vma->vm_flags & VM_LOCKED ? 'l' : '-',
383 vma->vm_flags & VM_IO ? 'i' : '-',
384 VM_OFFSET(vma));
386 #if defined(__i386__)
387 pgprot = pgprot_val(vma->vm_page_prot);
388 DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
389 pgprot & _PAGE_PRESENT ? 'p' : '-',
390 pgprot & _PAGE_RW ? 'w' : 'r',
391 pgprot & _PAGE_USER ? 'u' : 's',
392 pgprot & _PAGE_PWT ? 't' : 'b',
393 pgprot & _PAGE_PCD ? 'u' : 'c',
394 pgprot & _PAGE_ACCESSED ? 'a' : '-',
395 pgprot & _PAGE_DIRTY ? 'd' : '-',
396 pgprot & _PAGE_PSE ? 'm' : 'k',
397 pgprot & _PAGE_GLOBAL ? 'g' : 'l' );
398 #endif
399 DRM_PROC_PRINT("\n");
400 for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
401 pgd = pgd_offset(vma->vm_mm, i);
402 pmd = pmd_offset(pgd, i);
403 pte = pte_offset(pmd, i);
404 if (pte_present(*pte)) {
405 address = __pa(pte_page(*pte))
406 + (i & (PAGE_SIZE-1));
407 DRM_PROC_PRINT(" 0x%08lx -> 0x%08lx"
408 " %c%c%c%c%c\n",
410 address,
411 pte_read(*pte) ? 'r' : '-',
412 pte_write(*pte) ? 'w' : '-',
413 pte_exec(*pte) ? 'x' : '-',
414 pte_dirty(*pte) ? 'd' : '-',
415 pte_young(*pte) ? 'a' : '-' );
416 } else {
417 DRM_PROC_PRINT(" 0x%08lx\n", i);
422 return len;
425 static int drm_vma_info(char *buf, char **start, off_t offset, int len,
426 int *eof, void *data)
428 drm_device_t *dev = (drm_device_t *)data;
429 int ret;
431 down(&dev->struct_sem);
432 ret = _drm_vma_info(buf, start, offset, len, eof, data);
433 up(&dev->struct_sem);
434 return ret;
436 #endif
439 #if DRM_DMA_HISTOGRAM
440 static int _drm_histo_info(char *buf, char **start, off_t offset, int len,
441 int *eof, void *data)
443 drm_device_t *dev = (drm_device_t *)data;
444 drm_device_dma_t *dma = dev->dma;
445 int i;
446 unsigned long slot_value = DRM_DMA_HISTOGRAM_INITIAL;
447 unsigned long prev_value = 0;
448 drm_buf_t *buffer;
450 if (offset > 0) return 0; /* no partial requests */
451 len = 0;
452 *eof = 1;
454 DRM_PROC_PRINT("general statistics:\n");
455 DRM_PROC_PRINT("total %10u\n", atomic_read(&dev->histo.total));
456 DRM_PROC_PRINT("open %10u\n", atomic_read(&dev->total_open));
457 DRM_PROC_PRINT("close %10u\n", atomic_read(&dev->total_close));
458 DRM_PROC_PRINT("ioctl %10u\n", atomic_read(&dev->total_ioctl));
459 DRM_PROC_PRINT("irq %10u\n", atomic_read(&dev->total_irq));
460 DRM_PROC_PRINT("ctx %10u\n", atomic_read(&dev->total_ctx));
462 DRM_PROC_PRINT("\nlock statistics:\n");
463 DRM_PROC_PRINT("locks %10u\n", atomic_read(&dev->total_locks));
464 DRM_PROC_PRINT("unlocks %10u\n", atomic_read(&dev->total_unlocks));
465 DRM_PROC_PRINT("contends %10u\n", atomic_read(&dev->total_contends));
466 DRM_PROC_PRINT("sleeps %10u\n", atomic_read(&dev->total_sleeps));
469 if (dma) {
470 DRM_PROC_PRINT("\ndma statistics:\n");
471 DRM_PROC_PRINT("prio %10u\n",
472 atomic_read(&dma->total_prio));
473 DRM_PROC_PRINT("bytes %10u\n",
474 atomic_read(&dma->total_bytes));
475 DRM_PROC_PRINT("dmas %10u\n",
476 atomic_read(&dma->total_dmas));
477 DRM_PROC_PRINT("missed:\n");
478 DRM_PROC_PRINT(" dma %10u\n",
479 atomic_read(&dma->total_missed_dma));
480 DRM_PROC_PRINT(" lock %10u\n",
481 atomic_read(&dma->total_missed_lock));
482 DRM_PROC_PRINT(" free %10u\n",
483 atomic_read(&dma->total_missed_free));
484 DRM_PROC_PRINT(" sched %10u\n",
485 atomic_read(&dma->total_missed_sched));
486 DRM_PROC_PRINT("tried %10u\n",
487 atomic_read(&dma->total_tried));
488 DRM_PROC_PRINT("hit %10u\n",
489 atomic_read(&dma->total_hit));
490 DRM_PROC_PRINT("lost %10u\n",
491 atomic_read(&dma->total_lost));
493 buffer = dma->next_buffer;
494 if (buffer) {
495 DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx);
496 } else {
497 DRM_PROC_PRINT("next_buffer none\n");
499 buffer = dma->this_buffer;
500 if (buffer) {
501 DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx);
502 } else {
503 DRM_PROC_PRINT("this_buffer none\n");
508 DRM_PROC_PRINT("\nvalues:\n");
509 if (dev->lock.hw_lock) {
510 DRM_PROC_PRINT("lock 0x%08x\n",
511 dev->lock.hw_lock->lock);
512 } else {
513 DRM_PROC_PRINT("lock none\n");
515 DRM_PROC_PRINT("context_flag 0x%08x\n", dev->context_flag);
516 DRM_PROC_PRINT("interrupt_flag 0x%08x\n", dev->interrupt_flag);
517 DRM_PROC_PRINT("dma_flag 0x%08x\n", dev->dma_flag);
519 DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count);
520 DRM_PROC_PRINT("last_context %10d\n", dev->last_context);
521 DRM_PROC_PRINT("last_switch %10lu\n", dev->last_switch);
522 DRM_PROC_PRINT("last_checked %10d\n", dev->last_checked);
525 DRM_PROC_PRINT("\n q2d d2c c2f"
526 " q2c q2f dma sch"
527 " ctx lacq lhld\n\n");
528 for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) {
529 DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u"
530 " %10u %10u %10u %10u %10u\n",
531 i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ",
532 i == DRM_DMA_HISTOGRAM_SLOTS - 1
533 ? prev_value : slot_value ,
535 atomic_read(&dev->histo
536 .queued_to_dispatched[i]),
537 atomic_read(&dev->histo
538 .dispatched_to_completed[i]),
539 atomic_read(&dev->histo
540 .completed_to_freed[i]),
542 atomic_read(&dev->histo
543 .queued_to_completed[i]),
544 atomic_read(&dev->histo
545 .queued_to_freed[i]),
546 atomic_read(&dev->histo.dma[i]),
547 atomic_read(&dev->histo.schedule[i]),
548 atomic_read(&dev->histo.ctx[i]),
549 atomic_read(&dev->histo.lacq[i]),
550 atomic_read(&dev->histo.lhld[i]));
551 prev_value = slot_value;
552 slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value);
554 return len;
557 static int drm_histo_info(char *buf, char **start, off_t offset, int len,
558 int *eof, void *data)
560 drm_device_t *dev = (drm_device_t *)data;
561 int ret;
563 down(&dev->struct_sem);
564 ret = _drm_histo_info(buf, start, offset, len, eof, data);
565 up(&dev->struct_sem);
566 return ret;
568 #endif