drm_stub.c 14.7 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 102
void drm_ut_debug_printk(unsigned int request_level,
			 const char *prefix,
			 const char *function_name,
			 const char *format, ...)
{
	va_list args;
L
Linus Torvalds 已提交
103

104 105 106 107 108 109 110 111 112
	if (drm_debug & request_level) {
		if (function_name)
			printk(KERN_DEBUG "[%s:%s], ", prefix, function_name);
		va_start(args, format);
		vprintk(format, args);
		va_end(args);
	}
}
EXPORT_SYMBOL(drm_ut_debug_printk);
J
Joe Perches 已提交
113

114 115 116 117 118
static int drm_minor_get_id(struct drm_device *dev, int type)
{
	int ret;
	int base = 0, limit = 63;

D
Dave Airlie 已提交
119
	if (type == DRM_MINOR_CONTROL) {
120 121 122 123 124 125
		base += 64;
		limit = base + 63;
	} else if (type == DRM_MINOR_RENDER) {
		base += 128;
		limit = base + 63;
	}
D
Dave Airlie 已提交
126

127
	mutex_lock(&dev->struct_mutex);
T
Tejun Heo 已提交
128
	ret = idr_alloc(&drm_minors_idr, NULL, base, limit, GFP_KERNEL);
129
	mutex_unlock(&dev->struct_mutex);
T
Tejun Heo 已提交
130 131

	return ret == -ENOSPC ? -EINVAL : ret;
132 133
}

134 135 136 137
struct drm_master *drm_master_create(struct drm_minor *minor)
{
	struct drm_master *master;

138
	master = kzalloc(sizeof(*master), GFP_KERNEL);
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
	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;
}
159
EXPORT_SYMBOL(drm_master_get);
160 161 162 163 164 165

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;
166
	struct drm_map_list *r_list, *list_temp;
167 168 169 170 171 172

	list_del(&master->head);

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

173 174 175 176 177 178 179
	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;
		}
	}

180
	if (master->unique) {
181
		kfree(master->unique);
182 183 184 185
		master->unique = NULL;
		master->unique_len = 0;
	}

186 187 188
	kfree(dev->devname);
	dev->devname = NULL;

189 190 191
	list_for_each_entry_safe(pt, next, &master->magicfree, head) {
		list_del(&pt->head);
		drm_ht_remove_item(&master->magiclist, &pt->hash_item);
192
		kfree(pt);
193 194 195 196
	}

	drm_ht_remove(&master->magiclist);

197
	kfree(master);
198 199 200 201 202 203 204
}

void drm_master_put(struct drm_master **master)
{
	kref_put(&(*master)->refcount, drm_master_destroy);
	*master = NULL;
}
205
EXPORT_SYMBOL(drm_master_put);
206 207 208 209

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

212 213 214
	if (file_priv->is_master)
		return 0;

215 216 217 218 219 220
	if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
		return -EINVAL;

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

221 222 223 224 225 226 227 228 229 230 231
	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);
232
		}
233
	}
234
	mutex_unlock(&dev->struct_mutex);
235

236
	return ret;
237 238 239 240 241
}

int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
{
242
	if (!file_priv->is_master)
243
		return -EINVAL;
244

245 246 247
	if (!file_priv->minor->master)
		return -EINVAL;

248
	mutex_lock(&dev->struct_mutex);
249 250
	if (dev->driver->master_drop)
		dev->driver->master_drop(dev, file_priv, false);
251
	drm_master_put(&file_priv->minor->master);
252
	file_priv->is_master = 0;
253 254 255 256
	mutex_unlock(&dev->struct_mutex);
	return 0;
}

L
Linus Torvalds 已提交
257
/**
D
David Herrmann 已提交
258 259 260 261
 * 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 已提交
262
 *
D
David Herrmann 已提交
263 264 265
 * 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 已提交
266
 *
D
David Herrmann 已提交
267 268
 * RETURNS:
 * 0 on success, negative error code on failure.
L
Linus Torvalds 已提交
269
 */
D
David Herrmann 已提交
270 271
static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor,
			 int type)
L
Linus Torvalds 已提交
272
{
273
	struct drm_minor *new_minor;
L
Linus Torvalds 已提交
274
	int ret;
275
	int minor_id;
L
Linus Torvalds 已提交
276 277 278

	DRM_DEBUG("\n");

279 280 281 282 283 284 285 286 287 288 289 290 291 292
	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;
293
	INIT_LIST_HEAD(&new_minor->master_list);
294 295 296

	idr_replace(&drm_minors_idr, new_minor, minor_id);

297 298 299
#if defined(CONFIG_DEBUG_FS)
	ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root);
	if (ret) {
300
		DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
D
Daniel Vetter 已提交
301
		goto err_mem;
302 303
	}
#endif
304 305 306 307 308

	ret = drm_sysfs_device_add(new_minor);
	if (ret) {
		printk(KERN_ERR
		       "DRM: Error sysfs_device_add.\n");
D
Daniel Vetter 已提交
309
		goto err_debugfs;
L
Linus Torvalds 已提交
310
	}
311 312 313 314 315 316
	*minor = new_minor;

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


D
Daniel Vetter 已提交
317 318 319
err_debugfs:
#if defined(CONFIG_DEBUG_FS)
	drm_debugfs_cleanup(new_minor);
320
err_mem:
D
Daniel Vetter 已提交
321
#endif
322 323 324 325
	kfree(new_minor);
err_idr:
	idr_remove(&drm_minors_idr, minor_id);
	*minor = NULL;
L
Linus Torvalds 已提交
326 327
	return ret;
}
D
Dave Airlie 已提交
328

L
Linus Torvalds 已提交
329
/**
330 331
 * drm_unplug_minor - Unplug DRM minor
 * @minor: Minor to unplug
L
Linus Torvalds 已提交
332
 *
333 334 335 336 337 338 339 340
 * 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)
{
341
	if (!minor || !minor->kdev)
342 343
		return;

344 345 346 347
#if defined(CONFIG_DEBUG_FS)
	drm_debugfs_cleanup(minor);
#endif

348
	drm_sysfs_device_remove(minor);
349
	idr_remove(&drm_minors_idr, minor->index);
350 351 352 353
}

/**
 * drm_put_minor - Destroy DRM minor
D
David Herrmann 已提交
354
 * @minor: Minor to destroy
355
 *
D
David Herrmann 已提交
356 357 358
 * 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.
359
 * The global DRM mutex must be held by the caller.
L
Linus Torvalds 已提交
360
 */
D
David Herrmann 已提交
361
static void drm_put_minor(struct drm_minor *minor)
L
Linus Torvalds 已提交
362
{
D
David Herrmann 已提交
363 364
	if (!minor)
		return;
365

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

368
	drm_unplug_minor(minor);
369
	kfree(minor);
L
Linus Torvalds 已提交
370
}
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387

/**
 * 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;
	}

388
	drm_dev_unregister(dev);
389
	drm_dev_free(dev);
390 391
}
EXPORT_SYMBOL(drm_put_dev);
392 393 394 395 396 397

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);
398 399
	if (dev->render)
		drm_unplug_minor(dev->render);
400 401 402 403 404 405 406 407 408 409 410 411
	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 已提交
412 413 414 415 416 417 418

/**
 * 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.
419 420
 * Call drm_dev_register() to advertice the device to user space and register it
 * with other core subsystems.
D
David Herrmann 已提交
421 422 423 424 425 426 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
 *
 * 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);
477

478 479 480 481 482 483 484 485 486 487 488 489
/**
 * 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)
{
490 491 492 493
	drm_put_minor(dev->control);
	drm_put_minor(dev->render);
	drm_put_minor(dev->primary);

494 495 496 497 498 499 500 501 502 503 504
	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);

505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 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 567 568
/**
 * 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 (dev->driver->bus->agp_init) {
		ret = dev->driver->bus->agp_init(dev);
		if (ret)
			goto out_unlock;
	}

	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
		if (ret)
			goto err_agp;
	}

	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;
	}

	list_add_tail(&dev->driver_item, &dev->driver->device_list);

	ret = 0;
	goto out_unlock;

err_unload:
	if (dev->driver->unload)
		dev->driver->unload(dev);
err_primary_node:
569
	drm_unplug_minor(dev->primary);
570
err_render_node:
571
	drm_unplug_minor(dev->render);
572
err_control_node:
573
	drm_unplug_minor(dev->control);
574 575 576 577 578 579 580 581
err_agp:
	if (dev->driver->bus->agp_destroy)
		dev->driver->bus->agp_destroy(dev);
out_unlock:
	mutex_unlock(&drm_global_mutex);
	return ret;
}
EXPORT_SYMBOL(drm_dev_register);
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607

/**
 * 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);

	if (dev->driver->bus->agp_destroy)
		dev->driver->bus->agp_destroy(dev);

	drm_vblank_cleanup(dev);

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

608 609 610
	drm_unplug_minor(dev->control);
	drm_unplug_minor(dev->render);
	drm_unplug_minor(dev->primary);
611 612 613 614

	list_del(&dev->driver_item);
}
EXPORT_SYMBOL(drm_dev_unregister);