drm: extract legacy ctxbitmap flushing
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / drm_context.c
1 /**
2  * \file drm_context.c
3  * IOCTLs for generic contexts
4  *
5  * \author Rickard E. (Rik) Faith <faith@valinux.com>
6  * \author Gareth Hughes <gareth@valinux.com>
7  */
8
9 /*
10  * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
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 <duwe@caldera.de>
39  *              added context constructor/destructor hooks,
40  *              needed by SiS driver's memory management.
41  */
42
43 #include <drm/drmP.h>
44
45 /******************************************************************/
46 /** \name Context bitmap support */
47 /*@{*/
48
49 /**
50  * Free a handle from the context bitmap.
51  *
52  * \param dev DRM device.
53  * \param ctx_handle context handle.
54  *
55  * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
56  * in drm_device::ctx_idr, while holding the drm_device::struct_mutex
57  * lock.
58  */
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
66 /**
67  * Context bitmap allocation.
68  *
69  * \param dev DRM device.
70  * \return (non-negative) context handle on success or a negative number on failure.
71  *
72  * Allocate a new idr from drm_device::ctx_idr while holding the
73  * drm_device::struct_mutex lock.
74  */
75 static int drm_ctxbitmap_next(struct drm_device * dev)
76 {
77         int ret;
78
79         mutex_lock(&dev->struct_mutex);
80         ret = idr_alloc(&dev->ctx_idr, NULL, DRM_RESERVED_CONTEXTS, 0,
81                         GFP_KERNEL);
82         mutex_unlock(&dev->struct_mutex);
83         return ret;
84 }
85
86 /**
87  * Context bitmap initialization.
88  *
89  * \param dev DRM device.
90  *
91  * Initialise the drm_device::ctx_idr
92  */
93 int drm_ctxbitmap_init(struct drm_device * dev)
94 {
95         idr_init(&dev->ctx_idr);
96         return 0;
97 }
98
99 /**
100  * Context bitmap cleanup.
101  *
102  * \param dev DRM device.
103  *
104  * Free all idr members using drm_ctx_sarea_free helper function
105  * while holding the drm_device::struct_mutex lock.
106  */
107 void drm_ctxbitmap_cleanup(struct drm_device * dev)
108 {
109         mutex_lock(&dev->struct_mutex);
110         idr_destroy(&dev->ctx_idr);
111         mutex_unlock(&dev->struct_mutex);
112 }
113
114 /**
115  * drm_ctxbitmap_flush() - Flush all contexts owned by a file
116  * @dev: DRM device to operate on
117  * @file: Open file to flush contexts for
118  *
119  * This iterates over all contexts on @dev and drops them if they're owned by
120  * @file. Note that after this call returns, new contexts might be added if
121  * the file is still alive.
122  */
123 void drm_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file)
124 {
125         struct drm_ctx_list *pos, *tmp;
126
127         mutex_lock(&dev->ctxlist_mutex);
128
129         list_for_each_entry_safe(pos, tmp, &dev->ctxlist, head) {
130                 if (pos->tag == file &&
131                     pos->handle != DRM_KERNEL_CONTEXT) {
132                         if (dev->driver->context_dtor)
133                                 dev->driver->context_dtor(dev, pos->handle);
134
135                         drm_ctxbitmap_free(dev, pos->handle);
136                         list_del(&pos->head);
137                         kfree(pos);
138                 }
139         }
140
141         mutex_unlock(&dev->ctxlist_mutex);
142 }
143
144 /*@}*/
145
146 /******************************************************************/
147 /** \name Per Context SAREA Support */
148 /*@{*/
149
150 /**
151  * Get per-context SAREA.
152  *
153  * \param inode device inode.
154  * \param file_priv DRM file private.
155  * \param cmd command.
156  * \param arg user argument pointing to a drm_ctx_priv_map structure.
157  * \return zero on success or a negative number on failure.
158  *
159  * Gets the map from drm_device::ctx_idr with the handle specified and
160  * returns its handle.
161  */
162 int drm_getsareactx(struct drm_device *dev, void *data,
163                     struct drm_file *file_priv)
164 {
165         struct drm_ctx_priv_map *request = data;
166         struct drm_local_map *map;
167         struct drm_map_list *_entry;
168
169         mutex_lock(&dev->struct_mutex);
170
171         map = idr_find(&dev->ctx_idr, request->ctx_id);
172         if (!map) {
173                 mutex_unlock(&dev->struct_mutex);
174                 return -EINVAL;
175         }
176
177         request->handle = NULL;
178         list_for_each_entry(_entry, &dev->maplist, head) {
179                 if (_entry->map == map) {
180                         request->handle =
181                             (void *)(unsigned long)_entry->user_token;
182                         break;
183                 }
184         }
185
186         mutex_unlock(&dev->struct_mutex);
187
188         if (request->handle == NULL)
189                 return -EINVAL;
190
191         return 0;
192 }
193
194 /**
195  * Set per-context SAREA.
196  *
197  * \param inode device inode.
198  * \param file_priv DRM file private.
199  * \param cmd command.
200  * \param arg user argument pointing to a drm_ctx_priv_map structure.
201  * \return zero on success or a negative number on failure.
202  *
203  * Searches the mapping specified in \p arg and update the entry in
204  * drm_device::ctx_idr with it.
205  */
206 int drm_setsareactx(struct drm_device *dev, void *data,
207                     struct drm_file *file_priv)
208 {
209         struct drm_ctx_priv_map *request = data;
210         struct drm_local_map *map = NULL;
211         struct drm_map_list *r_list = NULL;
212
213         mutex_lock(&dev->struct_mutex);
214         list_for_each_entry(r_list, &dev->maplist, head) {
215                 if (r_list->map
216                     && r_list->user_token == (unsigned long) request->handle)
217                         goto found;
218         }
219       bad:
220         mutex_unlock(&dev->struct_mutex);
221         return -EINVAL;
222
223       found:
224         map = r_list->map;
225         if (!map)
226                 goto bad;
227
228         if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id)))
229                 goto bad;
230
231         mutex_unlock(&dev->struct_mutex);
232
233         return 0;
234 }
235
236 /*@}*/
237
238 /******************************************************************/
239 /** \name The actual DRM context handling routines */
240 /*@{*/
241
242 /**
243  * Switch context.
244  *
245  * \param dev DRM device.
246  * \param old old context handle.
247  * \param new new context handle.
248  * \return zero on success or a negative number on failure.
249  *
250  * Attempt to set drm_device::context_flag.
251  */
252 static int drm_context_switch(struct drm_device * dev, int old, int new)
253 {
254         if (test_and_set_bit(0, &dev->context_flag)) {
255                 DRM_ERROR("Reentering -- FIXME\n");
256                 return -EBUSY;
257         }
258
259         DRM_DEBUG("Context switch from %d to %d\n", old, new);
260
261         if (new == dev->last_context) {
262                 clear_bit(0, &dev->context_flag);
263                 return 0;
264         }
265
266         return 0;
267 }
268
269 /**
270  * Complete context switch.
271  *
272  * \param dev DRM device.
273  * \param new new context handle.
274  * \return zero on success or a negative number on failure.
275  *
276  * Updates drm_device::last_context and drm_device::last_switch. Verifies the
277  * hardware lock is held, clears the drm_device::context_flag and wakes up
278  * drm_device::context_wait.
279  */
280 static int drm_context_switch_complete(struct drm_device *dev,
281                                        struct drm_file *file_priv, int new)
282 {
283         dev->last_context = new;        /* PRE/POST: This is the _only_ writer. */
284
285         if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) {
286                 DRM_ERROR("Lock isn't held after context switch\n");
287         }
288
289         /* If a context switch is ever initiated
290            when the kernel holds the lock, release
291            that lock here. */
292         clear_bit(0, &dev->context_flag);
293
294         return 0;
295 }
296
297 /**
298  * Reserve contexts.
299  *
300  * \param inode device inode.
301  * \param file_priv DRM file private.
302  * \param cmd command.
303  * \param arg user argument pointing to a drm_ctx_res structure.
304  * \return zero on success or a negative number on failure.
305  */
306 int drm_resctx(struct drm_device *dev, void *data,
307                struct drm_file *file_priv)
308 {
309         struct drm_ctx_res *res = data;
310         struct drm_ctx ctx;
311         int i;
312
313         if (res->count >= DRM_RESERVED_CONTEXTS) {
314                 memset(&ctx, 0, sizeof(ctx));
315                 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
316                         ctx.handle = i;
317                         if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx)))
318                                 return -EFAULT;
319                 }
320         }
321         res->count = DRM_RESERVED_CONTEXTS;
322
323         return 0;
324 }
325
326 /**
327  * Add context.
328  *
329  * \param inode device inode.
330  * \param file_priv DRM file private.
331  * \param cmd command.
332  * \param arg user argument pointing to a drm_ctx structure.
333  * \return zero on success or a negative number on failure.
334  *
335  * Get a new handle for the context and copy to userspace.
336  */
337 int drm_addctx(struct drm_device *dev, void *data,
338                struct drm_file *file_priv)
339 {
340         struct drm_ctx_list *ctx_entry;
341         struct drm_ctx *ctx = data;
342
343         ctx->handle = drm_ctxbitmap_next(dev);
344         if (ctx->handle == DRM_KERNEL_CONTEXT) {
345                 /* Skip kernel's context and get a new one. */
346                 ctx->handle = drm_ctxbitmap_next(dev);
347         }
348         DRM_DEBUG("%d\n", ctx->handle);
349         if (ctx->handle == -1) {
350                 DRM_DEBUG("Not enough free contexts.\n");
351                 /* Should this return -EBUSY instead? */
352                 return -ENOMEM;
353         }
354
355         ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL);
356         if (!ctx_entry) {
357                 DRM_DEBUG("out of memory\n");
358                 return -ENOMEM;
359         }
360
361         INIT_LIST_HEAD(&ctx_entry->head);
362         ctx_entry->handle = ctx->handle;
363         ctx_entry->tag = file_priv;
364
365         mutex_lock(&dev->ctxlist_mutex);
366         list_add(&ctx_entry->head, &dev->ctxlist);
367         mutex_unlock(&dev->ctxlist_mutex);
368
369         return 0;
370 }
371
372 /**
373  * Get context.
374  *
375  * \param inode device inode.
376  * \param file_priv DRM file private.
377  * \param cmd command.
378  * \param arg user argument pointing to a drm_ctx structure.
379  * \return zero on success or a negative number on failure.
380  */
381 int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
382 {
383         struct drm_ctx *ctx = data;
384
385         /* This is 0, because we don't handle any context flags */
386         ctx->flags = 0;
387
388         return 0;
389 }
390
391 /**
392  * Switch context.
393  *
394  * \param inode device inode.
395  * \param file_priv DRM file private.
396  * \param cmd command.
397  * \param arg user argument pointing to a drm_ctx structure.
398  * \return zero on success or a negative number on failure.
399  *
400  * Calls context_switch().
401  */
402 int drm_switchctx(struct drm_device *dev, void *data,
403                   struct drm_file *file_priv)
404 {
405         struct drm_ctx *ctx = data;
406
407         DRM_DEBUG("%d\n", ctx->handle);
408         return drm_context_switch(dev, dev->last_context, ctx->handle);
409 }
410
411 /**
412  * New context.
413  *
414  * \param inode device inode.
415  * \param file_priv DRM file private.
416  * \param cmd command.
417  * \param arg user argument pointing to a drm_ctx structure.
418  * \return zero on success or a negative number on failure.
419  *
420  * Calls context_switch_complete().
421  */
422 int drm_newctx(struct drm_device *dev, void *data,
423                struct drm_file *file_priv)
424 {
425         struct drm_ctx *ctx = data;
426
427         DRM_DEBUG("%d\n", ctx->handle);
428         drm_context_switch_complete(dev, file_priv, ctx->handle);
429
430         return 0;
431 }
432
433 /**
434  * Remove context.
435  *
436  * \param inode device inode.
437  * \param file_priv DRM file private.
438  * \param cmd command.
439  * \param arg user argument pointing to a drm_ctx structure.
440  * \return zero on success or a negative number on failure.
441  *
442  * If not the special kernel context, calls ctxbitmap_free() to free the specified context.
443  */
444 int drm_rmctx(struct drm_device *dev, void *data,
445               struct drm_file *file_priv)
446 {
447         struct drm_ctx *ctx = data;
448
449         DRM_DEBUG("%d\n", ctx->handle);
450         if (ctx->handle != DRM_KERNEL_CONTEXT) {
451                 if (dev->driver->context_dtor)
452                         dev->driver->context_dtor(dev, ctx->handle);
453                 drm_ctxbitmap_free(dev, ctx->handle);
454         }
455
456         mutex_lock(&dev->ctxlist_mutex);
457         if (!list_empty(&dev->ctxlist)) {
458                 struct drm_ctx_list *pos, *n;
459
460                 list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
461                         if (pos->handle == ctx->handle) {
462                                 list_del(&pos->head);
463                                 kfree(pos);
464                         }
465                 }
466         }
467         mutex_unlock(&dev->ctxlist_mutex);
468
469         return 0;
470 }
471
472 /*@}*/