Ejemplo n.º 1
0
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++;

   } 
} 
Ejemplo n.º 2
0
static void MACNET_discard_current_rx(ENET_CONTEXT_STRUCT_PTR    enet_ptr,MACNET_CONTEXT_STRUCT_PTR   macnet_context_ptr, boolean last)
{
   uint_32  i;
   

   if (macnet_context_ptr->CurrentRxECB) {
      for (i=0;i<macnet_context_ptr->CurrentRxFrag;i++) {
         ENET_INC_STATS(COMMON.ST_RX_DISCARDED);
         if (macnet_context_ptr->FRAGS[i].FRAGMENT) {
            ENET_Enqueue_Buffer((pointer*)&macnet_context_ptr->RX_BUFFERS, macnet_context_ptr->FRAGS[i].FRAGMENT);
         }
         macnet_context_ptr->FRAGS[i].FRAGMENT = NULL;
      }
   }
   macnet_context_ptr->CurrentRxECB=NULL;
   
   if (last) 
      macnet_context_ptr->CurrentRxFrag=0;
}      
Ejemplo n.º 3
0
uint32_t ENET_send
   (
      /* [IN] the Ethernet state structure */
      _enet_handle   handle,

      /* [IN] the packet to send */
      PCB_PTR        packet,

      /* [IN] the protocol */
      uint16_t        type,

      /* [IN] the destination Ethernet address */
      _enet_address  dest,

      /* [IN] optional flags, zero = default */
      uint32_t        flags
   )
{ 
   ENET_CONTEXT_STRUCT_PTR  enet_ptr = (ENET_CONTEXT_STRUCT_PTR)handle;
   ENET_HEADER_PTR         packet_ptr;
   unsigned char               *type_ptr;
   PCB_FRAGMENT_PTR        frag_ptr;
   uint32_t                 swhdr, size, frags;
   uint32_t                 error;
   _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
   
   _KLOGM(_GET_KERNEL_DATA(kernel_data));
   _KLOGE6(KLOG_ENET_send, handle, packet, type, dest, flags);

   if (flags & ENET_OPT_8021QTAG) {
       swhdr = ENET_FRAMESIZE_HEAD_VLAN;
   } else {
       swhdr = ENET_FRAMESIZE_HEAD;
   } 

   /*
   ** Make sure the first fragment is long enough for the Ethernet
   ** frame header.  This isn't strictly necessary, but it's impractical
   ** to split a 14-26 byte header over multiple fragments.
   */
#if MQX_CHECK_ERRORS
   if (packet->FRAG[0].LENGTH < swhdr) {
      ENET_INC_STATS(COMMON.ST_TX_DISCARDED);
      error = ENETERR_SEND_SHORT;
      goto ERROR;
   }
#endif

   /*
   ** Make sure that no fragment exceeds a maximum packet length.
   ** We check every fragment because we want to prevent something
   ** like FRAG[0].LENGTH = 2000, FRAG[1].LENGTH = -1000.  This
   ** situation would not be detected if we only check the total
   ** length.
   */
   size = frags = 0;
   for (frag_ptr = packet->FRAG; frag_ptr->LENGTH; frag_ptr++) {
#if MQX_CHECK_ERRORS
      if (frag_ptr->LENGTH > enet_ptr->MaxTxFrameSize) {   
         ENET_INC_STATS(COMMON.ST_TX_DISCARDED);
         error = ENETERR_SEND_LONG;
         goto ERROR;
      } 
#endif
      size += frag_ptr->LENGTH;
      frags++;
   } 

   /*
   ** Make sure that the total sum of the fragments doesn't exceed
   ** a maximum packet length.
   */
#if MQX_CHECK_ERRORS
   if (size > enet_ptr->MaxTxFrameSize) {
      ENET_INC_STATS(COMMON.ST_TX_DISCARDED);
      error = ENETERR_SEND_LONG;
      goto ERROR;
   } 
#endif

   /*
   ** Everything checks out -- fill in the header.
   */
   packet_ptr = (ENET_HEADER_PTR)packet->FRAG[0].FRAGMENT;
   htone(packet_ptr->DEST, dest);
   htone(packet_ptr->SOURCE, enet_ptr->ADDRESS);
   type_ptr = packet_ptr->TYPE;

   if (flags & ENET_OPT_8021QTAG) {
      ENET_8021QTAG_HEADER_PTR tag_ptr = (ENET_8021QTAG_HEADER_PTR)(type_ptr+2);
      uint16_t tag;
      tag = ENET_GETOPT_8021QPRIO(flags) << 13;
      mqx_htons(type_ptr, ENETPROT_8021Q);
      mqx_htons(tag_ptr->TAG, tag);
      type_ptr = tag_ptr->TYPE;
   } 

   if (flags & ENET_OPT_8023) {
      ENET_8022_HEADER_PTR llc_ptr = (ENET_8022_HEADER_PTR)(type_ptr+2);
      (void)mqx_htons(type_ptr, size - swhdr);
      mqx_htonc(llc_ptr->DSAP, 0xAA);
      mqx_htonc(llc_ptr->SSAP, 0xAA);
      mqx_htonc(llc_ptr->COMMAND, 0x03);
      mqx_htonc(&llc_ptr->OUI[0], 0x00);
      mqx_htonc(&llc_ptr->OUI[1], 0x00);
      mqx_htonc(&llc_ptr->OUI[2], 0x00);
      type_ptr = llc_ptr->TYPE;
   } 

   mqx_htons(type_ptr, type);

   /*
   ** This function can be called from any context, and it needs mutual
   ** exclusion with itself, and with ENET_ISR().
   */
   ENET_lock_context(enet_ptr);
   error = (*enet_ptr->PARAM_PTR->ENET_IF->MAC_IF->SEND)(handle, packet, size, frags, flags);
   ENET_unlock_context(enet_ptr);

   if (error) {
   ERROR:
      PCB_free(packet);
   }
   
   _KLOGX4(KLOG_ENET_send, handle, packet, error);
   
   return error;
}  
Ejemplo n.º 4
0
uint32_t ENET_send_raw
   (
      /* [IN] the Ethernet state structure */
      _enet_handle   handle,

      /* [IN] the packet to send */
      PCB_PTR        packet
   )
{ /* Body */
   ENET_CONTEXT_STRUCT_PTR    enet_ptr = (ENET_CONTEXT_STRUCT_PTR)handle;
   PCB_FRAGMENT_PTR           frag_ptr;
   uint32_t                    size, frags;
   uint32_t                    error;

   /*
   ** Make sure that no fragment exceeds a maximum packet length.
   ** We check every fragment because we want to prevent something
   ** like FRAG[0].LENGTH = 2000, FRAG[1].LENGTH = -1000.  This
   ** situation would not be detected if we only check the total
   ** length.
   */
   size = frags = 0;
   for (frag_ptr = packet->FRAG; frag_ptr->LENGTH; frag_ptr++) {
#if MQX_CHECK_ERRORS
      if (frag_ptr->LENGTH > enet_ptr->MaxTxFrameSize) {   
         ENET_INC_STATS(COMMON.ST_TX_DISCARDED);
         error = ENETERR_SEND_LONG;
         goto ERROR;
      } 
#endif
      size += frag_ptr->LENGTH;
      frags++;
   } 

   /*
   ** Make sure that the total sum of the fragments doesn't exceed
   ** a maximum packet length.
   */
#if MQX_CHECK_ERRORS
   if (size > enet_ptr->MaxTxFrameSize) {
      ENET_INC_STATS(COMMON.ST_TX_DISCARDED);
      error = ENETERR_SEND_LONG;
      goto ERROR;
   } 
#endif

   /*
   ** This function can be called from any context, and it needs mutual
   ** exclusion with itself, and with ENET_ISR().
   */
   ENET_lock_context(enet_ptr);
   error = (*enet_ptr->PARAM_PTR->ENET_IF->MAC_IF->SEND)(handle, packet, size, frags, 0);
   ENET_unlock_context(enet_ptr);

   if (error) {
   ERROR:
      PCB_free(packet);
   }  

   return error;

}  
Ejemplo n.º 5
0
/*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);
      }
   }
Ejemplo n.º 6
0
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;
}