⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fec.c

📁 motorola 针对coldfire 5275 评估板的Dbug bootloader源程序
💻 C
📖 第 1 页 / 共 3 页
字号:
     * Clear all FEC interrupt events
     */
    MCF_FEC_EIR(ch) = MCF_FEC_EIR_CLEAR_ALL;

    /*
     * Initialize the Receive Control Register
     */
    MCF_FEC_RCR(ch) = 0
        | MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM)
    #ifdef FEC_PROMISCUOUS
        | MCF_FEC_RCR_PROM
    #endif
        | MCF_FEC_RCR_FCE;

    if (mode == FEC_MODE_MII)
        MCF_FEC_RCR(ch) |= MCF_FEC_RCR_MII_MODE;

    else if (mode == FEC_MODE_LOOPBACK)
        MCF_FEC_RCR(ch) |= MCF_FEC_RCR_LOOP;

    /*
     * Initialize the Transmit Control Register
     */
    MCF_FEC_TCR(ch) = MCF_FEC_TCR_FDEN;

    /*
     * Set Rx FIFO alarm and granularity
     */
    MCF_FEC_FECRFCR(ch) = 0
        | MCF_FEC_FECRFCR_FRM
        | MCF_FEC_FECRFCR_RXW_MSK
        | MCF_FEC_FECRFCR_GR(7);
    MCF_FEC_FECRFAR(ch) = MCF_FEC_FECRFAR_ALARM(768);

    /*
     * Set Tx FIFO watermark, alarm and granularity
     */
    MCF_FEC_FECTFCR(ch) = 0
        | MCF_FEC_FECTFCR_FRM
        | MCF_FEC_FECTFCR_TXW_MSK
        | MCF_FEC_FECTFCR_GR(7);
    MCF_FEC_FECTFAR(ch) = MCF_FEC_FECTFAR_ALARM(256);
    MCF_FEC_FECTFWR(ch) = MCF_FEC_FECTFWR_X_WMRK_256;

    /*
     * Enable the transmitter to append the CRC
     */
    MCF_FEC_CTCWR(ch) = 0
        | MCF_FEC_CTCWR_TFCW
        | MCF_FEC_CTCWR_CRC;
}
/********************************************************************/
/*
 * Start the FEC Rx DMA task
 *
 * Parameters:
 *  ch      FEC channel
 *  rxbd    First Rx buffer descriptor in the chain
 */
void
fec_rx_start(uint8 ch, int8 *rxbd)
{
    uint32 initiator;
    int channel, result;

    ASSERT(ch == 0 || ch == 1);

    /*
     * Make the initiator assignment
     */
    result = dma_set_initiator(DMA_FEC_RX(ch));
    ASSERT(result == 0);

    /*
     * Grab the initiator number
     */
    initiator = dma_get_initiator(DMA_FEC_RX(ch));

    /*
     * Determine the DMA channel running the task for the
     * selected FEC
     */
    channel = dma_set_channel(DMA_FEC_RX(ch),
                              (ch == 0) ? fec0_rx_frame : fec1_rx_frame);
    ASSERT(channel != -1);

    /*
     * Start the Rx DMA task
     */
    /*
     * Start the Rx DMA task
     */
    MCD_startDma(channel,
                 (s8*)rxbd,
                 0,
                 (s8*)MCF_FEC_FECRFDR_ADDR(ch),
                 0,
                 RX_BUF_SZ,
                 0,
                 initiator,
                 FECRX_DMA_PRI(ch),
                 0 
                   | MCD_FECRX_DMA   
                   | MCD_INTERRUPT
                   | MCD_TT_FLAGS_CW 
                   | MCD_TT_FLAGS_RL
                   | MCD_TT_FLAGS_SP
                   ,
                 0 
                   | MCD_NO_CSUM
                   | MCD_NO_BYTE_SWAP
                 );
}
/********************************************************************/
/*
 * Continue the Rx DMA task
 *
 * This routine is called after the DMA task has halted after
 * encountering an Rx buffer descriptor that wasn't marked as
 * ready. There is no harm in calling the DMA continue routine
 * if the DMA is not halted.
 *
 * Parameters:
 *  ch      FEC channel
 */
void
fec_rx_continue(uint8 ch)
{
    int channel;

    ASSERT(ch == 0 || ch == 1);

    /*
     * Determine the DMA channel running the task for the
     * selected FEC
     */
    channel = dma_get_channel(DMA_FEC_RX(ch));
    ASSERT(channel != -1);

    /*
     * Continue/restart the DMA task
     */
    MCD_continDma(channel);
}
/********************************************************************/
/*
 * Stop all frame receptions on the selected FEC
 *
 * Parameters:
 *  ch  FEC channel
 */
void
fec_rx_stop (uint8 ch)
{
    uint32 mask;
    int channel;

    ASSERT(ch == 0 || ch == 1);

    /* Save off the EIMR value */
    mask = MCF_FEC_EIMR(ch);

    /* Mask all interrupts */
    MCF_FEC_EIMR(ch) = 0;

    /*
     * Determine the DMA channel running the task for the
     * selected FEC
     */
    channel = dma_get_channel(DMA_FEC_RX(ch));
    ASSERT(channel != -1);

    /* Kill the FEC Rx DMA task */
    MCD_killDma(channel);

    /* 
     * Free up the FEC requestor from the software maintained 
     * initiator list 
     */
    dma_free_initiator(DMA_FEC_RX(ch));

    /* Free up the DMA channel */
    dma_free_channel(DMA_FEC_RX(ch));

    /* Restore the interrupt mask register value */
    MCF_FEC_EIMR(ch) = mask;
}
/********************************************************************/
/*
 * Receive Frame interrupt handler - this handler is called by the 
 * DMA interrupt handler indicating that a packet was successfully
 * transferred out of the Rx FIFO.
 *
 * Parameters:
 *  nif     Pointer to Network Interface structure
 *  ch      FEC channel
 */
void
fec_rx_frame(uint8 ch, NIF *nif)
{
    ETH_HDR *eth_hdr;
    FECBD *pRxBD;
    NBUF *cur_nbuf, *new_nbuf;
    int keep;

    while ((pRxBD = fecbd_rx_alloc(ch)) != NULL)
    {
        fec_log[ch].drxf++;
        keep = TRUE;

        /*
         * Check the Receive Frame Status Word for errors
         *  - The L bit should always be set
         *  - No undefined bits should be set
         *  - The upper 5 bits of the length should be cleared
         */
        if (!(pRxBD->status & RX_BD_L) || (pRxBD->status & 0x0608) 
                                       || (pRxBD->length & 0xF800))
        {
            keep = FALSE;
            fec_log[ch].rfsw_inv++;
        }
        else if (pRxBD->status & RX_BD_ERROR)
        {
            keep = FALSE;
            if (pRxBD->status & RX_BD_NO)
                fec_log[ch].rfsw_no++;
            if (pRxBD->status & RX_BD_CR)
                fec_log[ch].rfsw_cr++;
            if (pRxBD->status & RX_BD_OV)
                fec_log[ch].rfsw_ov++;
            if (pRxBD->status & RX_BD_TR)
                fec_log[ch].rfsw_tr++;
        }
        else
        {
            if (pRxBD->status & RX_BD_LG)
                fec_log[ch].rfsw_lg++;
            if (pRxBD->status & RX_BD_M)
                fec_log[ch].rfsw_m++;
            if (pRxBD->status & RX_BD_BC)
                fec_log[ch].rfsw_bc++;
            if (pRxBD->status & RX_BD_MC)
                fec_log[ch].rfsw_mc++;
        }

        if (keep)
        {
            /* 
             * Pull the network buffer off the Rx ring queue 
             */
            cur_nbuf = nbuf_remove(NBUF_RX_RING);
            ASSERT(cur_nbuf);
            ASSERT(cur_nbuf->data == pRxBD->data);

            /*
             * Copy the buffer descriptor information to the network buffer
             */
            cur_nbuf->length = (pRxBD->length - (ETH_HDR_LEN + ETH_CRC_LEN));
            cur_nbuf->offset = ETH_HDR_LEN;

            /*
             * Get a new buffer pointer for this buffer descriptor
             */
            new_nbuf = nbuf_alloc();
            if (new_nbuf == NULL)
            {
                #ifdef DEBUG_PRINT
                    printf("nbuf_alloc() failed\n");
                #endif
                /*
                 * Can't allocate a new network buffer, so we
                 * have to trash the received data and reuse the buffer
                 * hoping that some buffers will free up in the system
                 * and this frame will be re-transmitted by the host
                 */
                pRxBD->length = RX_BUF_SZ;
                pRxBD->status &= (RX_BD_W | RX_BD_INTERRUPT);
                pRxBD->status |= RX_BD_E;
                nbuf_add(NBUF_RX_RING, cur_nbuf);
                fec_rx_continue(ch);
                continue;
            }

            /*
             * Add the new network buffer to the Rx ring queue
             */
            nbuf_add(NBUF_RX_RING, new_nbuf);

            /*
             * Re-initialize the buffer descriptor - pointing it
             * to the new data buffer.  The previous data buffer
             * will be passed up the stack
             */
            pRxBD->data = new_nbuf->data;
            pRxBD->length = RX_BUF_SZ;
            pRxBD->status &= (RX_BD_W | RX_BD_INTERRUPT);
            pRxBD->status |= RX_BD_E;


            /*
             * Let the DMA know that there is a new Rx BD (in case the 
             * ring was full and the DMA was waiting for an empty one)
             */
            fec_rx_continue(ch);

            /*
             * Get pointer to the frame data inside the network buffer
             */
            eth_hdr = (ETH_HDR *)cur_nbuf->data;
            
            /*
             * Pass the received packet up the network stack if the 
             * protocol is supported in our network interface (NIF)
             */
            if (nif_protocol_exist(nif,eth_hdr->type))
            {
                nif_protocol_handler(nif, eth_hdr->type, cur_nbuf);
            }
            else
                nbuf_free(cur_nbuf);
        }
        else 
        {
            /* 
             * This frame isn't a keeper
             * Reset the status and length, but don't need to get another
             * buffer since we are trashing the data in the current one
             */
            pRxBD->length = RX_BUF_SZ;
            pRxBD->status &= (RX_BD_W | RX_BD_INTERRUPT);
            pRxBD->status |= RX_BD_E;

            /*
             * Move the current buffer from the beginning to the end of the 
             * Rx ring queue
             */
            cur_nbuf = nbuf_remove(NBUF_RX_RING);
            nbuf_add(NBUF_RX_RING, cur_nbuf);

            /*
             * Let the DMA know that there are new Rx BDs (in case
             * it is waiting for an empty one)
             */
            fec_rx_continue(ch);
        }
    }
}

void
fec0_rx_frame(void)
{
    extern NIF nif1;
    fec_rx_frame(0, &nif1);
}

void
fec1_rx_frame(void)
{
    extern NIF nif1;
    fec_rx_frame(1, &nif1);
}
/********************************************************************/
/*
 * Start the FEC Tx DMA task
 *
 * Parameters:
 *  ch      FEC channel
 *  txbd    First Tx buffer descriptor in the chain
 */
void
fec_tx_start(uint8 ch, int8 *txbd)
{
    uint32 initiator;
    int channel, result;
    void fec0_tx_frame(void);
    void fec1_tx_frame(void);

    /*
     * Make the initiator assignment
     */
    result = dma_set_initiator(DMA_FEC_TX(ch));
    ASSERT(result == 0);

    /*
     * Grab the initiator number
     */
    initiator = dma_get_initiator(DMA_FEC_TX(ch));
    ASSERT(initiator != 0);

    /*
     * Determine the DMA channel running the task for the
     * selected FEC
     */
    channel = dma_set_channel(DMA_FEC_TX(ch),
                              (ch == 0) ? fec0_tx_frame : fec1_tx_frame);
    ASSERT(channel != -1);

    /*
     * Start the Tx DMA task
     */
    MCD_startDma(channel,
                 (s8*)txbd,
                 0,
                 (s8*)MCF_FEC_FECTFDR_ADDR(ch),
                 0,
                 ETH_MTU,
                 0,
                 initiator,
                 FECTX_DMA_PRI(ch),
                 0 
                   | MCD_FECTX_DMA   
                   | MCD_INTERRUPT
                   | MCD_TT_FLAGS_CW 
                   | MCD_TT_FLAGS_RL
                   | MCD_TT_FLAGS_SP
                   ,
                 0 
                   | MCD_NO_CSUM
                   | MCD_NO_BYTE_SWAP
                 );
}
/********************************************************************/
/*
 * Continue the Tx DMA task
 *
 * This routine is called after the DMA task has halted after
 * encountering an Tx buffer descriptor that wasn't marked as
 * ready.  There is no harm in calling the continue DMA routine
 * if the DMA was not paused.
 *
 * Parameters:
 *  ch      FEC channel
 */
void
fec_tx_continue(uint8 ch)
{
    int channel;

    /*
     * Determine the DMA channel running the task for the
     * selected FEC
     */
    channel = dma_get_channel(DMA_FEC_TX(ch));
    ASSERT(channel > 0);

    /*
     * Continue/restart the DMA task
     */
    MCD_continDma((int)channel);
}
/********************************************************************/
/*
 * Stop all transmissions on the selected FEC and kill the DMA task
 *
 * Parameters:
 *  ch  FEC channel
 */
void
fec_tx_stop (uint8 ch)
{
    uint32 mask;
    int channel;

    ASSERT(ch == 0 || ch == 1);

    /* Save off the EIMR value */
    mask = MCF_FEC_EIMR(ch);

    /* Mask all interrupts */
    MCF_FEC_EIMR(ch) = 0;

    /* If the Ethernet is still enabled... */
    if (MCF_FEC_ECR(ch) & MCF_FEC_ECR_ETHER_EN)
    {
        /* Issue the Graceful Transmit Stop */
        MCF_FEC_TCR(ch) |= MCF_FEC_TCR_GTS;

        /* Wait for the Graceful Stop Complete interrupt */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -