XStatus init_dma()

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;
}