drm_proc.c 19.7 KB
Newer Older
L
Linus Torvalds 已提交
1
/**
D
Dave Airlie 已提交
2
 * \file drm_proc.c
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 * /proc support for DRM
 *
 * \author Rickard E. (Rik) Faith <faith@valinux.com>
 * \author Gareth Hughes <gareth@valinux.com>
 *
 * \par Acknowledgements:
 *    Matthew J Sottek <matthew.j.sottek@intel.com> sent in a patch to fix
 *    the problem with the proc files not outputting all their information.
 */

/*
 * Created: Mon Jan 11 09:48:47 1999 by faith@valinux.com
 *
 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "drmP.h"

D
Dave Airlie 已提交
42 43 44 45 46 47 48 49 50 51
static int drm_name_info(char *buf, char **start, off_t offset,
			 int request, int *eof, void *data);
static int drm_vm_info(char *buf, char **start, off_t offset,
		       int request, int *eof, void *data);
static int drm_clients_info(char *buf, char **start, off_t offset,
			    int request, int *eof, void *data);
static int drm_queues_info(char *buf, char **start, off_t offset,
			   int request, int *eof, void *data);
static int drm_bufs_info(char *buf, char **start, off_t offset,
			 int request, int *eof, void *data);
52 53
static int drm_vblank_info(char *buf, char **start, off_t offset,
			   int request, int *eof, void *data);
54 55 56 57
static int drm_gem_name_info(char *buf, char **start, off_t offset,
			     int request, int *eof, void *data);
static int drm_gem_object_info(char *buf, char **start, off_t offset,
			       int request, int *eof, void *data);
L
Linus Torvalds 已提交
58
#if DRM_DEBUG_CODE
D
Dave Airlie 已提交
59 60
static int drm_vma_info(char *buf, char **start, off_t offset,
			int request, int *eof, void *data);
L
Linus Torvalds 已提交
61 62 63 64 65
#endif

/**
 * Proc file list.
 */
D
Dave Airlie 已提交
66
static struct drm_proc_list {
L
Linus Torvalds 已提交
67
	const char *name;	/**< file name */
D
Dave Airlie 已提交
68
	int (*f) (char *, char **, off_t, int, int *, void *);		/**< proc callback*/
69
	u32 driver_features; /**< Required driver features for this entry */
L
Linus Torvalds 已提交
70
} drm_proc_list[] = {
71 72 73 74 75 76
	{"name", drm_name_info, 0},
	{"mem", drm_mem_info, 0},
	{"vm", drm_vm_info, 0},
	{"clients", drm_clients_info, 0},
	{"queues", drm_queues_info, 0},
	{"bufs", drm_bufs_info, 0},
77
	{"vblank", drm_vblank_info, 0},
78 79
	{"gem_names", drm_gem_name_info, DRIVER_GEM},
	{"gem_objects", drm_gem_object_info, DRIVER_GEM},
L
Linus Torvalds 已提交
80
#if DRM_DEBUG_CODE
D
Dave Airlie 已提交
81
	{"vma", drm_vma_info},
L
Linus Torvalds 已提交
82 83
#endif
};
D
Dave Airlie 已提交
84

85
#define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list)
L
Linus Torvalds 已提交
86 87 88 89 90 91 92 93 94

/**
 * Initialize the DRI proc filesystem for a device.
 *
 * \param dev DRM device.
 * \param minor device minor number.
 * \param root DRI proc dir entry.
 * \param dev_root resulting DRI device proc dir entry.
 * \return root entry pointer on success, or NULL on failure.
D
Dave Airlie 已提交
95
 *
L
Linus Torvalds 已提交
96 97 98 99
 * Create the DRI proc root entry "/proc/dri", the device proc root entry
 * "/proc/dri/%minor%/", and each entry in proc_list as
 * "/proc/dri/%minor%/%name%".
 */
100 101
int drm_proc_init(struct drm_minor *minor, int minor_id,
		  struct proc_dir_entry *root)
L
Linus Torvalds 已提交
102
{
103
	struct drm_device *dev = minor->dev;
L
Linus Torvalds 已提交
104
	struct proc_dir_entry *ent;
105
	int i, j, ret;
D
Dave Airlie 已提交
106
	char name[64];
L
Linus Torvalds 已提交
107

108 109 110
	sprintf(name, "%d", minor_id);
	minor->dev_root = proc_mkdir(name, root);
	if (!minor->dev_root) {
L
Linus Torvalds 已提交
111 112 113 114 115
		DRM_ERROR("Cannot create /proc/dri/%s\n", name);
		return -1;
	}

	for (i = 0; i < DRM_PROC_ENTRIES; i++) {
116 117 118 119 120 121
		u32 features = drm_proc_list[i].driver_features;

		if (features != 0 &&
		    (dev->driver->driver_features & features) != features)
			continue;

L
Linus Torvalds 已提交
122
		ent = create_proc_entry(drm_proc_list[i].name,
123
					S_IFREG | S_IRUGO, minor->dev_root);
L
Linus Torvalds 已提交
124 125 126
		if (!ent) {
			DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
				  name, drm_proc_list[i].name);
127 128
			ret = -1;
			goto fail;
L
Linus Torvalds 已提交
129 130
		}
		ent->read_proc = drm_proc_list[i].f;
131
		ent->data = minor;
L
Linus Torvalds 已提交
132 133
	}

134 135 136 137 138 139 140 141 142
	if (dev->driver->proc_init) {
		ret = dev->driver->proc_init(minor);
		if (ret) {
			DRM_ERROR("DRM: Driver failed to initialize "
				  "/proc/dri.\n");
			goto fail;
		}
	}

L
Linus Torvalds 已提交
143
	return 0;
144 145 146 147 148 149 150 151
 fail:

	for (j = 0; j < i; j++)
		remove_proc_entry(drm_proc_list[i].name,
				  minor->dev_root);
	remove_proc_entry(name, root);
	minor->dev_root = NULL;
	return ret;
L
Linus Torvalds 已提交
152 153 154 155 156 157 158 159 160 161 162 163
}

/**
 * Cleanup the proc filesystem resources.
 *
 * \param minor device minor number.
 * \param root DRI proc dir entry.
 * \param dev_root DRI device proc dir entry.
 * \return always zero.
 *
 * Remove all proc entries created by proc_init().
 */
164
int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
L
Linus Torvalds 已提交
165
{
166
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
167
	int i;
L
Linus Torvalds 已提交
168 169
	char name[64];

170
	if (!root || !minor->dev_root)
D
Dave Airlie 已提交
171
		return 0;
L
Linus Torvalds 已提交
172

173 174 175
	if (dev->driver->proc_cleanup)
		dev->driver->proc_cleanup(minor);

L
Linus Torvalds 已提交
176
	for (i = 0; i < DRM_PROC_ENTRIES; i++)
177 178
		remove_proc_entry(drm_proc_list[i].name, minor->dev_root);
	sprintf(name, "%d", minor->index);
L
Linus Torvalds 已提交
179 180 181 182 183 184 185
	remove_proc_entry(name, root);

	return 0;
}

/**
 * Called when "/proc/dri/.../name" is read.
D
Dave Airlie 已提交
186
 *
L
Linus Torvalds 已提交
187 188 189 190 191 192 193
 * \param buf output buffer.
 * \param start start of output data.
 * \param offset requested start offset.
 * \param request requested number of bytes.
 * \param eof whether there is no more data to return.
 * \param data private data.
 * \return number of written bytes.
D
Dave Airlie 已提交
194
 *
L
Linus Torvalds 已提交
195 196 197
 * Prints the device name together with the bus id if available.
 */
static int drm_name_info(char *buf, char **start, off_t offset, int request,
D
Dave Airlie 已提交
198
			 int *eof, void *data)
L
Linus Torvalds 已提交
199
{
200
	struct drm_minor *minor = (struct drm_minor *) data;
201
	struct drm_master *master = minor->master;
202
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
203
	int len = 0;
L
Linus Torvalds 已提交
204 205 206 207 208 209

	if (offset > DRM_PROC_LIMIT) {
		*eof = 1;
		return 0;
	}

210 211 212
	if (!master)
		return 0;

L
Linus Torvalds 已提交
213
	*start = &buf[offset];
D
Dave Airlie 已提交
214
	*eof = 0;
L
Linus Torvalds 已提交
215

216
	if (master->unique) {
L
Linus Torvalds 已提交
217
		DRM_PROC_PRINT("%s %s %s\n",
D
Dave Airlie 已提交
218
			       dev->driver->pci_driver.name,
219
			       pci_name(dev->pdev), master->unique);
L
Linus Torvalds 已提交
220
	} else {
D
Dave Airlie 已提交
221 222
		DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name,
			       pci_name(dev->pdev));
L
Linus Torvalds 已提交
223 224
	}

D
Dave Airlie 已提交
225 226
	if (len > request + offset)
		return request;
L
Linus Torvalds 已提交
227 228 229 230 231 232
	*eof = 1;
	return len - offset;
}

/**
 * Called when "/proc/dri/.../vm" is read.
D
Dave Airlie 已提交
233
 *
L
Linus Torvalds 已提交
234 235 236 237 238 239 240
 * \param buf output buffer.
 * \param start start of output data.
 * \param offset requested start offset.
 * \param request requested number of bytes.
 * \param eof whether there is no more data to return.
 * \param data private data.
 * \return number of written bytes.
D
Dave Airlie 已提交
241
 *
L
Linus Torvalds 已提交
242 243 244
 * Prints information about all mappings in drm_device::maplist.
 */
static int drm__vm_info(char *buf, char **start, off_t offset, int request,
D
Dave Airlie 已提交
245
			int *eof, void *data)
L
Linus Torvalds 已提交
246
{
247 248
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
249
	int len = 0;
250
	struct drm_local_map *map;
D
Dave Airlie 已提交
251
	struct drm_map_list *r_list;
L
Linus Torvalds 已提交
252

D
Dave Airlie 已提交
253 254 255 256 257 258
	/* Hardcoded from _DRM_FRAME_BUFFER,
	   _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
	   _DRM_SCATTER_GATHER and _DRM_CONSISTENT */
	const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" };
	const char *type;
	int i;
L
Linus Torvalds 已提交
259 260 261 262 263 264 265

	if (offset > DRM_PROC_LIMIT) {
		*eof = 1;
		return 0;
	}

	*start = &buf[offset];
D
Dave Airlie 已提交
266
	*eof = 0;
L
Linus Torvalds 已提交
267 268 269 270

	DRM_PROC_PRINT("slot	 offset	      size type flags	 "
		       "address mtrr\n\n");
	i = 0;
271
	list_for_each_entry(r_list, &dev->maplist, head) {
L
Linus Torvalds 已提交
272
		map = r_list->map;
D
Dave Airlie 已提交
273
		if (!map)
D
Dave Airlie 已提交
274 275 276
			continue;
		if (map->type < 0 || map->type > 5)
			type = "??";
D
Dave Airlie 已提交
277
		else
D
Dave Airlie 已提交
278
			type = types[map->type];
279
		DRM_PROC_PRINT("%4d 0x%08llx 0x%08lx %4.4s  0x%02x 0x%08lx ",
L
Linus Torvalds 已提交
280
			       i,
281
			       (unsigned long long)map->offset,
282
			       map->size, type, map->flags,
283
			       (unsigned long) r_list->user_token);
L
Linus Torvalds 已提交
284 285 286 287 288 289
		if (map->mtrr < 0) {
			DRM_PROC_PRINT("none\n");
		} else {
			DRM_PROC_PRINT("%4d\n", map->mtrr);
		}
		i++;
290
	}
L
Linus Torvalds 已提交
291

D
Dave Airlie 已提交
292 293
	if (len > request + offset)
		return request;
L
Linus Torvalds 已提交
294 295 296 297 298
	*eof = 1;
	return len - offset;
}

/**
D
Dave Airlie 已提交
299
 * Simply calls _vm_info() while holding the drm_device::struct_mutex lock.
L
Linus Torvalds 已提交
300 301
 */
static int drm_vm_info(char *buf, char **start, off_t offset, int request,
D
Dave Airlie 已提交
302
		       int *eof, void *data)
L
Linus Torvalds 已提交
303
{
304 305
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
306
	int ret;
L
Linus Torvalds 已提交
307

D
Dave Airlie 已提交
308
	mutex_lock(&dev->struct_mutex);
L
Linus Torvalds 已提交
309
	ret = drm__vm_info(buf, start, offset, request, eof, data);
D
Dave Airlie 已提交
310
	mutex_unlock(&dev->struct_mutex);
L
Linus Torvalds 已提交
311 312 313 314 315
	return ret;
}

/**
 * Called when "/proc/dri/.../queues" is read.
D
Dave Airlie 已提交
316
 *
L
Linus Torvalds 已提交
317 318 319 320 321 322 323 324 325
 * \param buf output buffer.
 * \param start start of output data.
 * \param offset requested start offset.
 * \param request requested number of bytes.
 * \param eof whether there is no more data to return.
 * \param data private data.
 * \return number of written bytes.
 */
static int drm__queues_info(char *buf, char **start, off_t offset,
D
Dave Airlie 已提交
326
			    int request, int *eof, void *data)
L
Linus Torvalds 已提交
327
{
328 329
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
330 331
	int len = 0;
	int i;
332
	struct drm_queue *q;
L
Linus Torvalds 已提交
333 334 335 336 337 338 339

	if (offset > DRM_PROC_LIMIT) {
		*eof = 1;
		return 0;
	}

	*start = &buf[offset];
D
Dave Airlie 已提交
340
	*eof = 0;
L
Linus Torvalds 已提交
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357

	DRM_PROC_PRINT("  ctx/flags   use   fin"
		       "   blk/rw/rwf  wait    flushed	   queued"
		       "      locks\n\n");
	for (i = 0; i < dev->queue_count; i++) {
		q = dev->queuelist[i];
		atomic_inc(&q->use_count);
		DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
				   "%5d/0x%03x %5d %5d"
				   " %5d/%c%c/%c%c%c %5Zd\n",
				   i,
				   q->flags,
				   atomic_read(&q->use_count),
				   atomic_read(&q->finalization),
				   atomic_read(&q->block_count),
				   atomic_read(&q->block_read) ? 'r' : '-',
				   atomic_read(&q->block_write) ? 'w' : '-',
D
Dave Airlie 已提交
358 359 360 361 362
				   waitqueue_active(&q->read_queue) ? 'r' : '-',
				   waitqueue_active(&q->
						    write_queue) ? 'w' : '-',
				   waitqueue_active(&q->
						    flush_queue) ? 'f' : '-',
L
Linus Torvalds 已提交
363 364 365 366
				   DRM_BUFCOUNT(&q->waitlist));
		atomic_dec(&q->use_count);
	}

D
Dave Airlie 已提交
367 368
	if (len > request + offset)
		return request;
L
Linus Torvalds 已提交
369 370 371 372 373
	*eof = 1;
	return len - offset;
}

/**
D
Dave Airlie 已提交
374
 * Simply calls _queues_info() while holding the drm_device::struct_mutex lock.
L
Linus Torvalds 已提交
375 376
 */
static int drm_queues_info(char *buf, char **start, off_t offset, int request,
D
Dave Airlie 已提交
377
			   int *eof, void *data)
L
Linus Torvalds 已提交
378
{
379 380
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
381
	int ret;
L
Linus Torvalds 已提交
382

D
Dave Airlie 已提交
383
	mutex_lock(&dev->struct_mutex);
L
Linus Torvalds 已提交
384
	ret = drm__queues_info(buf, start, offset, request, eof, data);
D
Dave Airlie 已提交
385
	mutex_unlock(&dev->struct_mutex);
L
Linus Torvalds 已提交
386 387 388 389 390
	return ret;
}

/**
 * Called when "/proc/dri/.../bufs" is read.
D
Dave Airlie 已提交
391
 *
L
Linus Torvalds 已提交
392 393 394 395 396 397 398 399 400
 * \param buf output buffer.
 * \param start start of output data.
 * \param offset requested start offset.
 * \param request requested number of bytes.
 * \param eof whether there is no more data to return.
 * \param data private data.
 * \return number of written bytes.
 */
static int drm__bufs_info(char *buf, char **start, off_t offset, int request,
D
Dave Airlie 已提交
401
			  int *eof, void *data)
L
Linus Torvalds 已提交
402
{
403 404
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
405
	int len = 0;
406
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
407
	int i;
L
Linus Torvalds 已提交
408 409 410 411 412 413 414

	if (!dma || offset > DRM_PROC_LIMIT) {
		*eof = 1;
		return 0;
	}

	*start = &buf[offset];
D
Dave Airlie 已提交
415
	*eof = 0;
L
Linus Torvalds 已提交
416 417 418 419 420 421 422 423 424 425 426 427

	DRM_PROC_PRINT(" o     size count  free	 segs pages    kB\n\n");
	for (i = 0; i <= DRM_MAX_ORDER; i++) {
		if (dma->bufs[i].buf_count)
			DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
				       i,
				       dma->bufs[i].buf_size,
				       dma->bufs[i].buf_count,
				       atomic_read(&dma->bufs[i]
						   .freelist.count),
				       dma->bufs[i].seg_count,
				       dma->bufs[i].seg_count
D
Dave Airlie 已提交
428
				       * (1 << dma->bufs[i].page_order),
L
Linus Torvalds 已提交
429 430 431 432 433 434
				       (dma->bufs[i].seg_count
					* (1 << dma->bufs[i].page_order))
				       * PAGE_SIZE / 1024);
	}
	DRM_PROC_PRINT("\n");
	for (i = 0; i < dma->buf_count; i++) {
D
Dave Airlie 已提交
435 436
		if (i && !(i % 32))
			DRM_PROC_PRINT("\n");
L
Linus Torvalds 已提交
437 438 439 440
		DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
	}
	DRM_PROC_PRINT("\n");

D
Dave Airlie 已提交
441 442
	if (len > request + offset)
		return request;
L
Linus Torvalds 已提交
443 444 445 446 447
	*eof = 1;
	return len - offset;
}

/**
D
Dave Airlie 已提交
448
 * Simply calls _bufs_info() while holding the drm_device::struct_mutex lock.
L
Linus Torvalds 已提交
449 450
 */
static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
D
Dave Airlie 已提交
451
			 int *eof, void *data)
L
Linus Torvalds 已提交
452
{
453 454
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
455
	int ret;
L
Linus Torvalds 已提交
456

D
Dave Airlie 已提交
457
	mutex_lock(&dev->struct_mutex);
L
Linus Torvalds 已提交
458
	ret = drm__bufs_info(buf, start, offset, request, eof, data);
D
Dave Airlie 已提交
459
	mutex_unlock(&dev->struct_mutex);
L
Linus Torvalds 已提交
460 461 462
	return ret;
}

463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
/**
 * Called when "/proc/dri/.../vblank" is read.
 *
 * \param buf output buffer.
 * \param start start of output data.
 * \param offset requested start offset.
 * \param request requested number of bytes.
 * \param eof whether there is no more data to return.
 * \param data private data.
 * \return number of written bytes.
 */
static int drm__vblank_info(char *buf, char **start, off_t offset, int request,
			  int *eof, void *data)
{
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
	int len = 0;
	int crtc;

	if (offset > DRM_PROC_LIMIT) {
		*eof = 1;
		return 0;
	}

	*start = &buf[offset];
	*eof = 0;

	for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
		DRM_PROC_PRINT("CRTC %d enable:     %d\n",
			       crtc, atomic_read(&dev->vblank_refcount[crtc]));
		DRM_PROC_PRINT("CRTC %d counter:    %d\n",
			       crtc, drm_vblank_count(dev, crtc));
		DRM_PROC_PRINT("CRTC %d last wait:  %d\n",
			       crtc, dev->last_vblank_wait[crtc]);
		DRM_PROC_PRINT("CRTC %d in modeset: %d\n",
			       crtc, dev->vblank_inmodeset[crtc]);
	}

	if (len > request + offset)
		return request;
	*eof = 1;
	return len - offset;
}

/**
 * Simply calls _vblank_info() while holding the drm_device::struct_mutex lock.
 */
static int drm_vblank_info(char *buf, char **start, off_t offset, int request,
			 int *eof, void *data)
{
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
	int ret;

	mutex_lock(&dev->struct_mutex);
	ret = drm__vblank_info(buf, start, offset, request, eof, data);
	mutex_unlock(&dev->struct_mutex);
	return ret;
}

L
Linus Torvalds 已提交
523 524
/**
 * Called when "/proc/dri/.../clients" is read.
D
Dave Airlie 已提交
525
 *
L
Linus Torvalds 已提交
526 527 528 529 530 531 532 533 534
 * \param buf output buffer.
 * \param start start of output data.
 * \param offset requested start offset.
 * \param request requested number of bytes.
 * \param eof whether there is no more data to return.
 * \param data private data.
 * \return number of written bytes.
 */
static int drm__clients_info(char *buf, char **start, off_t offset,
D
Dave Airlie 已提交
535
			     int request, int *eof, void *data)
L
Linus Torvalds 已提交
536
{
537 538
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
539
	int len = 0;
540
	struct drm_file *priv;
L
Linus Torvalds 已提交
541 542 543 544 545 546 547

	if (offset > DRM_PROC_LIMIT) {
		*eof = 1;
		return 0;
	}

	*start = &buf[offset];
D
Dave Airlie 已提交
548
	*eof = 0;
L
Linus Torvalds 已提交
549 550

	DRM_PROC_PRINT("a dev	pid    uid	magic	  ioctls\n\n");
551
	list_for_each_entry(priv, &dev->filelist, lhead) {
L
Linus Torvalds 已提交
552 553
		DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
			       priv->authenticated ? 'y' : 'n',
554
			       priv->minor->index,
L
Linus Torvalds 已提交
555
			       priv->pid,
D
Dave Airlie 已提交
556
			       priv->uid, priv->magic, priv->ioctl_count);
L
Linus Torvalds 已提交
557 558
	}

D
Dave Airlie 已提交
559 560
	if (len > request + offset)
		return request;
L
Linus Torvalds 已提交
561 562 563 564 565
	*eof = 1;
	return len - offset;
}

/**
D
Dave Airlie 已提交
566
 * Simply calls _clients_info() while holding the drm_device::struct_mutex lock.
L
Linus Torvalds 已提交
567 568
 */
static int drm_clients_info(char *buf, char **start, off_t offset,
D
Dave Airlie 已提交
569
			    int request, int *eof, void *data)
L
Linus Torvalds 已提交
570
{
571 572
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
573
	int ret;
L
Linus Torvalds 已提交
574

D
Dave Airlie 已提交
575
	mutex_lock(&dev->struct_mutex);
L
Linus Torvalds 已提交
576
	ret = drm__clients_info(buf, start, offset, request, eof, data);
D
Dave Airlie 已提交
577
	mutex_unlock(&dev->struct_mutex);
L
Linus Torvalds 已提交
578 579 580
	return ret;
}

581 582 583 584 585 586 587 588 589 590 591
struct drm_gem_name_info_data {
       int                     len;
       char                    *buf;
       int                     eof;
};

static int drm_gem_one_name_info(int id, void *ptr, void *data)
{
	struct drm_gem_object *obj = ptr;
	struct drm_gem_name_info_data   *nid = data;

592
	DRM_INFO("name %d size %zd\n", obj->name, obj->size);
593 594 595 596
	if (nid->eof)
		return 0;

	nid->len += sprintf(&nid->buf[nid->len],
597
			    "%6d %8zd %7d %8d\n",
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
			    obj->name, obj->size,
			    atomic_read(&obj->handlecount.refcount),
			    atomic_read(&obj->refcount.refcount));
	if (nid->len > DRM_PROC_LIMIT) {
		nid->eof = 1;
		return 0;
	}
	return 0;
}

static int drm_gem_name_info(char *buf, char **start, off_t offset,
			     int request, int *eof, void *data)
{
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
	struct drm_gem_name_info_data nid;

	if (offset > DRM_PROC_LIMIT) {
		*eof = 1;
		return 0;
	}

	nid.len = sprintf(buf, "  name     size handles refcount\n");
	nid.buf = buf;
	nid.eof = 0;
	idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, &nid);

	*start = &buf[offset];
	*eof = 0;
	if (nid.len > request + offset)
		return request;
	*eof = 1;
	return nid.len - offset;
}

static int drm_gem_object_info(char *buf, char **start, off_t offset,
			       int request, int *eof, void *data)
{
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
	int len = 0;

	if (offset > DRM_PROC_LIMIT) {
		*eof = 1;
		return 0;
	}

	*start = &buf[offset];
	*eof = 0;
	DRM_PROC_PRINT("%d objects\n", atomic_read(&dev->object_count));
	DRM_PROC_PRINT("%d object bytes\n", atomic_read(&dev->object_memory));
	DRM_PROC_PRINT("%d pinned\n", atomic_read(&dev->pin_count));
	DRM_PROC_PRINT("%d pin bytes\n", atomic_read(&dev->pin_memory));
	DRM_PROC_PRINT("%d gtt bytes\n", atomic_read(&dev->gtt_memory));
	DRM_PROC_PRINT("%d gtt total\n", dev->gtt_total);
	if (len > request + offset)
		return request;
	*eof = 1;
	return len - offset;
}

L
Linus Torvalds 已提交
659 660 661
#if DRM_DEBUG_CODE

static int drm__vma_info(char *buf, char **start, off_t offset, int request,
D
Dave Airlie 已提交
662
			 int *eof, void *data)
L
Linus Torvalds 已提交
663
{
664 665
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
666
	int len = 0;
667
	struct drm_vma_entry *pt;
L
Linus Torvalds 已提交
668 669
	struct vm_area_struct *vma;
#if defined(__i386__)
D
Dave Airlie 已提交
670
	unsigned int pgprot;
L
Linus Torvalds 已提交
671 672 673 674 675 676 677 678
#endif

	if (offset > DRM_PROC_LIMIT) {
		*eof = 1;
		return 0;
	}

	*start = &buf[offset];
D
Dave Airlie 已提交
679
	*eof = 0;
L
Linus Torvalds 已提交
680 681 682 683

	DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
		       atomic_read(&dev->vma_count),
		       high_memory, virt_to_phys(high_memory));
684
	list_for_each_entry(pt, &dev->vmalist, head) {
D
Dave Airlie 已提交
685 686
		if (!(vma = pt->vma))
			continue;
687
		DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
L
Linus Torvalds 已提交
688 689 690
			       pt->pid,
			       vma->vm_start,
			       vma->vm_end,
D
Dave Airlie 已提交
691 692 693
			       vma->vm_flags & VM_READ ? 'r' : '-',
			       vma->vm_flags & VM_WRITE ? 'w' : '-',
			       vma->vm_flags & VM_EXEC ? 'x' : '-',
L
Linus Torvalds 已提交
694
			       vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
D
Dave Airlie 已提交
695 696
			       vma->vm_flags & VM_LOCKED ? 'l' : '-',
			       vma->vm_flags & VM_IO ? 'i' : '-',
697
			       vma->vm_pgoff);
L
Linus Torvalds 已提交
698 699 700 701

#if defined(__i386__)
		pgprot = pgprot_val(vma->vm_page_prot);
		DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
D
Dave Airlie 已提交
702 703 704 705 706
			       pgprot & _PAGE_PRESENT ? 'p' : '-',
			       pgprot & _PAGE_RW ? 'w' : 'r',
			       pgprot & _PAGE_USER ? 'u' : 's',
			       pgprot & _PAGE_PWT ? 't' : 'b',
			       pgprot & _PAGE_PCD ? 'u' : 'c',
L
Linus Torvalds 已提交
707
			       pgprot & _PAGE_ACCESSED ? 'a' : '-',
D
Dave Airlie 已提交
708 709 710
			       pgprot & _PAGE_DIRTY ? 'd' : '-',
			       pgprot & _PAGE_PSE ? 'm' : 'k',
			       pgprot & _PAGE_GLOBAL ? 'g' : 'l');
L
Linus Torvalds 已提交
711 712 713 714
#endif
		DRM_PROC_PRINT("\n");
	}

D
Dave Airlie 已提交
715 716
	if (len > request + offset)
		return request;
L
Linus Torvalds 已提交
717 718 719 720 721
	*eof = 1;
	return len - offset;
}

static int drm_vma_info(char *buf, char **start, off_t offset, int request,
D
Dave Airlie 已提交
722
			int *eof, void *data)
L
Linus Torvalds 已提交
723
{
724 725
	struct drm_minor *minor = (struct drm_minor *) data;
	struct drm_device *dev = minor->dev;
D
Dave Airlie 已提交
726
	int ret;
L
Linus Torvalds 已提交
727

D
Dave Airlie 已提交
728
	mutex_lock(&dev->struct_mutex);
L
Linus Torvalds 已提交
729
	ret = drm__vma_info(buf, start, offset, request, eof, data);
D
Dave Airlie 已提交
730
	mutex_unlock(&dev->struct_mutex);
L
Linus Torvalds 已提交
731 732 733
	return ret;
}
#endif