xserver-multidpi/hw/kdrive/ati/ati_dri.c
Eric Anholt 13c6b2f0b6 Add a set of macros for dealing with the repeated code to wait for a while
reading a register/attempting DMA. Now it'll wait for a certain number
    of seconds rather than a certain number of times through the loop
    before deciding that it's timed out and resetting the hardware. Also,
    add more timeout handling, and reset the draw state after resetting the
    engine.
2005-01-20 16:22:04 +00:00

1142 lines
33 KiB
C

/*
* $Id$
*
* Copyright © 2003 Eric Anholt
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Eric Anholt not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Eric Anholt makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Header$ */
#include <sys/time.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "ati.h"
#include "ati_reg.h"
#include "ati_dma.h"
#include "ati_dri.h"
#include "ati_dripriv.h"
#include "sarea.h"
#include "ati_sarea.h"
#include "ati_draw.h"
#include "r128_common.h"
#include "radeon_common.h"
/* ?? HACK - for now, put this here... */
/* ?? Alpha - this may need to be a variable to handle UP1x00 vs TITAN */
#if defined(__alpha__)
# define DRM_PAGE_SIZE 8192
#elif defined(__ia64__)
# define DRM_PAGE_SIZE getpagesize()
#else
# define DRM_PAGE_SIZE 4096
#endif
#ifdef GLXEXT
/* Initialize the visual configs that are supported by the hardware.
* These are combined with the visual configs that the indirect
* rendering core supports, and the intersection is exported to the
* client.
*/
static Bool ATIInitVisualConfigs(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
int numConfigs = 0;
__GLXvisualConfig *pConfigs = NULL;
ATIConfigPrivPtr pATIConfigs = NULL;
ATIConfigPrivPtr *pATIConfigPtrs = NULL;
int i, accum, stencil, db, use_db;
int depth = pScreenPriv->screen->fb[0].depth;
int bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
if (depth != 16 && (depth != 24 || bpp != 32))
ErrorF("DRI GLX unsupported at %d/%d depth/bpp\n", depth, bpp);
if (atis->depthOffset != 0)
use_db = 1;
else
use_db = 0;
numConfigs = 4;
if (use_db)
numConfigs *= 2;
pConfigs = xcalloc(sizeof(__GLXvisualConfig), numConfigs);
pATIConfigs = xcalloc(sizeof(ATIConfigPrivRec), numConfigs);
pATIConfigPtrs = xcalloc(sizeof(ATIConfigPrivPtr), numConfigs);
if (pConfigs == NULL || pATIConfigs == NULL || pATIConfigPtrs == NULL) {
xfree(pConfigs);
xfree(pATIConfigs);
xfree(pATIConfigPtrs);
return FALSE;
}
i = 0;
for (db = 0; db <= use_db; db++) {
for (accum = 0; accum <= 1; accum++) {
for (stencil = 0; stencil <= 1; stencil++) {
pATIConfigPtrs[i] = &pATIConfigs[i];
pConfigs[i].vid = (VisualID)(-1);
pConfigs[i].class = -1;
pConfigs[i].rgba = TRUE;
if (depth == 16) {
pConfigs[i].redSize = 5;
pConfigs[i].greenSize = 6;
pConfigs[i].blueSize = 5;
pConfigs[i].alphaSize = 0;
pConfigs[i].redMask = 0x0000F800;
pConfigs[i].greenMask = 0x000007E0;
pConfigs[i].blueMask = 0x0000001F;
pConfigs[i].alphaMask = 0x00000000;
} else {
pConfigs[i].redSize = 8;
pConfigs[i].greenSize = 8;
pConfigs[i].blueSize = 8;
pConfigs[i].alphaSize = 8;
pConfigs[i].redMask = 0x00FF0000;
pConfigs[i].greenMask = 0x0000FF00;
pConfigs[i].blueMask = 0x000000FF;
pConfigs[i].alphaMask = 0xFF000000;
}
if (accum) { /* Simulated in software */
pConfigs[i].accumRedSize = 16;
pConfigs[i].accumGreenSize = 16;
pConfigs[i].accumBlueSize = 16;
if (depth == 16)
pConfigs[i].accumAlphaSize = 0;
else
pConfigs[i].accumAlphaSize = 16;
} else {
pConfigs[i].accumRedSize = 0;
pConfigs[i].accumGreenSize = 0;
pConfigs[i].accumBlueSize = 0;
pConfigs[i].accumAlphaSize = 0;
}
if (db)
pConfigs[i].doubleBuffer = TRUE;
else
pConfigs[i].doubleBuffer = FALSE;
pConfigs[i].stereo = FALSE;
if (depth == 16) {
pConfigs[i].bufferSize = 16;
pConfigs[i].depthSize = 16;
if (stencil)
pConfigs[i].stencilSize = 8;
else
pConfigs[i].stencilSize = 0;
} else {
pConfigs[i].bufferSize = 32;
if (stencil) {
pConfigs[i].depthSize = 24;
pConfigs[i].stencilSize = 8;
} else {
pConfigs[i].depthSize = 24;
pConfigs[i].stencilSize = 0;
}
}
pConfigs[i].auxBuffers = 0;
pConfigs[i].level = 0;
if (accum) {
pConfigs[i].visualRating = GLX_SLOW_CONFIG;
} else {
pConfigs[i].visualRating = GLX_NONE;
}
pConfigs[i].transparentPixel = GLX_NONE;
pConfigs[i].transparentRed = 0;
pConfigs[i].transparentGreen = 0;
pConfigs[i].transparentBlue = 0;
pConfigs[i].transparentAlpha = 0;
pConfigs[i].transparentIndex = 0;
i++;
}
}
}
atis->numVisualConfigs = numConfigs;
atis->pVisualConfigs = pConfigs;
atis->pVisualConfigsPriv = pATIConfigs;
GlxSetVisualConfigs(numConfigs, pConfigs, (void**)pATIConfigPtrs);
return TRUE;
}
#endif /* GLXEXT */
static void
ATIDRIInitGARTValues(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
int s, l;
atis->gartOffset = 0;
/* Initialize the ring buffer data */
atis->ringStart = atis->gartOffset;
atis->ringMapSize = atis->ringSize * 1024 * 1024 + DRM_PAGE_SIZE;
atis->ringReadOffset = atis->ringStart + atis->ringMapSize;
atis->ringReadMapSize = DRM_PAGE_SIZE;
/* Reserve space for vertex/indirect buffers */
atis->bufStart = atis->ringReadOffset + atis->ringReadMapSize;
atis->bufMapSize = atis->bufSize * 1024 * 1024;
/* Reserve the rest for GART textures */
atis->gartTexStart = atis->bufStart + atis->bufMapSize;
s = (atis->gartSize * 1024 * 1024 - atis->gartTexStart);
l = ATILog2((s-1) / ATI_NR_TEX_REGIONS);
if (l < ATI_LOG_TEX_GRANULARITY) l = ATI_LOG_TEX_GRANULARITY;
atis->gartTexMapSize = (s >> l) << l;
atis->log2GARTTexGran = l;
}
static int
ATIDRIAddAndMap(int fd, drmHandle offset, drmSize size,
drmMapType type, drmMapFlags flags, drmHandlePtr handle,
drmAddressPtr address, char *desc)
{
char *name;
name = (type == DRM_AGP) ? "agp" : "pci";
if (drmAddMap(fd, offset, size, type, flags, handle) < 0) {
ErrorF("[%s] Could not add %s mapping\n", name, desc);
return FALSE;
}
ErrorF("[%s] %s handle = 0x%08lx\n", name, desc, *handle);
if (drmMap(fd, *handle, size, address) < 0) {
ErrorF("[%s] Could not map %s\n", name, desc);
return FALSE;
}
ErrorF("[%s] %s mapped at 0x%08lx\n", name, desc, *address);
return TRUE;
}
/* Initialize the AGP state. Request memory for use in AGP space, and
initialize the Rage 128 registers to point to that memory. */
static Bool
ATIDRIAgpInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
unsigned char *mmio = atic->reg_base;
unsigned long mode;
int ret;
CARD32 cntl, chunk;
if (drmAgpAcquire(atic->drmFd) < 0) {
ErrorF("[agp] AGP not available\n");
return FALSE;
}
ATIDRIInitGARTValues(pScreen);
mode = drmAgpGetMode(atic->drmFd);
if (atic->is_radeon) {
mode &= ~RADEON_AGP_MODE_MASK;
mode |= RADEON_AGP_1X_MODE;
} else {
mode &= ~R128_AGP_MODE_MASK;
mode |= R128_AGP_1X_MODE;
}
if (drmAgpEnable(atic->drmFd, mode) < 0) {
ErrorF("[agp] AGP not enabled\n");
drmAgpRelease(atic->drmFd);
return FALSE;
}
ErrorF("[agp] Mode 0x%08x selected\n", drmAgpGetMode(atic->drmFd));
if ((ret = drmAgpAlloc(atic->drmFd, atis->gartSize * 1024 * 1024, 0,
NULL, &atis->agpMemHandle)) < 0) {
ErrorF("[agp] Out of memory (%d)\n", ret);
drmAgpRelease(atic->drmFd);
return FALSE;
}
ErrorF("[agp] %d kB allocated with handle 0x%08lx\n",
atis->gartSize * 1024, (long)atis->agpMemHandle);
if (drmAgpBind(atic->drmFd, atis->agpMemHandle, atis->gartOffset) < 0) {
ErrorF("[agp] Could not bind\n");
drmAgpFree(atic->drmFd, atis->agpMemHandle);
drmAgpRelease(atic->drmFd);
return FALSE;
}
if (!ATIDRIAddAndMap(atic->drmFd, atis->ringStart, atis->ringMapSize,
DRM_AGP, DRM_READ_ONLY, &atis->ringHandle,
(drmAddressPtr)&atis->ring, "ring"))
return FALSE;
if (!ATIDRIAddAndMap(atic->drmFd, atis->ringReadOffset,
atis->ringReadMapSize, DRM_AGP, DRM_READ_ONLY,
&atis->ringReadPtrHandle, (drmAddressPtr)&atis->ringReadPtr,
"ring read ptr"))
return FALSE;
if (!ATIDRIAddAndMap(atic->drmFd, atis->bufStart, atis->bufMapSize,
DRM_AGP, 0, &atis->bufHandle, (drmAddressPtr)&atis->buf,
"vertex/indirect buffers"))
return FALSE;
if (!ATIDRIAddAndMap(atic->drmFd, atis->gartTexStart,
atis->gartTexMapSize, DRM_AGP, 0, &atis->gartTexHandle,
(drmAddressPtr)&atis->gartTex, "AGP texture map"))
return FALSE;
if (atic->is_r100) {
/* Workaround for some hardware bugs */
cntl = MMIO_IN32(mmio, ATI_REG_AGP_CNTL);
MMIO_OUT32(mmio, ATI_REG_AGP_CNTL, cntl |
RADEON_PENDING_SLOTS_VAL | RADEON_PENDING_SLOTS_SEL);
} else if (!atic->is_radeon) {
cntl = MMIO_IN32(mmio, ATI_REG_AGP_CNTL);
cntl &= ~R128_AGP_APER_SIZE_MASK;
switch (atis->gartSize) {
case 256: cntl |= R128_AGP_APER_SIZE_256MB; break;
case 128: cntl |= R128_AGP_APER_SIZE_128MB; break;
case 64: cntl |= R128_AGP_APER_SIZE_64MB; break;
case 32: cntl |= R128_AGP_APER_SIZE_32MB; break;
case 16: cntl |= R128_AGP_APER_SIZE_16MB; break;
case 8: cntl |= R128_AGP_APER_SIZE_8MB; break;
case 4: cntl |= R128_AGP_APER_SIZE_4MB; break;
default:
ErrorF("[agp] Illegal aperture size %d kB\n", atis->gartSize *
1024);
return FALSE;
}
MMIO_OUT32(mmio, ATI_REG_AGP_CNTL, cntl);
/* Disable Rage 128 PCIGART registers */
chunk = MMIO_IN32(mmio, R128_REG_BM_CHUNK_0_VAL);
chunk &= ~(R128_BM_PTR_FORCE_TO_PCI |
R128_BM_PM4_RD_FORCE_TO_PCI |
R128_BM_GLOBAL_FORCE_TO_PCI);
MMIO_OUT32(mmio, R128_REG_BM_CHUNK_0_VAL, chunk);
/* Ensure AGP GART is used (for now) */
MMIO_OUT32(mmio, R128_REG_PCI_GART_PAGE, 1);
}
MMIO_OUT32(mmio, ATI_REG_AGP_BASE, drmAgpBase(atic->drmFd));
return TRUE;
}
static Bool
ATIDRIPciInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
unsigned char *mmio = atic->reg_base;
CARD32 chunk;
int ret;
ATIDRIInitGARTValues(pScreen);
ret = drmScatterGatherAlloc(atic->drmFd, atis->gartSize * 1024 * 1024,
&atis->pciMemHandle);
if (ret < 0) {
ErrorF("[pci] Out of memory (%d)\n", ret);
return FALSE;
}
ErrorF("[pci] %d kB allocated with handle 0x%08lx\n",
atis->gartSize * 1024, (long)atis->pciMemHandle);
if (!ATIDRIAddAndMap(atic->drmFd, atis->ringStart, atis->ringMapSize,
DRM_SCATTER_GATHER, DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL,
&atis->ringHandle, (drmAddressPtr)&atis->ring, "ring"))
return FALSE;
if (!ATIDRIAddAndMap(atic->drmFd, atis->ringReadOffset,
atis->ringReadMapSize, DRM_SCATTER_GATHER,
DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL,
&atis->ringReadPtrHandle, (drmAddressPtr)&atis->ringReadPtr,
"ring read ptr"))
return FALSE;
if (!ATIDRIAddAndMap(atic->drmFd, atis->bufStart, atis->bufMapSize,
DRM_SCATTER_GATHER, 0, &atis->bufHandle, (drmAddressPtr)&atis->buf,
"vertex/indirect buffers"))
return FALSE;
if (!ATIDRIAddAndMap(atic->drmFd, atis->gartTexStart,
atis->gartTexMapSize, DRM_SCATTER_GATHER, 0, &atis->gartTexHandle,
(drmAddressPtr)&atis->gartTex, "PCI texture map"))
return FALSE;
if (!atic->is_radeon) {
/* Force PCI GART mode */
chunk = MMIO_IN32(mmio, R128_REG_BM_CHUNK_0_VAL);
chunk |= (R128_BM_PTR_FORCE_TO_PCI |
R128_BM_PM4_RD_FORCE_TO_PCI | R128_BM_GLOBAL_FORCE_TO_PCI);
MMIO_OUT32(mmio, R128_REG_BM_CHUNK_0_VAL, chunk);
/* Ensure PCI GART is used */
MMIO_OUT32(mmio, R128_REG_PCI_GART_PAGE, 0);
}
return TRUE;
}
/* Initialize the kernel data structures. */
static int
R128DRIKernelInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
drmR128Init drmInfo;
int bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
memset(&drmInfo, 0, sizeof(drmR128Init) );
drmInfo.func = DRM_R128_INIT_CCE;
drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec);
drmInfo.is_pci = !atis->using_agp;
drmInfo.cce_mode = R128_PM4_64BM_64VCBM_64INDBM;
drmInfo.cce_secure = TRUE;
drmInfo.ring_size = atis->ringSize * 1024 * 1024;
drmInfo.usec_timeout = atis->DMAusecTimeout;
drmInfo.front_offset = atis->frontOffset;
drmInfo.front_pitch = atis->frontPitch / (bpp / 8);
drmInfo.back_offset = atis->backOffset;
drmInfo.back_pitch = atis->backPitch / (bpp / 8);
drmInfo.fb_bpp = bpp;
drmInfo.depth_offset = atis->depthOffset;
drmInfo.depth_pitch = atis->depthPitch / (bpp / 8);
drmInfo.depth_bpp = bpp;
drmInfo.span_offset = atis->spanOffset;
drmInfo.fb_offset = atis->fbHandle;
drmInfo.mmio_offset = atis->registerHandle;
drmInfo.ring_offset = atis->ringHandle;
drmInfo.ring_rptr_offset = atis->ringReadPtrHandle;
drmInfo.buffers_offset = atis->bufHandle;
drmInfo.agp_textures_offset = atis->gartTexHandle;
if (drmCommandWrite(atic->drmFd, DRM_R128_INIT, &drmInfo,
sizeof(drmR128Init)) < 0)
return FALSE;
return TRUE;
}
/* Initialize the kernel data structures */
static int
RadeonDRIKernelInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
drmRadeonInit drmInfo;
memset(&drmInfo, 0, sizeof(drmRadeonInit));
if (atic->is_r200)
drmInfo.func = DRM_RADEON_INIT_R200_CP;
else
drmInfo.func = DRM_RADEON_INIT_CP;
drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec);
drmInfo.is_pci = !atis->using_agp;
drmInfo.cp_mode = RADEON_CSQ_PRIBM_INDBM;
drmInfo.gart_size = atis->gartSize * 1024 * 1024;
drmInfo.ring_size = atis->ringSize * 1024 * 1024;
drmInfo.usec_timeout = atis->DMAusecTimeout;
drmInfo.front_offset = atis->frontOffset;
drmInfo.front_pitch = atis->frontPitch;
drmInfo.back_offset = atis->backOffset;
drmInfo.back_pitch = atis->backPitch;
drmInfo.fb_bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
drmInfo.depth_offset = atis->depthOffset;
drmInfo.depth_pitch = atis->depthPitch;
drmInfo.depth_bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
drmInfo.fb_offset = atis->fbHandle;
drmInfo.mmio_offset = atis->registerHandle;
drmInfo.ring_offset = atis->ringHandle;
drmInfo.ring_rptr_offset = atis->ringReadPtrHandle;
drmInfo.buffers_offset = atis->bufHandle;
drmInfo.gart_textures_offset = atis->gartTexHandle;
if (drmCommandWrite(atic->drmFd, DRM_RADEON_CP_INIT,
&drmInfo, sizeof(drmRadeonInit)) < 0)
return FALSE;
return TRUE;
}
/* Add a map for the vertex buffers that will be accessed by any
DRI-based clients. */
static Bool
ATIDRIBufInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
int type, size;
if (atic->is_radeon)
size = RADEON_BUFFER_SIZE;
else
size = R128_BUFFER_SIZE;
if (atis->using_agp)
type = DRM_AGP_BUFFER;
else
type = DRM_SG_BUFFER;
/* Initialize vertex buffers */
atis->bufNumBufs = drmAddBufs(atic->drmFd, atis->bufMapSize / size,
size, type, atis->bufStart);
if (atis->bufNumBufs <= 0) {
ErrorF("[drm] Could not create vertex/indirect buffers list\n");
return FALSE;
}
ErrorF("[drm] Added %d %d byte vertex/indirect buffers\n",
atis->bufNumBufs, size);
atis->buffers = drmMapBufs(atic->drmFd);
if (atis->buffers == NULL) {
ErrorF("[drm] Failed to map vertex/indirect buffers list\n");
return FALSE;
}
ErrorF("[drm] Mapped %d vertex/indirect buffers\n",
atis->buffers->count);
return TRUE;
}
static int
ATIDRIIrqInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
if (atis->irqEnabled)
return FALSE;
atis->irqEnabled = drmCtlInstHandler(atic->drmFd, 0);
if (!atis->irqEnabled)
return FALSE;
return TRUE;
}
static void ATIDRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
DRIContextType oldContextType, void *oldContext,
DRIContextType newContextType, void *newContext)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
if ((syncType==DRI_3D_SYNC) && (oldContextType==DRI_2D_CONTEXT) &&
(newContextType==DRI_2D_CONTEXT)) {
/* Entering from Wakeup */
KdMarkSync(pScreen);
}
if ((syncType==DRI_2D_SYNC) && (oldContextType==DRI_NO_CONTEXT) &&
(newContextType==DRI_2D_CONTEXT)) {
/* Exiting from Block Handler */
if (atis->dma_started)
ATIFlushIndirect(atis, 1);
}
}
static Bool ATIDRIFinishScreenInit(ScreenPtr pScreen);
/* Initialize the screen-specific data structures for the Radeon or
Rage 128. This is the main entry point to the device-specific
initialization code. It calls device-independent DRI functions to
create the DRI data structures and initialize the DRI state. */
Bool
ATIDRIScreenInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
void *scratch_ptr;
int scratch_int;
DRIInfoPtr pDRIInfo;
int devSareaSize;
drmSetVersion sv;
if (pScreenPriv->screen->fb[0].depth < 16 ||
pScreenPriv->screen->fb[0].bitsPerPixel == 24) {
ErrorF("DRI unsupported at this depth/bpp, disabling.\n");
return FALSE;
}
atis->agpMode = 1;
atis->gartSize = 8;
atis->ringSize = 1;
atis->bufSize = 2;
atis->gartTexSize = 1;
atis->DMAusecTimeout = 10000;
if (atic->drmFd < 0)
return FALSE;
sv.drm_di_major = -1;
sv.drm_dd_major = -1;
drmSetInterfaceVersion(atic->drmFd, &sv);
if (atic->is_radeon) {
if (sv.drm_dd_major != 1 || sv.drm_dd_minor < 6) {
ErrorF("[dri] radeon kernel module version is %d.%d "
"but version 1.6 or greater is needed.\n",
sv.drm_dd_major, sv.drm_dd_minor);
return FALSE;
}
} else {
if (sv.drm_dd_major != 2 || sv.drm_dd_minor < 2) {
ErrorF("[dri] r128 kernel module version is %d.%d "
"but version 2.2 or greater is needed.\n",
sv.drm_dd_major, sv.drm_dd_minor);
return FALSE;
}
}
/* Create the DRI data structure, and fill it in before calling the
* DRIScreenInit().
*/
pDRIInfo = DRICreateInfoRec();
if (pDRIInfo == NULL)
return FALSE;
atis->pDRIInfo = pDRIInfo;
pDRIInfo->busIdString = atic->busid;
if (atic->is_radeon) {
pDRIInfo->drmDriverName = "radeon";
if (atic->is_r100)
pDRIInfo->clientDriverName = "radeon";
else
pDRIInfo->clientDriverName = "r200";
} else {
pDRIInfo->drmDriverName = "r128";
pDRIInfo->clientDriverName = "r128";
}
pDRIInfo->ddxDriverMajorVersion = 4;
pDRIInfo->ddxDriverMinorVersion = 0;
pDRIInfo->ddxDriverPatchVersion = 0;
pDRIInfo->frameBufferPhysicalAddress =
pScreenPriv->card->attr.address[0] & 0xfc000000;
pDRIInfo->frameBufferSize = pScreenPriv->screen->memory_size;
pDRIInfo->frameBufferStride = pScreenPriv->screen->fb[0].byteStride;
pDRIInfo->ddxDrawableTableEntry = SAREA_MAX_DRAWABLES;
pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES;
/* For now the mapping works by using a fixed size defined
* in the SAREA header
*/
pDRIInfo->SAREASize = SAREA_MAX;
if (atic->is_radeon) {
pDRIInfo->devPrivateSize = sizeof(RADEONDRIRec);
devSareaSize = sizeof(RADEONSAREAPriv);
} else {
pDRIInfo->devPrivateSize = sizeof(R128DRIRec);
devSareaSize = sizeof(R128SAREAPriv);
}
if (sizeof(XF86DRISAREARec) + devSareaSize > SAREA_MAX) {
ErrorF("[dri] Data does not fit in SAREA. Disabling DRI.\n");
return FALSE;
}
pDRIInfo->devPrivate = xcalloc(pDRIInfo->devPrivateSize, 1);
if (pDRIInfo->devPrivate == NULL) {
DRIDestroyInfoRec(atis->pDRIInfo);
atis->pDRIInfo = NULL;
return FALSE;
}
pDRIInfo->contextSize = sizeof(ATIDRIContextRec);
pDRIInfo->SwapContext = ATIDRISwapContext;
/*pDRIInfo->InitBuffers = R128DRIInitBuffers;*/ /* XXX Appears unnecessary */
/*pDRIInfo->MoveBuffers = R128DRIMoveBuffers;*/ /* XXX Badness */
pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
/*pDRIInfo->TransitionTo2d = R128DRITransitionTo2d;
pDRIInfo->TransitionTo3d = R128DRITransitionTo3d;
pDRIInfo->TransitionSingleToMulti3D = R128DRITransitionSingleToMulti3d;
pDRIInfo->TransitionMultiToSingle3D = R128DRITransitionMultiToSingle3d;*/
pDRIInfo->createDummyCtx = TRUE;
pDRIInfo->createDummyCtxPriv = FALSE;
if (!DRIScreenInit(pScreen, pDRIInfo, &atic->drmFd)) {
ErrorF("[dri] DRIScreenInit failed. Disabling DRI.\n");
xfree(pDRIInfo->devPrivate);
pDRIInfo->devPrivate = NULL;
DRIDestroyInfoRec(pDRIInfo);
pDRIInfo = NULL;
return FALSE;
}
/* Add a map for the MMIO registers that will be accessed by any
* DRI-based clients.
*/
atis->registerSize = ATI_REG_SIZE(pScreenPriv->screen->card);
if (drmAddMap(atic->drmFd, ATI_REG_BASE(pScreenPriv->screen->card),
atis->registerSize, DRM_REGISTERS, DRM_READ_ONLY,
&atis->registerHandle) < 0) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
ErrorF("[drm] register handle = 0x%08lx\n", atis->registerHandle);
/* DRIScreenInit adds the frame buffer map, but we need it as well */
DRIGetDeviceInfo(pScreen, &atis->fbHandle, &scratch_int, &scratch_int,
&scratch_int, &scratch_int, &scratch_ptr);
/* Initialize AGP */
atis->using_agp = atic->is_agp;
if (atic->is_agp && !ATIDRIAgpInit(pScreen)) {
atis->using_agp = FALSE;
ErrorF("[agp] AGP failed to initialize; falling back to PCI mode.\n");
ErrorF("[agp] Make sure your kernel's AGP support is loaded and functioning.\n");
}
/* Initialize PCIGART */
if (!atis->using_agp && !ATIDRIPciInit(pScreen)) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
#ifdef GLXEXT
if (!ATIInitVisualConfigs(pScreen)) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
ErrorF("[dri] Visual configs initialized\n");
#endif
atis->serverContext = DRIGetContext(pScreen);
return ATIDRIFinishScreenInit(pScreen);
}
/* Finish initializing the device-dependent DRI state, and call
DRIFinishScreenInit() to complete the device-independent DRI
initialization. */
static Bool
R128DRIFinishScreenInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
R128SAREAPrivPtr pSAREAPriv;
R128DRIPtr pR128DRI;
int bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
/* Initialize the kernel data structures */
if (!R128DRIKernelInit(pScreen)) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
/* Initialize the vertex buffers list */
if (!ATIDRIBufInit(pScreen)) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
/* Initialize IRQ */
ATIDRIIrqInit(pScreen);
pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
pR128DRI = (R128DRIPtr)atis->pDRIInfo->devPrivate;
pR128DRI->deviceID = pScreenPriv->screen->card->attr.deviceID;
pR128DRI->width = pScreenPriv->screen->width;
pR128DRI->height = pScreenPriv->screen->height;
pR128DRI->depth = pScreenPriv->screen->fb[0].depth;
pR128DRI->bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
pR128DRI->IsPCI = !atis->using_agp;
pR128DRI->AGPMode = atis->agpMode;
pR128DRI->frontOffset = atis->frontOffset;
pR128DRI->frontPitch = atis->frontPitch / (bpp / 8);
pR128DRI->backOffset = atis->backOffset;
pR128DRI->backPitch = atis->backPitch / (bpp / 8);
pR128DRI->depthOffset = atis->depthOffset;
pR128DRI->depthPitch = atis->depthPitch / (bpp / 8);
pR128DRI->spanOffset = atis->spanOffset;
pR128DRI->textureOffset = atis->textureOffset;
pR128DRI->textureSize = atis->textureSize;
pR128DRI->log2TexGran = atis->log2TexGran;
pR128DRI->registerHandle = atis->registerHandle;
pR128DRI->registerSize = atis->registerSize;
pR128DRI->gartTexHandle = atis->gartTexHandle;
pR128DRI->gartTexMapSize = atis->gartTexMapSize;
pR128DRI->log2AGPTexGran = atis->log2GARTTexGran;
pR128DRI->gartTexOffset = atis->gartTexStart;
pR128DRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
return TRUE;
}
/* Finish initializing the device-dependent DRI state, and call
* DRIFinishScreenInit() to complete the device-independent DRI
* initialization.
*/
static Bool
RadeonDRIFinishScreenInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
RADEONSAREAPrivPtr pSAREAPriv;
RADEONDRIPtr pRADEONDRI;
drmRadeonMemInitHeap drmHeap;
/* Initialize the kernel data structures */
if (!RadeonDRIKernelInit(pScreen)) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
/* Initialize the vertex buffers list */
if (!ATIDRIBufInit(pScreen)) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
/* Initialize IRQ */
ATIDRIIrqInit(pScreen);
drmHeap.region = RADEON_MEM_REGION_GART;
drmHeap.start = 0;
drmHeap.size = atis->gartTexMapSize;
if (drmCommandWrite(atic->drmFd, DRM_RADEON_INIT_HEAP, &drmHeap,
sizeof(drmHeap))) {
ErrorF("[drm] Failed to initialize GART heap manager\n");
}
/* Initialize the SAREA private data structure */
pSAREAPriv = (RADEONSAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
pRADEONDRI = (RADEONDRIPtr)atis->pDRIInfo->devPrivate;
pRADEONDRI->deviceID = pScreenPriv->screen->card->attr.deviceID;
pRADEONDRI->width = pScreenPriv->screen->width;
pRADEONDRI->height = pScreenPriv->screen->height;
pRADEONDRI->depth = pScreenPriv->screen->fb[0].depth;
pRADEONDRI->bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
pRADEONDRI->IsPCI = !atis->using_agp;
pRADEONDRI->AGPMode = atis->agpMode;
pRADEONDRI->frontOffset = atis->frontOffset;
pRADEONDRI->frontPitch = atis->frontPitch;
pRADEONDRI->backOffset = atis->backOffset;
pRADEONDRI->backPitch = atis->backPitch;
pRADEONDRI->depthOffset = atis->depthOffset;
pRADEONDRI->depthPitch = atis->depthPitch;
pRADEONDRI->textureOffset = atis->textureOffset;
pRADEONDRI->textureSize = atis->textureSize;
pRADEONDRI->log2TexGran = atis->log2TexGran;
pRADEONDRI->registerHandle = atis->registerHandle;
pRADEONDRI->registerSize = atis->registerSize;
pRADEONDRI->statusHandle = atis->ringReadPtrHandle;
pRADEONDRI->statusSize = atis->ringReadMapSize;
pRADEONDRI->gartTexHandle = atis->gartTexHandle;
pRADEONDRI->gartTexMapSize = atis->gartTexMapSize;
pRADEONDRI->log2GARTTexGran = atis->log2GARTTexGran;
pRADEONDRI->gartTexOffset = atis->gartTexStart;
pRADEONDRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
return TRUE;
}
static Bool
ATIDRIFinishScreenInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo (pScreenPriv);
atis->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
/* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit
* because *DRIKernelInit requires that the hardware lock is held by
* the X server, and the first time the hardware lock is grabbed is
* in DRIFinishScreenInit.
*/
if (!DRIFinishScreenInit(pScreen)) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
if (atic->is_radeon) {
if (!RadeonDRIFinishScreenInit(pScreen)) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
} else {
if (!R128DRIFinishScreenInit(pScreen)) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
}
return TRUE;
}
/* The screen is being closed, so clean up any state and free any
resources used by the DRI. */
void
ATIDRICloseScreen(ScreenPtr pScreen)
{
KdScreenPriv (pScreen);
ATIScreenInfo (pScreenPriv);
ATICardInfo (pScreenPriv);
drmR128Init drmR128Info;
drmRadeonInit drmRadeonInfo;
if (atis->indirectBuffer != NULL) {
/* Flush any remaining commands and free indirect buffers.
* Two steps are used because ATIFlushIndirect gets a
* new buffer after discarding.
*/
ATIFlushIndirect(atis, 1);
ATIDRIDispatchIndirect(atis, 1);
xfree(atis->indirectBuffer);
atis->indirectBuffer = NULL;
atis->indirectStart = 0;
}
ATIDRIDMAStop(atis);
if (atis->irqEnabled) {
drmCtlUninstHandler(atic->drmFd);
atis->irqEnabled = FALSE;
}
/* De-allocate vertex buffers */
if (atis->buffers) {
drmUnmapBufs(atis->buffers);
atis->buffers = NULL;
}
/* De-allocate all kernel resources */
if (!atic->is_radeon) {
memset(&drmR128Info, 0, sizeof(drmR128Init));
drmR128Info.func = DRM_R128_CLEANUP_CCE;
drmCommandWrite(atic->drmFd, DRM_R128_INIT, &drmR128Info,
sizeof(drmR128Init));
} else {
memset(&drmRadeonInfo, 0, sizeof(drmRadeonInfo));
drmRadeonInfo.func = DRM_RADEON_CLEANUP_CP;
drmCommandWrite(atic->drmFd, DRM_RADEON_CP_INIT, &drmRadeonInfo,
sizeof(drmR128Init));
}
/* De-allocate all AGP resources */
if (atis->gartTex) {
drmUnmap(atis->gartTex, atis->gartTexMapSize);
atis->gartTex = NULL;
}
if (atis->buf) {
drmUnmap(atis->buf, atis->bufMapSize);
atis->buf = NULL;
}
if (atis->ringReadPtr) {
drmUnmap(atis->ringReadPtr, atis->ringReadMapSize);
atis->ringReadPtr = NULL;
}
if (atis->ring) {
drmUnmap(atis->ring, atis->ringMapSize);
atis->ring = NULL;
}
if (atis->agpMemHandle != DRM_AGP_NO_HANDLE) {
drmAgpUnbind(atic->drmFd, atis->agpMemHandle);
drmAgpFree(atic->drmFd, atis->agpMemHandle);
atis->agpMemHandle = DRM_AGP_NO_HANDLE;
drmAgpRelease(atic->drmFd);
}
if (atis->pciMemHandle) {
drmScatterGatherFree(atic->drmFd, atis->pciMemHandle);
atis->pciMemHandle = 0;
}
/* De-allocate all DRI resources */
DRICloseScreen(pScreen);
/* De-allocate all DRI data structures */
if (atis->pDRIInfo) {
if (atis->pDRIInfo->devPrivate) {
xfree(atis->pDRIInfo->devPrivate);
atis->pDRIInfo->devPrivate = NULL;
}
DRIDestroyInfoRec(atis->pDRIInfo);
atis->pDRIInfo = NULL;
}
#ifdef GLXEXT
if (atis->pVisualConfigs) {
xfree(atis->pVisualConfigs);
atis->pVisualConfigs = NULL;
}
if (atis->pVisualConfigsPriv) {
xfree(atis->pVisualConfigsPriv);
atis->pVisualConfigsPriv = NULL;
}
#endif /* GLXEXT */
atic->drmFd = -1;
}
void
ATIDRIDMAStart(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
int ret;
if (atic->is_radeon)
ret = drmCommandNone(atic->drmFd, DRM_RADEON_CP_START);
else
ret = drmCommandNone(atic->drmFd, DRM_R128_CCE_START);
if (ret == 0)
atis->dma_started = TRUE;
else
FatalError("%s: DMA start returned %d\n", __FUNCTION__, ret);
}
/* Attempts to idle the DMA engine and stops it. Note that the ioctl is the
* same for both R128 and Radeon, so we can just use the name of one of them.
*/
void
ATIDRIDMAStop(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
drmRadeonCPStop stop;
int ret;
stop.flush = 1;
stop.idle = 1;
ret = drmCommandWrite(atic->drmFd, DRM_RADEON_CP_STOP, &stop,
sizeof(drmRadeonCPStop));
if (ret != 0 && errno == EBUSY) {
ErrorF("Failed to idle the DMA engine\n");
stop.idle = 0;
ret = drmCommandWrite(atic->drmFd, DRM_RADEON_CP_STOP, &stop,
sizeof(drmRadeonCPStop));
}
atis->dma_started = FALSE;
}
void
ATIDRIDMAReset(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
int ret;
ret = drmCommandNone(atic->drmFd, atic->is_radeon ?
DRM_RADEON_CP_RESET : DRM_R128_CCE_RESET);
if (ret != 0)
FatalError("Failed to reset CCE/CP\n");
atis->dma_started = FALSE;
}
/* The R128 and Radeon Indirect ioctls differ only in the ioctl number */
void
ATIDRIDispatchIndirect(ATIScreenInfo *atis, Bool discard)
{
ATICardInfo *atic = atis->atic;
drmBufPtr buffer = atis->indirectBuffer->drmBuf;
drmR128Indirect indirect;
int cmd;
indirect.idx = buffer->idx;
indirect.start = atis->indirectStart;
indirect.end = buffer->used;
indirect.discard = discard;
cmd = atic->is_radeon ? DRM_RADEON_INDIRECT : DRM_R128_INDIRECT;
drmCommandWriteRead(atic->drmFd, cmd, &indirect,
sizeof(drmR128Indirect));
}
/* Get an indirect buffer for the DMA 2D acceleration commands */
drmBufPtr
ATIDRIGetBuffer(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
drmDMAReq dma;
drmBufPtr buf = NULL;
int indx = 0;
int size = 0;
int ret;
TIMEOUT_LOCALS;
dma.context = atis->serverContext;
dma.send_count = 0;
dma.send_list = NULL;
dma.send_sizes = NULL;
dma.flags = 0;
dma.request_count = 1;
if (atic->is_radeon)
dma.request_size = RADEON_BUFFER_SIZE;
else
dma.request_size = R128_BUFFER_SIZE;
dma.request_list = &indx;
dma.request_sizes = &size;
dma.granted_count = 0;
WHILE_NOT_TIMEOUT(.2) {
ret = drmDMA(atic->drmFd, &dma);
if (ret != -EBUSY)
break;
}
if (TIMEDOUT())
FatalError("Timeout fetching DMA buffer (card hung)\n");
if (ret != 0)
FatalError("Error fetching DMA buffer: %d\n", ret);
buf = &atis->buffers->list[indx];
buf->used = 0;
return buf;
}