via_dri.c revision 7e6fb56f
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    pDRIInfo->busIdString = xalloc(64);
603    sprintf(pDRIInfo->busIdString, "PCI:%d:%d:%d",
604#ifdef XSERVER_LIBPCIACCESS
605            ((pVia->PciInfo->domain << 8) | pVia->PciInfo->bus),
606            pVia->PciInfo->dev, pVia->PciInfo->func
607#else
608            ((pciConfigPtr)pVia->PciInfo->thisCard)->busnum,
609            ((pciConfigPtr)pVia->PciInfo->thisCard)->devnum,
610            ((pciConfigPtr)pVia->PciInfo->thisCard)->funcnum
611#endif
612           );
613    pDRIInfo->ddxDriverMajorVersion = VIA_DRIDDX_VERSION_MAJOR;
614    pDRIInfo->ddxDriverMinorVersion = VIA_DRIDDX_VERSION_MINOR;
615    pDRIInfo->ddxDriverPatchVersion = VIA_DRIDDX_VERSION_PATCH;
616#if (DRIINFO_MAJOR_VERSION == 5)
617    pDRIInfo->frameBufferPhysicalAddress = (pointer) pVia->FrameBufferBase;
618#else
619    pDRIInfo->frameBufferPhysicalAddress = pVia->FrameBufferBase;
620#endif
621    pDRIInfo->frameBufferSize = pVia->videoRambytes;
622
623    pDRIInfo->frameBufferStride = (pScrn->displayWidth *
624                                   pScrn->bitsPerPixel / 8);
625    pDRIInfo->ddxDrawableTableEntry = VIA_MAX_DRAWABLES;
626
627    if (SAREA_MAX_DRAWABLES < VIA_MAX_DRAWABLES)
628        pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES;
629    else
630        pDRIInfo->maxDrawableTableEntry = VIA_MAX_DRAWABLES;
631
632#ifdef NOT_DONE
633    /* FIXME: need to extend DRI protocol to pass this size back to client
634     * for SAREA mapping that includes a device private record. */
635    pDRIInfo->SAREASize = ((sizeof(XF86DRISAREARec) + 0xfff) & 0x1000); /* round to page */
636    /* + shared memory device private rec */
637#else
638    /* For now the mapping works by using a fixed size defined
639     * in the SAREA header. */
640    if (sizeof(XF86DRISAREARec) + sizeof(drm_via_sarea_t) > SAREA_MAX) {
641        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Data does not fit in SAREA\n");
642        DRIDestroyInfoRec(pVia->pDRIInfo);
643        pVia->pDRIInfo = NULL;
644        return FALSE;
645    }
646    pDRIInfo->SAREASize = SAREA_MAX;
647#endif
648
649    if (!(pVIADRI = (VIADRIPtr) xcalloc(sizeof(VIADRIRec), 1))) {
650        DRIDestroyInfoRec(pVia->pDRIInfo);
651        pVia->pDRIInfo = NULL;
652        return FALSE;
653    }
654    pDRIInfo->devPrivate = pVIADRI;
655    pDRIInfo->devPrivateSize = sizeof(VIADRIRec);
656    pDRIInfo->contextSize = sizeof(VIADRIContextRec);
657
658    pDRIInfo->CreateContext = VIACreateContext;
659    pDRIInfo->DestroyContext = VIADestroyContext;
660    pDRIInfo->SwapContext = VIADRISwapContext;
661    pDRIInfo->InitBuffers = VIADRIInitBuffers;
662    pDRIInfo->MoveBuffers = VIADRIMoveBuffers;
663    pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
664
665    if (!DRIScreenInit(pScreen, pDRIInfo, &pVia->drmFD)) {
666        xf86DrvMsg(pScreen->myNum, X_ERROR,
667                   "[dri] DRIScreenInit failed.  Disabling DRI.\n");
668        xfree(pDRIInfo->devPrivate);
669        pDRIInfo->devPrivate = NULL;
670        DRIDestroyInfoRec(pVia->pDRIInfo);
671        pVia->pDRIInfo = NULL;
672        pVia->drmFD = -1;
673        return FALSE;
674    }
675
676    if (NULL == (drmVer = drmGetVersion(pVia->drmFD))) {
677        VIADRICloseScreen(pScreen);
678        return FALSE;
679    }
680    pVia->drmVerMajor = drmVer->version_major;
681    pVia->drmVerMinor = drmVer->version_minor;
682    pVia->drmVerPL = drmVer->version_patchlevel;
683
684    if ((drmVer->version_major < drmExpected.major) ||
685        (drmVer->version_major > drmCompat.major) ||
686        ((drmVer->version_major == drmExpected.major) &&
687         (drmVer->version_minor < drmExpected.minor))) {
688        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
689                   "[dri] Kernel drm is not compatible with this driver.\n"
690                   "[dri] Kernel drm version is %d.%d.%d, "
691                   "and I can work with versions %d.%d.x - %d.x.x.\n"
692                   "[dri] Update either this 2D driver or your kernel DRM. "
693                   "Disabling DRI.\n",
694                   drmVer->version_major, drmVer->version_minor,
695                   drmVer->version_patchlevel,
696                   drmExpected.major, drmExpected.minor, drmCompat.major);
697        drmFreeVersion(drmVer);
698        VIADRICloseScreen(pScreen);
699        return FALSE;
700    }
701    drmFreeVersion(drmVer);
702
703    if (!(VIAInitVisualConfigs(pScreen))) {
704        VIADRICloseScreen(pScreen);
705        return FALSE;
706    }
707    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] visual configs initialized.\n");
708
709    /* DRIScreenInit doesn't add all the common mappings.
710     * Add additional mappings here. */
711    if (!VIADRIMapInit(pScreen, pVia)) {
712        VIADRICloseScreen(pScreen);
713        return FALSE;
714    }
715    pVIADRI->regs.size = VIA_MMIO_REGSIZE;
716    pVIADRI->regs.handle = pVia->registerHandle;
717    xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] mmio Registers = 0x%08lx\n",
718               (unsigned long)pVIADRI->regs.handle);
719
720    pVIADRI->drixinerama = FALSE;
721
722    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] mmio mapped.\n");
723
724    return TRUE;
725}
726
727void
728VIADRICloseScreen(ScreenPtr pScreen)
729{
730    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
731    VIAPtr pVia = VIAPTR(pScrn);
732    VIADRIPtr pVIADRI;
733
734    VIADRIRingBufferCleanup(pScrn);
735    if (pVia->agpSize) {
736        drmUnmap(pVia->agpMappedAddr, pVia->agpSize);
737        drmRmMap(pVia->drmFD, pVia->agpHandle);
738        drmAgpUnbind(pVia->drmFD, pVia->agpHandle);
739        xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Freeing agp memory\n");
740        drmAgpFree(pVia->drmFD, pVia->agpHandle);
741        xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Releasing agp module\n");
742        drmAgpRelease(pVia->drmFD);
743    }
744
745    DRICloseScreen(pScreen);
746    VIAFreeLinear(&pVia->driOffScreenMem);
747
748    if (pVia->pDRIInfo) {
749        if ((pVIADRI = (VIADRIPtr) pVia->pDRIInfo->devPrivate)) {
750            VIADRIIrqExit(pScrn, pVIADRI);
751            xfree(pVIADRI);
752            pVia->pDRIInfo->devPrivate = NULL;
753        }
754        DRIDestroyInfoRec(pVia->pDRIInfo);
755        pVia->pDRIInfo = NULL;
756    }
757
758    if (pVia->pVisualConfigs) {
759        xfree(pVia->pVisualConfigs);
760        pVia->pVisualConfigs = NULL;
761    }
762    if (pVia->pVisualConfigsPriv) {
763        xfree(pVia->pVisualConfigsPriv);
764        pVia->pVisualConfigsPriv = NULL;
765    }
766}
767
768/* TODO: xserver receives driver's swapping event and does something
769 *       according the data initialized in this function.
770 */
771static Bool
772VIACreateContext(ScreenPtr pScreen, VisualPtr visual,
773                 drm_context_t hwContext, void *pVisualConfigPriv,
774                 DRIContextType contextStore)
775{
776    return TRUE;
777}
778
779static void
780VIADestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
781                  DRIContextType contextStore)
782{
783}
784
785Bool
786VIADRIFinishScreenInit(ScreenPtr pScreen)
787{
788    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
789    VIAPtr pVia = VIAPTR(pScrn);
790    VIADRIPtr pVIADRI;
791
792    pVia->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
793
794    pVia->IsPCI = !VIADRIAgpInit(pScreen, pVia);
795
796    if (pVia->IsPCI) {
797        VIADRIPciInit(pScreen, pVia);
798        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Using PCI.\n");
799    } else
800        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Using AGP.\n");
801
802    if (!(VIADRIFBInit(pScreen, pVia))) {
803        VIADRICloseScreen(pScreen);
804        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
805                   "[dri] Frame buffer initialization failed.\n");
806        return FALSE;
807    }
808
809    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Frame buffer initialized.\n");
810
811    DRIFinishScreenInit(pScreen);
812
813    if (!VIADRIKernelInit(pScreen, pVia)) {
814        VIADRICloseScreen(pScreen);
815        return FALSE;
816    }
817    xf86DrvMsg(pScreen->myNum, X_INFO, "[dri] Kernel data initialized.\n");
818
819    /* Set SAREA value. */
820    {
821        drm_via_sarea_t *saPriv;
822
823        saPriv = (drm_via_sarea_t *) DRIGetSAREAPrivate(pScreen);
824        assert(saPriv);
825        memset(saPriv, 0, sizeof(*saPriv));
826        saPriv->ctxOwner = -1;
827    }
828    pVIADRI = (VIADRIPtr) pVia->pDRIInfo->devPrivate;
829    pVIADRI->deviceID = pVia->Chipset;
830    pVIADRI->width = pScrn->virtualX;
831    pVIADRI->height = pScrn->virtualY;
832    pVIADRI->mem = pScrn->videoRam * 1024;
833    pVIADRI->bytesPerPixel = (pScrn->bitsPerPixel + 7) / 8;
834    pVIADRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
835    /* TODO */
836    pVIADRI->scrnX = pVIADRI->width;
837    pVIADRI->scrnY = pVIADRI->height;
838
839    /* Initialize IRQ. */
840    if (pVia->DRIIrqEnable)
841        VIADRIIrqInit(pScrn, pVIADRI);
842
843    pVIADRI->ringBufActive = 0;
844    VIADRIRingBufferInit(pScrn);
845    return TRUE;
846}
847
848static void
849VIADRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
850                  DRIContextType oldContextType, void *oldContext,
851                  DRIContextType newContextType, void *newContext)
852{
853#if 0
854    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
855    VIAPtr pVia = VIAPTR(pScrn);
856#endif
857    return;
858}
859
860static void
861VIADRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index)
862{
863#if 0
864    ScreenPtr pScreen = pWin->drawable.pScreen;
865    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
866    VIAPtr pVia = VIAPTR(pScrn);
867#endif
868    return;
869}
870
871static void
872VIADRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg,
873                  RegionPtr prgnSrc, CARD32 index)
874{
875#if 0
876    ScreenPtr pScreen = pParent->drawable.pScreen;
877    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
878    VIAPtr pVia = VIAPTR(pScrn);
879#endif
880    return;
881}
882
883/* Initialize the kernel data structures. */
884static Bool
885VIADRIKernelInit(ScreenPtr pScreen, VIAPtr pVia)
886{
887    drm_via_init_t drmInfo;
888
889    memset(&drmInfo, 0, sizeof(drm_via_init_t));
890    drmInfo.func = VIA_INIT_MAP;
891    drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec);
892    drmInfo.fb_offset = pVia->frameBufferHandle;
893    drmInfo.mmio_offset = pVia->registerHandle;
894
895    if (pVia->IsPCI) {
896        drmInfo.agpAddr = (CARD32) NULL;
897    } else {
898        /*For AMD64*/
899#ifndef __x86_64__
900	drmInfo.agpAddr = (CARD32)pVia->agpAddr;
901#else
902	drmInfo.agpAddr = (CARD64)pVia->agpAddr;
903#endif
904    }
905
906    if ((drmCommandWrite(pVia->drmFD, DRM_VIA_MAP_INIT, &drmInfo,
907                         sizeof(drm_via_init_t))) < 0)
908        return FALSE;
909
910    return TRUE;
911}
912
913/* Add a map for the MMIO registers. */
914static Bool
915VIADRIMapInit(ScreenPtr pScreen, VIAPtr pVia)
916{
917    int flags = DRM_READ_ONLY;
918
919    if (drmAddMap(pVia->drmFD, pVia->MmioBase, VIA_MMIO_REGSIZE,
920                  DRM_REGISTERS, flags, &pVia->registerHandle) < 0) {
921        return FALSE;
922    }
923    xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] register handle = 0x%08lx\n",
924               (unsigned long)pVia->registerHandle);
925    if (drmAddMap(pVia->drmFD, pVia->FrameBufferBase, pVia->videoRambytes,
926                  DRM_FRAME_BUFFER, 0, &pVia->frameBufferHandle) < 0) {
927        return FALSE;
928    }
929    xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] framebuffer handle = 0x%08lx\n",
930               (unsigned long)pVia->frameBufferHandle);
931
932    return TRUE;
933}
934
935#define DRM_VIA_BLIT_MAX_SIZE (2048*2048*4)
936
937static int
938viaDRIFBMemcpy(int fd, unsigned long fbOffset, unsigned char *addr,
939               unsigned long size, Bool toFB)
940{
941    int err;
942    drm_via_dmablit_t blit;
943    unsigned long curSize;
944
945    do {
946        curSize = (size > DRM_VIA_BLIT_MAX_SIZE) ? DRM_VIA_BLIT_MAX_SIZE : size;
947
948        blit.num_lines = 1;
949        blit.line_length = curSize;
950        blit.fb_addr = fbOffset;
951        blit.fb_stride = ALIGN_TO(curSize, 16);
952        blit.mem_addr = addr;
953        blit.mem_stride = blit.fb_stride;
954        blit.to_fb = (toFB) ? 1 : 0;
955
956        do {
957            err = drmCommandWriteRead(fd, DRM_VIA_DMA_BLIT,
958                                      &blit, sizeof(blit));
959        } while (-EAGAIN == err);
960        if (err)
961            return err;
962
963        do {
964            err = drmCommandWriteRead(fd, DRM_VIA_BLIT_SYNC,
965                                      &blit.sync, sizeof(blit.sync));
966        } while (-EAGAIN == err);
967        if (err)
968            return err;
969
970        fbOffset += curSize;
971        addr += curSize;
972        size -= curSize;
973
974    } while (size > 0);
975    return 0;
976}
977
978
979void
980viaDRIOffscreenSave(ScrnInfoPtr pScrn)
981{
982    VIAPtr pVia = VIAPTR(pScrn);
983    VIADRIPtr pVIADRI = pVia->pDRIInfo->devPrivate;
984    unsigned char *saveAddr = pVia->FBBase + pVIADRI->fbOffset;
985    unsigned long saveSize = pVIADRI->fbSize;
986    unsigned long curSize;
987    int err;
988
989    if (pVia->driOffScreenSave)
990        free(pVia->driOffScreenSave);
991
992    pVia->driOffScreenSave = malloc(saveSize + 16);
993    if (pVia->driOffScreenSave) {
994        if ((pVia->drmVerMajor == 2) && (pVia->drmVerMinor >= 8)) {
995            err = viaDRIFBMemcpy(pVia->drmFD, pVIADRI->fbOffset,
996                                 (unsigned char *)
997                                 ALIGN_TO((unsigned long)
998                                          pVia->driOffScreenSave, 16),
999                                 saveSize, FALSE);
1000            if (!err)
1001                return;
1002
1003            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1004                       "Hardware backup of DRI offscreen memory failed: %s.\n"
1005                       "\tUsing slow software backup instead.\n",
1006                       strerror(-err));
1007        }
1008        memcpy((void *)ALIGN_TO((unsigned long)pVia->driOffScreenSave, 16),
1009               saveAddr, saveSize);
1010
1011    } else {
1012        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1013                   "Out of memory trying to backup DRI offscreen memory.\n");
1014    }
1015    return;
1016}
1017
1018void
1019viaDRIOffscreenRestore(ScrnInfoPtr pScrn)
1020{
1021    VIAPtr pVia = VIAPTR(pScrn);
1022    VIADRIPtr pVIADRI = pVia->pDRIInfo->devPrivate;
1023
1024    unsigned char *saveAddr = pVia->FBBase + pVIADRI->fbOffset;
1025    unsigned long saveSize = pVIADRI->fbSize;
1026
1027    if (pVia->driOffScreenSave) {
1028        memcpy(saveAddr,
1029               (void *)ALIGN_TO((unsigned long)pVia->driOffScreenSave, 16),
1030               saveSize);
1031        free(pVia->driOffScreenSave);
1032        pVia->driOffScreenSave = NULL;
1033    }
1034}
1035