Esempio n. 1
0
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();
} 
Esempio n. 2
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++;

   } 
} 
Esempio n. 3
0
/*  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);
        }
    }
}
Esempio n. 4
0
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();

}
Esempio 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);
      }
   }
Esempio 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;
}