drm_context.c revision 235783
1235783Skib/*-
2235783Skib * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
3235783Skib * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
4235783Skib * All Rights Reserved.
5235783Skib *
6235783Skib * Permission is hereby granted, free of charge, to any person obtaining a
7235783Skib * copy of this software and associated documentation files (the "Software"),
8235783Skib * to deal in the Software without restriction, including without limitation
9235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10235783Skib * and/or sell copies of the Software, and to permit persons to whom the
11235783Skib * Software is furnished to do so, subject to the following conditions:
12235783Skib *
13235783Skib * The above copyright notice and this permission notice (including the next
14235783Skib * paragraph) shall be included in all copies or substantial portions of the
15235783Skib * Software.
16235783Skib *
17235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20235783Skib * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21235783Skib * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22235783Skib * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23235783Skib * OTHER DEALINGS IN THE SOFTWARE.
24235783Skib *
25235783Skib * Authors:
26235783Skib *    Rickard E. (Rik) Faith <faith@valinux.com>
27235783Skib *    Gareth Hughes <gareth@valinux.com>
28235783Skib *
29235783Skib */
30235783Skib
31235783Skib#include <sys/cdefs.h>
32235783Skib__FBSDID("$FreeBSD: head/sys/dev/drm2/drm_context.c 235783 2012-05-22 11:07:44Z kib $");
33235783Skib
34235783Skib/** @file drm_context.c
35235783Skib * Implementation of the context management ioctls.
36235783Skib */
37235783Skib
38235783Skib#include <dev/drm2/drmP.h>
39235783Skib
40235783Skib/* ================================================================
41235783Skib * Context bitmap support
42235783Skib */
43235783Skib
44235783Skibvoid drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle)
45235783Skib{
46235783Skib	if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP ||
47235783Skib	    dev->ctx_bitmap == NULL) {
48235783Skib		DRM_ERROR("Attempt to free invalid context handle: %d\n",
49235783Skib		   ctx_handle);
50235783Skib		return;
51235783Skib	}
52235783Skib
53235783Skib	DRM_LOCK(dev);
54235783Skib	clear_bit(ctx_handle, dev->ctx_bitmap);
55235783Skib	dev->context_sareas[ctx_handle] = NULL;
56235783Skib	DRM_UNLOCK(dev);
57235783Skib	return;
58235783Skib}
59235783Skib
60235783Skibint drm_ctxbitmap_next(struct drm_device *dev)
61235783Skib{
62235783Skib	int bit;
63235783Skib
64235783Skib	if (dev->ctx_bitmap == NULL)
65235783Skib		return -1;
66235783Skib
67235783Skib	DRM_LOCK(dev);
68235783Skib	bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
69235783Skib	if (bit >= DRM_MAX_CTXBITMAP) {
70235783Skib		DRM_UNLOCK(dev);
71235783Skib		return -1;
72235783Skib	}
73235783Skib
74235783Skib	set_bit(bit, dev->ctx_bitmap);
75235783Skib	DRM_DEBUG("bit : %d\n", bit);
76235783Skib	if ((bit+1) > dev->max_context) {
77235783Skib		drm_local_map_t **ctx_sareas;
78235783Skib		int max_ctx = (bit+1);
79235783Skib
80235783Skib		ctx_sareas = realloc(dev->context_sareas,
81235783Skib		    max_ctx * sizeof(*dev->context_sareas),
82235783Skib		    DRM_MEM_SAREA, M_NOWAIT);
83235783Skib		if (ctx_sareas == NULL) {
84235783Skib			clear_bit(bit, dev->ctx_bitmap);
85235783Skib			DRM_DEBUG("failed to allocate bit : %d\n", bit);
86235783Skib			DRM_UNLOCK(dev);
87235783Skib			return -1;
88235783Skib		}
89235783Skib		dev->max_context = max_ctx;
90235783Skib		dev->context_sareas = ctx_sareas;
91235783Skib		dev->context_sareas[bit] = NULL;
92235783Skib	}
93235783Skib	DRM_UNLOCK(dev);
94235783Skib	return bit;
95235783Skib}
96235783Skib
97235783Skibint drm_ctxbitmap_init(struct drm_device *dev)
98235783Skib{
99235783Skib	int i;
100235783Skib   	int temp;
101235783Skib
102235783Skib	DRM_LOCK(dev);
103235783Skib	dev->ctx_bitmap = malloc(PAGE_SIZE, DRM_MEM_CTXBITMAP,
104235783Skib	    M_NOWAIT | M_ZERO);
105235783Skib	if (dev->ctx_bitmap == NULL) {
106235783Skib		DRM_UNLOCK(dev);
107235783Skib		return ENOMEM;
108235783Skib	}
109235783Skib	dev->context_sareas = NULL;
110235783Skib	dev->max_context = -1;
111235783Skib	DRM_UNLOCK(dev);
112235783Skib
113235783Skib	for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
114235783Skib		temp = drm_ctxbitmap_next(dev);
115235783Skib		DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
116235783Skib	}
117235783Skib
118235783Skib	return 0;
119235783Skib}
120235783Skib
121235783Skibvoid drm_ctxbitmap_cleanup(struct drm_device *dev)
122235783Skib{
123235783Skib	DRM_LOCK(dev);
124235783Skib	if (dev->context_sareas != NULL)
125235783Skib		free(dev->context_sareas, DRM_MEM_SAREA);
126235783Skib	free(dev->ctx_bitmap, DRM_MEM_CTXBITMAP);
127235783Skib	DRM_UNLOCK(dev);
128235783Skib}
129235783Skib
130235783Skib/* ================================================================
131235783Skib * Per Context SAREA Support
132235783Skib */
133235783Skib
134235783Skibint drm_getsareactx(struct drm_device *dev, void *data,
135235783Skib		    struct drm_file *file_priv)
136235783Skib{
137235783Skib	struct drm_ctx_priv_map *request = data;
138235783Skib	drm_local_map_t *map;
139235783Skib
140235783Skib	DRM_LOCK(dev);
141235783Skib	if (dev->max_context < 0 ||
142235783Skib	    request->ctx_id >= (unsigned) dev->max_context) {
143235783Skib		DRM_UNLOCK(dev);
144235783Skib		return EINVAL;
145235783Skib	}
146235783Skib
147235783Skib	map = dev->context_sareas[request->ctx_id];
148235783Skib	DRM_UNLOCK(dev);
149235783Skib
150235783Skib	request->handle = (void *)map->handle;
151235783Skib
152235783Skib	return 0;
153235783Skib}
154235783Skib
155235783Skibint drm_setsareactx(struct drm_device *dev, void *data,
156235783Skib		    struct drm_file *file_priv)
157235783Skib{
158235783Skib	struct drm_ctx_priv_map *request = data;
159235783Skib	drm_local_map_t *map = NULL;
160235783Skib
161235783Skib	DRM_LOCK(dev);
162235783Skib	TAILQ_FOREACH(map, &dev->maplist, link) {
163235783Skib		if (map->handle == request->handle) {
164235783Skib			if (dev->max_context < 0)
165235783Skib				goto bad;
166235783Skib			if (request->ctx_id >= (unsigned) dev->max_context)
167235783Skib				goto bad;
168235783Skib			dev->context_sareas[request->ctx_id] = map;
169235783Skib			DRM_UNLOCK(dev);
170235783Skib			return 0;
171235783Skib		}
172235783Skib	}
173235783Skib
174235783Skibbad:
175235783Skib	DRM_UNLOCK(dev);
176235783Skib	return EINVAL;
177235783Skib}
178235783Skib
179235783Skib/* ================================================================
180235783Skib * The actual DRM context handling routines
181235783Skib */
182235783Skib
183235783Skibint drm_context_switch(struct drm_device *dev, int old, int new)
184235783Skib{
185235783Skib	if (test_and_set_bit(0, &dev->context_flag)) {
186235783Skib		DRM_ERROR("Reentering -- FIXME\n");
187235783Skib		return EBUSY;
188235783Skib	}
189235783Skib
190235783Skib	DRM_DEBUG("Context switch from %d to %d\n", old, new);
191235783Skib
192235783Skib	if (new == dev->last_context) {
193235783Skib		clear_bit(0, &dev->context_flag);
194235783Skib		return 0;
195235783Skib	}
196235783Skib
197235783Skib	return 0;
198235783Skib}
199235783Skib
200235783Skibint drm_context_switch_complete(struct drm_device *dev, int new)
201235783Skib{
202235783Skib	dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
203235783Skib
204235783Skib	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
205235783Skib		DRM_ERROR("Lock isn't held after context switch\n");
206235783Skib	}
207235783Skib
208235783Skib	/* If a context switch is ever initiated
209235783Skib	   when the kernel holds the lock, release
210235783Skib	   that lock here. */
211235783Skib	clear_bit(0, &dev->context_flag);
212235783Skib
213235783Skib	return 0;
214235783Skib}
215235783Skib
216235783Skibint drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
217235783Skib{
218235783Skib	struct drm_ctx_res *res = data;
219235783Skib	struct drm_ctx ctx;
220235783Skib	int i;
221235783Skib
222235783Skib	if (res->count >= DRM_RESERVED_CONTEXTS) {
223235783Skib		bzero(&ctx, sizeof(ctx));
224235783Skib		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
225235783Skib			ctx.handle = i;
226235783Skib			if (DRM_COPY_TO_USER(&res->contexts[i],
227235783Skib			    &ctx, sizeof(ctx)))
228235783Skib				return EFAULT;
229235783Skib		}
230235783Skib	}
231235783Skib	res->count = DRM_RESERVED_CONTEXTS;
232235783Skib
233235783Skib	return 0;
234235783Skib}
235235783Skib
236235783Skibint drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
237235783Skib{
238235783Skib	struct drm_ctx *ctx = data;
239235783Skib
240235783Skib	ctx->handle = drm_ctxbitmap_next(dev);
241235783Skib	if (ctx->handle == DRM_KERNEL_CONTEXT) {
242235783Skib		/* Skip kernel's context and get a new one. */
243235783Skib		ctx->handle = drm_ctxbitmap_next(dev);
244235783Skib	}
245235783Skib	DRM_DEBUG("%d\n", ctx->handle);
246235783Skib	if (ctx->handle == -1) {
247235783Skib		DRM_DEBUG("Not enough free contexts.\n");
248235783Skib		/* Should this return -EBUSY instead? */
249235783Skib		return ENOMEM;
250235783Skib	}
251235783Skib
252235783Skib	if (dev->driver->context_ctor && ctx->handle != DRM_KERNEL_CONTEXT) {
253235783Skib		DRM_LOCK(dev);
254235783Skib		dev->driver->context_ctor(dev, ctx->handle);
255235783Skib		DRM_UNLOCK(dev);
256235783Skib	}
257235783Skib
258235783Skib	return 0;
259235783Skib}
260235783Skib
261235783Skibint drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
262235783Skib{
263235783Skib	/* This does nothing */
264235783Skib	return 0;
265235783Skib}
266235783Skib
267235783Skibint drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
268235783Skib{
269235783Skib	struct drm_ctx *ctx = data;
270235783Skib
271235783Skib	/* This is 0, because we don't handle any context flags */
272235783Skib	ctx->flags = 0;
273235783Skib
274235783Skib	return 0;
275235783Skib}
276235783Skib
277235783Skibint drm_switchctx(struct drm_device *dev, void *data,
278235783Skib		  struct drm_file *file_priv)
279235783Skib{
280235783Skib	struct drm_ctx *ctx = data;
281235783Skib
282235783Skib	DRM_DEBUG("%d\n", ctx->handle);
283235783Skib	return drm_context_switch(dev, dev->last_context, ctx->handle);
284235783Skib}
285235783Skib
286235783Skibint drm_newctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
287235783Skib{
288235783Skib	struct drm_ctx *ctx = data;
289235783Skib
290235783Skib	DRM_DEBUG("%d\n", ctx->handle);
291235783Skib	drm_context_switch_complete(dev, ctx->handle);
292235783Skib
293235783Skib	return 0;
294235783Skib}
295235783Skib
296235783Skibint drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
297235783Skib{
298235783Skib	struct drm_ctx *ctx = data;
299235783Skib
300235783Skib	DRM_DEBUG("%d\n", ctx->handle);
301235783Skib	if (ctx->handle != DRM_KERNEL_CONTEXT) {
302235783Skib		if (dev->driver->context_dtor) {
303235783Skib			DRM_LOCK(dev);
304235783Skib			dev->driver->context_dtor(dev, ctx->handle);
305235783Skib			DRM_UNLOCK(dev);
306235783Skib		}
307235783Skib
308235783Skib		drm_ctxbitmap_free(dev, ctx->handle);
309235783Skib	}
310235783Skib
311235783Skib	return 0;
312235783Skib}
313