Import of XFree86 4.0
[platform/upstream/libdrm.git] / linux / tdfx_context.c
1 /* tdfx_context.c -- IOCTLs for tdfx contexts -*- linux-c -*-
2  * Created: Thu Oct  7 10:50:22 1999 by faith@precisioninsight.com
3  * Revised: Sat Oct  9 23:39:56 1999 by faith@precisioninsight.com
4  *
5  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
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  * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/tdfx_context.c,v 1.2 2000/02/23 04:47:30 martin Exp $
28  *
29  */
30
31 #include <linux/sched.h>
32
33 #define __NO_VERSION__
34 #include "drmP.h"
35 #include "tdfx_drv.h"
36
37 extern drm_ctx_t tdfx_res_ctx;
38
39 static int tdfx_alloc_queue(drm_device_t *dev)
40 {
41         static int context = 0;
42
43         return ++context;       /* Should this reuse contexts in the future? */
44 }
45
46 int tdfx_context_switch(drm_device_t *dev, int old, int new)
47 {
48         char        buf[64];
49
50         atomic_inc(&dev->total_ctx);
51
52         if (test_and_set_bit(0, &dev->context_flag)) {
53                 DRM_ERROR("Reentering -- FIXME\n");
54                 return -EBUSY;
55         }
56
57 #if DRM_DMA_HISTOGRAM
58         dev->ctx_start = get_cycles();
59 #endif
60         
61         DRM_DEBUG("Context switch from %d to %d\n", old, new);
62
63         if (new == dev->last_context) {
64                 clear_bit(0, &dev->context_flag);
65                 return 0;
66         }
67         
68         if (drm_flags & DRM_FLAG_NOCTX) {
69                 tdfx_context_switch_complete(dev, new);
70         } else {
71                 sprintf(buf, "C %d %d\n", old, new);
72                 drm_write_string(dev, buf);
73         }
74         
75         return 0;
76 }
77
78 int tdfx_context_switch_complete(drm_device_t *dev, int new)
79 {
80         dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
81         dev->last_switch  = jiffies;
82         
83         if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
84                 DRM_ERROR("Lock isn't held after context switch\n");
85         }
86
87                                 /* If a context switch is ever initiated
88                                    when the kernel holds the lock, release
89                                    that lock here. */
90 #if DRM_DMA_HISTOGRAM
91         atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
92                                                       - dev->ctx_start)]);
93                    
94 #endif
95         clear_bit(0, &dev->context_flag);
96         wake_up(&dev->context_wait);
97         
98         return 0;
99 }
100
101
102 int tdfx_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
103                unsigned long arg)
104 {
105         drm_ctx_res_t   res;
106         drm_ctx_t       ctx;
107         int             i;
108
109         DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
110         copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
111         if (res.count >= DRM_RESERVED_CONTEXTS) {
112                 memset(&ctx, 0, sizeof(ctx));
113                 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
114                         ctx.handle = i;
115                         copy_to_user_ret(&res.contexts[i],
116                                          &i,
117                                          sizeof(i),
118                                          -EFAULT);
119                 }
120         }
121         res.count = DRM_RESERVED_CONTEXTS;
122         copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
123         return 0;
124 }
125
126
127 int tdfx_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
128                unsigned long arg)
129 {
130         drm_file_t      *priv   = filp->private_data;
131         drm_device_t    *dev    = priv->dev;
132         drm_ctx_t       ctx;
133
134         copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
135         if ((ctx.handle = tdfx_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
136                                 /* Skip kernel's context and get a new one. */
137                 ctx.handle = tdfx_alloc_queue(dev);
138         }
139         DRM_DEBUG("%d\n", ctx.handle);
140         copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
141         return 0;
142 }
143
144 int tdfx_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
145         unsigned long arg)
146 {
147         drm_ctx_t ctx;
148
149         copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
150         if (ctx.flags==_DRM_CONTEXT_PRESERVED)
151                 tdfx_res_ctx.handle=ctx.handle;
152         return 0;
153 }
154
155 int tdfx_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
156         unsigned long arg)
157 {
158         drm_ctx_t ctx;
159
160         copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
161         /* This is 0, because we don't hanlde any context flags */
162         ctx.flags = 0;
163         copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
164         return 0;
165 }
166
167 int tdfx_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
168                    unsigned long arg)
169 {
170         drm_file_t      *priv   = filp->private_data;
171         drm_device_t    *dev    = priv->dev;
172         drm_ctx_t       ctx;
173
174         copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
175         DRM_DEBUG("%d\n", ctx.handle);
176         return tdfx_context_switch(dev, dev->last_context, ctx.handle);
177 }
178
179 int tdfx_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
180                 unsigned long arg)
181 {
182         drm_file_t      *priv   = filp->private_data;
183         drm_device_t    *dev    = priv->dev;
184         drm_ctx_t       ctx;
185
186         copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
187         DRM_DEBUG("%d\n", ctx.handle);
188         tdfx_context_switch_complete(dev, ctx.handle);
189
190         return 0;
191 }
192
193 int tdfx_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
194                unsigned long arg)
195 {
196         drm_ctx_t       ctx;
197
198         copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
199         DRM_DEBUG("%d\n", ctx.handle);
200                                 /* This is currently a noop because we
201                                    don't reuse context values.  Perhaps we
202                                    should? */
203         
204         return 0;
205 }