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