drm_proc.c revision 7c1c2871a6a3a114853ec6836e9035ac1c0c7f7a
1/** 2 * \file drm_proc.c 3 * /proc support for DRM 4 * 5 * \author Rickard E. (Rik) Faith <faith@valinux.com> 6 * \author Gareth Hughes <gareth@valinux.com> 7 * 8 * \par Acknowledgements: 9 * Matthew J Sottek <matthew.j.sottek@intel.com> sent in a patch to fix 10 * the problem with the proc files not outputting all their information. 11 */ 12 13/* 14 * Created: Mon Jan 11 09:48:47 1999 by faith@valinux.com 15 * 16 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 17 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 18 * All Rights Reserved. 19 * 20 * Permission is hereby granted, free of charge, to any person obtaining a 21 * copy of this software and associated documentation files (the "Software"), 22 * to deal in the Software without restriction, including without limitation 23 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 24 * and/or sell copies of the Software, and to permit persons to whom the 25 * Software is furnished to do so, subject to the following conditions: 26 * 27 * The above copyright notice and this permission notice (including the next 28 * paragraph) shall be included in all copies or substantial portions of the 29 * Software. 30 * 31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 34 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 35 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 36 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 37 * OTHER DEALINGS IN THE SOFTWARE. 38 */ 39 40#include "drmP.h" 41 42static int drm_name_info(char *buf, char **start, off_t offset, 43 int request, int *eof, void *data); 44static int drm_vm_info(char *buf, char **start, off_t offset, 45 int request, int *eof, void *data); 46static int drm_clients_info(char *buf, char **start, off_t offset, 47 int request, int *eof, void *data); 48static int drm_queues_info(char *buf, char **start, off_t offset, 49 int request, int *eof, void *data); 50static int drm_bufs_info(char *buf, char **start, off_t offset, 51 int request, int *eof, void *data); 52static int drm_gem_name_info(char *buf, char **start, off_t offset, 53 int request, int *eof, void *data); 54static int drm_gem_object_info(char *buf, char **start, off_t offset, 55 int request, int *eof, void *data); 56#if DRM_DEBUG_CODE 57static int drm_vma_info(char *buf, char **start, off_t offset, 58 int request, int *eof, void *data); 59#endif 60 61/** 62 * Proc file list. 63 */ 64static struct drm_proc_list { 65 const char *name; /**< file name */ 66 int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/ 67 u32 driver_features; /**< Required driver features for this entry */ 68} drm_proc_list[] = { 69 {"name", drm_name_info, 0}, 70 {"mem", drm_mem_info, 0}, 71 {"vm", drm_vm_info, 0}, 72 {"clients", drm_clients_info, 0}, 73 {"queues", drm_queues_info, 0}, 74 {"bufs", drm_bufs_info, 0}, 75 {"gem_names", drm_gem_name_info, DRIVER_GEM}, 76 {"gem_objects", drm_gem_object_info, DRIVER_GEM}, 77#if DRM_DEBUG_CODE 78 {"vma", drm_vma_info}, 79#endif 80}; 81 82#define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list) 83 84/** 85 * Initialize the DRI proc filesystem for a device. 86 * 87 * \param dev DRM device. 88 * \param minor device minor number. 89 * \param root DRI proc dir entry. 90 * \param dev_root resulting DRI device proc dir entry. 91 * \return root entry pointer on success, or NULL on failure. 92 * 93 * Create the DRI proc root entry "/proc/dri", the device proc root entry 94 * "/proc/dri/%minor%/", and each entry in proc_list as 95 * "/proc/dri/%minor%/%name%". 96 */ 97int drm_proc_init(struct drm_minor *minor, int minor_id, 98 struct proc_dir_entry *root) 99{ 100 struct drm_device *dev = minor->dev; 101 struct proc_dir_entry *ent; 102 int i, j, ret; 103 char name[64]; 104 105 sprintf(name, "%d", minor_id); 106 minor->dev_root = proc_mkdir(name, root); 107 if (!minor->dev_root) { 108 DRM_ERROR("Cannot create /proc/dri/%s\n", name); 109 return -1; 110 } 111 112 for (i = 0; i < DRM_PROC_ENTRIES; i++) { 113 u32 features = drm_proc_list[i].driver_features; 114 115 if (features != 0 && 116 (dev->driver->driver_features & features) != features) 117 continue; 118 119 ent = create_proc_entry(drm_proc_list[i].name, 120 S_IFREG | S_IRUGO, minor->dev_root); 121 if (!ent) { 122 DRM_ERROR("Cannot create /proc/dri/%s/%s\n", 123 name, drm_proc_list[i].name); 124 ret = -1; 125 goto fail; 126 } 127 ent->read_proc = drm_proc_list[i].f; 128 ent->data = minor; 129 } 130 131 if (dev->driver->proc_init) { 132 ret = dev->driver->proc_init(minor); 133 if (ret) { 134 DRM_ERROR("DRM: Driver failed to initialize " 135 "/proc/dri.\n"); 136 goto fail; 137 } 138 } 139 140 return 0; 141 fail: 142 143 for (j = 0; j < i; j++) 144 remove_proc_entry(drm_proc_list[i].name, 145 minor->dev_root); 146 remove_proc_entry(name, root); 147 minor->dev_root = NULL; 148 return ret; 149} 150 151/** 152 * Cleanup the proc filesystem resources. 153 * 154 * \param minor device minor number. 155 * \param root DRI proc dir entry. 156 * \param dev_root DRI device proc dir entry. 157 * \return always zero. 158 * 159 * Remove all proc entries created by proc_init(). 160 */ 161int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) 162{ 163 struct drm_device *dev = minor->dev; 164 int i; 165 char name[64]; 166 167 if (!root || !minor->dev_root) 168 return 0; 169 170 if (dev->driver->proc_cleanup) 171 dev->driver->proc_cleanup(minor); 172 173 for (i = 0; i < DRM_PROC_ENTRIES; i++) 174 remove_proc_entry(drm_proc_list[i].name, minor->dev_root); 175 sprintf(name, "%d", minor->index); 176 remove_proc_entry(name, root); 177 178 return 0; 179} 180 181/** 182 * Called when "/proc/dri/.../name" is read. 183 * 184 * \param buf output buffer. 185 * \param start start of output data. 186 * \param offset requested start offset. 187 * \param request requested number of bytes. 188 * \param eof whether there is no more data to return. 189 * \param data private data. 190 * \return number of written bytes. 191 * 192 * Prints the device name together with the bus id if available. 193 */ 194static int drm_name_info(char *buf, char **start, off_t offset, int request, 195 int *eof, void *data) 196{ 197 struct drm_minor *minor = (struct drm_minor *) data; 198 struct drm_master *master = minor->master; 199 struct drm_device *dev = minor->dev; 200 int len = 0; 201 202 if (offset > DRM_PROC_LIMIT) { 203 *eof = 1; 204 return 0; 205 } 206 207 if (!master) 208 return 0; 209 210 *start = &buf[offset]; 211 *eof = 0; 212 213 if (master->unique) { 214 DRM_PROC_PRINT("%s %s %s\n", 215 dev->driver->pci_driver.name, 216 pci_name(dev->pdev), master->unique); 217 } else { 218 DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, 219 pci_name(dev->pdev)); 220 } 221 222 if (len > request + offset) 223 return request; 224 *eof = 1; 225 return len - offset; 226} 227 228/** 229 * Called when "/proc/dri/.../vm" is read. 230 * 231 * \param buf output buffer. 232 * \param start start of output data. 233 * \param offset requested start offset. 234 * \param request requested number of bytes. 235 * \param eof whether there is no more data to return. 236 * \param data private data. 237 * \return number of written bytes. 238 * 239 * Prints information about all mappings in drm_device::maplist. 240 */ 241static int drm__vm_info(char *buf, char **start, off_t offset, int request, 242 int *eof, void *data) 243{ 244 struct drm_minor *minor = (struct drm_minor *) data; 245 struct drm_device *dev = minor->dev; 246 int len = 0; 247 struct drm_map *map; 248 struct drm_map_list *r_list; 249 250 /* Hardcoded from _DRM_FRAME_BUFFER, 251 _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and 252 _DRM_SCATTER_GATHER and _DRM_CONSISTENT */ 253 const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" }; 254 const char *type; 255 int i; 256 257 if (offset > DRM_PROC_LIMIT) { 258 *eof = 1; 259 return 0; 260 } 261 262 *start = &buf[offset]; 263 *eof = 0; 264 265 DRM_PROC_PRINT("slot offset size type flags " 266 "address mtrr\n\n"); 267 i = 0; 268 list_for_each_entry(r_list, &dev->maplist, head) { 269 map = r_list->map; 270 if (!map) 271 continue; 272 if (map->type < 0 || map->type > 5) 273 type = "??"; 274 else 275 type = types[map->type]; 276 DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", 277 i, 278 map->offset, 279 map->size, type, map->flags, 280 (unsigned long) r_list->user_token); 281 if (map->mtrr < 0) { 282 DRM_PROC_PRINT("none\n"); 283 } else { 284 DRM_PROC_PRINT("%4d\n", map->mtrr); 285 } 286 i++; 287 } 288 289 if (len > request + offset) 290 return request; 291 *eof = 1; 292 return len - offset; 293} 294 295/** 296 * Simply calls _vm_info() while holding the drm_device::struct_mutex lock. 297 */ 298static int drm_vm_info(char *buf, char **start, off_t offset, int request, 299 int *eof, void *data) 300{ 301 struct drm_minor *minor = (struct drm_minor *) data; 302 struct drm_device *dev = minor->dev; 303 int ret; 304 305 mutex_lock(&dev->struct_mutex); 306 ret = drm__vm_info(buf, start, offset, request, eof, data); 307 mutex_unlock(&dev->struct_mutex); 308 return ret; 309} 310 311/** 312 * Called when "/proc/dri/.../queues" is read. 313 * 314 * \param buf output buffer. 315 * \param start start of output data. 316 * \param offset requested start offset. 317 * \param request requested number of bytes. 318 * \param eof whether there is no more data to return. 319 * \param data private data. 320 * \return number of written bytes. 321 */ 322static int drm__queues_info(char *buf, char **start, off_t offset, 323 int request, int *eof, void *data) 324{ 325 struct drm_minor *minor = (struct drm_minor *) data; 326 struct drm_device *dev = minor->dev; 327 int len = 0; 328 int i; 329 struct drm_queue *q; 330 331 if (offset > DRM_PROC_LIMIT) { 332 *eof = 1; 333 return 0; 334 } 335 336 *start = &buf[offset]; 337 *eof = 0; 338 339 DRM_PROC_PRINT(" ctx/flags use fin" 340 " blk/rw/rwf wait flushed queued" 341 " locks\n\n"); 342 for (i = 0; i < dev->queue_count; i++) { 343 q = dev->queuelist[i]; 344 atomic_inc(&q->use_count); 345 DRM_PROC_PRINT_RET(atomic_dec(&q->use_count), 346 "%5d/0x%03x %5d %5d" 347 " %5d/%c%c/%c%c%c %5Zd\n", 348 i, 349 q->flags, 350 atomic_read(&q->use_count), 351 atomic_read(&q->finalization), 352 atomic_read(&q->block_count), 353 atomic_read(&q->block_read) ? 'r' : '-', 354 atomic_read(&q->block_write) ? 'w' : '-', 355 waitqueue_active(&q->read_queue) ? 'r' : '-', 356 waitqueue_active(&q-> 357 write_queue) ? 'w' : '-', 358 waitqueue_active(&q-> 359 flush_queue) ? 'f' : '-', 360 DRM_BUFCOUNT(&q->waitlist)); 361 atomic_dec(&q->use_count); 362 } 363 364 if (len > request + offset) 365 return request; 366 *eof = 1; 367 return len - offset; 368} 369 370/** 371 * Simply calls _queues_info() while holding the drm_device::struct_mutex lock. 372 */ 373static int drm_queues_info(char *buf, char **start, off_t offset, int request, 374 int *eof, void *data) 375{ 376 struct drm_minor *minor = (struct drm_minor *) data; 377 struct drm_device *dev = minor->dev; 378 int ret; 379 380 mutex_lock(&dev->struct_mutex); 381 ret = drm__queues_info(buf, start, offset, request, eof, data); 382 mutex_unlock(&dev->struct_mutex); 383 return ret; 384} 385 386/** 387 * Called when "/proc/dri/.../bufs" is read. 388 * 389 * \param buf output buffer. 390 * \param start start of output data. 391 * \param offset requested start offset. 392 * \param request requested number of bytes. 393 * \param eof whether there is no more data to return. 394 * \param data private data. 395 * \return number of written bytes. 396 */ 397static int drm__bufs_info(char *buf, char **start, off_t offset, int request, 398 int *eof, void *data) 399{ 400 struct drm_minor *minor = (struct drm_minor *) data; 401 struct drm_device *dev = minor->dev; 402 int len = 0; 403 struct drm_device_dma *dma = dev->dma; 404 int i; 405 406 if (!dma || offset > DRM_PROC_LIMIT) { 407 *eof = 1; 408 return 0; 409 } 410 411 *start = &buf[offset]; 412 *eof = 0; 413 414 DRM_PROC_PRINT(" o size count free segs pages kB\n\n"); 415 for (i = 0; i <= DRM_MAX_ORDER; i++) { 416 if (dma->bufs[i].buf_count) 417 DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n", 418 i, 419 dma->bufs[i].buf_size, 420 dma->bufs[i].buf_count, 421 atomic_read(&dma->bufs[i] 422 .freelist.count), 423 dma->bufs[i].seg_count, 424 dma->bufs[i].seg_count 425 * (1 << dma->bufs[i].page_order), 426 (dma->bufs[i].seg_count 427 * (1 << dma->bufs[i].page_order)) 428 * PAGE_SIZE / 1024); 429 } 430 DRM_PROC_PRINT("\n"); 431 for (i = 0; i < dma->buf_count; i++) { 432 if (i && !(i % 32)) 433 DRM_PROC_PRINT("\n"); 434 DRM_PROC_PRINT(" %d", dma->buflist[i]->list); 435 } 436 DRM_PROC_PRINT("\n"); 437 438 if (len > request + offset) 439 return request; 440 *eof = 1; 441 return len - offset; 442} 443 444/** 445 * Simply calls _bufs_info() while holding the drm_device::struct_mutex lock. 446 */ 447static int drm_bufs_info(char *buf, char **start, off_t offset, int request, 448 int *eof, void *data) 449{ 450 struct drm_minor *minor = (struct drm_minor *) data; 451 struct drm_device *dev = minor->dev; 452 int ret; 453 454 mutex_lock(&dev->struct_mutex); 455 ret = drm__bufs_info(buf, start, offset, request, eof, data); 456 mutex_unlock(&dev->struct_mutex); 457 return ret; 458} 459 460/** 461 * Called when "/proc/dri/.../clients" is read. 462 * 463 * \param buf output buffer. 464 * \param start start of output data. 465 * \param offset requested start offset. 466 * \param request requested number of bytes. 467 * \param eof whether there is no more data to return. 468 * \param data private data. 469 * \return number of written bytes. 470 */ 471static int drm__clients_info(char *buf, char **start, off_t offset, 472 int request, int *eof, void *data) 473{ 474 struct drm_minor *minor = (struct drm_minor *) data; 475 struct drm_device *dev = minor->dev; 476 int len = 0; 477 struct drm_file *priv; 478 479 if (offset > DRM_PROC_LIMIT) { 480 *eof = 1; 481 return 0; 482 } 483 484 *start = &buf[offset]; 485 *eof = 0; 486 487 DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n"); 488 list_for_each_entry(priv, &dev->filelist, lhead) { 489 DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", 490 priv->authenticated ? 'y' : 'n', 491 priv->minor->index, 492 priv->pid, 493 priv->uid, priv->magic, priv->ioctl_count); 494 } 495 496 if (len > request + offset) 497 return request; 498 *eof = 1; 499 return len - offset; 500} 501 502/** 503 * Simply calls _clients_info() while holding the drm_device::struct_mutex lock. 504 */ 505static int drm_clients_info(char *buf, char **start, off_t offset, 506 int request, int *eof, void *data) 507{ 508 struct drm_minor *minor = (struct drm_minor *) data; 509 struct drm_device *dev = minor->dev; 510 int ret; 511 512 mutex_lock(&dev->struct_mutex); 513 ret = drm__clients_info(buf, start, offset, request, eof, data); 514 mutex_unlock(&dev->struct_mutex); 515 return ret; 516} 517 518struct drm_gem_name_info_data { 519 int len; 520 char *buf; 521 int eof; 522}; 523 524static int drm_gem_one_name_info(int id, void *ptr, void *data) 525{ 526 struct drm_gem_object *obj = ptr; 527 struct drm_gem_name_info_data *nid = data; 528 529 DRM_INFO("name %d size %zd\n", obj->name, obj->size); 530 if (nid->eof) 531 return 0; 532 533 nid->len += sprintf(&nid->buf[nid->len], 534 "%6d %8zd %7d %8d\n", 535 obj->name, obj->size, 536 atomic_read(&obj->handlecount.refcount), 537 atomic_read(&obj->refcount.refcount)); 538 if (nid->len > DRM_PROC_LIMIT) { 539 nid->eof = 1; 540 return 0; 541 } 542 return 0; 543} 544 545static int drm_gem_name_info(char *buf, char **start, off_t offset, 546 int request, int *eof, void *data) 547{ 548 struct drm_minor *minor = (struct drm_minor *) data; 549 struct drm_device *dev = minor->dev; 550 struct drm_gem_name_info_data nid; 551 552 if (offset > DRM_PROC_LIMIT) { 553 *eof = 1; 554 return 0; 555 } 556 557 nid.len = sprintf(buf, " name size handles refcount\n"); 558 nid.buf = buf; 559 nid.eof = 0; 560 idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, &nid); 561 562 *start = &buf[offset]; 563 *eof = 0; 564 if (nid.len > request + offset) 565 return request; 566 *eof = 1; 567 return nid.len - offset; 568} 569 570static int drm_gem_object_info(char *buf, char **start, off_t offset, 571 int request, int *eof, void *data) 572{ 573 struct drm_minor *minor = (struct drm_minor *) data; 574 struct drm_device *dev = minor->dev; 575 int len = 0; 576 577 if (offset > DRM_PROC_LIMIT) { 578 *eof = 1; 579 return 0; 580 } 581 582 *start = &buf[offset]; 583 *eof = 0; 584 DRM_PROC_PRINT("%d objects\n", atomic_read(&dev->object_count)); 585 DRM_PROC_PRINT("%d object bytes\n", atomic_read(&dev->object_memory)); 586 DRM_PROC_PRINT("%d pinned\n", atomic_read(&dev->pin_count)); 587 DRM_PROC_PRINT("%d pin bytes\n", atomic_read(&dev->pin_memory)); 588 DRM_PROC_PRINT("%d gtt bytes\n", atomic_read(&dev->gtt_memory)); 589 DRM_PROC_PRINT("%d gtt total\n", dev->gtt_total); 590 if (len > request + offset) 591 return request; 592 *eof = 1; 593 return len - offset; 594} 595 596#if DRM_DEBUG_CODE 597 598static int drm__vma_info(char *buf, char **start, off_t offset, int request, 599 int *eof, void *data) 600{ 601 struct drm_minor *minor = (struct drm_minor *) data; 602 struct drm_device *dev = minor->dev; 603 int len = 0; 604 struct drm_vma_entry *pt; 605 struct vm_area_struct *vma; 606#if defined(__i386__) 607 unsigned int pgprot; 608#endif 609 610 if (offset > DRM_PROC_LIMIT) { 611 *eof = 1; 612 return 0; 613 } 614 615 *start = &buf[offset]; 616 *eof = 0; 617 618 DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n", 619 atomic_read(&dev->vma_count), 620 high_memory, virt_to_phys(high_memory)); 621 list_for_each_entry(pt, &dev->vmalist, head) { 622 if (!(vma = pt->vma)) 623 continue; 624 DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000", 625 pt->pid, 626 vma->vm_start, 627 vma->vm_end, 628 vma->vm_flags & VM_READ ? 'r' : '-', 629 vma->vm_flags & VM_WRITE ? 'w' : '-', 630 vma->vm_flags & VM_EXEC ? 'x' : '-', 631 vma->vm_flags & VM_MAYSHARE ? 's' : 'p', 632 vma->vm_flags & VM_LOCKED ? 'l' : '-', 633 vma->vm_flags & VM_IO ? 'i' : '-', 634 vma->vm_pgoff); 635 636#if defined(__i386__) 637 pgprot = pgprot_val(vma->vm_page_prot); 638 DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c", 639 pgprot & _PAGE_PRESENT ? 'p' : '-', 640 pgprot & _PAGE_RW ? 'w' : 'r', 641 pgprot & _PAGE_USER ? 'u' : 's', 642 pgprot & _PAGE_PWT ? 't' : 'b', 643 pgprot & _PAGE_PCD ? 'u' : 'c', 644 pgprot & _PAGE_ACCESSED ? 'a' : '-', 645 pgprot & _PAGE_DIRTY ? 'd' : '-', 646 pgprot & _PAGE_PSE ? 'm' : 'k', 647 pgprot & _PAGE_GLOBAL ? 'g' : 'l'); 648#endif 649 DRM_PROC_PRINT("\n"); 650 } 651 652 if (len > request + offset) 653 return request; 654 *eof = 1; 655 return len - offset; 656} 657 658static int drm_vma_info(char *buf, char **start, off_t offset, int request, 659 int *eof, void *data) 660{ 661 struct drm_minor *minor = (struct drm_minor *) data; 662 struct drm_device *dev = minor->dev; 663 int ret; 664 665 mutex_lock(&dev->struct_mutex); 666 ret = drm__vma_info(buf, start, offset, request, eof, data); 667 mutex_unlock(&dev->struct_mutex); 668 return ret; 669} 670#endif 671