1 /* proc.c -- /proc support for DRM -*- linux-c -*-
2 * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
3 *
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
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 * Authors:
28 * Rickard E. (Rik) Faith <faith@valinux.com>
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
drm_proc_init(drm_device_t * dev)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 break;
96 }
97 if (drm_dev_root->nlink == 2) break;
98 drm_dev_root = NULL;
99 }
100 if (!drm_dev_root) {
101 DRM_ERROR("Cannot find slot in /proc/dri\n");
102 return -1;
103 }
104
105 for (i = 0; i < DRM_PROC_ENTRIES; i++) {
106 ent = create_proc_entry(drm_proc_list[i].name,
107 S_IFREG|S_IRUGO, drm_dev_root);
108 if (!ent) {
109 DRM_ERROR("Cannot create /proc/%s/%s\n",
110 drm_slot_name, drm_proc_list[i].name);
111 for (j = 0; j < i; j++)
112 remove_proc_entry(drm_proc_list[i].name,
113 drm_dev_root);
114 remove_proc_entry(drm_slot_name, NULL);
115 remove_proc_entry("dri", NULL);
116 return -1;
117 }
118 ent->read_proc = drm_proc_list[i].f;
119 ent->data = dev;
120 }
121
122 return 0;
123 }
124
125
drm_proc_cleanup(void)126 int drm_proc_cleanup(void)
127 {
128 int i;
129
130 if (drm_root) {
131 if (drm_dev_root) {
132 for (i = 0; i < DRM_PROC_ENTRIES; i++) {
133 remove_proc_entry(drm_proc_list[i].name,
134 drm_dev_root);
135 }
136 remove_proc_entry(drm_slot_name, NULL);
137 }
138 remove_proc_entry("dri", NULL);
139 remove_proc_entry(DRM_NAME, NULL);
140 }
141 drm_root = drm_dev_root = NULL;
142 return 0;
143 }
144
drm_name_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)145 static int drm_name_info(char *buf, char **start, off_t offset, int len,
146 int *eof, void *data)
147 {
148 drm_device_t *dev = (drm_device_t *)data;
149
150 if (offset > 0) return 0; /* no partial requests */
151 len = 0;
152 *eof = 1;
153
154 if (dev->unique) {
155 DRM_PROC_PRINT("%s 0x%x %s\n",
156 dev->name, dev->device, dev->unique);
157 } else {
158 DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device);
159 }
160 return len;
161 }
162
_drm_vm_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)163 static int _drm_vm_info(char *buf, char **start, off_t offset, int len,
164 int *eof, void *data)
165 {
166 drm_device_t *dev = (drm_device_t *)data;
167 drm_map_t *map;
168 /* Hardcoded from _DRM_FRAME_BUFFER,
169 _DRM_REGISTERS, _DRM_SHM, and
170 _DRM_AGP. */
171 const char *types[] = { "FB", "REG", "SHM", "AGP" };
172 const char *type;
173 int i;
174
175 if (offset > 0) return 0; /* no partial requests */
176 len = 0;
177 *eof = 1;
178 DRM_PROC_PRINT("slot offset size type flags "
179 "address mtrr\n\n");
180 for (i = 0; i < dev->map_count; i++) {
181 map = dev->maplist[i];
182 if (map->type < 0 || map->type > 3) type = "??";
183 else type = types[map->type];
184 DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ",
185 i,
186 map->offset,
187 map->size,
188 type,
189 map->flags,
190 (unsigned long)map->handle);
191 if (map->mtrr < 0) {
192 DRM_PROC_PRINT("none\n");
193 } else {
194 DRM_PROC_PRINT("%4d\n", map->mtrr);
195 }
196 }
197
198 return len;
199 }
200
drm_vm_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)201 static int drm_vm_info(char *buf, char **start, off_t offset, int len,
202 int *eof, void *data)
203 {
204 drm_device_t *dev = (drm_device_t *)data;
205 int ret;
206
207 down(&dev->struct_sem);
208 ret = _drm_vm_info(buf, start, offset, len, eof, data);
209 up(&dev->struct_sem);
210 return ret;
211 }
212
213
_drm_queues_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)214 static int _drm_queues_info(char *buf, char **start, off_t offset, int len,
215 int *eof, void *data)
216 {
217 drm_device_t *dev = (drm_device_t *)data;
218 int i;
219 drm_queue_t *q;
220
221 if (offset > 0) return 0; /* no partial requests */
222 len = 0;
223 *eof = 1;
224 DRM_PROC_PRINT(" ctx/flags use fin"
225 " blk/rw/rwf wait flushed queued"
226 " locks\n\n");
227 for (i = 0; i < dev->queue_count; i++) {
228 q = dev->queuelist[i];
229 atomic_inc(&q->use_count);
230 DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
231 "%5d/0x%03x %5d %5d"
232 " %5d/%c%c/%c%c%c %5Zd %10d %10d %10d\n",
233 i,
234 q->flags,
235 atomic_read(&q->use_count),
236 atomic_read(&q->finalization),
237 atomic_read(&q->block_count),
238 atomic_read(&q->block_read) ? 'r' : '-',
239 atomic_read(&q->block_write) ? 'w' : '-',
240 waitqueue_active(&q->read_queue) ? 'r':'-',
241 waitqueue_active(&q->write_queue) ? 'w':'-',
242 waitqueue_active(&q->flush_queue) ? 'f':'-',
243 DRM_BUFCOUNT(&q->waitlist),
244 atomic_read(&q->total_flushed),
245 atomic_read(&q->total_queued),
246 atomic_read(&q->total_locks));
247 atomic_dec(&q->use_count);
248 }
249
250 return len;
251 }
252
drm_queues_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)253 static int drm_queues_info(char *buf, char **start, off_t offset, int len,
254 int *eof, void *data)
255 {
256 drm_device_t *dev = (drm_device_t *)data;
257 int ret;
258
259 down(&dev->struct_sem);
260 ret = _drm_queues_info(buf, start, offset, len, eof, data);
261 up(&dev->struct_sem);
262 return ret;
263 }
264
265 /* drm_bufs_info is called whenever a process reads
266 /dev/drm/<dev>/bufs. */
267
_drm_bufs_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)268 static int _drm_bufs_info(char *buf, char **start, off_t offset, int len,
269 int *eof, void *data)
270 {
271 drm_device_t *dev = (drm_device_t *)data;
272 drm_device_dma_t *dma = dev->dma;
273 int i;
274
275 if (!dma) return 0;
276 if (offset > 0) return 0; /* no partial requests */
277 len = 0;
278 *eof = 1;
279 DRM_PROC_PRINT(" o size count free segs pages kB\n\n");
280 for (i = 0; i <= DRM_MAX_ORDER; i++) {
281 if (dma->bufs[i].buf_count)
282 DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
283 i,
284 dma->bufs[i].buf_size,
285 dma->bufs[i].buf_count,
286 atomic_read(&dma->bufs[i]
287 .freelist.count),
288 dma->bufs[i].seg_count,
289 dma->bufs[i].seg_count
290 *(1 << dma->bufs[i].page_order),
291 (dma->bufs[i].seg_count
292 * (1 << dma->bufs[i].page_order))
293 * PAGE_SIZE / 1024);
294 }
295 DRM_PROC_PRINT("\n");
296 for (i = 0; i < dma->buf_count; i++) {
297 if (i && !(i%32)) DRM_PROC_PRINT("\n");
298 DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
299 }
300 DRM_PROC_PRINT("\n");
301
302 return len;
303 }
304
drm_bufs_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)305 static int drm_bufs_info(char *buf, char **start, off_t offset, int len,
306 int *eof, void *data)
307 {
308 drm_device_t *dev = (drm_device_t *)data;
309 int ret;
310
311 down(&dev->struct_sem);
312 ret = _drm_bufs_info(buf, start, offset, len, eof, data);
313 up(&dev->struct_sem);
314 return ret;
315 }
316
317
_drm_clients_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)318 static int _drm_clients_info(char *buf, char **start, off_t offset, int len,
319 int *eof, void *data)
320 {
321 drm_device_t *dev = (drm_device_t *)data;
322 drm_file_t *priv;
323
324 if (offset > 0) return 0; /* no partial requests */
325 len = 0;
326 *eof = 1;
327 DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n");
328 for (priv = dev->file_first; priv; priv = priv->next) {
329 DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
330 priv->authenticated ? 'y' : 'n',
331 priv->minor,
332 priv->pid,
333 priv->uid,
334 priv->magic,
335 priv->ioctl_count);
336 }
337
338 return len;
339 }
340
drm_clients_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)341 static int drm_clients_info(char *buf, char **start, off_t offset, int len,
342 int *eof, void *data)
343 {
344 drm_device_t *dev = (drm_device_t *)data;
345 int ret;
346
347 down(&dev->struct_sem);
348 ret = _drm_clients_info(buf, start, offset, len, eof, data);
349 up(&dev->struct_sem);
350 return ret;
351 }
352
353 #if DRM_DEBUG_CODE
354
355 #define DRM_VMA_VERBOSE 0
356
_drm_vma_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)357 static int _drm_vma_info(char *buf, char **start, off_t offset, int len,
358 int *eof, void *data)
359 {
360 drm_device_t *dev = (drm_device_t *)data;
361 drm_vma_entry_t *pt;
362 struct vm_area_struct *vma;
363 #if DRM_VMA_VERBOSE
364 unsigned long i;
365 unsigned long address;
366 pgd_t *pgd;
367 pmd_t *pmd;
368 pte_t *pte;
369 #endif
370 #if defined(__i386__)
371 unsigned int pgprot;
372 #endif
373
374 if (offset > 0) return 0; /* no partial requests */
375 len = 0;
376 *eof = 1;
377 DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
378 atomic_read(&dev->vma_count),
379 high_memory, virt_to_phys(high_memory));
380 for (pt = dev->vmalist; pt; pt = pt->next) {
381 if (!(vma = pt->vma)) continue;
382 DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
383 pt->pid,
384 vma->vm_start,
385 vma->vm_end,
386 vma->vm_flags & VM_READ ? 'r' : '-',
387 vma->vm_flags & VM_WRITE ? 'w' : '-',
388 vma->vm_flags & VM_EXEC ? 'x' : '-',
389 vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
390 vma->vm_flags & VM_LOCKED ? 'l' : '-',
391 vma->vm_flags & VM_IO ? 'i' : '-',
392 VM_OFFSET(vma));
393
394 #if defined(__i386__)
395 pgprot = pgprot_val(vma->vm_page_prot);
396 DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
397 pgprot & _PAGE_PRESENT ? 'p' : '-',
398 pgprot & _PAGE_RW ? 'w' : 'r',
399 pgprot & _PAGE_USER ? 'u' : 's',
400 pgprot & _PAGE_PWT ? 't' : 'b',
401 pgprot & _PAGE_PCD ? 'u' : 'c',
402 pgprot & _PAGE_ACCESSED ? 'a' : '-',
403 pgprot & _PAGE_DIRTY ? 'd' : '-',
404 pgprot & _PAGE_PSE ? 'm' : 'k',
405 pgprot & _PAGE_GLOBAL ? 'g' : 'l' );
406 #endif
407 DRM_PROC_PRINT("\n");
408 #if 0
409 for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
410 pgd = pgd_offset(vma->vm_mm, i);
411 pmd = pmd_offset(pgd, i);
412 pte = pte_offset(pmd, i);
413 if (pte_present(*pte)) {
414 address = __pa(pte_page(*pte))
415 + (i & (PAGE_SIZE-1));
416 DRM_PROC_PRINT(" 0x%08lx -> 0x%08lx"
417 " %c%c%c%c%c\n",
418 i,
419 address,
420 pte_read(*pte) ? 'r' : '-',
421 pte_write(*pte) ? 'w' : '-',
422 pte_exec(*pte) ? 'x' : '-',
423 pte_dirty(*pte) ? 'd' : '-',
424 pte_young(*pte) ? 'a' : '-' );
425 } else {
426 DRM_PROC_PRINT(" 0x%08lx\n", i);
427 }
428 }
429 #endif
430 }
431
432 return len;
433 }
434
drm_vma_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)435 static int drm_vma_info(char *buf, char **start, off_t offset, int len,
436 int *eof, void *data)
437 {
438 drm_device_t *dev = (drm_device_t *)data;
439 int ret;
440
441 down(&dev->struct_sem);
442 ret = _drm_vma_info(buf, start, offset, len, eof, data);
443 up(&dev->struct_sem);
444 return ret;
445 }
446 #endif
447
448
449 #if DRM_DMA_HISTOGRAM
_drm_histo_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)450 static int _drm_histo_info(char *buf, char **start, off_t offset, int len,
451 int *eof, void *data)
452 {
453 drm_device_t *dev = (drm_device_t *)data;
454 drm_device_dma_t *dma = dev->dma;
455 int i;
456 unsigned long slot_value = DRM_DMA_HISTOGRAM_INITIAL;
457 unsigned long prev_value = 0;
458 drm_buf_t *buffer;
459
460 if (offset > 0) return 0; /* no partial requests */
461 len = 0;
462 *eof = 1;
463
464 DRM_PROC_PRINT("general statistics:\n");
465 DRM_PROC_PRINT("total %10u\n", atomic_read(&dev->histo.total));
466 DRM_PROC_PRINT("open %10u\n", atomic_read(&dev->total_open));
467 DRM_PROC_PRINT("close %10u\n", atomic_read(&dev->total_close));
468 DRM_PROC_PRINT("ioctl %10u\n", atomic_read(&dev->total_ioctl));
469 DRM_PROC_PRINT("irq %10u\n", atomic_read(&dev->total_irq));
470 DRM_PROC_PRINT("ctx %10u\n", atomic_read(&dev->total_ctx));
471
472 DRM_PROC_PRINT("\nlock statistics:\n");
473 DRM_PROC_PRINT("locks %10u\n", atomic_read(&dev->total_locks));
474 DRM_PROC_PRINT("unlocks %10u\n", atomic_read(&dev->total_unlocks));
475 DRM_PROC_PRINT("contends %10u\n", atomic_read(&dev->total_contends));
476 DRM_PROC_PRINT("sleeps %10u\n", atomic_read(&dev->total_sleeps));
477
478
479 if (dma) {
480 DRM_PROC_PRINT("\ndma statistics:\n");
481 DRM_PROC_PRINT("prio %10u\n",
482 atomic_read(&dma->total_prio));
483 DRM_PROC_PRINT("bytes %10u\n",
484 atomic_read(&dma->total_bytes));
485 DRM_PROC_PRINT("dmas %10u\n",
486 atomic_read(&dma->total_dmas));
487 DRM_PROC_PRINT("missed:\n");
488 DRM_PROC_PRINT(" dma %10u\n",
489 atomic_read(&dma->total_missed_dma));
490 DRM_PROC_PRINT(" lock %10u\n",
491 atomic_read(&dma->total_missed_lock));
492 DRM_PROC_PRINT(" free %10u\n",
493 atomic_read(&dma->total_missed_free));
494 DRM_PROC_PRINT(" sched %10u\n",
495 atomic_read(&dma->total_missed_sched));
496 DRM_PROC_PRINT("tried %10u\n",
497 atomic_read(&dma->total_tried));
498 DRM_PROC_PRINT("hit %10u\n",
499 atomic_read(&dma->total_hit));
500 DRM_PROC_PRINT("lost %10u\n",
501 atomic_read(&dma->total_lost));
502
503 buffer = dma->next_buffer;
504 if (buffer) {
505 DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx);
506 } else {
507 DRM_PROC_PRINT("next_buffer none\n");
508 }
509 buffer = dma->this_buffer;
510 if (buffer) {
511 DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx);
512 } else {
513 DRM_PROC_PRINT("this_buffer none\n");
514 }
515 }
516
517
518 DRM_PROC_PRINT("\nvalues:\n");
519 if (dev->lock.hw_lock) {
520 DRM_PROC_PRINT("lock 0x%08x\n",
521 dev->lock.hw_lock->lock);
522 } else {
523 DRM_PROC_PRINT("lock none\n");
524 }
525 DRM_PROC_PRINT("context_flag 0x%08lx\n", dev->context_flag);
526 DRM_PROC_PRINT("interrupt_flag 0x%08lx\n", dev->interrupt_flag);
527 DRM_PROC_PRINT("dma_flag 0x%08lx\n", dev->dma_flag);
528
529 DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count);
530 DRM_PROC_PRINT("last_context %10d\n", dev->last_context);
531 DRM_PROC_PRINT("last_switch %10lu\n", dev->last_switch);
532 DRM_PROC_PRINT("last_checked %10d\n", dev->last_checked);
533
534
535 DRM_PROC_PRINT("\n q2d d2c c2f"
536 " q2c q2f dma sch"
537 " ctx lacq lhld\n\n");
538 for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) {
539 DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u"
540 " %10u %10u %10u %10u %10u\n",
541 i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ",
542 i == DRM_DMA_HISTOGRAM_SLOTS - 1
543 ? prev_value : slot_value ,
544
545 atomic_read(&dev->histo
546 .queued_to_dispatched[i]),
547 atomic_read(&dev->histo
548 .dispatched_to_completed[i]),
549 atomic_read(&dev->histo
550 .completed_to_freed[i]),
551
552 atomic_read(&dev->histo
553 .queued_to_completed[i]),
554 atomic_read(&dev->histo
555 .queued_to_freed[i]),
556 atomic_read(&dev->histo.dma[i]),
557 atomic_read(&dev->histo.schedule[i]),
558 atomic_read(&dev->histo.ctx[i]),
559 atomic_read(&dev->histo.lacq[i]),
560 atomic_read(&dev->histo.lhld[i]));
561 prev_value = slot_value;
562 slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value);
563 }
564 return len;
565 }
566
drm_histo_info(char * buf,char ** start,off_t offset,int len,int * eof,void * data)567 static int drm_histo_info(char *buf, char **start, off_t offset, int len,
568 int *eof, void *data)
569 {
570 drm_device_t *dev = (drm_device_t *)data;
571 int ret;
572
573 down(&dev->struct_sem);
574 ret = _drm_histo_info(buf, start, offset, len, eof, data);
575 up(&dev->struct_sem);
576 return ret;
577 }
578 #endif
579