Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / drivers / char / drm / context.c
blob933fd0cd26330d09ae80fc80bb5a8fa14c1d788b
1 /* context.c -- IOCTLs for contexts and DMA queues -*- linux-c -*-
2 * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6 * All Rights Reserved.
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:
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.
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.
27 * Authors:
28 * Rickard E. (Rik) Faith <faith@valinux.com>
32 #define __NO_VERSION__
33 #include "drmP.h"
35 static int drm_init_queue(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx)
37 DRM_DEBUG("\n");
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));
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);
56 init_waitqueue_head(&q->write_queue);
57 init_waitqueue_head(&q->read_queue);
58 init_waitqueue_head(&q->flush_queue);
60 q->flags = ctx->flags;
62 drm_waitlist_create(&q->waitlist, dev->dma->buf_count);
64 return 0;
68 /* drm_alloc_queue:
69 PRE: 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
74 POST: 1) dev->queuelist[i].use_count == 1
75 2) dev->queue_count < dev->queue_slots */
77 static int drm_alloc_queue(drm_device_t *dev)
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;
91 atomic_dec(&dev->queuelist[i]->use_count);
93 /* Allocate a new queue */
94 down(&dev->struct_sem);
96 queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES);
97 memset(queue, 0, sizeof(*queue));
98 atomic_set(&queue->use_count, 1);
100 ++dev->queue_count;
101 if (dev->queue_count >= dev->queue_slots) {
102 oldslots = dev->queue_slots * sizeof(*dev->queuelist);
103 if (!dev->queue_slots) dev->queue_slots = 1;
104 dev->queue_slots *= 2;
105 newslots = dev->queue_slots * sizeof(*dev->queuelist);
107 dev->queuelist = drm_realloc(dev->queuelist,
108 oldslots,
109 newslots,
110 DRM_MEM_QUEUES);
111 if (!dev->queuelist) {
112 up(&dev->struct_sem);
113 DRM_DEBUG("out of memory\n");
114 return -ENOMEM;
117 dev->queuelist[dev->queue_count-1] = queue;
119 up(&dev->struct_sem);
120 DRM_DEBUG("%d (new)\n", dev->queue_count - 1);
121 return dev->queue_count - 1;
124 int drm_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
125 unsigned long arg)
127 drm_ctx_res_t res;
128 drm_ctx_t ctx;
129 int i;
131 DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
132 if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
133 return -EFAULT;
134 if (res.count >= DRM_RESERVED_CONTEXTS) {
135 memset(&ctx, 0, sizeof(ctx));
136 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
137 ctx.handle = i;
138 if (copy_to_user(&res.contexts[i],
140 sizeof(i)))
141 return -EFAULT;
144 res.count = DRM_RESERVED_CONTEXTS;
145 if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
146 return -EFAULT;
147 return 0;
151 int drm_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
152 unsigned long arg)
154 drm_file_t *priv = filp->private_data;
155 drm_device_t *dev = priv->dev;
156 drm_ctx_t ctx;
158 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
159 return -EFAULT;
160 if ((ctx.handle = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
161 /* Init kernel's context and get a new one. */
162 drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
163 ctx.handle = drm_alloc_queue(dev);
165 drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
166 DRM_DEBUG("%d\n", ctx.handle);
167 if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
168 return -EFAULT;
169 return 0;
172 int drm_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
173 unsigned long arg)
175 drm_file_t *priv = filp->private_data;
176 drm_device_t *dev = priv->dev;
177 drm_ctx_t ctx;
178 drm_queue_t *q;
180 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
181 return -EFAULT;
183 DRM_DEBUG("%d\n", ctx.handle);
185 if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL;
186 q = dev->queuelist[ctx.handle];
188 atomic_inc(&q->use_count);
189 if (atomic_read(&q->use_count) == 1) {
190 /* No longer in use */
191 atomic_dec(&q->use_count);
192 return -EINVAL;
195 if (DRM_BUFCOUNT(&q->waitlist)) {
196 atomic_dec(&q->use_count);
197 return -EBUSY;
200 q->flags = ctx.flags;
202 atomic_dec(&q->use_count);
203 return 0;
206 int drm_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
207 unsigned long arg)
209 drm_file_t *priv = filp->private_data;
210 drm_device_t *dev = priv->dev;
211 drm_ctx_t ctx;
212 drm_queue_t *q;
214 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
215 return -EFAULT;
217 DRM_DEBUG("%d\n", ctx.handle);
219 if (ctx.handle >= dev->queue_count) return -EINVAL;
220 q = dev->queuelist[ctx.handle];
222 atomic_inc(&q->use_count);
223 if (atomic_read(&q->use_count) == 1) {
224 /* No longer in use */
225 atomic_dec(&q->use_count);
226 return -EINVAL;
229 ctx.flags = q->flags;
230 atomic_dec(&q->use_count);
232 if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
233 return -EFAULT;
235 return 0;
238 int drm_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
239 unsigned long arg)
241 drm_file_t *priv = filp->private_data;
242 drm_device_t *dev = priv->dev;
243 drm_ctx_t ctx;
245 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
246 return -EFAULT;
247 DRM_DEBUG("%d\n", ctx.handle);
248 return drm_context_switch(dev, dev->last_context, ctx.handle);
251 int drm_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
252 unsigned long arg)
254 drm_file_t *priv = filp->private_data;
255 drm_device_t *dev = priv->dev;
256 drm_ctx_t ctx;
258 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
259 return -EFAULT;
260 DRM_DEBUG("%d\n", ctx.handle);
261 drm_context_switch_complete(dev, ctx.handle);
263 return 0;
266 int drm_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
267 unsigned long arg)
269 drm_file_t *priv = filp->private_data;
270 drm_device_t *dev = priv->dev;
271 drm_ctx_t ctx;
272 drm_queue_t *q;
273 drm_buf_t *buf;
275 if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
276 return -EFAULT;
277 DRM_DEBUG("%d\n", ctx.handle);
279 if (ctx.handle >= dev->queue_count) return -EINVAL;
280 q = dev->queuelist[ctx.handle];
282 atomic_inc(&q->use_count);
283 if (atomic_read(&q->use_count) == 1) {
284 /* No longer in use */
285 atomic_dec(&q->use_count);
286 return -EINVAL;
289 atomic_inc(&q->finalization); /* Mark queue in finalization state */
290 atomic_sub(2, &q->use_count); /* Mark queue as unused (pending
291 finalization) */
293 while (test_and_set_bit(0, &dev->interrupt_flag)) {
294 schedule();
295 if (signal_pending(current)) {
296 clear_bit(0, &dev->interrupt_flag);
297 return -EINTR;
300 /* Remove queued buffers */
301 while ((buf = drm_waitlist_get(&q->waitlist))) {
302 drm_free_buffer(dev, buf);
304 clear_bit(0, &dev->interrupt_flag);
306 /* Wakeup blocked processes */
307 wake_up_interruptible(&q->read_queue);
308 wake_up_interruptible(&q->write_queue);
309 wake_up_interruptible(&q->flush_queue);
311 /* Finalization over. Queue is made
312 available when both use_count and
313 finalization become 0, which won't
314 happen until all the waiting processes
315 stop waiting. */
316 atomic_dec(&q->finalization);
317 return 0;