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(drm_device_t * 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 drm_device_t *dev = (drm_device_t *) 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 drm_device_t *dev = (drm_device_t *) data; 209 int len = 0; 210 drm_map_t *map; 211 drm_map_list_t *r_list; 212 struct list_head *list; 213 214 /* Hardcoded from _DRM_FRAME_BUFFER, 215 _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and 216 _DRM_SCATTER_GATHER and _DRM_CONSISTENT */ 217 const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" }; 218 const char *type; 219 int i; 220 221 if (offset > DRM_PROC_LIMIT) { 222 *eof = 1; 223 return 0; 224 } 225 226 *start = &buf[offset]; 227 *eof = 0; 228 229 DRM_PROC_PRINT("slot offset size type flags " 230 "address mtrr\n\n"); 231 i = 0; 232 if (dev->maplist != NULL) 233 list_for_each(list, &dev->maplist->head) { 234 r_list = list_entry(list, drm_map_list_t, head); 235 map = r_list->map; 236 if (!map) 237 continue; 238 if (map->type < 0 || map->type > 5) 239 type = "??"; 240 else 241 type = types[map->type]; 242 DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08x ", 243 i, 244 map->offset, 245 map->size, type, map->flags, 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 drm_device_t *dev = (drm_device_t *) data; 267 int ret; 268 269 mutex_lock(&dev->struct_mutex); 270 ret = drm__vm_info(buf, start, offset, request, eof, data); 271 mutex_unlock(&dev->struct_mutex); 272 return ret; 273} 274 275/** 276 * Called when "/proc/dri/.../queues" is read. 277 * 278 * \param buf output buffer. 279 * \param start start of output data. 280 * \param offset requested start offset. 281 * \param request requested number of bytes. 282 * \param eof whether there is no more data to return. 283 * \param data private data. 284 * \return number of written bytes. 285 */ 286static int drm__queues_info(char *buf, char **start, off_t offset, 287 int request, int *eof, void *data) 288{ 289 drm_device_t *dev = (drm_device_t *) data; 290 int len = 0; 291 int i; 292 drm_queue_t *q; 293 294 if (offset > DRM_PROC_LIMIT) { 295 *eof = 1; 296 return 0; 297 } 298 299 *start = &buf[offset]; 300 *eof = 0; 301 302 DRM_PROC_PRINT(" ctx/flags use fin" 303 " blk/rw/rwf wait flushed queued" 304 " locks\n\n"); 305 for (i = 0; i < dev->queue_count; i++) { 306 q = dev->queuelist[i]; 307 atomic_inc(&q->use_count); 308 DRM_PROC_PRINT_RET(atomic_dec(&q->use_count), 309 "%5d/0x%03x %5d %5d" 310 " %5d/%c%c/%c%c%c %5Zd\n", 311 i, 312 q->flags, 313 atomic_read(&q->use_count), 314 atomic_read(&q->finalization), 315 atomic_read(&q->block_count), 316 atomic_read(&q->block_read) ? 'r' : '-', 317 atomic_read(&q->block_write) ? 'w' : '-', 318 waitqueue_active(&q->read_queue) ? 'r' : '-', 319 waitqueue_active(&q-> 320 write_queue) ? 'w' : '-', 321 waitqueue_active(&q-> 322 flush_queue) ? 'f' : '-', 323 DRM_BUFCOUNT(&q->waitlist)); 324 atomic_dec(&q->use_count); 325 } 326 327 if (len > request + offset) 328 return request; 329 *eof = 1; 330 return len - offset; 331} 332 333/** 334 * Simply calls _queues_info() while holding the drm_device::struct_mutex lock. 335 */ 336static int drm_queues_info(char *buf, char **start, off_t offset, int request, 337 int *eof, void *data) 338{ 339 drm_device_t *dev = (drm_device_t *) data; 340 int ret; 341 342 mutex_lock(&dev->struct_mutex); 343 ret = drm__queues_info(buf, start, offset, request, eof, data); 344 mutex_unlock(&dev->struct_mutex); 345 return ret; 346} 347 348/** 349 * Called when "/proc/dri/.../bufs" is read. 350 * 351 * \param buf output buffer. 352 * \param start start of output data. 353 * \param offset requested start offset. 354 * \param request requested number of bytes. 355 * \param eof whether there is no more data to return. 356 * \param data private data. 357 * \return number of written bytes. 358 */ 359static int drm__bufs_info(char *buf, char **start, off_t offset, int request, 360 int *eof, void *data) 361{ 362 drm_device_t *dev = (drm_device_t *) data; 363 int len = 0; 364 drm_device_dma_t *dma = dev->dma; 365 int i; 366 367 if (!dma || offset > DRM_PROC_LIMIT) { 368 *eof = 1; 369 return 0; 370 } 371 372 *start = &buf[offset]; 373 *eof = 0; 374 375 DRM_PROC_PRINT(" o size count free segs pages kB\n\n"); 376 for (i = 0; i <= DRM_MAX_ORDER; i++) { 377 if (dma->bufs[i].buf_count) 378 DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n", 379 i, 380 dma->bufs[i].buf_size, 381 dma->bufs[i].buf_count, 382 atomic_read(&dma->bufs[i] 383 .freelist.count), 384 dma->bufs[i].seg_count, 385 dma->bufs[i].seg_count 386 * (1 << dma->bufs[i].page_order), 387 (dma->bufs[i].seg_count 388 * (1 << dma->bufs[i].page_order)) 389 * PAGE_SIZE / 1024); 390 } 391 DRM_PROC_PRINT("\n"); 392 for (i = 0; i < dma->buf_count; i++) { 393 if (i && !(i % 32)) 394 DRM_PROC_PRINT("\n"); 395 DRM_PROC_PRINT(" %d", dma->buflist[i]->list); 396 } 397 DRM_PROC_PRINT("\n"); 398 399 if (len > request + offset) 400 return request; 401 *eof = 1; 402 return len - offset; 403} 404 405/** 406 * Simply calls _bufs_info() while holding the drm_device::struct_mutex lock. 407 */ 408static int drm_bufs_info(char *buf, char **start, off_t offset, int request, 409 int *eof, void *data) 410{ 411 drm_device_t *dev = (drm_device_t *) data; 412 int ret; 413 414 mutex_lock(&dev->struct_mutex); 415 ret = drm__bufs_info(buf, start, offset, request, eof, data); 416 mutex_unlock(&dev->struct_mutex); 417 return ret; 418} 419 420/** 421 * Called when "/proc/dri/.../clients" is read. 422 * 423 * \param buf output buffer. 424 * \param start start of output data. 425 * \param offset requested start offset. 426 * \param request requested number of bytes. 427 * \param eof whether there is no more data to return. 428 * \param data private data. 429 * \return number of written bytes. 430 */ 431static int drm__clients_info(char *buf, char **start, off_t offset, 432 int request, int *eof, void *data) 433{ 434 drm_device_t *dev = (drm_device_t *) data; 435 int len = 0; 436 drm_file_t *priv; 437 438 if (offset > DRM_PROC_LIMIT) { 439 *eof = 1; 440 return 0; 441 } 442 443 *start = &buf[offset]; 444 *eof = 0; 445 446 DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n"); 447 for (priv = dev->file_first; priv; priv = priv->next) { 448 DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", 449 priv->authenticated ? 'y' : 'n', 450 priv->minor, 451 priv->pid, 452 priv->uid, priv->magic, priv->ioctl_count); 453 } 454 455 if (len > request + offset) 456 return request; 457 *eof = 1; 458 return len - offset; 459} 460 461/** 462 * Simply calls _clients_info() while holding the drm_device::struct_mutex lock. 463 */ 464static int drm_clients_info(char *buf, char **start, off_t offset, 465 int request, int *eof, void *data) 466{ 467 drm_device_t *dev = (drm_device_t *) data; 468 int ret; 469 470 mutex_lock(&dev->struct_mutex); 471 ret = drm__clients_info(buf, start, offset, request, eof, data); 472 mutex_unlock(&dev->struct_mutex); 473 return ret; 474} 475 476#if DRM_DEBUG_CODE 477 478static int drm__vma_info(char *buf, char **start, off_t offset, int request, 479 int *eof, void *data) 480{ 481 drm_device_t *dev = (drm_device_t *) data; 482 int len = 0; 483 drm_vma_entry_t *pt; 484 struct vm_area_struct *vma; 485#if defined(__i386__) 486 unsigned int pgprot; 487#endif 488 489 if (offset > DRM_PROC_LIMIT) { 490 *eof = 1; 491 return 0; 492 } 493 494 *start = &buf[offset]; 495 *eof = 0; 496 497 DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n", 498 atomic_read(&dev->vma_count), 499 high_memory, virt_to_phys(high_memory)); 500 for (pt = dev->vmalist; pt; pt = pt->next) { 501 if (!(vma = pt->vma)) 502 continue; 503 DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000", 504 pt->pid, 505 vma->vm_start, 506 vma->vm_end, 507 vma->vm_flags & VM_READ ? 'r' : '-', 508 vma->vm_flags & VM_WRITE ? 'w' : '-', 509 vma->vm_flags & VM_EXEC ? 'x' : '-', 510 vma->vm_flags & VM_MAYSHARE ? 's' : 'p', 511 vma->vm_flags & VM_LOCKED ? 'l' : '-', 512 vma->vm_flags & VM_IO ? 'i' : '-', 513 vma->vm_pgoff); 514 515#if defined(__i386__) 516 pgprot = pgprot_val(vma->vm_page_prot); 517 DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c", 518 pgprot & _PAGE_PRESENT ? 'p' : '-', 519 pgprot & _PAGE_RW ? 'w' : 'r', 520 pgprot & _PAGE_USER ? 'u' : 's', 521 pgprot & _PAGE_PWT ? 't' : 'b', 522 pgprot & _PAGE_PCD ? 'u' : 'c', 523 pgprot & _PAGE_ACCESSED ? 'a' : '-', 524 pgprot & _PAGE_DIRTY ? 'd' : '-', 525 pgprot & _PAGE_PSE ? 'm' : 'k', 526 pgprot & _PAGE_GLOBAL ? 'g' : 'l'); 527#endif 528 DRM_PROC_PRINT("\n"); 529 } 530 531 if (len > request + offset) 532 return request; 533 *eof = 1; 534 return len - offset; 535} 536 537static int drm_vma_info(char *buf, char **start, off_t offset, int request, 538 int *eof, void *data) 539{ 540 drm_device_t *dev = (drm_device_t *) data; 541 int ret; 542 543 mutex_lock(&dev->struct_mutex); 544 ret = drm__vma_info(buf, start, offset, request, eof, data); 545 mutex_unlock(&dev->struct_mutex); 546 return ret; 547} 548#endif 549