Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /** |
2 | * \file drm_proc.h | |
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 | ||
42 | static int drm_name_info(char *buf, char **start, off_t offset, | |
43 | int request, int *eof, void *data); | |
44 | static int drm_vm_info(char *buf, char **start, off_t offset, | |
45 | int request, int *eof, void *data); | |
46 | static int drm_clients_info(char *buf, char **start, off_t offset, | |
47 | int request, int *eof, void *data); | |
48 | static int drm_queues_info(char *buf, char **start, off_t offset, | |
49 | int request, int *eof, void *data); | |
50 | static int drm_bufs_info(char *buf, char **start, off_t offset, | |
51 | int request, int *eof, void *data); | |
52 | #if DRM_DEBUG_CODE | |
53 | static 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 | */ | |
c94f7029 | 60 | static struct drm_proc_list { |
1da177e4 LT |
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 | #define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0])) | |
75 | ||
76 | /** | |
77 | * Initialize the DRI proc filesystem for a device. | |
78 | * | |
79 | * \param dev DRM device. | |
80 | * \param minor device minor number. | |
81 | * \param root DRI proc dir entry. | |
82 | * \param dev_root resulting DRI device proc dir entry. | |
83 | * \return root entry pointer on success, or NULL on failure. | |
84 | * | |
85 | * Create the DRI proc root entry "/proc/dri", the device proc root entry | |
86 | * "/proc/dri/%minor%/", and each entry in proc_list as | |
87 | * "/proc/dri/%minor%/%name%". | |
88 | */ | |
89 | int drm_proc_init(drm_device_t *dev, int minor, | |
90 | struct proc_dir_entry *root, | |
91 | 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 = create_proc_entry(name, S_IFDIR, 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 | /** | |
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 | */ | |
134 | int drm_proc_cleanup(int minor, struct proc_dir_entry *root, | |
135 | struct proc_dir_entry *dev_root) | |
136 | { | |
137 | int i; | |
138 | char name[64]; | |
139 | ||
140 | if (!root || !dev_root) 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 | */ | |
163 | static 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, pci_name(dev->pdev), dev->unique); | |
180 | } else { | |
181 | DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, pci_name(dev->pdev)); | |
182 | } | |
183 | ||
184 | if (len > request + offset) return request; | |
185 | *eof = 1; | |
186 | return len - offset; | |
187 | } | |
188 | ||
189 | /** | |
190 | * Called when "/proc/dri/.../vm" is read. | |
191 | * | |
192 | * \param buf output buffer. | |
193 | * \param start start of output data. | |
194 | * \param offset requested start offset. | |
195 | * \param request requested number of bytes. | |
196 | * \param eof whether there is no more data to return. | |
197 | * \param data private data. | |
198 | * \return number of written bytes. | |
199 | * | |
200 | * Prints information about all mappings in drm_device::maplist. | |
201 | */ | |
202 | static int drm__vm_info(char *buf, char **start, off_t offset, int request, | |
203 | int *eof, void *data) | |
204 | { | |
205 | drm_device_t *dev = (drm_device_t *)data; | |
206 | int len = 0; | |
207 | drm_map_t *map; | |
208 | drm_map_list_t *r_list; | |
209 | struct list_head *list; | |
210 | ||
211 | /* Hardcoded from _DRM_FRAME_BUFFER, | |
212 | _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and | |
2d0f9eaf DA |
213 | _DRM_SCATTER_GATHER and _DRM_CONSISTENT */ |
214 | const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" }; | |
1da177e4 LT |
215 | const char *type; |
216 | int i; | |
217 | ||
218 | if (offset > DRM_PROC_LIMIT) { | |
219 | *eof = 1; | |
220 | return 0; | |
221 | } | |
222 | ||
223 | *start = &buf[offset]; | |
224 | *eof = 0; | |
225 | ||
226 | DRM_PROC_PRINT("slot offset size type flags " | |
227 | "address mtrr\n\n"); | |
228 | i = 0; | |
229 | if (dev->maplist != NULL) list_for_each(list, &dev->maplist->head) { | |
230 | r_list = list_entry(list, drm_map_list_t, head); | |
231 | map = r_list->map; | |
2d0f9eaf DA |
232 | if(!map) |
233 | continue; | |
234 | if (map->type < 0 || map->type > 5) | |
235 | type = "??"; | |
236 | else | |
237 | type = types[map->type]; | |
d1f2b55a | 238 | DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08x ", |
1da177e4 LT |
239 | i, |
240 | map->offset, | |
241 | map->size, | |
242 | type, | |
243 | map->flags, | |
d1f2b55a | 244 | r_list->user_token); |
1da177e4 LT |
245 | if (map->mtrr < 0) { |
246 | DRM_PROC_PRINT("none\n"); | |
247 | } else { | |
248 | DRM_PROC_PRINT("%4d\n", map->mtrr); | |
249 | } | |
250 | i++; | |
251 | } | |
252 | ||
253 | if (len > request + offset) return request; | |
254 | *eof = 1; | |
255 | return len - offset; | |
256 | } | |
257 | ||
258 | /** | |
259 | * Simply calls _vm_info() while holding the drm_device::struct_sem lock. | |
260 | */ | |
261 | static int drm_vm_info(char *buf, char **start, off_t offset, int request, | |
262 | int *eof, void *data) | |
263 | { | |
264 | drm_device_t *dev = (drm_device_t *)data; | |
265 | int ret; | |
266 | ||
267 | down(&dev->struct_sem); | |
268 | ret = drm__vm_info(buf, start, offset, request, eof, data); | |
269 | up(&dev->struct_sem); | |
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 | */ | |
284 | static int drm__queues_info(char *buf, char **start, off_t offset, | |
285 | int request, int *eof, void *data) | |
286 | { | |
287 | drm_device_t *dev = (drm_device_t *)data; | |
288 | int len = 0; | |
289 | int i; | |
290 | drm_queue_t *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->write_queue) ? 'w':'-', | |
318 | waitqueue_active(&q->flush_queue) ? 'f':'-', | |
319 | DRM_BUFCOUNT(&q->waitlist)); | |
320 | atomic_dec(&q->use_count); | |
321 | } | |
322 | ||
323 | if (len > request + offset) return request; | |
324 | *eof = 1; | |
325 | return len - offset; | |
326 | } | |
327 | ||
328 | /** | |
329 | * Simply calls _queues_info() while holding the drm_device::struct_sem lock. | |
330 | */ | |
331 | static int drm_queues_info(char *buf, char **start, off_t offset, int request, | |
332 | int *eof, void *data) | |
333 | { | |
334 | drm_device_t *dev = (drm_device_t *)data; | |
335 | int ret; | |
336 | ||
337 | down(&dev->struct_sem); | |
338 | ret = drm__queues_info(buf, start, offset, request, eof, data); | |
339 | up(&dev->struct_sem); | |
340 | return ret; | |
341 | } | |
342 | ||
343 | /** | |
344 | * Called when "/proc/dri/.../bufs" is read. | |
345 | * | |
346 | * \param buf output buffer. | |
347 | * \param start start of output data. | |
348 | * \param offset requested start offset. | |
349 | * \param request requested number of bytes. | |
350 | * \param eof whether there is no more data to return. | |
351 | * \param data private data. | |
352 | * \return number of written bytes. | |
353 | */ | |
354 | static int drm__bufs_info(char *buf, char **start, off_t offset, int request, | |
355 | int *eof, void *data) | |
356 | { | |
357 | drm_device_t *dev = (drm_device_t *)data; | |
358 | int len = 0; | |
359 | drm_device_dma_t *dma = dev->dma; | |
360 | int i; | |
361 | ||
362 | if (!dma || offset > DRM_PROC_LIMIT) { | |
363 | *eof = 1; | |
364 | return 0; | |
365 | } | |
366 | ||
367 | *start = &buf[offset]; | |
368 | *eof = 0; | |
369 | ||
370 | DRM_PROC_PRINT(" o size count free segs pages kB\n\n"); | |
371 | for (i = 0; i <= DRM_MAX_ORDER; i++) { | |
372 | if (dma->bufs[i].buf_count) | |
373 | DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n", | |
374 | i, | |
375 | dma->bufs[i].buf_size, | |
376 | dma->bufs[i].buf_count, | |
377 | atomic_read(&dma->bufs[i] | |
378 | .freelist.count), | |
379 | dma->bufs[i].seg_count, | |
380 | dma->bufs[i].seg_count | |
381 | *(1 << dma->bufs[i].page_order), | |
382 | (dma->bufs[i].seg_count | |
383 | * (1 << dma->bufs[i].page_order)) | |
384 | * PAGE_SIZE / 1024); | |
385 | } | |
386 | DRM_PROC_PRINT("\n"); | |
387 | for (i = 0; i < dma->buf_count; i++) { | |
388 | if (i && !(i%32)) DRM_PROC_PRINT("\n"); | |
389 | DRM_PROC_PRINT(" %d", dma->buflist[i]->list); | |
390 | } | |
391 | DRM_PROC_PRINT("\n"); | |
392 | ||
393 | if (len > request + offset) return request; | |
394 | *eof = 1; | |
395 | return len - offset; | |
396 | } | |
397 | ||
398 | /** | |
399 | * Simply calls _bufs_info() while holding the drm_device::struct_sem lock. | |
400 | */ | |
401 | static int drm_bufs_info(char *buf, char **start, off_t offset, int request, | |
402 | int *eof, void *data) | |
403 | { | |
404 | drm_device_t *dev = (drm_device_t *)data; | |
405 | int ret; | |
406 | ||
407 | down(&dev->struct_sem); | |
408 | ret = drm__bufs_info(buf, start, offset, request, eof, data); | |
409 | up(&dev->struct_sem); | |
410 | return ret; | |
411 | } | |
412 | ||
413 | /** | |
414 | * Called when "/proc/dri/.../clients" is read. | |
415 | * | |
416 | * \param buf output buffer. | |
417 | * \param start start of output data. | |
418 | * \param offset requested start offset. | |
419 | * \param request requested number of bytes. | |
420 | * \param eof whether there is no more data to return. | |
421 | * \param data private data. | |
422 | * \return number of written bytes. | |
423 | */ | |
424 | static int drm__clients_info(char *buf, char **start, off_t offset, | |
425 | int request, int *eof, void *data) | |
426 | { | |
427 | drm_device_t *dev = (drm_device_t *)data; | |
428 | int len = 0; | |
429 | drm_file_t *priv; | |
430 | ||
431 | if (offset > DRM_PROC_LIMIT) { | |
432 | *eof = 1; | |
433 | return 0; | |
434 | } | |
435 | ||
436 | *start = &buf[offset]; | |
437 | *eof = 0; | |
438 | ||
439 | DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n"); | |
440 | for (priv = dev->file_first; priv; priv = priv->next) { | |
441 | DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", | |
442 | priv->authenticated ? 'y' : 'n', | |
443 | priv->minor, | |
444 | priv->pid, | |
445 | priv->uid, | |
446 | priv->magic, | |
447 | priv->ioctl_count); | |
448 | } | |
449 | ||
450 | if (len > request + offset) return request; | |
451 | *eof = 1; | |
452 | return len - offset; | |
453 | } | |
454 | ||
455 | /** | |
456 | * Simply calls _clients_info() while holding the drm_device::struct_sem lock. | |
457 | */ | |
458 | static int drm_clients_info(char *buf, char **start, off_t offset, | |
459 | int request, int *eof, void *data) | |
460 | { | |
461 | drm_device_t *dev = (drm_device_t *)data; | |
462 | int ret; | |
463 | ||
464 | down(&dev->struct_sem); | |
465 | ret = drm__clients_info(buf, start, offset, request, eof, data); | |
466 | up(&dev->struct_sem); | |
467 | return ret; | |
468 | } | |
469 | ||
470 | #if DRM_DEBUG_CODE | |
471 | ||
472 | static int drm__vma_info(char *buf, char **start, off_t offset, int request, | |
473 | int *eof, void *data) | |
474 | { | |
475 | drm_device_t *dev = (drm_device_t *)data; | |
476 | int len = 0; | |
477 | drm_vma_entry_t *pt; | |
478 | struct vm_area_struct *vma; | |
479 | #if defined(__i386__) | |
480 | unsigned int pgprot; | |
481 | #endif | |
482 | ||
483 | if (offset > DRM_PROC_LIMIT) { | |
484 | *eof = 1; | |
485 | return 0; | |
486 | } | |
487 | ||
488 | *start = &buf[offset]; | |
489 | *eof = 0; | |
490 | ||
491 | DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n", | |
492 | atomic_read(&dev->vma_count), | |
493 | high_memory, virt_to_phys(high_memory)); | |
494 | for (pt = dev->vmalist; pt; pt = pt->next) { | |
495 | if (!(vma = pt->vma)) continue; | |
496 | DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx", | |
497 | pt->pid, | |
498 | vma->vm_start, | |
499 | vma->vm_end, | |
500 | vma->vm_flags & VM_READ ? 'r' : '-', | |
501 | vma->vm_flags & VM_WRITE ? 'w' : '-', | |
502 | vma->vm_flags & VM_EXEC ? 'x' : '-', | |
503 | vma->vm_flags & VM_MAYSHARE ? 's' : 'p', | |
504 | vma->vm_flags & VM_LOCKED ? 'l' : '-', | |
505 | vma->vm_flags & VM_IO ? 'i' : '-', | |
506 | VM_OFFSET(vma)); | |
507 | ||
508 | #if defined(__i386__) | |
509 | pgprot = pgprot_val(vma->vm_page_prot); | |
510 | DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c", | |
511 | pgprot & _PAGE_PRESENT ? 'p' : '-', | |
512 | pgprot & _PAGE_RW ? 'w' : 'r', | |
513 | pgprot & _PAGE_USER ? 'u' : 's', | |
514 | pgprot & _PAGE_PWT ? 't' : 'b', | |
515 | pgprot & _PAGE_PCD ? 'u' : 'c', | |
516 | pgprot & _PAGE_ACCESSED ? 'a' : '-', | |
517 | pgprot & _PAGE_DIRTY ? 'd' : '-', | |
518 | pgprot & _PAGE_PSE ? 'm' : 'k', | |
519 | pgprot & _PAGE_GLOBAL ? 'g' : 'l' ); | |
520 | #endif | |
521 | DRM_PROC_PRINT("\n"); | |
522 | } | |
523 | ||
524 | if (len > request + offset) return request; | |
525 | *eof = 1; | |
526 | return len - offset; | |
527 | } | |
528 | ||
529 | static int drm_vma_info(char *buf, char **start, off_t offset, int request, | |
530 | int *eof, void *data) | |
531 | { | |
532 | drm_device_t *dev = (drm_device_t *)data; | |
533 | int ret; | |
534 | ||
535 | down(&dev->struct_sem); | |
536 | ret = drm__vma_info(buf, start, offset, request, eof, data); | |
537 | up(&dev->struct_sem); | |
538 | return ret; | |
539 | } | |
540 | #endif | |
541 | ||
542 |