1 /*
2  * Copyright 2005-2015 The Openchrome Project
3  *                     [https://www.freedesktop.org/wiki/Openchrome]
4  * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
5  * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, 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 
66 extern void GlxSetVisualConfigs(int nconfigs,
67                                 __GLXvisualConfig * configs,
68                                 void **configprivs);
69 
70 typedef struct
71 {
72     int major;
73     int minor;
74     int patchlevel;
75 } ViaDRMVersion;
76 
77 static char VIAKernelDriverName[] = "via";
78 static char VIAClientDriverName[] = "unichrome";
79 static const ViaDRMVersion drmExpected = { 1, 3, 0 };
80 static const ViaDRMVersion drmCompat = { 2, 0, 0 };
81 
82 static Bool VIAInitVisualConfigs(ScreenPtr pScreen);
83 static Bool VIADRIMapInit(ScreenPtr pScreen, VIAPtr pVia);
84 
85 static Bool VIACreateContext(ScreenPtr pScreen, VisualPtr visual,
86                              drm_context_t hwContext, void *pVisualConfigPriv,
87                              DRIContextType contextStore);
88 static void VIADestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
89                               DRIContextType contextStore);
90 static void VIADRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
91                               DRIContextType readContextType,
92                               void *readContextStore,
93                               DRIContextType writeContextType,
94                               void *writeContextStore);
95 static void VIADRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index);
96 static void VIADRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg,
97                               RegionPtr prgnSrc, CARD32 index);
98 
99 void
kickVblank(ScrnInfoPtr pScrn)100 kickVblank(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 
116 static void
VIADRIIrqInit(ScrnInfoPtr pScrn,VIADRIPtr pVIADRI)117 VIADRIIrqInit(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 
145 static void
VIADRIIrqExit(ScrnInfoPtr pScrn,VIADRIPtr pVIADRI)146 VIADRIIrqExit(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 
161 void
VIADRIRingBufferCleanup(ScrnInfoPtr pScrn)162 VIADRIRingBufferCleanup(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 
182 Bool
VIADRIRingBufferInit(ScrnInfoPtr pScrn)183 VIADRIRingBufferInit(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 
232 static Bool
VIASetAgpMode(ScrnInfoPtr pScrn)233 VIASetAgpMode(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 
263 static Bool
VIADRIAgpInit(ScrnInfoPtr pScrn)264 VIADRIAgpInit(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 
349 static Bool
VIADRIFBInit(ScrnInfoPtr pScrn)350 VIADRIFBInit(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 
369 static Bool
VIAInitVisualConfigs(ScreenPtr pScreen)370 VIAInitVisualConfigs(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 
502 Bool
VIADRI1ScreenInit(ScreenPtr pScreen)503 VIADRI1ScreenInit(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     pDRIInfo->busIdString = DRICreatePCIBusID(pVia->PciInfo);
558     pDRIInfo->ddxDriverMajorVersion = VIA_DRIDDX_VERSION_MAJOR;
559     pDRIInfo->ddxDriverMinorVersion = VIA_DRIDDX_VERSION_MINOR;
560     pDRIInfo->ddxDriverPatchVersion = VIA_DRIDDX_VERSION_PATCH;
561 #if (DRIINFO_MAJOR_VERSION == 5)
562     pDRIInfo->frameBufferPhysicalAddress = (pointer) pVia->FrameBufferBase;
563 #else
564     pDRIInfo->frameBufferPhysicalAddress = pVia->FrameBufferBase;
565 #endif
566     pDRIInfo->frameBufferSize = pVia->videoRambytes;
567 
568     pDRIInfo->frameBufferStride = (pScrn->displayWidth *
569                                    pScrn->bitsPerPixel / 8);
570     pDRIInfo->ddxDrawableTableEntry = VIA_MAX_DRAWABLES;
571 
572     if (SAREA_MAX_DRAWABLES < VIA_MAX_DRAWABLES)
573         pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES;
574     else
575         pDRIInfo->maxDrawableTableEntry = VIA_MAX_DRAWABLES;
576 
577 #ifdef NOT_DONE
578     /* FIXME: need to extend DRI protocol to pass this size back to client
579      * for SAREA mapping that includes a device private record. */
580     pDRIInfo->SAREASize = ((sizeof(XF86DRISAREARec) + 0xfff) & 0x1000); /* round to page */
581     /* + shared memory device private rec */
582 #else
583     /* For now the mapping works by using a fixed size defined
584      * in the SAREA header. */
585     if (sizeof(XF86DRISAREARec) + sizeof(drm_via_sarea_t) > SAREA_MAX) {
586         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Data does not fit in SAREA\n");
587         DRIDestroyInfoRec(pVia->pDRIInfo);
588         pVia->pDRIInfo = NULL;
589         return FALSE;
590     }
591     pDRIInfo->SAREASize = SAREA_MAX;
592 #endif
593 
594     if (!(pVIADRI = (VIADRIPtr) calloc(sizeof(VIADRIRec), 1))) {
595         DRIDestroyInfoRec(pVia->pDRIInfo);
596         pVia->pDRIInfo = NULL;
597         return FALSE;
598     }
599     pDRIInfo->devPrivate = pVIADRI;
600     pDRIInfo->devPrivateSize = sizeof(VIADRIRec);
601     pDRIInfo->contextSize = sizeof(VIADRIContextRec);
602 
603     pDRIInfo->CreateContext = VIACreateContext;
604     pDRIInfo->DestroyContext = VIADestroyContext;
605     pDRIInfo->SwapContext = VIADRISwapContext;
606     pDRIInfo->InitBuffers = VIADRIInitBuffers;
607     pDRIInfo->MoveBuffers = VIADRIMoveBuffers;
608     pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
609 
610     if (!DRIScreenInit(pScreen, pDRIInfo, &pVia->drmmode.fd)) {
611         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
612                    "[dri] DRIScreenInit failed.  Disabling DRI.\n");
613         free(pDRIInfo->devPrivate);
614         pDRIInfo->devPrivate = NULL;
615         DRIDestroyInfoRec(pVia->pDRIInfo);
616         pVia->pDRIInfo = NULL;
617         pVia->drmmode.fd = -1;
618         return FALSE;
619     }
620 
621     if (!(VIAInitVisualConfigs(pScreen))) {
622         VIADRICloseScreen(pScreen);
623         return FALSE;
624     }
625     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] visual configs initialized.\n");
626 
627     /* DRIScreenInit doesn't add all the common mappings.
628      * Add additional mappings here. */
629     if (!VIADRIMapInit(pScreen, pVia)) {
630         VIADRICloseScreen(pScreen);
631         return FALSE;
632     }
633     pVIADRI->regs.size = VIA_MMIO_REGSIZE;
634     pVIADRI->regs.handle = pVia->registerHandle;
635     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] mmio Registers = 0x%08lx\n",
636                (unsigned long)pVIADRI->regs.handle);
637 
638     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] mmio mapped.\n");
639     return TRUE;
640 }
641 
642 void
VIADRICloseScreen(ScreenPtr pScreen)643 VIADRICloseScreen(ScreenPtr pScreen)
644 {
645     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
646     VIAPtr pVia = VIAPTR(pScrn);
647     VIADRIPtr pVIADRI;
648 
649     VIADRIRingBufferCleanup(pScrn);
650     if (pVia->agpSize) {
651         drmUnmap(pVia->agpMappedAddr, pVia->agpSize);
652         drmRmMap(pVia->drmmode.fd, pVia->agpHandle);
653         drmAgpUnbind(pVia->drmmode.fd, pVia->agpHandle);
654         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Freeing agp memory\n");
655         drmAgpFree(pVia->drmmode.fd, pVia->agpHandle);
656         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Releasing agp module\n");
657         drmAgpRelease(pVia->drmmode.fd);
658     }
659 
660     DRICloseScreen(pScreen);
661     drm_bo_free(pScrn, pVia->driOffScreenMem);
662 
663     if (pVia->pDRIInfo) {
664         if ((pVIADRI = (VIADRIPtr) pVia->pDRIInfo->devPrivate)) {
665             VIADRIIrqExit(pScrn, pVIADRI);
666             free(pVIADRI);
667             pVia->pDRIInfo->devPrivate = NULL;
668         }
669         DRIDestroyInfoRec(pVia->pDRIInfo);
670         pVia->pDRIInfo = NULL;
671     }
672 
673     if (pVia->pVisualConfigs) {
674         free(pVia->pVisualConfigs);
675         pVia->pVisualConfigs = NULL;
676     }
677     if (pVia->pVisualConfigsPriv) {
678         free(pVia->pVisualConfigsPriv);
679         pVia->pVisualConfigsPriv = NULL;
680     }
681 }
682 
683 /* TODO: xserver receives driver's swapping event and does something
684  *       according the data initialized in this function.
685  */
686 static Bool
VIACreateContext(ScreenPtr pScreen,VisualPtr visual,drm_context_t hwContext,void * pVisualConfigPriv,DRIContextType contextStore)687 VIACreateContext(ScreenPtr pScreen, VisualPtr visual,
688                  drm_context_t hwContext, void *pVisualConfigPriv,
689                  DRIContextType contextStore)
690 {
691     return TRUE;
692 }
693 
694 static void
VIADestroyContext(ScreenPtr pScreen,drm_context_t hwContext,DRIContextType contextStore)695 VIADestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
696                   DRIContextType contextStore)
697 {
698 }
699 
700 Bool
VIADRIFinishScreenInit(ScreenPtr pScreen)701 VIADRIFinishScreenInit(ScreenPtr pScreen)
702 {
703     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
704     VIAPtr pVia = VIAPTR(pScrn);
705     VIADRIPtr pVIADRI;
706 
707     pVia->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
708     pVia->agpDMA = FALSE;
709 
710     pVIADRI = (VIADRIPtr) pVia->pDRIInfo->devPrivate;
711     pVIADRI->drixinerama = FALSE;
712 
713     if (pVia->driSize < pVia->Bpl) {
714         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
715                    "[drm] No DRM framebuffer heap available.\n"
716                    "[drm] Please increase the frame buffer\n"
717                    "[drm] memory area in the BIOS. Disabling DRI.\n");
718         return FALSE;
719     }
720     if (pVia->driSize < 3 * (pScrn->virtualY * pVia->Bpl)) {
721         xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
722                    "[drm] The DRM heap and pixmap cache memory may be too\n"
723                    "[drm] small for optimal performance. Please increase\n"
724                    "[drm] the frame buffer memory area in the BIOS.\n");
725     }
726 
727     pVia->driOffScreenMem = drm_bo_alloc(pScrn, pVia->driSize, 16, TTM_PL_FLAG_VRAM);
728 
729     DRIFinishScreenInit(pScreen);
730 
731     /* Set SAREA value. */
732     {
733         drm_via_sarea_t *saPriv;
734 
735         saPriv = (drm_via_sarea_t *) DRIGetSAREAPrivate(pScreen);
736         assert(saPriv);
737         memset(saPriv, 0, sizeof(*saPriv));
738         saPriv->ctxOwner = -1;
739     }
740     pVIADRI->deviceID = pVia->Chipset;
741     pVIADRI->width = pScrn->virtualX;
742     pVIADRI->height = pScrn->virtualY;
743     pVIADRI->mem = pScrn->videoRam * 1024;
744     pVIADRI->bytesPerPixel = (pScrn->bitsPerPixel + 7) / 8;
745     pVIADRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
746     /* TODO */
747     pVIADRI->scrnX = pVIADRI->width;
748     pVIADRI->scrnY = pVIADRI->height;
749 
750     /* Initialize IRQ. */
751     if (pVia->DRIIrqEnable)
752         VIADRIIrqInit(pScrn, pVIADRI);
753 
754     pVIADRI->ringBufActive = 0;
755     VIADRIRingBufferInit(pScrn);
756     pVia->agpDMA = pVia->dma2d && pVIADRI->ringBufActive;
757     return TRUE;
758 }
759 
760 static void
VIADRISwapContext(ScreenPtr pScreen,DRISyncType syncType,DRIContextType oldContextType,void * oldContext,DRIContextType newContextType,void * newContext)761 VIADRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
762                   DRIContextType oldContextType, void *oldContext,
763                   DRIContextType newContextType, void *newContext)
764 {
765 #if 0
766     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
767     VIAPtr pVia = VIAPTR(pScrn);
768 #endif
769     return;
770 }
771 
772 static void
VIADRIInitBuffers(WindowPtr pWin,RegionPtr prgn,CARD32 index)773 VIADRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index)
774 {
775 #if 0
776     ScreenPtr pScreen = pWin->drawable.pScreen;
777     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
778     VIAPtr pVia = VIAPTR(pScrn);
779 #endif
780     return;
781 }
782 
783 static void
VIADRIMoveBuffers(WindowPtr pParent,DDXPointRec ptOldOrg,RegionPtr prgnSrc,CARD32 index)784 VIADRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg,
785                   RegionPtr prgnSrc, CARD32 index)
786 {
787 #if 0
788     ScreenPtr pScreen = pParent->drawable.pScreen;
789     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
790     VIAPtr pVia = VIAPTR(pScrn);
791 #endif
792     return;
793 }
794 
795 /* Initialize the kernel data structures. */
796 Bool
VIADRIKernelInit(ScrnInfoPtr pScrn)797 VIADRIKernelInit(ScrnInfoPtr pScrn)
798 {
799     VIAPtr pVia = VIAPTR(pScrn);
800     drm_via_init_t drmInfo;
801 
802     pVia->IsPCI = !VIADRIAgpInit(pScrn);
803     if (pVia->IsPCI)
804         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Using PCI.\n");
805     else
806         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Using AGP.\n");
807 
808     if (!(VIADRIFBInit(pScrn))) {
809         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
810                    "[dri] Frame buffer initialization failed.\n");
811         return FALSE;
812     }
813     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Frame buffer initialized.\n");
814 
815     memset(&drmInfo, 0, sizeof(drm_via_init_t));
816     drmInfo.func = VIA_INIT_MAP;
817     drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec);
818     drmInfo.fb_offset = pVia->frameBufferHandle;
819     drmInfo.mmio_offset = pVia->registerHandle;
820 
821     if (pVia->IsPCI) {
822         drmInfo.agpAddr = 0;
823     } else {
824         /*For AMD64*/
825 #ifndef __x86_64__
826 	    drmInfo.agpAddr = (CARD32)pVia->agpAddr;
827 #else
828 	    drmInfo.agpAddr = (CARD64)pVia->agpAddr;
829 #endif
830     }
831 
832     if ((drmCommandWrite(pVia->drmmode.fd, DRM_VIA_MAP_INIT, &drmInfo,
833                          sizeof(drm_via_init_t))) < 0)
834         return FALSE;
835 
836     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Kernel data initialized.\n");
837     return TRUE;
838 }
839 
840 /* Add a map for the MMIO registers. */
841 static Bool
VIADRIMapInit(ScreenPtr pScreen,VIAPtr pVia)842 VIADRIMapInit(ScreenPtr pScreen, VIAPtr pVia)
843 {
844     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
845     int flags = DRM_READ_ONLY;
846 
847     if (drmAddMap(pVia->drmmode.fd, pVia->MmioBase, VIA_MMIO_REGSIZE,
848                   DRM_REGISTERS, flags, &pVia->registerHandle) < 0) {
849         return FALSE;
850     }
851     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] register handle = 0x%08lx\n",
852                (unsigned long)pVia->registerHandle);
853     if (drmAddMap(pVia->drmmode.fd, pVia->FrameBufferBase, pVia->videoRambytes,
854                   DRM_FRAME_BUFFER, 0, &pVia->frameBufferHandle) < 0) {
855         return FALSE;
856     }
857     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] framebuffer handle = 0x%08lx\n",
858                (unsigned long)pVia->frameBufferHandle);
859 
860     return TRUE;
861 }
862 
863 #define DRM_VIA_BLIT_MAX_SIZE (2048*2048*4)
864 
865 static int
viaDRIFBMemcpy(int fd,struct buffer_object * vram,unsigned char * addr,Bool toFB)866 viaDRIFBMemcpy(int fd, struct buffer_object *vram, unsigned char *addr,
867                Bool toFB)
868 {
869     unsigned long fbOffset = vram->offset, size = vram->size, curSize;
870     drm_via_dmablit_t blit;
871     int err;
872 
873     do {
874         curSize = (size > DRM_VIA_BLIT_MAX_SIZE) ? DRM_VIA_BLIT_MAX_SIZE : size;
875 
876         blit.num_lines = 1;
877         blit.line_length = curSize;
878         blit.fb_addr = fbOffset;
879         blit.fb_stride = ALIGN_TO(curSize, 16);
880         blit.mem_addr = addr;
881         blit.mem_stride = blit.fb_stride;
882         blit.to_fb = (toFB) ? 1 : 0;
883 
884         do {
885             err = drmCommandWriteRead(fd, DRM_VIA_DMA_BLIT,
886                                       &blit, sizeof(blit));
887         } while (-EAGAIN == err);
888         if (err)
889             return err;
890 
891         do {
892             err = drmCommandWriteRead(fd, DRM_VIA_BLIT_SYNC,
893                                       &blit.sync, sizeof(blit.sync));
894         } while (-EAGAIN == err);
895         if (err)
896             return err;
897 
898         fbOffset += curSize;
899         addr += curSize;
900         size -= curSize;
901 
902     } while (size > 0);
903     return 0;
904 }
905 
906 void
viaDRIOffscreenSave(ScrnInfoPtr pScrn)907 viaDRIOffscreenSave(ScrnInfoPtr pScrn)
908 {
909     VIAPtr pVia = VIAPTR(pScrn);
910     unsigned long srcSize = pVia->driOffScreenMem->size;
911     int err;
912 
913     if (pVia->driOffScreenSave)
914         free(pVia->driOffScreenSave);
915 
916     pVia->driOffScreenSave = malloc(srcSize + 16);
917     if (pVia->driOffScreenSave) {
918         void *dst, *src = drm_bo_map(pScrn, pVia->driOffScreenMem);
919 
920         dst = (void *) ALIGN_TO((unsigned long) pVia->driOffScreenSave, 16);
921         if ((pVia->drmVerMajor == 2) && (pVia->drmVerMinor >= 8)) {
922             err = viaDRIFBMemcpy(pVia->drmmode.fd, pVia->driOffScreenMem, dst, FALSE);
923             if (!err)
924                 return;
925 
926             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
927                        "Hardware backup of DRI offscreen memory failed: %s.\n"
928                        "\tUsing slow software backup instead.\n",
929                        strerror(-err));
930         }
931         memcpy(dst, src, srcSize);
932         drm_bo_unmap(pScrn, pVia->driOffScreenMem);
933     } else {
934         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
935                    "Out of memory trying to backup DRI offscreen memory.\n");
936     }
937     return;
938 }
939 
940 void
viaDRIOffscreenRestore(ScrnInfoPtr pScrn)941 viaDRIOffscreenRestore(ScrnInfoPtr pScrn)
942 {
943     VIAPtr pVia = VIAPTR(pScrn);
944 
945     if (pVia->driOffScreenSave) {
946         void *src, *dst = drm_bo_map(pScrn, pVia->driOffScreenMem);
947 
948         src = pVia->driOffScreenSave;
949         memcpy(dst, src, pVia->driOffScreenMem->size);
950         free(pVia->driOffScreenSave);
951         pVia->driOffScreenSave = NULL;
952 
953         drm_bo_unmap(pScrn, pVia->driOffScreenMem);
954     } else {
955     }
956 }
957