1145132Sanholt/*- 2145132Sanholt * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 3145132Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 4145132Sanholt * All Rights Reserved. 5145132Sanholt * 6145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a 7145132Sanholt * copy of this software and associated documentation files (the "Software"), 8145132Sanholt * to deal in the Software without restriction, including without limitation 9145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the 11145132Sanholt * Software is furnished to do so, subject to the following conditions: 12145132Sanholt * 13145132Sanholt * The above copyright notice and this permission notice (including the next 14145132Sanholt * paragraph) shall be included in all copies or substantial portions of the 15145132Sanholt * Software. 16145132Sanholt * 17145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20145132Sanholt * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21145132Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22145132Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23145132Sanholt * OTHER DEALINGS IN THE SOFTWARE. 24145132Sanholt * 25145132Sanholt * Authors: 26145132Sanholt * Rickard E. (Rik) Faith <faith@valinux.com> 27145132Sanholt * Gareth Hughes <gareth@valinux.com> 28145132Sanholt * 29145132Sanholt */ 30145132Sanholt 31152909Sanholt#include <sys/cdefs.h> 32152909Sanholt__FBSDID("$FreeBSD$"); 33152909Sanholt 34182080Srnoland/** @file drm_context.c 35182080Srnoland * Implementation of the context management ioctls. 36182080Srnoland */ 37182080Srnoland 38145132Sanholt#include "dev/drm/drmP.h" 39145132Sanholt 40145132Sanholt/* ================================================================ 41145132Sanholt * Context bitmap support 42145132Sanholt */ 43145132Sanholt 44182080Srnolandvoid drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle) 45145132Sanholt{ 46145132Sanholt if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP || 47145132Sanholt dev->ctx_bitmap == NULL) { 48145132Sanholt DRM_ERROR("Attempt to free invalid context handle: %d\n", 49145132Sanholt ctx_handle); 50145132Sanholt return; 51145132Sanholt } 52145132Sanholt 53145132Sanholt DRM_LOCK(); 54145132Sanholt clear_bit(ctx_handle, dev->ctx_bitmap); 55145132Sanholt dev->context_sareas[ctx_handle] = NULL; 56145132Sanholt DRM_UNLOCK(); 57145132Sanholt return; 58145132Sanholt} 59145132Sanholt 60182080Srnolandint drm_ctxbitmap_next(struct drm_device *dev) 61145132Sanholt{ 62145132Sanholt int bit; 63145132Sanholt 64145132Sanholt if (dev->ctx_bitmap == NULL) 65145132Sanholt return -1; 66145132Sanholt 67145132Sanholt DRM_LOCK(); 68183573Srnoland bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP); 69145132Sanholt if (bit >= DRM_MAX_CTXBITMAP) { 70145132Sanholt DRM_UNLOCK(); 71145132Sanholt return -1; 72145132Sanholt } 73145132Sanholt 74145132Sanholt set_bit(bit, dev->ctx_bitmap); 75194539Srnoland DRM_DEBUG("bit : %d\n", bit); 76145132Sanholt if ((bit+1) > dev->max_context) { 77194539Srnoland drm_local_map_t **ctx_sareas; 78194539Srnoland int max_ctx = (bit+1); 79145132Sanholt 80194539Srnoland ctx_sareas = realloc(dev->context_sareas, 81194539Srnoland max_ctx * sizeof(*dev->context_sareas), 82194539Srnoland DRM_MEM_SAREA, M_NOWAIT); 83194539Srnoland if (ctx_sareas == NULL) { 84194539Srnoland clear_bit(bit, dev->ctx_bitmap); 85194539Srnoland DRM_DEBUG("failed to allocate bit : %d\n", bit); 86194539Srnoland DRM_UNLOCK(); 87194539Srnoland return -1; 88145132Sanholt } 89194539Srnoland dev->max_context = max_ctx; 90194539Srnoland dev->context_sareas = ctx_sareas; 91194539Srnoland dev->context_sareas[bit] = NULL; 92145132Sanholt } 93145132Sanholt DRM_UNLOCK(); 94145132Sanholt return bit; 95145132Sanholt} 96145132Sanholt 97182080Srnolandint drm_ctxbitmap_init(struct drm_device *dev) 98145132Sanholt{ 99145132Sanholt int i; 100145132Sanholt int temp; 101145132Sanholt 102145132Sanholt DRM_LOCK(); 103183833Srnoland dev->ctx_bitmap = malloc(PAGE_SIZE, DRM_MEM_CTXBITMAP, 104183833Srnoland M_NOWAIT | M_ZERO); 105183573Srnoland if (dev->ctx_bitmap == NULL) { 106145132Sanholt DRM_UNLOCK(); 107182080Srnoland return ENOMEM; 108145132Sanholt } 109145132Sanholt dev->context_sareas = NULL; 110145132Sanholt dev->max_context = -1; 111145132Sanholt DRM_UNLOCK(); 112145132Sanholt 113183573Srnoland for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { 114145132Sanholt temp = drm_ctxbitmap_next(dev); 115183573Srnoland DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp); 116145132Sanholt } 117145132Sanholt 118145132Sanholt return 0; 119145132Sanholt} 120145132Sanholt 121182080Srnolandvoid drm_ctxbitmap_cleanup(struct drm_device *dev) 122145132Sanholt{ 123145132Sanholt DRM_LOCK(); 124145132Sanholt if (dev->context_sareas != NULL) 125183833Srnoland free(dev->context_sareas, DRM_MEM_SAREA); 126183833Srnoland free(dev->ctx_bitmap, DRM_MEM_CTXBITMAP); 127145132Sanholt DRM_UNLOCK(); 128145132Sanholt} 129145132Sanholt 130145132Sanholt/* ================================================================ 131145132Sanholt * Per Context SAREA Support 132145132Sanholt */ 133145132Sanholt 134182080Srnolandint drm_getsareactx(struct drm_device *dev, void *data, 135182080Srnoland struct drm_file *file_priv) 136145132Sanholt{ 137183573Srnoland struct drm_ctx_priv_map *request = data; 138145132Sanholt drm_local_map_t *map; 139145132Sanholt 140145132Sanholt DRM_LOCK(); 141182080Srnoland if (dev->max_context < 0 || 142182080Srnoland request->ctx_id >= (unsigned) dev->max_context) { 143145132Sanholt DRM_UNLOCK(); 144182080Srnoland return EINVAL; 145145132Sanholt } 146145132Sanholt 147182080Srnoland map = dev->context_sareas[request->ctx_id]; 148145132Sanholt DRM_UNLOCK(); 149145132Sanholt 150207066Srnoland request->handle = (void *)map->handle; 151145132Sanholt 152145132Sanholt return 0; 153145132Sanholt} 154145132Sanholt 155182080Srnolandint drm_setsareactx(struct drm_device *dev, void *data, 156182080Srnoland struct drm_file *file_priv) 157145132Sanholt{ 158183573Srnoland struct drm_ctx_priv_map *request = data; 159145132Sanholt drm_local_map_t *map = NULL; 160145132Sanholt 161145132Sanholt DRM_LOCK(); 162145132Sanholt TAILQ_FOREACH(map, &dev->maplist, link) { 163182080Srnoland if (map->handle == request->handle) { 164145132Sanholt if (dev->max_context < 0) 165145132Sanholt goto bad; 166182080Srnoland if (request->ctx_id >= (unsigned) dev->max_context) 167145132Sanholt goto bad; 168182080Srnoland dev->context_sareas[request->ctx_id] = map; 169145132Sanholt DRM_UNLOCK(); 170145132Sanholt return 0; 171145132Sanholt } 172145132Sanholt } 173145132Sanholt 174145132Sanholtbad: 175145132Sanholt DRM_UNLOCK(); 176182080Srnoland return EINVAL; 177145132Sanholt} 178145132Sanholt 179145132Sanholt/* ================================================================ 180145132Sanholt * The actual DRM context handling routines 181145132Sanholt */ 182145132Sanholt 183182080Srnolandint drm_context_switch(struct drm_device *dev, int old, int new) 184145132Sanholt{ 185183573Srnoland if (test_and_set_bit(0, &dev->context_flag)) { 186183573Srnoland DRM_ERROR("Reentering -- FIXME\n"); 187183573Srnoland return EBUSY; 188183573Srnoland } 189145132Sanholt 190183573Srnoland DRM_DEBUG("Context switch from %d to %d\n", old, new); 191145132Sanholt 192183573Srnoland if (new == dev->last_context) { 193183573Srnoland clear_bit(0, &dev->context_flag); 194183573Srnoland return 0; 195183573Srnoland } 196145132Sanholt 197183573Srnoland return 0; 198145132Sanholt} 199145132Sanholt 200182080Srnolandint drm_context_switch_complete(struct drm_device *dev, int new) 201145132Sanholt{ 202183573Srnoland dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ 203145132Sanholt 204183573Srnoland if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { 205183573Srnoland DRM_ERROR("Lock isn't held after context switch\n"); 206183573Srnoland } 207145132Sanholt 208183573Srnoland /* If a context switch is ever initiated 209183573Srnoland when the kernel holds the lock, release 210183573Srnoland that lock here. */ 211183573Srnoland clear_bit(0, &dev->context_flag); 212145132Sanholt 213183573Srnoland return 0; 214145132Sanholt} 215145132Sanholt 216182080Srnolandint drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv) 217145132Sanholt{ 218183573Srnoland struct drm_ctx_res *res = data; 219183573Srnoland struct drm_ctx ctx; 220145132Sanholt int i; 221145132Sanholt 222183573Srnoland if (res->count >= DRM_RESERVED_CONTEXTS) { 223152909Sanholt bzero(&ctx, sizeof(ctx)); 224183573Srnoland for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { 225152909Sanholt ctx.handle = i; 226183573Srnoland if (DRM_COPY_TO_USER(&res->contexts[i], 227183573Srnoland &ctx, sizeof(ctx))) 228182080Srnoland return EFAULT; 229145132Sanholt } 230145132Sanholt } 231182080Srnoland res->count = DRM_RESERVED_CONTEXTS; 232145132Sanholt 233145132Sanholt return 0; 234145132Sanholt} 235145132Sanholt 236182080Srnolandint drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv) 237145132Sanholt{ 238183573Srnoland struct drm_ctx *ctx = data; 239145132Sanholt 240182080Srnoland ctx->handle = drm_ctxbitmap_next(dev); 241183573Srnoland if (ctx->handle == DRM_KERNEL_CONTEXT) { 242183573Srnoland /* Skip kernel's context and get a new one. */ 243182080Srnoland ctx->handle = drm_ctxbitmap_next(dev); 244145132Sanholt } 245183573Srnoland DRM_DEBUG("%d\n", ctx->handle); 246183573Srnoland if (ctx->handle == -1) { 247183573Srnoland DRM_DEBUG("Not enough free contexts.\n"); 248183573Srnoland /* Should this return -EBUSY instead? */ 249182080Srnoland return ENOMEM; 250145132Sanholt } 251145132Sanholt 252183573Srnoland if (dev->driver->context_ctor && ctx->handle != DRM_KERNEL_CONTEXT) { 253145132Sanholt DRM_LOCK(); 254183573Srnoland dev->driver->context_ctor(dev, ctx->handle); 255145132Sanholt DRM_UNLOCK(); 256145132Sanholt } 257145132Sanholt 258145132Sanholt return 0; 259145132Sanholt} 260145132Sanholt 261182080Srnolandint drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv) 262145132Sanholt{ 263145132Sanholt /* This does nothing */ 264145132Sanholt return 0; 265145132Sanholt} 266145132Sanholt 267182080Srnolandint drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv) 268145132Sanholt{ 269183573Srnoland struct drm_ctx *ctx = data; 270145132Sanholt 271145132Sanholt /* This is 0, because we don't handle any context flags */ 272182080Srnoland ctx->flags = 0; 273145132Sanholt 274145132Sanholt return 0; 275145132Sanholt} 276145132Sanholt 277182080Srnolandint drm_switchctx(struct drm_device *dev, void *data, 278182080Srnoland struct drm_file *file_priv) 279145132Sanholt{ 280183573Srnoland struct drm_ctx *ctx = data; 281145132Sanholt 282183573Srnoland DRM_DEBUG("%d\n", ctx->handle); 283182080Srnoland return drm_context_switch(dev, dev->last_context, ctx->handle); 284145132Sanholt} 285145132Sanholt 286182080Srnolandint drm_newctx(struct drm_device *dev, void *data, struct drm_file *file_priv) 287145132Sanholt{ 288183573Srnoland struct drm_ctx *ctx = data; 289145132Sanholt 290183573Srnoland DRM_DEBUG("%d\n", ctx->handle); 291182080Srnoland drm_context_switch_complete(dev, ctx->handle); 292145132Sanholt 293145132Sanholt return 0; 294145132Sanholt} 295145132Sanholt 296182080Srnolandint drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv) 297145132Sanholt{ 298183573Srnoland struct drm_ctx *ctx = data; 299145132Sanholt 300183573Srnoland DRM_DEBUG("%d\n", ctx->handle); 301183573Srnoland if (ctx->handle != DRM_KERNEL_CONTEXT) { 302183573Srnoland if (dev->driver->context_dtor) { 303145132Sanholt DRM_LOCK(); 304183573Srnoland dev->driver->context_dtor(dev, ctx->handle); 305145132Sanholt DRM_UNLOCK(); 306145132Sanholt } 307145132Sanholt 308182080Srnoland drm_ctxbitmap_free(dev, ctx->handle); 309145132Sanholt } 310145132Sanholt 311145132Sanholt return 0; 312145132Sanholt} 313