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); }
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 ); } } }
//----------------------------------------------------------------------------- /// 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; }
//----------------------------------------------------------------------------- /// 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; }
//----------------------------------------------------------------------------- /// 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"); } }
//----------------------------------------------------------------------------- /// 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); } }