|
|
/******************************Module*Header*******************************\
* * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * !! !! * !! WARNING: NOT DDK SAMPLE CODE !! * !! !! * !! This source code is provided for completeness only and should not be !! * !! used as sample code for display driver development. Only those sources !! * !! marked as sample code for a given driver component should be used for !! * !! development purposes. !! * !! !! * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * * Module Name: dma.h * * Content: DMA transport definitons and macros * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/
#ifndef __DMA_H
#define __DMA_H
//-----------------------------------------------------------------------------
//
// DMA/Fifo utility function declarations
//
//-----------------------------------------------------------------------------
// Enables a driver to switch between FIFO/DMA operations
void HWC_SwitchToFIFO( P3_THUNKEDDATA* pThisDisplay, LPGLINTINFO pGLInfo ); void HWC_SwitchToDMA( P3_THUNKEDDATA* pThisDisplay, LPGLINTINFO pGLInfo ); void HWC_AllocDMABuffer(P3_THUNKEDDATA* pThisDisplay); DWORD WINAPI HWC_StartDMA(P3_THUNKEDDATA* pThisDisplay, DWORD dwContext, DWORD dwSize, DWORD dwPhys, ULONG_PTR dwVirt, DWORD dwEvent); void HWC_GetDXBuffer( P3_THUNKEDDATA*, char*, int ); void HWC_SetDXBuffer( P3_THUNKEDDATA*, char*, int ); void HWC_FlushDXBuffer( P3_THUNKEDDATA* );
//-----------------------------------------------------------------------------
//
// DMA & Fifo common definitions & macros
//
//-----------------------------------------------------------------------------
// Compute the depth of the FIFO depending on if we are a simple
// Permedia3 or if we are going through the Gamma chip of the GVX1
#define FIFO_DEPTH ((ULONG)((TLCHIP_GAMMA) ? 32 : 120))
// Always check the FIFO. Remember that the DMA just loads the FIFO, and even
// if the DMA is empty, there can be tons left in the FIFO.
#define DRAW_ENGINE_BUSY(pThisDisplay) \
( pThisDisplay->pGlint->InFIFOSpace < FIFO_DEPTH )
// We track the fifo space so that we never wait for entries that we don't
// need to. We wait for nEntries + 1 instead of nEntries because of an issue
// in the Gamma chip
#define __WAIT_GLINT_FIFO_SPACE(nEntries) \
{ \ DWORD dwEntries; \ do \ { \ dwEntries = *inFIFOptr; \ if (dwEntries > 120) dwEntries = 120; \ } while (dwEntries < nEntries + 1); \ }
// Local variables needed on all DX functions that try to use DMA/FIFO
#define P3_DMA_DEFS() \
ULONG * volatile dmaPtr; \ ULONG * volatile inFIFOptr = \ (ULONG *)(&pThisDisplay->pGlint->InFIFOSpace)
// Debug & free versions to get / commit / flush a buffer
#if DBG
#define P3_DMA_GET_BUFFER() \
{ \ HWC_GetDXBuffer( pThisDisplay, __FILE__, __LINE__ ); \ dmaPtr = pThisDisplay->pGLInfo->CurrentBuffer; \ }
#define P3_DMA_COMMIT_BUFFER() \
{ \ pThisDisplay->pGLInfo->CurrentBuffer = dmaPtr; \ HWC_SetDXBuffer( pThisDisplay, __FILE__, __LINE__ ); \ } #else
#define P3_DMA_GET_BUFFER() \
dmaPtr = pThisDisplay->pGLInfo->CurrentBuffer;
#define P3_DMA_COMMIT_BUFFER() \
{ \ pThisDisplay->pGLInfo->CurrentBuffer = dmaPtr; \ } #endif // DBG
#define P3_DMA_FLUSH_BUFFER() \
{ \ P3_DMA_COMMIT_BUFFER(); \ HWC_FlushDXBuffer( pThisDisplay ); \ dmaPtr = pThisDisplay->pGLInfo->CurrentBuffer; \ }
#if DBG
#define __SET_FIFO_ENTRIES_LEFT(a) \
do { \ g_pThisTemp = pThisDisplay; \ pThisDisplay->EntriesLeft = (a); \ } while (0)
#define __SET_DMA_ENTRIES_LEFT(a) \
do { \ g_pThisTemp = pThisDisplay; \ pThisDisplay->DMAEntriesLeft = (a); \ } while (0)
#define __RESET_FIFO_ERROR_CHECK g_bDetectedFIFOError = FALSE
#else
#define __SET_FIFO_ENTRIES_LEFT(a)
#define __SET_DMA_ENTRIES_LEFT(a)
#define __RESET_FIFO_ERROR_CHECK
#endif // DBG
#if DBG
// Note the DMAEntriesLeft+=2 compensates for the fact that this macro
// doesn't load a DMA Buffer - it writes to the FIFO directly. That
// means it does need to wait for FIFO space
#define LOAD_GLINT_REG(r, v) \
{ \ DISPDBG(( DBGLVL, "LoadGlintReg: %s 0x%x", #r, v )); \ __SET_DMA_ENTRIES_LEFT(pThisDisplay->DMAEntriesLeft + 2); \ CHECK_FIFO(2); \ MEMORY_BARRIER(); \ pThisDisplay->pGlint->r = v; \ MEMORY_BARRIER(); \ }
// Control registers do not require fifo entries
#define LOAD_GLINT_CTRL_REG(r, v) \
{ \ MEMORY_BARRIER(); \ pThisDisplay->pGlint->r = v; \ MEMORY_BARRIER(); \ }
#else
#define LOAD_GLINT_REG(r, v) \
{ \ MEMORY_BARRIER(); \ pThisDisplay->pGlint->r = v; \ MEMORY_BARRIER(); \ }
#define LOAD_GLINT_CTRL_REG(r, v) \
{ \ MEMORY_BARRIER(); \ pThisDisplay->pGlint->r = v; \ MEMORY_BARRIER(); \ } #endif
#define READ_GLINT_CTRL_REG(r) (pThisDisplay->pGlint->r)
// We wait for nEntries + 1 instead of nEntries because of a bug in Gamma chip
#define WAIT_GLINT_FIFO(nEntries) \
while((READ_GLINT_CTRL_REG (InFIFOSpace)) < nEntries + 1);
#define READ_OUTPUT_FIFO(d) d = READ_GLINT_CTRL_REG(GPFifo[0])
#define GET_DMA_COUNT(c) c = READ_GLINT_CTRL_REG(DMACount)
#if DBG
#define SET_MAX_ERROR_CHECK_FIFO_SPACE pThisDisplay->EntriesLeft = 120;
#define SET_ERROR_CHECK_FIFO_SPACES(a) pThisDisplay->EntriesLeft = (a);
#else
#define SET_MAX_ERROR_CHECK_FIFO_SPACE
#define SET_ERROR_CHECK_FIFO_SPACES(a)
#endif
//-----------------------------------------------------------------------------
//
// DMA EXCLUSIVE definitions & macros
//
// Below macros are used if we have defined that we want a DMA capable build
//-----------------------------------------------------------------------------
#ifdef WANT_DMA
#define WAIT_FIFO(a) \
do { if(pThisDisplay->pGLInfo->InterfaceType != GLINT_DMA) \ __WAIT_GLINT_FIFO_SPACE(a); \ __SET_FIFO_ENTRIES_LEFT(a); \ __RESET_FIFO_ERROR_CHECK; \ } while (0)
#define __ENSURE_DMA_SPACE(entries) \
{ \ if (pThisDisplay->pGLInfo->InterfaceType != GLINT_NON_DMA) \ { \ if(((ULONG_PTR)dmaPtr + entries) >= \ (ULONG_PTR)(pThisDisplay->pGLInfo->DMAPartition[pThisDisplay->pGLInfo->CurrentPartition].MaxAddress)) \ { \ P3_DMA_FLUSH_BUFFER(); \ } \ } \ else \ { \ pThisDisplay->pGLInfo->CurrentBuffer = (ULONG*)&pThisDisplay->pGlint->GPFifo; \ dmaPtr = pThisDisplay->pGLInfo->CurrentBuffer; \ } \ __SET_DMA_ENTRIES_LEFT(entries); \ __RESET_FIFO_ERROR_CHECK; \ }
#define P3_ENSURE_DX_SPACE(entries) \
{ \ __ENSURE_DMA_SPACE(entries) \ __SET_DMA_ENTRIES_LEFT(entries); \ __RESET_FIFO_ERROR_CHECK; \ }
#if WNT_DDRAW
#define WAIT_DMA_COMPLETE DDWaitDMAComplete(pThisDisplay->ppdev);
#else
extern void Wait_2D_DMA_Complete(P3_THUNKEDDATA* pThisDisplay);
#define PATIENTLY_WAIT_DMA() \
{ \ volatile DWORD count; \ while (GET_DMA_COUNT(count) > 0) \ { \ if (count < 32) \ count = 1; \ else \ count <<= 1; \ while (--count > 0) NULL; \ } \ }
#define WAIT_DMA_COMPLETE \
{ \ CHECK_ERROR(); \ if (!(pThisDisplay->pGLInfo->GlintBoardStatus & GLINT_DMA_COMPLETE)) { \ if (pThisDisplay->pGLInfo->GlintBoardStatus & GLINT_INTR_CONTEXT) { \ static int retry = 0; \ while (!(pThisDisplay->pGLInfo->GlintBoardStatus & GLINT_DMA_COMPLETE)) \ { \ LOCKUP(); \ } \ } else { \ if (pThisDisplay->pGLInfo->dwCurrentContext == CONTEXT_DISPLAY_HANDLE) {\ Wait_2D_DMA_Complete(pThisDisplay); \ } \ else { \ PATIENTLY_WAIT_DMA(); \ pThisDisplay->pGLInfo->GlintBoardStatus |= GLINT_DMA_COMPLETE; \ } \ } \ ASSERTDD( READ_GLINT_CTRL_REG(DMACount) == 0, "DMACount not zero after WAIT_DMA_COMPLETE" );\ ASSERTDD((READ_GLINT_CTRL_REG(ByDMAControl) & 3 ) == 0, "Bypass DMA not complete after WAIT_DMA_COMPLETE" );\ } \ else { \ ASSERTDD( READ_GLINT_CTRL_REG(DMACount) == 0, "DMACount not zero despite GLINT_DMA_COMPLETE" );\ ASSERTDD((READ_GLINT_CTRL_REG(ByDMAControl) & 3 ) == 0, "Bypass DMA not complete despite GLINT_DMA_COMPLETE" );\ } \ CHECK_ERROR(); \ } #endif // WNT_DDRAW
#if WNT_DDRAW
#define SYNC_WITH_GLINT \
vNTSyncWith2DDriver(pThisDisplay->ppdev); \ SET_MAX_ERROR_CHECK_FIFO_SPACE #else
#define SYNC_WITH_GLINT \
DISPDBG(( DBGLVL, "SYNC_WITH_GLINT" )); \ WAIT_DMA_COMPLETE \ while( pThisDisplay->pGlint->InFIFOSpace < 6 ) /* void */ ; \ SET_ERROR_CHECK_FIFO_SPACES(6); \ LOAD_GLINT_REG(FilterMode, 0x400); \ LOAD_GLINT_REG(Sync, 0); \ LOAD_GLINT_REG(FilterMode, 0x0); \ do { \ while (pThisDisplay->pGlint->OutFIFOWords == 0) /* void */ ; \ } while (pThisDisplay->pGlint->GPFifo[0] != 0x188); \ DISPDBG((DBGLVL,"Sync at line %d in %s", __LINE__, __FILE__)); \ SET_MAX_ERROR_CHECK_FIFO_SPACE #endif // WNT_DDRAW
//-----------------------------------------------------------------------------
//
// FIFO EXCLUSIVE definitions & macros
//
//-----------------------------------------------------------------------------
#else //!WANT_DMA
#define WAIT_FIFO(a) \
do { \ __WAIT_GLINT_FIFO_SPACE(a); \ __SET_FIFO_ENTRIES_LEFT(a); \ __RESET_FIFO_ERROR_CHECK; \ } while(0)
#define P3_ENSURE_DX_SPACE(entries) \
{ \ dmaPtr = (unsigned long *) (DWORD)pThisDisplay->pGlint->GPFifo; \ P3_DMA_COMMIT_BUFFER(); \ __SET_DMA_ENTRIES_LEFT(entries); \ __RESET_FIFO_ERROR_CHECK; \ }
#define P3_DMA_FLUSH_BUFFER() \
{ \ dmaPtr = (unsigned long *) pThisDisplay->pGlint->GPFifo; \ P3_DMA_COMMIT_BUFFER(); \ }
#define WAIT_DMA_COMPLETE
#define SYNC_WITH_GLINT \
vNTSyncWith2DDriver(pThisDisplay->ppdev); \ SET_MAX_ERROR_CHECK_FIFO_SPACE
#endif // !WANT_DMA
//-----------------------------------------------------------------------------
//
// Win9x specific definitons & macros
//
//-----------------------------------------------------------------------------
#if W95_DDRAW
// wait for DMA to complete (DMACount becomes zero). So as not to kill the
// PCI bus bandwidth for the DMA put in a backoff based on the amount of data
// still left to DMA. Also set the timer going if at any time, the count we
// read is the same as the previous count.
//
#if DBG
#define LOCKUP() \
if(( ++retry & 0xfffff ) == 0 ) \ { \ DISPDBG(( WRNLVL, "Locked up in WAIT_DMA_COMPLETE" \ " - %d retries", retry )); \ }
#else
#define LOCKUP()
#endif
#endif // W95_DDRAW
//-----------------------------------------------------------------------------
//
// Macros used to send data to the Permedia 3 hardware
//
//-----------------------------------------------------------------------------
#define SEND_P3_DATA(tag,data) \
{ \ MEMORY_BARRIER(); \ dmaPtr[0] = tag##_Tag; \ MEMORY_BARRIER(); \ dmaPtr[1] = data; \ MEMORY_BARRIER(); \ dmaPtr+=2; \ CHECK_FIFO(2); \ }
#define SEND_P3_DATA_OFFSET(tag,data, i) \
{ \ MEMORY_BARRIER(); \ dmaPtr[0] = (tag##_Tag + i); \ MEMORY_BARRIER(); \ dmaPtr[1] = data; \ MEMORY_BARRIER(); \ dmaPtr += 2; CHECK_FIFO(2); \ } #define COPY_P3_DATA(tag,data) \
{ \ MEMORY_BARRIER(); \ dmaPtr[0] = tag##_Tag; \ MEMORY_BARRIER(); \ dmaPtr[1] = *((unsigned long*) &(data)); \ MEMORY_BARRIER(); \ dmaPtr += 2; \ CHECK_FIFO(2); \ }
#define COPY_P3_DATA_OFFSET(tag,data,i) \
{ \ MEMORY_BARRIER(); \ dmaPtr[0] = tag##_Tag + i; \ MEMORY_BARRIER(); \ dmaPtr[1] = *((unsigned long*) &(data)); \ MEMORY_BARRIER(); \ dmaPtr += 2; \ CHECK_FIFO(2); \ }
#define P3RX_HOLD_CMD(tag, count) \
{ \ MEMORY_BARRIER(); \ dmaPtr[0] = ( tag##_Tag | ((count-1) << 16)); \ dmaPtr++; \ CHECK_FIFO(1); \ }
#define P3_DMA_GET_BUFFER_ENTRIES( fifo_count ) \
{ \ P3_DMA_GET_BUFFER(); \ WAIT_FIFO( fifo_count ); \ P3_ENSURE_DX_SPACE((fifo_count)); \ }
#define ADD_FUNNY_DWORD(a) \
{ \ MEMORY_BARRIER(); \ *dmaPtr++ = a; \ MEMORY_BARRIER(); \ CHECK_FIFO(1); \ }
//-----------------------------------------------------------------------------
//
// Setup/Clear discconnect signals
//
// Setting the FIFODiscon register to 1 forces host write retries until
// the data is accepted (might affect other time-critical processes though)
//
//-----------------------------------------------------------------------------
#if DBG
#define NO_FIFO_CHECK pThisDisplay->EntriesLeft = -20000;
#define END_NO_FIFO_CHECK pThisDisplay->EntriesLeft = 0;
#else
#define NO_FIFO_CHECK
#define END_NO_FIFO_CHECK
#endif
#define SET_DISCONNECT_CONTROL(val) \
if(pThisDisplay->pGLInfo->InterfaceType == GLINT_NON_DMA) \ { \ WAIT_FIFO(1); \ if(pThisDisplay->pGLInfo->dwFlags & GMVF_DELTA) \ { \ LOAD_GLINT_REG(DeltaDisconnectControl,val); \ } \ else \ { \ LOAD_GLINT_REG(FIFODiscon,val); \ } \ }
#define TURN_ON_DISCONNECT \
SET_DISCONNECT_CONTROL(0x1) \ NO_FIFO_CHECK #define TURN_OFF_DISCONNECT \
SET_DISCONNECT_CONTROL(0x0) \ END_NO_FIFO_CHECK
#define SET_D3D_DISCONNECT_CONTROL(val) \
if(pThisDisplay->pGLInfo->InterfaceType == GLINT_NON_DMA) \ { \ WAIT_FIFO(1); \ if(pThisDisplay->pGLInfo->dwFlags & GMVF_DELTA) \ { \ LOAD_GLINT_REG(DeltaDisconnectControl,val); \ } \ else \ { \ LOAD_GLINT_REG(FIFODiscon,val); \ } \ }
#define TURN_ON_D3D_DISCONNECT \
SET_D3D_DISCONNECT_CONTROL(0x1) \ NO_FIFO_CHECK
#define TURN_OFF_D3D_DISCONNECT \
SET_D3D_DISCONNECT_CONTROL(0x0) \ END_NO_FIFO_CHECK
//-----------------------------------------------------------------------------
//
// Macros used to switch the chips hardware context between DDRAW/D3D ops
//
//-----------------------------------------------------------------------------
#define DDRAW_OPERATION(pContext, pThisDisplay) \
{ \ ASSERTDD(pThisDisplay, "Error: pThisDisplay invalid in DDRAW_OPERATION!");\ if (!IS_DXCONTEXT_CURRENT(pThisDisplay)) \ { \ DXCONTEXT_IMMEDIATE(pThisDisplay); \ if (pThisDisplay->b2D_FIFOS == TRUE) \ { \ HWC_SwitchToFIFO(pThisDisplay, pThisDisplay->pGLInfo); \ } \ else \ { \ HWC_SwitchToDMA(pThisDisplay, pThisDisplay->pGLInfo); \ } \ HWC_SwitchToDDRAW(pThisDisplay, TRUE); \ pThisDisplay->pGLInfo->dwDirectXState = DIRECTX_LASTOP_2D; \ } \ else \ { \ if (pThisDisplay->pGLInfo->dwDirectXState != DIRECTX_LASTOP_2D) \ { \ if (pThisDisplay->b2D_FIFOS == TRUE) \ { \ HWC_SwitchToFIFO(pThisDisplay, pThisDisplay->pGLInfo); \ } \ else \ { \ HWC_SwitchToDMA(pThisDisplay, pThisDisplay->pGLInfo); \ } \ HWC_SwitchToDDRAW(pThisDisplay, FALSE); \ pThisDisplay->pGLInfo->dwDirectXState = DIRECTX_LASTOP_2D; \ } \ } \ }
#define D3D_OPERATION(pContext, pThisDisplay) \
{ \ ASSERTDD(pThisDisplay, "Error: pThisDisplay invalid in D3D_OPERATION!"); \ ASSERTDD(pContext, "Error: pContext invalid in D3D_OPERATION!"); \ if (!IS_DXCONTEXT_CURRENT(pThisDisplay)) \ { \ DXCONTEXT_IMMEDIATE(pThisDisplay); \ if (pContext->b3D_FIFOS == TRUE) \ { \ HWC_SwitchToFIFO(pThisDisplay, pThisDisplay->pGLInfo); \ } \ else \ { \ HWC_SwitchToDMA(pThisDisplay, pThisDisplay->pGLInfo); \ } \ HWC_SwitchToD3D(pContext, pThisDisplay, TRUE); \ pThisDisplay->pGLInfo->dwDirectXState = (ULONG_PTR)pContext; \ } \ else \ { \ if ((pThisDisplay->pGLInfo->dwDirectXState != (ULONG_PTR)pContext) || \ (pContext->dwDirtyFlags & CONTEXT_DIRTY_RENDER_OFFSETS)) \ { \ if (pContext->b3D_FIFOS == TRUE) \ { \ HWC_SwitchToFIFO(pThisDisplay, pThisDisplay->pGLInfo); \ } \ else \ { \ HWC_SwitchToDMA(pThisDisplay, pThisDisplay->pGLInfo); \ } \ HWC_SwitchToD3D(pContext, pThisDisplay, FALSE); \ pThisDisplay->pGLInfo->dwDirectXState = (ULONG_PTR)pContext; \ } \ } \ }
// Function to update the DDDRAW & D3D Software copy
void HWC_SwitchToDDRAW( P3_THUNKEDDATA* pThisDisplay, BOOL bDXEntry ); void HWC_SwitchToD3D(struct _p3_d3dcontext* pContext, struct tagThunkedData* pThisDisplay, BOOL bDXEntry);
#endif __DMA_H
|