Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / mga / mgaioctl.c
1 /*
2  * Copyright 2000-2001 VA Linux Systems, Inc.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * on the rights to use, copy, modify, merge, publish, distribute, sub
9  * license, and/or sell copies of the Software, and to permit persons to whom
10  * the Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 /**
26  * \file mgaioctl.c
27  * MGA IOCTL related wrapper functions.
28  *
29  * \author Keith Whitwell <keith@tungstengraphics.com>
30  * \author Gareth Hughes <gareth@valinux.com>
31  */
32
33 #include <errno.h>
34 #include "main/mtypes.h"
35 #include "main/macros.h"
36 #include "main/dd.h"
37 #include "swrast/swrast.h"
38
39 #include "main/mm.h"
40 #include "drm.h"
41 #include "mga_drm.h"
42 #include "mgacontext.h"
43 #include "mgadd.h"
44 #include "mgastate.h"
45 #include "mgaioctl.h"
46
47 #include "vblank.h"
48
49
50 static int
51 mgaSetFence( mgaContextPtr mmesa, uint32_t * fence )
52 {
53     int ret = ENOSYS;
54
55     if ( mmesa->driScreen->drm_version.minor >= 2 ) {
56         ret = drmCommandWriteRead( mmesa->driScreen->fd, DRM_MGA_SET_FENCE,
57                                    fence, sizeof( uint32_t ));
58         if (ret) {
59             fprintf(stderr, "drmMgaSetFence: %d\n", ret);
60             exit(1);
61         }
62     }
63
64     return ret;
65 }
66
67
68 static int
69 mgaWaitFence( mgaContextPtr mmesa, uint32_t fence, uint32_t * curr_fence )
70 {
71     int ret = ENOSYS;
72
73     if ( mmesa->driScreen->drm_version.minor >= 2 ) {
74         uint32_t temp = fence;
75         
76         ret = drmCommandWriteRead( mmesa->driScreen->fd,
77                                    DRM_MGA_WAIT_FENCE,
78                                    & temp, sizeof( uint32_t ));
79         if (ret) {
80            fprintf(stderr, "drmMgaSetFence: %d\n", ret);
81             exit(1);
82         }
83
84         if ( curr_fence ) {
85             *curr_fence = temp;
86         }
87     }
88
89     return ret;
90 }
91
92
93 static void mga_iload_dma_ioctl(mgaContextPtr mmesa,
94                                 unsigned long dest,
95                                 int length)
96 {
97    drmBufPtr buf = mmesa->iload_buffer;
98    drm_mga_iload_t iload;
99    int ret, i;
100
101    if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
102       fprintf(stderr, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n",
103               buf->idx, (int) dest, length);
104
105    if ( (length & MGA_ILOAD_MASK) != 0 ) {
106       UNLOCK_HARDWARE( mmesa );
107       fprintf( stderr, "%s: Invalid ILOAD datasize (%d), must be "
108                "multiple of %u.\n", __FUNCTION__, length, MGA_ILOAD_ALIGN );
109       exit( 1 );
110    }
111
112    iload.idx = buf->idx;
113    iload.dstorg = dest;
114    iload.length = length;
115
116    i = 0;
117    do {
118       ret = drmCommandWrite( mmesa->driFd, DRM_MGA_ILOAD, 
119                              &iload, sizeof(iload) );
120    } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY );
121
122    if ( ret < 0 ) {
123       printf("send iload retcode = %d\n", ret);
124       exit(1);
125    }
126
127    mmesa->iload_buffer = 0;
128
129    if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
130       fprintf(stderr, "finished iload dma put\n");
131
132 }
133
134 drmBufPtr mga_get_buffer_ioctl( mgaContextPtr mmesa )
135 {
136    int idx = 0;
137    int size = 0;
138    drmDMAReq dma;
139    int retcode;
140    drmBufPtr buf;
141
142    if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
143       fprintf(stderr,  "Getting dma buffer\n");
144
145    dma.context = mmesa->hHWContext;
146    dma.send_count = 0;
147    dma.send_list = NULL;
148    dma.send_sizes = NULL;
149    dma.flags = 0;
150    dma.request_count = 1;
151    dma.request_size = MGA_BUFFER_SIZE;
152    dma.request_list = &idx;
153    dma.request_sizes = &size;
154    dma.granted_count = 0;
155
156
157    if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
158       fprintf(stderr, "drmDMA (get) ctx %d count %d size 0x%x\n",
159            dma.context, dma.request_count,
160            dma.request_size);
161
162    while (1) {
163       retcode = drmDMA(mmesa->driFd, &dma);
164
165       if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
166          fprintf(stderr, "retcode %d sz %d idx %d count %d\n",
167                  retcode,
168                  dma.request_sizes[0],
169                  dma.request_list[0],
170                  dma.granted_count);
171
172       if (retcode == 0 &&
173           dma.request_sizes[0] &&
174           dma.granted_count)
175          break;
176
177       if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
178          fprintf(stderr, "\n\nflush");
179
180       UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT );
181    }
182
183    buf = &(mmesa->mgaScreen->bufs->list[idx]);
184    buf->used = 0;
185
186    if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
187       fprintf(stderr,
188            "drmDMA (get) returns size[0] 0x%x idx[0] %d\n"
189            "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n",
190            dma.request_sizes[0], dma.request_list[0],
191            buf->idx, buf->total,
192            buf->used, buf->address);
193
194    if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
195       fprintf(stderr, "finished getbuffer\n");
196
197    return buf;
198 }
199
200
201
202
203 static void
204 mgaClear( struct gl_context *ctx, GLbitfield mask )
205 {
206    mgaContextPtr mmesa = MGA_CONTEXT(ctx);
207    __DRIdrawable *dPriv = mmesa->driDrawable;
208    GLuint flags = 0;
209    GLuint clear_color = mmesa->ClearColor;
210    GLuint clear_depth = 0;
211    GLuint color_mask = 0;
212    GLuint depth_mask = 0;
213    int ret;
214    int i;
215    static int nrclears;
216    drm_mga_clear_t clear;
217    GLint cx, cy, cw, ch;
218
219    FLUSH_BATCH( mmesa );
220
221    if ( mask & BUFFER_BIT_FRONT_LEFT ) {
222       flags |= MGA_FRONT;
223       color_mask = mmesa->setup.plnwt;
224       mask &= ~BUFFER_BIT_FRONT_LEFT;
225    }
226
227    if ( mask & BUFFER_BIT_BACK_LEFT ) {
228       flags |= MGA_BACK;
229       color_mask = mmesa->setup.plnwt;
230       mask &= ~BUFFER_BIT_BACK_LEFT;
231    }
232
233    if ( (mask & BUFFER_BIT_DEPTH) && ctx->Depth.Mask ) {
234       flags |= MGA_DEPTH;
235       clear_depth = (mmesa->ClearDepth & mmesa->depth_clear_mask);
236       depth_mask |= mmesa->depth_clear_mask;
237       mask &= ~BUFFER_BIT_DEPTH;
238    }
239
240    if ( (mask & BUFFER_BIT_STENCIL) && mmesa->hw_stencil ) {
241       flags |= MGA_DEPTH;
242       clear_depth |= (ctx->Stencil.Clear & mmesa->stencil_clear_mask);
243       depth_mask |= mmesa->stencil_clear_mask;
244       mask &= ~BUFFER_BIT_STENCIL;
245    }
246
247    if ( flags ) {
248       LOCK_HARDWARE( mmesa );
249
250       /* compute region after locking: */
251       cx = ctx->DrawBuffer->_Xmin;
252       cy = ctx->DrawBuffer->_Ymin;
253       cw = ctx->DrawBuffer->_Xmax - cx;
254       ch = ctx->DrawBuffer->_Ymax - cy;
255
256       if ( mmesa->dirty_cliprects )
257          mgaUpdateRects( mmesa, (MGA_FRONT | MGA_BACK) );
258
259       /* flip top to bottom */
260       cy = dPriv->h-cy-ch;
261       cx += mmesa->drawX;
262       cy += mmesa->drawY;
263
264       if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
265          fprintf( stderr, "Clear, bufs %x nbox %d\n",
266                   (int)flags, (int)mmesa->numClipRects );
267
268       for (i = 0 ; i < mmesa->numClipRects ; )
269       {
270          int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, mmesa->numClipRects);
271          drm_clip_rect_t *box = mmesa->pClipRects;
272          drm_clip_rect_t *b = mmesa->sarea->boxes;
273          int n = 0;
274
275          if (cw != dPriv->w || ch != dPriv->h) {
276             /* clear subregion */
277             for ( ; i < nr ; i++) {
278                GLint x = box[i].x1;
279                GLint y = box[i].y1;
280                GLint w = box[i].x2 - x;
281                GLint h = box[i].y2 - y;
282
283                if (x < cx) w -= cx - x, x = cx;
284                if (y < cy) h -= cy - y, y = cy;
285                if (x + w > cx + cw) w = cx + cw - x;
286                if (y + h > cy + ch) h = cy + ch - y;
287                if (w <= 0) continue;
288                if (h <= 0) continue;
289
290                b->x1 = x;
291                b->y1 = y;
292                b->x2 = x + w;
293                b->y2 = y + h;
294                b++;
295                n++;
296             }
297          } else {
298             /* clear whole window */
299             for ( ; i < nr ; i++) {
300                *b++ = box[i];
301                n++;
302             }
303          }
304
305
306          if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
307             fprintf( stderr,
308                      "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n",
309                      flags, clear_color, clear_depth, mmesa->sarea->nbox );
310
311          mmesa->sarea->nbox = n;
312
313          clear.flags = flags;
314          clear.clear_color = clear_color;
315          clear.clear_depth = clear_depth;
316          clear.color_mask = color_mask;
317          clear.depth_mask = depth_mask;
318          ret = drmCommandWrite( mmesa->driFd, DRM_MGA_CLEAR,
319                                  &clear, sizeof(clear));
320          if ( ret ) {
321             fprintf( stderr, "send clear retcode = %d\n", ret );
322             exit( 1 );
323          }
324          if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
325             fprintf( stderr, "finished clear %d\n", ++nrclears );
326       }
327
328       UNLOCK_HARDWARE( mmesa );
329       mmesa->dirty |= MGA_UPLOAD_CLIPRECTS|MGA_UPLOAD_CONTEXT;
330    }
331
332    if (mask) 
333       _swrast_Clear( ctx, mask );
334 }
335
336
337 /**
338  * Wait for the previous frame of rendering has completed.
339  * 
340  * \param mmesa  Hardware context pointer.
341  *
342  * \bug
343  * The loop in this function should have some sort of a timeout mechanism.
344  *
345  * \warning
346  * This routine used to assume that the hardware lock was held on entry.  It
347  * now assumes that the lock is \b not held on entry.
348  */
349
350 static void mgaWaitForFrameCompletion( mgaContextPtr mmesa )
351 {
352     if ( mgaWaitFence( mmesa, mmesa->last_frame_fence, NULL ) == ENOSYS ) {
353         unsigned wait = 0;
354         GLuint last_frame;
355         GLuint last_wrap;
356
357
358         LOCK_HARDWARE( mmesa );
359         last_frame = mmesa->sarea->last_frame.head;
360         last_wrap = mmesa->sarea->last_frame.wrap;
361
362         /* The DMA routines in the kernel track a couple values in the SAREA
363          * that we use here.  The number of times that the primary DMA buffer
364          * has "wrapped" around is tracked in last_wrap.  In addition, the
365          * wrap count and the buffer position at the end of the last frame are
366          * stored in last_frame.wrap and last_frame.head.
367          * 
368          * By comparing the wrap counts and the current DMA pointer value
369          * (read directly from the hardware) to last_frame.head, we can
370          * determine when the graphics processor has processed all of the
371          * commands for the last frame.
372          * 
373          * In this case "last frame" means the frame of the *previous* swap-
374          * buffers call.  This is done to prevent queuing a second buffer swap
375          * before the previous swap is executed.
376          */
377         while ( 1 ) {
378             if ( last_wrap < mmesa->sarea->last_wrap ||
379                  ( last_wrap == mmesa->sarea->last_wrap &&
380                    last_frame <= (MGA_READ( MGAREG_PRIMADDRESS ) -
381                                   mmesa->primary_offset) ) ) {
382                 break;
383             }
384             if ( 0 ) {
385                 wait++;
386                 fprintf( stderr, "   last: head=0x%06x wrap=%d\n",
387                          last_frame, last_wrap );
388                 fprintf( stderr, "   head: head=0x%06lx wrap=%d\n",
389                          (long)(MGA_READ( MGAREG_PRIMADDRESS ) - mmesa->primary_offset),
390                          mmesa->sarea->last_wrap );
391             }
392             UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
393
394             UNLOCK_HARDWARE( mmesa );
395             DO_USLEEP( 1 );
396             LOCK_HARDWARE( mmesa );
397         }
398         if ( wait )
399           fprintf( stderr, "\n" );
400
401         UNLOCK_HARDWARE( mmesa );
402     }
403 }
404
405
406 /*
407  * Copy the back buffer to the front buffer.
408  */
409 void mgaCopyBuffer( __DRIdrawable *dPriv )
410 {
411    mgaContextPtr mmesa;
412    drm_clip_rect_t *pbox;
413    GLint nbox;
414    GLint ret;
415    GLint i;
416    GLboolean   missed_target;
417    __DRIscreen *psp = dPriv->driScreenPriv;
418
419    assert(dPriv);
420    assert(dPriv->driContextPriv);
421    assert(dPriv->driContextPriv->driverPrivate);
422
423    mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate;
424
425    FLUSH_BATCH( mmesa );
426
427    mgaWaitForFrameCompletion( mmesa );
428    driWaitForVBlank( dPriv, & missed_target );
429    if ( missed_target ) {
430       mmesa->swap_missed_count++;
431       (void) (*psp->systemTime->getUST)( & mmesa->swap_missed_ust );
432    }
433    LOCK_HARDWARE( mmesa );
434
435    /* Use the frontbuffer cliprects
436     */
437    if (mmesa->dirty_cliprects & MGA_FRONT)
438       mgaUpdateRects( mmesa, MGA_FRONT );
439
440
441    pbox = dPriv->pClipRects;
442    nbox = dPriv->numClipRects;
443
444    for (i = 0 ; i < nbox ; )
445    {
446       int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, dPriv->numClipRects);
447       drm_clip_rect_t *b = mmesa->sarea->boxes;
448
449       mmesa->sarea->nbox = nr - i;
450
451       for ( ; i < nr ; i++)
452          *b++ = pbox[i];
453
454       if (0)
455          fprintf(stderr, "DRM_IOCTL_MGA_SWAP\n");
456
457       ret = drmCommandNone( mmesa->driFd, DRM_MGA_SWAP );
458       if ( ret ) {
459          printf("send swap retcode = %d\n", ret);
460          exit(1);
461       }
462    }
463
464    (void) mgaSetFence( mmesa, & mmesa->last_frame_fence );
465    UNLOCK_HARDWARE( mmesa );
466
467    mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
468    mmesa->swap_count++;
469    (void) (*psp->systemTime->getUST)( & mmesa->swap_ust );
470 }
471
472
473 /**
474  * Implement the hardware-specific portion of \c glFinish.
475  *
476  * Flushes all pending commands to the hardware and wait for them to finish.
477  * 
478  * \param ctx  Context where the \c glFinish command was issued.
479  *
480  * \sa glFinish, mgaFlush, mgaFlushDMA
481  */
482 static void mgaFinish( struct gl_context *ctx  )
483 {
484     mgaContextPtr mmesa = MGA_CONTEXT(ctx);
485     uint32_t  fence;
486
487
488     LOCK_HARDWARE( mmesa );
489     if ( mmesa->vertex_dma_buffer != NULL ) {
490         mgaFlushVerticesLocked( mmesa );
491     }
492
493     if ( mgaSetFence( mmesa, & fence ) == 0 ) {
494         UNLOCK_HARDWARE( mmesa );
495         (void) mgaWaitFence( mmesa, fence, NULL );
496     }
497     else {
498         if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) {
499             fprintf(stderr, "mgaRegetLockQuiescent\n");
500         }
501
502         UPDATE_LOCK( mmesa, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH );
503         UNLOCK_HARDWARE( mmesa );
504     }
505 }
506
507
508 /**
509  * Flush all commands upto at least a certain point to the hardware.
510  *
511  * \note
512  * The term "wait" in the name of this function is misleading.  It doesn't
513  * actually wait for anything.  It just makes sure that the commands have
514  * been flushed to the hardware.
515  *
516  * \warning
517  * As the name implies, this function assumes that the hardware lock is
518  * held on entry.
519  */
520 void mgaWaitAgeLocked( mgaContextPtr mmesa, int age  )
521 {
522    if (GET_DISPATCH_AGE(mmesa) < age) {
523       UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
524    }
525 }
526
527
528 static GLboolean intersect_rect( drm_clip_rect_t *out,
529                                  const drm_clip_rect_t *a,
530                                  const drm_clip_rect_t *b )
531 {
532    *out = *a;
533    if (b->x1 > out->x1) out->x1 = b->x1;
534    if (b->y1 > out->y1) out->y1 = b->y1;
535    if (b->x2 < out->x2) out->x2 = b->x2;
536    if (b->y2 < out->y2) out->y2 = b->y2;
537
538    return ((out->x1 < out->x2) && (out->y1 < out->y2));
539 }
540
541
542
543
544 static void age_mmesa( mgaContextPtr mmesa, int age )
545 {
546    if (mmesa->CurrentTexObj[0]) mmesa->CurrentTexObj[0]->age = age;
547    if (mmesa->CurrentTexObj[1]) mmesa->CurrentTexObj[1]->age = age;
548 }
549
550
551 void mgaFlushVerticesLocked( mgaContextPtr mmesa )
552 {
553    drm_clip_rect_t *pbox = mmesa->pClipRects;
554    int nbox = mmesa->numClipRects;
555    drmBufPtr buffer = mmesa->vertex_dma_buffer;
556    drm_mga_vertex_t vertex;
557    int i;
558
559    mmesa->vertex_dma_buffer = 0;
560
561    if (!buffer)
562       return;
563
564    if (mmesa->dirty_cliprects & mmesa->draw_buffer)
565       mgaUpdateRects( mmesa, mmesa->draw_buffer );
566
567    if (mmesa->dirty & ~MGA_UPLOAD_CLIPRECTS)
568       mgaEmitHwStateLocked( mmesa );
569
570    /* FIXME: Workaround bug in kernel module.
571     */
572    mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT;
573
574    if (!nbox)
575       buffer->used = 0;
576
577    if (nbox >= MGA_NR_SAREA_CLIPRECTS)
578       mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
579
580 #if 0
581    if (!buffer->used || !(mmesa->dirty & MGA_UPLOAD_CLIPRECTS))
582    {
583       if (nbox == 1)
584          mmesa->sarea->nbox = 0;
585       else
586          mmesa->sarea->nbox = nbox;
587
588       if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
589          fprintf(stderr, "Firing vertex -- case a nbox %d\n", nbox);
590
591       vertex.idx = buffer->idx;
592       vertex.used = buffer->used;
593       vertex.discard = 1;
594       drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX, 
595                        &vertex, sizeof(drmMGAVertex) );
596
597       age_mmesa(mmesa, mmesa->sarea->last_enqueue);
598    }
599    else
600 #endif
601    {
602       for (i = 0 ; i < nbox ; )
603       {
604          int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, nbox);
605          drm_clip_rect_t *b = mmesa->sarea->boxes;
606          int discard = 0;
607
608          if (mmesa->scissor) {
609             mmesa->sarea->nbox = 0;
610
611             for ( ; i < nr ; i++) {
612                *b = pbox[i];
613                if (intersect_rect(b, b, &mmesa->scissor_rect)) {
614                   mmesa->sarea->nbox++;
615                   b++;
616                }
617             }
618
619             /* Culled?
620              */
621             if (!mmesa->sarea->nbox) {
622                if (nr < nbox) continue;
623                buffer->used = 0;
624             }
625          } else {
626             mmesa->sarea->nbox = nr - i;
627             for ( ; i < nr ; i++)
628                *b++ = pbox[i];
629          }
630
631          /* Finished with the buffer?
632           */
633          if (nr == nbox)
634             discard = 1;
635
636          mmesa->sarea->dirty |= MGA_UPLOAD_CLIPRECTS;
637
638          vertex.idx = buffer->idx;
639          vertex.used = buffer->used;
640          vertex.discard = discard;
641          drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX,
642                           &vertex, sizeof(vertex) );
643
644          age_mmesa(mmesa, mmesa->sarea->last_enqueue);
645       }
646    }
647
648    mmesa->dirty &= ~MGA_UPLOAD_CLIPRECTS;
649 }
650
651 void mgaFlushVertices( mgaContextPtr mmesa )
652 {
653    LOCK_HARDWARE( mmesa );
654    mgaFlushVerticesLocked( mmesa );
655    UNLOCK_HARDWARE( mmesa );
656 }
657
658
659 void mgaFireILoadLocked( mgaContextPtr mmesa,
660                          GLuint offset, GLuint length )
661 {
662    if (!mmesa->iload_buffer) {
663       fprintf(stderr, "mgaFireILoad: no buffer\n");
664       return;
665    }
666
667    if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
668       fprintf(stderr, "mgaFireILoad idx %d ofs 0x%x length %d\n",
669               mmesa->iload_buffer->idx, (int)offset, (int)length );
670
671    mga_iload_dma_ioctl( mmesa, offset, length );
672 }
673
674 void mgaGetILoadBufferLocked( mgaContextPtr mmesa )
675 {
676    if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
677       fprintf(stderr, "mgaGetIloadBuffer (buffer now %p)\n",
678               (void *) mmesa->iload_buffer);
679
680    mmesa->iload_buffer = mga_get_buffer_ioctl( mmesa );
681 }
682
683
684 /**
685  * Implement the hardware-specific portion of \c glFlush.
686  *
687  * \param ctx  Context to be flushed.
688  *
689  * \sa glFlush, mgaFinish, mgaFlushDMA
690  */
691 static void mgaFlush( struct gl_context *ctx )
692 {
693     mgaContextPtr mmesa = MGA_CONTEXT( ctx );
694
695
696     LOCK_HARDWARE( mmesa );
697     if ( mmesa->vertex_dma_buffer != NULL ) {
698         mgaFlushVerticesLocked( mmesa );
699     }
700
701     UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
702     UNLOCK_HARDWARE( mmesa );
703 }
704
705
706 int mgaFlushDMA( int fd, drmLockFlags flags )
707 {
708    drm_lock_t lock;
709    int ret, i = 0;
710
711    memset( &lock, 0, sizeof(lock) );
712
713    lock.flags = flags & (DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH 
714                          | DRM_LOCK_FLUSH_ALL);
715
716    do {
717       ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) );
718    } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY );
719
720    if ( ret == 0 )
721       return 0;
722    if ( errno != EBUSY )
723       return -errno;
724
725    if ( lock.flags & DRM_LOCK_QUIESCENT ) {
726       /* Only keep trying if we need quiescence.
727        */
728       lock.flags &= ~(DRM_LOCK_FLUSH | DRM_LOCK_FLUSH_ALL);
729
730       do {
731          ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) );
732       } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY );
733    }
734
735    if ( ret == 0 ) {
736       return 0;
737    } else {
738       return -errno;
739    }
740 }
741
742 void mgaInitIoctlFuncs( struct dd_function_table *functions )
743 {
744    functions->Clear = mgaClear;
745    functions->Flush = mgaFlush;
746    functions->Finish = mgaFinish;
747 }