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