📄 dma1.c
字号:
if ( DMA_Get_Stat( host, eumbbar, channel, &stat ) != DMASUCCESS )
{
return DMAINVALID;
}
if ( stat.cb == 1 )
{
/* DMA is not free */
return DMACHNBUSY;
}
mode = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG] );
/* clear DMA_MR(CS) */
mode &= 0xfffffffe;
store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode );
/* set DMA_MR(CS) */
mode |= CS;
store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode );
return DMASUCCESS;
}
/***********************************************************
* function: DMA_Halt
*
* description: halt the current dma transaction on the specified
* channel.
* return DMASUCCESS if success otherwise return DMAINVALID
*
* note: if the specified DMA channel is idle, nothing happens
*************************************************************/
static
DMAStatus DMA_Halt( LOCATION host, unsigned int eumbbar, unsigned int channel )
{
unsigned int mode;
if ( channel != 0 && channel != 1 )
{
return DMAINVALID;
}
mode = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG]);
/* clear DMA_MR(CS) */
mode &= 0xfffffffe;
store_runtime_reg(eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode );
return DMASUCCESS;
}
/*************************************************************
* function: DMA_Chn_Cnt
*
* description: set the DMA_MR(CC) bit for a given channel
* that is in chaining mode.
* return DMASUCCESS if successfule, otherwise return
* DMAINVALID.
*
* note: if the given channel is not in chaining mode, nothing
* happen.
*
*************************************************************/
static
DMAStatus DMA_Chn_Cnt( LOCATION host, unsigned int eumbbar, unsigned int channel )
{
DMA_MR mode;
if ( channel != 0 && channel != 1 )
{
return DMAINVALID;
}
if ( DMA_Get_Mode( host, eumbbar, channel, &mode ) != DMASUCCESS )
{
return DMAINVALID;
}
if ( mode.ctm == 0 )
{
/* either illegal mode or not chaining mode */
return DMAINVALID;
}
mode.cc = 1;
return DMA_Set_Mode( host, eumbbar, channel, mode );
}
/**************************************************************
* function: DMA_Bld_Desp
*
* description: set current descriptor address register
* according to the desp for a given channel
*
* if the given channel is busy return DMACHNBUSY
* and no change made, otherwise return DMASUCCESS.
*
* note:
**************************************************************/
static
DMAStatus DMA_Bld_Desp( LOCATION host,
unsigned int eumbbar,
unsigned int channel,
DMA_CDAR desp )
{
DMA_SR status;
unsigned int temp;
if ( channel != 0 && channel != 1 )
{
/* channel number out of range */
return DMAINVALID;
}
if ( DMA_Get_Stat( host, eumbbar, channel, &status ) != DMASUCCESS )
{
return DMAINVALID;
}
if ( status.cb == 1 )
{
/* channel busy */
return DMACHNBUSY;
}
temp = ( desp.cda & 0x7ffffff ) << 5;
temp |= (( desp.snen & 0x1 ) << 4 );
temp |= (( desp.eosie & 0x1 ) << 3 );
temp |= (( desp.ctt & 0x3 ) << 1 );
temp |= ( desp.eotd & 0x1 );
store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], temp );
#ifdef DMADBG0
PRINT( "%s(%d): %s DMA %d (0x%08x) cdar := 0x%08x\n", __FILE__, __LINE__,
( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], temp );
#endif
return DMASUCCESS;
}
/**************************************************************
* function: DMA_Poke_Desp
*
* description: poke the current descriptor address register
* for a given channel
*
* return DMASUCCESS if no error
*
* note: Due to the undeterministic parallellism of DMA operation,
* the value returned by this function shall be taken as
* the most recently used descriptor when the last time
* DMA starts a chaining mode operation.
**************************************************************/
static
DMAStatus DMA_Poke_Desp( LOCATION host,
unsigned int eumbbar,
unsigned int channel,
DMA_CDAR *desp )
{
unsigned int cdar;
if ( channel != 0 && channel != 1 || desp == 0 )
{
return DMAINVALID;
}
cdar = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG] );
#ifdef DMADBG0
PRINT( "%s(%d): %s DMA %d (0x%08x) cdar : 0x%08x\n", __FILE__, __LINE__,
( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], cdar );
#endif
desp->cda = ( cdar & 0xffffffe0 ) >> 5;
desp->snen = ( cdar & 0x00000010 ) >> 4;
desp->eosie = ( cdar & 0x00000008 ) >> 3;
desp->ctt = ( cdar & 0x00000006 ) >> 1;
desp->eotd = ( cdar & 0x00000001 );
return DMASUCCESS;
}
/**************************************************************
* function: DMA_Bld_Curr
*
* description: set current src, dest, byte count registers
* according to the desp for a given channel
* return DMASUCCESS if no error.
*
* note:
**************************************************************/
static
DMAStatus DMA_Bld_Curr( LOCATION host,
unsigned int eumbbar,
unsigned int channel,
DMA_CURR desp )
{
DMA_SR status;
if ( channel != 0 && channel != 1 )
{
/* channel number out of range */
return DMAINVALID;
}
if ( DMA_Get_Stat( host, eumbbar, channel, &status ) != DMASUCCESS )
{
return DMAINVALID;
}
if ( status.cb == 1 )
{
/* channel busy */
return DMACHNBUSY;
}
desp.byte_cnt &= 0x03ffffff; /* upper 6-bits are 0s */
store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SAR_REG], desp.src_addr );
#ifdef DMADBG0
PRINT( "%s(%d): %s DMA %d (0x%08x) src := 0x%08x\n", __FILE__, __LINE__,
( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.src_addr );
#endif
store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_DAR_REG], desp.dest_addr );
#ifdef DMADBG0
PRINT( "%s(%d): %s DMA %d (0x%08x) dest := 0x%08x\n", __FILE__, __LINE__,
( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.dest_addr );
#endif
store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_BCR_REG], desp.byte_cnt );
#ifdef DMADBG0
PRINT( "%s(%d): %s DMA %d (0x%08x) count := 0x%08x\n", __FILE__, __LINE__,
( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.byte_cnt );
#endif
return DMASUCCESS;
}
/**************************************************************
* function: DMA_Poke_Curr
*
* description: poke the current src, dest, byte count registers
* for a given channel.
*
* return DMASUCCESS if no error
*
* note: Due to the undeterministic parallelism, in chaining
* mode, the value returned by this function shall
* be taken as reference when the query is made rather
* than the absolute snapshot when the value is returned.
**************************************************************/
static
DMAStatus DMA_Poke_Curr( LOCATION host,
unsigned int eumbbar,
unsigned int channel,
DMA_CURR* desp )
{
if ( channel != 0 && channel != 1 || desp == 0 )
{
return DMAINVALID;
}
desp->src_addr = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SAR_REG] );
#ifdef DMADBG0
PRINT( "%s(%d): %s DMA %d (0x%08x) src : 0x%08x\n", __FILE__, __LINE__,
( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->src_addr );
#endif
desp->dest_addr = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_DAR_REG] );
#ifdef DMADBG0
PRINT( "%s(%d): %s DMA %d (0x%08x) dest : 0x%08x\n", __FILE__, __LINE__,
( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->dest_addr );
#endif
desp->byte_cnt = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_BCR_REG] );
#ifdef DMADBG0
PRINT( "%s(%d): %s DMA %d (0x%08x) count : 0x%08x\n", __FILE__, __LINE__,
( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->byte_cnt );
#endif
return DMASUCCESS;
}
/*****************************************************************
* function: dma_error_func
*
* description: display the error information
*
* note: This seems like a highly convoluted way to handle messages,
* but I'll leave it as it was in device.c when I moved it into the
* DMA library source.
****************************************************************/
static
DMAStatus dma_error_func( unsigned int eumbbar, unsigned int chn, DMAStatus err)
{
unsigned char *msg[] =
{
"Local Memory Error",
"PCI Error",
"Channel Busy",
"End-of-Segment Interrupt",
"End-of-Chain/Direct Interrupt",
};
if ( err >= DMALMERROR && err <= DMAEOCAINT )
{
PRINT( "DMA Status: channel %d %s\n", chn, msg[err-DMASUCCESS-1] );
}
return err;
}
/*************************************************************
* function: DMA_ISR
*
* description: DMA interrupt service routine
* return DMAStatus value based on
* the status
*
*************************************************************/
static
DMAStatus DMA_ISR( unsigned int eumbbar,
unsigned int channel,
DMAStatus (*lme_func)( unsigned int, unsigned int, DMAStatus ),
DMAStatus (*pe_func) ( unsigned int, unsigned int, DMAStatus ),
DMAStatus (*eosi_func)( unsigned int, unsigned int, DMAStatus ),
DMAStatus (*eocai_func)(unsigned int, unsigned int, DMAStatus ))
{
DMA_SR stat;
DMAStatus rval = DMANOEVENT;
unsigned int temp;
if ( channel != 0 && channel != 1 )
{
return DMAINVALID;
}
if ( DMA_Get_Stat( LOCAL, eumbbar, channel, &stat ) != DMASUCCESS )
{
return DMAINVALID;
}
if ( stat.lme == 1 )
{
/* local memory error */
rval = DMALMERROR;
if ( lme_func != 0 )
{
rval = (*lme_func)(eumbbar, channel, DMALMERROR );
}
}
else if ( stat.pe == 1 )
{
/* PCI error */
rval = DMAPERROR;
if ( pe_func != 0 )
{
rval = (*pe_func)(eumbbar, channel, DMAPERROR );
}
}
else if ( stat.eosi == 1 )
{
/* end-of-segment interrupt */
rval = DMAEOSINT;
if ( eosi_func != 0 )
{
rval = (*eosi_func)(eumbbar, channel, DMAEOSINT );
}
}
else
{
/* End-of-chain/direct interrupt */
rval = DMAEOCAINT;
if ( eocai_func != 0 )
{
rval = (*eocai_func)(eumbbar, channel, DMAEOCAINT );
}
}
temp = ( stat.reserved0 & 0xffffff ) << 8;
temp |= ( ( stat.lme & 0x1 ) << 7 ); /* write one to clear */
temp |= ( ( stat.reserved1 & 0x3 ) << 5 );
temp |= ( ( stat.pe & 0x1 ) << 4 ); /* write one to clear */
temp |= ( ( stat.reserved2 & 0x1 ) << 3 );
temp |= ( ( stat.cb & 0x1 ) << 2 ); /* write one to clear */
temp |= ( ( stat.eosi & 0x1 ) << 1 ); /* write one to clear */
temp |= ( stat.eocai & 0x1 ); /* write one to clear */
store_runtime_reg( eumbbar, dma_reg_tb[LOCAL][channel*NUM_DMA_REG + DMA_SR_REG], temp );
#ifdef DMADBG0
PRINT( "%s(%d): DMA channel %d SR := 0x%08x\n", __FILE__, __LINE__, channel, temp );
#endif
return rval;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -