drm_context.c 14.8 KB
Newer Older
L
Linus Torvalds 已提交
1
/**
D
Dave Airlie 已提交
2
 * \file drm_context.c
L
Linus Torvalds 已提交
3
 * IOCTLs for generic contexts
D
Dave Airlie 已提交
4
 *
L
Linus Torvalds 已提交
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
 * \author Rickard E. (Rik) Faith <faith@valinux.com>
 * \author Gareth Hughes <gareth@valinux.com>
 */

/*
 * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
 *
 * Copyright 1999, 2000 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.
 */

/*
 * ChangeLog:
 *  2001-11-16	Torsten Duwe <duwe@caldera.de>
 *		added context constructor/destructor hooks,
 *		needed by SiS driver's memory management.
 */

#include "drmP.h"

/******************************************************************/
/** \name Context bitmap support */
/*@{*/

/**
 * Free a handle from the context bitmap.
 *
 * \param dev DRM device.
 * \param ctx_handle context handle.
 *
 * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
 * in drm_device::context_sareas, while holding the drm_device::struct_sem
 * lock.
 */
D
Dave Airlie 已提交
59
void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
L
Linus Torvalds 已提交
60
{
D
Dave Airlie 已提交
61 62 63 64
	if (ctx_handle < 0)
		goto failed;
	if (!dev->ctx_bitmap)
		goto failed;
L
Linus Torvalds 已提交
65

D
Dave Airlie 已提交
66
	if (ctx_handle < DRM_MAX_CTXBITMAP) {
L
Linus Torvalds 已提交
67
		down(&dev->struct_sem);
D
Dave Airlie 已提交
68
		clear_bit(ctx_handle, dev->ctx_bitmap);
L
Linus Torvalds 已提交
69 70 71 72
		dev->context_sareas[ctx_handle] = NULL;
		up(&dev->struct_sem);
		return;
	}
D
Dave Airlie 已提交
73 74 75
      failed:
	DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle);
	return;
L
Linus Torvalds 已提交
76 77
}

D
Dave Airlie 已提交
78
/**
L
Linus Torvalds 已提交
79 80 81 82 83 84 85 86 87
 * Context bitmap allocation.
 *
 * \param dev DRM device.
 * \return (non-negative) context handle on success or a negative number on failure.
 *
 * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates
 * drm_device::context_sareas to accommodate the new entry while holding the
 * drm_device::struct_sem lock.
 */
D
Dave Airlie 已提交
88
static int drm_ctxbitmap_next(drm_device_t * dev)
L
Linus Torvalds 已提交
89 90 91
{
	int bit;

D
Dave Airlie 已提交
92 93
	if (!dev->ctx_bitmap)
		return -1;
L
Linus Torvalds 已提交
94 95

	down(&dev->struct_sem);
D
Dave Airlie 已提交
96 97 98 99 100 101 102
	bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
	if (bit < DRM_MAX_CTXBITMAP) {
		set_bit(bit, dev->ctx_bitmap);
		DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit);
		if ((bit + 1) > dev->max_context) {
			dev->max_context = (bit + 1);
			if (dev->context_sareas) {
L
Linus Torvalds 已提交
103 104 105
				drm_map_t **ctx_sareas;

				ctx_sareas = drm_realloc(dev->context_sareas,
D
Dave Airlie 已提交
106 107 108 109 110 111 112 113 114
							 (dev->max_context -
							  1) *
							 sizeof(*dev->
								context_sareas),
							 dev->max_context *
							 sizeof(*dev->
								context_sareas),
							 DRM_MEM_MAPS);
				if (!ctx_sareas) {
L
Linus Torvalds 已提交
115 116 117 118 119 120 121 122
					clear_bit(bit, dev->ctx_bitmap);
					up(&dev->struct_sem);
					return -1;
				}
				dev->context_sareas = ctx_sareas;
				dev->context_sareas[bit] = NULL;
			} else {
				/* max_context == 1 at this point */
D
Dave Airlie 已提交
123 124 125 126 127
				dev->context_sareas =
				    drm_alloc(dev->max_context *
					      sizeof(*dev->context_sareas),
					      DRM_MEM_MAPS);
				if (!dev->context_sareas) {
L
Linus Torvalds 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
					clear_bit(bit, dev->ctx_bitmap);
					up(&dev->struct_sem);
					return -1;
				}
				dev->context_sareas[bit] = NULL;
			}
		}
		up(&dev->struct_sem);
		return bit;
	}
	up(&dev->struct_sem);
	return -1;
}

/**
 * Context bitmap initialization.
 *
 * \param dev DRM device.
 *
 * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding
 * the drm_device::struct_sem lock.
 */
D
Dave Airlie 已提交
150
int drm_ctxbitmap_init(drm_device_t * dev)
L
Linus Torvalds 已提交
151 152
{
	int i;
D
Dave Airlie 已提交
153
	int temp;
L
Linus Torvalds 已提交
154 155

	down(&dev->struct_sem);
D
Dave Airlie 已提交
156 157 158
	dev->ctx_bitmap = (unsigned long *)drm_alloc(PAGE_SIZE,
						     DRM_MEM_CTXBITMAP);
	if (dev->ctx_bitmap == NULL) {
L
Linus Torvalds 已提交
159 160 161
		up(&dev->struct_sem);
		return -ENOMEM;
	}
D
Dave Airlie 已提交
162
	memset((void *)dev->ctx_bitmap, 0, PAGE_SIZE);
L
Linus Torvalds 已提交
163 164 165 166
	dev->context_sareas = NULL;
	dev->max_context = -1;
	up(&dev->struct_sem);

D
Dave Airlie 已提交
167 168 169
	for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
		temp = drm_ctxbitmap_next(dev);
		DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
L
Linus Torvalds 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182
	}

	return 0;
}

/**
 * Context bitmap cleanup.
 *
 * \param dev DRM device.
 *
 * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding
 * the drm_device::struct_sem lock.
 */
D
Dave Airlie 已提交
183
void drm_ctxbitmap_cleanup(drm_device_t * dev)
L
Linus Torvalds 已提交
184 185
{
	down(&dev->struct_sem);
D
Dave Airlie 已提交
186 187 188 189 190
	if (dev->context_sareas)
		drm_free(dev->context_sareas,
			 sizeof(*dev->context_sareas) *
			 dev->max_context, DRM_MEM_MAPS);
	drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP);
L
Linus Torvalds 已提交
191 192 193 194 195 196 197 198 199 200 201
	up(&dev->struct_sem);
}

/*@}*/

/******************************************************************/
/** \name Per Context SAREA Support */
/*@{*/

/**
 * Get per-context SAREA.
D
Dave Airlie 已提交
202
 *
L
Linus Torvalds 已提交
203 204 205 206 207 208 209 210 211 212
 * \param inode device inode.
 * \param filp file pointer.
 * \param cmd command.
 * \param arg user argument pointing to a drm_ctx_priv_map structure.
 * \return zero on success or a negative number on failure.
 *
 * Gets the map from drm_device::context_sareas with the handle specified and
 * returns its handle.
 */
int drm_getsareactx(struct inode *inode, struct file *filp,
D
Dave Airlie 已提交
213
		    unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
214
{
D
Dave Airlie 已提交
215 216
	drm_file_t *priv = filp->private_data;
	drm_device_t *dev = priv->head->dev;
L
Linus Torvalds 已提交
217 218 219
	drm_ctx_priv_map_t __user *argp = (void __user *)arg;
	drm_ctx_priv_map_t request;
	drm_map_t *map;
220
	drm_map_list_t *_entry;
L
Linus Torvalds 已提交
221 222 223 224 225

	if (copy_from_user(&request, argp, sizeof(request)))
		return -EFAULT;

	down(&dev->struct_sem);
D
Dave Airlie 已提交
226 227
	if (dev->max_context < 0
	    || request.ctx_id >= (unsigned)dev->max_context) {
L
Linus Torvalds 已提交
228 229 230 231 232 233 234
		up(&dev->struct_sem);
		return -EINVAL;
	}

	map = dev->context_sareas[request.ctx_id];
	up(&dev->struct_sem);

235
	request.handle = 0;
D
Dave Airlie 已提交
236
	list_for_each_entry(_entry, &dev->maplist->head, head) {
237
		if (_entry->map == map) {
D
Dave Airlie 已提交
238 239
			request.handle =
			    (void *)(unsigned long)_entry->user_token;
240 241 242 243 244 245
			break;
		}
	}
	if (request.handle == 0)
		return -EINVAL;

L
Linus Torvalds 已提交
246 247 248 249 250 251 252
	if (copy_to_user(argp, &request, sizeof(request)))
		return -EFAULT;
	return 0;
}

/**
 * Set per-context SAREA.
D
Dave Airlie 已提交
253
 *
L
Linus Torvalds 已提交
254 255 256 257 258 259 260 261 262 263
 * \param inode device inode.
 * \param filp file pointer.
 * \param cmd command.
 * \param arg user argument pointing to a drm_ctx_priv_map structure.
 * \return zero on success or a negative number on failure.
 *
 * Searches the mapping specified in \p arg and update the entry in
 * drm_device::context_sareas with it.
 */
int drm_setsareactx(struct inode *inode, struct file *filp,
D
Dave Airlie 已提交
264
		    unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
265
{
D
Dave Airlie 已提交
266 267
	drm_file_t *priv = filp->private_data;
	drm_device_t *dev = priv->head->dev;
L
Linus Torvalds 已提交
268 269 270 271 272 273
	drm_ctx_priv_map_t request;
	drm_map_t *map = NULL;
	drm_map_list_t *r_list = NULL;
	struct list_head *list;

	if (copy_from_user(&request,
D
Dave Airlie 已提交
274
			   (drm_ctx_priv_map_t __user *) arg, sizeof(request)))
L
Linus Torvalds 已提交
275 276 277 278 279
		return -EFAULT;

	down(&dev->struct_sem);
	list_for_each(list, &dev->maplist->head) {
		r_list = list_entry(list, drm_map_list_t, head);
280
		if (r_list->map
D
Dave Airlie 已提交
281
		    && r_list->user_token == (unsigned long)request.handle)
L
Linus Torvalds 已提交
282 283
			goto found;
	}
D
Dave Airlie 已提交
284
      bad:
L
Linus Torvalds 已提交
285 286 287
	up(&dev->struct_sem);
	return -EINVAL;

D
Dave Airlie 已提交
288
      found:
L
Linus Torvalds 已提交
289
	map = r_list->map;
D
Dave Airlie 已提交
290 291
	if (!map)
		goto bad;
L
Linus Torvalds 已提交
292 293
	if (dev->max_context < 0)
		goto bad;
D
Dave Airlie 已提交
294
	if (request.ctx_id >= (unsigned)dev->max_context)
L
Linus Torvalds 已提交
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
		goto bad;
	dev->context_sareas[request.ctx_id] = map;
	up(&dev->struct_sem);
	return 0;
}

/*@}*/

/******************************************************************/
/** \name The actual DRM context handling routines */
/*@{*/

/**
 * Switch context.
 *
 * \param dev DRM device.
 * \param old old context handle.
 * \param new new context handle.
 * \return zero on success or a negative number on failure.
 *
 * Attempt to set drm_device::context_flag.
 */
D
Dave Airlie 已提交
317
static int drm_context_switch(drm_device_t * dev, int old, int new)
L
Linus Torvalds 已提交
318
{
D
Dave Airlie 已提交
319 320 321 322
	if (test_and_set_bit(0, &dev->context_flag)) {
		DRM_ERROR("Reentering -- FIXME\n");
		return -EBUSY;
	}
L
Linus Torvalds 已提交
323

D
Dave Airlie 已提交
324
	DRM_DEBUG("Context switch from %d to %d\n", old, new);
L
Linus Torvalds 已提交
325

D
Dave Airlie 已提交
326 327 328 329
	if (new == dev->last_context) {
		clear_bit(0, &dev->context_flag);
		return 0;
	}
L
Linus Torvalds 已提交
330

D
Dave Airlie 已提交
331
	return 0;
L
Linus Torvalds 已提交
332 333 334 335 336 337 338 339 340 341 342 343 344
}

/**
 * Complete context switch.
 *
 * \param dev DRM device.
 * \param new new context handle.
 * \return zero on success or a negative number on failure.
 *
 * Updates drm_device::last_context and drm_device::last_switch. Verifies the
 * hardware lock is held, clears the drm_device::context_flag and wakes up
 * drm_device::context_wait.
 */
D
Dave Airlie 已提交
345
static int drm_context_switch_complete(drm_device_t * dev, int new)
L
Linus Torvalds 已提交
346
{
D
Dave Airlie 已提交
347 348
	dev->last_context = new;	/* PRE/POST: This is the _only_ writer. */
	dev->last_switch = jiffies;
L
Linus Torvalds 已提交
349

D
Dave Airlie 已提交
350 351 352
	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
		DRM_ERROR("Lock isn't held after context switch\n");
	}
L
Linus Torvalds 已提交
353

D
Dave Airlie 已提交
354 355 356 357 358
	/* If a context switch is ever initiated
	   when the kernel holds the lock, release
	   that lock here. */
	clear_bit(0, &dev->context_flag);
	wake_up(&dev->context_wait);
L
Linus Torvalds 已提交
359

D
Dave Airlie 已提交
360
	return 0;
L
Linus Torvalds 已提交
361 362 363 364 365 366 367 368 369 370 371
}

/**
 * Reserve contexts.
 *
 * \param inode device inode.
 * \param filp file pointer.
 * \param cmd command.
 * \param arg user argument pointing to a drm_ctx_res structure.
 * \return zero on success or a negative number on failure.
 */
D
Dave Airlie 已提交
372 373
int drm_resctx(struct inode *inode, struct file *filp,
	       unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
374 375 376 377 378 379
{
	drm_ctx_res_t res;
	drm_ctx_t __user *argp = (void __user *)arg;
	drm_ctx_t ctx;
	int i;

D
Dave Airlie 已提交
380
	if (copy_from_user(&res, argp, sizeof(res)))
L
Linus Torvalds 已提交
381 382
		return -EFAULT;

D
Dave Airlie 已提交
383 384 385
	if (res.count >= DRM_RESERVED_CONTEXTS) {
		memset(&ctx, 0, sizeof(ctx));
		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
L
Linus Torvalds 已提交
386
			ctx.handle = i;
D
Dave Airlie 已提交
387
			if (copy_to_user(&res.contexts[i], &ctx, sizeof(ctx)))
L
Linus Torvalds 已提交
388 389 390 391 392
				return -EFAULT;
		}
	}
	res.count = DRM_RESERVED_CONTEXTS;

D
Dave Airlie 已提交
393
	if (copy_to_user(argp, &res, sizeof(res)))
L
Linus Torvalds 已提交
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
		return -EFAULT;
	return 0;
}

/**
 * Add context.
 *
 * \param inode device inode.
 * \param filp file pointer.
 * \param cmd command.
 * \param arg user argument pointing to a drm_ctx structure.
 * \return zero on success or a negative number on failure.
 *
 * Get a new handle for the context and copy to userspace.
 */
D
Dave Airlie 已提交
409 410
int drm_addctx(struct inode *inode, struct file *filp,
	       unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
411 412 413
{
	drm_file_t *priv = filp->private_data;
	drm_device_t *dev = priv->head->dev;
D
Dave Airlie 已提交
414
	drm_ctx_list_t *ctx_entry;
L
Linus Torvalds 已提交
415 416 417
	drm_ctx_t __user *argp = (void __user *)arg;
	drm_ctx_t ctx;

D
Dave Airlie 已提交
418
	if (copy_from_user(&ctx, argp, sizeof(ctx)))
L
Linus Torvalds 已提交
419 420
		return -EFAULT;

D
Dave Airlie 已提交
421 422 423 424
	ctx.handle = drm_ctxbitmap_next(dev);
	if (ctx.handle == DRM_KERNEL_CONTEXT) {
		/* Skip kernel's context and get a new one. */
		ctx.handle = drm_ctxbitmap_next(dev);
L
Linus Torvalds 已提交
425
	}
D
Dave Airlie 已提交
426 427 428 429
	DRM_DEBUG("%d\n", ctx.handle);
	if (ctx.handle == -1) {
		DRM_DEBUG("Not enough free contexts.\n");
		/* Should this return -EBUSY instead? */
L
Linus Torvalds 已提交
430 431 432
		return -ENOMEM;
	}

D
Dave Airlie 已提交
433
	if (ctx.handle != DRM_KERNEL_CONTEXT) {
L
Linus Torvalds 已提交
434 435 436 437
		if (dev->driver->context_ctor)
			dev->driver->context_ctor(dev, ctx.handle);
	}

D
Dave Airlie 已提交
438 439
	ctx_entry = drm_alloc(sizeof(*ctx_entry), DRM_MEM_CTXLIST);
	if (!ctx_entry) {
L
Linus Torvalds 已提交
440 441 442 443
		DRM_DEBUG("out of memory\n");
		return -ENOMEM;
	}

D
Dave Airlie 已提交
444
	INIT_LIST_HEAD(&ctx_entry->head);
L
Linus Torvalds 已提交
445 446 447
	ctx_entry->handle = ctx.handle;
	ctx_entry->tag = priv;

D
Dave Airlie 已提交
448 449
	down(&dev->ctxlist_sem);
	list_add(&ctx_entry->head, &dev->ctxlist->head);
L
Linus Torvalds 已提交
450
	++dev->ctx_count;
D
Dave Airlie 已提交
451
	up(&dev->ctxlist_sem);
L
Linus Torvalds 已提交
452

D
Dave Airlie 已提交
453
	if (copy_to_user(argp, &ctx, sizeof(ctx)))
L
Linus Torvalds 已提交
454 455 456 457
		return -EFAULT;
	return 0;
}

D
Dave Airlie 已提交
458 459
int drm_modctx(struct inode *inode, struct file *filp,
	       unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
460 461 462 463 464 465 466 467 468 469 470 471 472 473
{
	/* This does nothing */
	return 0;
}

/**
 * Get context.
 *
 * \param inode device inode.
 * \param filp file pointer.
 * \param cmd command.
 * \param arg user argument pointing to a drm_ctx structure.
 * \return zero on success or a negative number on failure.
 */
D
Dave Airlie 已提交
474 475
int drm_getctx(struct inode *inode, struct file *filp,
	       unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
476 477 478 479
{
	drm_ctx_t __user *argp = (void __user *)arg;
	drm_ctx_t ctx;

D
Dave Airlie 已提交
480
	if (copy_from_user(&ctx, argp, sizeof(ctx)))
L
Linus Torvalds 已提交
481 482 483 484 485
		return -EFAULT;

	/* This is 0, because we don't handle any context flags */
	ctx.flags = 0;

D
Dave Airlie 已提交
486
	if (copy_to_user(argp, &ctx, sizeof(ctx)))
L
Linus Torvalds 已提交
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
		return -EFAULT;
	return 0;
}

/**
 * Switch context.
 *
 * \param inode device inode.
 * \param filp file pointer.
 * \param cmd command.
 * \param arg user argument pointing to a drm_ctx structure.
 * \return zero on success or a negative number on failure.
 *
 * Calls context_switch().
 */
D
Dave Airlie 已提交
502 503
int drm_switchctx(struct inode *inode, struct file *filp,
		  unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
504 505 506 507 508
{
	drm_file_t *priv = filp->private_data;
	drm_device_t *dev = priv->head->dev;
	drm_ctx_t ctx;

D
Dave Airlie 已提交
509
	if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx)))
L
Linus Torvalds 已提交
510 511
		return -EFAULT;

D
Dave Airlie 已提交
512 513
	DRM_DEBUG("%d\n", ctx.handle);
	return drm_context_switch(dev, dev->last_context, ctx.handle);
L
Linus Torvalds 已提交
514 515 516 517 518 519 520 521 522 523 524 525 526
}

/**
 * New context.
 *
 * \param inode device inode.
 * \param filp file pointer.
 * \param cmd command.
 * \param arg user argument pointing to a drm_ctx structure.
 * \return zero on success or a negative number on failure.
 *
 * Calls context_switch_complete().
 */
D
Dave Airlie 已提交
527 528
int drm_newctx(struct inode *inode, struct file *filp,
	       unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
529 530 531 532 533
{
	drm_file_t *priv = filp->private_data;
	drm_device_t *dev = priv->head->dev;
	drm_ctx_t ctx;

D
Dave Airlie 已提交
534
	if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx)))
L
Linus Torvalds 已提交
535 536
		return -EFAULT;

D
Dave Airlie 已提交
537 538
	DRM_DEBUG("%d\n", ctx.handle);
	drm_context_switch_complete(dev, ctx.handle);
L
Linus Torvalds 已提交
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553

	return 0;
}

/**
 * Remove context.
 *
 * \param inode device inode.
 * \param filp file pointer.
 * \param cmd command.
 * \param arg user argument pointing to a drm_ctx structure.
 * \return zero on success or a negative number on failure.
 *
 * If not the special kernel context, calls ctxbitmap_free() to free the specified context.
 */
D
Dave Airlie 已提交
554 555
int drm_rmctx(struct inode *inode, struct file *filp,
	      unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
556 557 558 559 560
{
	drm_file_t *priv = filp->private_data;
	drm_device_t *dev = priv->head->dev;
	drm_ctx_t ctx;

D
Dave Airlie 已提交
561
	if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx)))
L
Linus Torvalds 已提交
562 563
		return -EFAULT;

D
Dave Airlie 已提交
564 565
	DRM_DEBUG("%d\n", ctx.handle);
	if (ctx.handle == DRM_KERNEL_CONTEXT + 1) {
L
Linus Torvalds 已提交
566 567
		priv->remove_auth_on_close = 1;
	}
D
Dave Airlie 已提交
568
	if (ctx.handle != DRM_KERNEL_CONTEXT) {
L
Linus Torvalds 已提交
569 570
		if (dev->driver->context_dtor)
			dev->driver->context_dtor(dev, ctx.handle);
D
Dave Airlie 已提交
571
		drm_ctxbitmap_free(dev, ctx.handle);
L
Linus Torvalds 已提交
572 573
	}

D
Dave Airlie 已提交
574 575
	down(&dev->ctxlist_sem);
	if (!list_empty(&dev->ctxlist->head)) {
L
Linus Torvalds 已提交
576 577
		drm_ctx_list_t *pos, *n;

D
Dave Airlie 已提交
578 579 580 581
		list_for_each_entry_safe(pos, n, &dev->ctxlist->head, head) {
			if (pos->handle == ctx.handle) {
				list_del(&pos->head);
				drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);
L
Linus Torvalds 已提交
582 583 584 585
				--dev->ctx_count;
			}
		}
	}
D
Dave Airlie 已提交
586
	up(&dev->ctxlist_sem);
L
Linus Torvalds 已提交
587 588 589 590 591

	return 0;
}

/*@}*/