Pull altix-fpga-reset into release branch
[sfrench/cifs-2.6.git] / drivers / char / drm / mga_state.c
1 /* mga_state.c -- State support for MGA G200/G400 -*- linux-c -*-
2  * Created: Thu Jan 27 02:53:43 2000 by jhartmann@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  * VA LINUX SYSTEMS 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
25  * OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * Authors:
28  *    Jeff Hartmann <jhartmann@valinux.com>
29  *    Keith Whitwell <keith@tungstengraphics.com>
30  *
31  * Rewritten by:
32  *    Gareth Hughes <gareth@valinux.com>
33  */
34
35 #include "drmP.h"
36 #include "drm.h"
37 #include "mga_drm.h"
38 #include "mga_drv.h"
39
40 /* ================================================================
41  * DMA hardware state programming functions
42  */
43
44 static void mga_emit_clip_rect( drm_mga_private_t *dev_priv,
45                                 drm_clip_rect_t *box )
46 {
47         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
48         drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
49         unsigned int pitch = dev_priv->front_pitch;
50         DMA_LOCALS;
51
52         BEGIN_DMA( 2 );
53
54         /* Force reset of DWGCTL on G400 (eliminates clip disable bit).
55          */
56         if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
57                 DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl,
58                           MGA_LEN + MGA_EXEC, 0x80000000,
59                           MGA_DWGCTL, ctx->dwgctl,
60                           MGA_LEN + MGA_EXEC, 0x80000000);
61         }
62         DMA_BLOCK(MGA_DMAPAD, 0x00000000,
63                   MGA_CXBNDRY, ((box->x2 - 1) << 16) | box->x1,
64                   MGA_YTOP, box->y1 * pitch,
65                   MGA_YBOT, (box->y2 - 1) * pitch);
66
67         ADVANCE_DMA();
68 }
69
70 static __inline__ void mga_g200_emit_context( drm_mga_private_t *dev_priv )
71 {
72         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
73         drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
74         DMA_LOCALS;
75
76         BEGIN_DMA( 3 );
77
78         DMA_BLOCK( MGA_DSTORG,          ctx->dstorg,
79                    MGA_MACCESS,         ctx->maccess,
80                    MGA_PLNWT,           ctx->plnwt,
81                    MGA_DWGCTL,          ctx->dwgctl );
82
83         DMA_BLOCK( MGA_ALPHACTRL,       ctx->alphactrl,
84                    MGA_FOGCOL,          ctx->fogcolor,
85                    MGA_WFLAG,           ctx->wflag,
86                    MGA_ZORG,            dev_priv->depth_offset );
87
88         DMA_BLOCK( MGA_FCOL,            ctx->fcol,
89                    MGA_DMAPAD,          0x00000000,
90                    MGA_DMAPAD,          0x00000000,
91                    MGA_DMAPAD,          0x00000000 );
92
93         ADVANCE_DMA();
94 }
95
96 static __inline__ void mga_g400_emit_context( drm_mga_private_t *dev_priv )
97 {
98         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
99         drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
100         DMA_LOCALS;
101
102         BEGIN_DMA( 4 );
103
104         DMA_BLOCK( MGA_DSTORG,          ctx->dstorg,
105                    MGA_MACCESS,         ctx->maccess,
106                    MGA_PLNWT,           ctx->plnwt,
107                    MGA_DWGCTL,          ctx->dwgctl );
108
109         DMA_BLOCK( MGA_ALPHACTRL,       ctx->alphactrl,
110                    MGA_FOGCOL,          ctx->fogcolor,
111                    MGA_WFLAG,           ctx->wflag,
112                    MGA_ZORG,            dev_priv->depth_offset );
113
114         DMA_BLOCK( MGA_WFLAG1,          ctx->wflag,
115                    MGA_TDUALSTAGE0,     ctx->tdualstage0,
116                    MGA_TDUALSTAGE1,     ctx->tdualstage1,
117                    MGA_FCOL,            ctx->fcol );
118
119         DMA_BLOCK( MGA_STENCIL,         ctx->stencil,
120                    MGA_STENCILCTL,      ctx->stencilctl,
121                    MGA_DMAPAD,          0x00000000,
122                    MGA_DMAPAD,          0x00000000 );
123
124         ADVANCE_DMA();
125 }
126
127 static __inline__ void mga_g200_emit_tex0( drm_mga_private_t *dev_priv )
128 {
129         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
130         drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
131         DMA_LOCALS;
132
133         BEGIN_DMA( 4 );
134
135         DMA_BLOCK( MGA_TEXCTL2,         tex->texctl2,
136                    MGA_TEXCTL,          tex->texctl,
137                    MGA_TEXFILTER,       tex->texfilter,
138                    MGA_TEXBORDERCOL,    tex->texbordercol );
139
140         DMA_BLOCK( MGA_TEXORG,          tex->texorg,
141                    MGA_TEXORG1,         tex->texorg1,
142                    MGA_TEXORG2,         tex->texorg2,
143                    MGA_TEXORG3,         tex->texorg3 );
144
145         DMA_BLOCK( MGA_TEXORG4,         tex->texorg4,
146                    MGA_TEXWIDTH,        tex->texwidth,
147                    MGA_TEXHEIGHT,       tex->texheight,
148                    MGA_WR24,            tex->texwidth );
149
150         DMA_BLOCK( MGA_WR34,            tex->texheight,
151                    MGA_TEXTRANS,        0x0000ffff,
152                    MGA_TEXTRANSHIGH,    0x0000ffff,
153                    MGA_DMAPAD,          0x00000000 );
154
155         ADVANCE_DMA();
156 }
157
158 static __inline__ void mga_g400_emit_tex0( drm_mga_private_t *dev_priv )
159 {
160         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
161         drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
162         DMA_LOCALS;
163
164 /*      printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */
165 /*             tex->texctl, tex->texctl2); */
166
167         BEGIN_DMA( 6 );
168
169         DMA_BLOCK( MGA_TEXCTL2,         tex->texctl2 | MGA_G400_TC2_MAGIC,
170                    MGA_TEXCTL,          tex->texctl,
171                    MGA_TEXFILTER,       tex->texfilter,
172                    MGA_TEXBORDERCOL,    tex->texbordercol );
173
174         DMA_BLOCK( MGA_TEXORG,          tex->texorg,
175                    MGA_TEXORG1,         tex->texorg1,
176                    MGA_TEXORG2,         tex->texorg2,
177                    MGA_TEXORG3,         tex->texorg3 );
178
179         DMA_BLOCK( MGA_TEXORG4,         tex->texorg4,
180                    MGA_TEXWIDTH,        tex->texwidth,
181                    MGA_TEXHEIGHT,       tex->texheight,
182                    MGA_WR49,            0x00000000 );
183
184         DMA_BLOCK( MGA_WR57,            0x00000000,
185                    MGA_WR53,            0x00000000,
186                    MGA_WR61,            0x00000000,
187                    MGA_WR52,            MGA_G400_WR_MAGIC );
188
189         DMA_BLOCK( MGA_WR60,            MGA_G400_WR_MAGIC,
190                    MGA_WR54,            tex->texwidth | MGA_G400_WR_MAGIC,
191                    MGA_WR62,            tex->texheight | MGA_G400_WR_MAGIC,
192                    MGA_DMAPAD,          0x00000000 );
193
194         DMA_BLOCK( MGA_DMAPAD,          0x00000000,
195                    MGA_DMAPAD,          0x00000000,
196                    MGA_TEXTRANS,        0x0000ffff,
197                    MGA_TEXTRANSHIGH,    0x0000ffff );
198
199         ADVANCE_DMA();
200 }
201
202 static __inline__ void mga_g400_emit_tex1( drm_mga_private_t *dev_priv )
203 {
204         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
205         drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1];
206         DMA_LOCALS;
207
208 /*      printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg,  */
209 /*             tex->texctl, tex->texctl2); */
210
211         BEGIN_DMA( 5 );
212
213         DMA_BLOCK( MGA_TEXCTL2,         (tex->texctl2 |
214                                          MGA_MAP1_ENABLE |
215                                          MGA_G400_TC2_MAGIC),
216                    MGA_TEXCTL,          tex->texctl,
217                    MGA_TEXFILTER,       tex->texfilter,
218                    MGA_TEXBORDERCOL,    tex->texbordercol );
219
220         DMA_BLOCK( MGA_TEXORG,          tex->texorg,
221                    MGA_TEXORG1,         tex->texorg1,
222                    MGA_TEXORG2,         tex->texorg2,
223                    MGA_TEXORG3,         tex->texorg3 );
224
225         DMA_BLOCK( MGA_TEXORG4,         tex->texorg4,
226                    MGA_TEXWIDTH,        tex->texwidth,
227                    MGA_TEXHEIGHT,       tex->texheight,
228                    MGA_WR49,            0x00000000 );
229
230         DMA_BLOCK( MGA_WR57,            0x00000000,
231                    MGA_WR53,            0x00000000,
232                    MGA_WR61,            0x00000000,
233                    MGA_WR52,            tex->texwidth | MGA_G400_WR_MAGIC );
234
235         DMA_BLOCK( MGA_WR60,            tex->texheight | MGA_G400_WR_MAGIC,
236                    MGA_TEXTRANS,        0x0000ffff,
237                    MGA_TEXTRANSHIGH,    0x0000ffff,
238                    MGA_TEXCTL2,         tex->texctl2 | MGA_G400_TC2_MAGIC );
239
240         ADVANCE_DMA();
241 }
242
243 static __inline__ void mga_g200_emit_pipe( drm_mga_private_t *dev_priv )
244 {
245         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
246         unsigned int pipe = sarea_priv->warp_pipe;
247         DMA_LOCALS;
248
249         BEGIN_DMA( 3 );
250
251         DMA_BLOCK( MGA_WIADDR,  MGA_WMODE_SUSPEND,
252                    MGA_WVRTXSZ, 0x00000007,
253                    MGA_WFLAG,   0x00000000,
254                    MGA_WR24,    0x00000000 );
255
256         DMA_BLOCK( MGA_WR25,    0x00000100,
257                    MGA_WR34,    0x00000000,
258                    MGA_WR42,    0x0000ffff,
259                    MGA_WR60,    0x0000ffff );
260
261         /* Padding required to to hardware bug.
262          */
263         DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
264                   MGA_DMAPAD, 0xffffffff,
265                   MGA_DMAPAD, 0xffffffff,
266                   MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] |
267                                MGA_WMODE_START | dev_priv->wagp_enable));
268
269         ADVANCE_DMA();
270 }
271
272 static __inline__ void mga_g400_emit_pipe( drm_mga_private_t *dev_priv )
273 {
274         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
275         unsigned int pipe = sarea_priv->warp_pipe;
276         DMA_LOCALS;
277
278 /*      printk("mga_g400_emit_pipe %x\n", pipe); */
279
280         BEGIN_DMA( 10 );
281
282         DMA_BLOCK( MGA_WIADDR2, MGA_WMODE_SUSPEND,
283                    MGA_DMAPAD,  0x00000000,
284                    MGA_DMAPAD,  0x00000000,
285                    MGA_DMAPAD,  0x00000000 );
286
287         if ( pipe & MGA_T2 ) {
288                 DMA_BLOCK( MGA_WVRTXSZ,         0x00001e09,
289                            MGA_DMAPAD,          0x00000000,
290                            MGA_DMAPAD,          0x00000000,
291                            MGA_DMAPAD,          0x00000000 );
292
293                 DMA_BLOCK( MGA_WACCEPTSEQ,      0x00000000,
294                            MGA_WACCEPTSEQ,      0x00000000,
295                            MGA_WACCEPTSEQ,      0x00000000,
296                            MGA_WACCEPTSEQ,      0x1e000000 );
297         } else {
298                 if ( dev_priv->warp_pipe & MGA_T2 ) {
299                         /* Flush the WARP pipe */
300                         DMA_BLOCK( MGA_YDST,            0x00000000,
301                                    MGA_FXLEFT,          0x00000000,
302                                    MGA_FXRIGHT,         0x00000001,
303                                    MGA_DWGCTL,          MGA_DWGCTL_FLUSH );
304
305                         DMA_BLOCK( MGA_LEN + MGA_EXEC,  0x00000001,
306                                    MGA_DWGSYNC,         0x00007000,
307                                    MGA_TEXCTL2,         MGA_G400_TC2_MAGIC,
308                                    MGA_LEN + MGA_EXEC,  0x00000000 );
309
310                         DMA_BLOCK( MGA_TEXCTL2,         (MGA_DUALTEX |
311                                                          MGA_G400_TC2_MAGIC),
312                                    MGA_LEN + MGA_EXEC,  0x00000000,
313                                    MGA_TEXCTL2,         MGA_G400_TC2_MAGIC,
314                                    MGA_DMAPAD,          0x00000000 );
315                 }
316
317                 DMA_BLOCK( MGA_WVRTXSZ,         0x00001807,
318                            MGA_DMAPAD,          0x00000000,
319                            MGA_DMAPAD,          0x00000000,
320                            MGA_DMAPAD,          0x00000000 );
321
322                 DMA_BLOCK( MGA_WACCEPTSEQ,      0x00000000,
323                            MGA_WACCEPTSEQ,      0x00000000,
324                            MGA_WACCEPTSEQ,      0x00000000,
325                            MGA_WACCEPTSEQ,      0x18000000 );
326         }
327
328         DMA_BLOCK( MGA_WFLAG,   0x00000000,
329                    MGA_WFLAG1,  0x00000000,
330                    MGA_WR56,    MGA_G400_WR56_MAGIC,
331                    MGA_DMAPAD,  0x00000000 );
332
333         DMA_BLOCK( MGA_WR49,    0x00000000,             /* tex0              */
334                    MGA_WR57,    0x00000000,             /* tex0              */
335                    MGA_WR53,    0x00000000,             /* tex1              */
336                    MGA_WR61,    0x00000000 );           /* tex1              */
337
338         DMA_BLOCK( MGA_WR54,    MGA_G400_WR_MAGIC,      /* tex0 width        */
339                    MGA_WR62,    MGA_G400_WR_MAGIC,      /* tex0 height       */
340                    MGA_WR52,    MGA_G400_WR_MAGIC,      /* tex1 width        */
341                    MGA_WR60,    MGA_G400_WR_MAGIC );    /* tex1 height       */
342
343         /* Padding required to to hardware bug */
344         DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
345                   MGA_DMAPAD, 0xffffffff,
346                   MGA_DMAPAD, 0xffffffff,
347                   MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] |
348                                 MGA_WMODE_START | dev_priv->wagp_enable));
349
350         ADVANCE_DMA();
351 }
352
353 static void mga_g200_emit_state( drm_mga_private_t *dev_priv )
354 {
355         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
356         unsigned int dirty = sarea_priv->dirty;
357
358         if ( sarea_priv->warp_pipe != dev_priv->warp_pipe ) {
359                 mga_g200_emit_pipe( dev_priv );
360                 dev_priv->warp_pipe = sarea_priv->warp_pipe;
361         }
362
363         if ( dirty & MGA_UPLOAD_CONTEXT ) {
364                 mga_g200_emit_context( dev_priv );
365                 sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT;
366         }
367
368         if ( dirty & MGA_UPLOAD_TEX0 ) {
369                 mga_g200_emit_tex0( dev_priv );
370                 sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
371         }
372 }
373
374 static void mga_g400_emit_state( drm_mga_private_t *dev_priv )
375 {
376         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
377         unsigned int dirty = sarea_priv->dirty;
378         int multitex = sarea_priv->warp_pipe & MGA_T2;
379
380         if ( sarea_priv->warp_pipe != dev_priv->warp_pipe ) {
381                 mga_g400_emit_pipe( dev_priv );
382                 dev_priv->warp_pipe = sarea_priv->warp_pipe;
383         }
384
385         if ( dirty & MGA_UPLOAD_CONTEXT ) {
386                 mga_g400_emit_context( dev_priv );
387                 sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT;
388         }
389
390         if ( dirty & MGA_UPLOAD_TEX0 ) {
391                 mga_g400_emit_tex0( dev_priv );
392                 sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
393         }
394
395         if ( (dirty & MGA_UPLOAD_TEX1) && multitex ) {
396                 mga_g400_emit_tex1( dev_priv );
397                 sarea_priv->dirty &= ~MGA_UPLOAD_TEX1;
398         }
399 }
400
401
402 /* ================================================================
403  * SAREA state verification
404  */
405
406 /* Disallow all write destinations except the front and backbuffer.
407  */
408 static int mga_verify_context( drm_mga_private_t *dev_priv )
409 {
410         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
411         drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
412
413         if ( ctx->dstorg != dev_priv->front_offset &&
414              ctx->dstorg != dev_priv->back_offset ) {
415                 DRM_ERROR( "*** bad DSTORG: %x (front %x, back %x)\n\n",
416                            ctx->dstorg, dev_priv->front_offset,
417                            dev_priv->back_offset );
418                 ctx->dstorg = 0;
419                 return DRM_ERR(EINVAL);
420         }
421
422         return 0;
423 }
424
425 /* Disallow texture reads from PCI space.
426  */
427 static int mga_verify_tex( drm_mga_private_t *dev_priv, int unit )
428 {
429         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
430         drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[unit];
431         unsigned int org;
432
433         org = tex->texorg & (MGA_TEXORGMAP_MASK | MGA_TEXORGACC_MASK);
434
435         if ( org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI) ) {
436                 DRM_ERROR( "*** bad TEXORG: 0x%x, unit %d\n",
437                            tex->texorg, unit );
438                 tex->texorg = 0;
439                 return DRM_ERR(EINVAL);
440         }
441
442         return 0;
443 }
444
445 static int mga_verify_state( drm_mga_private_t *dev_priv )
446 {
447         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
448         unsigned int dirty = sarea_priv->dirty;
449         int ret = 0;
450
451         if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS )
452                 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
453
454         if ( dirty & MGA_UPLOAD_CONTEXT )
455                 ret |= mga_verify_context( dev_priv );
456
457         if ( dirty & MGA_UPLOAD_TEX0 )
458                 ret |= mga_verify_tex( dev_priv, 0 );
459
460         if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
461                 if (dirty & MGA_UPLOAD_TEX1)
462                         ret |= mga_verify_tex(dev_priv, 1);
463
464                 if ( dirty & MGA_UPLOAD_PIPE )
465                         ret |= ( sarea_priv->warp_pipe > MGA_MAX_G400_PIPES );
466         } else {
467                 if ( dirty & MGA_UPLOAD_PIPE )
468                         ret |= ( sarea_priv->warp_pipe > MGA_MAX_G200_PIPES );
469         }
470
471         return ( ret == 0 );
472 }
473
474 static int mga_verify_iload( drm_mga_private_t *dev_priv,
475                              unsigned int dstorg, unsigned int length )
476 {
477         if ( dstorg < dev_priv->texture_offset ||
478              dstorg + length > (dev_priv->texture_offset +
479                                 dev_priv->texture_size) ) {
480                 DRM_ERROR( "*** bad iload DSTORG: 0x%x\n", dstorg );
481                 return DRM_ERR(EINVAL);
482         }
483
484         if ( length & MGA_ILOAD_MASK ) {
485                 DRM_ERROR( "*** bad iload length: 0x%x\n",
486                            length & MGA_ILOAD_MASK );
487                 return DRM_ERR(EINVAL);
488         }
489
490         return 0;
491 }
492
493 static int mga_verify_blit( drm_mga_private_t *dev_priv,
494                             unsigned int srcorg, unsigned int dstorg )
495 {
496         if ( (srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ||
497              (dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ) {
498                 DRM_ERROR( "*** bad blit: src=0x%x dst=0x%x\n",
499                            srcorg, dstorg );
500                 return DRM_ERR(EINVAL);
501         }
502         return 0;
503 }
504
505
506 /* ================================================================
507  *
508  */
509
510 static void mga_dma_dispatch_clear( drm_device_t *dev,
511                                     drm_mga_clear_t *clear )
512 {
513         drm_mga_private_t *dev_priv = dev->dev_private;
514         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
515         drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
516         drm_clip_rect_t *pbox = sarea_priv->boxes;
517         int nbox = sarea_priv->nbox;
518         int i;
519         DMA_LOCALS;
520         DRM_DEBUG( "\n" );
521
522         BEGIN_DMA( 1 );
523
524         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
525                    MGA_DMAPAD,  0x00000000,
526                    MGA_DWGSYNC, 0x00007100,
527                    MGA_DWGSYNC, 0x00007000 );
528
529         ADVANCE_DMA();
530
531         for ( i = 0 ; i < nbox ; i++ ) {
532                 drm_clip_rect_t *box = &pbox[i];
533                 u32 height = box->y2 - box->y1;
534
535                 DRM_DEBUG( "   from=%d,%d to=%d,%d\n",
536                            box->x1, box->y1, box->x2, box->y2 );
537
538                 if ( clear->flags & MGA_FRONT ) {
539                         BEGIN_DMA( 2 );
540
541                         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
542                                    MGA_PLNWT,   clear->color_mask,
543                                    MGA_YDSTLEN, (box->y1 << 16) | height,
544                                    MGA_FXBNDRY, (box->x2 << 16) | box->x1 );
545
546                         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
547                                    MGA_FCOL,    clear->clear_color,
548                                    MGA_DSTORG,  dev_priv->front_offset,
549                                    MGA_DWGCTL + MGA_EXEC,
550                                                 dev_priv->clear_cmd );
551
552                         ADVANCE_DMA();
553                 }
554
555
556                 if ( clear->flags & MGA_BACK ) {
557                         BEGIN_DMA( 2 );
558
559                         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
560                                    MGA_PLNWT,   clear->color_mask,
561                                    MGA_YDSTLEN, (box->y1 << 16) | height,
562                                    MGA_FXBNDRY, (box->x2 << 16) | box->x1 );
563
564                         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
565                                    MGA_FCOL,    clear->clear_color,
566                                    MGA_DSTORG,  dev_priv->back_offset,
567                                    MGA_DWGCTL + MGA_EXEC,
568                                                 dev_priv->clear_cmd );
569
570                         ADVANCE_DMA();
571                 }
572
573                 if ( clear->flags & MGA_DEPTH ) {
574                         BEGIN_DMA( 2 );
575
576                         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
577                                    MGA_PLNWT,   clear->depth_mask,
578                                    MGA_YDSTLEN, (box->y1 << 16) | height,
579                                    MGA_FXBNDRY, (box->x2 << 16) | box->x1 );
580
581                         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
582                                    MGA_FCOL,    clear->clear_depth,
583                                    MGA_DSTORG,  dev_priv->depth_offset,
584                                    MGA_DWGCTL + MGA_EXEC,
585                                                 dev_priv->clear_cmd );
586
587                         ADVANCE_DMA();
588                 }
589
590         }
591
592         BEGIN_DMA( 1 );
593
594         /* Force reset of DWGCTL */
595         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
596                    MGA_DMAPAD,  0x00000000,
597                    MGA_PLNWT,   ctx->plnwt,
598                    MGA_DWGCTL,  ctx->dwgctl );
599
600         ADVANCE_DMA();
601
602         FLUSH_DMA();
603 }
604
605 static void mga_dma_dispatch_swap( drm_device_t *dev )
606 {
607         drm_mga_private_t *dev_priv = dev->dev_private;
608         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
609         drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
610         drm_clip_rect_t *pbox = sarea_priv->boxes;
611         int nbox = sarea_priv->nbox;
612         int i;
613         DMA_LOCALS;
614         DRM_DEBUG( "\n" );
615
616         sarea_priv->last_frame.head = dev_priv->prim.tail;
617         sarea_priv->last_frame.wrap = dev_priv->prim.last_wrap;
618
619         BEGIN_DMA( 4 + nbox );
620
621         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
622                    MGA_DMAPAD,  0x00000000,
623                    MGA_DWGSYNC, 0x00007100,
624                    MGA_DWGSYNC, 0x00007000 );
625
626         DMA_BLOCK( MGA_DSTORG,  dev_priv->front_offset,
627                    MGA_MACCESS, dev_priv->maccess,
628                    MGA_SRCORG,  dev_priv->back_offset,
629                    MGA_AR5,     dev_priv->front_pitch );
630
631         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
632                    MGA_DMAPAD,  0x00000000,
633                    MGA_PLNWT,   0xffffffff,
634                    MGA_DWGCTL,  MGA_DWGCTL_COPY );
635
636         for ( i = 0 ; i < nbox ; i++ ) {
637                 drm_clip_rect_t *box = &pbox[i];
638                 u32 height = box->y2 - box->y1;
639                 u32 start = box->y1 * dev_priv->front_pitch;
640
641                 DRM_DEBUG( "   from=%d,%d to=%d,%d\n",
642                            box->x1, box->y1, box->x2, box->y2 );
643
644                 DMA_BLOCK( MGA_AR0,     start + box->x2 - 1,
645                            MGA_AR3,     start + box->x1,
646                            MGA_FXBNDRY, ((box->x2 - 1) << 16) | box->x1,
647                            MGA_YDSTLEN + MGA_EXEC,
648                                         (box->y1 << 16) | height );
649         }
650
651         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
652                    MGA_PLNWT,   ctx->plnwt,
653                    MGA_SRCORG,  dev_priv->front_offset,
654                    MGA_DWGCTL,  ctx->dwgctl );
655
656         ADVANCE_DMA();
657
658         FLUSH_DMA();
659
660         DRM_DEBUG( "%s... done.\n", __FUNCTION__ );
661 }
662
663 static void mga_dma_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf )
664 {
665         drm_mga_private_t *dev_priv = dev->dev_private;
666         drm_mga_buf_priv_t *buf_priv = buf->dev_private;
667         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
668         u32 address = (u32) buf->bus_address;
669         u32 length = (u32) buf->used;
670         int i = 0;
671         DMA_LOCALS;
672         DRM_DEBUG( "vertex: buf=%d used=%d\n", buf->idx, buf->used );
673
674         if ( buf->used ) {
675                 buf_priv->dispatched = 1;
676
677                 MGA_EMIT_STATE( dev_priv, sarea_priv->dirty );
678
679                 do {
680                         if ( i < sarea_priv->nbox ) {
681                                 mga_emit_clip_rect( dev_priv,
682                                                     &sarea_priv->boxes[i] );
683                         }
684
685                         BEGIN_DMA( 1 );
686
687                         DMA_BLOCK(MGA_DMAPAD, 0x00000000,
688                                   MGA_DMAPAD, 0x00000000,
689                                   MGA_SECADDRESS, (address |
690                                                    MGA_DMA_VERTEX),
691                                   MGA_SECEND, ((address + length) |
692                                                dev_priv->dma_access));
693
694                         ADVANCE_DMA();
695                 } while ( ++i < sarea_priv->nbox );
696         }
697
698         if ( buf_priv->discard ) {
699                 AGE_BUFFER( buf_priv );
700                 buf->pending = 0;
701                 buf->used = 0;
702                 buf_priv->dispatched = 0;
703
704                 mga_freelist_put( dev, buf );
705         }
706
707         FLUSH_DMA();
708 }
709
710 static void mga_dma_dispatch_indices( drm_device_t *dev, drm_buf_t *buf,
711                                       unsigned int start, unsigned int end )
712 {
713         drm_mga_private_t *dev_priv = dev->dev_private;
714         drm_mga_buf_priv_t *buf_priv = buf->dev_private;
715         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
716         u32 address = (u32) buf->bus_address;
717         int i = 0;
718         DMA_LOCALS;
719         DRM_DEBUG( "indices: buf=%d start=%d end=%d\n", buf->idx, start, end );
720
721         if ( start != end ) {
722                 buf_priv->dispatched = 1;
723
724                 MGA_EMIT_STATE( dev_priv, sarea_priv->dirty );
725
726                 do {
727                         if ( i < sarea_priv->nbox ) {
728                                 mga_emit_clip_rect( dev_priv,
729                                                     &sarea_priv->boxes[i] );
730                         }
731
732                         BEGIN_DMA( 1 );
733
734                         DMA_BLOCK(MGA_DMAPAD, 0x00000000,
735                                   MGA_DMAPAD, 0x00000000,
736                                   MGA_SETUPADDRESS, address + start,
737                                   MGA_SETUPEND, ((address + end) |
738                                                  dev_priv->dma_access));
739
740                         ADVANCE_DMA();
741                 } while ( ++i < sarea_priv->nbox );
742         }
743
744         if ( buf_priv->discard ) {
745                 AGE_BUFFER( buf_priv );
746                 buf->pending = 0;
747                 buf->used = 0;
748                 buf_priv->dispatched = 0;
749
750                 mga_freelist_put( dev, buf );
751         }
752
753         FLUSH_DMA();
754 }
755
756 /* This copies a 64 byte aligned agp region to the frambuffer with a
757  * standard blit, the ioctl needs to do checking.
758  */
759 static void mga_dma_dispatch_iload( drm_device_t *dev, drm_buf_t *buf,
760                                     unsigned int dstorg, unsigned int length )
761 {
762         drm_mga_private_t *dev_priv = dev->dev_private;
763         drm_mga_buf_priv_t *buf_priv = buf->dev_private;
764         drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state;
765         u32 srcorg = buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM;
766         u32 y2;
767         DMA_LOCALS;
768         DRM_DEBUG( "buf=%d used=%d\n", buf->idx, buf->used );
769
770         y2 = length / 64;
771
772         BEGIN_DMA( 5 );
773
774         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
775                    MGA_DMAPAD,  0x00000000,
776                    MGA_DWGSYNC, 0x00007100,
777                    MGA_DWGSYNC, 0x00007000 );
778
779         DMA_BLOCK( MGA_DSTORG,  dstorg,
780                    MGA_MACCESS, 0x00000000,
781                    MGA_SRCORG,  srcorg,
782                    MGA_AR5,     64 );
783
784         DMA_BLOCK( MGA_PITCH,   64,
785                    MGA_PLNWT,   0xffffffff,
786                    MGA_DMAPAD,  0x00000000,
787                    MGA_DWGCTL,  MGA_DWGCTL_COPY );
788
789         DMA_BLOCK( MGA_AR0,     63,
790                    MGA_AR3,     0,
791                    MGA_FXBNDRY, (63 << 16) | 0,
792                    MGA_YDSTLEN + MGA_EXEC, y2 );
793
794         DMA_BLOCK( MGA_PLNWT,   ctx->plnwt,
795                    MGA_SRCORG,  dev_priv->front_offset,
796                    MGA_PITCH,   dev_priv->front_pitch,
797                    MGA_DWGSYNC, 0x00007000 );
798
799         ADVANCE_DMA();
800
801         AGE_BUFFER( buf_priv );
802
803         buf->pending = 0;
804         buf->used = 0;
805         buf_priv->dispatched = 0;
806
807         mga_freelist_put( dev, buf );
808
809         FLUSH_DMA();
810 }
811
812 static void mga_dma_dispatch_blit( drm_device_t *dev,
813                                    drm_mga_blit_t *blit )
814 {
815         drm_mga_private_t *dev_priv = dev->dev_private;
816         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
817         drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
818         drm_clip_rect_t *pbox = sarea_priv->boxes;
819         int nbox = sarea_priv->nbox;
820         u32 scandir = 0, i;
821         DMA_LOCALS;
822         DRM_DEBUG( "\n" );
823
824         BEGIN_DMA( 4 + nbox );
825
826         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
827                    MGA_DMAPAD,  0x00000000,
828                    MGA_DWGSYNC, 0x00007100,
829                    MGA_DWGSYNC, 0x00007000 );
830
831         DMA_BLOCK( MGA_DWGCTL,  MGA_DWGCTL_COPY,
832                    MGA_PLNWT,   blit->planemask,
833                    MGA_SRCORG,  blit->srcorg,
834                    MGA_DSTORG,  blit->dstorg );
835
836         DMA_BLOCK( MGA_SGN,     scandir,
837                    MGA_MACCESS, dev_priv->maccess,
838                    MGA_AR5,     blit->ydir * blit->src_pitch,
839                    MGA_PITCH,   blit->dst_pitch );
840
841         for ( i = 0 ; i < nbox ; i++ ) {
842                 int srcx = pbox[i].x1 + blit->delta_sx;
843                 int srcy = pbox[i].y1 + blit->delta_sy;
844                 int dstx = pbox[i].x1 + blit->delta_dx;
845                 int dsty = pbox[i].y1 + blit->delta_dy;
846                 int h = pbox[i].y2 - pbox[i].y1;
847                 int w = pbox[i].x2 - pbox[i].x1 - 1;
848                 int start;
849
850                 if ( blit->ydir == -1 ) {
851                         srcy = blit->height - srcy - 1;
852                 }
853
854                 start = srcy * blit->src_pitch + srcx;
855
856                 DMA_BLOCK( MGA_AR0,     start + w,
857                            MGA_AR3,     start,
858                            MGA_FXBNDRY, ((dstx + w) << 16) | (dstx & 0xffff),
859                            MGA_YDSTLEN + MGA_EXEC, (dsty << 16) | h );
860         }
861
862         /* Do something to flush AGP?
863          */
864
865         /* Force reset of DWGCTL */
866         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
867                    MGA_PLNWT,   ctx->plnwt,
868                    MGA_PITCH,   dev_priv->front_pitch,
869                    MGA_DWGCTL,  ctx->dwgctl );
870
871         ADVANCE_DMA();
872 }
873
874
875 /* ================================================================
876  *
877  */
878
879 static int mga_dma_clear( DRM_IOCTL_ARGS )
880 {
881         DRM_DEVICE;
882         drm_mga_private_t *dev_priv = dev->dev_private;
883         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
884         drm_mga_clear_t clear;
885
886         LOCK_TEST_WITH_RETURN( dev, filp );
887
888         DRM_COPY_FROM_USER_IOCTL( clear, (drm_mga_clear_t __user *)data, sizeof(clear) );
889
890         if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS )
891                 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
892
893         WRAP_TEST_WITH_RETURN( dev_priv );
894
895         mga_dma_dispatch_clear( dev, &clear );
896
897         /* Make sure we restore the 3D state next time.
898          */
899         dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
900
901         return 0;
902 }
903
904 static int mga_dma_swap( DRM_IOCTL_ARGS )
905 {
906         DRM_DEVICE;
907         drm_mga_private_t *dev_priv = dev->dev_private;
908         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
909
910         LOCK_TEST_WITH_RETURN( dev, filp );
911
912         if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS )
913                 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
914
915         WRAP_TEST_WITH_RETURN( dev_priv );
916
917         mga_dma_dispatch_swap( dev );
918
919         /* Make sure we restore the 3D state next time.
920          */
921         dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
922
923         return 0;
924 }
925
926 static int mga_dma_vertex( DRM_IOCTL_ARGS )
927 {
928         DRM_DEVICE;
929         drm_mga_private_t *dev_priv = dev->dev_private;
930         drm_device_dma_t *dma = dev->dma;
931         drm_buf_t *buf;
932         drm_mga_buf_priv_t *buf_priv;
933         drm_mga_vertex_t vertex;
934
935         LOCK_TEST_WITH_RETURN( dev, filp );
936
937         DRM_COPY_FROM_USER_IOCTL( vertex,
938                              (drm_mga_vertex_t __user *)data,
939                              sizeof(vertex) );
940
941         if(vertex.idx < 0 || vertex.idx > dma->buf_count) return DRM_ERR(EINVAL);
942         buf = dma->buflist[vertex.idx];
943         buf_priv = buf->dev_private;
944
945         buf->used = vertex.used;
946         buf_priv->discard = vertex.discard;
947
948         if ( !mga_verify_state( dev_priv ) ) {
949                 if ( vertex.discard ) {
950                         if ( buf_priv->dispatched == 1 )
951                                 AGE_BUFFER( buf_priv );
952                         buf_priv->dispatched = 0;
953                         mga_freelist_put( dev, buf );
954                 }
955                 return DRM_ERR(EINVAL);
956         }
957
958         WRAP_TEST_WITH_RETURN( dev_priv );
959
960         mga_dma_dispatch_vertex( dev, buf );
961
962         return 0;
963 }
964
965 static int mga_dma_indices( DRM_IOCTL_ARGS )
966 {
967         DRM_DEVICE;
968         drm_mga_private_t *dev_priv = dev->dev_private;
969         drm_device_dma_t *dma = dev->dma;
970         drm_buf_t *buf;
971         drm_mga_buf_priv_t *buf_priv;
972         drm_mga_indices_t indices;
973
974         LOCK_TEST_WITH_RETURN( dev, filp );
975
976         DRM_COPY_FROM_USER_IOCTL( indices,
977                              (drm_mga_indices_t __user *)data,
978                              sizeof(indices) );
979
980         if(indices.idx < 0 || indices.idx > dma->buf_count) return DRM_ERR(EINVAL);
981
982         buf = dma->buflist[indices.idx];
983         buf_priv = buf->dev_private;
984
985         buf_priv->discard = indices.discard;
986
987         if ( !mga_verify_state( dev_priv ) ) {
988                 if ( indices.discard ) {
989                         if ( buf_priv->dispatched == 1 )
990                                 AGE_BUFFER( buf_priv );
991                         buf_priv->dispatched = 0;
992                         mga_freelist_put( dev, buf );
993                 }
994                 return DRM_ERR(EINVAL);
995         }
996
997         WRAP_TEST_WITH_RETURN( dev_priv );
998
999         mga_dma_dispatch_indices( dev, buf, indices.start, indices.end );
1000
1001         return 0;
1002 }
1003
1004 static int mga_dma_iload( DRM_IOCTL_ARGS )
1005 {
1006         DRM_DEVICE;
1007         drm_device_dma_t *dma = dev->dma;
1008         drm_mga_private_t *dev_priv = dev->dev_private;
1009         drm_buf_t *buf;
1010         drm_mga_buf_priv_t *buf_priv;
1011         drm_mga_iload_t iload;
1012         DRM_DEBUG( "\n" );
1013
1014         LOCK_TEST_WITH_RETURN( dev, filp );
1015
1016         DRM_COPY_FROM_USER_IOCTL( iload, (drm_mga_iload_t __user *)data, sizeof(iload) );
1017
1018 #if 0
1019         if ( mga_do_wait_for_idle( dev_priv ) < 0 ) {
1020                 if ( MGA_DMA_DEBUG )
1021                         DRM_INFO( "%s: -EBUSY\n", __FUNCTION__ );
1022                 return DRM_ERR(EBUSY);
1023         }
1024 #endif
1025         if(iload.idx < 0 || iload.idx > dma->buf_count) return DRM_ERR(EINVAL);
1026
1027         buf = dma->buflist[iload.idx];
1028         buf_priv = buf->dev_private;
1029
1030         if ( mga_verify_iload( dev_priv, iload.dstorg, iload.length ) ) {
1031                 mga_freelist_put( dev, buf );
1032                 return DRM_ERR(EINVAL);
1033         }
1034
1035         WRAP_TEST_WITH_RETURN( dev_priv );
1036
1037         mga_dma_dispatch_iload( dev, buf, iload.dstorg, iload.length );
1038
1039         /* Make sure we restore the 3D state next time.
1040          */
1041         dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
1042
1043         return 0;
1044 }
1045
1046 static int mga_dma_blit( DRM_IOCTL_ARGS )
1047 {
1048         DRM_DEVICE;
1049         drm_mga_private_t *dev_priv = dev->dev_private;
1050         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
1051         drm_mga_blit_t blit;
1052         DRM_DEBUG( "\n" );
1053
1054         LOCK_TEST_WITH_RETURN( dev, filp );
1055
1056         DRM_COPY_FROM_USER_IOCTL( blit, (drm_mga_blit_t __user *)data, sizeof(blit) );
1057
1058         if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS )
1059                 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
1060
1061         if ( mga_verify_blit( dev_priv, blit.srcorg, blit.dstorg ) )
1062                 return DRM_ERR(EINVAL);
1063
1064         WRAP_TEST_WITH_RETURN( dev_priv );
1065
1066         mga_dma_dispatch_blit( dev, &blit );
1067
1068         /* Make sure we restore the 3D state next time.
1069          */
1070         dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
1071
1072         return 0;
1073 }
1074
1075 static int mga_getparam( DRM_IOCTL_ARGS )
1076 {
1077         DRM_DEVICE;
1078         drm_mga_private_t *dev_priv = dev->dev_private;
1079         drm_mga_getparam_t param;
1080         int value;
1081
1082         if ( !dev_priv ) {
1083                 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
1084                 return DRM_ERR(EINVAL);
1085         }
1086
1087         DRM_COPY_FROM_USER_IOCTL( param, (drm_mga_getparam_t __user *)data,
1088                              sizeof(param) );
1089
1090         DRM_DEBUG( "pid=%d\n", DRM_CURRENTPID );
1091
1092         switch( param.param ) {
1093         case MGA_PARAM_IRQ_NR:
1094                 value = dev->irq;
1095                 break;
1096         case MGA_PARAM_CARD_TYPE:
1097                 value = dev_priv->chipset;
1098                 break;
1099         default:
1100                 return DRM_ERR(EINVAL);
1101         }
1102
1103         if ( DRM_COPY_TO_USER( param.value, &value, sizeof(int) ) ) {
1104                 DRM_ERROR( "copy_to_user\n" );
1105                 return DRM_ERR(EFAULT);
1106         }
1107         
1108         return 0;
1109 }
1110
1111 static int mga_set_fence(DRM_IOCTL_ARGS)
1112 {
1113         DRM_DEVICE;
1114         drm_mga_private_t *dev_priv = dev->dev_private;
1115         u32 temp;
1116         DMA_LOCALS;
1117
1118         if (!dev_priv) {
1119                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
1120                 return DRM_ERR(EINVAL);
1121         }
1122
1123         DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
1124
1125         /* I would normal do this assignment in the declaration of temp,
1126          * but dev_priv may be NULL.
1127          */
1128
1129         temp = dev_priv->next_fence_to_post;
1130         dev_priv->next_fence_to_post++;
1131
1132         BEGIN_DMA(1);
1133         DMA_BLOCK(MGA_DMAPAD, 0x00000000,
1134                   MGA_DMAPAD, 0x00000000,
1135                   MGA_DMAPAD, 0x00000000,
1136                   MGA_SOFTRAP, 0x00000000);
1137         ADVANCE_DMA();
1138
1139         if (DRM_COPY_TO_USER( (u32 __user *) data, & temp, sizeof(u32))) {
1140                 DRM_ERROR("copy_to_user\n");
1141                 return DRM_ERR(EFAULT);
1142         }
1143
1144         return 0;
1145 }
1146
1147 static int mga_wait_fence(DRM_IOCTL_ARGS)
1148 {
1149         DRM_DEVICE;
1150         drm_mga_private_t *dev_priv = dev->dev_private;
1151         u32 fence;
1152
1153         if (!dev_priv) {
1154                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
1155                 return DRM_ERR(EINVAL);
1156         }
1157
1158         DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32));
1159
1160         DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
1161
1162         mga_driver_fence_wait(dev, & fence);
1163
1164         if (DRM_COPY_TO_USER( (u32 __user *) data, & fence, sizeof(u32))) {
1165                 DRM_ERROR("copy_to_user\n");
1166                 return DRM_ERR(EFAULT);
1167         }
1168
1169         return 0;
1170 }
1171
1172 drm_ioctl_desc_t mga_ioctls[] = {
1173         [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, 1, 1},
1174         [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, 1, 0},
1175         [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, 1, 0},
1176         [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, 1, 0},
1177         [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, 1, 0},
1178         [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, 1, 0},
1179         [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, 1, 0},
1180         [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, 1, 0},
1181         [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, 1, 0},
1182         [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, 1, 0},
1183         [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, 1, 0},
1184         [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, 1, 0},
1185         [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, 1, 1},
1186
1187 };
1188
1189 int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);