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