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