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 34static struct proc_dir_entry *drm_root = NULL; 35static struct proc_dir_entry *drm_dev_root = NULL; 36static char drm_slot_name[64]; 37 38static int drm_name_info(char *buf, char **start, off_t offset, 39 int len, int *eof, void *data); 40static int drm_vm_info(char *buf, char **start, off_t offset, 41 int len, int *eof, void *data); 42static int drm_clients_info(char *buf, char **start, off_t offset, 43 int len, int *eof, void *data); 44static int drm_queues_info(char *buf, char **start, off_t offset, 45 int len, int *eof, void *data); 46static int drm_bufs_info(char *buf, char **start, off_t offset, 47 int len, int *eof, void *data); 48#if DRM_DEBUG_CODE 49static 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 53static int drm_histo_info(char *buf, char **start, off_t offset, 54 int len, int *eof, void *data); 55#endif 56 57struct 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 76int 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 126int 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 145static 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 163static 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 201static 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 214static 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 253static 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 268static 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 305static 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 318static 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 341static 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 357static 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 } 409 410 return len; 411} 412 413static int drm_vma_info(char *buf, char **start, off_t offset, int len, 414 int *eof, void *data) 415{ 416 drm_device_t *dev = (drm_device_t *)data; 417 int ret; 418 419 down(&dev->struct_sem); 420 ret = _drm_vma_info(buf, start, offset, len, eof, data); 421 up(&dev->struct_sem); 422 return ret; 423} 424#endif 425 426 427#if DRM_DMA_HISTOGRAM 428static int _drm_histo_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 drm_device_dma_t *dma = dev->dma; 433 int i; 434 unsigned long slot_value = DRM_DMA_HISTOGRAM_INITIAL; 435 unsigned long prev_value = 0; 436 drm_buf_t *buffer; 437 438 if (offset > 0) return 0; /* no partial requests */ 439 len = 0; 440 *eof = 1; 441 442 DRM_PROC_PRINT("general statistics:\n"); 443 DRM_PROC_PRINT("total %10u\n", atomic_read(&dev->histo.total)); 444 DRM_PROC_PRINT("open %10u\n", atomic_read(&dev->total_open)); 445 DRM_PROC_PRINT("close %10u\n", atomic_read(&dev->total_close)); 446 DRM_PROC_PRINT("ioctl %10u\n", atomic_read(&dev->total_ioctl)); 447 DRM_PROC_PRINT("irq %10u\n", atomic_read(&dev->total_irq)); 448 DRM_PROC_PRINT("ctx %10u\n", atomic_read(&dev->total_ctx)); 449 450 DRM_PROC_PRINT("\nlock statistics:\n"); 451 DRM_PROC_PRINT("locks %10u\n", atomic_read(&dev->total_locks)); 452 DRM_PROC_PRINT("unlocks %10u\n", atomic_read(&dev->total_unlocks)); 453 DRM_PROC_PRINT("contends %10u\n", atomic_read(&dev->total_contends)); 454 DRM_PROC_PRINT("sleeps %10u\n", atomic_read(&dev->total_sleeps)); 455 456 457 if (dma) { 458 DRM_PROC_PRINT("\ndma statistics:\n"); 459 DRM_PROC_PRINT("prio %10u\n", 460 atomic_read(&dma->total_prio)); 461 DRM_PROC_PRINT("bytes %10u\n", 462 atomic_read(&dma->total_bytes)); 463 DRM_PROC_PRINT("dmas %10u\n", 464 atomic_read(&dma->total_dmas)); 465 DRM_PROC_PRINT("missed:\n"); 466 DRM_PROC_PRINT(" dma %10u\n", 467 atomic_read(&dma->total_missed_dma)); 468 DRM_PROC_PRINT(" lock %10u\n", 469 atomic_read(&dma->total_missed_lock)); 470 DRM_PROC_PRINT(" free %10u\n", 471 atomic_read(&dma->total_missed_free)); 472 DRM_PROC_PRINT(" sched %10u\n", 473 atomic_read(&dma->total_missed_sched)); 474 DRM_PROC_PRINT("tried %10u\n", 475 atomic_read(&dma->total_tried)); 476 DRM_PROC_PRINT("hit %10u\n", 477 atomic_read(&dma->total_hit)); 478 DRM_PROC_PRINT("lost %10u\n", 479 atomic_read(&dma->total_lost)); 480 481 buffer = dma->next_buffer; 482 if (buffer) { 483 DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx); 484 } else { 485 DRM_PROC_PRINT("next_buffer none\n"); 486 } 487 buffer = dma->this_buffer; 488 if (buffer) { 489 DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx); 490 } else { 491 DRM_PROC_PRINT("this_buffer none\n"); 492 } 493 } 494 495 496 DRM_PROC_PRINT("\nvalues:\n"); 497 if (dev->lock.hw_lock) { 498 DRM_PROC_PRINT("lock 0x%08x\n", 499 dev->lock.hw_lock->lock); 500 } else { 501 DRM_PROC_PRINT("lock none\n"); 502 } 503 DRM_PROC_PRINT("context_flag 0x%08lx\n", dev->context_flag); 504 DRM_PROC_PRINT("interrupt_flag 0x%08lx\n", dev->interrupt_flag); 505 DRM_PROC_PRINT("dma_flag 0x%08lx\n", dev->dma_flag); 506 507 DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count); 508 DRM_PROC_PRINT("last_context %10d\n", dev->last_context); 509 DRM_PROC_PRINT("last_switch %10lu\n", dev->last_switch); 510 DRM_PROC_PRINT("last_checked %10d\n", dev->last_checked); 511 512 513 DRM_PROC_PRINT("\n q2d d2c c2f" 514 " q2c q2f dma sch" 515 " ctx lacq lhld\n\n"); 516 for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) { 517 DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u" 518 " %10u %10u %10u %10u %10u\n", 519 i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ", 520 i == DRM_DMA_HISTOGRAM_SLOTS - 1 521 ? prev_value : slot_value , 522 523 atomic_read(&dev->histo 524 .queued_to_dispatched[i]), 525 atomic_read(&dev->histo 526 .dispatched_to_completed[i]), 527 atomic_read(&dev->histo 528 .completed_to_freed[i]), 529 530 atomic_read(&dev->histo 531 .queued_to_completed[i]), 532 atomic_read(&dev->histo 533 .queued_to_freed[i]), 534 atomic_read(&dev->histo.dma[i]), 535 atomic_read(&dev->histo.schedule[i]), 536 atomic_read(&dev->histo.ctx[i]), 537 atomic_read(&dev->histo.lacq[i]), 538 atomic_read(&dev->histo.lhld[i])); 539 prev_value = slot_value; 540 slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value); 541 } 542 return len; 543} 544 545static int drm_histo_info(char *buf, char **start, off_t offset, int len, 546 int *eof, void *data) 547{ 548 drm_device_t *dev = (drm_device_t *)data; 549 int ret; 550 551 down(&dev->struct_sem); 552 ret = _drm_histo_info(buf, start, offset, len, eof, data); 553 up(&dev->struct_sem); 554 return ret; 555} 556#endif 557