drm_stub.c 14.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 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
/**
 * \file drm_stub.h
 * Stub support
 *
 * \author Rickard E. (Rik) Faith <faith@valinux.com>
 */

/*
 * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
 *
 * Copyright 2001 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
 * PRECISION INSIGHT 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 <linux/module.h>
#include <linux/moduleparam.h>
36
#include <linux/slab.h>
37 38
#include <drm/drmP.h>
#include <drm/drm_core.h>
L
Linus Torvalds 已提交
39

D
Dave Airlie 已提交
40
unsigned int drm_debug = 0;	/* 1 to enable debug output */
L
Linus Torvalds 已提交
41 42
EXPORT_SYMBOL(drm_debug);

43 44 45
unsigned int drm_rnodes = 0;	/* 1 to enable experimental render nodes API */
EXPORT_SYMBOL(drm_rnodes);

46 47 48 49 50 51
unsigned int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
EXPORT_SYMBOL(drm_vblank_offdelay);

unsigned int drm_timestamp_precision = 20;  /* Default to 20 usecs. */
EXPORT_SYMBOL(drm_timestamp_precision);

52 53 54 55 56 57
/*
 * Default to use monotonic timestamps for wait-for-vblank and page-flip
 * complete events.
 */
unsigned int drm_timestamp_monotonic = 1;

D
Dave Airlie 已提交
58 59
MODULE_AUTHOR(CORE_AUTHOR);
MODULE_DESCRIPTION(CORE_DESC);
L
Linus Torvalds 已提交
60 61
MODULE_LICENSE("GPL and additional rights");
MODULE_PARM_DESC(debug, "Enable debug output");
62
MODULE_PARM_DESC(rnodes, "Enable experimental render nodes API");
63 64
MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]");
MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
65
MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
L
Linus Torvalds 已提交
66

67
module_param_named(debug, drm_debug, int, 0600);
68
module_param_named(rnodes, drm_rnodes, int, 0600);
69 70
module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
71
module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
L
Linus Torvalds 已提交
72

73 74
struct idr drm_minors_idr;

75
struct class *drm_class;
76
struct dentry *drm_debugfs_root;
J
Joe Perches 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

int drm_err(const char *func, const char *format, ...)
{
	struct va_format vaf;
	va_list args;
	int r;

	va_start(args, format);

	vaf.fmt = format;
	vaf.va = &args;

	r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);

	va_end(args);

	return r;
}
EXPORT_SYMBOL(drm_err);

97 98 99 100 101
void drm_ut_debug_printk(unsigned int request_level,
			 const char *prefix,
			 const char *function_name,
			 const char *format, ...)
{
D
Daniel Vetter 已提交
102
	struct va_format vaf;
103
	va_list args;
L
Linus Torvalds 已提交
104

105 106
	if (drm_debug & request_level) {
		va_start(args, format);
D
Daniel Vetter 已提交
107 108 109 110 111 112 113 114
		vaf.fmt = format;
		vaf.va = &args;

		if (function_name)
			printk(KERN_DEBUG "[%s:%s], %pV", prefix,
			       function_name, &vaf);
		else
			printk(KERN_DEBUG "%pV", &vaf);
115 116 117 118
		va_end(args);
	}
}
EXPORT_SYMBOL(drm_ut_debug_printk);
J
Joe Perches 已提交
119

120 121 122 123 124
static int drm_minor_get_id(struct drm_device *dev, int type)
{
	int ret;
	int base = 0, limit = 63;

D
Dave Airlie 已提交
125
	if (type == DRM_MINOR_CONTROL) {
126 127 128 129 130 131
		base += 64;
		limit = base + 63;
	} else if (type == DRM_MINOR_RENDER) {
		base += 128;
		limit = base + 63;
	}
D
Dave Airlie 已提交
132

133
	mutex_lock(&dev->struct_mutex);
T
Tejun Heo 已提交
134
	ret = idr_alloc(&drm_minors_idr, NULL, base, limit, GFP_KERNEL);
135
	mutex_unlock(&dev->struct_mutex);
T
Tejun Heo 已提交
136 137

	return ret == -ENOSPC ? -EINVAL : ret;
138 139
}

140 141 142 143
struct drm_master *drm_master_create(struct drm_minor *minor)
{
	struct drm_master *master;

144
	master = kzalloc(sizeof(*master), GFP_KERNEL);
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
	if (!master)
		return NULL;

	kref_init(&master->refcount);
	spin_lock_init(&master->lock.spinlock);
	init_waitqueue_head(&master->lock.lock_queue);
	drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER);
	INIT_LIST_HEAD(&master->magicfree);
	master->minor = minor;

	list_add_tail(&master->head, &minor->master_list);

	return master;
}

struct drm_master *drm_master_get(struct drm_master *master)
{
	kref_get(&master->refcount);
	return master;
}
165
EXPORT_SYMBOL(drm_master_get);
166 167 168 169 170 171

static void drm_master_destroy(struct kref *kref)
{
	struct drm_master *master = container_of(kref, struct drm_master, refcount);
	struct drm_magic_entry *pt, *next;
	struct drm_device *dev = master->minor->dev;
172
	struct drm_map_list *r_list, *list_temp;
173 174 175 176 177 178

	list_del(&master->head);

	if (dev->driver->master_destroy)
		dev->driver->master_destroy(dev, master);

179 180 181 182 183 184 185
	list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) {
		if (r_list->master == master) {
			drm_rmmap_locked(dev, r_list->map);
			r_list = NULL;
		}
	}

186
	if (master->unique) {
187
		kfree(master->unique);
188 189 190 191
		master->unique = NULL;
		master->unique_len = 0;
	}

192 193 194
	kfree(dev->devname);
	dev->devname = NULL;

195 196 197
	list_for_each_entry_safe(pt, next, &master->magicfree, head) {
		list_del(&pt->head);
		drm_ht_remove_item(&master->magiclist, &pt->hash_item);
198
		kfree(pt);
199 200 201 202
	}

	drm_ht_remove(&master->magiclist);

203
	kfree(master);
204 205 206 207 208 209 210
}

void drm_master_put(struct drm_master **master)
{
	kref_put(&(*master)->refcount, drm_master_destroy);
	*master = NULL;
}
211
EXPORT_SYMBOL(drm_master_put);
212 213 214 215

int drm_setmaster_ioctl(struct drm_device *dev, void *data,
			struct drm_file *file_priv)
{
216
	int ret = 0;
217

218 219 220
	if (file_priv->is_master)
		return 0;

221 222 223 224 225 226
	if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
		return -EINVAL;

	if (!file_priv->master)
		return -EINVAL;

227 228 229 230 231 232 233 234 235 236 237
	if (file_priv->minor->master)
		return -EINVAL;

	mutex_lock(&dev->struct_mutex);
	file_priv->minor->master = drm_master_get(file_priv->master);
	file_priv->is_master = 1;
	if (dev->driver->master_set) {
		ret = dev->driver->master_set(dev, file_priv, false);
		if (unlikely(ret != 0)) {
			file_priv->is_master = 0;
			drm_master_put(&file_priv->minor->master);
238
		}
239
	}
240
	mutex_unlock(&dev->struct_mutex);
241

242
	return ret;
243 244 245 246 247
}

int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
{
248
	if (!file_priv->is_master)
249
		return -EINVAL;
250

251 252 253
	if (!file_priv->minor->master)
		return -EINVAL;

254
	mutex_lock(&dev->struct_mutex);
255 256
	if (dev->driver->master_drop)
		dev->driver->master_drop(dev, file_priv, false);
257
	drm_master_put(&file_priv->minor->master);
258
	file_priv->is_master = 0;
259 260 261 262
	mutex_unlock(&dev->struct_mutex);
	return 0;
}

L
Linus Torvalds 已提交
263
/**
D
David Herrmann 已提交
264 265 266 267
 * drm_get_minor - Allocate and register new DRM minor
 * @dev: DRM device
 * @minor: Pointer to where new minor is stored
 * @type: Type of minor
L
Linus Torvalds 已提交
268
 *
D
David Herrmann 已提交
269 270 271
 * Allocate a new minor of the given type and register it. A pointer to the new
 * minor is returned in @minor.
 * Caller must hold the global DRM mutex.
L
Linus Torvalds 已提交
272
 *
D
David Herrmann 已提交
273 274
 * RETURNS:
 * 0 on success, negative error code on failure.
L
Linus Torvalds 已提交
275
 */
D
David Herrmann 已提交
276 277
static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor,
			 int type)
L
Linus Torvalds 已提交
278
{
279
	struct drm_minor *new_minor;
L
Linus Torvalds 已提交
280
	int ret;
281
	int minor_id;
L
Linus Torvalds 已提交
282 283 284

	DRM_DEBUG("\n");

285 286 287 288 289 290 291 292 293 294 295 296 297 298
	minor_id = drm_minor_get_id(dev, type);
	if (minor_id < 0)
		return minor_id;

	new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL);
	if (!new_minor) {
		ret = -ENOMEM;
		goto err_idr;
	}

	new_minor->type = type;
	new_minor->device = MKDEV(DRM_MAJOR, minor_id);
	new_minor->dev = dev;
	new_minor->index = minor_id;
299
	INIT_LIST_HEAD(&new_minor->master_list);
300 301 302

	idr_replace(&drm_minors_idr, new_minor, minor_id);

303 304 305
#if defined(CONFIG_DEBUG_FS)
	ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root);
	if (ret) {
306
		DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
D
Daniel Vetter 已提交
307
		goto err_mem;
308 309
	}
#endif
310 311 312 313 314

	ret = drm_sysfs_device_add(new_minor);
	if (ret) {
		printk(KERN_ERR
		       "DRM: Error sysfs_device_add.\n");
D
Daniel Vetter 已提交
315
		goto err_debugfs;
L
Linus Torvalds 已提交
316
	}
317 318 319 320 321 322
	*minor = new_minor;

	DRM_DEBUG("new minor assigned %d\n", minor_id);
	return 0;


D
Daniel Vetter 已提交
323 324 325
err_debugfs:
#if defined(CONFIG_DEBUG_FS)
	drm_debugfs_cleanup(new_minor);
326
err_mem:
D
Daniel Vetter 已提交
327
#endif
328 329 330 331
	kfree(new_minor);
err_idr:
	idr_remove(&drm_minors_idr, minor_id);
	*minor = NULL;
L
Linus Torvalds 已提交
332 333
	return ret;
}
D
Dave Airlie 已提交
334

L
Linus Torvalds 已提交
335
/**
336 337
 * drm_unplug_minor - Unplug DRM minor
 * @minor: Minor to unplug
L
Linus Torvalds 已提交
338
 *
339 340 341 342 343 344 345 346
 * Unplugs the given DRM minor but keeps the object. So after this returns,
 * minor->dev is still valid so existing open-files can still access it to get
 * device information from their drm_file ojects.
 * If the minor is already unplugged or if @minor is NULL, nothing is done.
 * The global DRM mutex must be held by the caller.
 */
static void drm_unplug_minor(struct drm_minor *minor)
{
347
	if (!minor || !minor->kdev)
348 349
		return;

350 351 352 353
#if defined(CONFIG_DEBUG_FS)
	drm_debugfs_cleanup(minor);
#endif

354
	drm_sysfs_device_remove(minor);
355
	idr_remove(&drm_minors_idr, minor->index);
356 357 358 359
}

/**
 * drm_put_minor - Destroy DRM minor
D
David Herrmann 已提交
360
 * @minor: Minor to destroy
361
 *
D
David Herrmann 已提交
362 363 364
 * This calls drm_unplug_minor() on the given minor and then frees it. Nothing
 * is done if @minor is NULL. It is fine to call this on already unplugged
 * minors.
365
 * The global DRM mutex must be held by the caller.
L
Linus Torvalds 已提交
366
 */
D
David Herrmann 已提交
367
static void drm_put_minor(struct drm_minor *minor)
L
Linus Torvalds 已提交
368
{
D
David Herrmann 已提交
369 370
	if (!minor)
		return;
371

372
	DRM_DEBUG("release secondary minor %d\n", minor->index);
D
Dave Airlie 已提交
373

374
	drm_unplug_minor(minor);
375
	kfree(minor);
L
Linus Torvalds 已提交
376
}
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393

/**
 * Called via drm_exit() at module unload time or when pci device is
 * unplugged.
 *
 * Cleans up all DRM device, calling drm_lastclose().
 *
 */
void drm_put_dev(struct drm_device *dev)
{
	DRM_DEBUG("\n");

	if (!dev) {
		DRM_ERROR("cleanup called no dev\n");
		return;
	}

394
	drm_dev_unregister(dev);
395
	drm_dev_free(dev);
396 397
}
EXPORT_SYMBOL(drm_put_dev);
398 399 400 401 402 403

void drm_unplug_dev(struct drm_device *dev)
{
	/* for a USB device */
	if (drm_core_check_feature(dev, DRIVER_MODESET))
		drm_unplug_minor(dev->control);
404 405
	if (dev->render)
		drm_unplug_minor(dev->render);
406 407 408 409 410 411 412 413 414 415 416 417
	drm_unplug_minor(dev->primary);

	mutex_lock(&drm_global_mutex);

	drm_device_set_unplugged(dev);

	if (dev->open_count == 0) {
		drm_put_dev(dev);
	}
	mutex_unlock(&drm_global_mutex);
}
EXPORT_SYMBOL(drm_unplug_dev);
D
David Herrmann 已提交
418 419 420 421 422 423 424

/**
 * drm_dev_alloc - Allocate new drm device
 * @driver: DRM driver to allocate device for
 * @parent: Parent device object
 *
 * Allocate and initialize a new DRM device. No device registration is done.
425 426
 * Call drm_dev_register() to advertice the device to user space and register it
 * with other core subsystems.
D
David Herrmann 已提交
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
 *
 * RETURNS:
 * Pointer to new DRM device, or NULL if out of memory.
 */
struct drm_device *drm_dev_alloc(struct drm_driver *driver,
				 struct device *parent)
{
	struct drm_device *dev;
	int ret;

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev)
		return NULL;

	dev->dev = parent;
	dev->driver = driver;

	INIT_LIST_HEAD(&dev->filelist);
	INIT_LIST_HEAD(&dev->ctxlist);
	INIT_LIST_HEAD(&dev->vmalist);
	INIT_LIST_HEAD(&dev->maplist);
	INIT_LIST_HEAD(&dev->vblank_event_list);

	spin_lock_init(&dev->count_lock);
	spin_lock_init(&dev->event_lock);
	mutex_init(&dev->struct_mutex);
	mutex_init(&dev->ctxlist_mutex);

	if (drm_ht_create(&dev->map_hash, 12))
		goto err_free;

	ret = drm_ctxbitmap_init(dev);
	if (ret) {
		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
		goto err_ht;
	}

	if (driver->driver_features & DRIVER_GEM) {
		ret = drm_gem_init(dev);
		if (ret) {
			DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n");
			goto err_ctxbitmap;
		}
	}

	return dev;

err_ctxbitmap:
	drm_ctxbitmap_cleanup(dev);
err_ht:
	drm_ht_remove(&dev->map_hash);
err_free:
	kfree(dev);
	return NULL;
}
EXPORT_SYMBOL(drm_dev_alloc);
483

484 485 486 487 488 489 490 491 492 493 494 495
/**
 * drm_dev_free - Free DRM device
 * @dev: DRM device to free
 *
 * Free a DRM device that has previously been allocated via drm_dev_alloc().
 * You must not use kfree() instead or you will leak memory.
 *
 * This must not be called once the device got registered. Use drm_put_dev()
 * instead, which then calls drm_dev_free().
 */
void drm_dev_free(struct drm_device *dev)
{
496 497 498 499
	drm_put_minor(dev->control);
	drm_put_minor(dev->render);
	drm_put_minor(dev->primary);

500 501 502 503 504 505 506 507 508 509 510
	if (dev->driver->driver_features & DRIVER_GEM)
		drm_gem_destroy(dev);

	drm_ctxbitmap_cleanup(dev);
	drm_ht_remove(&dev->map_hash);

	kfree(dev->devname);
	kfree(dev);
}
EXPORT_SYMBOL(drm_dev_free);

511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
/**
 * drm_dev_register - Register DRM device
 * @dev: Device to register
 *
 * Register the DRM device @dev with the system, advertise device to user-space
 * and start normal device operation. @dev must be allocated via drm_dev_alloc()
 * previously.
 *
 * Never call this twice on any device!
 *
 * RETURNS:
 * 0 on success, negative error code on failure.
 */
int drm_dev_register(struct drm_device *dev, unsigned long flags)
{
	int ret;

	mutex_lock(&drm_global_mutex);

	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
		if (ret)
533
			goto out_unlock;
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
	}

	if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) {
		ret = drm_get_minor(dev, &dev->render, DRM_MINOR_RENDER);
		if (ret)
			goto err_control_node;
	}

	ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY);
	if (ret)
		goto err_render_node;

	if (dev->driver->load) {
		ret = dev->driver->load(dev, flags);
		if (ret)
			goto err_primary_node;
	}

	/* setup grouping for legacy outputs */
	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		ret = drm_mode_group_init_legacy_group(dev,
				&dev->primary->mode_group);
		if (ret)
			goto err_unload;
	}

	ret = 0;
	goto out_unlock;

err_unload:
	if (dev->driver->unload)
		dev->driver->unload(dev);
err_primary_node:
567
	drm_unplug_minor(dev->primary);
568
err_render_node:
569
	drm_unplug_minor(dev->render);
570
err_control_node:
571
	drm_unplug_minor(dev->control);
572 573 574 575 576
out_unlock:
	mutex_unlock(&drm_global_mutex);
	return ret;
}
EXPORT_SYMBOL(drm_dev_register);
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594

/**
 * drm_dev_unregister - Unregister DRM device
 * @dev: Device to unregister
 *
 * Unregister the DRM device from the system. This does the reverse of
 * drm_dev_register() but does not deallocate the device. The caller must call
 * drm_dev_free() to free all resources.
 */
void drm_dev_unregister(struct drm_device *dev)
{
	struct drm_map_list *r_list, *list_temp;

	drm_lastclose(dev);

	if (dev->driver->unload)
		dev->driver->unload(dev);

595 596
	if (dev->agp)
		drm_pci_agp_destroy(dev);
597 598 599 600 601 602

	drm_vblank_cleanup(dev);

	list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
		drm_rmmap(dev, r_list->map);

603 604 605
	drm_unplug_minor(dev->control);
	drm_unplug_minor(dev->render);
	drm_unplug_minor(dev->primary);
606 607
}
EXPORT_SYMBOL(drm_dev_unregister);