via_dri.c revision 485acf3e
1/*
2 * Copyright 2005-2008 The Openchrome Project  [openchrome.org]
3 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
4 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sub license,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include "xf86.h"
31#include "xf86_OSproc.h"
32#include "xf86Priv.h"
33
34#include "xf86PciInfo.h"
35#include "xf86Pci.h"
36
37#define _XF86DRI_SERVER_
38#include "GL/glxtokens.h"
39#include "sarea.h"
40
41#include "via.h"
42#include "via_driver.h"
43#include "via_drm.h"
44#include "via_dri.h"
45#include "via_id.h"
46#include "xf86drm.h"
47
48#ifndef DRIINFO_MAJOR_VERSION
49#define DRIINFO_MAJOR_VERSION 4
50#endif
51#ifndef DRIINFO_MINOR_VERSION
52#define DRIINFO_MINOR_VERSION 0
53#endif
54
55#define VIDEO  0
56#define AGP    1
57#define AGP_CMDBUF_PAGES 512
58#define AGP_CMDBUF_SIZE (AGP_PAGE_SIZE * AGP_CMDBUF_PAGES)
59#define VIA_AGP_MODE_MASK 0x17
60#define VIA_AGPv3_MODE    0x08
61#define VIA_AGPv3_8X_MODE 0x02
62#define VIA_AGPv3_4X_MODE 0x01
63#define VIA_AGP_4X_MODE 0x04
64#define VIA_AGP_2X_MODE 0x02
65#define VIA_AGP_1X_MODE 0x01
66#define VIA_AGP_FW_MODE 0x10
67
68extern void GlxSetVisualConfigs(int nconfigs,
69                                __GLXvisualConfig * configs,
70                                void **configprivs);
71
72typedef struct
73{
74    int major;
75    int minor;
76    int patchlevel;
77} ViaDRMVersion;
78
79static char VIAKernelDriverName[] = "via";
80static char VIAClientDriverName[] = "unichrome";
81static const ViaDRMVersion drmExpected = { 1, 3, 0 };
82static const ViaDRMVersion drmCompat = { 2, 0, 0 };
83
84int test_alloc_FB(ScreenPtr pScreen, VIAPtr pVia, int Size);
85int test_alloc_AGP(ScreenPtr pScreen, VIAPtr pVia, int Size);
86static Bool VIAInitVisualConfigs(ScreenPtr pScreen);
87static Bool VIADRIAgpInit(ScreenPtr pScreen, VIAPtr pVia);
88static Bool VIADRIPciInit(ScreenPtr pScreen, VIAPtr pVia);
89static Bool VIADRIFBInit(ScreenPtr pScreen, VIAPtr pVia);
90static Bool VIADRIKernelInit(ScreenPtr pScreen, VIAPtr pVia);
91static Bool VIADRIMapInit(ScreenPtr pScreen, VIAPtr pVia);
92
93static Bool VIACreateContext(ScreenPtr pScreen, VisualPtr visual,
94                             drm_context_t hwContext, void *pVisualConfigPriv,
95                             DRIContextType contextStore);
96static void VIADestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
97                              DRIContextType contextStore);
98static void VIADRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
99                              DRIContextType readContextType,
100                              void *readContextStore,
101                              DRIContextType writeContextType,
102                              void *writeContextStore);
103static void VIADRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index);
104static void VIADRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg,
105                              RegionPtr prgnSrc, CARD32 index);
106
107
108static void
109VIADRIIrqInit(ScrnInfoPtr pScrn, VIADRIPtr pVIADRI)
110{
111    VIAPtr pVia = VIAPTR(pScrn);
112
113    pVIADRI->irqEnabled = drmGetInterruptFromBusID
114            (pVia->drmFD,
115#ifdef XSERVER_LIBPCIACCESS
116             ((pVia->PciInfo->domain << 8) | pVia->PciInfo->bus),
117             pVia->PciInfo->dev, pVia->PciInfo->func
118#else
119             ((pciConfigPtr)pVia->PciInfo->thisCard)->busnum,
120             ((pciConfigPtr)pVia->PciInfo->thisCard)->devnum,
121             ((pciConfigPtr)pVia->PciInfo->thisCard)->funcnum
122#endif
123            );
124    if ((drmCtlInstHandler(pVia->drmFD, pVIADRI->irqEnabled))) {
125        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
126                   "[drm] Failure adding IRQ handler. "
127                   "Falling back to IRQ-free operation.\n");
128        pVIADRI->irqEnabled = 0;
129    }
130
131    if (pVIADRI->irqEnabled)
132        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
133                   "[drm] IRQ handler installed, using IRQ %d.\n",
134                   pVIADRI->irqEnabled);
135}
136
137static void
138VIADRIIrqExit(ScrnInfoPtr pScrn, VIADRIPtr pVIADRI)
139{
140    VIAPtr pVia = VIAPTR(pScrn);
141
142    if (pVIADRI->irqEnabled) {
143        if (drmCtlUninstHandler(pVia->drmFD)) {
144            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
145                       "[drm] IRQ handler uninstalled.\n");
146        } else {
147            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
148                       "[drm] Could not uninstall IRQ handler.\n");
149        }
150    }
151}
152
153void
154VIADRIRingBufferCleanup(ScrnInfoPtr pScrn)
155{
156    VIAPtr pVia = VIAPTR(pScrn);
157    VIADRIPtr pVIADRI = pVia->pDRIInfo->devPrivate;
158
159    if (pVIADRI->ringBufActive) {
160        drm_via_dma_init_t ringBufInit;
161
162        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
163                   "[drm] Cleaning up DMA ring-buffer.\n");
164        ringBufInit.func = VIA_CLEANUP_DMA;
165        if (drmCommandWrite(pVia->drmFD, DRM_VIA_DMA_INIT, &ringBufInit,
166                            sizeof(ringBufInit))) {
167            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
168                       "[drm] Failed to clean up DMA ring-buffer: %d\n", errno);
169        }
170        pVIADRI->ringBufActive = 0;
171    }
172}
173
174Bool
175VIADRIRingBufferInit(ScrnInfoPtr pScrn)
176{
177    VIAPtr pVia = VIAPTR(pScrn);
178    VIADRIPtr pVIADRI = pVia->pDRIInfo->devPrivate;
179
180    if (pVIADRI->ringBufActive)
181        return TRUE;
182
183    if (pVia->agpEnable) {
184        drm_via_dma_init_t ringBufInit;
185
186        if ((pVia->drmVerMajor == 1) && (pVia->drmVerMinor <= 3))
187            return FALSE;
188
189        /*
190         * Info frome code-snippet on DRI-DEVEL list; Erdi Chen.
191         */
192
193        switch (pVia->ChipId) {
194            case PCI_CHIP_VT3314:
195            case PCI_CHIP_VT3259:
196                pVIADRI->reg_pause_addr = 0x40c;
197                break;
198            default:
199                pVIADRI->reg_pause_addr = 0x418;
200                break;
201        }
202
203        ringBufInit.offset = pVia->agpSize;
204        ringBufInit.size = AGP_CMDBUF_SIZE;
205        ringBufInit.reg_pause_addr = pVIADRI->reg_pause_addr;
206        ringBufInit.func = VIA_INIT_DMA;
207
208        if (drmCommandWrite(pVia->drmFD, DRM_VIA_DMA_INIT, &ringBufInit,
209                            sizeof(ringBufInit))) {
210            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
211                       "[drm] Failed to initialize DMA ring-buffer: %d\n",
212                       errno);
213            return FALSE;
214        }
215
216        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
217                   "[drm] Initialized AGP ring-buffer, size 0x%lx at AGP "
218                   "offset 0x%lx.\n", ringBufInit.size, ringBufInit.offset);
219        pVIADRI->ringBufActive = 1;
220    }
221    return TRUE;
222}
223
224static Bool
225VIASetAgpMode(ScrnInfoPtr pScrn)
226{
227    VIAPtr pVia = VIAPTR(pScrn);
228    CARD32 mode = drmAgpGetMode(pVia->drmFD);
229    unsigned int vendor = drmAgpVendorId(pVia->drmFD);
230    unsigned int device = drmAgpDeviceId(pVia->drmFD);
231
232    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Detected AGP "
233               "vendor 0x%04x, device 0x%04x\n", vendor, device);
234
235    mode &= ~VIA_AGP_MODE_MASK;
236    if (mode & VIA_AGPv3_MODE) {
237        mode |= VIA_AGPv3_8X_MODE;
238        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Found AGP v3 "
239                   "compatible device. Trying AGP 8X mode.\n");
240    } else {
241        mode |= VIA_AGP_4X_MODE;
242        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Didn't find any AGP v3 "
243                   "compatible device. Trying AGP 4X mode.\n");
244    }
245
246    mode |= VIA_AGP_FW_MODE;
247    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
248               "[drm] Trying to enable AGP fast writes.\n");
249
250    if (drmAgpEnable(pVia->drmFD, mode) < 0)
251        return FALSE;
252
253    return TRUE;
254}
255
256static Bool
257VIADRIAgpInit(ScreenPtr pScreen, VIAPtr pVia)
258{
259    int agpPages;
260    unsigned long agpCmdSize;
261    unsigned long agp_phys;
262    drmAddress agpaddr;
263    VIADRIPtr pVIADRI;
264    DRIInfoPtr pDRIInfo;
265
266    pDRIInfo = pVia->pDRIInfo;
267    pVIADRI = pDRIInfo->devPrivate;
268    pVia->agpSize = 0;
269
270    if (drmAgpAcquire(pVia->drmFD) < 0) {
271        xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAgpAcquire failed %d\n",
272                   errno);
273        return FALSE;
274    }
275
276    if (!VIASetAgpMode(xf86Screens[pScreen->myNum])) {
277        xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] VIASetAgpMode failed\n");
278        drmAgpRelease(pVia->drmFD);
279        return FALSE;
280    }
281
282    xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] drmAgpEnabled succeeded\n");
283
284    agpCmdSize = (pVia->agpEnable) ? AGP_CMDBUF_SIZE : 0;
285
286    if (pVia->agpMem * 1024 < agpCmdSize + AGP_PAGE_SIZE) {
287        pVia->agpMem = (agpCmdSize + AGP_PAGE_SIZE) / 1024;
288        xf86DrvMsg(pScreen->myNum, X_INFO,
289                   "[drm] Forcing AGP size to %d kB\n", pVia->agpMem);
290    }
291
292    agpPages = (pVia->agpMem * 1024 + AGP_PAGE_SIZE - 1) / AGP_PAGE_SIZE;
293
294    if (drmAgpAlloc(pVia->drmFD, agpPages * AGP_PAGE_SIZE,
295                    0, &agp_phys, &pVia->agpHandle) < 0) {
296        xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAgpAlloc failed\n");
297        drmAgpRelease(pVia->drmFD);
298        return FALSE;
299    }
300
301    if (drmAgpBind(pVia->drmFD, pVia->agpHandle, 0) < 0) {
302        xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAgpBind failed\n");
303        drmAgpFree(pVia->drmFD, pVia->agpHandle);
304        drmAgpRelease(pVia->drmFD);
305        return FALSE;
306    }
307
308    /*
309     * Place the ring-buffer last in the AGP region, and restrict the
310     * public map not to include the buffer for security reasons.
311     */
312
313    pVia->agpSize = agpPages * AGP_PAGE_SIZE - agpCmdSize;
314    pVia->agpAddr = drmAgpBase(pVia->drmFD);
315    xf86DrvMsg(pScreen->myNum, X_INFO,
316               "[drm] agpAddr = 0x%08lx\n", pVia->agpAddr);
317
318    pVIADRI->agp.size = pVia->agpSize;
319    if (drmAddMap(pVia->drmFD, (drm_handle_t) 0, pVIADRI->agp.size,
320                  DRM_AGP, 0, &pVIADRI->agp.handle) < 0) {
321        xf86DrvMsg(pScreen->myNum, X_ERROR,
322                   "[drm] Failed to map public agp area.\n");
323        pVIADRI->agp.size = 0;
324        drmAgpUnbind(pVia->drmFD, pVia->agpHandle);
325        drmAgpFree(pVia->drmFD, pVia->agpHandle);
326        drmAgpRelease(pVia->drmFD);
327        return FALSE;
328    }
329
330    drmMap(pVia->drmFD, pVIADRI->agp.handle, pVIADRI->agp.size, &agpaddr);
331    pVia->agpMappedAddr = agpaddr;
332
333    xf86DrvMsg(pScreen->myNum, X_INFO,
334               "[drm] agpBase = %p\n", pVia->agpBase);
335    xf86DrvMsg(pScreen->myNum, X_INFO,
336               "[drm] agpAddr = 0x%08lx\n", pVia->agpAddr);
337    xf86DrvMsg(pScreen->myNum, X_INFO,
338               "[drm] agpSize = 0x%08x\n", pVia->agpSize);
339    xf86DrvMsg(pScreen->myNum, X_INFO,
340               "[drm] agp physical addr = 0x%08lx\n", agp_phys);
341
342    {
343        drm_via_agp_t agp;
344
345        agp.offset = 0;
346        agp.size = pVia->agpSize;
347        if (drmCommandWrite(pVia->drmFD, DRM_VIA_AGP_INIT, &agp,
348                            sizeof(drm_via_agp_t)) < 0) {
349            drmUnmap(agpaddr, pVia->agpSize);
350            drmRmMap(pVia->drmFD, pVIADRI->agp.handle);
351            drmAgpUnbind(pVia->drmFD, pVia->agpHandle);
352            drmAgpFree(pVia->drmFD, pVia->agpHandle);
353            drmAgpRelease(pVia->drmFD);
354            return FALSE;
355        }
356    }
357
358    return TRUE;
359}
360
361static Bool
362VIADRIFBInit(ScreenPtr pScreen, VIAPtr pVia)
363{
364    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
365    int FBSize = pVia->driSize;
366    int FBOffset;
367    VIADRIPtr pVIADRI = pVia->pDRIInfo->devPrivate;
368
369    if (FBSize < pVia->Bpl) {
370        xf86DrvMsg(pScreen->myNum, X_ERROR,
371                   "[drm] No DRM framebuffer heap available.\n"
372                   "[drm] Please increase the frame buffer\n"
373                   "[drm] memory area in the BIOS. Disabling DRI.\n");
374        return FALSE;
375    }
376    if (FBSize < 3 * (pScrn->virtualY * pVia->Bpl)) {
377        xf86DrvMsg(pScreen->myNum, X_WARNING,
378                   "[drm] The DRM heap and pixmap cache memory may be too\n"
379                   "[drm] small for optimal performance. Please increase\n"
380                   "[drm] the frame buffer memory area in the BIOS.\n");
381    }
382
383    pVia->driOffScreenMem.pool = 0;
384    if (Success != viaOffScreenLinear(&pVia->driOffScreenMem, pScrn, FBSize)) {
385        xf86DrvMsg(pScreen->myNum, X_ERROR,
386                   "[drm] Failed to allocate offscreen frame buffer area.\n");
387        return FALSE;
388    }
389
390    FBOffset = pVia->driOffScreenMem.base;
391
392    pVIADRI->fbOffset = FBOffset;
393    pVIADRI->fbSize = FBSize;
394
395    {
396        drm_via_fb_t fb;
397
398        fb.offset = FBOffset;
399        fb.size = FBSize;
400
401        if (drmCommandWrite(pVia->drmFD, DRM_VIA_FB_INIT, &fb,
402                            sizeof(drm_via_fb_t)) < 0) {
403            xf86DrvMsg(pScreen->myNum, X_ERROR,
404                       "[drm] Failed to initialize frame buffer area.\n");
405            return FALSE;
406        } else {
407            xf86DrvMsg(pScreen->myNum, X_INFO,
408                       "[drm] Using %d bytes for DRM memory heap.\n", FBSize);
409            return TRUE;
410        }
411    }
412}
413
414static Bool
415VIADRIPciInit(ScreenPtr pScreen, VIAPtr pVia)
416{
417    return TRUE;
418}
419
420static Bool
421VIAInitVisualConfigs(ScreenPtr pScreen)
422{
423    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
424    VIAPtr pVia = VIAPTR(pScrn);
425    int numConfigs = 0;
426    __GLXvisualConfig *pConfigs = 0;
427    VIAConfigPrivPtr pVIAConfigs = 0;
428    VIAConfigPrivPtr *pVIAConfigPtrs = 0;
429    int i, db, stencil, accum;
430
431    if (pScrn->bitsPerPixel == 16 || pScrn->bitsPerPixel == 32) {
432        numConfigs = 12;
433        if (!(pConfigs = (__GLXvisualConfig *)
434                         xcalloc(sizeof(__GLXvisualConfig), numConfigs)))
435            return FALSE;
436        if (!(pVIAConfigs = (VIAConfigPrivPtr)
437                            xcalloc(sizeof(VIAConfigPrivRec), numConfigs))) {
438            xfree(pConfigs);
439            return FALSE;
440        }
441        if (!(pVIAConfigPtrs = (VIAConfigPrivPtr *)
442                               xcalloc(sizeof(VIAConfigPrivPtr), numConfigs))) {
443            xfree(pConfigs);
444            xfree(pVIAConfigs);
445            return FALSE;
446        }
447        for (i = 0; i < numConfigs; i++)
448            pVIAConfigPtrs[i] = &pVIAConfigs[i];
449
450        i = 0;
451        for (accum = 0; accum <= 1; accum++) {
452            /* 32bpp depth buffer disabled, as Mesa has limitations */
453            for (stencil = 0; stencil <= 2; stencil++) {
454                for (db = 0; db <= 1; db++) {
455                    pConfigs[i].vid = -1;
456                    pConfigs[i].class = -1;
457                    pConfigs[i].rgba = TRUE;
458                    pConfigs[i].redSize = -1;
459                    pConfigs[i].greenSize = -1;
460                    pConfigs[i].blueSize = -1;
461                    pConfigs[i].redMask = -1;
462                    pConfigs[i].greenMask = -1;
463                    pConfigs[i].blueMask = -1;
464                    if (pScrn->bitsPerPixel == 32) {
465                        pConfigs[i].alphaSize = 8;
466                        pConfigs[i].alphaMask = 0xFF000000;
467                    } else {
468                        pConfigs[i].alphaSize = 0;
469                        pConfigs[i].alphaMask = 0;
470                    }
471
472                    if (accum) {
473                        pConfigs[i].accumRedSize = 16;
474                        pConfigs[i].accumGreenSize = 16;
475                        pConfigs[i].accumBlueSize = 16;
476                        if (pScrn->bitsPerPixel == 32)
477                            pConfigs[i].accumAlphaSize = 16;
478                        else
479                            pConfigs[i].accumAlphaSize = 0;
480                    } else {
481                        pConfigs[i].accumRedSize = 0;
482                        pConfigs[i].accumGreenSize = 0;
483                        pConfigs[i].accumBlueSize = 0;
484                        pConfigs[i].accumAlphaSize = 0;
485                    }
486                    if (!db)
487                        pConfigs[i].doubleBuffer = TRUE;
488                    else
489                        pConfigs[i].doubleBuffer = FALSE;
490
491                    pConfigs[i].stereo = FALSE;
492                    pConfigs[i].bufferSize = -1;
493
494                    switch (stencil) {
495                        case 0:
496                            pConfigs[i].depthSize = 24;
497                            pConfigs[i].stencilSize = 8;
498                            break;
499                        case 1:
500                            pConfigs[i].depthSize = 16;
501                            pConfigs[i].stencilSize = 0;
502                            break;
503                        case 2:
504                            pConfigs[i].depthSize = 0;
505                            pConfigs[i].stencilSize = 0;
506                            break;
507                        case 3:
508                            pConfigs[i].depthSize = 32;
509                            pConfigs[i].stencilSize = 0;
510                            break;
511                    }
512
513                    pConfigs[i].auxBuffers = 0;
514                    pConfigs[i].level = 0;
515                    if (accum)
516                        pConfigs[i].visualRating = GLX_SLOW_VISUAL_EXT;
517                    else
518                        pConfigs[i].visualRating = GLX_NONE_EXT;
519                    pConfigs[i].transparentPixel = GLX_NONE_EXT;
520                    pConfigs[i].transparentRed = 0;
521                    pConfigs[i].transparentGreen = 0;
522                    pConfigs[i].transparentBlue = 0;
523                    pConfigs[i].transparentAlpha = 0;
524                    pConfigs[i].transparentIndex = 0;
525                    i++;
526                }
527            }
528        }
529
530        if (i != numConfigs) {
531            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[dri] Incorrect "
532                       "initialization of visuals.  Disabling DRI.\n");
533            return FALSE;
534        }
535    }
536
537    pVia->numVisualConfigs = numConfigs;
538    pVia->pVisualConfigs = pConfigs;
539    pVia->pVisualConfigsPriv = pVIAConfigs;
540    GlxSetVisualConfigs(numConfigs, pConfigs, (void **)pVIAConfigPtrs);
541
542    return TRUE;
543}
544
545Bool
546VIADRIScreenInit(ScreenPtr pScreen)
547{
548    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
549    VIAPtr pVia = VIAPTR(pScrn);
550    DRIInfoPtr pDRIInfo;
551    VIADRIPtr pVIADRI;
552    drmVersionPtr drmVer;
553
554    /* If symbols or version check fails, we still want this to be NULL. */
555    pVia->pDRIInfo = NULL;
556
557    /* Check that the GLX, DRI, and DRM modules have been loaded by testing
558     * for canonical symbols in each module. */
559    if (!xf86LoaderCheckSymbol("GlxSetVisualConfigs"))
560        return FALSE;
561    if (!xf86LoaderCheckSymbol("drmAvailable"))
562        return FALSE;
563    if (!xf86LoaderCheckSymbol("DRIQueryVersion")) {
564        xf86DrvMsg(pScreen->myNum, X_ERROR,
565                   "[dri] VIADRIScreenInit failed (libdri.a is too old).\n");
566        return FALSE;
567    }
568
569    /* Check the DRI version. */
570    {
571        int major, minor, patch;
572
573        DRIQueryVersion(&major, &minor, &patch);
574        if (major != DRIINFO_MAJOR_VERSION || minor < DRIINFO_MINOR_VERSION) {
575            xf86DrvMsg(pScreen->myNum, X_ERROR,
576                       "[dri] VIADRIScreenInit failed -- version mismatch.\n"
577                       "[dri] libdri is %d.%d.%d, but %d.%d.x is needed.\n"
578                       "[dri] Disabling DRI.\n",
579                       major, minor, patch,
580                       DRIINFO_MAJOR_VERSION, DRIINFO_MINOR_VERSION);
581            return FALSE;
582        }
583    }
584
585    pVia->pDRIInfo = DRICreateInfoRec();
586    if (!pVia->pDRIInfo)
587        return FALSE;
588
589    pDRIInfo = pVia->pDRIInfo;
590    pDRIInfo->drmDriverName = VIAKernelDriverName;
591    switch (pVia->Chipset) {
592        case VIA_K8M890:
593        case VIA_P4M900:
594        case VIA_VX800:
595        case VIA_VX855:
596            pDRIInfo->clientDriverName = "swrast";
597            break;
598        default:
599            pDRIInfo->clientDriverName = VIAClientDriverName;
600            break;
601    }
602    if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) {
603        pDRIInfo->busIdString = DRICreatePCIBusID(pVia->PciInfo);
604    } else {
605        pDRIInfo->busIdString = xalloc(64);
606        sprintf(pDRIInfo->busIdString, "PCI:%d:%d:%d",
607#ifdef XSERVER_LIBPCIACCESS
608                ((pVia->PciInfo->domain << 8) | pVia->PciInfo->bus),
609                pVia->PciInfo->dev, pVia->PciInfo->func
610#else
611                ((pciConfigPtr)pVia->PciInfo->thisCard)->busnum,
612                ((pciConfigPtr)pVia->PciInfo->thisCard)->devnum,
613                ((pciConfigPtr)pVia->PciInfo->thisCard)->funcnum
614#endif
615               );
616    }
617    pDRIInfo->ddxDriverMajorVersion = VIA_DRIDDX_VERSION_MAJOR;
618    pDRIInfo->ddxDriverMinorVersion = VIA_DRIDDX_VERSION_MINOR;
619    pDRIInfo->ddxDriverPatchVersion = VIA_DRIDDX_VERSION_PATCH;
620#if (DRIINFO_MAJOR_VERSION == 5)
621    pDRIInfo->frameBufferPhysicalAddress = (pointer) pVia->FrameBufferBase;
622#else
623    pDRIInfo->frameBufferPhysicalAddress = pVia->FrameBufferBase;
624#endif
625    pDRIInfo->frameBufferSize = pVia->videoRambytes;
626
627    pDRIInfo->frameBufferStride = (pScrn->displayWidth *
628                                   pScrn->bitsPerPixel / 8);
629    pDRIInfo->ddxDrawableTableEntry = VIA_MAX_DRAWABLES;
630
631    if (SAREA_MAX_DRAWABLES < VIA_MAX_DRAWABLES)
632        pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES;
633    else
634        pDRIInfo->maxDrawableTableEntry = VIA_MAX_DRAWABLES;
635
636#ifdef NOT_DONE
637    /* FIXME: need to extend DRI protocol to pass this size back to client
638     * for SAREA mapping that includes a device private record. */
639    pDRIInfo->SAREASize = ((sizeof(XF86DRISAREARec) + 0xfff) & 0x1000); /* round to page */
640    /* + shared memory device private rec */
641#else
642    /* For now the mapping works by using a fixed size defined
643     * in the SAREA header. */
644    if (sizeof(XF86DRISAREARec) + sizeof(drm_via_sarea_t) > SAREA_MAX) {
645        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Data does not fit in SAREA\n");
646        DRIDestroyInfoRec(pVia->pDRIInfo);
647        pVia->pDRIInfo = NULL;
648        return FALSE;
649    }
650    pDRIInfo->SAREASize = SAREA_MAX;
651#endif
652
653    if (!(pVIADRI = (VIADRIPtr) xcalloc(sizeof(VIADRIRec), 1))) {
654        DRIDestroyInfoRec(pVia->pDRIInfo);
655        pVia->pDRIInfo = NULL;
656        return FALSE;
657    }
658    pDRIInfo->devPrivate = pVIADRI;
659    pDRIInfo->devPrivateSize = sizeof(VIADRIRec);
660    pDRIInfo->contextSize = sizeof(VIADRIContextRec);
661
662    pDRIInfo->CreateContext = VIACreateContext;
663    pDRIInfo->DestroyContext = VIADestroyContext;
664    pDRIInfo->SwapContext = VIADRISwapContext;
665    pDRIInfo->InitBuffers = VIADRIInitBuffers;
666    pDRIInfo->MoveBuffers = VIADRIMoveBuffers;
667    pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
668
669    if (!DRIScreenInit(pScreen, pDRIInfo, &pVia->drmFD)) {
670        xf86DrvMsg(pScreen->myNum, X_ERROR,
671                   "[dri] DRIScreenInit failed.  Disabling DRI.\n");
672        xfree(pDRIInfo->devPrivate);
673        pDRIInfo->devPrivate = NULL;
674        DRIDestroyInfoRec(pVia->pDRIInfo);
675        pVia->pDRIInfo = NULL;
676        pVia->drmFD = -1;
677        return FALSE;
678    }
679
680    if (NULL == (drmVer = drmGetVersion(pVia->drmFD))) {
681        VIADRICloseScreen(pScreen);
682        return FALSE;
683    }
684    pVia->drmVerMajor = drmVer->version_major;
685    pVia->drmVerMinor = drmVer->version_minor;
686    pVia->drmVerPL = drmVer->version_patchlevel;
687
688    if ((drmVer->version_major < drmExpected.major) ||
689        (drmVer->version_major > drmCompat.major) ||
690        ((drmVer->version_major == drmExpected.major) &&
691         (drmVer->version_minor < drmExpected.minor))) {
692        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
693                   "[dri] Kernel drm is not compatible with this driver.\n"
694                   "[dri] Kernel drm version is %d.%d.%d, "
695                   "and I can work with versions %d.%d.x - %d.x.x.\n"
696                   "[dri] Update either this 2D driver or your kernel DRM. "
697                   "Disabling DRI.\n",
698                   drmVer->version_major, drmVer->version_minor,
699                   drmVer->version_patchlevel,
700                   drmExpected.major, drmExpected.minor, drmCompat.major);
701        drmFreeVersion(drmVer);
702        VIADRICloseScreen(pScreen);
703        return FALSE;
704    }
705    drmFreeVersion(drmVer);
706
707    if (!(VIAInitVisualConfigs(pScreen))) {
708        VIADRICloseScreen(pScreen);
709        return FALSE;
710    }
711    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] visual configs initialized.\n");
712
713    /* DRIScreenInit doesn't add all the common mappings.
714     * Add additional mappings here. */
715    if (!VIADRIMapInit(pScreen, pVia)) {
716        VIADRICloseScreen(pScreen);
717        return FALSE;
718    }
719    pVIADRI->regs.size = VIA_MMIO_REGSIZE;
720    pVIADRI->regs.handle = pVia->registerHandle;
721    xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] mmio Registers = 0x%08lx\n",
722               (unsigned long)pVIADRI->regs.handle);
723
724    pVIADRI->drixinerama = FALSE;
725
726    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] mmio mapped.\n");
727
728    return TRUE;
729}
730
731void
732VIADRICloseScreen(ScreenPtr pScreen)
733{
734    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
735    VIAPtr pVia = VIAPTR(pScrn);
736    VIADRIPtr pVIADRI;
737
738    VIADRIRingBufferCleanup(pScrn);
739    if (pVia->agpSize) {
740        drmUnmap(pVia->agpMappedAddr, pVia->agpSize);
741        drmRmMap(pVia->drmFD, pVia->agpHandle);
742        drmAgpUnbind(pVia->drmFD, pVia->agpHandle);
743        xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Freeing agp memory\n");
744        drmAgpFree(pVia->drmFD, pVia->agpHandle);
745        xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Releasing agp module\n");
746        drmAgpRelease(pVia->drmFD);
747    }
748
749    DRICloseScreen(pScreen);
750    VIAFreeLinear(&pVia->driOffScreenMem);
751
752    if (pVia->pDRIInfo) {
753        if ((pVIADRI = (VIADRIPtr) pVia->pDRIInfo->devPrivate)) {
754            VIADRIIrqExit(pScrn, pVIADRI);
755            xfree(pVIADRI);
756            pVia->pDRIInfo->devPrivate = NULL;
757        }
758        DRIDestroyInfoRec(pVia->pDRIInfo);
759        pVia->pDRIInfo = NULL;
760    }
761
762    if (pVia->pVisualConfigs) {
763        xfree(pVia->pVisualConfigs);
764        pVia->pVisualConfigs = NULL;
765    }
766    if (pVia->pVisualConfigsPriv) {
767        xfree(pVia->pVisualConfigsPriv);
768        pVia->pVisualConfigsPriv = NULL;
769    }
770}
771
772/* TODO: xserver receives driver's swapping event and does something
773 *       according the data initialized in this function.
774 */
775static Bool
776VIACreateContext(ScreenPtr pScreen, VisualPtr visual,
777                 drm_context_t hwContext, void *pVisualConfigPriv,
778                 DRIContextType contextStore)
779{
780    return TRUE;
781}
782
783static void
784VIADestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
785                  DRIContextType contextStore)
786{
787}
788
789Bool
790VIADRIFinishScreenInit(ScreenPtr pScreen)
791{
792    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
793    VIAPtr pVia = VIAPTR(pScrn);
794    VIADRIPtr pVIADRI;
795
796    pVia->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
797
798    pVia->IsPCI = !VIADRIAgpInit(pScreen, pVia);
799
800    if (pVia->IsPCI) {
801        VIADRIPciInit(pScreen, pVia);
802        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Using PCI.\n");
803    } else
804        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Using AGP.\n");
805
806    if (!(VIADRIFBInit(pScreen, pVia))) {
807        VIADRICloseScreen(pScreen);
808        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
809                   "[dri] Frame buffer initialization failed.\n");
810        return FALSE;
811    }
812
813    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Frame buffer initialized.\n");
814
815    DRIFinishScreenInit(pScreen);
816
817    if (!VIADRIKernelInit(pScreen, pVia)) {
818        VIADRICloseScreen(pScreen);
819        return FALSE;
820    }
821    xf86DrvMsg(pScreen->myNum, X_INFO, "[dri] Kernel data initialized.\n");
822
823    /* Set SAREA value. */
824    {
825        drm_via_sarea_t *saPriv;
826
827        saPriv = (drm_via_sarea_t *) DRIGetSAREAPrivate(pScreen);
828        assert(saPriv);
829        memset(saPriv, 0, sizeof(*saPriv));
830        saPriv->ctxOwner = -1;
831    }
832    pVIADRI = (VIADRIPtr) pVia->pDRIInfo->devPrivate;
833    pVIADRI->deviceID = pVia->Chipset;
834    pVIADRI->width = pScrn->virtualX;
835    pVIADRI->height = pScrn->virtualY;
836    pVIADRI->mem = pScrn->videoRam * 1024;
837    pVIADRI->bytesPerPixel = (pScrn->bitsPerPixel + 7) / 8;
838    pVIADRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
839    /* TODO */
840    pVIADRI->scrnX = pVIADRI->width;
841    pVIADRI->scrnY = pVIADRI->height;
842
843    /* Initialize IRQ. */
844    if (pVia->DRIIrqEnable)
845        VIADRIIrqInit(pScrn, pVIADRI);
846
847    pVIADRI->ringBufActive = 0;
848    VIADRIRingBufferInit(pScrn);
849    return TRUE;
850}
851
852static void
853VIADRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
854                  DRIContextType oldContextType, void *oldContext,
855                  DRIContextType newContextType, void *newContext)
856{
857#if 0
858    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
859    VIAPtr pVia = VIAPTR(pScrn);
860#endif
861    return;
862}
863
864static void
865VIADRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index)
866{
867#if 0
868    ScreenPtr pScreen = pWin->drawable.pScreen;
869    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
870    VIAPtr pVia = VIAPTR(pScrn);
871#endif
872    return;
873}
874
875static void
876VIADRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg,
877                  RegionPtr prgnSrc, CARD32 index)
878{
879#if 0
880    ScreenPtr pScreen = pParent->drawable.pScreen;
881    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
882    VIAPtr pVia = VIAPTR(pScrn);
883#endif
884    return;
885}
886
887/* Initialize the kernel data structures. */
888static Bool
889VIADRIKernelInit(ScreenPtr pScreen, VIAPtr pVia)
890{
891    drm_via_init_t drmInfo;
892
893    memset(&drmInfo, 0, sizeof(drm_via_init_t));
894    drmInfo.func = VIA_INIT_MAP;
895    drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec);
896    drmInfo.fb_offset = pVia->frameBufferHandle;
897    drmInfo.mmio_offset = pVia->registerHandle;
898
899    if (pVia->IsPCI) {
900        drmInfo.agpAddr = (CARD32) NULL;
901    } else {
902        /*For AMD64*/
903#ifndef __x86_64__
904	drmInfo.agpAddr = (CARD32)pVia->agpAddr;
905#else
906	drmInfo.agpAddr = (CARD64)pVia->agpAddr;
907#endif
908    }
909
910    if ((drmCommandWrite(pVia->drmFD, DRM_VIA_MAP_INIT, &drmInfo,
911                         sizeof(drm_via_init_t))) < 0)
912        return FALSE;
913
914    return TRUE;
915}
916
917/* Add a map for the MMIO registers. */
918static Bool
919VIADRIMapInit(ScreenPtr pScreen, VIAPtr pVia)
920{
921    int flags = DRM_READ_ONLY;
922
923    if (drmAddMap(pVia->drmFD, pVia->MmioBase, VIA_MMIO_REGSIZE,
924                  DRM_REGISTERS, flags, &pVia->registerHandle) < 0) {
925        return FALSE;
926    }
927    xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] register handle = 0x%08lx\n",
928               (unsigned long)pVia->registerHandle);
929    if (drmAddMap(pVia->drmFD, pVia->FrameBufferBase, pVia->videoRambytes,
930                  DRM_FRAME_BUFFER, 0, &pVia->frameBufferHandle) < 0) {
931        return FALSE;
932    }
933    xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] framebuffer handle = 0x%08lx\n",
934               (unsigned long)pVia->frameBufferHandle);
935
936    return TRUE;
937}
938
939#define DRM_VIA_BLIT_MAX_SIZE (2048*2048*4)
940
941static int
942viaDRIFBMemcpy(int fd, unsigned long fbOffset, unsigned char *addr,
943               unsigned long size, Bool toFB)
944{
945    int err;
946    drm_via_dmablit_t blit;
947    unsigned long curSize;
948
949    do {
950        curSize = (size > DRM_VIA_BLIT_MAX_SIZE) ? DRM_VIA_BLIT_MAX_SIZE : size;
951
952        blit.num_lines = 1;
953        blit.line_length = curSize;
954        blit.fb_addr = fbOffset;
955        blit.fb_stride = ALIGN_TO(curSize, 16);
956        blit.mem_addr = addr;
957        blit.mem_stride = blit.fb_stride;
958        blit.to_fb = (toFB) ? 1 : 0;
959
960        do {
961            err = drmCommandWriteRead(fd, DRM_VIA_DMA_BLIT,
962                                      &blit, sizeof(blit));
963        } while (-EAGAIN == err);
964        if (err)
965            return err;
966
967        do {
968            err = drmCommandWriteRead(fd, DRM_VIA_BLIT_SYNC,
969                                      &blit.sync, sizeof(blit.sync));
970        } while (-EAGAIN == err);
971        if (err)
972            return err;
973
974        fbOffset += curSize;
975        addr += curSize;
976        size -= curSize;
977
978    } while (size > 0);
979    return 0;
980}
981
982
983void
984viaDRIOffscreenSave(ScrnInfoPtr pScrn)
985{
986    VIAPtr pVia = VIAPTR(pScrn);
987    VIADRIPtr pVIADRI = pVia->pDRIInfo->devPrivate;
988    unsigned char *saveAddr = pVia->FBBase + pVIADRI->fbOffset;
989    unsigned long saveSize = pVIADRI->fbSize;
990    unsigned long curSize;
991    int err;
992
993    if (pVia->driOffScreenSave)
994        free(pVia->driOffScreenSave);
995
996    pVia->driOffScreenSave = malloc(saveSize + 16);
997    if (pVia->driOffScreenSave) {
998        if ((pVia->drmVerMajor == 2) && (pVia->drmVerMinor >= 8)) {
999            err = viaDRIFBMemcpy(pVia->drmFD, pVIADRI->fbOffset,
1000                                 (unsigned char *)
1001                                 ALIGN_TO((unsigned long)
1002                                          pVia->driOffScreenSave, 16),
1003                                 saveSize, FALSE);
1004            if (!err)
1005                return;
1006
1007            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1008                       "Hardware backup of DRI offscreen memory failed: %s.\n"
1009                       "\tUsing slow software backup instead.\n",
1010                       strerror(-err));
1011        }
1012        memcpy((void *)ALIGN_TO((unsigned long)pVia->driOffScreenSave, 16),
1013               saveAddr, saveSize);
1014
1015    } else {
1016        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1017                   "Out of memory trying to backup DRI offscreen memory.\n");
1018    }
1019    return;
1020}
1021
1022void
1023viaDRIOffscreenRestore(ScrnInfoPtr pScrn)
1024{
1025    VIAPtr pVia = VIAPTR(pScrn);
1026    VIADRIPtr pVIADRI = pVia->pDRIInfo->devPrivate;
1027
1028    unsigned char *saveAddr = pVia->FBBase + pVIADRI->fbOffset;
1029    unsigned long saveSize = pVIADRI->fbSize;
1030
1031    if (pVia->driOffScreenSave) {
1032        memcpy(saveAddr,
1033               (void *)ALIGN_TO((unsigned long)pVia->driOffScreenSave, 16),
1034               saveSize);
1035        free(pVia->driOffScreenSave);
1036        pVia->driOffScreenSave = NULL;
1037    }
1038}
1039