⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpltransmit.c

📁 NATIONAL公司DP83816芯片Linux下驱动
💻 C
📖 第 1 页 / 共 2 页
字号:

//******************************************************************************
//
//  MPLTRANSMIT.C
//
//  Copyright (c) 2004 National Semiconductor Corporation.
//  All Rights Reserved
//
//  MPL Transmit Engine.
//
//  This file contains the API implementations for
//     o MPL transmit engine configuration
//     o MPL packet transmit and completion handlers
//     o Transmit engine reset
//
//******************************************************************************

#include <mplinternal.h>

// Local helful debug macros
#undef ENTER
#undef EXIT
#undef ASSERT
#undef PRINT
#undef PRINTI
#undef PRINTS
#undef TBREAK

#define ENTER(fn) MPL_CENTER(DZONE_MPL_TRANS, fn)
#define EXIT(fn) MPL_CEXIT(DZONE_MPL_TRANS, fn)
#define ASSERT(le) MPL_CASSERT(DZONE_MPL_TRANS, le)
#define PRINT(fmt) MPL_CTRACE(DZONE_MPL_TRANS, fmt)
#define PRINTI(v) MPL_CTRACE(DZONE_MPL_TRANS, (" "#v": %x \n",(NS_UINT)(v)))
#define PRINTS(v) MPL_CTRACE(DZONE_MPL_TRANS, (" "#v": %s \n", v))
#define TBREAK(fmt) MPL_CTRACEBREAK(DZONE_MPL_TRANS, fmt)

// Locals
static NS_VOID setTxCfg(MPL_CONTEXT *pMplCtx,MPL_TRANSMIT_CFG *pCfgTransmit);
static MPL_STATUS allocTxdRing(MPL_CONTEXT *pMplCtx);
static NS_VOID setupTxdRing(MPL_CONTEXT *pMplCtx);

//*****************************************************************************
//   MplTransmitCfg
//      Configures the transmit engine on the device. 
//
//   Parameters
//      pMplHandle
//         MPL device handle returned following a call to MplInitialize
//      pCfgTransmit
//         Pointer to a caller allocated MPL_TRANSMIT_CFG structure with 
//          configuration values for the transmit engine
//
//   Return Value
//      NS_STATUS_SUCCESS
//         The configurations were successfully applied
//      NS_STATUS_INVALID_PARM
//         An invalid parameter value was detected
//      NS_STATUS_RESOURCES
//         Failed to allocate required resources
//
//*****************************************************************************
MPL_STATUS
   MplTransmitCfg (
      IN NS_VOID            *pMplHandle,
      IN MPL_TRANSMIT_CFG   *pCfgTransmit
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   NS_UINT8 i;
   NS_UINT32 regVal;

   // FM: Assert for pCfgTransmit == NULL

   ENTER(MplTransmitCfg);

   // Configure FIFO and DMA if client desires
   if (pCfgTransmit->cfgFlags & MPL_TRANSMIT_CFG_FIFO)
   {
      // Validate the FIFO thresholds and DMA burst size
      if ((pCfgTransmit->fillThreshold < pMplCtx->caps.txCaps.minFill) ||
           (pCfgTransmit->drainThreshold < pMplCtx->caps.txCaps.minDrain) ||
            ((pCfgTransmit->fillThreshold + pCfgTransmit->drainThreshold) > 
             pMplCtx->caps.txCaps.fifoSize)     ||
           (pCfgTransmit->maxDmaBurst > pMplCtx->caps.txCaps.maxDma) ||
           (pCfgTransmit->maxDmaBurst > pCfgTransmit->fillThreshold))
      {
         EXIT(MplTransmitCfg);
         return NS_STATUS_INVALID_PARM;
      }

      // Notify the hardware about the FIFO thresholds and DMA burst
      setTxCfg(pMplCtx, pCfgTransmit);
   }


   // Configure Tx queues if client desires
   if (pCfgTransmit->cfgFlags & MPL_TRANSMIT_CFG_QUEUES)
   {
      // Validate the priority queue count - should be atleast 1!
      if (pCfgTransmit->priorityQueueCnt > pMplCtx->caps.txCaps.priorityQCnt)
      {
         EXIT(MplTransmitCfg);
         return NS_STATUS_INVALID_PARM;
      }

      // If this is a runtime reconfiguration request, then free the old ring
      if (pMplCtx->txDescCnt)
      {
         freeTxdRing(pMplCtx);
      }

      // Get the Txd count - for all enabled queues
      pMplCtx->txQueueCnt = pCfgTransmit->priorityQueueCnt;
      for (i = 0x0; i < pMplCtx->txQueueCnt; i++)
      {
         pMplCtx->txQueue[i].descCnt = pCfgTransmit->descCnt[i]; //per queue
         pMplCtx->txDescCnt += pCfgTransmit->descCnt[i];
      }

      // Note max transmit done indications to be passed to NSM in one pass
      pMplCtx->maxTxDones = pCfgTransmit->maxIndications;

      // Allocate Txd ring 
      if (allocTxdRing(pMplCtx) != NS_STATUS_SUCCESS)
      {
         EXIT(MplTransmitCfg);
         return NS_STATUS_RESOURCES;
      }

      // Setup Txd ring 
      setupTxdRing(pMplCtx);

      // Enable priority Queuing if more than one Tx queue is requested
      if (pMplCtx->txQueueCnt > 0x01)
      {
         regVal = MPL_READ32(pMplCtx, PQCR);;
         regVal |= TXPRIOQ_EN;

         // Check if caller requests round-robin scheme for queue scheduling
         if (pCfgTransmit->cfgFlags & MPL_TRANSMIT_CFG_QUEUE_RR)
            regVal |= ROTPRIO_EN;

         MPL_WRITE32(pMplCtx, PQCR, regVal);
      }

      // Notify the device about the head node on the ring
      MPL_WRITE32(pMplCtx, TXDP,  pMplCtx->txQueue[0].ringPA);
      MPL_WRITE32(pMplCtx, TXDP1, pMplCtx->txQueue[1].ringPA);
      MPL_WRITE32(pMplCtx, TXDP2, pMplCtx->txQueue[2].ringPA);
      MPL_WRITE32(pMplCtx, TXDP3, pMplCtx->txQueue[3].ringPA);
   }

   EXIT(MplTransmitCfg);
   return NS_STATUS_SUCCESS; // All done
}

//*****************************************************************************
//   MplTransmitGetFreeDesc
//      Returns the total free transmit descriptors currently available. 
//
//   Parameters
//      pMplHandle
//         MPL device handle returned following a call to MplInitialize
//      pQueue
//         Queue (1,2...max tx queues) from which the free count is desired
//      pTxdCnt
//         Pointer to a caller allocated fields in which the count of free 
//          transmit descriptors is returned
//
//   Return Value
//      NS_STATUS_SUCCESS
//         The count was successfully returned.
//      NS_STATUS_INVALID_PARM
//         The priority queue count is invalid
//
//*****************************************************************************
MPL_STATUS
   MplTransmitGetFreeDesc (
      IN NS_VOID    *pMplHandle,
      IN NS_UINT8    pQueue,
      OUT NS_UINT   *pTxdCnt
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;

   ENTER(MplTransmitGetFreeDesc);

   // Validate the pQueue number
   if (pQueue > pMplCtx->txQueueCnt)
   {
      EXIT(MplTransmitGetFreeDesc);
      return NS_STATUS_INVALID_PARM;
   }

   // Get the free Txd count - Note we always hold one for ring termination
   *pTxdCnt = (pMplCtx->txQueue[pQueue-1].descCnt - 1) -
           (pMplCtx->txQueue[pQueue-1].curr - pMplCtx->txQueue[pQueue-1].dirty);

    EXIT(MplTransmitGetFreeDesc);
    return NS_STATUS_SUCCESS;
}

//*****************************************************************************
//   MplTransmit
//      Queues up one or more packets for transmission by the device.
//      NOTE: This function is non-reentrant with respect to itself, 
//        MplTransmitReset and MplTransmitDone
//
//   Parameters
//      pMplHandle
//         MPL device handle returned following a call to MplInitialize
//      pktCount
//         The count of packets being queued for transmission
//      pPacket
//         Pointer to a list of MPL_PKT structures due for transmission
//
//  Return Value
//      NS_STATUS_SUCCESS
//         All packets were successfully queued up for transmission
//      NS_STATUS_FAILURE
//         One or more of the packets where unacceptable for transmission
//         Clients need to check the status of each packet to detemine
//         which one failed,
//
//           Per packet status (pPacket->packetStatus) is one of
//             NS_STATUS_INVALID_PARM
//               The priority queue count is invalid
//             NS_STATUS_RESOURCES
//               Failed to allocate the required resources (Txds)
//
//*****************************************************************************
MPL_STATUS
   MplTransmit (
      IN NS_VOID      *pMplHandle,
      IN NS_UINT       pktCount,
      IN MPL_PKT      *pPacket
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   MPL_STATUS status = NS_STATUS_SUCCESS;
   MPL_DESC *currTxd, *firstTxd;
   MPL_PKT_FRAG *pFrag;
   NS_UINT8  priQSel = 0x0, pQueue;
   NS_UINT   i, entry, fragIndex, cmdSts, csFlag, txdAvail;

   ENTER(MplTransmit);

   // Send each packet
   for (i = 0x0; i < pktCount; i++)
   {
      // Get the priority queue number and validate
      if ((pPacket->txOOB.pQueue > pMplCtx->txQueueCnt) ||
          (pPacket->txOOB.pQueue < 0x1))
      {
         // Invalid Tx Q
         pPacket->packetStatus = NS_STATUS_INVALID_PARM;
         status = NS_STATUS_FAILURE;
         continue; // To Next Pkt
      }

      // Set the priority queue select
      pQueue = pPacket->txOOB.pQueue - 1;

      // Get available Txd count
      txdAvail = (pMplCtx->txQueue[pQueue].descCnt - 1) -
                  (pMplCtx->txQueue[pQueue].curr - 
                     pMplCtx->txQueue[pQueue].dirty);

      // Check availability - Each fragment needs a Txd
      if (txdAvail < pPacket->fragCount)
      {
         pPacket->packetStatus = NS_STATUS_RESOURCES;
         status = NS_STATUS_FAILURE;
         continue; // To Next Pkt - Maybe it is on a diff Tx-Q
      }

      // Set the priority queue select
      priQSel |= 1 << pQueue;

      // Get the first Txd for this packet
      entry = pMplCtx->txQueue[pQueue].curr % pMplCtx->txQueue[pQueue].descCnt;
      firstTxd = &pMplCtx->txQueue[pQueue].pRing[entry];

      // When dealing with multiple Txds per packet, the first Txd will
      //  have its OWN bit set last (to avoid Tx underruns)
      csFlag = CS_INTR;

#ifdef MPL_TASK_VLAN
      // If we are in VLAN per-pkt tag insertion mode then include the tag
      if (pMplCtx->taskVlan.cfg & MPL_TASK_VLAN_PERPACKET)
      {
         firstTxd->extCtlSts = MPL_HTOL32(pPacket->txOOB.extCtl);
      }
      else
      {
         firstTxd->extCtlSts = 0x0; // Clear
      }
#endif

      // Get the frag head
      pFrag = pPacket->pFragHead;
      fragIndex = 0x0;

      // Process each fragment
      currTxd = firstTxd;
      while (fragIndex < pPacket->fragCount)
      {
         // Check fragSize to be within max allowed
         if (pFrag->fragSize > CS_MAX_FRAG_SIZE)
         {
            pPacket->packetStatus = NS_STATUS_INVALID_PARM;
            status = NS_STATUS_FAILURE;
            break; // Go to next packet
         }

         // Set the buffer length and buffer phy address
         currTxd->bufptrPA = MPL_ADDR_HTOL(pFrag->physAddr);
         cmdSts = pFrag->fragSize; // Swapped later

         // Copy the physical addr of Txd -  for diag mode operations only
         pFrag->pMplPrivate = (NS_VOID *)(pMplCtx->txQueue[pQueue].ringPA + 
                                           (entry * sizeof(MPL_DESC)));

         // Increment the frag count and check if this is the last fragment
         if (++fragIndex < pPacket->fragCount)
         {
PRINT(("Multi Txd?  %d\n", pPacket->fragCount));
            // More frags to go
            
            // Set MORE on the current Txd
            currTxd->cmdSts = MPL_HTOL32(cmdSts | csFlag | CS_MORE);

            // Get the next Txd in the reserved order
            entry = (entry + 1) % pMplCtx->txQueue[pQueue].descCnt;
            currTxd = &pMplCtx->txQueue[pQueue].pRing[entry];

            // All further fragments will have its OWN bit set
            //  Note: See the OWN bit for first fragment above
            csFlag = CS_OWN_INTR;

            // Move on to the next fragment
            pFrag = pFrag->pNextFrag;
         }
         else
         {
            // Last frag

            // Note the Client Handle in this last Txd
            currTxd->mplPriv = pPacket->pNsmPrivate;

            // Set OWN, no MORE
            currTxd->cmdSts = MPL_HTOL32(cmdSts | CS_OWN_INTR);

            // For cases with MPL_PKT having multiple fragments we need to 
            //  hit the OWN bit for the first Txd - See notes above
            if (currTxd != firstTxd)
            {
               firstTxd->cmdSts |= CS_OWN_ES;
            }

            // Move free Txd index
            pMplCtx->txQueue[pQueue].curr += pPacket->fragCount;
            
            // Note the status
            pPacket->packetStatus = NS_STATUS_SUCCESS;
         }
      }

      // Get the next packet
      pPacket = pPacket->pNextPacket;
   }

   // FM: Evaulate if we should hit TXE per packet or a set of packets
   MPL_WRITE32(pMplCtx, CR, (priQSel << TX_PQUEUE_OFF) | TX_EN);

   EXIT(MplTransmit);
   return status;
}

//*****************************************************************************
//   MplTransmitDone
//      Processes transmit engine related events.
//      NOTE: This function is non-reentrant with respect to itself, 
//        MplTransmitReset and MplTransmit
//
//   Parameters
//      pMplHandle
//         MPL device handle returned following a call to MplInitialize
//      maxEvents
//         The maximum transmit engine related events (e.g. transmit complete) 
//          that MPL should process before returning back to the caller.
//
//   Return Value
//      NS_STATUS_SUCCESS
//         The transmit event was successfully handled.
//      NS_STATUS_ABORTED
//         The processing was aborted since the maximum event count specified
//          was met.
//
//*****************************************************************************
MPL_STATUS
   MplTransmitDone (
      IN NS_VOID   *pMplHandle,
      IN NS_UINT    maxEvents
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   MPL_STATUS status = NS_STATUS_SUCCESS;
   MPL_DESC *currTxd;
   NS_UINT8 pQueue, qNum;
   NS_UINT   priQSel, entry, pktCnt = 0x0, evtCnt = 0x0;

   ENTER(MplTransmitDone);

   // Get the Priority Queues that have completion events
   if (pMplCtx->txQueueCnt > 1) 
   {
      priQSel = (pMplCtx->isrReg & TXDESC_MASK) >> TXDESC_OFF;
   }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -