xref: /titanic_50/usr/src/uts/common/io/drm/drm_context.c (revision 3fbbb872ea33adea240e8fd8c692f6d3131cc69b)
1 /*
2  * Copyright 2007 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 static inline int
45 find_first_zero_bit(volatile void *p, int max)
46 {
47 	int b;
48 	volatile int *ptr = (volatile int *)p;
49 
50 	for (b = 0; b < max; b += 32) {
51 		if (ptr[b >> 5] != ~0) {
52 			for (;;) {
53 				if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0)
54 					return (b);
55 				b++;
56 			}
57 		}
58 	}
59 	return (max);
60 }
61 
62 static inline atomic_t
63 test_and_set_bit(int b, volatile void *p)
64 {
65 	int s = splhigh();
66 	unsigned int m = 1<<b;
67 	unsigned int r = *(volatile int *)p & m;
68 	*(volatile int *)p |= m;
69 	splx(s);
70 	return ((atomic_t)r);
71 }
72 
73 
74 /*
75  * Context bitmap support
76  */
77 void
78 drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle)
79 {
80 	if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP ||
81 	    dev->ctx_bitmap == NULL) {
82 		DRM_ERROR("drm_ctxbitmap_free: Attempt to free\
83 		    invalid context handle: %d\n",
84 		    ctx_handle);
85 		return;
86 	}
87 
88 	DRM_LOCK();
89 	clear_bit(ctx_handle, dev->ctx_bitmap);
90 	dev->context_sareas[ctx_handle] = NULL;
91 	DRM_UNLOCK();
92 }
93 
94 /* Is supposed to return -1 if  any error by calling functions */
95 int
96 drm_ctxbitmap_next(drm_device_t *dev)
97 {
98 	int bit;
99 
100 	if (dev->ctx_bitmap == NULL)
101 		return (-1);
102 
103 	DRM_LOCK();
104 	bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
105 	if (bit >= DRM_MAX_CTXBITMAP) {
106 		DRM_UNLOCK();
107 		return (-1);
108 	}
109 
110 	set_bit(bit, dev->ctx_bitmap);
111 	DRM_DEBUG("drm_ctxbitmap_next: bit : %d", bit);
112 	if ((bit+1) > dev->max_context) {
113 		dev->max_context = (bit+1);
114 		if (dev->context_sareas != NULL) {
115 			drm_local_map_t **ctx_sareas;
116 			ctx_sareas = drm_realloc(dev->context_sareas,
117 			    (dev->max_context - 1) *
118 			    sizeof (*dev->context_sareas),
119 			    dev->max_context *
120 			    sizeof (*dev->context_sareas),
121 			    DRM_MEM_MAPS);
122 			if (ctx_sareas == NULL) {
123 				clear_bit(bit, dev->ctx_bitmap);
124 				DRM_UNLOCK();
125 				return (-1);
126 			}
127 			dev->context_sareas = ctx_sareas;
128 			dev->context_sareas[bit] = NULL;
129 		} else {
130 			/* max_context == 1 at this point */
131 			dev->context_sareas = drm_alloc(dev->max_context *
132 			    sizeof (*dev->context_sareas), KM_NOSLEEP);
133 			if (dev->context_sareas == NULL) {
134 				clear_bit(bit, dev->ctx_bitmap);
135 				DRM_UNLOCK();
136 				return (-1);
137 			}
138 			dev->context_sareas[bit] = NULL;
139 		}
140 	}
141 	DRM_UNLOCK();
142 	DRM_DEBUG("drm_ctxbitmap_next: return %d", bit);
143 	return (bit);
144 }
145 
146 int
147 drm_ctxbitmap_init(drm_device_t *dev)
148 {
149 	int i;
150 	int temp;
151 
152 	DRM_LOCK();
153 	dev->ctx_bitmap = drm_calloc(1, DRM_PAGE_SIZE, DRM_MEM_CTXBITMAP);
154 	if (dev->ctx_bitmap == NULL) {
155 		DRM_UNLOCK();
156 		return (DRM_ERR(ENOMEM));
157 	}
158 	dev->context_sareas = NULL;
159 	dev->max_context = -1;
160 	DRM_UNLOCK();
161 
162 	for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
163 		temp = drm_ctxbitmap_next(dev);
164 		DRM_DEBUG("drm_ctxbitmap_init : %d", temp);
165 	}
166 	return (0);
167 }
168 
169 void
170 drm_ctxbitmap_cleanup(drm_device_t *dev)
171 {
172 	DRM_LOCK();
173 	if (dev->context_sareas != NULL)
174 		drm_free(dev->context_sareas,
175 		    sizeof (*dev->context_sareas) *
176 		    dev->max_context,
177 		    DRM_MEM_MAPS);
178 	drm_free(dev->ctx_bitmap, DRM_PAGE_SIZE, DRM_MEM_CTXBITMAP);
179 	DRM_UNLOCK();
180 }
181 
182 /*
183  * Per Context SAREA Support
184  */
185 /*ARGSUSED*/
186 int
187 drm_getsareactx(DRM_IOCTL_ARGS)
188 {
189 	DRM_DEVICE;
190 	drm_ctx_priv_map_t request;
191 	drm_local_map_t *map;
192 
193 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
194 		drm_ctx_priv_map32_t request32;
195 		DRM_COPY_FROM_USER_IOCTL(request32,
196 		    (drm_ctx_priv_map32_t *)data,
197 		    sizeof (drm_ctx_priv_map32_t));
198 		request.ctx_id = request32.ctx_id;
199 		request.handle = (void *)(uintptr_t)request32.handle;
200 	} else
201 		DRM_COPY_FROM_USER_IOCTL(request, (drm_ctx_priv_map_t *)data,
202 		    sizeof (request));
203 
204 	DRM_LOCK();
205 	if (dev->max_context < 0 || request.ctx_id >= (unsigned)
206 	    dev->max_context) {
207 		DRM_UNLOCK();
208 		return (DRM_ERR(EINVAL));
209 	}
210 
211 	map = dev->context_sareas[request.ctx_id];
212 	DRM_UNLOCK();
213 
214 	request.handle = map->handle;
215 
216 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
217 		drm_ctx_priv_map32_t request32;
218 		request32.ctx_id = request.ctx_id;
219 		request32.handle = (caddr32_t)(uintptr_t)request.handle;
220 		DRM_COPY_TO_USER_IOCTL((drm_ctx_priv_map32_t *)data,
221 		    request32, sizeof (drm_ctx_priv_map32_t));
222 	} else
223 		DRM_COPY_TO_USER_IOCTL((drm_ctx_priv_map_t *)data, request,
224 		    sizeof (request));
225 
226 	return (0);
227 }
228 
229 /*ARGSUSED*/
230 int
231 drm_setsareactx(DRM_IOCTL_ARGS)
232 {
233 	DRM_DEVICE;
234 	drm_ctx_priv_map_t request;
235 	drm_local_map_t *map = NULL;
236 
237 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
238 		drm_ctx_priv_map32_t request32;
239 
240 		DRM_COPY_FROM_USER_IOCTL(request32,
241 		    (drm_ctx_priv_map32_t *)data,
242 		    sizeof (drm_ctx_priv_map32_t));
243 		request.ctx_id = request32.ctx_id;
244 		request.handle = (void *)(uintptr_t)request32.handle;
245 	} else
246 		DRM_COPY_FROM_USER_IOCTL(request, (drm_ctx_priv_map_t *)data,
247 		    sizeof (request));
248 
249 	DRM_LOCK();
250 	TAILQ_FOREACH(map, &dev->maplist, link) {
251 		if (map->handle == request.handle) {
252 			if (dev->max_context < 0)
253 				goto bad;
254 			if (request.ctx_id >= (unsigned)dev->max_context)
255 				goto bad;
256 			dev->context_sareas[request.ctx_id] = map;
257 			DRM_UNLOCK();
258 			return (0);
259 		}
260 	}
261 
262 bad:
263 	DRM_UNLOCK();
264 	return (DRM_ERR(EINVAL));
265 }
266 
267 /*
268  * The actual DRM context handling routines
269  */
270 int
271 drm_context_switch(drm_device_t *dev, int old, int new)
272 {
273 	if (test_and_set_bit(0, &dev->context_flag)) {
274 		DRM_ERROR("drm_context_switch: Reentering -- FIXME");
275 		return (DRM_ERR(EBUSY));
276 	}
277 
278 	DRM_DEBUG("drm_context_switch: Context switch from %d to %d",
279 	    old, new);
280 
281 	if (new == dev->last_context) {
282 		clear_bit(0, &dev->context_flag);
283 		return (0);
284 	}
285 
286 	return (0);
287 }
288 
289 int
290 drm_context_switch_complete(drm_device_t *dev, int new)
291 {
292 	dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
293 
294 	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
295 		DRM_ERROR(
296 		    "drm_context_switch_complete: Lock not held");
297 	}
298 	/*
299 	 * If a context switch is ever initiated
300 	 * when the kernel holds the lock, release
301 	 * that lock here.
302 	 */
303 	clear_bit(0, &dev->context_flag);
304 
305 	return (0);
306 }
307 
308 /*ARGSUSED*/
309 int
310 drm_resctx(DRM_IOCTL_ARGS)
311 {
312 	drm_ctx_res_t res;
313 	drm_ctx_t ctx;
314 	int i;
315 
316 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
317 		drm_ctx_res32_t res32;
318 		DRM_COPY_FROM_USER_IOCTL(res32,
319 		    (drm_ctx_res32_t *)data,
320 		    sizeof (drm_ctx_res32_t));
321 		res.count = res32.count;
322 		res.contexts = (drm_ctx_t __user *)(uintptr_t)res32.contexts;
323 	} else
324 		DRM_COPY_FROM_USER_IOCTL(res,
325 		    (drm_ctx_res_t *)data,
326 		    sizeof (res));
327 
328 	if (res.count >= DRM_RESERVED_CONTEXTS) {
329 		bzero(&ctx, sizeof (ctx));
330 		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
331 			ctx.handle = i;
332 			if (DRM_COPY_TO_USER(&res.contexts[i],
333 			    &ctx, sizeof (ctx)))
334 				return (DRM_ERR(EFAULT));
335 		}
336 	}
337 	res.count = DRM_RESERVED_CONTEXTS;
338 
339 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
340 		drm_ctx_res32_t res32;
341 		res32.count = res.count;
342 		res32.contexts = (caddr32_t)(uintptr_t)res.contexts;
343 
344 		DRM_COPY_TO_USER_IOCTL((drm_ctx_res32_t *)data,
345 		    res32, sizeof (drm_ctx_res32_t));
346 	} else
347 		DRM_COPY_TO_USER_IOCTL((drm_ctx_res_t *)data,
348 		    res, sizeof (res));
349 
350 	return (0);
351 }
352 
353 /*ARGSUSED*/
354 int
355 drm_addctx(DRM_IOCTL_ARGS)
356 {
357 	DRM_DEVICE;
358 	drm_ctx_t ctx;
359 
360 	DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx));
361 
362 	ctx.handle = drm_ctxbitmap_next(dev);
363 	DRM_DEBUG("drm_addctx: ctx.handle 1:%d\n", (int)ctx.handle);
364 	if (ctx.handle == DRM_KERNEL_CONTEXT) {
365 		/* Skip kernel's context and get a new one. */
366 		DRM_DEBUG("drm_addctx: ctx.handle 2:%d\n", (int)ctx.handle);
367 		ctx.handle = drm_ctxbitmap_next(dev);
368 	}
369 	DRM_DEBUG("drm_addctx :%d\n", ctx.handle);
370 	if (ctx.handle == -1) {
371 		DRM_DEBUG("drm_addctx: Not enough free contexts.");
372 		return (DRM_ERR(ENOMEM));
373 	}
374 
375 	if (dev->context_ctor && ctx.handle != DRM_KERNEL_CONTEXT) {
376 		DRM_LOCK();
377 		dev->context_ctor(dev, ctx.handle);
378 		DRM_UNLOCK();
379 	}
380 
381 	DRM_COPY_TO_USER_IOCTL((drm_ctx_t *)data, ctx, sizeof (ctx));
382 
383 	return (0);
384 }
385 
386 /*ARGSUSED*/
387 int
388 drm_modctx(DRM_IOCTL_ARGS)
389 {
390 	/* This does nothing */
391 	return (0);
392 }
393 
394 /*ARGSUSED*/
395 int
396 drm_getctx(DRM_IOCTL_ARGS)
397 {
398 	drm_ctx_t ctx;
399 
400 	DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx));
401 
402 	/* This is 0, because we don't handle any context flags */
403 	ctx.flags = 0;
404 
405 	DRM_COPY_TO_USER_IOCTL((drm_ctx_t *)data, ctx, sizeof (ctx));
406 
407 	return (0);
408 }
409 
410 /*ARGSUSED*/
411 int
412 drm_switchctx(DRM_IOCTL_ARGS)
413 {
414 	DRM_DEVICE;
415 	drm_ctx_t ctx;
416 
417 	DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx));
418 
419 	DRM_DEBUG("drm_switchctx: %d", ctx.handle);
420 	return (drm_context_switch(dev, dev->last_context, ctx.handle));
421 }
422 
423 /*ARGSUSED*/
424 int
425 drm_newctx(DRM_IOCTL_ARGS)
426 {
427 	DRM_DEVICE;
428 	drm_ctx_t ctx;
429 
430 	DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx));
431 
432 	DRM_DEBUG("drm_newctx: %d", ctx.handle);
433 	(void) drm_context_switch_complete(dev, ctx.handle);
434 
435 	return (0);
436 }
437 
438 /*ARGSUSED*/
439 int
440 drm_rmctx(DRM_IOCTL_ARGS)
441 {
442 	DRM_DEVICE;
443 	drm_ctx_t ctx;
444 
445 	DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx));
446 
447 	DRM_DEBUG("drm_rmctx : %d", ctx.handle);
448 	if (ctx.handle != DRM_KERNEL_CONTEXT) {
449 		if (dev->context_dtor) {
450 			DRM_LOCK();
451 			dev->context_dtor(dev, ctx.handle);
452 			DRM_UNLOCK();
453 		}
454 
455 		drm_ctxbitmap_free(dev, ctx.handle);
456 	}
457 
458 	return (0);
459 }
460