xref: /titanic_50/usr/src/uts/common/io/drm/drm_context.c (revision 381a2a9a387f449fab7d0c7e97c4184c26963abf)
1 /*
2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * drm_context.h -- IOCTLs for generic contexts -*- linux-c -*-
8  * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
9  */
10 /*
11  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
12  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
13  * All Rights Reserved.
14  *
15  * Permission is hereby granted, free of charge, to any person obtaining a
16  * copy of this software and associated documentation files (the "Software"),
17  * to deal in the Software without restriction, including without limitation
18  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19  * and/or sell copies of the Software, and to permit persons to whom the
20  * Software is furnished to do so, subject to the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the next
23  * paragraph) shall be included in all copies or substantial portions of the
24  * Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
29  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
30  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
31  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32  * OTHER DEALINGS IN THE SOFTWARE.
33  *
34  * Authors:
35  *    Rickard E. (Rik) Faith <faith@valinux.com>
36  *    Gareth Hughes <gareth@valinux.com>
37  *
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include "drmP.h"
43 
44 /*
45  * Context bitmap support
46  */
47 void
48 drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle)
49 {
50 	if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP ||
51 	    dev->ctx_bitmap == NULL) {
52 		DRM_ERROR("drm_ctxbitmap_free: Attempt to free\
53 		    invalid context handle: %d\n",
54 		    ctx_handle);
55 		return;
56 	}
57 
58 	DRM_LOCK();
59 	clear_bit(ctx_handle, dev->ctx_bitmap);
60 	dev->context_sareas[ctx_handle] = NULL;
61 	DRM_UNLOCK();
62 }
63 
64 /* Is supposed to return -1 if  any error by calling functions */
65 int
66 drm_ctxbitmap_next(drm_device_t *dev)
67 {
68 	int bit;
69 
70 	if (dev->ctx_bitmap == NULL)
71 		return (-1);
72 
73 	DRM_LOCK();
74 	bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
75 	if (bit >= DRM_MAX_CTXBITMAP) {
76 		DRM_UNLOCK();
77 		return (-1);
78 	}
79 
80 	set_bit(bit, dev->ctx_bitmap);
81 	DRM_DEBUG("drm_ctxbitmap_next: bit : %d", bit);
82 	if ((bit+1) > dev->max_context) {
83 		dev->max_context = (bit+1);
84 		if (dev->context_sareas != NULL) {
85 			drm_local_map_t **ctx_sareas;
86 			ctx_sareas = drm_realloc(dev->context_sareas,
87 					(dev->max_context - 1) *
88 					sizeof (*dev->context_sareas),
89 					dev->max_context *
90 					sizeof (*dev->context_sareas),
91 					DRM_MEM_MAPS);
92 			if (ctx_sareas == NULL) {
93 				clear_bit(bit, dev->ctx_bitmap);
94 				DRM_UNLOCK();
95 				return (-1);
96 			}
97 			dev->context_sareas = ctx_sareas;
98 			dev->context_sareas[bit] = NULL;
99 		} else {
100 			/* max_context == 1 at this point */
101 			dev->context_sareas = drm_alloc(dev->max_context *
102 				    sizeof (*dev->context_sareas), KM_NOSLEEP);
103 			if (dev->context_sareas == NULL) {
104 				clear_bit(bit, dev->ctx_bitmap);
105 				DRM_UNLOCK();
106 				return (-1);
107 			}
108 			dev->context_sareas[bit] = NULL;
109 		}
110 	}
111 	DRM_UNLOCK();
112 	DRM_DEBUG("drm_ctxbitmap_next: return %d", bit);
113 	return (bit);
114 }
115 
116 int
117 drm_ctxbitmap_init(drm_device_t *dev)
118 {
119 	int i;
120 	int temp;
121 
122 	DRM_LOCK();
123 	dev->ctx_bitmap = drm_calloc(1, DRM_PAGE_SIZE, DRM_MEM_CTXBITMAP);
124 	if (dev->ctx_bitmap == NULL) {
125 		DRM_UNLOCK();
126 		return (DRM_ERR(ENOMEM));
127 	}
128 	dev->context_sareas = NULL;
129 	dev->max_context = -1;
130 	DRM_UNLOCK();
131 
132 	for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
133 		temp = drm_ctxbitmap_next(dev);
134 		DRM_DEBUG("drm_ctxbitmap_init : %d", temp);
135 	}
136 	return (0);
137 }
138 
139 void
140 drm_ctxbitmap_cleanup(drm_device_t *dev)
141 {
142 	DRM_LOCK();
143 	if (dev->context_sareas != NULL)
144 		drm_free(dev->context_sareas,
145 			sizeof (*dev->context_sareas) *
146 			dev->max_context,
147 			DRM_MEM_MAPS);
148 	drm_free(dev->ctx_bitmap, DRM_PAGE_SIZE, DRM_MEM_CTXBITMAP);
149 	DRM_UNLOCK();
150 }
151 
152 /*
153  * Per Context SAREA Support
154  */
155 /*ARGSUSED*/
156 int
157 drm_getsareactx(DRM_IOCTL_ARGS)
158 {
159 	DRM_DEVICE;
160 	drm_ctx_priv_map_t request;
161 	drm_local_map_t *map;
162 
163 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
164 		drm_ctx_priv_map32_t request32;
165 		DRM_COPY_FROM_USER_IOCTL(request32,
166 			(drm_ctx_priv_map32_t *)data,
167 			sizeof (drm_ctx_priv_map32_t));
168 		request.ctx_id = request32.ctx_id;
169 		request.handle = (void *)(uintptr_t)request32.handle;
170 	} else
171 		DRM_COPY_FROM_USER_IOCTL(request, (drm_ctx_priv_map_t *)data,
172 			sizeof (request));
173 
174 	DRM_LOCK();
175 	if (dev->max_context < 0 || request.ctx_id >= (unsigned)
176 	    dev->max_context) {
177 		DRM_UNLOCK();
178 		return (DRM_ERR(EINVAL));
179 	}
180 
181 	map = dev->context_sareas[request.ctx_id];
182 	DRM_UNLOCK();
183 
184 	request.handle = map->handle;
185 
186 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
187 		drm_ctx_priv_map32_t request32;
188 		request32.ctx_id = request.ctx_id;
189 		request32.handle = (caddr32_t)(uintptr_t)request.handle;
190 		DRM_COPY_TO_USER_IOCTL((drm_ctx_priv_map32_t *)data,
191 			request32,
192 			sizeof (drm_ctx_priv_map32_t));
193 	} else
194 		DRM_COPY_TO_USER_IOCTL((drm_ctx_priv_map_t *)data, request,
195 			sizeof (request));
196 
197 	return (0);
198 }
199 
200 /*ARGSUSED*/
201 int
202 drm_setsareactx(DRM_IOCTL_ARGS)
203 {
204 	DRM_DEVICE;
205 	drm_ctx_priv_map_t request;
206 	drm_local_map_t *map = NULL;
207 
208 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
209 		drm_ctx_priv_map32_t request32;
210 
211 		DRM_COPY_FROM_USER_IOCTL(request32,
212 			(drm_ctx_priv_map32_t *)data,
213 			sizeof (drm_ctx_priv_map32_t));
214 		request.ctx_id = request32.ctx_id;
215 		request.handle = (void *)(uintptr_t)request32.handle;
216 	} else
217 		DRM_COPY_FROM_USER_IOCTL(request, (drm_ctx_priv_map_t *)data,
218 			sizeof (request));
219 
220 	DRM_LOCK();
221 	TAILQ_FOREACH(map, &dev->maplist, link) {
222 		if (map->handle == request.handle) {
223 			if (dev->max_context < 0)
224 				goto bad;
225 			if (request.ctx_id >= (unsigned)dev->max_context)
226 				goto bad;
227 			dev->context_sareas[request.ctx_id] = map;
228 			DRM_UNLOCK();
229 			return (0);
230 		}
231 	}
232 
233 bad:
234 	DRM_UNLOCK();
235 	return (DRM_ERR(EINVAL));
236 }
237 
238 /*
239  * The actual DRM context handling routines
240  */
241 int
242 drm_context_switch(drm_device_t *dev, int old, int new)
243 {
244 	if (test_and_set_bit(0, &dev->context_flag)) {
245 		DRM_ERROR("drm_context_switch: Reentering -- FIXME");
246 		return (DRM_ERR(EBUSY));
247 	}
248 
249 	DRM_DEBUG("drm_context_switch: Context switch from %d to %d",
250 	    old, new);
251 
252 	if (new == dev->last_context) {
253 		clear_bit(0, &dev->context_flag);
254 		return (0);
255 	}
256 
257 	return (0);
258 }
259 
260 int
261 drm_context_switch_complete(drm_device_t *dev, int new)
262 {
263 	dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
264 
265 	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
266 		DRM_ERROR(
267 		    "drm_context_switch_complete: Lock not held");
268 	}
269 	/*
270 	 * If a context switch is ever initiated
271 	 * when the kernel holds the lock, release
272 	 * that lock here.
273 	 */
274 	clear_bit(0, &dev->context_flag);
275 
276 	return (0);
277 }
278 
279 /*ARGSUSED*/
280 int
281 drm_resctx(DRM_IOCTL_ARGS)
282 {
283 	drm_ctx_res_t res;
284 	drm_ctx_t ctx;
285 	int i;
286 
287 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
288 		drm_ctx_res32_t res32;
289 		DRM_COPY_FROM_USER_IOCTL(res32,
290 			(drm_ctx_res32_t *)data,
291 			sizeof (drm_ctx_res32_t));
292 		res.count = res32.count;
293 		res.contexts = (drm_ctx_t __user *)(uintptr_t)res32.contexts;
294 	} else
295 		DRM_COPY_FROM_USER_IOCTL(res,
296 			(drm_ctx_res_t *)data,
297 			sizeof (res));
298 
299 	if (res.count >= DRM_RESERVED_CONTEXTS) {
300 		bzero(&ctx, sizeof (ctx));
301 		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
302 			ctx.handle = i;
303 			if (DRM_COPY_TO_USER(&res.contexts[i],
304 			    &ctx, sizeof (ctx)))
305 				return (DRM_ERR(EFAULT));
306 		}
307 	}
308 	res.count = DRM_RESERVED_CONTEXTS;
309 
310 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
311 		drm_ctx_res32_t res32;
312 		res32.count = res.count;
313 		res32.contexts = (caddr32_t)(uintptr_t)res.contexts;
314 
315 		DRM_COPY_TO_USER_IOCTL((drm_ctx_res32_t *)data,
316 			res32, sizeof (drm_ctx_res32_t));
317 	} else
318 		DRM_COPY_TO_USER_IOCTL((drm_ctx_res_t *)data,
319 			res, sizeof (res));
320 
321 	return (0);
322 }
323 
324 /*ARGSUSED*/
325 int
326 drm_addctx(DRM_IOCTL_ARGS)
327 {
328 	DRM_DEVICE;
329 	drm_ctx_t ctx;
330 
331 	DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx));
332 
333 	ctx.handle = drm_ctxbitmap_next(dev);
334 	DRM_DEBUG("drm_addctx: ctx.handle 1:%d\n", (int)ctx.handle);
335 	if (ctx.handle == DRM_KERNEL_CONTEXT) {
336 		/* Skip kernel's context and get a new one. */
337 		DRM_DEBUG("drm_addctx: ctx.handle 2:%d\n", (int)ctx.handle);
338 		ctx.handle = drm_ctxbitmap_next(dev);
339 	}
340 	DRM_DEBUG("drm_addctx :%d\n", ctx.handle);
341 	if (ctx.handle == -1) {
342 		DRM_DEBUG("drm_addctx: Not enough free contexts.");
343 		return (DRM_ERR(ENOMEM));
344 	}
345 
346 	if (dev->context_ctor && ctx.handle != DRM_KERNEL_CONTEXT) {
347 		DRM_LOCK();
348 		dev->context_ctor(dev, ctx.handle);
349 		DRM_UNLOCK();
350 	}
351 
352 	DRM_COPY_TO_USER_IOCTL((drm_ctx_t *)data, ctx, sizeof (ctx));
353 
354 	return (0);
355 }
356 
357 /*ARGSUSED*/
358 int
359 drm_modctx(DRM_IOCTL_ARGS)
360 {
361 	/* This does nothing */
362 	return (0);
363 }
364 
365 /*ARGSUSED*/
366 int
367 drm_getctx(DRM_IOCTL_ARGS)
368 {
369 	drm_ctx_t ctx;
370 
371 	DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx));
372 
373 	/* This is 0, because we don't handle any context flags */
374 	ctx.flags = 0;
375 
376 	DRM_COPY_TO_USER_IOCTL((drm_ctx_t *)data, ctx, sizeof (ctx));
377 
378 	return (0);
379 }
380 
381 /*ARGSUSED*/
382 int
383 drm_switchctx(DRM_IOCTL_ARGS)
384 {
385 	DRM_DEVICE;
386 	drm_ctx_t ctx;
387 
388 	DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx));
389 
390 	DRM_DEBUG("drm_switchctx: %d", ctx.handle);
391 	return (drm_context_switch(dev, dev->last_context, ctx.handle));
392 }
393 
394 /*ARGSUSED*/
395 int
396 drm_newctx(DRM_IOCTL_ARGS)
397 {
398 	DRM_DEVICE;
399 	drm_ctx_t ctx;
400 
401 	DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx));
402 
403 	DRM_DEBUG("drm_newctx: %d", ctx.handle);
404 	(void) drm_context_switch_complete(dev, ctx.handle);
405 
406 	return (0);
407 }
408 
409 /*ARGSUSED*/
410 int
411 drm_rmctx(DRM_IOCTL_ARGS)
412 {
413 	DRM_DEVICE;
414 	drm_ctx_t ctx;
415 
416 	DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx));
417 
418 	DRM_DEBUG("drm_rmctx : %d", ctx.handle);
419 	if (ctx.handle != DRM_KERNEL_CONTEXT) {
420 		if (dev->context_dtor) {
421 			DRM_LOCK();
422 			dev->context_dtor(dev, ctx.handle);
423 			DRM_UNLOCK();
424 		}
425 
426 		drm_ctxbitmap_free(dev, ctx.handle);
427 	}
428 
429 	return (0);
430 }
431