in portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_dma.c [518:702]
XStatus init_dma( xemacpsif_s * xemacpsif )
{
NetworkBufferDescriptor_t * pxBuffer;
int iIndex;
UBaseType_t xRxSize;
UBaseType_t xTxSize;
struct xtopology_t * xtopologyp = &xXTopology;
XEmacPs_BdRing * rxRing;
XEmacPs * emac = &( xemacpsif->emacps );
XEmacPs_Bd bdTemplate;
XEmacPs_Bd * dmaBdPtr = NULL;
uint32_t status;
xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );
xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );
xemacpsif->uTxUnitSize = ( dmaRX_TX_BUFFER_SIZE + 0x1000UL ) & ~0xfffUL;
/*
* We allocate 65536 bytes for RX BDs which can accommodate a
* maximum of 8192 BDs which is much more than any application
* will ever need.
*/
xemacpsif->rxSegments = ( struct xBD_TYPE * ) ( pucGetUncachedMemory( xRxSize ) );
xemacpsif->txSegments = ( struct xBD_TYPE * ) ( pucGetUncachedMemory( xTxSize ) );
configASSERT( xemacpsif->rxSegments );
configASSERT( xemacpsif->txSegments );
configASSERT( ( ( ( uintptr_t ) xemacpsif->rxSegments ) % XEMACPS_DMABD_MINIMUM_ALIGNMENT ) == 0 );
configASSERT( ( ( ( uintptr_t ) xemacpsif->txSegments ) % XEMACPS_DMABD_MINIMUM_ALIGNMENT ) == 0 );
rxRing = &( XEmacPs_GetRxRing( emac ) );
XEmacPs_BdClear( bdTemplate );
status = XEmacPs_BdRingCreate( rxRing, ( UINTPTR ) xemacpsif->rxSegments,
( UINTPTR ) xemacpsif->rxSegments, XEMACPS_DMABD_MINIMUM_ALIGNMENT,
ipconfigNIC_N_RX_DESC );
if( status != 0 )
{
return status;
}
status = XEmacPs_BdRingClone( rxRing, &bdTemplate, XEMACPS_RECV );
if( status != 0 )
{
return status;
}
if( xTXDescriptorSemaphore == NULL )
{
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );
configASSERT( xTXDescriptorSemaphore != NULL );
}
/*
* Allocate RX descriptors, 1 RxBD at a time.
*/
for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )
{
pxBuffer = pxDMA_rx_buffers[ iIndex ];
if( pxBuffer == NULL )
{
pxBuffer = pxGetNetworkBufferWithDescriptor( dmaRX_TX_BUFFER_SIZE, ( TickType_t ) 0 );
if( pxBuffer == NULL )
{
FreeRTOS_printf( ( "Unable to allocate a network buffer in recv_handler\n" ) );
return -1;
}
}
status = XEmacPs_BdRingAlloc( rxRing, 1, &dmaBdPtr );
if( status != 0 )
{
return status;
}
XEmacPs_BdSetAddressRx( dmaBdPtr,
( ( uintptr_t ) pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK );
status = XEmacPs_BdRingToHw( rxRing, 1, dmaBdPtr );
if( status != 0 )
{
return status;
}
/* Writing for debug - can look at it in RX processing */
xemacpsif->rxSegments[ iIndex ].reserved = iIndex;
pxDMA_rx_buffers[ iIndex ] = pxBuffer;
/* Make sure this memory is not in cache for now. */
if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
{
Xil_DCacheInvalidateRange( ( ( uintptr_t ) pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,
( unsigned ) dmaRX_TX_BUFFER_SIZE );
}
}
xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;
clean_dma_txdescs( xemacpsif );
{
uint32_t value;
value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );
/* 1xxxx: Attempt to use INCR16 AHB bursts */
value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
value |= XEMACPS_DMACR_TCPCKSUM_MASK;
#else
#warning Are you sure the EMAC should not calculate outgoing checksums?
value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;
#endif
XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );
}
{
uint32_t value;
value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
/* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).
* Now tell the EMAC that received messages should be stored at "address + 2". */
value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;
#if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
#else
#warning Are you sure the EMAC should not calculate incoming checksums?
value &= ~( ( uint32_t ) XEMACPS_NWCFG_RXCHKSUMEN_MASK );
#endif
XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );
}
/* Set terminating BDs for US+ GEM */
if( xemacpsif->emacps.Version > 2 )
{
xemacpsif->rxBdTerminator = ( struct xBD_TYPE * ) pucGetUncachedMemory( sizeof( *xemacpsif->rxBdTerminator ) );
xemacpsif->txBdTerminator = ( struct xBD_TYPE * ) pucGetUncachedMemory( sizeof( *xemacpsif->txBdTerminator ) );
XEmacPs_BdClear( xemacpsif->rxBdTerminator );
XEmacPs_BdSetAddressRx( xemacpsif->rxBdTerminator, ( XEMACPS_RXBUF_NEW_MASK |
XEMACPS_RXBUF_WRAP_MASK ) );
XEmacPs_Out32( ( emac->Config.BaseAddress + XEMACPS_RXQ1BASE_OFFSET ),
( UINTPTR ) xemacpsif->rxBdTerminator );
XEmacPs_BdClear( xemacpsif->txBdTerminator );
XEmacPs_BdSetStatus( xemacpsif->txBdTerminator,
( XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK ) );
XEmacPs_Out32( ( emac->Config.BaseAddress + XEMACPS_TXQBASE_OFFSET ),
( UINTPTR ) xemacpsif->txBdTerminator );
}
/* These variables will be used in XEmacPs_Start (see src/xemacps.c). */
XEmacPs_SetQueuePtr( emac, ( uintptr_t ) xemacpsif->rxSegments, 0, XEMACPS_RECV );
if( xemacpsif->emacps.Version > 2 )
{
XEmacPs_SetQueuePtr( emac, ( uintptr_t ) xemacpsif->txSegments, 1, XEMACPS_SEND );
}
else
{
XEmacPs_SetQueuePtr( emac, ( uintptr_t ) xemacpsif->txSegments, 0, XEMACPS_SEND );
}
XScuGic_Connect( &xInterruptController,
xtopologyp->scugic_emac_intr,
XEmacPs_IntrHandler,
emac );
/*
* Enable the interrupt for emacps.
*/
EmacEnableIntr();
return 0;
}