void MACNET_add_buffers_to_rx_ring(MACNET_CONTEXT_STRUCT_PTR macnet_context_ptr) { ENET_MemMapPtr macnet_ptr = macnet_context_ptr->MACNET_ADDRESS; VENET_BD_STRUCT_PTR bd_ptr; uchar_ptr buf; if (macnet_ptr == NULL) return; /* ** This function can be called from any context, and it needs mutual ** exclusion with itself. */ MACNET_int_disable(); while (macnet_context_ptr->ActiveRxBDs < macnet_context_ptr->NumRxBDs) { bd_ptr = &macnet_context_ptr->MACNET_RX_RING_PTR[macnet_context_ptr->LastRxBD]; _DCACHE_INVALIDATE_MBYTES((pointer)bd_ptr, sizeof(ENET_BD_STRUCT)); /* Initialize the descriptor and give it to the MACNET */ buf = (uchar_ptr)HOST_TO_BE_LONG((uint_32)ENET_Dequeue_Buffer((pointer *) &macnet_context_ptr->RX_BUFFERS)); if (buf == NULL) { MACNET_int_enable(); return; } bd_ptr->BUFFER = buf; bd_ptr->LENGTH = 0; /* ** The processor doesn't clear control bits when errors don't occur; ** it just sets bits when errors do occur. So we clear all the ** control bits before enqueueing the descriptor. */ bd_ptr->CONTROL &= HOST_TO_BE_SHORT_CONST(ENET_BD_ETHER_RX_WRAP); /* ** Add the PCB to the receive PCB queue (linked via PRIVATE) and ** increment the tail to the next descriptor */ BD_INC(macnet_context_ptr->LastRxBD, macnet_context_ptr->NumRxBDs); macnet_context_ptr->ActiveRxBDs++; bd_ptr->CONTROL |= HOST_TO_BE_SHORT_CONST(ENET_BD_ETHER_RX_EMPTY); /* In case Enhanced BD are used allow interrupt generation */ bd_ptr->CONTROL_EXT0 |= HOST_TO_BE_SHORT_CONST(ENET_BD_EXT0_ETHER_RX_GENERATE_INTR); _DCACHE_FLUSH_MBYTES((pointer)bd_ptr, sizeof(ENET_BD_STRUCT)); /* ** Signals the MACNET that empty buffers are available. */ macnet_ptr->RDAR = ENET_RDAR_RDAR_MASK; } MACNET_int_enable(); }
static void MACNET_process_tx_bds ( /* [IN] the Ethernet state structure */ ENET_CONTEXT_STRUCT_PTR enet_ptr ) { MACNET_CONTEXT_STRUCT_PTR macnet_context_ptr = (MACNET_CONTEXT_STRUCT_PTR) enet_ptr->MAC_CONTEXT_PTR; uint_16 tx_status; /* Dequeue all transmitted frames */ while (macnet_context_ptr->AvailableTxBDs < macnet_context_ptr->NumTxBDs) { VENET_BD_STRUCT_PTR bd_ptr = &macnet_context_ptr->MACNET_TX_RING_PTR[macnet_context_ptr->LastTxBD]; _DCACHE_INVALIDATE_MBYTES((pointer)bd_ptr, sizeof(ENET_BD_STRUCT)); if (bd_ptr->CONTROL & HOST_TO_BE_SHORT_CONST(ENET_BD_ETHER_TX_READY)) { break; } /* Endif */ macnet_context_ptr->TxErrors |= SHORT_BE_TO_HOST(bd_ptr->CONTROL); tx_status = macnet_context_ptr->TxErrors; /* Record statistics for each frame (not each buffer) */ if (tx_status & ENET_BD_ETHER_TX_LAST) { PCB_PTR pcb_ptr; macnet_context_ptr->TxErrors = 0; ENET_INC_STATS(COMMON.ST_TX_TOTAL); pcb_ptr = macnet_context_ptr->TxPCBS_PTR[macnet_context_ptr->LastTxBD]; PCB_free(pcb_ptr); } if (macnet_context_ptr->FREE_TX_SMALL & (1<<macnet_context_ptr->LastTxBD)) { ENET_Enqueue_Buffer((pointer *) &macnet_context_ptr->SMALL_BUFFERS, (pointer)LONG_BE_TO_HOST((uint_32)(bd_ptr->BUFFER))); macnet_context_ptr->FREE_TX_SMALL &= ~(1<<macnet_context_ptr->LastTxBD); } else if (macnet_context_ptr->FREE_TX & (1<<macnet_context_ptr->LastTxBD)) { ENET_Enqueue_Buffer((pointer *) &macnet_context_ptr->TX_BUFFERS, (pointer)LONG_BE_TO_HOST((uint_32)(bd_ptr->BUFFER))); macnet_context_ptr->FREE_TX &= ~(1<<macnet_context_ptr->LastTxBD); } BD_INC(macnet_context_ptr->LastTxBD,macnet_context_ptr->NumTxBDs); macnet_context_ptr->AvailableTxBDs++; } }
/* Custom_DeliverFrameToNetworkStack - Called by API_RxComplete to * deliver a data frame to the network stack. This code will perform * platform specific operations. * void *pCxt - the driver context. * void *pReq - the packet. *****************************************************************************/ void Custom_DeliverFrameToNetworkStack(void *pCxt, void *pReq) { A_NETBUF *a_netbuf_ptr = (A_NETBUF *)pReq; QCA_CONTEXT_STRUCT_PTR qca_ptr = (QCA_CONTEXT_STRUCT_PTR)GET_DRIVER_CXT(pCxt)->pUpperCxt[0]; QCA_ECB_STRUCT_PTR RxECB; uint32_t len; A_DRIVER_CONTEXT *pDCxt = GET_DRIVER_COMMON(pCxt); ATH_PROMISCUOUS_CB prom_cb = (ATH_PROMISCUOUS_CB)(GET_DRIVER_CXT(pCxt)->promiscuous_cb); if (a_netbuf_ptr) { len = A_NETBUF_LEN(pReq); _DCACHE_INVALIDATE_MBYTES(A_NETBUF_DATA(pReq), len); if (pDCxt->promiscuous_mode) { if (prom_cb) { /* send frame to callback function rather than an QCA_receiver */ a_netbuf_ptr->native.FRAG[0].LENGTH = len; a_netbuf_ptr->native.FRAG[0].FRAGMENT = A_NETBUF_DATA(pReq); prom_cb((void *)&(a_netbuf_ptr->native)); } else { A_NETBUF_FREE(pReq); } } else if ((RxECB = QCA_find_receiver(qca_ptr, (QCA_HEADER_PTR)A_NETBUF_DATA(pReq), &len)) != NULL) { // Call the receiver's service function to pass the PCB to the receiver a_netbuf_ptr->native.FRAG[0].LENGTH = len; a_netbuf_ptr->native.FRAG[0].FRAGMENT = A_NETBUF_DATA(pReq); RxECB->SERVICE((PCB_PTR) & (a_netbuf_ptr->native), RxECB->PRIVATE); } else { /* failed to find a receiver for this data packet. */ A_NETBUF_FREE(pReq); } } }
void _io_pcb_shm_rx_isr ( /* [IN] the info structure */ pointer handle ) { IO_PCB_SHM_INFO_STRUCT_PTR info_ptr; IO_PCB_SHM_INIT_STRUCT_PTR init_ptr; IO_PCB_STRUCT_PTR local_pcb_ptr; IO_PCB_STRUCT_PTR remote_pcb_ptr; IO_PCB_FRAGMENT_STRUCT_PTR frag_ptr; IO_PCB_SHM_BUFFER_STRUCT_PTR bd_ptr; uchar_ptr data_addr; uint_32 data_length; uint_32 cntrl; uint_16 num_frags; uint_32 max_size; boolean discard; info_ptr = (IO_PCB_SHM_INFO_STRUCT_PTR)handle; init_ptr = &info_ptr->INIT; /* Get the next RX buffer descriptor */ bd_ptr = &info_ptr->RX_RING_PTR[info_ptr->RXNEXT]; _DCACHE_INVALIDATE_LINE(bd_ptr); cntrl = bd_ptr->CONTROL; remote_pcb_ptr = (IO_PCB_STRUCT_PTR) _bsp_ptov(bd_ptr->PACKET_PTR); _DCACHE_INVALIDATE_MBYTES(remote_pcb_ptr, sizeof(*remote_pcb_ptr)); num_frags = remote_pcb_ptr->NUMBER_OF_FRAGMENTS; /* Disable interrupts */ _int_disable(); while(cntrl == (IO_PCB_SHM_BUFFER_OWN|IO_PCB_SHM_BUFFER_ALOCATED)){ discard = FALSE; /* Get a PCB */ local_pcb_ptr = _io_pcb_alloc(info_ptr->READ_PCB_POOL, FALSE); if ((local_pcb_ptr == NULL)) { break; } data_addr = local_pcb_ptr->FRAGMENTS[0].FRAGMENT; data_length = ((IO_PCB_SHM_INIT_STRUCT_PTR) &info_ptr->INIT)->INPUT_MAX_LENGTH; max_size = ((IO_PCB_SHM_INIT_STRUCT_PTR) &info_ptr->INIT)->INPUT_MAX_LENGTH; /* Copy packet */ for(frag_ptr = (IO_PCB_FRAGMENT_STRUCT_PTR) &(remote_pcb_ptr->FRAGMENTS[0]); num_frags; num_frags--, frag_ptr++) { if(frag_ptr->LENGTH > max_size){ discard = TRUE; break; } _DCACHE_INVALIDATE_MBYTES(frag_ptr->FRAGMENT, frag_ptr->LENGTH); _mem_copy(_bsp_ptov((pointer)frag_ptr->FRAGMENT), (pointer)data_addr, frag_ptr->LENGTH); data_addr += frag_ptr->LENGTH; data_length -= frag_ptr->LENGTH; } local_pcb_ptr->FRAGMENTS[0].LENGTH = max_size - data_length; if (info_ptr->READ_CALLBACK_FUNCTION) { (*info_ptr->READ_CALLBACK_FUNCTION)(info_ptr->FD, local_pcb_ptr); } else { _queue_enqueue((QUEUE_STRUCT_PTR)&info_ptr->READ_QUEUE, (QUEUE_ELEMENT_STRUCT_PTR)&local_pcb_ptr->QUEUE); _lwsem_post(&info_ptr->READ_LWSEM); } /* Set the buffer pointer and control bits */ bd_ptr->CONTROL &= IO_PCB_SHM_BUFFER_ALOCATED; _DCACHE_FLUSH_LINE(bd_ptr); /* Update Info structure */ info_ptr->RXNEXT = NEXT_INDEX(info_ptr->RXNEXT, info_ptr->RX_LENGTH); info_ptr->RXENTRIES--; /* Get the next RX buffer descriptor */ bd_ptr = &info_ptr->RX_RING_PTR[info_ptr->RXNEXT]; _DCACHE_INVALIDATE_LINE(bd_ptr); cntrl = bd_ptr->CONTROL; remote_pcb_ptr = (IO_PCB_STRUCT_PTR) _bsp_ptov(bd_ptr->PACKET_PTR); _DCACHE_INVALIDATE_MBYTES(remote_pcb_ptr, sizeof(*remote_pcb_ptr)); num_frags = remote_pcb_ptr->NUMBER_OF_FRAGMENTS; } if (init_ptr->TX_VECTOR == 0) { _io_pcb_shm_tx_isr(handle); } /* Reception successful */ if (!discard) { /* Trigger remote side */ (*init_ptr->INT_TRIGGER)(init_ptr->REMOTE_TX_VECTOR); } _int_enable(); }
/*FUNCTION*------------------------------------------------------------- * * Function Name : MACNET_process_rx_bds * Returned Value : void * Comments : * Processes received buffers. * * NOTE: For MACNET, a frame consists of one or more buffers. * For ENET, a packet consists of one or more fragments * Therefore, a frame = a packet, and a buffer = a fragment. * * *END*-----------------------------------------------------------------*/ static void MACNET_process_rx_bds ( /* [IN] the Ethernet state structure */ ENET_CONTEXT_STRUCT_PTR enet_ptr ) { /* Body */ MACNET_CONTEXT_STRUCT_PTR macnet_context_ptr = (MACNET_CONTEXT_STRUCT_PTR) enet_ptr->MAC_CONTEXT_PTR; VENET_BD_STRUCT_PTR bd_ptr; PCB_PTR pcb_ptr=NULL; uint_16 rx_status; uint_32 i,length; int_32 ilength; uchar_ptr buffer, small_packet, large_packet; boolean buffer_is_valid, consumed, first, last; //_DCACHE_INVALIDATE(); // temporary - I can't find fast actual part of memory for cache invalidation /* Dequeue all received buffers (fragments) */ while (macnet_context_ptr->ActiveRxBDs > 0) { bd_ptr = &macnet_context_ptr->MACNET_RX_RING_PTR[macnet_context_ptr->NextRxBD]; _DCACHE_INVALIDATE_MBYTES((pointer)bd_ptr, sizeof(ENET_BD_STRUCT)); if ((bd_ptr->CONTROL & HOST_TO_BE_SHORT_CONST(ENET_BD_ETHER_RX_EMPTY)) != 0) { break; // Currently being written to by MII } BD_INC(macnet_context_ptr->NextRxBD,macnet_context_ptr->NumRxBDs); macnet_context_ptr->ActiveRxBDs--; ENET_INC_STATS(COMMON.ST_RX_TOTAL); rx_status = SHORT_BE_TO_HOST(bd_ptr->CONTROL); length = SHORT_BE_TO_HOST(bd_ptr->LENGTH); buffer = (uchar_ptr)LONG_BE_TO_HOST((uint_32)(bd_ptr->BUFFER)); //buffer = LONG_BE_TO_HOST(bd_ptr->BUFFER); consumed = FALSE; first = macnet_context_ptr->CurrentRxFrag == 0; last = TRUE; // Start by validating the received buffer // a buffer is valid if: // (it is error free) AND ( (it is the first buffer in a frame) OR (it is a subsequent buffer in a frame we want ) ) // buffer_is_valid = FALSE; if (rx_status & ENET_BD_ETHER_RX_TRUNCATED) { ENET_INC_STATS(ST_RX_RUNT); } else if (rx_status & ENET_BD_ETHER_RX_LAST_FRAME) { // Some error bits can only be checked on the last buffer // Overrun needs to be checked first, If this bit is // set, the other status bits, M, LG, NO, CR, and CL lose their normal meaning and are zero. This bit // is valid only if the L-bit is set. if (rx_status & ENET_BD_ETHER_RX_OVERRUN) { ENET_INC_STATS(ST_RX_OVERRUN); } else if (rx_status & ENET_BD_ETHER_RX_LENGTH_VIOLATION) { ENET_INC_STATS(ST_RX_GIANT); } else if (rx_status & ENET_BD_ETHER_RX_NON_OCTET) { ENET_INC_STATS(ST_RX_ALIGN); } else if (rx_status & ENET_BD_ETHER_RX_CRC_ERROR) { ENET_INC_STATS(ST_RX_FCS); } else { #if BSPCFG_ENABLE_ENET_HISTOGRAM uint_32 index = length>> ENET_HISTOGRAM_SHIFT; if (index < ENET_HISTOGRAM_ENTRIES) { ENET_INC_STATS(RX_HISTOGRAM[index]); } #endif // Good buffer (with Last bit set). buffer_is_valid = TRUE; // Remove CRC and compute buffer length ilength = length - (ENET_FRAMESIZE_TAIL + (macnet_context_ptr->CurrentRxFrag * enet_ptr->PARAM_PTR->RX_BUFFER_SIZE)); // The last fragment may contain nothing but part of the CRC. If this is the case, length will be <= 0, // and if length < 0, the previous fragment contains part of the CRC, which needs to be removed. if (ilength < 0) { length = 0; if (!first) { macnet_context_ptr->FRAGS[macnet_context_ptr->CurrentRxFrag-1].LENGTH += ilength; } else { // Should never get here - would mean we received a really small packet which should have already been // caught above. But if we do, discard it. buffer_is_valid = TRUE; } } else { length = (uint_32) ilength; } } } else { // Good buffer (without Last bit set). Can only be processed if we are not currently discarding. buffer_is_valid = TRUE; last = FALSE; } if (!buffer_is_valid) { // Was a buffer with an error ENET_INC_STATS(COMMON.ST_RX_ERRORS); MACNET_discard_current_rx(enet_ptr,macnet_context_ptr,last); } else { // If it is the first buffer in the frame, we have to see if the frame is of interest. if (first) { // make sure we don't examine a cached copy of the buffer _DCACHE_INVALIDATE_MBYTES(buffer, length); // the frame is of interest if there is a receiver registered for the destination and protocol. We can do this on the first buffer // of the frame, since the ethernet header information always fits in the first buffer of a frame. macnet_context_ptr->CurrentRxECB = ENET_find_receiver(enet_ptr, (ENET_HEADER_PTR) buffer, &length); } // If we have an Rx ECB, it means we want this packet if (macnet_context_ptr->CurrentRxECB ) { if (!first) { // If it is not the first packet, the cache is still valid. We could have put the invalidate before the first "if (first)", // but that would mean we may invalidate the cache on buffers that we know we are discarding. _DCACHE_INVALIDATE_MBYTES(buffer, length); } // Add the packet to the list of fragments in the PCB macnet_context_ptr->FRAGS[macnet_context_ptr->CurrentRxFrag].FRAGMENT = buffer; macnet_context_ptr->FRAGS[macnet_context_ptr->CurrentRxFrag].LENGTH = length; macnet_context_ptr->CurrentRxFrag++; consumed = TRUE; // Now, there are three cases: // !l - start or mid frame buffer - store it for later coalecing into a large buffer // !f, l - end of multi-buffer packet - coalece into a large buffer // f, l - single buffer packet - ready to process if (!last) { // Not the last frame in the packet. Have to make sure there is room for at least one // more fragment. If not, the packet is too large if (macnet_context_ptr->CurrentRxFrag >= MACNET_MAX_FRAGS) { MACNET_discard_current_rx(enet_ptr,macnet_context_ptr,last); ENET_INC_STATS(RX_FRAGS_EXCEEDED); } } else { // last buffer (may or may not also be the first buffer) so process it // There is a receiver, so need to allocate a receive PCB QGET(macnet_context_ptr->RxPCBHead, macnet_context_ptr->RxPCBTail, pcb_ptr); if (pcb_ptr) { // allocation successful, initialize new receive PCB pcb_ptr->PRIVATE = (pointer)enet_ptr; pcb_ptr->FREE = MACNET_rx_free; // Check to see if it is a large packet if (!first) { // Coalese large_packet = ENET_Dequeue_Buffer((pointer *)&macnet_context_ptr->LARGE_BUFFERS); if (large_packet) { // need to compute the length of this fragment, because the length on a BD with the L bit set // is not the length of the buffer, it is the length of the frame. pcb_ptr->FRAG[0].FRAGMENT = large_packet; pcb_ptr->FRAG[0].LENGTH = 0; pcb_ptr->FREE = MACNET_rx_free_large; for (i=0;i<macnet_context_ptr->CurrentRxFrag;i++) { if (macnet_context_ptr->FRAGS[i].LENGTH ) { _mem_copy(macnet_context_ptr->FRAGS[i].FRAGMENT, large_packet, macnet_context_ptr->FRAGS[i].LENGTH ); large_packet += macnet_context_ptr->FRAGS[i].LENGTH; pcb_ptr->FRAG[0].LENGTH += macnet_context_ptr->FRAGS[i].LENGTH; } ENET_Enqueue_Buffer((pointer*)&macnet_context_ptr->RX_BUFFERS, macnet_context_ptr->FRAGS[i].FRAGMENT); macnet_context_ptr->FRAGS[i].FRAGMENT = NULL; } ENET_INC_STATS(ST_RX_COPY_LARGE); } else { ENET_INC_STATS(RX_LARGE_BUFFERS_EXHAUSTED); MACNET_discard_current_rx(enet_ptr,macnet_context_ptr,last); QADD(macnet_context_ptr->RxPCBHead, macnet_context_ptr->RxPCBTail, pcb_ptr); pcb_ptr=NULL; } // Check to see if it is a small packet } else { pcb_ptr->FRAG[0].LENGTH = length; pcb_ptr->FRAG[0].FRAGMENT = buffer; if (length < MACNET_SMALL_PACKET_SIZE) { small_packet = ENET_Dequeue_Buffer((pointer *)&macnet_context_ptr->SMALL_BUFFERS); if (small_packet) { _mem_copy( macnet_context_ptr->FRAGS[0].FRAGMENT, small_packet, length ); pcb_ptr->FRAG[0].FRAGMENT = small_packet; pcb_ptr->FREE = MACNET_rx_free_small; consumed = FALSE; ENET_INC_STATS(ST_RX_COPY_SMALL); } } } if (pcb_ptr) { pcb_ptr->FRAG[1].LENGTH = 0; pcb_ptr->FRAG[1].FRAGMENT = NULL; #if ENETCFG_SUPPORT_PTP if (macnet_context_ptr->PTP_PRIV->PTIMER_PRESENT) { MACNET_ptp_store_rxstamp(enet_ptr, pcb_ptr, bd_ptr); } #endif /* ENETCFG_SUPPORT_PTP */ // Call the receiver's service function to pass the PCB to the receiver macnet_context_ptr->CurrentRxECB->SERVICE(pcb_ptr, macnet_context_ptr->CurrentRxECB->PRIVATE); // and clear the current ECB and PCB info, as it's gone to the receiver now. macnet_context_ptr->CurrentRxECB = NULL; macnet_context_ptr->CurrentRxFrag = 0; } } else { // Couldn't get a Receive PCB, so need to discard buffers until last buffer in frame. MACNET_discard_current_rx(enet_ptr,macnet_context_ptr,last); ENET_INC_STATS(RX_PCBS_EXHAUSTED); } } } } if (!consumed) { ENET_INC_STATS(COMMON.ST_RX_DISCARDED); ENET_Enqueue_Buffer((pointer*)&macnet_context_ptr->RX_BUFFERS, buffer); } }
uint_32 MACNET_send ( ENET_CONTEXT_STRUCT_PTR enet_ptr, /* [IN] the Ethernet state structure */ PCB_PTR packet, /* [IN] the packet to send */ uint_32 size, /* [IN] total size of the packet */ uint_32 frags, /* [IN] total fragments in the packet */ uint_32 flags /* [IN] optional flags, zero = default */ ) { MACNET_CONTEXT_STRUCT_PTR macnet_context_ptr = (MACNET_CONTEXT_STRUCT_PTR) enet_ptr->MAC_CONTEXT_PTR; ENET_MemMapPtr macnet_ptr= macnet_context_ptr->MACNET_ADDRESS; PCB_FRAGMENT_PTR frag_ptr; VENET_BD_STRUCT_PTR tx_bd_ptr; uint_32 len,totlen,frag; uchar_ptr txmem; boolean aligned; uint_32 err = ENET_OK; #if ENETCFG_SUPPORT_PTP MACNET_PTP_DATA tmp_tx_time; boolean wait_for_ts=FALSE; #endif if (macnet_ptr == NULL) return ENETERR_INVALID_DEVICE; MACNET_int_disable(); /* ** Make sure there aren't too many fragments. (We really should check ** this every time through the previous loop, but it is extremely ** unlikely that the fragment counter overflowed -- there would have ** to be over 2^32 fragments.) */ if (macnet_context_ptr->AvailableTxBDs < 1) { ENET_INC_STATS(COMMON.ST_TX_MISSED); err = ENETERR_SEND_FULL; goto END; } #if BSPCFG_ENABLE_ENET_HISTOGRAM { uint_32 index = size>> ENET_HISTOGRAM_SHIFT; if (index < ENET_HISTOGRAM_ENTRIES) { ENET_INC_STATS(TX_HISTOGRAM[index]); } } #endif aligned = TRUE; for (frag_ptr = packet->FRAG; frag_ptr->LENGTH; frag_ptr++) { if (MACNET_TX_ALIGN((uint_32)frag_ptr->FRAGMENT)!= (uint_32)frag_ptr->FRAGMENT) aligned = FALSE; } if (aligned) { ENET_INC_STATS(TX_ALL_ALIGNED); } /* ** Enqueue the packet on the transmit ring. Don't set the ready ** bit in the first descriptor until all descriptors are enqueued. */ tx_bd_ptr = &macnet_context_ptr->MACNET_TX_RING_PTR[macnet_context_ptr->NextTxBD]; frag_ptr = packet->FRAG; frag = (uint_32) frag_ptr->FRAGMENT; if (frags > 1 || (MACNET_TX_ALIGN(frag)!= frag)) { // Packet is fragmented and/or it is misaligned, needs to be copied txmem = NULL; // See if it fits in a small buffer if (size <= MACNET_SMALL_PACKET_SIZE) { // it does txmem = ENET_Dequeue_Buffer((pointer *) &macnet_context_ptr->SMALL_BUFFERS); } // If it didn't fit, or the small alloc failed, try for a large buffer if (txmem) { // signal buffer is to be deallocated. macnet_context_ptr->FREE_TX_SMALL |= (1<<macnet_context_ptr->NextTxBD); ENET_INC_STATS(ST_TX_COPY_SMALL); } else { if (size <= macnet_context_ptr->AlignedTxBufferSize) { txmem = ENET_Dequeue_Buffer((pointer *) &macnet_context_ptr->TX_BUFFERS); } if (txmem) { // signal buffer is to be deallocated. macnet_context_ptr->FREE_TX |= (1<<macnet_context_ptr->NextTxBD); } else { ENET_INC_STATS(COMMON.ST_TX_MISSED); err = ENETERR_NO_TX_BUFFER; goto END; } } totlen = 0; for (len = frag_ptr->LENGTH; len != 0; len = frag_ptr->LENGTH) { _mem_copy(frag_ptr->FRAGMENT, txmem + totlen, len); totlen += len; frag_ptr++; } } else { // Packet is not fragmented and it is not misaligned totlen = frag_ptr->LENGTH; txmem = frag_ptr->FRAGMENT; ENET_INC_STATS(TX_ALIGNED); } // Flush the buffer from cache _DCACHE_FLUSH_MBYTES(txmem, totlen); // Invalidate the bd from cache _DCACHE_INVALIDATE_MBYTES((pointer)tx_bd_ptr, sizeof(ENET_BD_STRUCT)); // set up the tx bd tx_bd_ptr->CONTROL &= HOST_TO_BE_SHORT_CONST(ENET_BD_ETHER_TX_WRAP); tx_bd_ptr->BUFFER = (uchar_ptr)HOST_TO_BE_LONG((uint_32)txmem); tx_bd_ptr->LENGTH = HOST_TO_BE_SHORT(totlen); tx_bd_ptr->CONTROL |= HOST_TO_BE_SHORT_CONST(ENET_BD_ETHER_TX_LAST | ENET_BD_ETHER_TX_SEND_CRC | ENET_BD_ETHER_TX_READY); tx_bd_ptr->CONTROL_EXT0 |= HOST_TO_BE_SHORT_CONST(ENET_BD_EXT0_ETHER_TX_GENERATE_INTR); #if ENETCFG_SUPPORT_PTP if (macnet_context_ptr->PTP_PRIV->PTIMER_PRESENT) { /* PTP over Ethernet frames: Check the PTPv2 over Ethernet type (identifier) */ if((totlen > 44) && (*(uint_16 *)(txmem + MACNET_PTP_ETHER_PKT_TYPE_OFFS) == HOST_TO_BE_SHORT_CONST(MACNET_PACKET_TYPE_IEEE_802_3))) { /* Allow interrupt and timestamp generation */ tx_bd_ptr->CONTROL_EXT0 |= HOST_TO_BE_SHORT_CONST(ENET_BD_EXT0_ETHER_TX_TIMESTAMP); tmp_tx_time.KEY = HOST_TO_BE_SHORT(*((uint_16 *)(txmem + MACNET_PTP_ETHER_SEQ_ID_OFFS))); for(len=0;len<MACNET_PTP_CLOCKID_SIZE;len++) tmp_tx_time.CLOCKID[len] = *((uint_8 *)(txmem + MACNET_PTP_ETHER_CLOCKID + len)); wait_for_ts = TRUE; } /* PTP over UDP: Check if port is 319 for PTP Event, and check for UDP */ else if((totlen > 44) && (*(uchar_ptr)(txmem + MACNET_PTP_UDP_PKT_TYPE_OFFS) == MACNET_PACKET_TYPE_UDP) && (*(uint_16 *)(txmem + MACNET_PTP_UDP_PORT_OFFS) == HOST_TO_BE_SHORT_CONST(MACNET_PTP_EVNT_PORT))) { tx_bd_ptr->CONTROL_EXT0 |= HOST_TO_BE_SHORT_CONST(ENET_BD_EXT0_ETHER_TX_TIMESTAMP); tmp_tx_time.KEY = HOST_TO_BE_SHORT(*((uint_16 *)(txmem + MACNET_PTP_UDP_SEQ_ID_OFFS))); for(len=0;len<MACNET_PTP_CLOCKID_SIZE;len++) tmp_tx_time.CLOCKID[len] = *((uint_8 *)(txmem + MACNET_PTP_UDP_CLOCKID + len)); wait_for_ts = TRUE; } } #endif /* ENETCFG_SUPPORT_PTP */ // Flush the tx bd from cache _DCACHE_FLUSH_MBYTES((pointer)tx_bd_ptr, sizeof(ENET_BD_STRUCT)); macnet_context_ptr->TxPCBS_PTR[macnet_context_ptr->NextTxBD] = packet; macnet_context_ptr->AvailableTxBDs--; BD_INC(macnet_context_ptr->NextTxBD,macnet_context_ptr->NumTxBDs); macnet_ptr->TDAR = ENET_TDAR_TDAR_MASK; END: MACNET_int_enable(); #if ENETCFG_SUPPORT_PTP if(wait_for_ts) { /* Wait for the interrupt */ _lwevent_wait_ticks(&macnet_context_ptr->PTP_PRIV->LWEVENT_PTP, MACNET_PTP_LWEVENT_TX_TS_INTR, FALSE, (uint_32)NULL); /* Clear the event */ _lwevent_clear(&macnet_context_ptr->PTP_PRIV->LWEVENT_PTP, MACNET_PTP_LWEVENT_TX_TS_INTR); /* Clear the TS flag from the BD */ tx_bd_ptr->CONTROL_EXT0 &= HOST_TO_BE_SHORT_CONST(~ENET_BD_EXT0_ETHER_TX_TIMESTAMP); tmp_tx_time.TS_TIME.NSEC = macnet_context_ptr->PTP_PRIV->TXSTAMP.NSEC; tmp_tx_time.TS_TIME.SEC = macnet_context_ptr->PTP_PRIV->TXSTAMP.SEC; MACNET_ptp_insert(&(macnet_context_ptr->PTP_PRIV->TX_TIME), &tmp_tx_time); wait_for_ts = FALSE; } #endif /* ENETCFG_SUPPORT_PTP */ return err; }