1 /*
2  * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
3  *                      Precision Insight, Inc., Cedar Park, Texas, and
4  *                      VA Linux Systems Inc., Fremont, California.
5  *
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining
9  * a copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation on the rights to use, copy, modify, merge,
12  * publish, distribute, sublicense, and/or sell copies of the Software,
13  * and to permit persons to whom the Software is furnished to do so,
14  * subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the
17  * next paragraph) shall be included in all copies or substantial
18  * portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
24  * SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27  * OTHER DEALINGS IN THE SOFTWARE.
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 
34 #include <string.h>
35 #include <stdio.h>
36 
37 /*
38  * Authors:
39  *   Kevin E. Martin <martin@valinux.com>
40  *   Rickard E. Faith <faith@valinux.com>
41  *   Daryll Strauss <daryll@valinux.com>
42  *   Gareth Hughes <gareth@valinux.com>
43  *
44  */
45 
46 				/* Driver data structures */
47 #include "r128.h"
48 #include "r128_dri.h"
49 #include "r128_common.h"
50 #include "r128_reg.h"
51 #include "r128_sarea.h"
52 #include "r128_version.h"
53 
54 				/* X and server generic header files */
55 #include "xf86.h"
56 #include "windowstr.h"
57 
58 #include "shadowfb.h"
59 				/* DRI/DRM definitions */
60 #define _XF86DRI_SERVER_
61 #include "sarea.h"
62 
63 static size_t r128_drm_page_size;
64 
65 static void R128DRITransitionTo2d(ScreenPtr pScreen);
66 static void R128DRITransitionTo3d(ScreenPtr pScreen);
67 static void R128DRITransitionMultiToSingle3d(ScreenPtr pScreen);
68 static void R128DRITransitionSingleToMulti3d(ScreenPtr pScreen);
69 
70 static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
71 
72 /* Create the Rage 128-specific context information */
R128CreateContext(ScreenPtr pScreen,VisualPtr visual,drm_context_t hwContext,void * pVisualConfigPriv,DRIContextType contextStore)73 static Bool R128CreateContext(ScreenPtr pScreen, VisualPtr visual,
74 			      drm_context_t hwContext, void *pVisualConfigPriv,
75 			      DRIContextType contextStore)
76 {
77     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
78     R128InfoPtr info = R128PTR(pScrn);
79 
80     info->drmCtx = hwContext;
81     return TRUE;
82 }
83 
84 /* Destroy the Rage 128-specific context information */
R128DestroyContext(ScreenPtr pScreen,drm_context_t hwContext,DRIContextType contextStore)85 static void R128DestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
86 			       DRIContextType contextStore)
87 {
88     /* Nothing yet */
89 }
90 
91 /* Called when the X server is woken up to allow the last client's
92    context to be saved and the X server's context to be loaded.  This is
93    not necessary for the Rage 128 since the client detects when it's
94    context is not currently loaded and then load's it itself.  Since the
95    registers to start and stop the CCE are privileged, only the X server
96    can start/stop the engine. */
R128EnterServer(ScreenPtr pScreen)97 static void R128EnterServer(ScreenPtr pScreen)
98 {
99     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
100     R128InfoPtr info = R128PTR(pScrn);
101 
102 #ifdef HAVE_XAA_H
103     if (info->accel) info->accel->NeedToSync = TRUE;
104 #endif
105 #ifdef USE_EXA
106     if (info->ExaDriver) exaMarkSync(pScreen);
107     /* EXA and DRI are fighting over control of the texture hardware.
108      * That means we need to setup compositing when the server wakes
109      * up if a 3D app is running.
110      */
111     if (info->have3DWindows) info->state_2d.composite_setup = FALSE;
112 #endif
113 }
114 
115 /* Called when the X server goes to sleep to allow the X server's
116    context to be saved and the last client's context to be loaded.  This
117    is not necessary for the Rage 128 since the client detects when it's
118    context is not currently loaded and then load's it itself.  Since the
119    registers to start and stop the CCE are privileged, only the X server
120    can start/stop the engine. */
R128LeaveServer(ScreenPtr pScreen)121 static void R128LeaveServer(ScreenPtr pScreen)
122 {
123     ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
124     R128InfoPtr   info      = R128PTR(pScrn);
125     unsigned char *R128MMIO = info->MMIO;
126 
127     if (!info->directRenderingEnabled) {
128 	/* Save all hardware scissors */
129 	info->sc_left     = INREG(R128_SC_LEFT);
130 	info->sc_right    = INREG(R128_SC_RIGHT);
131 	info->sc_top      = INREG(R128_SC_TOP);
132 	info->sc_bottom   = INREG(R128_SC_BOTTOM);
133 	info->aux_sc_cntl = INREG(R128_SC_BOTTOM);
134     } else if (info->CCEInUse) {
135 	R128CCEReleaseIndirect(pScrn);
136 
137 	info->CCEInUse = FALSE;
138     }
139 }
140 
141 /* Contexts can be swapped by the X server if necessary.  This callback
142    is currently only used to perform any functions necessary when
143    entering or leaving the X server, and in the future might not be
144    necessary. */
R128DRISwapContext(ScreenPtr pScreen,DRISyncType syncType,DRIContextType oldContextType,void * oldContext,DRIContextType newContextType,void * newContext)145 static void R128DRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
146 			       DRIContextType oldContextType, void *oldContext,
147 			       DRIContextType newContextType, void *newContext)
148 {
149     if ((syncType==DRI_3D_SYNC) && (oldContextType==DRI_2D_CONTEXT) &&
150 	(newContextType==DRI_2D_CONTEXT)) { /* Entering from Wakeup */
151 	R128EnterServer(pScreen);
152     }
153     if ((syncType==DRI_2D_SYNC) && (oldContextType==DRI_NO_CONTEXT) &&
154 	(newContextType==DRI_2D_CONTEXT)) { /* Exiting from Block Handler */
155 	R128LeaveServer(pScreen);
156     }
157 }
158 
159 /* Initialize the state of the back and depth buffers. */
R128DRIInitBuffers(WindowPtr pWin,RegionPtr prgn,CARD32 indx)160 static void R128DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 indx)
161 {
162     /* FIXME: This routine needs to have acceleration turned on */
163     ScreenPtr   pScreen = pWin->drawable.pScreen;
164     ScrnInfoPtr pScrn   = xf86ScreenToScrn(pScreen);
165     R128InfoPtr info    = R128PTR(pScrn);
166 #ifdef HAVE_XAA_H
167     BoxPtr      pbox, pboxSave;
168     int         nbox, nboxSave;
169     int         depth;
170 #endif
171 
172     /* FIXME: Use accel when CCE 2D code is written
173      * EA: What is this code kept for? Radeon doesn't have it and
174      * has a comment: "There's no need for the 2d driver to be clearing
175      * buffers for the 3d client.  It knows how to do that on its own."
176      */
177     if (info->directRenderingEnabled)
178 	return;
179 #ifdef HAVE_XAA_H
180     /* FIXME: This should be based on the __GLXvisualConfig info */
181     switch (pScrn->bitsPerPixel) {
182     case  8: depth = 0x000000ff; break;
183     case 16: depth = 0x0000ffff; break;
184     case 24: depth = 0x00ffffff; break;
185     case 32: depth = 0xffffffff; break;
186     default: depth = 0x00000000; break;
187     }
188 
189     /* FIXME: Copy XAAPaintWindow() and use REGION_TRANSLATE() */
190     /* FIXME: Only initialize the back and depth buffers for contexts
191        that request them */
192 
193     pboxSave = pbox = REGION_RECTS(prgn);
194     nboxSave = nbox = REGION_NUM_RECTS(prgn);
195 
196     (*info->accel->SetupForSolidFill)(pScrn, 0, GXcopy, (uint32_t)(-1));
197     for (; nbox; nbox--, pbox++) {
198 	(*info->accel->SubsequentSolidFillRect)(pScrn,
199 						pbox->x1 + info->fbX,
200 						pbox->y1 + info->fbY,
201 						pbox->x2 - pbox->x1,
202 						pbox->y2 - pbox->y1);
203 	(*info->accel->SubsequentSolidFillRect)(pScrn,
204 						pbox->x1 + info->backX,
205 						pbox->y1 + info->backY,
206 						pbox->x2 - pbox->x1,
207 						pbox->y2 - pbox->y1);
208     }
209 
210     pbox = pboxSave;
211     nbox = nboxSave;
212 
213     /* FIXME: this needs to consider depth tiling. */
214     (*info->accel->SetupForSolidFill)(pScrn, depth, GXcopy, (uint32_t)(-1));
215     for (; nbox; nbox--, pbox++)
216 	(*info->accel->SubsequentSolidFillRect)(pScrn,
217 						pbox->x1 + info->depthX,
218 						pbox->y1 + info->depthY,
219 						pbox->x2 - pbox->x1,
220 						pbox->y2 - pbox->y1);
221 
222     info->accel->NeedToSync = TRUE;
223 #endif
224 }
225 
226 /* Copy the back and depth buffers when the X server moves a window. */
R128DRIMoveBuffers(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc,CARD32 indx)227 static void R128DRIMoveBuffers(WindowPtr pWin, DDXPointRec ptOldOrg,
228 			       RegionPtr prgnSrc, CARD32 indx)
229 {
230     ScreenPtr   pScreen = pWin->drawable.pScreen;
231     ScrnInfoPtr pScrn   = xf86ScreenToScrn(pScreen);
232     R128InfoPtr info   = R128PTR(pScrn);
233 
234     /* FIXME: This routine needs to have acceleration turned on */
235     /* FIXME: Copy XAACopyWindow() and use REGION_TRANSLATE() */
236     /* FIXME: Only initialize the back and depth buffers for contexts
237        that request them */
238 
239     /* FIXME: Use accel when CCE 2D code is written */
240     if (info->directRenderingEnabled)
241 	return;
242 }
243 
244 /* Initialize the AGP state.  Request memory for use in AGP space, and
245    initialize the Rage 128 registers to point to that memory. */
R128DRIAgpInit(R128InfoPtr info,ScreenPtr pScreen)246 static Bool R128DRIAgpInit(R128InfoPtr info, ScreenPtr pScreen)
247 {
248     unsigned char *R128MMIO = info->MMIO;
249     unsigned long mode;
250     unsigned int  vendor, device;
251     int           ret;
252     unsigned long cntl, chunk;
253     int           s, l;
254     int           flags;
255     unsigned long agpBase;
256 
257     if (drmAgpAcquire(info->drmFD) < 0) {
258 	xf86DrvMsg(pScreen->myNum, X_WARNING, "[agp] AGP not available\n");
259 	return FALSE;
260     }
261 
262 				/* Modify the mode if the default mode is
263 				   not appropriate for this particular
264 				   combination of graphics card and AGP
265 				   chipset. */
266 
267     mode   = drmAgpGetMode(info->drmFD);        /* Default mode */
268     vendor = drmAgpVendorId(info->drmFD);
269     device = drmAgpDeviceId(info->drmFD);
270 
271     mode &= ~R128_AGP_MODE_MASK;
272     switch (info->agpMode) {
273     case 4:          mode |= R128_AGP_4X_MODE;
274     case 2:          mode |= R128_AGP_2X_MODE;
275     case 1: default: mode |= R128_AGP_1X_MODE;
276     }
277 
278     xf86DrvMsg(pScreen->myNum, X_INFO,
279 	       "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n",
280 	       mode, vendor, device,
281 	       PCI_DEV_VENDOR_ID(info->PciInfo),
282 	       PCI_DEV_DEVICE_ID(info->PciInfo));
283 
284     if (drmAgpEnable(info->drmFD, mode) < 0) {
285 	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n");
286 	drmAgpRelease(info->drmFD);
287 	return FALSE;
288     }
289 
290     info->agpOffset = 0;
291 
292     if ((ret = drmAgpAlloc(info->drmFD, info->agpSize*1024*1024, 0, NULL,
293 			   &info->agpMemHandle)) < 0) {
294 	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret);
295 	drmAgpRelease(info->drmFD);
296 	return FALSE;
297     }
298     xf86DrvMsg(pScreen->myNum, X_INFO,
299 	       "[agp] %d kB allocated with handle 0x%08lx\n",
300 	       info->agpSize*1024, info->agpMemHandle);
301 
302     if (drmAgpBind(info->drmFD, info->agpMemHandle, info->agpOffset) < 0) {
303 	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not bind\n");
304 	drmAgpFree(info->drmFD, info->agpMemHandle);
305 	drmAgpRelease(info->drmFD);
306 	return FALSE;
307     }
308 
309 				/* Initialize the CCE ring buffer data */
310     info->ringStart       = info->agpOffset;
311     info->ringMapSize     = info->ringSize*1024*1024 + r128_drm_page_size;
312     info->ringSizeLog2QW  = R128MinBits(info->ringSize*1024*1024/8) - 1;
313 
314     info->ringReadOffset  = info->ringStart + info->ringMapSize;
315     info->ringReadMapSize = r128_drm_page_size;
316 
317 				/* Reserve space for vertex/indirect buffers */
318     info->bufStart        = info->ringReadOffset + info->ringReadMapSize;
319     info->bufMapSize      = info->bufSize*1024*1024;
320 
321 				/* Reserve the rest for AGP textures */
322     info->agpTexStart     = info->bufStart + info->bufMapSize;
323     s = (info->agpSize*1024*1024 - info->agpTexStart);
324     l = R128MinBits((s-1) / R128_NR_TEX_REGIONS);
325     if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY;
326     info->agpTexMapSize   = (s >> l) << l;
327     info->log2AGPTexGran  = l;
328 
329     if (info->CCESecure) flags = DRM_READ_ONLY;
330     else                  flags = 0;
331 
332     if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize,
333 		  DRM_AGP, flags, &info->ringHandle) < 0) {
334 	xf86DrvMsg(pScreen->myNum, X_ERROR,
335 		   "[agp] Could not add ring mapping\n");
336 	return FALSE;
337     }
338     xf86DrvMsg(pScreen->myNum, X_INFO,
339 	       "[agp] ring handle = 0x%08lx\n", info->ringHandle);
340 
341     if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize,
342 	       &info->ring) < 0) {
343 	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not map ring\n");
344 	return FALSE;
345     }
346     xf86DrvMsg(pScreen->myNum, X_INFO,
347 	       "[agp] Ring mapped at 0x%08lx\n",
348 	       (unsigned long)info->ring);
349 
350     if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize,
351 		  DRM_AGP, flags, &info->ringReadPtrHandle) < 0) {
352 	xf86DrvMsg(pScreen->myNum, X_ERROR,
353 		   "[agp] Could not add ring read ptr mapping\n");
354 	return FALSE;
355     }
356     xf86DrvMsg(pScreen->myNum, X_INFO,
357  	       "[agp] ring read ptr handle = 0x%08lx\n",
358 	       info->ringReadPtrHandle);
359 
360     if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize,
361 	       &info->ringReadPtr) < 0) {
362 	xf86DrvMsg(pScreen->myNum, X_ERROR,
363 		   "[agp] Could not map ring read ptr\n");
364 	return FALSE;
365     }
366     xf86DrvMsg(pScreen->myNum, X_INFO,
367 	       "[agp] Ring read ptr mapped at 0x%08lx\n",
368 	       (unsigned long)info->ringReadPtr);
369 
370     if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize,
371 		  DRM_AGP, 0, &info->bufHandle) < 0) {
372 	xf86DrvMsg(pScreen->myNum, X_ERROR,
373 		   "[agp] Could not add vertex/indirect buffers mapping\n");
374 	return FALSE;
375     }
376     xf86DrvMsg(pScreen->myNum, X_INFO,
377 	       "[agp] vertex/indirect buffers handle = 0x%08lx\n",
378 	       info->bufHandle);
379 
380     if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize,
381 	       &info->buf) < 0) {
382 	xf86DrvMsg(pScreen->myNum, X_ERROR,
383 		   "[agp] Could not map vertex/indirect buffers\n");
384 	return FALSE;
385     }
386     xf86DrvMsg(pScreen->myNum, X_INFO,
387 	       "[agp] Vertex/indirect buffers mapped at 0x%08lx\n",
388 	       (unsigned long)info->buf);
389 
390     if (drmAddMap(info->drmFD, info->agpTexStart, info->agpTexMapSize,
391 		  DRM_AGP, 0, &info->agpTexHandle) < 0) {
392 	xf86DrvMsg(pScreen->myNum, X_ERROR,
393 		   "[agp] Could not add AGP texture map mapping\n");
394 	return FALSE;
395     }
396     xf86DrvMsg(pScreen->myNum, X_INFO,
397 	       "[agp] AGP texture map handle = 0x%08lx\n",
398 	       info->agpTexHandle);
399 
400     if (drmMap(info->drmFD, info->agpTexHandle, info->agpTexMapSize,
401 	       &info->agpTex) < 0) {
402 	xf86DrvMsg(pScreen->myNum, X_ERROR,
403 		   "[agp] Could not map AGP texture map\n");
404 	return FALSE;
405     }
406     xf86DrvMsg(pScreen->myNum, X_INFO,
407 	       "[agp] AGP Texture map mapped at 0x%08lx\n",
408 	       (unsigned long)info->agpTex);
409 
410 				/* Initialize Rage 128's AGP registers */
411     cntl  = INREG(R128_AGP_CNTL);
412     cntl &= ~R128_AGP_APER_SIZE_MASK;
413     switch (info->agpSize) {
414     case 256: cntl |= R128_AGP_APER_SIZE_256MB; break;
415     case 128: cntl |= R128_AGP_APER_SIZE_128MB; break;
416     case  64: cntl |= R128_AGP_APER_SIZE_64MB;  break;
417     case  32: cntl |= R128_AGP_APER_SIZE_32MB;  break;
418     case  16: cntl |= R128_AGP_APER_SIZE_16MB;  break;
419     case   8: cntl |= R128_AGP_APER_SIZE_8MB;   break;
420     case   4: cntl |= R128_AGP_APER_SIZE_4MB;   break;
421     default:
422 	xf86DrvMsg(pScreen->myNum, X_ERROR,
423 		   "[agp] Illegal aperture size %d kB\n",
424 		   info->agpSize*1024);
425 	return FALSE;
426     }
427     agpBase = drmAgpBase(info->drmFD);
428     OUTREG(R128_AGP_BASE, agpBase);
429     OUTREG(R128_AGP_CNTL, cntl);
430 
431 				/* Disable Rage 128's PCIGART registers */
432     chunk = INREG(R128_BM_CHUNK_0_VAL);
433     chunk &= ~(R128_BM_PTR_FORCE_TO_PCI |
434 	       R128_BM_PM4_RD_FORCE_TO_PCI |
435 	       R128_BM_GLOBAL_FORCE_TO_PCI);
436     OUTREG(R128_BM_CHUNK_0_VAL, chunk);
437 
438     OUTREG(R128_PCI_GART_PAGE, 1); /* Ensure AGP GART is used (for now) */
439 
440     return TRUE;
441 }
442 
R128DRIPciInit(R128InfoPtr info,ScreenPtr pScreen)443 static Bool R128DRIPciInit(R128InfoPtr info, ScreenPtr pScreen)
444 {
445     unsigned char *R128MMIO = info->MMIO;
446     uint32_t chunk;
447     int ret;
448     int flags;
449 
450     info->agpOffset = 0;
451 
452     ret = drmScatterGatherAlloc(info->drmFD, info->agpSize*1024*1024,
453 				&info->pciMemHandle);
454     if (ret < 0) {
455 	xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Out of memory (%d)\n", ret);
456 	return FALSE;
457     }
458     xf86DrvMsg(pScreen->myNum, X_INFO,
459 	       "[pci] %d kB allocated with handle 0x%08lx\n",
460 	       info->agpSize*1024, info->pciMemHandle);
461 
462 				/* Initialize the CCE ring buffer data */
463     info->ringStart       = info->agpOffset;
464     info->ringMapSize     = info->ringSize*1024*1024 + r128_drm_page_size;
465     info->ringSizeLog2QW  = R128MinBits(info->ringSize*1024*1024/8) - 1;
466 
467     info->ringReadOffset  = info->ringStart + info->ringMapSize;
468     info->ringReadMapSize = r128_drm_page_size;
469 
470 				/* Reserve space for vertex/indirect buffers */
471     info->bufStart        = info->ringReadOffset + info->ringReadMapSize;
472     info->bufMapSize      = info->bufSize*1024*1024;
473 
474     flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL;
475 
476     if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize,
477 		  DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) {
478 	xf86DrvMsg(pScreen->myNum, X_ERROR,
479 		   "[pci] Could not add ring mapping\n");
480 	return FALSE;
481     }
482     xf86DrvMsg(pScreen->myNum, X_INFO,
483 	       "[pci] ring handle = 0x%08lx\n", info->ringHandle);
484 
485     if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize,
486 	       &info->ring) < 0) {
487 	xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Could not map ring\n");
488 	return FALSE;
489     }
490     xf86DrvMsg(pScreen->myNum, X_INFO,
491 	       "[pci] Ring mapped at 0x%08lx\n",
492 	       (unsigned long)info->ring);
493     xf86DrvMsg(pScreen->myNum, X_INFO,
494 	       "[pci] Ring contents 0x%08lx\n",
495 	       *(unsigned long *)(pointer)info->ring);
496 
497     if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize,
498 		  DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) {
499 	xf86DrvMsg(pScreen->myNum, X_ERROR,
500 		   "[pci] Could not add ring read ptr mapping\n");
501 	return FALSE;
502     }
503     xf86DrvMsg(pScreen->myNum, X_INFO,
504 	       "[pci] ring read ptr handle = 0x%08lx\n",
505 	       info->ringReadPtrHandle);
506 
507     if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize,
508 	       &info->ringReadPtr) < 0) {
509 	xf86DrvMsg(pScreen->myNum, X_ERROR,
510 		   "[pci] Could not map ring read ptr\n");
511 	return FALSE;
512     }
513     xf86DrvMsg(pScreen->myNum, X_INFO,
514 	       "[pci] Ring read ptr mapped at 0x%08lx\n",
515 	       (unsigned long)info->ringReadPtr);
516     xf86DrvMsg(pScreen->myNum, X_INFO,
517 	       "[pci] Ring read ptr contents 0x%08lx\n",
518 	       *(unsigned long *)(pointer)info->ringReadPtr);
519 
520     if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize,
521 		  DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) {
522 	xf86DrvMsg(pScreen->myNum, X_ERROR,
523 		   "[pci] Could not add vertex/indirect buffers mapping\n");
524 	return FALSE;
525     }
526     xf86DrvMsg(pScreen->myNum, X_INFO,
527 	       "[pci] vertex/indirect buffers handle = 0x%08lx\n",
528 	       info->bufHandle);
529 
530     if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize,
531 	       &info->buf) < 0) {
532 	xf86DrvMsg(pScreen->myNum, X_ERROR,
533 		   "[pci] Could not map vertex/indirect buffers\n");
534 	return FALSE;
535     }
536     xf86DrvMsg(pScreen->myNum, X_INFO,
537 	       "[pci] Vertex/indirect buffers mapped at 0x%08lx\n",
538 	       (unsigned long)info->buf);
539     xf86DrvMsg(pScreen->myNum, X_INFO,
540 	       "[pci] Vertex/indirect buffers contents 0x%08lx\n",
541 	       *(unsigned long *)(pointer)info->buf);
542 
543     switch (info->Chipset) {
544     case PCI_CHIP_RAGE128LE:
545     case PCI_CHIP_RAGE128RE:
546     case PCI_CHIP_RAGE128RK:
547     case PCI_CHIP_RAGE128PD:
548     case PCI_CHIP_RAGE128PP:
549     case PCI_CHIP_RAGE128PR:
550 	/* This is a PCI card, do nothing */
551 	break;
552 
553     case PCI_CHIP_RAGE128LF:
554     case PCI_CHIP_RAGE128MF:
555     case PCI_CHIP_RAGE128ML:
556     case PCI_CHIP_RAGE128RF:
557     case PCI_CHIP_RAGE128RG:
558     case PCI_CHIP_RAGE128RL:
559     case PCI_CHIP_RAGE128SM:
560     case PCI_CHIP_RAGE128PF:
561     case PCI_CHIP_RAGE128TF:
562     case PCI_CHIP_RAGE128TL:
563     case PCI_CHIP_RAGE128TR:
564     /* FIXME: ATI documentation does not specify if the following chips are
565      * AGP or PCI, it just mentions their PCI IDs.  I'm assuming they're AGP
566      * until I get more correct information. <mharris@redhat.com>
567      */
568     case PCI_CHIP_RAGE128PA:
569     case PCI_CHIP_RAGE128PB:
570     case PCI_CHIP_RAGE128PC:
571     case PCI_CHIP_RAGE128PE:
572     case PCI_CHIP_RAGE128PG:
573     case PCI_CHIP_RAGE128PH:
574     case PCI_CHIP_RAGE128PI:
575     case PCI_CHIP_RAGE128PJ:
576     case PCI_CHIP_RAGE128PK:
577     case PCI_CHIP_RAGE128PL:
578     case PCI_CHIP_RAGE128PM:
579     case PCI_CHIP_RAGE128PN:
580     case PCI_CHIP_RAGE128PO:
581     case PCI_CHIP_RAGE128PQ:
582     case PCI_CHIP_RAGE128PS:
583     case PCI_CHIP_RAGE128PT:
584     case PCI_CHIP_RAGE128PU:
585     case PCI_CHIP_RAGE128PV:
586     case PCI_CHIP_RAGE128PW:
587     case PCI_CHIP_RAGE128PX:
588     case PCI_CHIP_RAGE128SE:
589     case PCI_CHIP_RAGE128SF:
590     case PCI_CHIP_RAGE128SG:
591     case PCI_CHIP_RAGE128SH:
592     case PCI_CHIP_RAGE128SK:
593     case PCI_CHIP_RAGE128SL:
594     case PCI_CHIP_RAGE128SN:
595     case PCI_CHIP_RAGE128TS:
596     case PCI_CHIP_RAGE128TT:
597     case PCI_CHIP_RAGE128TU:
598     default:
599 	/* This is really an AGP card, force PCI GART mode */
600         chunk = INREG(R128_BM_CHUNK_0_VAL);
601         chunk |= (R128_BM_PTR_FORCE_TO_PCI |
602 		  R128_BM_PM4_RD_FORCE_TO_PCI |
603 		  R128_BM_GLOBAL_FORCE_TO_PCI);
604         OUTREG(R128_BM_CHUNK_0_VAL, chunk);
605         OUTREG(R128_PCI_GART_PAGE, 0); /* Ensure PCI GART is used */
606         break;
607     }
608 
609     return TRUE;
610 }
611 
612 /* Add a map for the MMIO registers that will be accessed by any
613    DRI-based clients. */
R128DRIMapInit(R128InfoPtr info,ScreenPtr pScreen)614 static Bool R128DRIMapInit(R128InfoPtr info, ScreenPtr pScreen)
615 {
616     int flags;
617 
618     if (info->CCESecure) flags = DRM_READ_ONLY;
619     else                 flags = 0;
620 
621 				/* Map registers */
622     info->registerSize = R128_MMIOSIZE;
623     if (drmAddMap(info->drmFD, info->MMIOAddr, info->registerSize,
624 		  DRM_REGISTERS, flags, &info->registerHandle) < 0) {
625 	return FALSE;
626     }
627     xf86DrvMsg(pScreen->myNum, X_INFO,
628 	       "[drm] register handle = 0x%08lx\n", info->registerHandle);
629 
630     return TRUE;
631 }
632 
633 /* Initialize the kernel data structures. */
R128DRIKernelInit(R128InfoPtr info,ScreenPtr pScreen)634 static int R128DRIKernelInit(R128InfoPtr info, ScreenPtr pScreen)
635 {
636     drmR128Init drmInfo;
637 
638     memset( &drmInfo, 0, sizeof(drmR128Init) );
639 
640     drmInfo.func                = DRM_R128_INIT_CCE;
641     drmInfo.sarea_priv_offset   = sizeof(XF86DRISAREARec);
642     drmInfo.is_pci              = info->IsPCI;
643     drmInfo.cce_mode            = info->CCEMode;
644     drmInfo.cce_secure          = info->CCESecure;
645     drmInfo.ring_size           = info->ringSize*1024*1024;
646     drmInfo.usec_timeout        = info->CCEusecTimeout;
647 
648     drmInfo.fb_bpp              = info->CurrentLayout.pixel_code;
649     drmInfo.depth_bpp           = info->CurrentLayout.pixel_code;
650 
651     drmInfo.front_offset        = info->frontOffset;
652     drmInfo.front_pitch         = info->frontPitch;
653 
654     drmInfo.back_offset         = info->backOffset;
655     drmInfo.back_pitch          = info->backPitch;
656 
657     drmInfo.depth_offset        = info->depthOffset;
658     drmInfo.depth_pitch         = info->depthPitch;
659     drmInfo.span_offset         = info->spanOffset;
660 
661     drmInfo.fb_offset           = info->fbHandle;
662     drmInfo.mmio_offset         = info->registerHandle;
663     drmInfo.ring_offset         = info->ringHandle;
664     drmInfo.ring_rptr_offset    = info->ringReadPtrHandle;
665     drmInfo.buffers_offset      = info->bufHandle;
666     drmInfo.agp_textures_offset = info->agpTexHandle;
667 
668     if (drmCommandWrite(info->drmFD, DRM_R128_INIT,
669                         &drmInfo, sizeof(drmR128Init)) < 0)
670         return FALSE;
671 
672     return TRUE;
673 }
674 
675 /* Add a map for the vertex buffers that will be accessed by any
676    DRI-based clients. */
R128DRIBufInit(R128InfoPtr info,ScreenPtr pScreen)677 static Bool R128DRIBufInit(R128InfoPtr info, ScreenPtr pScreen)
678 {
679 				/* Initialize vertex buffers */
680     if (info->IsPCI) {
681 	info->bufNumBufs = drmAddBufs(info->drmFD,
682 				      info->bufMapSize / R128_BUFFER_SIZE,
683 				      R128_BUFFER_SIZE,
684 				      DRM_SG_BUFFER,
685 				      info->bufStart);
686     } else {
687 	info->bufNumBufs = drmAddBufs(info->drmFD,
688 				      info->bufMapSize / R128_BUFFER_SIZE,
689 				      R128_BUFFER_SIZE,
690 				      DRM_AGP_BUFFER,
691 				      info->bufStart);
692     }
693     if (info->bufNumBufs <= 0) {
694 	xf86DrvMsg(pScreen->myNum, X_ERROR,
695 		   "[drm] Could not create vertex/indirect buffers list\n");
696 	return FALSE;
697     }
698     xf86DrvMsg(pScreen->myNum, X_INFO,
699 	       "[drm] Added %d %d byte vertex/indirect buffers\n",
700 	       info->bufNumBufs, R128_BUFFER_SIZE);
701 
702     if (!(info->buffers = drmMapBufs(info->drmFD))) {
703 	xf86DrvMsg(pScreen->myNum, X_ERROR,
704 		   "[drm] Failed to map vertex/indirect buffers list\n");
705 	return FALSE;
706     }
707     xf86DrvMsg(pScreen->myNum, X_INFO,
708 	       "[drm] Mapped %d vertex/indirect buffers\n",
709 	       info->buffers->count);
710 
711     return TRUE;
712 }
713 
R128DRIIrqInit(R128InfoPtr info,ScreenPtr pScreen)714 static void R128DRIIrqInit(R128InfoPtr info, ScreenPtr pScreen)
715 {
716    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
717 
718    if (!info->irq) {
719       info->irq = drmGetInterruptFromBusID(
720 	 info->drmFD,
721 	 PCI_CFG_BUS(info->PciInfo),
722 	 PCI_CFG_DEV(info->PciInfo),
723 	 PCI_CFG_FUNC(info->PciInfo));
724 
725       if((drmCtlInstHandler(info->drmFD, info->irq)) != 0) {
726 	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
727 		    "[drm] failure adding irq handler, "
728 		    "there is a device already using that irq\n"
729 		    "[drm] falling back to irq-free operation\n");
730 	 info->irq = 0;
731       } else {
732           unsigned char *R128MMIO = info->MMIO;
733           info->gen_int_cntl = INREG( R128_GEN_INT_CNTL );
734       }
735    }
736 
737    if (info->irq)
738       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
739 		 "[drm] dma control initialized, using IRQ %d\n",
740 		 info->irq);
741 }
742 
743 /* Initialize the CCE state, and start the CCE (if used by the X server) */
R128DRICCEInit(ScrnInfoPtr pScrn)744 static void R128DRICCEInit(ScrnInfoPtr pScrn)
745 {
746     R128InfoPtr   info      = R128PTR(pScrn);
747 
748 				/* Turn on bus mastering */
749     info->BusCntl &= ~R128_BUS_MASTER_DIS;
750 
751 				/* CCEMode is initialized in r128_driver.c */
752     switch (info->CCEMode) {
753     case R128_PM4_NONPM4:                 info->CCEFifoSize = 0;   break;
754     case R128_PM4_192PIO:                 info->CCEFifoSize = 192; break;
755     case R128_PM4_192BM:                  info->CCEFifoSize = 192; break;
756     case R128_PM4_128PIO_64INDBM:         info->CCEFifoSize = 128; break;
757     case R128_PM4_128BM_64INDBM:          info->CCEFifoSize = 128; break;
758     case R128_PM4_64PIO_128INDBM:         info->CCEFifoSize = 64;  break;
759     case R128_PM4_64BM_128INDBM:          info->CCEFifoSize = 64;  break;
760     case R128_PM4_64PIO_64VCBM_64INDBM:   info->CCEFifoSize = 64;  break;
761     case R128_PM4_64BM_64VCBM_64INDBM:    info->CCEFifoSize = 64;  break;
762     case R128_PM4_64PIO_64VCPIO_64INDPIO: info->CCEFifoSize = 64;  break;
763     }
764 
765     if (info->directRenderingEnabled) {
766 				/* Make sure the CCE is on for the X server */
767 	R128CCE_START(pScrn, info);
768     } else {
769 				/* Make sure the CCE is off for the X server */
770 	R128CCE_STOP(pScrn, info);
771     }
772 }
773 
774 /* Initialize the screen-specific data structures for the DRI and the
775    Rage 128.  This is the main entry point to the device-specific
776    initialization code.  It calls device-independent DRI functions to
777    create the DRI data structures and initialize the DRI state. */
R128DRIScreenInit(ScreenPtr pScreen)778 Bool R128DRIScreenInit(ScreenPtr pScreen)
779 {
780     ScrnInfoPtr   pScrn = xf86ScreenToScrn(pScreen);
781     R128InfoPtr   info = R128PTR(pScrn);
782     DRIInfoPtr    pDRIInfo;
783     R128DRIPtr    pR128DRI;
784     int           major, minor, patch;
785     drmVersionPtr version;
786 
787     /* Check that the DRI, and DRM modules have been loaded by testing
788      * for known symbols in each module. */
789     if (!xf86LoaderCheckSymbol("drmAvailable"))        return FALSE;
790     if (!xf86LoaderCheckSymbol("DRIQueryVersion")) {
791       xf86DrvMsg(pScreen->myNum, X_ERROR,
792 		 "[dri] R128DRIScreenInit failed (libdri.a too old)\n");
793       return FALSE;
794     }
795 
796     /* Check the DRI version */
797     DRIQueryVersion(&major, &minor, &patch);
798     if (major != DRIINFO_MAJOR_VERSION || minor < 0) {
799 	xf86DrvMsg(pScreen->myNum, X_ERROR,
800 		"[dri] R128DRIScreenInit failed because of a version mismatch.\n"
801 		"[dri] libdri version is %d.%d.%d but version %d.%d.x is needed.\n"
802 		"[dri] Disabling the DRI.\n",
803 		major, minor, patch,
804                 DRIINFO_MAJOR_VERSION, 0);
805 	return FALSE;
806     }
807 
808     switch (info->CurrentLayout.pixel_code) {
809     case 8:
810 	/* These modes are not supported (yet). */
811     case 15:
812     case 24:
813 	xf86DrvMsg(pScreen->myNum, X_ERROR,
814 		   "[dri] R128DRIScreenInit failed (depth %d not supported).  "
815 		   "[dri] Disabling DRI.\n", info->CurrentLayout.pixel_code);
816 	return FALSE;
817 
818 	/* Only 16 and 32 color depths are supports currently. */
819     case 16:
820     case 32:
821 	break;
822     }
823 
824     r128_drm_page_size = getpagesize();
825 
826     /* Create the DRI data structure, and fill it in before calling the
827        DRIScreenInit(). */
828     if (!(pDRIInfo = DRICreateInfoRec())) return FALSE;
829 
830     info->pDRIInfo                       = pDRIInfo;
831     pDRIInfo->drmDriverName              = R128_DRIVER_NAME;
832     pDRIInfo->clientDriverName           = R128_DRIVER_NAME;
833     if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) {
834 	pDRIInfo->busIdString = DRICreatePCIBusID(info->PciInfo);
835     } else {
836 	pDRIInfo->busIdString            = malloc(64);
837 	sprintf(pDRIInfo->busIdString,
838 		"PCI:%d:%d:%d",
839 		PCI_DEV_BUS(info->PciInfo),
840 		PCI_DEV_DEV(info->PciInfo),
841 		PCI_DEV_FUNC(info->PciInfo));
842     }
843     pDRIInfo->ddxDriverMajorVersion      = R128_VERSION_MAJOR;
844     pDRIInfo->ddxDriverMinorVersion      = R128_VERSION_MINOR;
845     pDRIInfo->ddxDriverPatchVersion      = R128_VERSION_PATCH;
846     pDRIInfo->frameBufferPhysicalAddress = (void *)info->LinearAddr;
847     pDRIInfo->frameBufferSize            = info->FbMapSize;
848     pDRIInfo->frameBufferStride          = (pScrn->displayWidth *
849 					    info->CurrentLayout.pixel_bytes);
850     pDRIInfo->ddxDrawableTableEntry      = R128_MAX_DRAWABLES;
851     pDRIInfo->maxDrawableTableEntry      = (SAREA_MAX_DRAWABLES
852 					    < R128_MAX_DRAWABLES
853 					    ? SAREA_MAX_DRAWABLES
854 					    : R128_MAX_DRAWABLES);
855 
856 #ifdef NOT_DONE
857     /* FIXME: Need to extend DRI protocol to pass this size back to
858      * client for SAREA mapping that includes a device private record
859      */
860     pDRIInfo->SAREASize =
861 	((sizeof(XF86DRISAREARec) + 0xfff) & 0x1000); /* round to page */
862     /* + shared memory device private rec */
863 #else
864     /* For now the mapping works by using a fixed size defined
865      * in the SAREA header
866      */
867     if (sizeof(XF86DRISAREARec)+sizeof(R128SAREAPriv)>SAREA_MAX) {
868         xf86DrvMsg(pScreen->myNum, X_ERROR,
869                    "[dri] Data does not fit in SAREA.  Disabling DRI.\n");
870 	return FALSE;
871     }
872     pDRIInfo->SAREASize = SAREA_MAX;
873 #endif
874 
875     if (!(pR128DRI = (R128DRIPtr)calloc(sizeof(R128DRIRec),1))) {
876 	DRIDestroyInfoRec(info->pDRIInfo);
877 	info->pDRIInfo = NULL;
878 	return FALSE;
879     }
880     pDRIInfo->devPrivate     = pR128DRI;
881     pDRIInfo->devPrivateSize = sizeof(R128DRIRec);
882     pDRIInfo->contextSize    = sizeof(R128DRIContextRec);
883 
884     pDRIInfo->CreateContext  = R128CreateContext;
885     pDRIInfo->DestroyContext = R128DestroyContext;
886     pDRIInfo->SwapContext    = R128DRISwapContext;
887     pDRIInfo->InitBuffers    = R128DRIInitBuffers;
888     pDRIInfo->MoveBuffers    = R128DRIMoveBuffers;
889     pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
890     pDRIInfo->TransitionTo2d = R128DRITransitionTo2d;
891     pDRIInfo->TransitionTo3d = R128DRITransitionTo3d;
892     pDRIInfo->TransitionSingleToMulti3D = R128DRITransitionSingleToMulti3d;
893     pDRIInfo->TransitionMultiToSingle3D = R128DRITransitionMultiToSingle3d;
894 
895     pDRIInfo->createDummyCtx     = TRUE;
896     pDRIInfo->createDummyCtxPriv = FALSE;
897 
898     if (!DRIScreenInit(pScreen, pDRIInfo, &info->drmFD)) {
899 	xf86DrvMsg(pScreen->myNum, X_ERROR,
900                    "[dri] DRIScreenInit failed.  Disabling DRI.\n");
901 	free(pDRIInfo->devPrivate);
902 	pDRIInfo->devPrivate = NULL;
903 	DRIDestroyInfoRec(pDRIInfo);
904 	pDRIInfo = NULL;
905 	return FALSE;
906     }
907 
908     /* Check the DRM lib version.
909        drmGetLibVersion was not supported in version 1.0, so check for
910        symbol first to avoid possible crash or hang.
911      */
912     if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
913         version = drmGetLibVersion(info->drmFD);
914     }
915     else {
916         /* drmlib version 1.0.0 didn't have the drmGetLibVersion
917            entry point.  Fake it by allocating a version record
918            via drmGetVersion and changing it to version 1.0.0
919          */
920         version = drmGetVersion(info->drmFD);
921         version->version_major      = 1;
922         version->version_minor      = 0;
923         version->version_patchlevel = 0;
924     }
925 
926     if (version) {
927 	if (version->version_major != 1 ||
928 	    version->version_minor < 1) {
929             /* incompatible drm library version */
930             xf86DrvMsg(pScreen->myNum, X_ERROR,
931 		"[dri] R128DRIScreenInit failed because of a version mismatch.\n"
932 		"[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n"
933 		"[dri] Disabling DRI.\n",
934                 version->version_major,
935                 version->version_minor,
936                 version->version_patchlevel);
937             drmFreeVersion(version);
938 	    R128DRICloseScreen(pScreen);
939             return FALSE;
940 	}
941 	drmFreeVersion(version);
942     }
943 
944     /* Check the r128 DRM version */
945     version = drmGetVersion(info->drmFD);
946     if (version) {
947 	if (version->version_major != 2 ||
948 	    version->version_minor < 2) {
949 	    /* incompatible drm version */
950 	    xf86DrvMsg(pScreen->myNum, X_ERROR,
951 		"[dri] R128DRIScreenInit failed because of a version mismatch.\n"
952 		"[dri] r128.o kernel module version is %d.%d.%d but version 2.2 or greater is needed.\n"
953 		"[dri] Disabling the DRI.\n",
954 		version->version_major,
955 		version->version_minor,
956 		version->version_patchlevel);
957 	    drmFreeVersion(version);
958 	    R128DRICloseScreen(pScreen);
959 	    return FALSE;
960 	}
961 	info->drmMinor = version->version_minor;
962 	drmFreeVersion(version);
963     }
964 
965 				/* Initialize AGP */
966     if (!info->IsPCI && !R128DRIAgpInit(info, pScreen)) {
967 	info->IsPCI = TRUE;
968 	xf86DrvMsg(pScreen->myNum, X_WARNING,
969 		   "[agp] AGP failed to initialize -- falling back to PCI mode.\n");
970 	xf86DrvMsg(pScreen->myNum, X_WARNING,
971 		   "[agp] Make sure you have the agpgart kernel module loaded.\n");
972     }
973 
974 				/* Initialize PCIGART */
975     if (info->IsPCI && !R128DRIPciInit(info, pScreen)) {
976 	R128DRICloseScreen(pScreen);
977 	return FALSE;
978     }
979 
980 				/* DRIScreenInit doesn't add all the
981 				   common mappings.  Add additional
982 				   mappings here. */
983     if (!R128DRIMapInit(info, pScreen)) {
984 	R128DRICloseScreen(pScreen);
985 	return FALSE;
986     }
987 
988 				/* DRIScreenInit adds the frame buffer
989 				   map, but we need it as well */
990     {
991 	void *scratch_ptr;
992         int scratch_int;
993 
994 	DRIGetDeviceInfo(pScreen, &info->fbHandle,
995                          &scratch_int, &scratch_int,
996                          &scratch_int, &scratch_int,
997                          &scratch_ptr);
998     }
999 
1000 				/* FIXME: When are these mappings unmapped? */
1001 
1002     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Visual configs initialized\n");
1003 
1004     return TRUE;
1005 }
1006 
1007 /* Finish initializing the device-dependent DRI state, and call
1008    DRIFinishScreenInit() to complete the device-independent DRI
1009    initialization. */
R128DRIFinishScreenInit(ScreenPtr pScreen)1010 Bool R128DRIFinishScreenInit(ScreenPtr pScreen)
1011 {
1012     ScrnInfoPtr      pScrn = xf86ScreenToScrn(pScreen);
1013     R128InfoPtr      info  = R128PTR(pScrn);
1014     R128SAREAPrivPtr pSAREAPriv;
1015     R128DRIPtr       pR128DRI;
1016 
1017     info->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
1018     /* info->pDRIInfo->driverSwapMethod = DRI_SERVER_SWAP; */
1019 
1020     /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit
1021        because *DRIKernelInit requires that the hardware lock is held by
1022        the X server, and the first time the hardware lock is grabbed is
1023        in DRIFinishScreenInit. */
1024     if (!DRIFinishScreenInit(pScreen)) {
1025 	R128DRICloseScreen(pScreen);
1026 	return FALSE;
1027     }
1028 
1029     /* Initialize the kernel data structures */
1030     if (!R128DRIKernelInit(info, pScreen)) {
1031 	R128DRICloseScreen(pScreen);
1032 	return FALSE;
1033     }
1034 
1035     /* Initialize the vertex buffers list */
1036     if (!R128DRIBufInit(info, pScreen)) {
1037 	R128DRICloseScreen(pScreen);
1038 	return FALSE;
1039     }
1040 
1041     /* Initialize IRQ */
1042     R128DRIIrqInit(info, pScreen);
1043 
1044     /* Initialize and start the CCE if required */
1045     R128DRICCEInit(pScrn);
1046 
1047     pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
1048     memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
1049 
1050     pR128DRI                    = (R128DRIPtr)info->pDRIInfo->devPrivate;
1051 
1052     pR128DRI->deviceID          = info->Chipset;
1053     pR128DRI->width             = pScrn->virtualX;
1054     pR128DRI->height            = pScrn->virtualY;
1055     pR128DRI->depth             = pScrn->depth;
1056     pR128DRI->bpp               = pScrn->bitsPerPixel;
1057 
1058     pR128DRI->IsPCI             = info->IsPCI;
1059     pR128DRI->AGPMode           = info->agpMode;
1060 
1061     pR128DRI->frontOffset       = info->frontOffset;
1062     pR128DRI->frontPitch        = info->frontPitch;
1063     pR128DRI->backOffset        = info->backOffset;
1064     pR128DRI->backPitch         = info->backPitch;
1065     pR128DRI->depthOffset       = info->depthOffset;
1066     pR128DRI->depthPitch        = info->depthPitch;
1067     pR128DRI->spanOffset        = info->spanOffset;
1068     pR128DRI->textureOffset     = info->textureOffset;
1069     pR128DRI->textureSize       = info->textureSize;
1070     pR128DRI->log2TexGran       = info->log2TexGran;
1071 
1072     pR128DRI->registerHandle    = info->registerHandle;
1073     pR128DRI->registerSize      = info->registerSize;
1074 
1075     pR128DRI->agpTexHandle      = info->agpTexHandle;
1076     pR128DRI->agpTexMapSize     = info->agpTexMapSize;
1077     pR128DRI->log2AGPTexGran    = info->log2AGPTexGran;
1078     pR128DRI->agpTexOffset      = info->agpTexStart;
1079     pR128DRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
1080 
1081     /* Have shadowfb run only while there is 3d active. */
1082     if (info->allowPageFlip && info->drmMinor >= 5 ) {
1083 	ShadowFBInit( pScreen, R128DRIRefreshArea );
1084     } else if (info->allowPageFlip) {
1085 	xf86DrvMsg(pScreen->myNum, X_WARNING,
1086 		   "[dri] Kernel module version 2.5.0 or newer is required for pageflipping.\n");
1087        info->allowPageFlip = 0;
1088     }
1089 
1090     return TRUE;
1091 }
1092 
1093 /* The screen is being closed, so clean up any state and free any
1094    resources used by the DRI. */
R128DRICloseScreen(ScreenPtr pScreen)1095 void R128DRICloseScreen(ScreenPtr pScreen)
1096 {
1097     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1098     R128InfoPtr info = R128PTR(pScrn);
1099     drmR128Init drmInfo;
1100 
1101 				/* Stop the CCE if it is still in use */
1102     if (info->directRenderingEnabled) {
1103 	R128CCE_STOP(pScrn, info);
1104     }
1105 
1106     if (info->irq) {
1107 	drmCtlUninstHandler(info->drmFD);
1108 	info->irq = 0;
1109 	info->gen_int_cntl = 0;
1110     }
1111 
1112 				/* De-allocate vertex buffers */
1113     if (info->buffers) {
1114 	drmUnmapBufs(info->buffers);
1115 	info->buffers = NULL;
1116     }
1117 
1118 				/* De-allocate all kernel resources */
1119     memset(&drmInfo, 0, sizeof(drmR128Init));
1120     drmInfo.func = DRM_R128_CLEANUP_CCE;
1121     drmCommandWrite(info->drmFD, DRM_R128_INIT,
1122                     &drmInfo, sizeof(drmR128Init));
1123 
1124 				/* De-allocate all AGP resources */
1125     if (info->agpTex) {
1126 	drmUnmap(info->agpTex, info->agpTexMapSize);
1127 	info->agpTex = NULL;
1128     }
1129     if (info->buf) {
1130 	drmUnmap(info->buf, info->bufMapSize);
1131 	info->buf = NULL;
1132     }
1133     if (info->ringReadPtr) {
1134 	drmUnmap(info->ringReadPtr, info->ringReadMapSize);
1135 	info->ringReadPtr = NULL;
1136     }
1137     if (info->ring) {
1138 	drmUnmap(info->ring, info->ringMapSize);
1139 	info->ring = NULL;
1140     }
1141     if (info->agpMemHandle != DRM_AGP_NO_HANDLE) {
1142 	drmAgpUnbind(info->drmFD, info->agpMemHandle);
1143 	drmAgpFree(info->drmFD, info->agpMemHandle);
1144 	info->agpMemHandle = DRM_AGP_NO_HANDLE;
1145 	drmAgpRelease(info->drmFD);
1146     }
1147     if (info->pciMemHandle) {
1148 	drmScatterGatherFree(info->drmFD, info->pciMemHandle);
1149 	info->pciMemHandle = 0;
1150     }
1151 
1152 				/* De-allocate all DRI resources */
1153     DRICloseScreen(pScreen);
1154 
1155 				/* De-allocate all DRI data structures */
1156     if (info->pDRIInfo) {
1157 	if (info->pDRIInfo->devPrivate) {
1158 	    free(info->pDRIInfo->devPrivate);
1159 	    info->pDRIInfo->devPrivate = NULL;
1160 	}
1161 	DRIDestroyInfoRec(info->pDRIInfo);
1162 	info->pDRIInfo = NULL;
1163     }
1164 }
1165 
1166 /* Use callbacks from dri.c to support pageflipping mode for a single
1167  * 3d context without need for any specific full-screen extension.
1168  */
1169 
1170 /* Use the shadowfb module to maintain a list of dirty rectangles.
1171  * These are blitted to the back buffer to keep both buffers clean
1172  * during page-flipping when the 3d application isn't fullscreen.
1173  *
1174  * Unlike most use of the shadowfb code, both buffers are in video memory.
1175  *
1176  * An alternative to this would be to organize for all on-screen drawing
1177  * operations to be duplicated for the two buffers.  That might be
1178  * faster, but seems like a lot more work...
1179  */
1180 
1181 
R128DRIRefreshArea(ScrnInfoPtr pScrn,int num,BoxPtr pbox)1182 static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
1183 {
1184     R128InfoPtr         info       = R128PTR(pScrn);
1185     int                 i;
1186     R128SAREAPrivPtr    pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen);
1187     PixmapPtr		pPix	   = pScrn->pScreen->GetScreenPixmap(pScrn->pScreen);
1188 
1189     /* Don't want to do this when no 3d is active and pages are
1190      * right-way-round
1191      */
1192     if (!pSAREAPriv->pfAllowPageFlip && pSAREAPriv->pfCurrentPage == 0)
1193 	return;
1194 
1195 #ifdef HAVE_XAA_H
1196     if (!info->useEXA) {
1197 	(*info->accel->SetupForScreenToScreenCopy)(pScrn,
1198 					       1, 1, GXcopy,
1199 					       (uint32_t)(-1), -1);
1200     }
1201 #endif
1202 #ifdef USE_EXA
1203     if (info->useEXA) {
1204         uint32_t src_pitch_offset, dst_pitch_offset, datatype;
1205 
1206 	R128GetPixmapOffsetPitch(pPix, &src_pitch_offset);
1207 	dst_pitch_offset = src_pitch_offset + (info->backOffset >> 5);
1208 	R128GetDatatypeBpp(pScrn->bitsPerPixel, &datatype);
1209 	info->xdir = info->ydir = 1;
1210 
1211 	R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, GXcopy, ~0);
1212     }
1213 #endif
1214 
1215     for (i = 0 ; i < num ; i++, pbox++) {
1216 	int xa = max(pbox->x1, 0), xb = min(pbox->x2, pScrn->virtualX-1);
1217 	int ya = max(pbox->y1, 0), yb = min(pbox->y2, pScrn->virtualY-1);
1218 
1219 	if (xa <= xb && ya <= yb) {
1220 #ifdef HAVE_XAA_H
1221 	    if (!info->useEXA) {
1222 	        (*info->accel->SubsequentScreenToScreenCopy)(pScrn, xa, ya,
1223 							 xa + info->backX,
1224 							 ya + info->backY,
1225 							 xb - xa + 1,
1226 							 yb - ya + 1);
1227 	    }
1228 #endif
1229 #ifdef USE_EXA
1230 	    if (info->useEXA) {
1231 		(*info->ExaDriver->Copy)(pPix, xa, ya, xa, ya, xb - xa + 1, yb - ya + 1);
1232 	    }
1233 #endif
1234 	}
1235     }
1236 }
1237 
R128EnablePageFlip(ScreenPtr pScreen)1238 static void R128EnablePageFlip(ScreenPtr pScreen)
1239 {
1240     ScrnInfoPtr         pScrn      = xf86ScreenToScrn(pScreen);
1241     R128InfoPtr         info       = R128PTR(pScrn);
1242     R128SAREAPrivPtr    pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1243     PixmapPtr		pPix	   = pScreen->GetScreenPixmap(pScreen);
1244 
1245     if (info->allowPageFlip) {
1246 	/* Duplicate the frontbuffer to the backbuffer */
1247 #ifdef HAVE_XAA_H
1248 	if (!info->useEXA) {
1249 	    (*info->accel->SetupForScreenToScreenCopy)(pScrn,
1250 						   1, 1, GXcopy,
1251 						   (uint32_t)(-1), -1);
1252 
1253 	    (*info->accel->SubsequentScreenToScreenCopy)(pScrn,
1254 						     0,
1255 						     0,
1256 						     info->backX,
1257 						     info->backY,
1258 						     pScrn->virtualX,
1259 						     pScrn->virtualY);
1260 	}
1261 #endif
1262 #ifdef USE_EXA
1263 	if (info->useEXA) {
1264 	    uint32_t src_pitch_offset, dst_pitch_offset, datatype;
1265 
1266 	    R128GetPixmapOffsetPitch(pPix, &src_pitch_offset);
1267 	    dst_pitch_offset = src_pitch_offset + (info->backOffset >> 5);
1268 	    R128GetDatatypeBpp(pScrn->bitsPerPixel, &datatype);
1269 	    info->xdir = info->ydir = 1;
1270 
1271             R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, GXcopy, ~0);
1272 
1273 	    (*info->ExaDriver->Copy)(pPix, 0, 0, 0, 0, pScrn->virtualX, pScrn->virtualY);
1274 	}
1275 #endif
1276 
1277 	pSAREAPriv->pfAllowPageFlip = 1;
1278     }
1279 }
1280 
R128DisablePageFlip(ScreenPtr pScreen)1281 static void R128DisablePageFlip(ScreenPtr pScreen)
1282 {
1283     /* Tell the clients not to pageflip.  How?
1284      *   -- Field in sarea, plus bumping the window counters.
1285      *   -- DRM needs to cope with Front-to-Back swapbuffers.
1286      */
1287     R128SAREAPrivPtr  pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1288 
1289     pSAREAPriv->pfAllowPageFlip = 0;
1290 }
1291 
R128DRITransitionSingleToMulti3d(ScreenPtr pScreen)1292 static void R128DRITransitionSingleToMulti3d(ScreenPtr pScreen)
1293 {
1294     R128DisablePageFlip(pScreen);
1295 }
1296 
R128DRITransitionMultiToSingle3d(ScreenPtr pScreen)1297 static void R128DRITransitionMultiToSingle3d(ScreenPtr pScreen)
1298 {
1299     /* Let the remaining 3d app start page flipping again */
1300     R128EnablePageFlip(pScreen);
1301 }
1302 
R128DRITransitionTo3d(ScreenPtr pScreen)1303 static void R128DRITransitionTo3d(ScreenPtr pScreen)
1304 {
1305     ScrnInfoPtr    pScrn = xf86ScreenToScrn(pScreen);
1306     R128InfoPtr    info  = R128PTR(pScrn);
1307 
1308     R128EnablePageFlip(pScreen);
1309 
1310     info->have3DWindows = 1;
1311 }
1312 
R128DRITransitionTo2d(ScreenPtr pScreen)1313 static void R128DRITransitionTo2d(ScreenPtr pScreen)
1314 {
1315     ScrnInfoPtr         pScrn      = xf86ScreenToScrn(pScreen);
1316     R128InfoPtr         info       = R128PTR(pScrn);
1317     R128SAREAPrivPtr    pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1318 
1319     /* Try flipping back to the front page if necessary */
1320     if (pSAREAPriv->pfCurrentPage == 1)
1321 	drmCommandNone(info->drmFD, DRM_R128_FLIP);
1322 
1323     /* Shut down shadowing if we've made it back to the front page */
1324     if (pSAREAPriv->pfCurrentPage == 0) {
1325 	R128DisablePageFlip(pScreen);
1326     } else {
1327 	xf86DrvMsg(pScreen->myNum, X_WARNING,
1328 		   "[dri] R128DRITransitionTo2d: "
1329 		   "kernel failed to unflip buffers.\n");
1330     }
1331 
1332     info->have3DWindows = 0;
1333 }
1334