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