int SH7619_EDMAC_xmit(PIFACE pi, DCU msg)
{
	RTP_UINT16              length = 0;
	EmacTDescriptor *pTxTd;
	char* send_packet;
	UINT16  count;
	long    flag = FP1;
	UINT16  size = length;

	GLOBAL_LOCK(encIrq);

	if (!pi)
	{
		return (-1);
	}   

	length = msg->length;

	if (length > (ETHERSIZE+4))
	{
		RTP_DEBUG_ERROR("xmit - length is too large, truncated", NOVAR, 0, 0);
		length = ETHERSIZE+4;         /* what a terriable hack! */
	}

	send_packet = (char*)DCUTODATA(msg);

	for( count = 0 ; length > 0 ; length -= count )
	{  
    	// Pointers to the current TxTd
    	pTxTd = *(txTd.td + txTd.head);
		while( (count = Send_Packet(pTxTd, send_packet, length)) < 0 );
		if( count == length )
		{
			flag |= FP0;
		}
		pTxTd->status = (pTxTd->status & DL) | flag | ACT;
		flag = 0;

		// Driver manage the ring buffer
		CIRC_INC(txTd.head, TX_BUFFERS)

		send_packet += count;
	}

	// Now start to transmit if it is not already done
	if( EDTRR0 == 0x00000000 )
	{
		EDTRR0 = 0x00000001;
	}

	return (0);
}
Beispiel #2
0
void EMAC_Discard_Fragments(void) {
    unsigned int   tmpIdx = rxTd.idx;
    volatile EmacRxTDescriptor *pRxTd = rxTd.td + rxTd.idx;

    do {
        if ((pRxTd->addr & EMAC_RX_OWNERSHIP_BIT) != EMAC_RX_OWNERSHIP_BIT) {
            break;
        }

        pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
        CIRC_INC(rxTd.idx, RX_BUFFERS);

        pRxTd = rxTd.td + rxTd.idx;

        if ((pRxTd->status & EMAC_RX_SOF_BIT) == EMAC_RX_SOF_BIT) {
            break;
        }
    } while (tmpIdx != rxTd.idx);
}
void AT91_EMAC_LWIP_interrupt(struct netif *pNetIf)
{
    UINT32 emac_isr;
    UINT32 emac_rsr;
    UINT32 emac_tsr;

    AT91_EMAC &emac = AT91_EMAC::EMAC();
    
    GLOBAL_LOCK(encIrq);

    emac_isr = emac.EMAC_ISR & emac.EMAC_IMR;
    emac_rsr = emac.EMAC_RSR;
    emac_tsr = emac.EMAC_TSR;
    
    /* Frame(s) received */
    if((emac_isr & AT91_EMAC::EMAC_RCOMP) || (emac_rsr & AT91_EMAC::EMAC_REC))
    {
        emac.EMAC_RSR |= emac_rsr;
        lwip_interrupt_continuation();
    }

    /* a Frame is transmitted */
    if((emac_isr & AT91_EMAC::EMAC_TCOMP) || (emac_tsr & AT91_EMAC::EMAC_COMP))
    {
        volatile EmacTDescriptor *pTxTd;

        emac.EMAC_TSR |= emac_tsr;

        // Check the buffers
        while (CIRC_CNT(txTd.head, txTd.tail, TX_BUFFERS))
        {
            pTxTd = txTd.td + txTd.tail;         

            // Exit if buffer has not been sent yet
            if (!(pTxTd->status & EMAC_TX_USED_BIT))            
                break;
            
            CIRC_INC( txTd.tail, TX_BUFFERS );
        }
    }
    
}
Beispiel #4
0
//-----------------------------------------------------------------------------
/// Receive a packet with EMAC
/// If not enough buffer for the packet, the remaining data is lost but right
/// frame length is returned.
/// \param pFrame           Buffer to store the frame
/// \param frameSize        Size of the frame
/// \param pRcvSize         Received size
/// \return                 OK, no data, or frame too small
//-----------------------------------------------------------------------------
unsigned char EMAC_Poll(unsigned char *pFrame,
                        unsigned int frameSize,
                        unsigned int *pRcvSize)
{
    unsigned short bufferLength;
    unsigned int   tmpFrameSize=0;
    unsigned char  *pTmpFrame=0;
    unsigned int   tmpIdx = rxTd.idx;
    volatile EmacRxTDescriptor *pRxTd = rxTd.td + rxTd.idx;

    ASSERT(pFrame, "F: EMAC_Poll\n\r");

    char isFrame = 0;
    // Set the default return value
    *pRcvSize = 0;

    // Process received RxTd
    while ((pRxTd->addr & EMAC_RX_OWNERSHIP_BIT) == EMAC_RX_OWNERSHIP_BIT) {

        // A start of frame has been received, discard previous fragments
        if ((pRxTd->status & EMAC_RX_SOF_BIT) == EMAC_RX_SOF_BIT) {
            // Skip previous fragment
            while (tmpIdx != rxTd.idx) {
                pRxTd = rxTd.td + rxTd.idx;
                pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
                CIRC_INC(rxTd.idx, RX_BUFFERS);
            }
            // Reset the temporary frame pointer
            pTmpFrame = pFrame;
            tmpFrameSize = 0;
            // Start to gather buffers in a frame
            isFrame = 1;
        }

        // Increment the pointer
        CIRC_INC(tmpIdx, RX_BUFFERS);

        // Copy data in the frame buffer
        if (isFrame) {
            if (tmpIdx == rxTd.idx) {
                TRACE_INFO("no EOF (Invalid of buffers too small)\n\r");

                do {

                    pRxTd = rxTd.td + rxTd.idx;
                    pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
                    CIRC_INC(rxTd.idx, RX_BUFFERS);
                } while(tmpIdx != rxTd.idx);
                return EMAC_RX_NO_DATA;
            }
            // Copy the buffer into the application frame
            bufferLength = EMAC_RX_UNITSIZE;
            if ((tmpFrameSize + bufferLength) > frameSize) {
                bufferLength = frameSize - tmpFrameSize;
            }

            memcpy(pTmpFrame, (void*)(pRxTd->addr & EMAC_ADDRESS_MASK), bufferLength);
            pTmpFrame += bufferLength;
            tmpFrameSize += bufferLength;
            
            // An end of frame has been received, return the data
            if ((pRxTd->status & EMAC_RX_EOF_BIT) == EMAC_RX_EOF_BIT) {
                // Frame size from the EMAC
                *pRcvSize = (pRxTd->status & EMAC_LENGTH_FRAME);
                
                // Application frame buffer is too small all data have not been copied
                if (tmpFrameSize < *pRcvSize) {
                    printf("size req %d size allocated %d\n\r", *pRcvSize, frameSize);
                    
                    return EMAC_RX_FRAME_SIZE_TOO_SMALL;
                }
                
                TRACE_DEBUG("packet %d-%d (%d)\n\r", rxTd.idx, tmpIdx, *pRcvSize);
                // All data have been copied in the application frame buffer => release TD
                while (rxTd.idx != tmpIdx) {
                    pRxTd = rxTd.td + rxTd.idx;
                    pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
                    CIRC_INC(rxTd.idx, RX_BUFFERS);
                }
                EmacStatistics.rx_packets++;
                return EMAC_RX_OK;
            }
        }
        
        // SOF has not been detected, skip the fragment
        else {
           pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
           rxTd.idx = tmpIdx;
        }
       
        // Process the next buffer
        pRxTd = rxTd.td + tmpIdx;
    }
    
    //TRACE_DEBUG("E");
    return EMAC_RX_NO_DATA;
}
Beispiel #5
0
//-----------------------------------------------------------------------------
/// Send a packet with EMAC.
/// If the packet size is larger than transfer buffer size error returned.
/// If packet transfer status is monitored, specify callback for each packet.
/// \param buffer   The buffer to be send
/// \param size     The size of buffer to be send
/// \param fEMAC_TxCallback Threshold Wakeup callback
/// \param fWakeUpCb   TX Wakeup
/// \return         OK, Busy or invalid packet
//-----------------------------------------------------------------------------
unsigned char EMAC_Send(void *pBuffer,
                        unsigned int size,
                        EMAC_TxCallback fEMAC_TxCallback)
{
    volatile EmacTxTDescriptor *pTxTd;
    volatile EMAC_TxCallback   *pTxCb;

    //TRACE_DEBUG("EMAC_Send\n\r");

    // Check parameter
    if (size > EMAC_TX_UNITSIZE) {

        TRACE_ERROR("EMAC driver does not split send packets.");
        TRACE_ERROR("%d bytes max in one packet (%d bytes requested)\n\r",
            EMAC_TX_UNITSIZE, size);
        return EMAC_TX_INVALID_PACKET;
    }

    // Pointers to the current TxTd
    pTxTd = txTd.td + txTd.head;

    // If no free TxTd, buffer can't be sent, schedule the wakeup callback
    if( CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) == 0) {
        if ((pTxTd->status & EMAC_TX_USED_BIT) != 0) {
            //EMAC_ResetTx();
            //TRACE_WARNING("Circ Full but FREE TD found\n\r");
            //AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TE;
        }
        //else {
            return EMAC_TX_BUFFER_BUSY;
        //}
    }

    // Pointers to the current TxTd
    pTxCb = txTd.txCb + txTd.head;

    // Sanity check

    // Setup/Copy data to transmition buffer
    if (pBuffer && size) {
        // Driver manage the ring buffer
        memcpy((void *)pTxTd->addr, pBuffer, size);
    }
    
    // Tx Callback
    *pTxCb = fEMAC_TxCallback;

    // Update TD status
    // The buffer size defined is length of ethernet frame
    // so it's always the last buffer of the frame.
    if (txTd.head == TX_BUFFERS-1) {
        pTxTd->status = 
            (size & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT | EMAC_TX_WRAP_BIT;
    }
    else {
        pTxTd->status = (size & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT;
    }
    
    CIRC_INC(txTd.head, TX_BUFFERS)

    // Tx packets count
    EmacStatistics.tx_packets++;

    // Now start to transmit if it is not already done
    AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;

    return EMAC_TX_OK;
}
Beispiel #6
0
//-----------------------------------------------------------------------------
/// EMAC Interrupt handler
//-----------------------------------------------------------------------------
void EMAC_Handler(void)
{
    volatile EmacTxTDescriptor *pTxTd;
    volatile EMAC_TxCallback   *pTxCb;
    volatile unsigned int isr;
    volatile unsigned int rsr;
    volatile unsigned int tsr;
    unsigned int rxStatusFlag;
    unsigned int txStatusFlag;

    //TRACE_DEBUG("EMAC_Handler\n\r");
    isr = AT91C_BASE_EMAC->EMAC_ISR;
    rsr = AT91C_BASE_EMAC->EMAC_RSR;
    tsr = AT91C_BASE_EMAC->EMAC_TSR;
    isr &= ~(AT91C_BASE_EMAC->EMAC_IMR | 0xFFC300);

    // RX packet
    if ((isr & AT91C_EMAC_RCOMP) || (rsr & AT91C_EMAC_REC)) {
        rxStatusFlag = AT91C_EMAC_REC;

        // Frame received
        EmacStatistics.rx_packets++;

        // Check OVR
        if (rsr & AT91C_EMAC_OVR) {
            rxStatusFlag |= AT91C_EMAC_OVR;
            EmacStatistics.rx_ovrs++;
        }
        // Check BNA
        if (rsr & AT91C_EMAC_BNA) {
            rxStatusFlag |= AT91C_EMAC_BNA;
            EmacStatistics.rx_bnas++;
        }
        // Clear status
        AT91C_BASE_EMAC->EMAC_RSR |= rxStatusFlag;

        // Invoke callbacks
        if (rxTd.rxCb) {
            rxTd.rxCb(rxStatusFlag);
        }
    }

    // TX packet
    if ((isr & AT91C_EMAC_TCOMP) || (tsr & AT91C_EMAC_COMP)) {

        txStatusFlag = AT91C_EMAC_COMP;
        EmacStatistics.tx_comp ++;

        // A frame transmitted
        // Check RLE
        if (tsr & AT91C_EMAC_RLES) {
            // Status RLE & Number of discarded buffers
            txStatusFlag = AT91C_EMAC_RLES
                         | CIRC_CNT(txTd.head, txTd.tail, TX_BUFFERS);
            pTxCb = txTd.txCb + txTd.tail;
            EMAC_ResetTx();
            TRACE_INFO("Tx RLE!!\n\r");
            AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TE;
            EmacStatistics.tx_errors++;
        }
        // Check COL
        if (tsr & AT91C_EMAC_COL) {
            txStatusFlag |= AT91C_EMAC_COL;
            EmacStatistics.collisions++;
        }
        // Check BEX
        if (tsr & AT91C_EMAC_BEX) {
            txStatusFlag |= AT91C_EMAC_BEX;
            EmacStatistics.tx_exausts++;
        }
        // Check UND
        if (tsr & AT91C_EMAC_UND) {
            txStatusFlag |= AT91C_EMAC_UND;
            EmacStatistics.tx_underruns++;
        }
        // Clear status
        AT91C_BASE_EMAC->EMAC_TSR |= txStatusFlag;

        if (!CIRC_EMPTY(&txTd))
        {
            // Check the buffers
            do {
                pTxTd = txTd.td + txTd.tail;
                pTxCb = txTd.txCb + txTd.tail;
                // Any error?
                // Exit if buffer has not been sent yet
                if ((pTxTd->status & EMAC_TX_USED_BIT) == 0) {
                    break;
                }

                // Notify upper layer that a packet has been sent
                if (*pTxCb) {
                    (*pTxCb)(txStatusFlag);
                }

                CIRC_INC( txTd.tail, TX_BUFFERS );
            } while (CIRC_CNT(txTd.head, txTd.tail, TX_BUFFERS));
        }
        
        if (tsr & AT91C_EMAC_RLES) {
            // Notify upper layer RLE
            if (*pTxCb) {
                (*pTxCb)(txStatusFlag);
            }
        }
        
        // If a wakeup has been scheduled, notify upper layer that it can  
        // send other packets, send will be successfull.
        if( (CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) >=
                                            txTd.wakeupThreshold)
         &&  txTd.wakeupCb) {
            txTd.wakeupCb();
        }
    }

    // PAUSE Frame
    if (isr & AT91C_EMAC_PFRE) {
        TRACE_INFO("Pause!\n\r");
    }
    if (isr & AT91C_EMAC_PTZ) {
        TRACE_INFO("Pause TO!\n\r");
    }
}
Beispiel #7
0
//-----------------------------------------------------------------------------
/// EMAC Interrupt handler
//-----------------------------------------------------------------------------
void EMAC_Handler(void)
{
    volatile EmacTxTDescriptor *pTxTd;
    volatile EMAC_TxCallback   *pTxCb;
    unsigned int isr;
    unsigned int rsr;
    unsigned int tsr;
    unsigned int rxStatusFlag;
    unsigned int txStatusFlag;

    //TRACE_DEBUG("EMAC_Handler\n\r");
    isr = AT91C_BASE_EMAC->EMAC_ISR & AT91C_BASE_EMAC->EMAC_IMR;
    rsr = AT91C_BASE_EMAC->EMAC_RSR;
    tsr = AT91C_BASE_EMAC->EMAC_TSR;

    // RX packet
    if ((isr & AT91C_EMAC_RCOMP) || (rsr & AT91C_EMAC_REC)) {
        rxStatusFlag = AT91C_EMAC_REC;

        // Frame received
        EmacStatistics.rx_packets++;

        // Check OVR
        if (rsr & AT91C_EMAC_OVR) {
            rxStatusFlag |= AT91C_EMAC_OVR;
            EmacStatistics.rx_ovrs++;
        }
        // Check BNA
        if (rsr & AT91C_EMAC_BNA) {
            rxStatusFlag |= AT91C_EMAC_BNA;
            EmacStatistics.rx_bnas++;
        }
        // Clear status
        AT91C_BASE_EMAC->EMAC_RSR |= rxStatusFlag;

        // Invoke callbacks
        if (rxTd.rxCb) {
            rxTd.rxCb(rxStatusFlag);
        }
    }

    // TX packet
    if ((isr & AT91C_EMAC_TCOMP) || (tsr & AT91C_EMAC_COMP)) {

        txStatusFlag = AT91C_EMAC_COMP;
        EmacStatistics.tx_comp ++;

        // A frame transmitted
        // Check RLE
        if (tsr & AT91C_EMAC_RLES) {
            txStatusFlag |= AT91C_EMAC_RLES;
            EmacStatistics.tx_errors++;
        }
        // Check COL
        if (tsr & AT91C_EMAC_COL) {
            txStatusFlag |= AT91C_EMAC_COL;
            EmacStatistics.collisions++;
        }
        // Check BEX
        if (tsr & AT91C_EMAC_BEX) {
            txStatusFlag |= AT91C_EMAC_BEX;
            EmacStatistics.tx_exausts++;
        }
        // Check UND
        if (tsr & AT91C_EMAC_UND) {
            txStatusFlag |= AT91C_EMAC_UND;
            EmacStatistics.tx_underruns++;
        }
        // Clear status
        AT91C_BASE_EMAC->EMAC_TSR |= txStatusFlag;

        // Sanity check: Tx buffers have to be scheduled
        ASSERT(!CIRC_EMPTY(&txTd),
            "-F- EMAC Tx interrupt received meanwhile no TX buffers has been scheduled\n\r");

        // Check the buffers
        while (CIRC_CNT(txTd.head, txTd.tail, TX_BUFFERS)) {
            pTxTd = txTd.td + txTd.tail;
            pTxCb = txTd.txCb + txTd.tail;

            // Exit if buffer has not been sent yet
            if ((pTxTd->status & EMAC_TX_USED_BIT) == 0) {
                break;
            }

            // Notify upper layer that packet has been sent
            if (*pTxCb) {
                (*pTxCb)(txStatusFlag);
            }

            CIRC_INC( txTd.tail, TX_BUFFERS );
        }

        // If a wakeup has been scheduled, notify upper layer that it can send
        // other packets, send will be successfull.
        if( (CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) >= txTd.wakeupThreshold)
         &&  txTd.wakeupCb) {
            txTd.wakeupCb();
        }
    }
}
err_t AT91_EMAC_LWIP_xmit(struct netif *pNetIf, struct pbuf *pPBuf)
{
    UINT16  length = 0;
    UINT8 *pDst;

    volatile EmacTDescriptor *pTxTd;

    GLOBAL_LOCK(encIrq);
    
    if (!pNetIf || !pPBuf)
    {
        return ERR_ARG;
    }
     
    length = pPBuf->tot_len;
/*    
    if (length < ETHER_MIN_LEN)
    {
        length = ETHER_MIN_LEN;
    }
*/    
    if (length > AT91_EMAC_MAX_FRAME_SIZE)
    {
        debug_printf("xmit - length is too large, truncated\r\n");
        length = AT91_EMAC_MAX_FRAME_SIZE;         /* what a terriable hack! */
    }
    
    /* First see if there is enough space in the remainder of the transmit buffer */
    if (CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) == 0)
    {
        debug_printf("AT91_EMAC_LWIP_xmit: no space\r\n");
        return ERR_IF;
    }

    // Pointers to the current TxTd
    pTxTd = txTd.td + txTd.head;
    pDst = (UINT8*)pTxTd->addr;

    // Copy data to transmition buffer
    if (length != 0)
    {
        while (pPBuf)
        {
            memcpy(pDst, pPBuf->payload, pPBuf->len);
            pDst += pPBuf->len;
            pPBuf = pPBuf->next;
        }
    }

    if (txTd.head == TX_BUFFERS-1)
    {
        pTxTd->status = (length & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT | EMAC_TX_WRAP_BIT;
    }
    else
    {
        pTxTd->status = (length & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT;
    }
    
    // Driver manage the ring buffer
    CIRC_INC(txTd.head, TX_BUFFERS)

    AT91_EMAC &emac = AT91_EMAC::EMAC();

    // Now start to transmit if it is not already done
    emac.EMAC_NCR |= AT91_EMAC::EMAC_TSTART;

    return ERR_OK;

}
void AT91_EMAC_LWIP_recv(struct netif *pNetIf)
{
    struct pbuf *pPBuf;
    UINT8       *dataRX;
    UINT16       frameLength;
    UINT16       bufferLength;
    UINT32       tmpIdx = rxTd.idx;
    BOOL         isFrame = FALSE;

    GLOBAL_LOCK(encIrq);

    volatile EmacTDescriptor *pRxTd = rxTd.td + rxTd.idx;

    while ((pRxTd->addr & EMAC_RX_OWNERSHIP_BIT) == EMAC_RX_OWNERSHIP_BIT)
    {
        // A start of frame has been received
        if(pRxTd->status & EMAC_RX_SOF_BIT) 
        {
            // Skip previous fragment
            while (tmpIdx != rxTd.idx)
            {
                pRxTd = rxTd.td + rxTd.idx;
                pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
                CIRC_INC(rxTd.idx, RX_BUFFERS);
            }
            
            // Start to gather buffers in a frame
            isFrame = TRUE;
        }

        // Increment the pointer
        CIRC_INC(tmpIdx, RX_BUFFERS);

        if(isFrame)
        {
            if (tmpIdx == rxTd.idx) 
            {
                debug_printf("Receive buffer is too small for the current frame!\r\n");
                do
                {
                    pRxTd = rxTd.td + rxTd.idx;
                    pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
                    CIRC_INC(rxTd.idx, RX_BUFFERS);
                } while(tmpIdx != rxTd.idx);
            }
            // An end of frame has been received
            if(pRxTd->status & EMAC_RX_EOF_BIT)
            {
                // Frame size from the EMAC
                frameLength = (pRxTd->status & EMAC_LENGTH_FRAME);

                pPBuf = pbuf_alloc(PBUF_RAW, frameLength, PBUF_RAM);

                if (pPBuf)
                {
                    dataRX = (UINT8*)pPBuf->payload;
 
                    bufferLength = EMAC_RX_UNITSIZE;
                    // Get all the data
                    while (rxTd.idx != tmpIdx)
                    {                   
                        pRxTd = rxTd.td + rxTd.idx;
                        if(bufferLength >= frameLength)
                        {
                            memcpy(dataRX, (void*)(pRxTd->addr & EMAC_ADDRESS_MASK), frameLength);
                        }
                        else
                        {
                            memcpy(dataRX, (void*)(pRxTd->addr & EMAC_ADDRESS_MASK), bufferLength);
                            frameLength -= bufferLength;
                            dataRX += bufferLength;
                        }
                    
                        pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
                        CIRC_INC(rxTd.idx, RX_BUFFERS);
                    }
                
                    // signal IP layer that a packet is on its exchange
                    pNetIf->input(pPBuf, pNetIf);
                }
                // Prepare for the next Frame
                isFrame = FALSE;
            }
        }// if(isFrame) ends
        else
        {
           pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
           rxTd.idx = tmpIdx;
        }
        
        // Process the next buffer
        pRxTd = rxTd.td + tmpIdx;
    }
}
void SH7619_EDMAC_recv(PIFACE pi)
{
	DCU               	msg;
	RTP_UINT16         	FrameLength = 0;
	long 				leng;
	UINT16             	BufferLength;
	UINT32  			tmpIdx = rxTd.idx;
	char*				recv_packet;
	int					tries = 100;
	BOOL				recv_error = FALSE;
	BOOL				mem_error = FALSE;
	EmacTDescriptor 	*pRxTd;
	BOOL isFrame = FALSE;
	
	GLOBAL_LOCK(encIrq);

	pRxTd = *(rxTd.td + rxTd.idx);

	while ((pRxTd->status & ACT) != 0 && tries-- > 0)
	{
		for(int i = 0; i < 500; i++);
	}

	if(tries <= 0)
	{
		//while ((pRxTd->status & ACT) != 0 && tries++ < RX_BUFFERS)
		//{
		//	CIRC_INC(rxTd.idx, RX_BUFFERS);
		//	pRxTd = *(rxTd.td + rxTd.idx);
		//}
		//tmpIdx = rxTd.idx;
		return;
	}

	while ((pRxTd->status & ACT) == 0)
	{
		leng = pRxTd->RDL;
		// A start of frame has been received
		if((pRxTd->status & FP1) != 0) 
		{
			// Skip previous fragment
			while (tmpIdx != rxTd.idx)
			{
				pRxTd = *(rxTd.td + rxTd.idx);
				pRxTd->status |= ACT;
				CIRC_INC(rxTd.idx, RX_BUFFERS);
			}

			FrameLength = 0;

			// Start to gather buffers in a frame
			isFrame = TRUE;
		}

		// Increment the pointer
		CIRC_INC(tmpIdx, RX_BUFFERS);

		if(isFrame)
		{
			if (tmpIdx == rxTd.idx) 
			{
				hal_printf("Receive buffer is too small for the current frame!\r\n");
				do
				{
					//FrameLength += pRxTd->RDL;
					pRxTd = *(rxTd.td + rxTd.idx);
					pRxTd->status |= ACT;
					CIRC_INC(rxTd.idx, RX_BUFFERS);
				} while(tmpIdx != rxTd.idx);
			}

			if((pRxTd->status & FE) != 0) 
			{
				recv_error = TRUE;
			}

			FrameLength += leng;

			// An end of frame has been received
			if((pRxTd->status & FP0) != 0)
			{
				tries = 0;

				if(recv_error == FALSE)
				{				
					do
					{
						msg = os_alloc_packet_input(FrameLength, DRIVER_ALLOC);
						if(!msg)
							for(int i = 0; i < 5000; i++);		//delay
					}while(!msg && tries++ < 50);

					if (msg)
					{
						recv_packet = (char*)DCUTODATA(msg);
						msg->length = FrameLength;
					}
					else
					{
						mem_error = TRUE;
					}
				}
				else
				{
					mem_error = TRUE;
				}

				BufferLength = EMAC_RX_UNITSIZE;
				// Get all the data
				while (rxTd.idx != tmpIdx)
				{                   
					pRxTd = *(rxTd.td + rxTd.idx);

					if(mem_error == FALSE)
					{
						if(BufferLength >= FrameLength)
						{
							memcpy(recv_packet, (void*)(pRxTd->TRBA), FrameLength);
						}
						else
						{
							memcpy(recv_packet, (void*)(pRxTd->TRBA), BufferLength);
							FrameLength -= BufferLength;
							recv_packet += BufferLength;
						}
					}

					pRxTd->status |= ACT;
					CIRC_INC(rxTd.idx, RX_BUFFERS);
				}
                
				// signal IP layer that a packet is on its exchange
				if(mem_error == FALSE)
					rtp_net_invoke_input(pi, msg, msg->length);

				// Prepare for the next Frame
				isFrame = FALSE;
				recv_error = FALSE;
				mem_error = FALSE;
			}
		}// if(isFrame) ends
		else
		{
			pRxTd->status |= ACT;
			rxTd.idx = tmpIdx;		   
		}

		// Process the next buffer
		pRxTd = *(rxTd.td + tmpIdx);
	}
}