mga_dri.c revision 0bb88ba4
1/*
2 * Copyright 2000 VA Linux Systems Inc., Fremont, California.
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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
19 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES
20 * OR 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 * Authors:
25 *    Keith Whitwell <keith@tungstengraphics.com>
26 *    Gareth Hughes <gareth@valinux.com>
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include "xf86.h"
34#include "xf86_OSproc.h"
35
36#include "xf86Pci.h"
37
38#include "miline.h"
39
40#include <errno.h>
41
42#include <inttypes.h>
43#include "mga_reg.h"
44#include "mga.h"
45#include "mga_macros.h"
46#include "mga_dri.h"
47#include "mga_sarea.h"
48#include "mga_drm.h"
49
50#define _XF86DRI_SERVER_
51#include "GL/glxtokens.h"
52#include "sarea.h"
53
54
55
56
57
58#include "GL/glxtokens.h"
59
60#include "mga_reg.h"
61#include "mga.h"
62#include "mga_macros.h"
63#include "mga_dri.h"
64
65#define  DRM_MGA_IDLE_RETRY          2048
66
67static char MGAKernelDriverName[] = "mga";
68static char MGAClientDriverName[] = "mga";
69
70/* Initialize the visual configs that are supported by the hardware.
71 * These are combined with the visual configs that the indirect
72 * rendering core supports, and the intersection is exported to the
73 * client.
74 */
75static Bool MGAInitVisualConfigs( ScreenPtr pScreen )
76{
77   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
78   MGAPtr pMga = MGAPTR(pScrn);
79   int numConfigs = 0;
80   __GLXvisualConfig *pConfigs = 0;
81   MGAConfigPrivPtr pMGAConfigs = 0;
82   MGAConfigPrivPtr *pMGAConfigPtrs = 0;
83   int i, db, depth, stencil, accum;
84
85   switch ( pScrn->bitsPerPixel ) {
86   case 8:
87   case 24:
88      break;
89
90   case 16:
91      numConfigs = 8;
92
93      pConfigs = (__GLXvisualConfig*)calloc( sizeof(__GLXvisualConfig),
94						numConfigs );
95      if ( !pConfigs ) {
96	 return FALSE;
97      }
98
99      pMGAConfigs = (MGAConfigPrivPtr)calloc( sizeof(MGAConfigPrivRec),
100						 numConfigs );
101      if ( !pMGAConfigs ) {
102	 free(pConfigs);
103	 return FALSE;
104      }
105
106      pMGAConfigPtrs = (MGAConfigPrivPtr*)calloc( sizeof(MGAConfigPrivPtr),
107						     numConfigs );
108      if ( !pMGAConfigPtrs ) {
109	 free(pConfigs);
110	 free(pMGAConfigs);
111	 return FALSE;
112      }
113
114      for ( i = 0 ; i < numConfigs ; i++ ) {
115	 pMGAConfigPtrs[i] = &pMGAConfigs[i];
116      }
117
118      i = 0;
119      for ( accum = 0 ; accum <= 1 ; accum++ ) {
120         for ( stencil = 0 ; stencil <= 1 ; stencil++ ) {
121            for ( db = 1 ; db >= 0 ; db-- ) {
122               pConfigs[i].vid			= -1;
123               pConfigs[i].class		= -1;
124               pConfigs[i].rgba			= TRUE;
125               pConfigs[i].redSize		= 5;
126               pConfigs[i].greenSize		= 6;
127               pConfigs[i].blueSize		= 5;
128               pConfigs[i].alphaSize		= 0;
129               pConfigs[i].redMask		= 0x0000F800;
130               pConfigs[i].greenMask		= 0x000007E0;
131               pConfigs[i].blueMask		= 0x0000001F;
132               pConfigs[i].alphaMask		= 0;
133               if ( accum ) {
134                  pConfigs[i].accumRedSize	= 16;
135                  pConfigs[i].accumGreenSize	= 16;
136                  pConfigs[i].accumBlueSize	= 16;
137                  pConfigs[i].accumAlphaSize	= 0;
138               } else {
139                  pConfigs[i].accumRedSize	= 0;
140                  pConfigs[i].accumGreenSize	= 0;
141                  pConfigs[i].accumBlueSize	= 0;
142                  pConfigs[i].accumAlphaSize	= 0;
143               }
144               if ( db ) {
145                  pConfigs[i].doubleBuffer	= TRUE;
146               } else {
147                  pConfigs[i].doubleBuffer	= FALSE;
148	       }
149               pConfigs[i].stereo		= FALSE;
150               pConfigs[i].bufferSize		= 16;
151               pConfigs[i].depthSize		= 16;
152               if ( stencil ) {
153                  pConfigs[i].stencilSize	= 8;
154               } else {
155                  pConfigs[i].stencilSize	= 0;
156	       }
157               pConfigs[i].auxBuffers		= 0;
158               pConfigs[i].level		= 0;
159               if ( accum || stencil ) {
160                  pConfigs[i].visualRating	= GLX_SLOW_CONFIG;
161               } else {
162                  pConfigs[i].visualRating	= GLX_NONE;
163	       }
164               pConfigs[i].transparentPixel	= GLX_NONE;
165               pConfigs[i].transparentRed	= 0;
166               pConfigs[i].transparentGreen	= 0;
167               pConfigs[i].transparentBlue	= 0;
168               pConfigs[i].transparentAlpha	= 0;
169               pConfigs[i].transparentIndex	= 0;
170               i++;
171            }
172         }
173      }
174      if ( i != numConfigs ) {
175         xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
176		     "[drm] Incorrect initialization of visuals\n" );
177         return FALSE;
178      }
179      break;
180
181   case 32:
182      numConfigs = 8;
183
184      pConfigs = (__GLXvisualConfig*)calloc( sizeof(__GLXvisualConfig),
185						numConfigs );
186      if ( !pConfigs ) {
187	 return FALSE;
188      }
189
190      pMGAConfigs = (MGAConfigPrivPtr)calloc( sizeof(MGAConfigPrivRec),
191						 numConfigs );
192      if ( !pMGAConfigs ) {
193	 free(pConfigs);
194	 return FALSE;
195      }
196
197      pMGAConfigPtrs = (MGAConfigPrivPtr*)calloc( sizeof(MGAConfigPrivPtr),
198						     numConfigs );
199      if ( !pMGAConfigPtrs ) {
200	 free(pConfigs);
201	 free(pMGAConfigs);
202	 return FALSE;
203      }
204
205      for ( i = 0 ; i < numConfigs ; i++ ) {
206	 pMGAConfigPtrs[i] = &pMGAConfigs[i];
207      }
208
209      i = 0;
210      for ( accum = 0 ; accum <= 1 ; accum++ ) {
211         for ( depth = 0 ; depth <= 1 ; depth++ ) { /* and stencil */
212            for ( db = 1 ; db >= 0 ; db-- ) {
213               pConfigs[i].vid			= -1;
214               pConfigs[i].class		= -1;
215               pConfigs[i].rgba			= TRUE;
216               pConfigs[i].redSize		= 8;
217               pConfigs[i].greenSize		= 8;
218               pConfigs[i].blueSize		= 8;
219               pConfigs[i].alphaSize		= 0;
220               pConfigs[i].redMask		= 0x00FF0000;
221               pConfigs[i].greenMask		= 0x0000FF00;
222               pConfigs[i].blueMask		= 0x000000FF;
223               pConfigs[i].alphaMask		= 0x0;
224               if ( accum ) {
225                  pConfigs[i].accumRedSize	= 16;
226                  pConfigs[i].accumGreenSize	= 16;
227                  pConfigs[i].accumBlueSize	= 16;
228                  pConfigs[i].accumAlphaSize	= 0;
229               } else {
230                  pConfigs[i].accumRedSize	= 0;
231                  pConfigs[i].accumGreenSize	= 0;
232                  pConfigs[i].accumBlueSize	= 0;
233                  pConfigs[i].accumAlphaSize	= 0;
234               }
235               if ( db ) {
236                  pConfigs[i].doubleBuffer	= TRUE;
237               } else {
238                  pConfigs[i].doubleBuffer	= FALSE;
239	       }
240               pConfigs[i].stereo		= FALSE;
241               pConfigs[i].bufferSize		= 24;
242               if ( depth ) {
243		     pConfigs[i].depthSize	= 24;
244                     pConfigs[i].stencilSize	= 8;
245               }
246               else {
247                     pConfigs[i].depthSize	= 0;
248                     pConfigs[i].stencilSize	= 0;
249               }
250               pConfigs[i].auxBuffers		= 0;
251               pConfigs[i].level		= 0;
252               if ( accum ) {
253                  pConfigs[i].visualRating	= GLX_SLOW_CONFIG;
254               } else {
255                  pConfigs[i].visualRating	= GLX_NONE;
256	       }
257               pConfigs[i].transparentPixel	= GLX_NONE;
258               pConfigs[i].transparentRed	= 0;
259               pConfigs[i].transparentGreen	= 0;
260               pConfigs[i].transparentBlue	= 0;
261               pConfigs[i].transparentAlpha	= 0;
262               pConfigs[i].transparentIndex	= 0;
263               i++;
264            }
265         }
266      }
267      if ( i != numConfigs ) {
268         xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
269		     "[drm] Incorrect initialization of visuals\n" );
270         return FALSE;
271      }
272      break;
273
274   default:
275      /* Unexpected bits/pixels */
276      break;
277   }
278
279   pMga->numVisualConfigs = numConfigs;
280   pMga->pVisualConfigs = pConfigs;
281   pMga->pVisualConfigsPriv = pMGAConfigs;
282
283   GlxSetVisualConfigs( numConfigs, pConfigs, (void **)pMGAConfigPtrs );
284
285   return TRUE;
286}
287
288static Bool MGACreateContext( ScreenPtr pScreen, VisualPtr visual,
289			      drm_context_t hwContext, void *pVisualConfigPriv,
290			      DRIContextType contextStore )
291{
292   /* Nothing yet */
293   return TRUE;
294}
295
296static void MGADestroyContext( ScreenPtr pScreen, drm_context_t hwContext,
297			       DRIContextType contextStore )
298{
299   /* Nothing yet */
300}
301
302
303/* Quiescence, locking
304 */
305#define MGA_TIMEOUT		2048
306
307static void MGAWaitForIdleDMA( ScrnInfoPtr pScrn )
308{
309   MGAPtr pMga = MGAPTR(pScrn);
310   drm_lock_t lock;
311   int ret;
312   int i = 0;
313
314   memset( &lock, 0, sizeof(drm_lock_t) );
315
316   for (;;) {
317      do {
318         /* first ask for quiescent and flush */
319         lock.flags = DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH;
320         do {
321	    ret = drmCommandWrite( pMga->drmFD, DRM_MGA_FLUSH,
322                                   &lock, sizeof( drm_lock_t ) );
323         } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY );
324
325         /* if it's still busy just try quiescent */
326         if ( ret == -EBUSY ) {
327            lock.flags = DRM_LOCK_QUIESCENT;
328            do {
329	       ret = drmCommandWrite( pMga->drmFD, DRM_MGA_FLUSH,
330                                      &lock, sizeof( drm_lock_t ) );
331            } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY );
332         }
333      } while ( ( ret == -EBUSY ) && ( i++ < MGA_TIMEOUT ) );
334
335      if ( ret == 0 )
336	 return;
337
338      xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
339		  "[dri] Idle timed out, resetting engine...\n" );
340
341      drmCommandNone( pMga->drmFD, DRM_MGA_RESET );
342   }
343}
344
345
346void MGAGetQuiescence( ScrnInfoPtr pScrn )
347{
348   MGAPtr pMga = MGAPTR(pScrn);
349
350   pMga->haveQuiescense = 1;
351
352   if ( pMga->directRenderingEnabled ) {
353      MGAFBLayout *pLayout = &pMga->CurrentLayout;
354
355      MGAWaitForIdleDMA( pScrn );
356
357        /* FIXME what about EXA? */
358#ifdef XAA
359        if (!pMga->Exa && pMga->AccelInfoRec) {
360      WAITFIFO( 11 );
361      OUTREG( MGAREG_MACCESS, pMga->MAccess );
362      OUTREG( MGAREG_PITCH, pLayout->displayWidth );
363
364      pMga->PlaneMask = ~0;
365      OUTREG( MGAREG_PLNWT, pMga->PlaneMask );
366
367      pMga->BgColor = 0;
368      pMga->FgColor = 0;
369      OUTREG( MGAREG_BCOL, pMga->BgColor );
370      OUTREG( MGAREG_FCOL, pMga->FgColor );
371      OUTREG( MGAREG_SRCORG, pMga->realSrcOrg );
372
373      pMga->SrcOrg = 0;
374      OUTREG( MGAREG_DSTORG, pMga->DstOrg );
375      OUTREG( MGAREG_OPMODE, MGAOPM_DMA_BLIT );
376      OUTREG( MGAREG_CXBNDRY, 0xFFFF0000 ); /* (maxX << 16) | minX */
377      OUTREG( MGAREG_YTOP, 0x00000000 );    /* minPixelPointer */
378      OUTREG( MGAREG_YBOT, 0x007FFFFF );    /* maxPixelPointer */
379
380            pMga->AccelFlags &= ~CLIPPER_ON;
381        }
382#endif
383   }
384}
385
386void MGAGetQuiescenceShared( ScrnInfoPtr pScrn )
387{
388   MGAPtr pMga = MGAPTR(pScrn);
389   MGAEntPtr pMGAEnt = pMga->entityPrivate;
390   MGAPtr pMGA2 = MGAPTR(pMGAEnt->pScrn_2);
391
392   pMga = MGAPTR(pMGAEnt->pScrn_1);
393   pMga->haveQuiescense = 1;
394   pMGA2->haveQuiescense = 1;
395
396   if ( pMGAEnt->directRenderingEnabled ) {
397      MGAWaitForIdleDMA( pMGAEnt->pScrn_1 );
398
399        /* FIXME what about EXA? */
400#ifdef USE_XAA
401        if (!pMga->Exa && pMga->AccelInfoRec)
402            pMga->RestoreAccelState( pScrn );
403#endif
404      xf86SetLastScrnFlag( pScrn->entityList[0], pScrn->scrnIndex );
405   }
406}
407
408static void MGASwapContext( ScreenPtr pScreen )
409{
410   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
411   MGAPtr pMga = MGAPTR(pScrn);
412
413   /* Arrange for dma_quiescence and xaa sync to be called as
414    * appropriate.
415    */
416   pMga->haveQuiescense = 0;
417
418   MGA_MARK_SYNC(pMga, pScrn);
419}
420
421static void MGASwapContextShared( ScreenPtr pScreen )
422{
423   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
424   MGAPtr pMga = MGAPTR(pScrn);
425   MGAEntPtr pMGAEnt = pMga->entityPrivate;
426   MGAPtr pMGA2 = MGAPTR(pMGAEnt->pScrn_2);
427
428   pMga = MGAPTR(pMGAEnt->pScrn_1);
429
430   pMga->haveQuiescense = pMGA2->haveQuiescense = 0;
431
432   MGA_MARK_SYNC(pMga, pScrn);
433   MGA_MARK_SYNC(pMGA2, pMGAEnt->pScrn_2);
434}
435
436/* FIXME: This comment is out of date, since we aren't overriding
437 * Block/Wakeuphandler anymore.
438 *
439 *
440 * This is really only called from validate/postvalidate as we
441 * override the dri lock/unlock.  Want to remove validate/postvalidate
442 * processing, but need to remove all client-side use of drawable lock
443 * first (otherwise there is noone recover when a client dies holding
444 * the drawable lock).
445 *
446 * What does this mean?
447 *
448 *   - The above code gets executed every time a
449 *     window changes shape or the focus changes, which isn't really
450 *     optimal.
451 *   - The X server therefore believes it needs to do an XAA sync
452 *     *and* a dma quiescense ioctl each time that happens.
453 *
454 * We don't wrap wakeuphandler any longer, so at least we can say that
455 * this doesn't happen *every time the mouse moves*...
456 */
457static void
458MGADRISwapContext( ScreenPtr pScreen, DRISyncType syncType,
459		   DRIContextType oldContextType, void *oldContext,
460		   DRIContextType newContextType, void *newContext )
461{
462   if ( syncType == DRI_3D_SYNC &&
463	oldContextType == DRI_2D_CONTEXT &&
464	newContextType == DRI_2D_CONTEXT )
465   {
466      MGASwapContext( pScreen );
467   }
468}
469
470static void
471MGADRISwapContextShared( ScreenPtr pScreen, DRISyncType syncType,
472			  DRIContextType oldContextType, void *oldContext,
473			  DRIContextType newContextType, void *newContext )
474{
475   if ( syncType == DRI_3D_SYNC &&
476	oldContextType == DRI_2D_CONTEXT &&
477	newContextType == DRI_2D_CONTEXT )
478   {
479      MGASwapContextShared( pScreen );
480   }
481}
482
483void MGASelectBuffer( ScrnInfoPtr pScrn, int which )
484{
485   MGAPtr pMga = MGAPTR(pScrn);
486   MGADRIPtr pMGADRI = (MGADRIPtr)pMga->pDRIInfo->devPrivate;
487
488   switch ( which ) {
489   case MGA_BACK:
490      OUTREG( MGAREG_DSTORG, pMGADRI->backOffset );
491      OUTREG( MGAREG_SRCORG, pMGADRI->backOffset );
492      break;
493   case MGA_DEPTH:
494      OUTREG( MGAREG_DSTORG, pMGADRI->depthOffset );
495      OUTREG( MGAREG_SRCORG, pMGADRI->depthOffset );
496      break;
497   default:
498   case MGA_FRONT:
499      OUTREG( MGAREG_DSTORG, pMGADRI->frontOffset );
500      OUTREG( MGAREG_SRCORG, pMGADRI->frontOffset );
501      break;
502   }
503}
504
505static unsigned int mylog2( unsigned int n )
506{
507   unsigned int log2 = 1;
508   while ( n > 1 ) n >>= 1, log2++;
509   return log2;
510}
511
512/**
513 * Initialize DMA and secondary texture memory
514 *
515 * \todo
516 * The sizes used for the primary DMA buffer and the bin size and count for
517 * the secondary DMA buffers should be configurable from the xorg.conf.
518 *
519 * \todo
520 * This routine should use \c mga_bios_values::host_interface to limit the
521 * AGP mode.  It the card is PCI, \c MGARec::agpSize should be forced to 0.
522 */
523static Bool MGADRIBootstrapDMA(ScreenPtr pScreen)
524{
525    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
526    MGAPtr pMga = MGAPTR(pScrn);
527    MGADRIServerPrivatePtr pMGADRIServer = pMga->DRIServerInfo;
528    int ret;
529    int requested_agp_mode;
530    int count;
531
532
533    if(pMga->agpSize < 12)pMga->agpSize = 12;
534    if(pMga->agpSize > 64)pMga->agpSize = 64; /* cap */
535
536
537    requested_agp_mode = 0;
538    switch ( pMga->agpMode ) {
539    case 4:
540	requested_agp_mode |= MGA_AGP_4X_MODE;
541    case 2:
542	requested_agp_mode |= MGA_AGP_2X_MODE;
543    case 1:
544    default:
545	requested_agp_mode |= MGA_AGP_1X_MODE;
546    }
547
548
549    if ( (pMGADRIServer->drm_version_minor >= 2) && !pMga->useOldDmaInit ) {
550	drm_mga_dma_bootstrap_t dma_bs;
551
552
553	(void) memset( & dma_bs, 0, sizeof( dma_bs ) );
554	dma_bs.primary_size = 1024 * 1024;
555	dma_bs.secondary_bin_count = MGA_NUM_BUFFERS;
556	dma_bs.secondary_bin_size = MGA_BUFFER_SIZE;
557	dma_bs.agp_size = pMga->agpSize;
558	dma_bs.agp_mode = (pMga->forcePciDma) ? 0 : requested_agp_mode;
559
560	ret = drmCommandWriteRead( pMga->drmFD, DRM_MGA_DMA_BOOTSTRAP,
561				   & dma_bs, sizeof( dma_bs ) );
562	if ( ret ) {
563	    xf86DrvMsg( pScreen->myNum, X_ERROR, "[drm] Could not boot-strap DMA (%d)\n", ret );
564	    return FALSE;
565	}
566
567	pMga->agpMode = dma_bs.agp_mode;
568	pMGADRIServer->agp.size = dma_bs.agp_size;
569
570	pMGADRIServer->agpTextures.handle = dma_bs.texture_handle;
571	pMGADRIServer->agpTextures.size   = dma_bs.texture_size;
572    }
573    else {
574	unsigned long mode;
575	unsigned int vendor, device;
576	int i;
577
578
579	if ( pMga->forcePciDma ) {
580	    const char * const msg = (pMGADRIServer->drm_version_minor < 2)
581	      ? "DRM version is too old (3.2 or later required)"
582	      : "old DMA init path was requested";
583
584	    xf86DrvMsg( pScreen->myNum, X_WARNING,
585			"[agp] Cannot force PCI DMA because %s\n", msg );
586	}
587
588	if ( drmAgpAcquire( pMga->drmFD ) < 0 ) {
589	    xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] AGP not available\n" );
590	    return FALSE;
591	}
592
593	mode   = drmAgpGetMode( pMga->drmFD );        /* Default mode */
594	vendor = drmAgpVendorId( pMga->drmFD );
595	device = drmAgpDeviceId( pMga->drmFD );
596
597	mode = (mode & ~MGA_AGP_MODE_MASK) | requested_agp_mode;
598
599	xf86DrvMsg( pScreen->myNum, X_INFO,
600		    "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n",
601		    mode, vendor, device,
602		    VENDOR_ID(pMga->PciInfo),
603		    DEVICE_ID(pMga->PciInfo));
604
605	if ( drmAgpEnable( pMga->drmFD, mode ) < 0 ) {
606	    xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n" );
607	    drmAgpRelease( pMga->drmFD );
608	    return FALSE;
609	}
610
611	if ( pMga->Chipset == PCI_CHIP_MGAG200 ) {
612	    switch ( pMga->agpMode ) {
613	    case 2:
614		xf86DrvMsg( pScreen->myNum, X_INFO,
615			    "[drm] Enabling AGP 2x PLL encoding\n" );
616		OUTREG( MGAREG_AGP_PLL, MGA_AGP2XPLL_ENABLE );
617		break;
618
619	    case 1:
620	    default:
621		xf86DrvMsg( pScreen->myNum, X_INFO,
622			    "[drm] Disabling AGP 2x PLL encoding\n" );
623		OUTREG( MGAREG_AGP_PLL, MGA_AGP2XPLL_DISABLE );
624		pMga->agpMode = 1;
625		break;
626	    }
627	}
628
629	pMGADRIServer->agp.size = pMga->agpSize * 1024 * 1024;
630
631	pMGADRIServer->warp.offset = 0;
632	pMGADRIServer->warp.size = MGA_WARP_UCODE_SIZE;
633
634	pMGADRIServer->primary.offset = (pMGADRIServer->warp.offset +
635					 pMGADRIServer->warp.size);
636	pMGADRIServer->primary.size = 1024 * 1024;
637
638	pMGADRIServer->buffers.offset = (pMGADRIServer->primary.offset +
639					 pMGADRIServer->primary.size);
640	pMGADRIServer->buffers.size = MGA_NUM_BUFFERS * MGA_BUFFER_SIZE;
641
642
643	pMGADRIServer->agpTextures.offset = (pMGADRIServer->buffers.offset +
644					     pMGADRIServer->buffers.size);
645
646	pMGADRIServer->agpTextures.size = (pMGADRIServer->agp.size -
647					   pMGADRIServer->agpTextures.offset);
648
649	ret = drmAgpAlloc( pMga->drmFD, pMGADRIServer->agp.size,
650			   0, NULL, &pMGADRIServer->agp.handle );
651	if ( ret < 0 ) {
652	    xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret );
653	    drmAgpRelease( pMga->drmFD );
654	    return FALSE;
655	}
656	xf86DrvMsg( pScreen->myNum, X_INFO,
657 		    "[agp] %d kB allocated with handle 0x%08x\n",
658		    pMGADRIServer->agp.size/1024,
659		    (unsigned int) pMGADRIServer->agp.handle );
660
661	if ( drmAgpBind( pMga->drmFD, pMGADRIServer->agp.handle, 0 ) < 0 ) {
662	    xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Could not bind memory\n" );
663	    drmAgpFree( pMga->drmFD, pMGADRIServer->agp.handle );
664	    drmAgpRelease( pMga->drmFD );
665	    return FALSE;
666	}
667
668	/* WARP microcode space
669	 */
670	if ( drmAddMap( pMga->drmFD,
671			pMGADRIServer->warp.offset,
672			pMGADRIServer->warp.size,
673			DRM_AGP, DRM_READ_ONLY,
674			&pMGADRIServer->warp.handle ) < 0 ) {
675	    xf86DrvMsg( pScreen->myNum, X_ERROR,
676			"[agp] Could not add WARP microcode mapping\n" );
677	    return FALSE;
678	}
679	xf86DrvMsg( pScreen->myNum, X_INFO,
680 		    "[agp] WARP microcode handle = 0x%08x\n",
681		    (unsigned int) pMGADRIServer->warp.handle );
682
683	/* Primary DMA space
684	 */
685	if ( drmAddMap( pMga->drmFD,
686			pMGADRIServer->primary.offset,
687			pMGADRIServer->primary.size,
688			DRM_AGP, DRM_READ_ONLY,
689			&pMGADRIServer->primary.handle ) < 0 ) {
690	    xf86DrvMsg( pScreen->myNum, X_ERROR,
691			"[agp] Could not add primary DMA mapping\n" );
692	    return FALSE;
693	}
694	xf86DrvMsg( pScreen->myNum, X_INFO,
695 		    "[agp] Primary DMA handle = 0x%08x\n",
696		    (unsigned int) pMGADRIServer->primary.handle );
697
698	/* DMA buffers
699	 */
700	if ( drmAddMap( pMga->drmFD,
701			pMGADRIServer->buffers.offset,
702			pMGADRIServer->buffers.size,
703			DRM_AGP, 0,
704			&pMGADRIServer->buffers.handle ) < 0 ) {
705	    xf86DrvMsg( pScreen->myNum, X_ERROR,
706			"[agp] Could not add DMA buffers mapping\n" );
707	    return FALSE;
708	}
709	xf86DrvMsg( pScreen->myNum, X_INFO,
710 		    "[agp] DMA buffers handle = 0x%08x\n",
711		    (unsigned int) pMGADRIServer->buffers.handle );
712
713	count = drmAddBufs( pMga->drmFD,
714			    MGA_NUM_BUFFERS, MGA_BUFFER_SIZE,
715			    DRM_AGP_BUFFER, pMGADRIServer->buffers.offset );
716	if ( count <= 0 ) {
717	    xf86DrvMsg( pScrn->scrnIndex, X_INFO,
718			"[drm] failure adding %d %d byte DMA buffers\n",
719			MGA_NUM_BUFFERS, MGA_BUFFER_SIZE );
720	    return FALSE;
721	}
722	xf86DrvMsg( pScreen->myNum, X_INFO,
723		    "[drm] Added %d %d byte DMA buffers\n",
724		    count, MGA_BUFFER_SIZE );
725
726	i = mylog2(pMGADRIServer->agpTextures.size / MGA_NR_TEX_REGIONS);
727	if(i < MGA_LOG_MIN_TEX_REGION_SIZE)
728	  i = MGA_LOG_MIN_TEX_REGION_SIZE;
729	pMGADRIServer->agpTextures.size = (pMGADRIServer->agpTextures.size >> i) << i;
730
731	if ( drmAddMap( pMga->drmFD,
732			pMGADRIServer->agpTextures.offset,
733			pMGADRIServer->agpTextures.size,
734			DRM_AGP, 0,
735			&pMGADRIServer->agpTextures.handle ) < 0 ) {
736	    xf86DrvMsg( pScreen->myNum, X_ERROR,
737			"[agp] Could not add agpTexture mapping\n" );
738	    return FALSE;
739	}
740
741	xf86DrvMsg( pScreen->myNum, X_INFO,
742 		    "[agp] agpTexture handle = 0x%08x\n",
743		    (unsigned int) pMGADRIServer->agpTextures.handle );
744	xf86DrvMsg( pScreen->myNum, X_INFO,
745		    "[agp] agpTexture size: %d kb\n", pMGADRIServer->agpTextures.size/1024 );
746
747	pMGADRIServer->registers.size = MGAIOMAPSIZE;
748
749	if ( drmAddMap( pMga->drmFD,
750			(drm_handle_t) MGA_IO_ADDRESS(pMga),
751			pMGADRIServer->registers.size,
752			DRM_REGISTERS, DRM_READ_ONLY,
753			&pMGADRIServer->registers.handle ) < 0 ) {
754	    xf86DrvMsg( pScreen->myNum, X_ERROR,
755			"[drm] Could not add MMIO registers mapping\n" );
756	    return FALSE;
757	}
758	xf86DrvMsg( pScreen->myNum, X_INFO,
759 		    "[drm] Registers handle = 0x%08x\n",
760		    (unsigned int) pMGADRIServer->registers.handle );
761
762	pMGADRIServer->status.size = SAREA_MAX;
763
764	if ( drmAddMap( pMga->drmFD, 0, pMGADRIServer->status.size,
765			DRM_SHM, DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL,
766			&pMGADRIServer->status.handle ) < 0 ) {
767	    xf86DrvMsg( pScreen->myNum, X_ERROR,
768			"[drm] Could not add status page mapping\n" );
769	    return FALSE;
770	}
771	xf86DrvMsg( pScreen->myNum, X_INFO,
772 		    "[drm] Status handle = 0x%08x\n",
773		    (unsigned int) pMGADRIServer->status.handle );
774    }
775
776    return TRUE;
777}
778
779static Bool MGADRIKernelInit( ScreenPtr pScreen )
780{
781   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
782   MGAPtr pMga = MGAPTR(pScrn);
783   MGADRIServerPrivatePtr pMGADRIServer = pMga->DRIServerInfo;
784   drm_mga_init_t init;
785   int ret;
786
787
788   if (!pMga->chip_attribs->dri_capable) {
789       return FALSE;
790   }
791
792   memset( &init, 0, sizeof(drm_mga_init_t) );
793
794   init.func = MGA_INIT_DMA;
795   init.sarea_priv_offset = sizeof(XF86DRISAREARec);
796   init.chipset = pMga->chip_attribs->dri_chipset;
797   init.sgram = !pMga->HasSDRAM;
798
799   init.maccess = pMga->MAccess;
800
801   init.fb_cpp		= pScrn->bitsPerPixel / 8;
802   init.front_offset	= pMGADRIServer->frontOffset;
803   init.front_pitch	= pMGADRIServer->frontPitch / init.fb_cpp;
804   init.back_offset	= pMGADRIServer->backOffset;
805   init.back_pitch	= pMGADRIServer->backPitch / init.fb_cpp;
806
807   init.depth_cpp	= pScrn->bitsPerPixel / 8;
808   init.depth_offset	= pMGADRIServer->depthOffset;
809   init.depth_pitch	= pMGADRIServer->depthPitch / init.depth_cpp;
810
811   init.texture_offset[0] = pMGADRIServer->textureOffset;
812   init.texture_size[0] = pMGADRIServer->textureSize;
813
814   init.fb_offset = pMGADRIServer->fb.handle;
815   init.mmio_offset = pMGADRIServer->registers.handle;
816   init.status_offset = pMGADRIServer->status.handle;
817
818   init.warp_offset = pMGADRIServer->warp.handle;
819   init.primary_offset = pMGADRIServer->primary.handle;
820   init.buffers_offset = pMGADRIServer->buffers.handle;
821
822   init.texture_offset[1] = pMGADRIServer->agpTextures.handle;
823   init.texture_size[1] = pMGADRIServer->agpTextures.size;
824
825   ret = drmCommandWrite( pMga->drmFD, DRM_MGA_INIT, &init, sizeof(drm_mga_init_t));
826   if ( ret < 0 ) {
827      xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
828		  "[drm] Failed to initialize DMA! (%d)\n", ret );
829      return FALSE;
830   }
831
832
833   return TRUE;
834}
835
836/* FIXME: This function uses the DRM to get the IRQ, but the pci_device
837 * FIXME: structure (PciInfo) already has that information.
838 */
839static void MGADRIIrqInit(MGAPtr pMga, ScreenPtr pScreen)
840{
841   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
842
843   if (!pMga->irq) {
844      pMga->irq = drmGetInterruptFromBusID(pMga->drmFD,
845#ifdef XSERVER_LIBPCIACCESS
846					   ((pMga->PciInfo->domain << 8) |
847					    pMga->PciInfo->bus),
848					   pMga->PciInfo->dev,
849					   pMga->PciInfo->func
850#else
851	 ((pciConfigPtr)pMga->PciInfo->thisCard)->busnum,
852	 ((pciConfigPtr)pMga->PciInfo->thisCard)->devnum,
853	 ((pciConfigPtr)pMga->PciInfo->thisCard)->funcnum
854#endif
855					   );
856
857      if((drmCtlInstHandler(pMga->drmFD, pMga->irq)) != 0) {
858	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
859		    "[drm] failure adding irq handler, "
860		    "there is a device already using that irq\n"
861		    "[drm] falling back to irq-free operation\n");
862	 pMga->irq = 0;
863      } else {
864          pMga->reg_ien = INREG( MGAREG_IEN );
865      }
866   }
867
868   if (pMga->irq)
869      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
870		 "[drm] dma control initialized, using IRQ %d\n",
871		 pMga->irq);
872}
873
874static Bool MGADRIBuffersInit( ScreenPtr pScreen )
875{
876   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
877   MGAPtr pMga = MGAPTR(pScrn);
878   MGADRIServerPrivatePtr pMGADRIServer = pMga->DRIServerInfo;
879
880
881   pMGADRIServer->drmBuffers = drmMapBufs( pMga->drmFD );
882   if ( !pMGADRIServer->drmBuffers ) {
883	xf86DrvMsg( pScreen->myNum, X_ERROR,
884		    "[drm] Failed to map DMA buffers list\n" );
885	return FALSE;
886    }
887    xf86DrvMsg( pScreen->myNum, X_INFO,
888		"[drm] Mapped %d DMA buffers\n",
889		pMGADRIServer->drmBuffers->count );
890
891    return TRUE;
892}
893
894#ifdef USE_XAA
895static void MGADRIInitBuffersXAA(WindowPtr pWin, RegionPtr prgn,
896                                 CARD32 index)
897{
898    ScreenPtr pScreen = pWin->drawable.pScreen;
899    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
900    MGAPtr pMga = MGAPTR(pScrn);
901    BoxPtr pbox = REGION_RECTS(prgn);
902    int nbox  = REGION_NUM_RECTS(prgn);
903    XAAInfoRecPtr xaa = pMga->AccelInfoRec;
904
905    CHECK_DMA_QUIESCENT(MGAPTR(pScrn), pScrn);
906
907    xaa->SetupForSolidFill(pScrn, 0, GXcopy, -1);
908
909    while (nbox--) {
910        MGASelectBuffer(pScrn, MGA_BACK);
911        xaa->SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1,
912                                     pbox->x2-pbox->x1, pbox->y2-pbox->y1);
913        MGASelectBuffer(pScrn, MGA_DEPTH);
914        xaa->SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1,
915                                     pbox->x2-pbox->x1, pbox->y2-pbox->y1);
916        pbox++;
917    }
918
919    MGASelectBuffer(pScrn, MGA_FRONT);
920
921    pMga->AccelInfoRec->NeedToSync = TRUE;
922}
923#endif
924
925static void MGADRIInitBuffersEXA(WindowPtr pWin, RegionPtr prgn,
926                                 CARD32 index)
927{
928    /* FIXME */
929}
930
931#ifdef USE_XAA
932/*
933  This routine is a modified form of XAADoBitBlt with the calls to
934  ScreenToScreenBitBlt built in. My routine has the prgnSrc as source
935  instead of destination. My origin is upside down so the ydir cases
936  are reversed.
937*/
938static void MGADRIMoveBuffersXAA(WindowPtr pParent, DDXPointRec ptOldOrg,
939                                 RegionPtr prgnSrc, CARD32 index)
940{
941    ScreenPtr pScreen = pParent->drawable.pScreen;
942    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
943    MGAPtr pMga = MGAPTR(pScrn);
944    int nbox;
945    BoxPtr pbox, pboxTmp, pboxNext, pboxBase, pboxNew1, pboxNew2;
946    DDXPointPtr pptTmp, pptNew1, pptNew2;
947    int xdir, ydir;
948    int dx, dy;
949    DDXPointPtr pptSrc;
950    int screenwidth = pScrn->virtualX;
951    int screenheight = pScrn->virtualY;
952    XAAInfoRecPtr xaa = pMga->AccelInfoRec;
953
954    CHECK_DMA_QUIESCENT(pMga, pScrn);
955
956    pbox = REGION_RECTS(prgnSrc);
957    nbox = REGION_NUM_RECTS(prgnSrc);
958    pboxNew1 = 0;
959    pptNew1 = 0;
960    pboxNew2 = 0;
961    pboxNew2 = 0;
962    pptSrc = &ptOldOrg;
963
964    dx = pParent->drawable.x - ptOldOrg.x;
965    dy = pParent->drawable.y - ptOldOrg.y;
966
967    /* If the copy will overlap in Y, reverse the order */
968    if (dy>0) {
969        ydir = -1;
970
971        if (nbox>1) {
972	    /* Keep ordering in each band, reverse order of bands */
973	    pboxNew1 = (BoxPtr)malloc(sizeof(BoxRec)*nbox);
974	    if (!pboxNew1) return;
975	    pptNew1 = (DDXPointPtr)malloc(sizeof(DDXPointRec)*nbox);
976	    if (!pptNew1) {
977	        free(pboxNew1);
978	        return;
979	    }
980	    pboxBase = pboxNext = pbox+nbox-1;
981	    while (pboxBase >= pbox) {
982	        while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1))
983		  pboxNext--;
984	        pboxTmp = pboxNext+1;
985	        pptTmp = pptSrc + (pboxTmp - pbox);
986	        while (pboxTmp <= pboxBase) {
987		    *pboxNew1++ = *pboxTmp++;
988		    *pptNew1++ = *pptTmp++;
989		}
990	        pboxBase = pboxNext;
991	    }
992	    pboxNew1 -= nbox;
993	    pbox = pboxNew1;
994	    pptNew1 -= nbox;
995	    pptSrc = pptNew1;
996	}
997    } else {
998        /* No changes required */
999        ydir = 1;
1000    }
1001
1002    /* If the regions will overlap in X, reverse the order */
1003    if (dx>0) {
1004        xdir = -1;
1005
1006        if (nbox > 1) {
1007	    /*reverse orderof rects in each band */
1008	    pboxNew2 = (BoxPtr)malloc(sizeof(BoxRec)*nbox);
1009	    pptNew2 = (DDXPointPtr)malloc(sizeof(DDXPointRec)*nbox);
1010	    if (!pboxNew2 || !pptNew2) {
1011	        free(pptNew2);
1012	        free(pboxNew2);
1013	        if (pboxNew1) {
1014		    free(pptNew1);
1015		    free(pboxNew1);
1016		}
1017	       return;
1018	    }
1019	    pboxBase = pboxNext = pbox;
1020	    while (pboxBase < pbox+nbox) {
1021	        while ((pboxNext < pbox+nbox) &&
1022		       (pboxNext->y1 == pboxBase->y1))
1023		  pboxNext++;
1024	        pboxTmp = pboxNext;
1025	        pptTmp = pptSrc + (pboxTmp - pbox);
1026	        while (pboxTmp != pboxBase) {
1027		    *pboxNew2++ = *--pboxTmp;
1028		    *pptNew2++ = *--pptTmp;
1029		}
1030	        pboxBase = pboxNext;
1031	    }
1032	    pboxNew2 -= nbox;
1033	    pbox = pboxNew2;
1034	    pptNew2 -= nbox;
1035	    pptSrc = pptNew2;
1036	}
1037    } else {
1038        /* No changes are needed */
1039        xdir = 1;
1040    }
1041
1042    xaa->SetupForScreenToScreenCopy(pScrn, xdir, ydir, GXcopy, -1, -1);
1043    for ( ; nbox-- ; pbox++) {
1044	 int x1 = pbox->x1;
1045	 int y1 = pbox->y1;
1046	 int destx = x1 + dx;
1047	 int desty = y1 + dy;
1048	 int w = pbox->x2 - x1 + 1;
1049	 int h = pbox->y2 - y1 + 1;
1050
1051	 if ( destx < 0 ) x1 -= destx, w += destx, destx = 0;
1052	 if ( desty < 0 ) y1 -= desty, h += desty, desty = 0;
1053	 if ( destx + w > screenwidth ) w = screenwidth - destx;
1054	 if ( desty + h > screenheight ) h = screenheight - desty;
1055	 if ( w <= 0 ) continue;
1056	 if ( h <= 0 ) continue;
1057
1058	 MGASelectBuffer(pScrn, MGA_BACK);
1059	 xaa->SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h);
1060	 MGASelectBuffer(pScrn, MGA_DEPTH);
1061	 xaa->SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h);
1062    }
1063    MGASelectBuffer(pScrn, MGA_FRONT);
1064
1065    if (pboxNew2) {
1066        free(pptNew2);
1067        free(pboxNew2);
1068    }
1069    if (pboxNew1) {
1070        free(pptNew1);
1071        free(pboxNew1);
1072    }
1073
1074    pMga->AccelInfoRec->NeedToSync = TRUE;
1075
1076}
1077#endif
1078
1079static void MGADRIMoveBuffersEXA(WindowPtr pParent, DDXPointRec ptOldOrg,
1080                                 RegionPtr prgnSrc, CARD32 index)
1081{
1082    /* FIXME */
1083}
1084
1085Bool MGADRIScreenInit( ScreenPtr pScreen )
1086{
1087   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1088   MGAPtr pMga = MGAPTR(pScrn);
1089   DRIInfoPtr pDRIInfo;
1090   MGADRIPtr pMGADRI;
1091   MGADRIServerPrivatePtr pMGADRIServer;
1092
1093   if (!pMga->chip_attribs->dri_capable) {
1094       xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[drm] Direct rendering only supported with G200/G400/G450/G550.\n");
1095       return FALSE;
1096   }
1097
1098   /* Check that the GLX, DRI, and DRM modules have been loaded by testing
1099    * for canonical symbols in each module.
1100    */
1101   if ( !xf86LoaderCheckSymbol( "GlxSetVisualConfigs" ) )	return FALSE;
1102   if ( !xf86LoaderCheckSymbol( "drmAvailable" ) )		return FALSE;
1103   if ( !xf86LoaderCheckSymbol( "DRIQueryVersion" ) ) {
1104      xf86DrvMsg( pScreen->myNum, X_ERROR,
1105		  "[dri] MGADRIScreenInit failed (libdri.a too old)\n" );
1106      return FALSE;
1107   }
1108
1109   /* Check the DRI version */
1110   {
1111      int major, minor, patch;
1112      DRIQueryVersion( &major, &minor, &patch );
1113      if ( major != DRIINFO_MAJOR_VERSION || minor < DRIINFO_MINOR_VERSION ) {
1114         xf86DrvMsg( pScreen->myNum, X_ERROR,
1115		     "[dri] MGADRIScreenInit failed because of a version mismatch.\n"
1116		     "[dri] libdri version = %d.%d.%d but version %d.%d.x is needed.\n"
1117		     "[dri] Disabling the DRI.\n",
1118		     major, minor, patch,
1119                     DRIINFO_MAJOR_VERSION, DRIINFO_MINOR_VERSION );
1120         return FALSE;
1121      }
1122   }
1123
1124   xf86DrvMsg( pScreen->myNum, X_INFO,
1125	       "[drm] bpp: %d depth: %d\n",
1126	       pScrn->bitsPerPixel, pScrn->depth );
1127
1128   if ( (pScrn->bitsPerPixel / 8) != 2 &&
1129	(pScrn->bitsPerPixel / 8) != 4 ) {
1130      xf86DrvMsg( pScreen->myNum, X_ERROR,
1131		  "[dri] Direct rendering only supported in 16 and 32 bpp modes\n" );
1132      return FALSE;
1133   }
1134
1135   pDRIInfo = DRICreateInfoRec();
1136   if ( !pDRIInfo ) {
1137      xf86DrvMsg( pScreen->myNum, X_ERROR,
1138		  "[dri] DRICreateInfoRec() failed\n" );
1139      return FALSE;
1140   }
1141   pMga->pDRIInfo = pDRIInfo;
1142
1143   pDRIInfo->drmDriverName = MGAKernelDriverName;
1144   pDRIInfo->clientDriverName = MGAClientDriverName;
1145   if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) {
1146      pDRIInfo->busIdString = DRICreatePCIBusID(pMga->PciInfo);
1147   } else {
1148      pDRIInfo->busIdString = malloc(64);
1149      sprintf( pDRIInfo->busIdString, "PCI:%d:%d:%d",
1150#ifdef XSERVER_LIBPCIACCESS
1151	       ((pMga->PciInfo->domain << 8) | pMga->PciInfo->bus),
1152	       pMga->PciInfo->dev, pMga->PciInfo->func
1153#else
1154	       ((pciConfigPtr)pMga->PciInfo->thisCard)->busnum,
1155	       ((pciConfigPtr)pMga->PciInfo->thisCard)->devnum,
1156	       ((pciConfigPtr)pMga->PciInfo->thisCard)->funcnum
1157#endif
1158	       );
1159   }
1160   pDRIInfo->ddxDriverMajorVersion = PACKAGE_VERSION_MAJOR;
1161   pDRIInfo->ddxDriverMinorVersion = PACKAGE_VERSION_MINOR;
1162   pDRIInfo->ddxDriverPatchVersion = PACKAGE_VERSION_PATCHLEVEL;
1163   pDRIInfo->frameBufferPhysicalAddress = (void *) pMga->FbAddress;
1164   pDRIInfo->frameBufferSize = pMga->FbMapSize;
1165   pDRIInfo->frameBufferStride = pScrn->displayWidth*(pScrn->bitsPerPixel/8);
1166   pDRIInfo->ddxDrawableTableEntry = MGA_MAX_DRAWABLES;
1167
1168   pDRIInfo->wrap.ValidateTree = NULL;
1169   pDRIInfo->wrap.PostValidateTree = NULL;
1170
1171   pDRIInfo->createDummyCtx = TRUE;
1172   pDRIInfo->createDummyCtxPriv = FALSE;
1173
1174   if ( SAREA_MAX_DRAWABLES < MGA_MAX_DRAWABLES ) {
1175      pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES;
1176   } else {
1177      pDRIInfo->maxDrawableTableEntry = MGA_MAX_DRAWABLES;
1178   }
1179
1180   /* For now the mapping works by using a fixed size defined
1181    * in the SAREA header.
1182    */
1183   if ( sizeof(XF86DRISAREARec) + sizeof(MGASAREAPrivRec) > SAREA_MAX ) {
1184      xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
1185		  "[drm] Data does not fit in SAREA\n" );
1186      return FALSE;
1187   }
1188
1189   xf86DrvMsg( pScrn->scrnIndex, X_INFO,
1190	       "[drm] Sarea %d+%d: %d\n",
1191	       (int)sizeof(XF86DRISAREARec), (int)sizeof(MGASAREAPrivRec),
1192	       (int)sizeof(XF86DRISAREARec) + (int)sizeof(MGASAREAPrivRec) );
1193
1194   pDRIInfo->SAREASize = SAREA_MAX;
1195
1196   pMGADRI = (MGADRIPtr)calloc( sizeof(MGADRIRec), 1 );
1197   if ( !pMGADRI ) {
1198      DRIDestroyInfoRec( pMga->pDRIInfo );
1199      pMga->pDRIInfo = 0;
1200      xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
1201		  "[drm] Failed to allocate memory for private record\n" );
1202      return FALSE;
1203   }
1204
1205   pMGADRIServer = (MGADRIServerPrivatePtr)
1206      calloc( sizeof(MGADRIServerPrivateRec), 1 );
1207   if ( !pMGADRIServer ) {
1208      free( pMGADRI );
1209      DRIDestroyInfoRec( pMga->pDRIInfo );
1210      pMga->pDRIInfo = 0;
1211      xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
1212		  "[drm] Failed to allocate memory for private record\n" );
1213      return FALSE;
1214   }
1215   pMga->DRIServerInfo = pMGADRIServer;
1216
1217   pDRIInfo->devPrivate = pMGADRI;
1218   pDRIInfo->devPrivateSize = sizeof(MGADRIRec);
1219   pDRIInfo->contextSize = sizeof(MGADRIContextRec);
1220
1221   pDRIInfo->CreateContext = MGACreateContext;
1222   pDRIInfo->DestroyContext = MGADestroyContext;
1223   if ( xf86IsEntityShared( pScrn->entityList[0] )
1224		&& pMga->DualHeadEnabled) {
1225      pDRIInfo->SwapContext = MGADRISwapContextShared;
1226   } else {
1227      pDRIInfo->SwapContext = MGADRISwapContext;
1228   }
1229
1230   pDRIInfo->InitBuffers = MGADRIInitBuffersEXA;
1231   pDRIInfo->MoveBuffers = MGADRIMoveBuffersEXA;
1232#ifdef USE_EXA
1233    if (pMga->Exa) {
1234        pDRIInfo->InitBuffers = MGADRIInitBuffersEXA;
1235        pDRIInfo->MoveBuffers = MGADRIMoveBuffersEXA;
1236    } else {
1237#endif
1238#ifdef USE_XAA
1239        pDRIInfo->InitBuffers = MGADRIInitBuffersXAA;
1240        pDRIInfo->MoveBuffers = MGADRIMoveBuffersXAA;
1241#endif
1242#ifdef USE_EXA
1243    }
1244#endif
1245
1246   pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
1247
1248   if ( !DRIScreenInit( pScreen, pDRIInfo, &pMga->drmFD ) ) {
1249      free( pMGADRIServer );
1250      pMga->DRIServerInfo = 0;
1251      free( pDRIInfo->devPrivate );
1252      pDRIInfo->devPrivate = 0;
1253      DRIDestroyInfoRec( pMga->pDRIInfo );
1254      pMga->pDRIInfo = 0;
1255      xf86DrvMsg( pScreen->myNum, X_ERROR,
1256		  "[drm] DRIScreenInit failed.  Disabling DRI.\n" );
1257      return FALSE;
1258   }
1259
1260   /* Check the DRM versioning */
1261   {
1262      drmVersionPtr version;
1263
1264      /* Check the DRM lib version.
1265	 drmGetLibVersion was not supported in version 1.0, so check for
1266	 symbol first to avoid possible crash or hang.
1267       */
1268      if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
1269         version = drmGetLibVersion(pMga->drmFD);
1270      }
1271      else {
1272	 /* drmlib version 1.0.0 didn't have the drmGetLibVersion
1273	    entry point.  Fake it by allocating a version record
1274	    via drmGetVersion and changing it to version 1.0.0
1275	  */
1276	 version = drmGetVersion(pMga->drmFD);
1277	 version->version_major      = 1;
1278	 version->version_minor      = 0;
1279	 version->version_patchlevel = 0;
1280      }
1281
1282      if (version) {
1283	 if (version->version_major != 1 ||
1284	     version->version_minor < 1) {
1285	     /* incompatible drm library version */
1286	    xf86DrvMsg(pScreen->myNum, X_ERROR,
1287		       "[dri] MGADRIScreenInit failed because of a version mismatch.\n"
1288		       "[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n"
1289		       "[dri] Disabling DRI.\n",
1290		       version->version_major,
1291		       version->version_minor,
1292		       version->version_patchlevel);
1293	    drmFreeVersion(version);
1294	    MGADRICloseScreen( pScreen );		/* FIXME: ??? */
1295	    return FALSE;
1296	 }
1297	 drmFreeVersion(version);
1298      }
1299
1300      /* Check the MGA DRM version */
1301      version = drmGetVersion(pMga->drmFD);
1302      if ( version ) {
1303         if ( version->version_major != 3 ||
1304	      version->version_minor < 0 ) {
1305            /* incompatible drm version */
1306            xf86DrvMsg( pScreen->myNum, X_ERROR,
1307			"[dri] MGADRIScreenInit failed because of a version mismatch.\n"
1308			"[dri] mga.o kernel module version is %d.%d.%d but version 3.0.x is needed.\n"
1309			"[dri] Disabling DRI.\n",
1310			version->version_major,
1311			version->version_minor,
1312			version->version_patchlevel );
1313            drmFreeVersion( version );
1314	    MGADRICloseScreen( pScreen );		/* FIXME: ??? */
1315            return FALSE;
1316         }
1317	 pMGADRIServer->drm_version_major = version->version_major;
1318	 pMGADRIServer->drm_version_minor = version->version_minor;
1319
1320         drmFreeVersion( version );
1321      }
1322   }
1323
1324   if ( (pMga->bios.host_interface == MGA_HOST_PCI) &&
1325	((pMGADRIServer->drm_version_minor < 2) || pMga->useOldDmaInit) ) {
1326       /* PCI cards are supported if the DRM version is at least 3.2 and the
1327	* user has not explicitly disabled the new DMA init path (i.e., to
1328	* support old version of the client-side driver that don't use the
1329	* new features of the 3.2 DRM).
1330	*/
1331       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1332		  "[drm] Direct rendering on PCI cards requires DRM version 3.2 or higher\n");
1333       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1334		  "[drm] and a recent client-side driver.  Also make sure that 'OldDmaInit'\n");
1335       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1336		  "[drm] is not selected in xorg.conf.'\n");
1337       return FALSE;
1338   }
1339
1340
1341   if ( !MGADRIBootstrapDMA( pScreen ) ) {
1342      DRICloseScreen( pScreen );
1343      return FALSE;
1344   }
1345
1346   {
1347       void *scratch_ptr;
1348       int scratch_int;
1349
1350       DRIGetDeviceInfo(pScreen, &pMGADRIServer->fb.handle,
1351			&scratch_int, &scratch_int,
1352			&scratch_int, &scratch_int,
1353			&scratch_ptr);
1354   }
1355
1356   if ( !MGAInitVisualConfigs( pScreen ) ) {
1357      DRICloseScreen( pScreen );
1358      return FALSE;
1359   }
1360   xf86DrvMsg( pScrn->scrnIndex, X_INFO, "[dri] visual configs initialized\n" );
1361
1362   return TRUE;
1363}
1364
1365
1366Bool MGADRIFinishScreenInit( ScreenPtr pScreen )
1367{
1368   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1369   MGAPtr pMga = MGAPTR(pScrn);
1370   MGADRIServerPrivatePtr pMGADRIServer = pMga->DRIServerInfo;
1371   MGADRIPtr pMGADRI;
1372   int i;
1373
1374   if ( !pMga->pDRIInfo )
1375      return FALSE;
1376
1377   pMGADRI = (MGADRIPtr)pMga->pDRIInfo->devPrivate;
1378
1379   pMga->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
1380
1381   /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit
1382    * because *DRIKernelInit requires that the hardware lock is held by
1383    * the X server, and the first time the hardware lock is grabbed is
1384    * in DRIFinishScreenInit.
1385    */
1386   if ( !DRIFinishScreenInit( pScreen ) ) {
1387      MGADRICloseScreen( pScreen );
1388      return FALSE;
1389   }
1390
1391   if ( !MGADRIKernelInit( pScreen ) ) {
1392      MGADRICloseScreen( pScreen );
1393      return FALSE;
1394   }
1395
1396   if ( !MGADRIBuffersInit( pScreen ) ) {
1397      MGADRICloseScreen( pScreen );
1398      return FALSE;
1399   }
1400
1401   MGADRIIrqInit(pMga, pScreen);
1402
1403   pMGADRI->chipset		= pMga->chip_attribs->dri_chipset;
1404   pMGADRI->width		= pScrn->virtualX;
1405   pMGADRI->height		= pScrn->virtualY;
1406   pMGADRI->cpp			= pScrn->bitsPerPixel / 8;
1407
1408   pMGADRI->agpMode		= pMga->agpMode;
1409
1410   pMGADRI->frontOffset		= pMGADRIServer->frontOffset;
1411   pMGADRI->frontPitch		= pMGADRIServer->frontPitch;
1412   pMGADRI->backOffset		= pMGADRIServer->backOffset;
1413   pMGADRI->backPitch		= pMGADRIServer->backPitch;
1414   pMGADRI->depthOffset		= pMGADRIServer->depthOffset;
1415   pMGADRI->depthPitch		= pMGADRIServer->depthPitch;
1416   pMGADRI->textureOffset	= pMGADRIServer->textureOffset;
1417   pMGADRI->textureSize		= pMGADRIServer->textureSize;
1418
1419   pMGADRI->agpTextureOffset = (unsigned int)pMGADRIServer->agpTextures.handle;
1420   pMGADRI->agpTextureSize = (unsigned int)pMGADRIServer->agpTextures.size;
1421
1422   pMGADRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
1423
1424
1425   /* Newer versions of the client-side driver do not need these if the
1426    * kernel version is high enough to support interrupt based waiting.
1427    */
1428
1429   pMGADRI->registers.handle	= pMGADRIServer->registers.handle;
1430   pMGADRI->registers.size	= pMGADRIServer->registers.size;
1431   pMGADRI->primary.handle	= pMGADRIServer->primary.handle;
1432   pMGADRI->primary.size	= pMGADRIServer->primary.size;
1433
1434
1435   /* These are no longer used by the client-side DRI driver.  They should
1436    * be removed in the next release (i.e., 6.9 / 7.0).
1437    */
1438
1439   pMGADRI->status.handle	= pMGADRIServer->status.handle;
1440   pMGADRI->status.size		= pMGADRIServer->status.size;
1441   pMGADRI->buffers.handle	= pMGADRIServer->buffers.handle;
1442   pMGADRI->buffers.size	= pMGADRIServer->buffers.size;
1443
1444   i = mylog2( pMGADRI->textureSize / MGA_NR_TEX_REGIONS );
1445   if ( i < MGA_LOG_MIN_TEX_REGION_SIZE )
1446      i = MGA_LOG_MIN_TEX_REGION_SIZE;
1447
1448   pMGADRI->logTextureGranularity = i;
1449   pMGADRI->textureSize = (pMGADRI->textureSize >> i) << i; /* truncate */
1450
1451   i = mylog2( pMGADRIServer->agpTextures.size / MGA_NR_TEX_REGIONS );
1452   if ( i < MGA_LOG_MIN_TEX_REGION_SIZE )
1453      i = MGA_LOG_MIN_TEX_REGION_SIZE;
1454
1455   pMGADRI->logAgpTextureGranularity = i;
1456
1457   return TRUE;
1458}
1459
1460
1461void MGADRICloseScreen( ScreenPtr pScreen )
1462{
1463   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1464   MGAPtr pMga = MGAPTR(pScrn);
1465   MGADRIServerPrivatePtr pMGADRIServer = pMga->DRIServerInfo;
1466   drm_mga_init_t init;
1467
1468   if ( pMGADRIServer->drmBuffers ) {
1469      drmUnmapBufs( pMGADRIServer->drmBuffers );
1470      pMGADRIServer->drmBuffers = NULL;
1471   }
1472
1473   if (pMga->irq) {
1474      drmCtlUninstHandler(pMga->drmFD);
1475      pMga->irq = 0;
1476      pMga->reg_ien = 0;
1477   }
1478
1479   /* Cleanup DMA */
1480   memset( &init, 0, sizeof(drm_mga_init_t) );
1481   init.func = MGA_CLEANUP_DMA;
1482   drmCommandWrite( pMga->drmFD, DRM_MGA_INIT, &init, sizeof(drm_mga_init_t) );
1483
1484   if ( pMGADRIServer->agp.handle != DRM_AGP_NO_HANDLE ) {
1485      drmAgpUnbind( pMga->drmFD, pMGADRIServer->agp.handle );
1486      drmAgpFree( pMga->drmFD, pMGADRIServer->agp.handle );
1487      pMGADRIServer->agp.handle = DRM_AGP_NO_HANDLE;
1488      drmAgpRelease( pMga->drmFD );
1489   }
1490
1491   DRICloseScreen( pScreen );
1492
1493   if ( pMga->pDRIInfo ) {
1494      free(pMga->pDRIInfo->devPrivate);
1495      pMga->pDRIInfo->devPrivate = 0;
1496      DRIDestroyInfoRec( pMga->pDRIInfo );
1497      pMga->pDRIInfo = 0;
1498   }
1499   free(pMga->DRIServerInfo);
1500   pMga->DRIServerInfo = 0;
1501   free(pMga->pVisualConfigs);
1502   free(pMga->pVisualConfigsPriv);
1503}
1504