at v2.6.27-rc2 557 lines 15 kB view raw
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); 52#if DRM_DEBUG_CODE 53static int drm_vma_info(char *buf, char **start, off_t offset, 54 int request, int *eof, void *data); 55#endif 56 57/** 58 * Proc file list. 59 */ 60static struct drm_proc_list { 61 const char *name; /**< file name */ 62 int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/ 63} drm_proc_list[] = { 64 {"name", drm_name_info}, 65 {"mem", drm_mem_info}, 66 {"vm", drm_vm_info}, 67 {"clients", drm_clients_info}, 68 {"queues", drm_queues_info}, 69 {"bufs", drm_bufs_info}, 70#if DRM_DEBUG_CODE 71 {"vma", drm_vma_info}, 72#endif 73}; 74 75#define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list) 76 77/** 78 * Initialize the DRI proc filesystem for a device. 79 * 80 * \param dev DRM device. 81 * \param minor device minor number. 82 * \param root DRI proc dir entry. 83 * \param dev_root resulting DRI device proc dir entry. 84 * \return root entry pointer on success, or NULL on failure. 85 * 86 * Create the DRI proc root entry "/proc/dri", the device proc root entry 87 * "/proc/dri/%minor%/", and each entry in proc_list as 88 * "/proc/dri/%minor%/%name%". 89 */ 90int drm_proc_init(struct drm_minor *minor, int minor_id, 91 struct proc_dir_entry *root) 92{ 93 struct proc_dir_entry *ent; 94 int i, j; 95 char name[64]; 96 97 sprintf(name, "%d", minor_id); 98 minor->dev_root = proc_mkdir(name, root); 99 if (!minor->dev_root) { 100 DRM_ERROR("Cannot create /proc/dri/%s\n", name); 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, minor->dev_root); 107 if (!ent) { 108 DRM_ERROR("Cannot create /proc/dri/%s/%s\n", 109 name, drm_proc_list[i].name); 110 for (j = 0; j < i; j++) 111 remove_proc_entry(drm_proc_list[i].name, 112 minor->dev_root); 113 remove_proc_entry(name, root); 114 minor->dev_root = NULL; 115 return -1; 116 } 117 ent->read_proc = drm_proc_list[i].f; 118 ent->data = minor; 119 } 120 121 return 0; 122} 123 124/** 125 * Cleanup the proc filesystem resources. 126 * 127 * \param minor device minor number. 128 * \param root DRI proc dir entry. 129 * \param dev_root DRI device proc dir entry. 130 * \return always zero. 131 * 132 * Remove all proc entries created by proc_init(). 133 */ 134int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) 135{ 136 int i; 137 char name[64]; 138 139 if (!root || !minor->dev_root) 140 return 0; 141 142 for (i = 0; i < DRM_PROC_ENTRIES; i++) 143 remove_proc_entry(drm_proc_list[i].name, minor->dev_root); 144 sprintf(name, "%d", minor->index); 145 remove_proc_entry(name, root); 146 147 return 0; 148} 149 150/** 151 * Called when "/proc/dri/.../name" is read. 152 * 153 * \param buf output buffer. 154 * \param start start of output data. 155 * \param offset requested start offset. 156 * \param request requested number of bytes. 157 * \param eof whether there is no more data to return. 158 * \param data private data. 159 * \return number of written bytes. 160 * 161 * Prints the device name together with the bus id if available. 162 */ 163static int drm_name_info(char *buf, char **start, off_t offset, int request, 164 int *eof, void *data) 165{ 166 struct drm_minor *minor = (struct drm_minor *) data; 167 struct drm_device *dev = minor->dev; 168 int len = 0; 169 170 if (offset > DRM_PROC_LIMIT) { 171 *eof = 1; 172 return 0; 173 } 174 175 *start = &buf[offset]; 176 *eof = 0; 177 178 if (dev->unique) { 179 DRM_PROC_PRINT("%s %s %s\n", 180 dev->driver->pci_driver.name, 181 pci_name(dev->pdev), dev->unique); 182 } else { 183 DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, 184 pci_name(dev->pdev)); 185 } 186 187 if (len > request + offset) 188 return request; 189 *eof = 1; 190 return len - offset; 191} 192 193/** 194 * Called when "/proc/dri/.../vm" is read. 195 * 196 * \param buf output buffer. 197 * \param start start of output data. 198 * \param offset requested start offset. 199 * \param request requested number of bytes. 200 * \param eof whether there is no more data to return. 201 * \param data private data. 202 * \return number of written bytes. 203 * 204 * Prints information about all mappings in drm_device::maplist. 205 */ 206static int drm__vm_info(char *buf, char **start, off_t offset, int request, 207 int *eof, void *data) 208{ 209 struct drm_minor *minor = (struct drm_minor *) data; 210 struct drm_device *dev = minor->dev; 211 int len = 0; 212 struct drm_map *map; 213 struct drm_map_list *r_list; 214 215 /* Hardcoded from _DRM_FRAME_BUFFER, 216 _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and 217 _DRM_SCATTER_GATHER and _DRM_CONSISTENT */ 218 const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" }; 219 const char *type; 220 int i; 221 222 if (offset > DRM_PROC_LIMIT) { 223 *eof = 1; 224 return 0; 225 } 226 227 *start = &buf[offset]; 228 *eof = 0; 229 230 DRM_PROC_PRINT("slot offset size type flags " 231 "address mtrr\n\n"); 232 i = 0; 233 list_for_each_entry(r_list, &dev->maplist, head) { 234 map = r_list->map; 235 if (!map) 236 continue; 237 if (map->type < 0 || map->type > 5) 238 type = "??"; 239 else 240 type = types[map->type]; 241 DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", 242 i, 243 map->offset, 244 map->size, type, map->flags, 245 (unsigned long) r_list->user_token); 246 if (map->mtrr < 0) { 247 DRM_PROC_PRINT("none\n"); 248 } else { 249 DRM_PROC_PRINT("%4d\n", map->mtrr); 250 } 251 i++; 252 } 253 254 if (len > request + offset) 255 return request; 256 *eof = 1; 257 return len - offset; 258} 259 260/** 261 * Simply calls _vm_info() while holding the drm_device::struct_mutex lock. 262 */ 263static int drm_vm_info(char *buf, char **start, off_t offset, int request, 264 int *eof, void *data) 265{ 266 struct drm_minor *minor = (struct drm_minor *) data; 267 struct drm_device *dev = minor->dev; 268 int ret; 269 270 mutex_lock(&dev->struct_mutex); 271 ret = drm__vm_info(buf, start, offset, request, eof, data); 272 mutex_unlock(&dev->struct_mutex); 273 return ret; 274} 275 276/** 277 * Called when "/proc/dri/.../queues" is read. 278 * 279 * \param buf output buffer. 280 * \param start start of output data. 281 * \param offset requested start offset. 282 * \param request requested number of bytes. 283 * \param eof whether there is no more data to return. 284 * \param data private data. 285 * \return number of written bytes. 286 */ 287static int drm__queues_info(char *buf, char **start, off_t offset, 288 int request, int *eof, void *data) 289{ 290 struct drm_minor *minor = (struct drm_minor *) data; 291 struct drm_device *dev = minor->dev; 292 int len = 0; 293 int i; 294 struct drm_queue *q; 295 296 if (offset > DRM_PROC_LIMIT) { 297 *eof = 1; 298 return 0; 299 } 300 301 *start = &buf[offset]; 302 *eof = 0; 303 304 DRM_PROC_PRINT(" ctx/flags use fin" 305 " blk/rw/rwf wait flushed queued" 306 " locks\n\n"); 307 for (i = 0; i < dev->queue_count; i++) { 308 q = dev->queuelist[i]; 309 atomic_inc(&q->use_count); 310 DRM_PROC_PRINT_RET(atomic_dec(&q->use_count), 311 "%5d/0x%03x %5d %5d" 312 " %5d/%c%c/%c%c%c %5Zd\n", 313 i, 314 q->flags, 315 atomic_read(&q->use_count), 316 atomic_read(&q->finalization), 317 atomic_read(&q->block_count), 318 atomic_read(&q->block_read) ? 'r' : '-', 319 atomic_read(&q->block_write) ? 'w' : '-', 320 waitqueue_active(&q->read_queue) ? 'r' : '-', 321 waitqueue_active(&q-> 322 write_queue) ? 'w' : '-', 323 waitqueue_active(&q-> 324 flush_queue) ? 'f' : '-', 325 DRM_BUFCOUNT(&q->waitlist)); 326 atomic_dec(&q->use_count); 327 } 328 329 if (len > request + offset) 330 return request; 331 *eof = 1; 332 return len - offset; 333} 334 335/** 336 * Simply calls _queues_info() while holding the drm_device::struct_mutex lock. 337 */ 338static int drm_queues_info(char *buf, char **start, off_t offset, int request, 339 int *eof, void *data) 340{ 341 struct drm_minor *minor = (struct drm_minor *) data; 342 struct drm_device *dev = minor->dev; 343 int ret; 344 345 mutex_lock(&dev->struct_mutex); 346 ret = drm__queues_info(buf, start, offset, request, eof, data); 347 mutex_unlock(&dev->struct_mutex); 348 return ret; 349} 350 351/** 352 * Called when "/proc/dri/.../bufs" is read. 353 * 354 * \param buf output buffer. 355 * \param start start of output data. 356 * \param offset requested start offset. 357 * \param request requested number of bytes. 358 * \param eof whether there is no more data to return. 359 * \param data private data. 360 * \return number of written bytes. 361 */ 362static int drm__bufs_info(char *buf, char **start, off_t offset, int request, 363 int *eof, void *data) 364{ 365 struct drm_minor *minor = (struct drm_minor *) data; 366 struct drm_device *dev = minor->dev; 367 int len = 0; 368 struct drm_device_dma *dma = dev->dma; 369 int i; 370 371 if (!dma || offset > DRM_PROC_LIMIT) { 372 *eof = 1; 373 return 0; 374 } 375 376 *start = &buf[offset]; 377 *eof = 0; 378 379 DRM_PROC_PRINT(" o size count free segs pages kB\n\n"); 380 for (i = 0; i <= DRM_MAX_ORDER; i++) { 381 if (dma->bufs[i].buf_count) 382 DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n", 383 i, 384 dma->bufs[i].buf_size, 385 dma->bufs[i].buf_count, 386 atomic_read(&dma->bufs[i] 387 .freelist.count), 388 dma->bufs[i].seg_count, 389 dma->bufs[i].seg_count 390 * (1 << dma->bufs[i].page_order), 391 (dma->bufs[i].seg_count 392 * (1 << dma->bufs[i].page_order)) 393 * PAGE_SIZE / 1024); 394 } 395 DRM_PROC_PRINT("\n"); 396 for (i = 0; i < dma->buf_count; i++) { 397 if (i && !(i % 32)) 398 DRM_PROC_PRINT("\n"); 399 DRM_PROC_PRINT(" %d", dma->buflist[i]->list); 400 } 401 DRM_PROC_PRINT("\n"); 402 403 if (len > request + offset) 404 return request; 405 *eof = 1; 406 return len - offset; 407} 408 409/** 410 * Simply calls _bufs_info() while holding the drm_device::struct_mutex lock. 411 */ 412static int drm_bufs_info(char *buf, char **start, off_t offset, int request, 413 int *eof, void *data) 414{ 415 struct drm_minor *minor = (struct drm_minor *) data; 416 struct drm_device *dev = minor->dev; 417 int ret; 418 419 mutex_lock(&dev->struct_mutex); 420 ret = drm__bufs_info(buf, start, offset, request, eof, data); 421 mutex_unlock(&dev->struct_mutex); 422 return ret; 423} 424 425/** 426 * Called when "/proc/dri/.../clients" is read. 427 * 428 * \param buf output buffer. 429 * \param start start of output data. 430 * \param offset requested start offset. 431 * \param request requested number of bytes. 432 * \param eof whether there is no more data to return. 433 * \param data private data. 434 * \return number of written bytes. 435 */ 436static int drm__clients_info(char *buf, char **start, off_t offset, 437 int request, int *eof, void *data) 438{ 439 struct drm_minor *minor = (struct drm_minor *) data; 440 struct drm_device *dev = minor->dev; 441 int len = 0; 442 struct drm_file *priv; 443 444 if (offset > DRM_PROC_LIMIT) { 445 *eof = 1; 446 return 0; 447 } 448 449 *start = &buf[offset]; 450 *eof = 0; 451 452 DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n"); 453 list_for_each_entry(priv, &dev->filelist, lhead) { 454 DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", 455 priv->authenticated ? 'y' : 'n', 456 priv->minor->index, 457 priv->pid, 458 priv->uid, priv->magic, priv->ioctl_count); 459 } 460 461 if (len > request + offset) 462 return request; 463 *eof = 1; 464 return len - offset; 465} 466 467/** 468 * Simply calls _clients_info() while holding the drm_device::struct_mutex lock. 469 */ 470static int drm_clients_info(char *buf, char **start, off_t offset, 471 int request, int *eof, void *data) 472{ 473 struct drm_minor *minor = (struct drm_minor *) data; 474 struct drm_device *dev = minor->dev; 475 int ret; 476 477 mutex_lock(&dev->struct_mutex); 478 ret = drm__clients_info(buf, start, offset, request, eof, data); 479 mutex_unlock(&dev->struct_mutex); 480 return ret; 481} 482 483#if DRM_DEBUG_CODE 484 485static int drm__vma_info(char *buf, char **start, off_t offset, int request, 486 int *eof, void *data) 487{ 488 struct drm_minor *minor = (struct drm_minor *) data; 489 struct drm_device *dev = minor->dev; 490 int len = 0; 491 struct drm_vma_entry *pt; 492 struct vm_area_struct *vma; 493#if defined(__i386__) 494 unsigned int pgprot; 495#endif 496 497 if (offset > DRM_PROC_LIMIT) { 498 *eof = 1; 499 return 0; 500 } 501 502 *start = &buf[offset]; 503 *eof = 0; 504 505 DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n", 506 atomic_read(&dev->vma_count), 507 high_memory, virt_to_phys(high_memory)); 508 list_for_each_entry(pt, &dev->vmalist, head) { 509 if (!(vma = pt->vma)) 510 continue; 511 DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000", 512 pt->pid, 513 vma->vm_start, 514 vma->vm_end, 515 vma->vm_flags & VM_READ ? 'r' : '-', 516 vma->vm_flags & VM_WRITE ? 'w' : '-', 517 vma->vm_flags & VM_EXEC ? 'x' : '-', 518 vma->vm_flags & VM_MAYSHARE ? 's' : 'p', 519 vma->vm_flags & VM_LOCKED ? 'l' : '-', 520 vma->vm_flags & VM_IO ? 'i' : '-', 521 vma->vm_pgoff); 522 523#if defined(__i386__) 524 pgprot = pgprot_val(vma->vm_page_prot); 525 DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c", 526 pgprot & _PAGE_PRESENT ? 'p' : '-', 527 pgprot & _PAGE_RW ? 'w' : 'r', 528 pgprot & _PAGE_USER ? 'u' : 's', 529 pgprot & _PAGE_PWT ? 't' : 'b', 530 pgprot & _PAGE_PCD ? 'u' : 'c', 531 pgprot & _PAGE_ACCESSED ? 'a' : '-', 532 pgprot & _PAGE_DIRTY ? 'd' : '-', 533 pgprot & _PAGE_PSE ? 'm' : 'k', 534 pgprot & _PAGE_GLOBAL ? 'g' : 'l'); 535#endif 536 DRM_PROC_PRINT("\n"); 537 } 538 539 if (len > request + offset) 540 return request; 541 *eof = 1; 542 return len - offset; 543} 544 545static int drm_vma_info(char *buf, char **start, off_t offset, int request, 546 int *eof, void *data) 547{ 548 struct drm_minor *minor = (struct drm_minor *) data; 549 struct drm_device *dev = minor->dev; 550 int ret; 551 552 mutex_lock(&dev->struct_mutex); 553 ret = drm__vma_info(buf, start, offset, request, eof, data); 554 mutex_unlock(&dev->struct_mutex); 555 return ret; 556} 557#endif