bf263e6398d38c55f3ded4b42075b403fee162e1
[dragonfly.git] / sys / dev / drm / mga / mga_dma.c
1 /* mga_dma.c -- DMA support for mga g200/g400 -*- linux-c -*-
2  * Created: Mon Dec 13 01:50:01 1999 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  * 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  *    Jeff Hartmann <jhartmann@valinux.com>
30  *    Keith Whitwell <keith@tungstengraphics.com>
31  *
32  * Rewritten by:
33  *    Gareth Hughes <gareth@valinux.com>
34  *
35  * $FreeBSD: src/sys/dev/drm/mga_dma.c,v 1.6.2.1 2003/04/26 07:05:29 anholt Exp $
36  * $DragonFly: src/sys/dev/drm/mga/Attic/mga_dma.c,v 1.3 2003/08/07 21:16:55 dillon Exp $
37  */
38
39 #include "mga.h"
40 #include "dev/drm/drmP.h"
41 #include "dev/drm/drm.h"
42 #include "mga_drm.h"
43 #include "mga_drv.h"
44
45 #define MGA_DEFAULT_USEC_TIMEOUT        10000
46 #define MGA_FREELIST_DEBUG              0
47
48
49 /* ================================================================
50  * Engine control
51  */
52
53 int mga_do_wait_for_idle( drm_mga_private_t *dev_priv )
54 {
55         u32 status = 0;
56         int i;
57         DRM_DEBUG( "\n" );
58
59         for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
60                 status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK;
61                 if ( status == MGA_ENDPRDMASTS ) {
62                         MGA_WRITE8( MGA_CRTC_INDEX, 0 );
63                         return 0;
64                 }
65                 DRM_UDELAY( 1 );
66         }
67
68 #if MGA_DMA_DEBUG
69         DRM_ERROR( "failed!\n" );
70         DRM_INFO( "   status=0x%08x\n", status );
71 #endif
72         return DRM_ERR(EBUSY);
73 }
74
75 int mga_do_dma_idle( drm_mga_private_t *dev_priv )
76 {
77         u32 status = 0;
78         int i;
79         DRM_DEBUG( "\n" );
80
81         for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
82                 status = MGA_READ( MGA_STATUS ) & MGA_DMA_IDLE_MASK;
83                 if ( status == MGA_ENDPRDMASTS ) return 0;
84                 DRM_UDELAY( 1 );
85         }
86
87 #if MGA_DMA_DEBUG
88         DRM_ERROR( "failed! status=0x%08x\n", status );
89 #endif
90         return DRM_ERR(EBUSY);
91 }
92
93 int mga_do_dma_reset( drm_mga_private_t *dev_priv )
94 {
95         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
96         drm_mga_primary_buffer_t *primary = &dev_priv->prim;
97
98         DRM_DEBUG( "\n" );
99
100         /* The primary DMA stream should look like new right about now.
101          */
102         primary->tail = 0;
103         primary->space = primary->size;
104         primary->last_flush = 0;
105
106         sarea_priv->last_wrap = 0;
107
108         /* FIXME: Reset counters, buffer ages etc...
109          */
110
111         /* FIXME: What else do we need to reinitialize?  WARP stuff?
112          */
113
114         return 0;
115 }
116
117 int mga_do_engine_reset( drm_mga_private_t *dev_priv )
118 {
119         DRM_DEBUG( "\n" );
120
121         /* Okay, so we've completely screwed up and locked the engine.
122          * How about we clean up after ourselves?
123          */
124         MGA_WRITE( MGA_RST, MGA_SOFTRESET );
125         DRM_UDELAY( 15 );                               /* Wait at least 10 usecs */
126         MGA_WRITE( MGA_RST, 0 );
127
128         /* Initialize the registers that get clobbered by the soft
129          * reset.  Many of the core register values survive a reset,
130          * but the drawing registers are basically all gone.
131          *
132          * 3D clients should probably die after calling this.  The X
133          * server should reset the engine state to known values.
134          */
135 #if 0
136         MGA_WRITE( MGA_PRIMPTR,
137                    virt_to_bus((void *)dev_priv->prim.status_page) |
138                    MGA_PRIMPTREN0 |
139                    MGA_PRIMPTREN1 );
140 #endif
141
142         MGA_WRITE( MGA_ICLEAR, MGA_SOFTRAPICLR );
143         MGA_WRITE( MGA_IEN,    MGA_SOFTRAPIEN );
144
145         /* The primary DMA stream should look like new right about now.
146          */
147         mga_do_dma_reset( dev_priv );
148
149         /* This bad boy will never fail.
150          */
151         return 0;
152 }
153
154
155 /* ================================================================
156  * Primary DMA stream
157  */
158
159 void mga_do_dma_flush( drm_mga_private_t *dev_priv )
160 {
161         drm_mga_primary_buffer_t *primary = &dev_priv->prim;
162         u32 head, tail;
163         u32 status = 0;
164         int i;
165         DMA_LOCALS;
166         DRM_DEBUG( "\n" );
167
168         /* We need to wait so that we can do an safe flush */
169         for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
170                 status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK;
171                 if ( status == MGA_ENDPRDMASTS ) break;
172                 DRM_UDELAY( 1 );
173         }
174
175         if ( primary->tail == primary->last_flush ) {
176                 DRM_DEBUG( "   bailing out...\n" );
177                 return;
178         }
179
180         tail = primary->tail + dev_priv->primary->offset;
181
182         /* We need to pad the stream between flushes, as the card
183          * actually (partially?) reads the first of these commands.
184          * See page 4-16 in the G400 manual, middle of the page or so.
185          */
186         BEGIN_DMA( 1 );
187
188         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
189                    MGA_DMAPAD,  0x00000000,
190                    MGA_DMAPAD,  0x00000000,
191                    MGA_DMAPAD,  0x00000000 );
192
193         ADVANCE_DMA();
194
195         primary->last_flush = primary->tail;
196
197         head = MGA_READ( MGA_PRIMADDRESS );
198
199         if ( head <= tail ) {
200                 primary->space = primary->size - primary->tail;
201         } else {
202                 primary->space = head - tail;
203         }
204
205         DRM_DEBUG( "   head = 0x%06lx\n", head - dev_priv->primary->offset );
206         DRM_DEBUG( "   tail = 0x%06lx\n", tail - dev_priv->primary->offset );
207         DRM_DEBUG( "  space = 0x%06x\n", primary->space );
208
209         mga_flush_write_combine();
210         MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER );
211
212         DRM_DEBUG( "done.\n" );
213 }
214
215 void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv )
216 {
217         drm_mga_primary_buffer_t *primary = &dev_priv->prim;
218         u32 head, tail;
219         DMA_LOCALS;
220         DRM_DEBUG( "\n" );
221
222         BEGIN_DMA_WRAP();
223
224         DMA_BLOCK( MGA_DMAPAD,  0x00000000,
225                    MGA_DMAPAD,  0x00000000,
226                    MGA_DMAPAD,  0x00000000,
227                    MGA_DMAPAD,  0x00000000 );
228
229         ADVANCE_DMA();
230
231         tail = primary->tail + dev_priv->primary->offset;
232
233         primary->tail = 0;
234         primary->last_flush = 0;
235         primary->last_wrap++;
236
237         head = MGA_READ( MGA_PRIMADDRESS );
238
239         if ( head == dev_priv->primary->offset ) {
240                 primary->space = primary->size;
241         } else {
242                 primary->space = head - dev_priv->primary->offset;
243         }
244
245         DRM_DEBUG( "   head = 0x%06lx\n",
246                   head - dev_priv->primary->offset );
247         DRM_DEBUG( "   tail = 0x%06x\n", primary->tail );
248         DRM_DEBUG( "   wrap = %d\n", primary->last_wrap );
249         DRM_DEBUG( "  space = 0x%06x\n", primary->space );
250
251         mga_flush_write_combine();
252         MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER );
253
254         set_bit( 0, &primary->wrapped );
255         DRM_DEBUG( "done.\n" );
256 }
257
258 void mga_do_dma_wrap_end( drm_mga_private_t *dev_priv )
259 {
260         drm_mga_primary_buffer_t *primary = &dev_priv->prim;
261         drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
262         u32 head = dev_priv->primary->offset;
263         DRM_DEBUG( "\n" );
264
265         sarea_priv->last_wrap++;
266         DRM_DEBUG( "   wrap = %d\n", sarea_priv->last_wrap );
267
268         mga_flush_write_combine();
269         MGA_WRITE( MGA_PRIMADDRESS, head | MGA_DMA_GENERAL );
270
271         clear_bit( 0, &primary->wrapped );
272         DRM_DEBUG( "done.\n" );
273 }
274
275
276 /* ================================================================
277  * Freelist management
278  */
279
280 #define MGA_BUFFER_USED         ~0
281 #define MGA_BUFFER_FREE         0
282
283 #if MGA_FREELIST_DEBUG
284 static void mga_freelist_print( drm_device_t *dev )
285 {
286         drm_mga_private_t *dev_priv = dev->dev_private;
287         drm_mga_freelist_t *entry;
288
289         DRM_INFO( "\n" );
290         DRM_INFO( "current dispatch: last=0x%x done=0x%x\n",
291                   dev_priv->sarea_priv->last_dispatch,
292                   (unsigned int)(MGA_READ( MGA_PRIMADDRESS ) -
293                                  dev_priv->primary->offset) );
294         DRM_INFO( "current freelist:\n" );
295
296         for ( entry = dev_priv->head->next ; entry ; entry = entry->next ) {
297                 DRM_INFO( "   %p   idx=%2d  age=0x%x 0x%06lx\n",
298                           entry, entry->buf->idx, entry->age.head,
299                           entry->age.head - dev_priv->primary->offset );
300         }
301         DRM_INFO( "\n" );
302 }
303 #endif
304
305 static int mga_freelist_init( drm_device_t *dev, drm_mga_private_t *dev_priv )
306 {
307         drm_device_dma_t *dma = dev->dma;
308         drm_buf_t *buf;
309         drm_mga_buf_priv_t *buf_priv;
310         drm_mga_freelist_t *entry;
311         int i;
312         DRM_DEBUG( "count=%d\n", dma->buf_count );
313
314         dev_priv->head = DRM(alloc)( sizeof(drm_mga_freelist_t),
315                                      DRM_MEM_DRIVER );
316         if ( dev_priv->head == NULL )
317                 return DRM_ERR(ENOMEM);
318
319         memset( dev_priv->head, 0, sizeof(drm_mga_freelist_t) );
320         SET_AGE( &dev_priv->head->age, MGA_BUFFER_USED, 0 );
321
322         for ( i = 0 ; i < dma->buf_count ; i++ ) {
323                 buf = dma->buflist[i];
324                 buf_priv = buf->dev_private;
325
326                 entry = DRM(alloc)( sizeof(drm_mga_freelist_t),
327                                     DRM_MEM_DRIVER );
328                 if ( entry == NULL )
329                         return DRM_ERR(ENOMEM);
330
331                 memset( entry, 0, sizeof(drm_mga_freelist_t) );
332
333                 entry->next = dev_priv->head->next;
334                 entry->prev = dev_priv->head;
335                 SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 );
336                 entry->buf = buf;
337
338                 if ( dev_priv->head->next != NULL )
339                         dev_priv->head->next->prev = entry;
340                 if ( entry->next == NULL )
341                         dev_priv->tail = entry;
342
343                 buf_priv->list_entry = entry;
344                 buf_priv->discard = 0;
345                 buf_priv->dispatched = 0;
346
347                 dev_priv->head->next = entry;
348         }
349
350         return 0;
351 }
352
353 static void mga_freelist_cleanup( drm_device_t *dev )
354 {
355         drm_mga_private_t *dev_priv = dev->dev_private;
356         drm_mga_freelist_t *entry;
357         drm_mga_freelist_t *next;
358         DRM_DEBUG( "\n" );
359
360         entry = dev_priv->head;
361         while ( entry ) {
362                 next = entry->next;
363                 DRM(free)( entry, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER );
364                 entry = next;
365         }
366
367         dev_priv->head = dev_priv->tail = NULL;
368 }
369
370 #if 0
371 /* FIXME: Still needed?
372  */
373 static void mga_freelist_reset( drm_device_t *dev )
374 {
375         drm_device_dma_t *dma = dev->dma;
376         drm_buf_t *buf;
377         drm_mga_buf_priv_t *buf_priv;
378         int i;
379
380         for ( i = 0 ; i < dma->buf_count ; i++ ) {
381                 buf = dma->buflist[i];
382                 buf_priv = buf->dev_private;
383                 SET_AGE( &buf_priv->list_entry->age,
384                          MGA_BUFFER_FREE, 0 );
385         }
386 }
387 #endif
388
389 static drm_buf_t *mga_freelist_get( drm_device_t *dev )
390 {
391         drm_mga_private_t *dev_priv = dev->dev_private;
392         drm_mga_freelist_t *next;
393         drm_mga_freelist_t *prev;
394         drm_mga_freelist_t *tail = dev_priv->tail;
395         u32 head, wrap;
396         DRM_DEBUG( "\n" );
397
398         head = MGA_READ( MGA_PRIMADDRESS );
399         wrap = dev_priv->sarea_priv->last_wrap;
400
401         DRM_DEBUG( "   tail=0x%06lx %d\n",
402                    tail->age.head ?
403                    tail->age.head - dev_priv->primary->offset : 0,
404                    tail->age.wrap );
405         DRM_DEBUG( "   head=0x%06lx %d\n",
406                    head - dev_priv->primary->offset, wrap );
407
408         if ( TEST_AGE( &tail->age, head, wrap ) ) {
409                 prev = dev_priv->tail->prev;
410                 next = dev_priv->tail;
411                 prev->next = NULL;
412                 next->prev = next->next = NULL;
413                 dev_priv->tail = prev;
414                 SET_AGE( &next->age, MGA_BUFFER_USED, 0 );
415                 return next->buf;
416         }
417
418         DRM_DEBUG( "returning NULL!\n" );
419         return NULL;
420 }
421
422 int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf )
423 {
424         drm_mga_private_t *dev_priv = dev->dev_private;
425         drm_mga_buf_priv_t *buf_priv = buf->dev_private;
426         drm_mga_freelist_t *head, *entry, *prev;
427
428         DRM_DEBUG( "age=0x%06lx wrap=%d\n",
429                    buf_priv->list_entry->age.head -
430                    dev_priv->primary->offset,
431                    buf_priv->list_entry->age.wrap );
432
433         entry = buf_priv->list_entry;
434         head = dev_priv->head;
435
436         if ( buf_priv->list_entry->age.head == MGA_BUFFER_USED ) {
437                 SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 );
438                 prev = dev_priv->tail;
439                 prev->next = entry;
440                 entry->prev = prev;
441                 entry->next = NULL;
442         } else {
443                 prev = head->next;
444                 head->next = entry;
445                 prev->prev = entry;
446                 entry->prev = head;
447                 entry->next = prev;
448         }
449
450         return 0;
451 }
452
453
454 /* ================================================================
455  * DMA initialization, cleanup
456  */
457
458 static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init )
459 {
460         drm_mga_private_t *dev_priv;
461         int ret;
462         DRM_DEBUG( "\n" );
463
464         dev_priv = DRM(alloc)( sizeof(drm_mga_private_t), DRM_MEM_DRIVER );
465         if ( !dev_priv )
466                 return DRM_ERR(ENOMEM);
467
468         memset( dev_priv, 0, sizeof(drm_mga_private_t) );
469
470         dev_priv->chipset = init->chipset;
471
472         dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
473
474         if ( init->sgram ) {
475                 dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK;
476         } else {
477                 dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR;
478         }
479         dev_priv->maccess       = init->maccess;
480
481         dev_priv->fb_cpp        = init->fb_cpp;
482         dev_priv->front_offset  = init->front_offset;
483         dev_priv->front_pitch   = init->front_pitch;
484         dev_priv->back_offset   = init->back_offset;
485         dev_priv->back_pitch    = init->back_pitch;
486
487         dev_priv->depth_cpp     = init->depth_cpp;
488         dev_priv->depth_offset  = init->depth_offset;
489         dev_priv->depth_pitch   = init->depth_pitch;
490
491         /* FIXME: Need to support AGP textures...
492          */
493         dev_priv->texture_offset = init->texture_offset[0];
494         dev_priv->texture_size = init->texture_size[0];
495
496         DRM_GETSAREA();
497
498         if(!dev_priv->sarea) {
499                 DRM_ERROR( "failed to find sarea!\n" );
500                 /* Assign dev_private so we can do cleanup. */
501                 dev->dev_private = (void *)dev_priv;
502                 mga_do_cleanup_dma( dev );
503                 return DRM_ERR(EINVAL);
504         }
505
506         DRM_FIND_MAP( dev_priv->fb, init->fb_offset );
507         if(!dev_priv->fb) {
508                 DRM_ERROR( "failed to find framebuffer!\n" );
509                 /* Assign dev_private so we can do cleanup. */
510                 dev->dev_private = (void *)dev_priv;
511                 mga_do_cleanup_dma( dev );
512                 return DRM_ERR(EINVAL);
513         }
514         DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset );
515         if(!dev_priv->mmio) {
516                 DRM_ERROR( "failed to find mmio region!\n" );
517                 /* Assign dev_private so we can do cleanup. */
518                 dev->dev_private = (void *)dev_priv;
519                 mga_do_cleanup_dma( dev );
520                 return DRM_ERR(EINVAL);
521         }
522         DRM_FIND_MAP( dev_priv->status, init->status_offset );
523         if(!dev_priv->status) {
524                 DRM_ERROR( "failed to find status page!\n" );
525                 /* Assign dev_private so we can do cleanup. */
526                 dev->dev_private = (void *)dev_priv;
527                 mga_do_cleanup_dma( dev );
528                 return DRM_ERR(EINVAL);
529         }
530
531         DRM_FIND_MAP( dev_priv->warp, init->warp_offset );
532         if(!dev_priv->warp) {
533                 DRM_ERROR( "failed to find warp microcode region!\n" );
534                 /* Assign dev_private so we can do cleanup. */
535                 dev->dev_private = (void *)dev_priv;
536                 mga_do_cleanup_dma( dev );
537                 return DRM_ERR(EINVAL);
538         }
539         DRM_FIND_MAP( dev_priv->primary, init->primary_offset );
540         if(!dev_priv->primary) {
541                 DRM_ERROR( "failed to find primary dma region!\n" );
542                 /* Assign dev_private so we can do cleanup. */
543                 dev->dev_private = (void *)dev_priv;
544                 mga_do_cleanup_dma( dev );
545                 return DRM_ERR(EINVAL);
546         }
547         DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset );
548         if(!dev_priv->buffers) {
549                 DRM_ERROR( "failed to find dma buffer region!\n" );
550                 /* Assign dev_private so we can do cleanup. */
551                 dev->dev_private = (void *)dev_priv;
552                 mga_do_cleanup_dma( dev );
553                 return DRM_ERR(EINVAL);
554         }
555
556         dev_priv->sarea_priv =
557                 (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle +
558                                     init->sarea_priv_offset);
559
560         DRM_IOREMAP( dev_priv->warp );
561         DRM_IOREMAP( dev_priv->primary );
562         DRM_IOREMAP( dev_priv->buffers );
563
564         if(!dev_priv->warp->handle ||
565            !dev_priv->primary->handle ||
566            !dev_priv->buffers->handle ) {
567                 DRM_ERROR( "failed to ioremap agp regions!\n" );
568                 /* Assign dev_private so we can do cleanup. */
569                 dev->dev_private = (void *)dev_priv;
570                 mga_do_cleanup_dma( dev );
571                 return DRM_ERR(ENOMEM);
572         }
573
574         ret = mga_warp_install_microcode( dev_priv );
575         if ( ret < 0 ) {
576                 DRM_ERROR( "failed to install WARP ucode!\n" );
577                 /* Assign dev_private so we can do cleanup. */
578                 dev->dev_private = (void *)dev_priv;
579                 mga_do_cleanup_dma( dev );
580                 return ret;
581         }
582
583         ret = mga_warp_init( dev_priv );
584         if ( ret < 0 ) {
585                 DRM_ERROR( "failed to init WARP engine!\n" );
586                 /* Assign dev_private so we can do cleanup. */
587                 dev->dev_private = (void *)dev_priv;
588                 mga_do_cleanup_dma( dev );
589                 return ret;
590         }
591
592         dev_priv->prim.status = (u32 *)dev_priv->status->handle;
593
594         mga_do_wait_for_idle( dev_priv );
595
596         /* Init the primary DMA registers.
597          */
598         MGA_WRITE( MGA_PRIMADDRESS,
599                    dev_priv->primary->offset | MGA_DMA_GENERAL );
600 #if 0
601         MGA_WRITE( MGA_PRIMPTR,
602                    virt_to_bus((void *)dev_priv->prim.status) |
603                    MGA_PRIMPTREN0 |     /* Soft trap, SECEND, SETUPEND */
604                    MGA_PRIMPTREN1 );    /* DWGSYNC */
605 #endif
606
607         dev_priv->prim.start = (u8 *)dev_priv->primary->handle;
608         dev_priv->prim.end = ((u8 *)dev_priv->primary->handle
609                               + dev_priv->primary->size);
610         dev_priv->prim.size = dev_priv->primary->size;
611
612         dev_priv->prim.tail = 0;
613         dev_priv->prim.space = dev_priv->prim.size;
614         dev_priv->prim.wrapped = 0;
615
616         dev_priv->prim.last_flush = 0;
617         dev_priv->prim.last_wrap = 0;
618
619         dev_priv->prim.high_mark = 256 * DMA_BLOCK_SIZE;
620
621         dev_priv->prim.status[0] = dev_priv->primary->offset;
622         dev_priv->prim.status[1] = 0;
623
624         dev_priv->sarea_priv->last_wrap = 0;
625         dev_priv->sarea_priv->last_frame.head = 0;
626         dev_priv->sarea_priv->last_frame.wrap = 0;
627
628         if ( mga_freelist_init( dev, dev_priv ) < 0 ) {
629                 DRM_ERROR( "could not initialize freelist\n" );
630                 /* Assign dev_private so we can do cleanup. */
631                 dev->dev_private = (void *)dev_priv;
632                 mga_do_cleanup_dma( dev );
633                 return DRM_ERR(ENOMEM);
634         }
635
636         /* Make dev_private visable to others. */
637         dev->dev_private = (void *)dev_priv;
638         return 0;
639 }
640
641 int mga_do_cleanup_dma( drm_device_t *dev )
642 {
643         DRM_DEBUG( "\n" );
644
645         if ( dev->dev_private ) {
646                 drm_mga_private_t *dev_priv = dev->dev_private;
647
648                 if ( dev_priv->warp != NULL )
649                         DRM_IOREMAPFREE( dev_priv->warp );
650                 if ( dev_priv->primary != NULL )
651                         DRM_IOREMAPFREE( dev_priv->primary );
652                 if ( dev_priv->buffers != NULL )
653                         DRM_IOREMAPFREE( dev_priv->buffers );
654
655                 if ( dev_priv->head != NULL ) {
656                         mga_freelist_cleanup( dev );
657                 }
658
659                 DRM(free)( dev->dev_private, sizeof(drm_mga_private_t),
660                            DRM_MEM_DRIVER );
661                 dev->dev_private = NULL;
662         }
663
664         return 0;
665 }
666
667 int mga_dma_init( DRM_IOCTL_ARGS )
668 {
669         DRM_DEVICE;
670         drm_mga_init_t init;
671
672         DRM_COPY_FROM_USER_IOCTL( init, (drm_mga_init_t *)data, sizeof(init) );
673
674         switch ( init.func ) {
675         case MGA_INIT_DMA:
676                 return mga_do_init_dma( dev, &init );
677         case MGA_CLEANUP_DMA:
678                 return mga_do_cleanup_dma( dev );
679         }
680
681         return DRM_ERR(EINVAL);
682 }
683
684
685 /* ================================================================
686  * Primary DMA stream management
687  */
688
689 int mga_dma_flush( DRM_IOCTL_ARGS )
690 {
691         DRM_DEVICE;
692         drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
693         drm_lock_t lock;
694
695         LOCK_TEST_WITH_RETURN( dev, filp );
696
697         DRM_COPY_FROM_USER_IOCTL( lock, (drm_lock_t *)data, sizeof(lock) );
698
699         DRM_DEBUG( "%s%s%s\n",
700                    (lock.flags & _DRM_LOCK_FLUSH) ?     "flush, " : "",
701                    (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "",
702                    (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "" );
703
704         WRAP_WAIT_WITH_RETURN( dev_priv );
705
706         if ( lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL) ) {
707                 mga_do_dma_flush( dev_priv );
708         }
709
710         if ( lock.flags & _DRM_LOCK_QUIESCENT ) {
711 #if MGA_DMA_DEBUG
712                 int ret = mga_do_wait_for_idle( dev_priv );
713                 if ( ret < 0 )
714                         DRM_INFO( "%s: -EBUSY\n", __FUNCTION__ );
715                 return ret;
716 #else
717                 return mga_do_wait_for_idle( dev_priv );
718 #endif
719         } else {
720                 return 0;
721         }
722 }
723
724 int mga_dma_reset( DRM_IOCTL_ARGS )
725 {
726         DRM_DEVICE;
727         drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
728
729         LOCK_TEST_WITH_RETURN( dev, filp );
730
731         return mga_do_dma_reset( dev_priv );
732 }
733
734
735 /* ================================================================
736  * DMA buffer management
737  */
738
739 static int mga_dma_get_buffers( DRMFILE filp,
740                                 drm_device_t *dev, drm_dma_t *d )
741 {
742         drm_buf_t *buf;
743         int i;
744
745         for ( i = d->granted_count ; i < d->request_count ; i++ ) {
746                 buf = mga_freelist_get( dev );
747                 if ( !buf ) return DRM_ERR(EAGAIN);
748
749                 buf->filp = filp;
750
751                 if ( DRM_COPY_TO_USER( &d->request_indices[i],
752                                    &buf->idx, sizeof(buf->idx) ) )
753                         return DRM_ERR(EFAULT);
754                 if ( DRM_COPY_TO_USER( &d->request_sizes[i],
755                                    &buf->total, sizeof(buf->total) ) )
756                         return DRM_ERR(EFAULT);
757
758                 d->granted_count++;
759         }
760         return 0;
761 }
762
763 int mga_dma_buffers( DRM_IOCTL_ARGS )
764 {
765         DRM_DEVICE;
766         drm_device_dma_t *dma = dev->dma;
767         drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
768         drm_dma_t d;
769         int ret = 0;
770
771         LOCK_TEST_WITH_RETURN( dev, filp );
772
773         DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *)data, sizeof(d) );
774
775         /* Please don't send us buffers.
776          */
777         if ( d.send_count != 0 ) {
778                 DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n",
779                            DRM_CURRENTPID, d.send_count );
780                 return DRM_ERR(EINVAL);
781         }
782
783         /* We'll send you buffers.
784          */
785         if ( d.request_count < 0 || d.request_count > dma->buf_count ) {
786                 DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n",
787                            DRM_CURRENTPID, d.request_count, dma->buf_count );
788                 return DRM_ERR(EINVAL);
789         }
790
791         WRAP_TEST_WITH_RETURN( dev_priv );
792
793         d.granted_count = 0;
794
795         if ( d.request_count ) {
796                 ret = mga_dma_get_buffers( filp, dev, &d );
797         }
798
799         DRM_COPY_TO_USER_IOCTL( (drm_dma_t *)data, d, sizeof(d) );
800
801         return ret;
802 }