1/* r128_context.c -- IOCTLs for r128 contexts -*- linux-c -*- 2 * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com 3 * 4 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the next 16 * paragraph) shall be included in all copies or substantial portions of the 17 * Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 * DEALINGS IN THE SOFTWARE. 26 * 27 * Author: Rickard E. (Rik) Faith <faith@valinux.com> 28 * 29 */ 30 31#define __NO_VERSION__ 32#include "drmP.h" 33#include "r128_drv.h" 34 35extern drm_ctx_t r128_res_ctx; 36 37static int r128_alloc_queue(drm_device_t *dev) 38{ 39 return drm_ctxbitmap_next(dev); 40} 41 42int r128_context_switch(drm_device_t *dev, int old, int new) 43{ 44 char buf[64]; 45 46 atomic_inc(&dev->total_ctx); 47 48 if (test_and_set_bit(0, &dev->context_flag)) { 49 DRM_ERROR("Reentering -- FIXME\n"); 50 return -EBUSY; 51 } 52 53#if DRM_DMA_HISTOGRAM 54 dev->ctx_start = get_cycles(); 55#endif 56 57 DRM_DEBUG("Context switch from %d to %d\n", old, new); 58 59 if (new == dev->last_context) { 60 clear_bit(0, &dev->context_flag); 61 return 0; 62 } 63 64 if (drm_flags & DRM_FLAG_NOCTX) { 65 r128_context_switch_complete(dev, new); 66 } else { 67 sprintf(buf, "C %d %d\n", old, new); 68 drm_write_string(dev, buf); 69 } 70 71 return 0; 72} 73 74int r128_context_switch_complete(drm_device_t *dev, int new) 75{ 76 dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ 77 dev->last_switch = jiffies; 78 79 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { 80 DRM_ERROR("Lock isn't held after context switch\n"); 81 } 82 83 /* If a context switch is ever initiated 84 when the kernel holds the lock, release 85 that lock here. */ 86#if DRM_DMA_HISTOGRAM 87 atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles() 88 - dev->ctx_start)]); 89 90#endif 91 clear_bit(0, &dev->context_flag); 92 wake_up(&dev->context_wait); 93 94 return 0; 95} 96 97 98int r128_resctx(struct inode *inode, struct file *filp, unsigned int cmd, 99 unsigned long arg) 100{ 101 drm_ctx_res_t res; 102 drm_ctx_t ctx; 103 int i; 104 105 DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); 106 if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res))) 107 return -EFAULT; 108 if (res.count >= DRM_RESERVED_CONTEXTS) { 109 memset(&ctx, 0, sizeof(ctx)); 110 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { 111 ctx.handle = i; 112 if (copy_to_user(&res.contexts[i], 113 &i, 114 sizeof(i))) 115 return -EFAULT; 116 } 117 } 118 res.count = DRM_RESERVED_CONTEXTS; 119 if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) 120 return -EFAULT; 121 return 0; 122} 123 124 125int r128_addctx(struct inode *inode, struct file *filp, unsigned int cmd, 126 unsigned long arg) 127{ 128 drm_file_t *priv = filp->private_data; 129 drm_device_t *dev = priv->dev; 130 drm_ctx_t ctx; 131 132 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) 133 return -EFAULT; 134 if ((ctx.handle = r128_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { 135 /* Skip kernel's context and get a new one. */ 136 ctx.handle = r128_alloc_queue(dev); 137 } 138 DRM_DEBUG("%d\n", ctx.handle); 139 if (ctx.handle == -1) { 140 DRM_DEBUG("Not enough free contexts.\n"); 141 /* Should this return -EBUSY instead? */ 142 return -ENOMEM; 143 } 144 145 if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) 146 return -EFAULT; 147 return 0; 148} 149 150int r128_modctx(struct inode *inode, struct file *filp, unsigned int cmd, 151 unsigned long arg) 152{ 153 drm_ctx_t ctx; 154 155 if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) 156 return -EFAULT; 157 if (ctx.flags==_DRM_CONTEXT_PRESERVED) 158 r128_res_ctx.handle=ctx.handle; 159 return 0; 160} 161 162int r128_getctx(struct inode *inode, struct file *filp, unsigned int cmd, 163 unsigned long arg) 164{ 165 drm_ctx_t ctx; 166 167 if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) 168 return -EFAULT; 169 /* This is 0, because we don't hanlde any context flags */ 170 ctx.flags = 0; 171 if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx))) 172 return -EFAULT; 173 return 0; 174} 175 176int r128_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, 177 unsigned long arg) 178{ 179 drm_file_t *priv = filp->private_data; 180 drm_device_t *dev = priv->dev; 181 drm_ctx_t ctx; 182 183 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) 184 return -EFAULT; 185 DRM_DEBUG("%d\n", ctx.handle); 186 return r128_context_switch(dev, dev->last_context, ctx.handle); 187} 188 189int r128_newctx(struct inode *inode, struct file *filp, unsigned int cmd, 190 unsigned long arg) 191{ 192 drm_file_t *priv = filp->private_data; 193 drm_device_t *dev = priv->dev; 194 drm_ctx_t ctx; 195 196 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) 197 return -EFAULT; 198 DRM_DEBUG("%d\n", ctx.handle); 199 r128_context_switch_complete(dev, ctx.handle); 200 201 return 0; 202} 203 204int r128_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, 205 unsigned long arg) 206{ 207 drm_file_t *priv = filp->private_data; 208 drm_device_t *dev = priv->dev; 209 drm_ctx_t ctx; 210 211 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) 212 return -EFAULT; 213 DRM_DEBUG("%d\n", ctx.handle); 214 drm_ctxbitmap_free(dev, ctx.handle); 215 216 return 0; 217} 218