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