drm_stub.c 14.6 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 258 259 260 261 262 263
/**
 * Get a secondary minor number.
 *
 * \param dev device data structure
 * \param sec-minor structure to hold the assigned minor
 * \return negative number on failure.
 *
D
Daniel Vetter 已提交
264 265
 * Search an empty entry and initialize it to the given parameters. This
 * routines assigns minor numbers to secondary heads of multi-headed cards
L
Linus Torvalds 已提交
266
 */
267
int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
L
Linus Torvalds 已提交
268
{
269
	struct drm_minor *new_minor;
L
Linus Torvalds 已提交
270
	int ret;
271
	int minor_id;
L
Linus Torvalds 已提交
272 273 274

	DRM_DEBUG("\n");

275 276 277 278 279 280 281 282 283 284 285 286 287 288
	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;
289
	INIT_LIST_HEAD(&new_minor->master_list);
290 291 292

	idr_replace(&drm_minors_idr, new_minor, minor_id);

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

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

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


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

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

	drm_sysfs_device_remove(minor);
}

/**
 * drm_put_minor - Destroy DRM minor
D
David Herrmann 已提交
346
 * @minor: Minor to destroy
347
 *
D
David Herrmann 已提交
348 349 350
 * 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.
351
 * The global DRM mutex must be held by the caller.
L
Linus Torvalds 已提交
352
 */
D
David Herrmann 已提交
353
static void drm_put_minor(struct drm_minor *minor)
L
Linus Torvalds 已提交
354
{
D
David Herrmann 已提交
355 356
	if (!minor)
		return;
357

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

360 361 362 363
#if defined(CONFIG_DEBUG_FS)
	drm_debugfs_cleanup(minor);
#endif

364
	drm_unplug_minor(minor);
L
Linus Torvalds 已提交
365

366
	idr_remove(&drm_minors_idr, minor->index);
D
Dave Airlie 已提交
367

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

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

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

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

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

477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
/**
 * 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)
{
	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);

500 501 502 503 504 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
/**
 * 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:
D
David Herrmann 已提交
564
	drm_put_minor(dev->primary);
565
err_render_node:
D
David Herrmann 已提交
566
	drm_put_minor(dev->render);
567
err_control_node:
D
David Herrmann 已提交
568
	drm_put_minor(dev->control);
569 570 571 572 573 574 575 576
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);
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602

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

D
David Herrmann 已提交
603 604 605
	drm_put_minor(dev->control);
	drm_put_minor(dev->render);
	drm_put_minor(dev->primary);
606 607 608 609

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