1/* context.c -- IOCTLs for contexts and DMA queues -*- linux-c -*- 2 * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com 3 * 4 * Copyright 1999 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 * Authors: 28 * Rickard E. (Rik) Faith <faith@valinux.com> 29 * 30 */ 31 32#define __NO_VERSION__ 33#include "drmP.h" 34 35static int drm_init_queue(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx) 36{ 37 DRM_DEBUG("\n"); 38 39 if (atomic_read(&q->use_count) != 1 40 || atomic_read(&q->finalization) 41 || atomic_read(&q->block_count)) { 42 DRM_ERROR("New queue is already in use: u%d f%d b%d\n", 43 atomic_read(&q->use_count), 44 atomic_read(&q->finalization), 45 atomic_read(&q->block_count)); 46 } 47 48 atomic_set(&q->finalization, 0); 49 atomic_set(&q->block_count, 0); 50 atomic_set(&q->block_read, 0); 51 atomic_set(&q->block_write, 0); 52 atomic_set(&q->total_queued, 0); 53 atomic_set(&q->total_flushed, 0); 54 atomic_set(&q->total_locks, 0); 55 56 init_waitqueue_head(&q->write_queue); 57 init_waitqueue_head(&q->read_queue); 58 init_waitqueue_head(&q->flush_queue); 59 60 q->flags = ctx->flags; 61 62 drm_waitlist_create(&q->waitlist, dev->dma->buf_count); 63 64 return 0; 65} 66 67 68/* drm_alloc_queue: 69PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not 70 disappear (so all deallocation must be done after IOCTLs are off) 71 2) dev->queue_count < dev->queue_slots 72 3) dev->queuelist[i].use_count == 0 and 73 dev->queuelist[i].finalization == 0 if i not in use 74POST: 1) dev->queuelist[i].use_count == 1 75 2) dev->queue_count < dev->queue_slots */ 76 77static int drm_alloc_queue(drm_device_t *dev) 78{ 79 int i; 80 drm_queue_t *queue; 81 int oldslots; 82 int newslots; 83 /* Check for a free queue */ 84 for (i = 0; i < dev->queue_count; i++) { 85 atomic_inc(&dev->queuelist[i]->use_count); 86 if (atomic_read(&dev->queuelist[i]->use_count) == 1 87 && !atomic_read(&dev->queuelist[i]->finalization)) { 88 DRM_DEBUG("%d (free)\n", i); 89 return i; 90 } 91 atomic_dec(&dev->queuelist[i]->use_count); 92 } 93 /* Allocate a new queue */ 94 95 queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES); 96 if(queue == NULL) 97 return -ENOMEM; 98 99 memset(queue, 0, sizeof(*queue)); 100 down(&dev->struct_sem); 101 atomic_set(&queue->use_count, 1); 102 103 ++dev->queue_count; 104 if (dev->queue_count >= dev->queue_slots) { 105 oldslots = dev->queue_slots * sizeof(*dev->queuelist); 106 if (!dev->queue_slots) dev->queue_slots = 1; 107 dev->queue_slots *= 2; 108 newslots = dev->queue_slots * sizeof(*dev->queuelist); 109 110 dev->queuelist = drm_realloc(dev->queuelist, 111 oldslots, 112 newslots, 113 DRM_MEM_QUEUES); 114 if (!dev->queuelist) { 115 up(&dev->struct_sem); 116 DRM_DEBUG("out of memory\n"); 117 return -ENOMEM; 118 } 119 } 120 dev->queuelist[dev->queue_count-1] = queue; 121 122 up(&dev->struct_sem); 123 DRM_DEBUG("%d (new)\n", dev->queue_count - 1); 124 return dev->queue_count - 1; 125} 126 127int drm_resctx(struct inode *inode, struct file *filp, unsigned int cmd, 128 unsigned long arg) 129{ 130 drm_ctx_res_t res; 131 drm_ctx_t ctx; 132 int i; 133 134 DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); 135 if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res))) 136 return -EFAULT; 137 if (res.count >= DRM_RESERVED_CONTEXTS) { 138 memset(&ctx, 0, sizeof(ctx)); 139 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { 140 ctx.handle = i; 141 if (copy_to_user(&res.contexts[i], 142 &i, 143 sizeof(i))) 144 return -EFAULT; 145 } 146 } 147 res.count = DRM_RESERVED_CONTEXTS; 148 if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) 149 return -EFAULT; 150 return 0; 151} 152 153 154int drm_addctx(struct inode *inode, struct file *filp, unsigned int cmd, 155 unsigned long arg) 156{ 157 drm_file_t *priv = filp->private_data; 158 drm_device_t *dev = priv->dev; 159 drm_ctx_t ctx; 160 161 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) 162 return -EFAULT; 163 if ((ctx.handle = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { 164 /* Init kernel's context and get a new one. */ 165 drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx); 166 ctx.handle = drm_alloc_queue(dev); 167 } 168 drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx); 169 DRM_DEBUG("%d\n", ctx.handle); 170 if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) 171 return -EFAULT; 172 return 0; 173} 174 175int drm_modctx(struct inode *inode, struct file *filp, unsigned int cmd, 176 unsigned long arg) 177{ 178 drm_file_t *priv = filp->private_data; 179 drm_device_t *dev = priv->dev; 180 drm_ctx_t ctx; 181 drm_queue_t *q; 182 183 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) 184 return -EFAULT; 185 186 DRM_DEBUG("%d\n", ctx.handle); 187 188 if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL; 189 q = dev->queuelist[ctx.handle]; 190 191 atomic_inc(&q->use_count); 192 if (atomic_read(&q->use_count) == 1) { 193 /* No longer in use */ 194 atomic_dec(&q->use_count); 195 return -EINVAL; 196 } 197 198 if (DRM_BUFCOUNT(&q->waitlist)) { 199 atomic_dec(&q->use_count); 200 return -EBUSY; 201 } 202 203 q->flags = ctx.flags; 204 205 atomic_dec(&q->use_count); 206 return 0; 207} 208 209int drm_getctx(struct inode *inode, struct file *filp, unsigned int cmd, 210 unsigned long arg) 211{ 212 drm_file_t *priv = filp->private_data; 213 drm_device_t *dev = priv->dev; 214 drm_ctx_t ctx; 215 drm_queue_t *q; 216 217 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) 218 return -EFAULT; 219 220 DRM_DEBUG("%d\n", ctx.handle); 221 222 if (ctx.handle >= dev->queue_count) return -EINVAL; 223 q = dev->queuelist[ctx.handle]; 224 225 atomic_inc(&q->use_count); 226 if (atomic_read(&q->use_count) == 1) { 227 /* No longer in use */ 228 atomic_dec(&q->use_count); 229 return -EINVAL; 230 } 231 232 ctx.flags = q->flags; 233 atomic_dec(&q->use_count); 234 235 if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) 236 return -EFAULT; 237 238 return 0; 239} 240 241int drm_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, 242 unsigned long arg) 243{ 244 drm_file_t *priv = filp->private_data; 245 drm_device_t *dev = priv->dev; 246 drm_ctx_t ctx; 247 248 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) 249 return -EFAULT; 250 DRM_DEBUG("%d\n", ctx.handle); 251 return drm_context_switch(dev, dev->last_context, ctx.handle); 252} 253 254int drm_newctx(struct inode *inode, struct file *filp, unsigned int cmd, 255 unsigned long arg) 256{ 257 drm_file_t *priv = filp->private_data; 258 drm_device_t *dev = priv->dev; 259 drm_ctx_t ctx; 260 261 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) 262 return -EFAULT; 263 DRM_DEBUG("%d\n", ctx.handle); 264 drm_context_switch_complete(dev, ctx.handle); 265 266 return 0; 267} 268 269int drm_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, 270 unsigned long arg) 271{ 272 drm_file_t *priv = filp->private_data; 273 drm_device_t *dev = priv->dev; 274 drm_ctx_t ctx; 275 drm_queue_t *q; 276 drm_buf_t *buf; 277 278 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) 279 return -EFAULT; 280 DRM_DEBUG("%d\n", ctx.handle); 281 282 if (ctx.handle >= dev->queue_count) return -EINVAL; 283 q = dev->queuelist[ctx.handle]; 284 285 atomic_inc(&q->use_count); 286 if (atomic_read(&q->use_count) == 1) { 287 /* No longer in use */ 288 atomic_dec(&q->use_count); 289 return -EINVAL; 290 } 291 292 atomic_inc(&q->finalization); /* Mark queue in finalization state */ 293 atomic_sub(2, &q->use_count); /* Mark queue as unused (pending 294 finalization) */ 295 296 while (test_and_set_bit(0, &dev->interrupt_flag)) { 297 schedule(); 298 if (signal_pending(current)) { 299 clear_bit(0, &dev->interrupt_flag); 300 return -EINTR; 301 } 302 } 303 /* Remove queued buffers */ 304 while ((buf = drm_waitlist_get(&q->waitlist))) { 305 drm_free_buffer(dev, buf); 306 } 307 clear_bit(0, &dev->interrupt_flag); 308 309 /* Wakeup blocked processes */ 310 wake_up_interruptible(&q->read_queue); 311 wake_up_interruptible(&q->write_queue); 312 wake_up_interruptible(&q->flush_queue); 313 314 /* Finalization over. Queue is made 315 available when both use_count and 316 finalization become 0, which won't 317 happen until all the waiting processes 318 stop waiting. */ 319 atomic_dec(&q->finalization); 320 return 0; 321} 322