Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
drm_context.c
Go to the documentation of this file.
1 
9 /*
10  * Created: Fri Nov 24 18:31:37 2000 by [email protected]
11  *
12  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
13  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
14  * All Rights Reserved.
15  *
16  * Permission is hereby granted, free of charge, to any person obtaining a
17  * copy of this software and associated documentation files (the "Software"),
18  * to deal in the Software without restriction, including without limitation
19  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20  * and/or sell copies of the Software, and to permit persons to whom the
21  * Software is furnished to do so, subject to the following conditions:
22  *
23  * The above copyright notice and this permission notice (including the next
24  * paragraph) shall be included in all copies or substantial portions of the
25  * Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
31  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
32  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33  * OTHER DEALINGS IN THE SOFTWARE.
34  */
35 
36 /*
37  * ChangeLog:
38  * 2001-11-16 Torsten Duwe <[email protected]>
39  * added context constructor/destructor hooks,
40  * needed by SiS driver's memory management.
41  */
42 
43 #include <drm/drmP.h>
44 
45 /******************************************************************/
48 
59 void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
60 {
61  mutex_lock(&dev->struct_mutex);
62  idr_remove(&dev->ctx_idr, ctx_handle);
63  mutex_unlock(&dev->struct_mutex);
64 }
65 
75 static int drm_ctxbitmap_next(struct drm_device * dev)
76 {
77  int new_id;
78  int ret;
79 
80 again:
81  if (idr_pre_get(&dev->ctx_idr, GFP_KERNEL) == 0) {
82  DRM_ERROR("Out of memory expanding drawable idr\n");
83  return -ENOMEM;
84  }
85  mutex_lock(&dev->struct_mutex);
86  ret = idr_get_new_above(&dev->ctx_idr, NULL,
87  DRM_RESERVED_CONTEXTS, &new_id);
88  mutex_unlock(&dev->struct_mutex);
89  if (ret == -EAGAIN)
90  goto again;
91  else if (ret)
92  return ret;
93 
94  return new_id;
95 }
96 
105 {
106  idr_init(&dev->ctx_idr);
107  return 0;
108 }
109 
119 {
120  mutex_lock(&dev->struct_mutex);
121  idr_remove_all(&dev->ctx_idr);
122  mutex_unlock(&dev->struct_mutex);
123 }
124 
127 /******************************************************************/
130 
143 int drm_getsareactx(struct drm_device *dev, void *data,
144  struct drm_file *file_priv)
145 {
146  struct drm_ctx_priv_map *request = data;
147  struct drm_local_map *map;
148  struct drm_map_list *_entry;
149 
150  mutex_lock(&dev->struct_mutex);
151 
152  map = idr_find(&dev->ctx_idr, request->ctx_id);
153  if (!map) {
154  mutex_unlock(&dev->struct_mutex);
155  return -EINVAL;
156  }
157 
158  request->handle = NULL;
159  list_for_each_entry(_entry, &dev->maplist, head) {
160  if (_entry->map == map) {
161  request->handle =
162  (void *)(unsigned long)_entry->user_token;
163  break;
164  }
165  }
166 
167  mutex_unlock(&dev->struct_mutex);
168 
169  if (request->handle == NULL)
170  return -EINVAL;
171 
172  return 0;
173 }
174 
187 int drm_setsareactx(struct drm_device *dev, void *data,
188  struct drm_file *file_priv)
189 {
190  struct drm_ctx_priv_map *request = data;
191  struct drm_local_map *map = NULL;
192  struct drm_map_list *r_list = NULL;
193 
194  mutex_lock(&dev->struct_mutex);
195  list_for_each_entry(r_list, &dev->maplist, head) {
196  if (r_list->map
197  && r_list->user_token == (unsigned long) request->handle)
198  goto found;
199  }
200  bad:
201  mutex_unlock(&dev->struct_mutex);
202  return -EINVAL;
203 
204  found:
205  map = r_list->map;
206  if (!map)
207  goto bad;
208 
209  if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id)))
210  goto bad;
211 
212  mutex_unlock(&dev->struct_mutex);
213 
214  return 0;
215 }
216 
219 /******************************************************************/
222 
233 static int drm_context_switch(struct drm_device * dev, int old, int new)
234 {
235  if (test_and_set_bit(0, &dev->context_flag)) {
236  DRM_ERROR("Reentering -- FIXME\n");
237  return -EBUSY;
238  }
239 
240  DRM_DEBUG("Context switch from %d to %d\n", old, new);
241 
242  if (new == dev->last_context) {
243  clear_bit(0, &dev->context_flag);
244  return 0;
245  }
246 
247  return 0;
248 }
249 
261 static int drm_context_switch_complete(struct drm_device *dev,
262  struct drm_file *file_priv, int new)
263 {
264  dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
265  dev->last_switch = jiffies;
266 
267  if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) {
268  DRM_ERROR("Lock isn't held after context switch\n");
269  }
270 
271  /* If a context switch is ever initiated
272  when the kernel holds the lock, release
273  that lock here. */
274  clear_bit(0, &dev->context_flag);
275  wake_up(&dev->context_wait);
276 
277  return 0;
278 }
279 
289 int drm_resctx(struct drm_device *dev, void *data,
290  struct drm_file *file_priv)
291 {
292  struct drm_ctx_res *res = data;
293  struct drm_ctx ctx;
294  int i;
295 
296  if (res->count >= DRM_RESERVED_CONTEXTS) {
297  memset(&ctx, 0, sizeof(ctx));
298  for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
299  ctx.handle = i;
300  if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx)))
301  return -EFAULT;
302  }
303  }
304  res->count = DRM_RESERVED_CONTEXTS;
305 
306  return 0;
307 }
308 
320 int drm_addctx(struct drm_device *dev, void *data,
321  struct drm_file *file_priv)
322 {
323  struct drm_ctx_list *ctx_entry;
324  struct drm_ctx *ctx = data;
325 
326  ctx->handle = drm_ctxbitmap_next(dev);
327  if (ctx->handle == DRM_KERNEL_CONTEXT) {
328  /* Skip kernel's context and get a new one. */
329  ctx->handle = drm_ctxbitmap_next(dev);
330  }
331  DRM_DEBUG("%d\n", ctx->handle);
332  if (ctx->handle == -1) {
333  DRM_DEBUG("Not enough free contexts.\n");
334  /* Should this return -EBUSY instead? */
335  return -ENOMEM;
336  }
337 
338  ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL);
339  if (!ctx_entry) {
340  DRM_DEBUG("out of memory\n");
341  return -ENOMEM;
342  }
343 
344  INIT_LIST_HEAD(&ctx_entry->head);
345  ctx_entry->handle = ctx->handle;
346  ctx_entry->tag = file_priv;
347 
348  mutex_lock(&dev->ctxlist_mutex);
349  list_add(&ctx_entry->head, &dev->ctxlist);
350  ++dev->ctx_count;
351  mutex_unlock(&dev->ctxlist_mutex);
352 
353  return 0;
354 }
355 
356 int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
357 {
358  /* This does nothing */
359  return 0;
360 }
361 
371 int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
372 {
373  struct drm_ctx *ctx = data;
374 
375  /* This is 0, because we don't handle any context flags */
376  ctx->flags = 0;
377 
378  return 0;
379 }
380 
392 int drm_switchctx(struct drm_device *dev, void *data,
393  struct drm_file *file_priv)
394 {
395  struct drm_ctx *ctx = data;
396 
397  DRM_DEBUG("%d\n", ctx->handle);
398  return drm_context_switch(dev, dev->last_context, ctx->handle);
399 }
400 
412 int drm_newctx(struct drm_device *dev, void *data,
413  struct drm_file *file_priv)
414 {
415  struct drm_ctx *ctx = data;
416 
417  DRM_DEBUG("%d\n", ctx->handle);
418  drm_context_switch_complete(dev, file_priv, ctx->handle);
419 
420  return 0;
421 }
422 
434 int drm_rmctx(struct drm_device *dev, void *data,
435  struct drm_file *file_priv)
436 {
437  struct drm_ctx *ctx = data;
438 
439  DRM_DEBUG("%d\n", ctx->handle);
440  if (ctx->handle != DRM_KERNEL_CONTEXT) {
441  if (dev->driver->context_dtor)
442  dev->driver->context_dtor(dev, ctx->handle);
443  drm_ctxbitmap_free(dev, ctx->handle);
444  }
445 
446  mutex_lock(&dev->ctxlist_mutex);
447  if (!list_empty(&dev->ctxlist)) {
448  struct drm_ctx_list *pos, *n;
449 
450  list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
451  if (pos->handle == ctx->handle) {
452  list_del(&pos->head);
453  kfree(pos);
454  --dev->ctx_count;
455  }
456  }
457  }
458  mutex_unlock(&dev->ctxlist_mutex);
459 
460  return 0;
461 }
462