SAMV71 Xplained Ultra Software Package 1.3

gmacd.c

Go to the documentation of this file.
00001 /* ----------------------------------------------------------------------------
00002  *         SAM Software Package License 
00003  * ----------------------------------------------------------------------------
00004  * Copyright (c) 2012, Atmel Corporation
00005  *
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright notice,
00012  * this list of conditions and the disclaimer below.
00013  *
00014  * Atmel's name may not be used to endorse or promote products derived from
00015  * this software without specific prior written permission.
00016  *
00017  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
00020  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00022  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00023  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00024  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00025  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00026  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  * ----------------------------------------------------------------------------
00028  */
00029  /** \file */
00030 
00031 /*---------------------------------------------------------------------------
00032  *         Headers
00033  *---------------------------------------------------------------------------*/
00034 
00035 #include "chip.h"
00036 #include <string.h>
00037 
00038 /** \addtogroup gmacd_defines
00039     @{*/
00040 
00041 /*----------------------------------------------------------------------------
00042  *        Macro
00043  *----------------------------------------------------------------------------*/
00044 #if !defined MPU_HAS_NOCACHE_REGION
00045 #define GMAC_CACHE 
00046 #endif
00047     
00048 #if defined GMAC_CACHE 
00049      #define GMAC_CACHE_COHERENCE {SCB_CleanInvalidateDCache();}
00050 #else 
00051      #define GMAC_CACHE_COHERENCE {}
00052 #endif     
00053 
00054 /** ISO/IEC 14882:2003(E) - 5.6 Multiplicative operators:
00055  * The binary / operator yields the quotient, and the binary % operator yields 
00056  * the remainder from the division of the first expression by the second. 
00057  * If the second operand of / or % is zero the behaviour is undefined; otherwise
00058  *  (a/b)*b + a%b is equal to a.
00059  * If both operands are non-negative then the remainder is non-negative;
00060  * if not, the sign of the remainder is implementation-defined 74).
00061  */
00062 __STATIC_INLINE int fixed_mod(int a, int b)
00063 {
00064     int rem = a % b;
00065     while (rem < 0)
00066         rem += b;
00067 
00068     return rem;
00069 }
00070 
00071 /** Return count in buffer */
00072 #define GCIRC_CNT(head,tail,size)  fixed_mod((head) - (tail), (size))
00073 
00074 /** Return space available, 0..size-1. always leave one free char as a 
00075     completely full buffer has head == tail, which is the same as empty */
00076 #define GCIRC_SPACE(head,tail,size) GCIRC_CNT((tail),((head)+1),(size))
00077 
00078 /** Return count up to the end of the buffer. Carefully avoid accessing head 
00079     and tail more than once, so they can change underneath us without returning 
00080     inconsistent results */
00081 #define GCIRC_CNT_TO_END(head,tail,size) \
00082      ({int end = (size) - (tail); \
00083      int n = fixed_mod((head) + end, (size));    \
00084      n < end ? n : end;})
00085 
00086 /** Return space available up to the end of the buffer */
00087 #define GCIRC_SPACE_TO_END(head,tail,size) \
00088    ({int end = (size) - 1 - (head); \
00089      int n = fixed_mod(end + (tail), (size));    \
00090      n <= end ? n : end+1;})
00091 
00092 /** Increment head or tail */
00093 #define GCIRC_INC(headortail,size) \
00094        headortail++;             \
00095         if(headortail >= size) {  \
00096             headortail = 0;       \
00097         }
00098 
00099 /** Circular buffer is empty ? */
00100 #define GCIRC_EMPTY(head, tail)     (head == tail)
00101 
00102 /** Clear circular buffer */
00103 #define GCIRC_CLEAR(head, tail)  (head = tail = 0)
00104 
00105 /* This variable holds the write index into gPtpMsgTxQue */
00106 uint8_t ptpTxQueWriteIdx = 0u;
00107 uint8_t ptpTxQueReadIdx = 0u;
00108 
00109 /* This queue holds the transmit event messages */
00110 ptpMsgType gPtpMsgTxQue[EFRS_BUFFER_LEN];
00111 uint16_t gPtpMsgTxSeqId[EFRS_BUFFER_LEN];
00112    
00113 
00114 
00115 const uint32_t isrMasks[] = { GMAC_IMR_SFT, GMAC_IMR_DRQFT, 
00116                             GMAC_IMR_PDRQFT , GMAC_IMR_PDRSFT };
00117 
00118 /*---------------------------------------------------------------------------
00119  *         Local functions
00120  *---------------------------------------------------------------------------*/
00121 
00122 /**
00123  *  \brief Disable TX & reset registers and descriptor list
00124  *  \param pDrv Pointer to GMAC Driver instance.
00125  */
00126 static void GMACD_ResetTx(sGmacd *pDrv, gmacQueList_t queIdx)
00127 {
00128     Gmac *pHw = pDrv->pHw;
00129     uint8_t *pTxBuffer = pDrv->queueList[queIdx].pTxBuffer;
00130     sGmacTxDescriptor *pTd = pDrv->queueList[queIdx].pTxD;
00131     uint32_t Index;
00132     uint32_t Address;
00133 
00134     /* Disable TX */
00135     GMAC_TransmitEnable(pHw, 0);
00136     
00137     /* Setup the TX descriptors. */
00138     GCIRC_CLEAR(pDrv->queueList[queIdx].wTxHead, pDrv->queueList[queIdx].wTxTail);
00139     for(Index = 0; Index < pDrv->queueList[queIdx].wTxListSize; Index++) {
00140         Address = (uint32_t)(&(pTxBuffer[Index * 
00141                     pDrv->queueList[queIdx].wTxBufferSize]));
00142         pTd[Index].addr = Address;
00143         pTd[Index].status.val = (uint32_t)GMAC_TX_USED_BIT;
00144     }
00145     
00146     pTd[pDrv->queueList[queIdx].wTxListSize - 1].status.val =
00147                     GMAC_TX_USED_BIT | GMAC_TX_WRAP_BIT; 
00148     
00149     /* Transmit Buffer Queue Pointer Register */
00150       
00151     GMAC_SetTxQueue(pHw, (uint32_t)pTd, queIdx);
00152 }
00153     
00154 /**
00155  *  \brief Disable RX & reset registers and descriptor list
00156  *  \param pDrv Pointer to GMAC Driver instance. 
00157  */
00158 static void GMACD_ResetRx(sGmacd *pDrv, gmacQueList_t queIdx )
00159 {
00160     Gmac    *pHw = pDrv->pHw;
00161     uint8_t *pRxBuffer = pDrv->queueList[queIdx].pRxBuffer;
00162     sGmacRxDescriptor *pRd = pDrv->queueList[queIdx].pRxD;
00163 
00164     uint32_t Index;
00165     uint32_t Address;
00166 
00167     /* Disable RX */
00168     GMAC_ReceiveEnable(pHw, 0);
00169 
00170     /* Setup the RX descriptors. */
00171     pDrv->queueList[queIdx].wRxI = 0;
00172     for(Index = 0; Index < pDrv->queueList[queIdx].wRxListSize; Index++) {
00173         Address = (uint32_t)(&(pRxBuffer[Index * 
00174                 pDrv->queueList[queIdx].wRxBufferSize]));
00175         /* Remove GMAC_RXD_bmOWNERSHIP and GMAC_RXD_bmWRAP */
00176         pRd[Index].addr.val = Address & GMAC_ADDRESS_MASK;
00177         pRd[Index].status.val = 0;
00178     }
00179     
00180     pRd[pDrv->queueList[queIdx].wRxListSize - 1].addr.val |= GMAC_RX_WRAP_BIT;
00181     
00182     /* Receive Buffer Queue Pointer Register */ 
00183     GMAC_SetRxQueue(pHw, (uint32_t)pRd, queIdx);
00184 }
00185 
00186 
00187 /**
00188  *  \brief Process successfully sent packets
00189  *  \param pGmacd Pointer to GMAC Driver instance.
00190  */
00191 static void GMACD_TxCompleteHandler(sGmacd *pGmacd, gmacQueList_t qId)
00192 {
00193     Gmac                   *pHw = pGmacd->pHw;
00194     sGmacTxDescriptor      *pTxTd;
00195     fGmacdTransferCallback fTxCb;
00196     uint32_t               tsr;
00197 
00198     /* Clear status */
00199     tsr = GMAC_GetTxStatus(pHw);
00200     GMAC_ClearTxStatus(pHw, tsr);
00201 
00202     while (!GCIRC_EMPTY(
00203             pGmacd->queueList[qId].wTxHead, pGmacd->queueList[qId].wTxTail)) {
00204         pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];
00205 
00206         /* Make hw descriptor updates visible to CPU */
00207         GMAC_CACHE_COHERENCE
00208 
00209         /* Exit if frame has not been sent yet:
00210          * On TX completion, the GMAC set the USED bit only into the
00211          * very first buffer descriptor of the sent frame.
00212          * Otherwise it updates this descriptor with status error bits.
00213          * This is the descriptor write back.
00214          */
00215         if ((pTxTd->status.val & GMAC_TX_USED_BIT) == 0)
00216             break;
00217 
00218         /* Process all buffers of the current transmitted frame */
00219         while ((pTxTd->status.val & GMAC_TX_LAST_BUFFER_BIT) == 0) {
00220             GCIRC_INC(pGmacd->queueList[qId].wTxTail, 
00221                     pGmacd->queueList[qId].wTxListSize);
00222             pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];
00223             memory_sync();
00224         }
00225 
00226         /* Notify upper layer that a frame has been sent */
00227         fTxCb = pGmacd->queueList[qId].fTxCbList[pGmacd->queueList[qId].wTxTail];
00228         if (fTxCb)
00229             fTxCb(tsr);
00230 
00231         /* Go to next frame */
00232         GCIRC_INC(pGmacd->queueList[qId].wTxTail, pGmacd->queueList[qId].wTxListSize);
00233     }
00234 
00235     /* If a wakeup has been scheduled, notify upper layer that it can
00236        send other packets, send will be successful. */
00237     if (pGmacd->queueList[qId].fWakupCb &&
00238         GCIRC_SPACE(pGmacd->queueList[qId].wTxHead,
00239                     pGmacd->queueList[qId].wTxTail,
00240                     pGmacd->queueList[qId].wTxListSize) >= 
00241                         pGmacd->queueList[qId].bWakeupThreshold)
00242         pGmacd->queueList[qId].fWakupCb();
00243 }
00244 
00245 
00246 /**
00247  *  \brief Reset TX queue when errors are detected
00248  *  \param pGmacd Pointer to GMAC Driver instance.
00249  */
00250 static void GMACD_TxErrorHandler(sGmacd *pGmacd, gmacQueList_t qId)
00251 {
00252     Gmac                   *pHw = pGmacd->pHw;
00253     sGmacTxDescriptor      *pTxTd;
00254     fGmacdTransferCallback fTxCb;
00255     uint32_t               tsr;
00256 
00257     /* Clear TXEN bit into the Network Configuration Register:
00258      * this is a workaround to recover from TX lockups that 
00259      * occur on sama5d3 gmac (r1p24f2) when using  scatter-gather.
00260      * This issue has never been seen on sama5d4 gmac (r1p31).
00261      */
00262     GMAC_TransmitEnable(pHw, 0);
00263 
00264     /* The following step should be optional since this function is called 
00265      * directly by the IRQ handler. Indeed, according to Cadence 
00266      * documentation, the transmission is halted on errors such as
00267      * too many retries or transmit under run.
00268      * However it would become mandatory if the call of this function
00269      * were scheduled as a task by the IRQ handler (this is how Linux 
00270      * driver works). Then this function might compete with GMACD_Send().
00271      *
00272      * Setting bit 10, tx_halt, of the Network Control Register is not enough:
00273      * We should wait for bit 3, tx_go, of the Transmit Status Register to 
00274      * be cleared at transmit completion if a frame is being transmitted.
00275      */
00276     GMAC_TransmissionHalt(pHw);
00277     while (GMAC_GetTxStatus(pHw) & GMAC_TSR_TXGO);
00278 
00279     /* Treat frames in TX queue including the ones that caused the error. */
00280     while (!GCIRC_EMPTY(pGmacd->queueList[qId].wTxHead, 
00281             pGmacd->queueList[qId].wTxTail)) {
00282         int tx_completed = 0;
00283         pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];
00284 
00285         /* Make hw descriptor updates visible to CPU */
00286         GMAC_CACHE_COHERENCE
00287         /* Check USED bit on the very first buffer descriptor to validate
00288          * TX completion.
00289          */
00290         if (pTxTd->status.val & GMAC_TX_USED_BIT)
00291             tx_completed = 1;
00292 
00293         /* Go to the last buffer descriptor of the frame */
00294         while ((pTxTd->status.val & GMAC_TX_LAST_BUFFER_BIT) == 0) {
00295             GCIRC_INC(pGmacd->queueList[qId].wTxTail, 
00296                     pGmacd->queueList[qId].wTxListSize);
00297             pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];
00298             GMAC_CACHE_COHERENCE
00299         }
00300 
00301         /* Notify upper layer that a frame status */
00302         fTxCb = pGmacd->queueList[qId].fTxCbList[pGmacd->queueList[qId].wTxTail];
00303         if (fTxCb)
00304             fTxCb(tx_completed ? GMAC_TSR_TXCOMP : 0); 
00305         // TODO: which error to notify?
00306 
00307         /* Go to next frame */
00308         GCIRC_INC(pGmacd->queueList[qId].wTxTail, pGmacd->queueList[qId].wTxListSize);
00309     }    
00310 
00311     /* Reset TX queue */
00312     GMACD_ResetTx(pGmacd, qId);
00313     
00314     /* Clear status */
00315     tsr = GMAC_GetTxStatus(pHw);
00316     GMAC_ClearTxStatus(pHw, tsr);
00317 
00318     /* Now we are ready to start transmission again */
00319     GMAC_TransmitEnable(pHw, 1);
00320     if (pGmacd->queueList[qId].fWakupCb)
00321         pGmacd->queueList[qId].fWakupCb();
00322 }
00323 
00324  
00325 /*---------------------------------------------------------------------------
00326  *         Exported functions
00327  *---------------------------------------------------------------------------*/
00328 
00329 
00330 #ifndef PTP_1588_TX_DISABLE  
00331 
00332 void GMACD_TxPtpEvtMsgCBRegister (sGmacd * pGmacd, 
00333         fGmacdTxPtpEvtCallBack pTxPtpEvtCb, gmacQueList_t queIdx)  
00334 {  
00335   pGmacd->queueList[queIdx].fTxPtpEvtCb = pTxPtpEvtCb;
00336 } 
00337 
00338 #endif   /* #ifdef PTP_1588_TX_DISABLE */  
00339  
00340 /**
00341  *  \brief GMAC Interrupt handler
00342  *  \param pGmacd Pointer to GMAC Driver instance.
00343  */
00344 void GMACD_Handler(sGmacd *pGmacd, gmacQueList_t queIdx)
00345 {
00346     Gmac *pHw = pGmacd->pHw;
00347     uint32_t isr;
00348     uint32_t rsr;
00349     
00350     /* Interrupt Status Register is cleared on read */
00351     while ( (isr = GMAC_GetItStatus(pHw, queIdx)) !=0) {
00352         /*  Sync Frame Received - PTP */
00353         if(0u != (isr & GMAC_ISR_SFR)) {
00354             rsr = GMAC_ISR_SFR;
00355             memory_barrier();
00356             /* Invoke callbacks */
00357             if (pGmacd->queueList[queIdx].fRxCb) {
00358                 pGmacd->queueList[queIdx].fRxCb(rsr);
00359             } else {
00360             }
00361         } else {
00362         }
00363         
00364         /* Peer Delay Request Frame Received - PTP */
00365         if (0u != (isr & GMAC_ISR_PDRQFR) ) {
00366             rsr = GMAC_ISR_PDRQFR;
00367             memory_barrier();
00368             
00369             /* Invoke callbacks */
00370             if (pGmacd->queueList[queIdx].fRxCb) {
00371                 pGmacd->queueList[queIdx].fRxCb(rsr);
00372             } else {
00373             }
00374         } else {
00375         }
00376 
00377         /* Peer Delay Response Frame Received - PTP */
00378         if (0u != (isr & GMAC_ISR_PDRSFR) ) {
00379             
00380             rsr = GMAC_ISR_PDRSFR;
00381             memory_barrier();
00382             
00383             /* Invoke callbacks */
00384             if (pGmacd->queueList[queIdx].fRxCb) {
00385                 pGmacd->queueList[queIdx].fRxCb(rsr);
00386             } else {
00387             }
00388         } else {
00389         }
00390     
00391         if( 0u != (isr & GMAC_ISR_TSU)) {
00392             /* Invoke call back with flag set to TSU comparison interrupt */
00393             rsr = GMAC_ISR_TSU;
00394             memory_barrier();
00395         
00396             /* Invoke callbacks */
00397             if (pGmacd->queueList[queIdx].fRxCb) { 
00398                 pGmacd->queueList[queIdx].fRxCb(rsr);
00399             } else {
00400             }
00401         } else {
00402         }
00403         
00404         /* RX packet */
00405         if (isr & GMAC_INT_RX_BITS) {
00406             /* Clear status */
00407             rsr = GMAC_GetRxStatus(pHw);
00408             GMAC_ClearRxStatus(pHw, rsr);
00409 
00410             /* Invoke callback */
00411             if (pGmacd->queueList[queIdx].fRxCb)
00412                 pGmacd->queueList[queIdx].fRxCb(rsr);
00413             }
00414 
00415             /* TX error */
00416             if (isr & GMAC_INT_TX_ERR_BITS) {
00417                 GMACD_TxErrorHandler(pGmacd, queIdx);
00418                 break;
00419             }
00420     
00421 #ifndef PTP_1588_TX_DISABLE
00422             /* Transmit of SYNC / PDELAY_REQ / PDELAY_RSP */    
00423             if(0u != (isr & isrMasks[gPtpMsgTxQue[ptpTxQueReadIdx]])) {
00424             /* Invoke callback */
00425             /*  Check if it is possible for multiple messages to be triggered 
00426             within a single isr. If so, a loop may be needed to validate the top
00427             of the queue with the actual interrupt that has been triggered */
00428 /* while(0u != (isr & (GMAC_IMR_SFT | GMAC_IMR_PDRQFT | GMAC_IMR_PDRSFT))) { */
00429             if (pGmacd->queueList[queIdx].fTxPtpEvtCb) {
00430                 switch (gPtpMsgTxQue[ptpTxQueReadIdx]) {
00431                 case SYNC_MSG_TYPE:
00432                     pGmacd->queueList[queIdx].fTxPtpEvtCb 
00433                                     (gPtpMsgTxQue[ptpTxQueReadIdx], 
00434                                     GMAC_GetTxEvtFrameSec(pHw), 
00435                                     GMAC_GetTxEvtFrameNsec(pHw), 
00436                                     gPtpMsgTxSeqId[ptpTxQueReadIdx]);
00437                     isr &= GMAC_IMR_SFT;
00438                     break;
00439                 case PDELAY_REQ_TYPE:
00440                     pGmacd->queueList[queIdx].fTxPtpEvtCb 
00441                                     (gPtpMsgTxQue[ptpTxQueReadIdx], 
00442                                     GMAC_GetTxPeerEvtFrameSec(pHw), 
00443                                     GMAC_GetTxPeerEvtFrameNsec(pHw), 
00444                                     gPtpMsgTxSeqId[ptpTxQueReadIdx]);
00445                     isr &= GMAC_IMR_PDRQFT;
00446                     break;
00447                 case PDELAY_RESP_TYPE:
00448                     pGmacd->queueList[queIdx].fTxPtpEvtCb 
00449                                     (gPtpMsgTxQue[ptpTxQueReadIdx], 
00450                                     GMAC_GetTxPeerEvtFrameSec(pHw), 
00451                                     GMAC_GetTxPeerEvtFrameNsec(pHw), 
00452                                     gPtpMsgTxSeqId[ptpTxQueReadIdx]);
00453                     isr &= GMAC_IMR_PDRSFT;
00454                     break;
00455                 default:
00456                     /* Only for Peer messages & sync messages */
00457                     break;
00458                 };
00459         } else {
00460         }
00461 
00462             ptpTxQueReadIdx++;
00463             ptpTxQueReadIdx &= (EFRS_BUFFER_LEN-1);
00464             
00465             } else { 
00466                 /* if(0u != (isr & isrMasks[gPtpMsgTxQue[ptpTxQueReadIdx]])) */
00467             }
00468 #endif /* #ifndef PTP_1588_TX_DISABLE */
00469         /* TX packet */
00470         if (isr & GMAC_IER_TCOMP)
00471             GMACD_TxCompleteHandler(pGmacd, queIdx);
00472         if (isr & GMAC_IER_HRESP) {
00473             TRACE_ERROR("HRESP\n\r");
00474         }
00475     }
00476 }
00477 
00478 
00479 /**
00480  * \brief Initialize the GMAC with the Gmac controller address
00481  *  \param pGmacd Pointer to GMAC Driver instance. 
00482  *  \param pHw    Pointer to HW address for registers.
00483  *  \param bID     HW ID for power management
00484  *  \param enableCAF    Enable/Disable CopyAllFrame.
00485  *  \param enableNBC    Enable/Disable NoBroadCast.
00486  */
00487  void GMACD_Init(sGmacd *pGmacd,
00488                 Gmac *pHw,
00489                 uint8_t bID, 
00490                 uint8_t enableCAF, 
00491                 uint8_t enableNBC )
00492 {
00493     uint32_t dwNcfgr;
00494     
00495     /* Check parameters */
00496 //    assert(GRX_BUFFERS * GMAC_RX_UNITSIZE > GMAC_FRAME_LENTGH_MAX);
00497 
00498     TRACE_DEBUG("GMAC_Init\n\r");
00499 
00500     /* Initialize struct */
00501     pGmacd->pHw = pHw;
00502     pGmacd->bId = bID;
00503 
00504     /* Power ON */
00505     PMC_EnablePeripheral(bID);
00506 
00507     /* Disable TX & RX and more */
00508     GMAC_NetworkControl(pHw, 0);
00509     GMAC_DisableAllQueueIt(pHw, ~0u);
00510     
00511     GMAC_ClearStatistics(pHw);
00512     /* Clear all status bits in the receive status register. */
00513     GMAC_ClearRxStatus(pHw, GMAC_RSR_RXOVR | GMAC_RSR_REC 
00514                     | GMAC_RSR_BNA |GMAC_RSR_HNO);
00515 
00516     /* Clear all status bits in the transmit status register */
00517     GMAC_ClearTxStatus(pHw, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE
00518                             | GMAC_TSR_TXGO | GMAC_TSR_TFC | GMAC_TSR_TXCOMP
00519                             | GMAC_TSR_HRESP );
00520 
00521     /* Clear All interrupts */
00522     GMAC_GetItStatus(pHw, GMAC_QUE_0);
00523     GMAC_GetItStatus(pHw, GMAC_QUE_1);
00524     GMAC_GetItStatus(pHw, GMAC_QUE_2);
00525 
00526     /* Enable the copy of data into the buffers
00527        ignore broadcasts, and don't copy FCS. */
00528     dwNcfgr = GMAC_NCFGR_FD | GMAC_NCFGR_DBW(0) | GMAC_NCFGR_CLK_MCK_64 |
00529               GMAC_NCFGR_MAXFS | GMAC_NCFGR_PEN | GMAC_NCFGR_RFCS;
00530     if( enableCAF ) {
00531         dwNcfgr |= GMAC_NCFGR_CAF;
00532     }
00533     if( enableNBC ) {
00534         dwNcfgr |= GMAC_NCFGR_NBC;
00535     }
00536     
00537     GMAC_Configure(pHw, dwNcfgr);
00538 }
00539 
00540 
00541 /**
00542  * Initialize necessary allocated buffer lists for GMAC Driver to transfer data.
00543  * Must be invoked after GMACD_Init() but before RX/TX start.
00544  * Replace the deprecated GMACD_InitTransfer().
00545  * \param pGmacd Pointer to GMAC Driver instance.
00546  * \param pInit  Pointer to sGmacInit.
00547  * \param pInit  Pointer to gmacQueList_t for different queue.
00548  * \return GMACD_OK or GMACD_PARAM.
00549  * \note If input address is not 8-byte aligned the address is automatically
00550  *       adjusted and the list size is reduced by one.
00551  */
00552 uint8_t GMACD_InitTransfer(sGmacd *pGmacd, const sGmacInit *pInit, 
00553                             gmacQueList_t queIdx)
00554 {
00555     Gmac *pHw = pGmacd->pHw;
00556     uint8_t *pRxBuffer = pInit->pRxBuffer;
00557     sGmacRxDescriptor *pRxD = pInit->pRxD;
00558     uint16_t wRxBufferSize = pInit->wRxBufferSize;
00559     uint16_t wRxSize = pInit->wRxSize;
00560     uint8_t *pTxBuffer = pInit->pTxBuffer;
00561     sGmacTxDescriptor *pTxD = pInit->pTxD;
00562     uint16_t wTxBufferSize = pInit->wTxBufferSize;
00563     uint16_t wTxSize = pInit->wTxSize;
00564     fGmacdTransferCallback *pTxCb = pInit->pTxCb;
00565     uint32_t dwDmaCfg;
00566     if (wRxSize <= 1 || wTxSize <= 1 || pTxCb == NULL) return GMACD_PARAM;
00567 
00568     if (!wRxBufferSize || wRxBufferSize > 16*1024 || wRxBufferSize & 0x3f)
00569         return GMACD_PARAM;
00570 
00571     if (!wTxBufferSize)
00572         return GMACD_PARAM;
00573 
00574     if (pInit->bIsGem) {
00575         if(!queIdx) {
00576             dwDmaCfg = (GMAC_DCFGR_DRBS(wRxBufferSize >> 6) ) 
00577                 | GMAC_DCFGR_RXBMS(3) | GMAC_DCFGR_TXPBMS;
00578             switch (pInit->bDmaBurstLength) {
00579             case 16:
00580                 dwDmaCfg |= GMAC_DCFGR_FBLDO_INCR16;
00581                 break;
00582             case 8:
00583                 dwDmaCfg |= GMAC_DCFGR_FBLDO_INCR8;
00584                 break;
00585             case 4:
00586                 dwDmaCfg |= GMAC_DCFGR_FBLDO_INCR4;
00587                 break;
00588             case 1:
00589                 dwDmaCfg |= GMAC_DCFGR_FBLDO_SINGLE;
00590                 break;
00591             default:
00592                 return GMACD_PARAM;
00593                 break;
00594             }
00595         } else {
00596             dwDmaCfg = (GMAC_RBSRPQ_RBS(wRxBufferSize >> 6) );
00597         }
00598         GMAC_SetDMAConfig(pHw, dwDmaCfg, queIdx);
00599     }
00600 
00601     pGmacd->queueList[queIdx].wRxBufferSize = wRxBufferSize;
00602     pGmacd->queueList[queIdx].wTxBufferSize = wTxBufferSize;
00603     /* Assign RX buffers */
00604     if (((uint32_t)pRxBuffer & 0x7)
00605         || ((uint32_t)pRxD & 0x7) ) {
00606         wRxSize --;
00607         TRACE_DEBUG("RX list address adjusted\n\r");
00608     }
00609     pGmacd->queueList[queIdx].pRxBuffer = (uint8_t*)((uint32_t)pRxBuffer & 0xFFFFFFF8);
00610     pGmacd->queueList[queIdx].pRxD = (sGmacRxDescriptor*)((uint32_t)pRxD & 0xFFFFFFF8);
00611     pGmacd->queueList[queIdx].wRxListSize = wRxSize;
00612 
00613     /* Assign TX buffers */
00614     if (   ((uint32_t)pTxBuffer & 0x7)
00615         || ((uint32_t)pTxD & 0x7) ) {
00616         wTxSize --;
00617         TRACE_DEBUG("TX list address adjusted\n\r");
00618     }
00619     pGmacd->queueList[queIdx].pTxBuffer = (uint8_t*)((uint32_t)pTxBuffer & 0xFFFFFFF8);
00620     pGmacd->queueList[queIdx].pTxD = (sGmacTxDescriptor*)((uint32_t)pTxD & 0xFFFFFFF8);
00621     pGmacd->queueList[queIdx].wTxListSize = wTxSize;
00622     pGmacd->queueList[queIdx].fTxCbList = pTxCb;
00623 
00624     /* Reset TX & RX */
00625     GMACD_ResetRx(pGmacd, queIdx);
00626     GMACD_ResetTx(pGmacd, queIdx);
00627 
00628    /* Setup the interrupts for RX/TX completion (and errors) */
00629     switch(queIdx) {
00630     case GMAC_QUE_0:
00631         /* YBP: Que 0 should be configured last so as to enable transmit and
00632         Receive in the NCR register */
00633         
00634         /* Enable Rx and Tx, plus the status register. */
00635         GMAC_TransmitEnable(pHw, 1);
00636         GMAC_ReceiveEnable(pHw, 1);
00637         GMAC_StatisticsWriteEnable(pHw, 1);
00638 
00639         GMAC_EnableIt(pHw,
00640                   GMAC_INT_RX_BITS |
00641                   GMAC_INT_TX_BITS |
00642                   GMAC_INT_TX_ERR_BITS, GMAC_QUE_0);
00643         break;
00644         
00645     case GMAC_QUE_1:
00646         GMAC_EnableIt(pHw,
00647                   GMAC_INT_RX_BITS |
00648                   GMAC_INT_TX_BITS |
00649                   GMAC_INT_TX_ERR_BITS, GMAC_QUE_1);
00650         break;
00651     case GMAC_QUE_2:
00652           GMAC_EnableIt(pHw,
00653                   GMAC_INT_RX_BITS |
00654                   GMAC_INT_TX_BITS |
00655                   GMAC_INT_TX_ERR_BITS, GMAC_QUE_2);
00656         break;
00657     };
00658     return GMACD_OK;
00659 }
00660 
00661 
00662 /**
00663  * Reset TX & RX queue & statistics
00664  * \param pGmacd Pointer to GMAC Driver instance.
00665  */
00666 void GMACD_Reset(sGmacd *pGmacd)
00667 {
00668     Gmac *pHw = pGmacd->pHw;
00669 
00670     GMACD_ResetRx(pGmacd, GMAC_QUE_0);
00671     GMACD_ResetRx(pGmacd, GMAC_QUE_1);
00672     GMACD_ResetRx(pGmacd, GMAC_QUE_2);
00673     
00674     GMACD_ResetTx(pGmacd, GMAC_QUE_0);
00675     GMACD_ResetTx(pGmacd, GMAC_QUE_1);
00676     GMACD_ResetTx(pGmacd, GMAC_QUE_2);
00677     
00678     //memset((void*)&GmacStatistics, 0x00, sizeof(GmacStats));
00679     GMAC_NetworkControl(pHw, GMAC_NCR_TXEN | GMAC_NCR_RXEN
00680                              | GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);
00681 }
00682 
00683 /**
00684  * \brief Send a frame split into buffers. If the frame size is larger than 
00685  * transfer buffer size error returned. If frame transfer status is monitored, 
00686  * specify callback for each frame.
00687  *  \param pGmacd Pointer to GMAC Driver instance. 
00688  *  \param sgl Pointer to a scatter-gather list describing the buffers of the 
00689  * ethernet frame.
00690  *  \param fTxCb Pointer to callback function.
00691  */
00692 uint8_t GMACD_SendSG(sGmacd *pGmacd,
00693                      const sGmacSGList *sgl,
00694                      fGmacdTransferCallback fTxCb,
00695                      gmacQueList_t queIdx)
00696 {
00697     Gmac *pHw = pGmacd->pHw;
00698     sGmacTxDescriptor *pTd = pGmacd->queueList[queIdx].pTxD;
00699     sGmacTxDescriptor *pTxTd;
00700     uint16_t wTxPos, wTxHead;
00701     int i;
00702 
00703     TRACE_DEBUG("%s\n\r", __FUNCTION__);
00704 
00705     /* Check parameter */
00706     if (!sgl->len) {
00707         TRACE_ERROR("%s:: ethernet frame is empty.\r\n", __FUNCTION__);
00708         return GMACD_PARAM;
00709     }
00710     if (sgl->len >= pGmacd->queueList[queIdx].wTxListSize) {
00711         TRACE_ERROR("%s: ethernet frame has too many buffers.\r\n", __FUNCTION__);
00712         return GMACD_PARAM;
00713     }
00714     /* Check available space */
00715     if (GCIRC_SPACE(pGmacd->queueList[queIdx].wTxHead, 
00716             pGmacd->queueList[queIdx].wTxTail,
00717             pGmacd->queueList[queIdx].wTxListSize) < (int)sgl->len)
00718         return GMACD_TX_BUSY;
00719 
00720     /* Tag end of TX queue */
00721     wTxHead = fixed_mod(pGmacd->queueList[queIdx].wTxHead + sgl->len, 
00722             pGmacd->queueList[queIdx].wTxListSize);
00723     wTxPos = wTxHead;
00724     pGmacd->queueList[queIdx].fTxCbList[wTxPos] = NULL;
00725     pTxTd = &pTd[wTxPos];
00726     pTxTd->status.val = GMAC_TX_USED_BIT;
00727     /* Update buffer descriptors in reverse order to avoid a race 
00728      * condition with hardware.
00729      */
00730     for (i = (int)(sgl->len-1); i >= 0; --i) {
00731         const sGmacSG *sg = &sgl->sg[i];
00732         uint32_t status;
00733 
00734         if (sg->size > pGmacd->queueList[queIdx].wTxBufferSize) {
00735             TRACE_ERROR("%s: buffer size is too big.\r\n", __FUNCTION__);
00736             return GMACD_PARAM;
00737         }
00738 
00739         if (wTxPos == 0)
00740             wTxPos = pGmacd->queueList[queIdx].wTxListSize-1;
00741         else
00742             wTxPos--;
00743 
00744         /* Reset TX callback */
00745         pGmacd->queueList[queIdx].fTxCbList[wTxPos] = NULL;
00746 
00747         pTxTd = &pTd[wTxPos];
00748 #ifdef GMAC_ZERO_COPY
00749         /** Update buffer descriptor address word:
00750          *  MUST be done before status word to avoid a race condition.
00751          */
00752         pTxTd->addr = (uint32_t)sg->pBuffer;
00753         
00754 #else
00755         /* Copy data into transmission buffer */
00756         if (sg->pBuffer && sg->size){
00757             memcpy((void *)pTxTd->addr, sg->pBuffer, sg->size); 
00758          }
00759 #endif
00760         GMAC_CACHE_COHERENCE
00761 
00762         /* Compute buffer descriptor status word */
00763         status = sg->size & GMAC_LENGTH_FRAME;
00764         if (i == (int)(sgl->len-1)) {
00765             status |= GMAC_TX_LAST_BUFFER_BIT;
00766             pGmacd->queueList[queIdx].fTxCbList[wTxPos] = fTxCb;
00767         }
00768         if (wTxPos == pGmacd->queueList[queIdx].wTxListSize-1)
00769             status |= GMAC_TX_WRAP_BIT;
00770 
00771         /* Update buffer descriptor status word: clear USED bit */
00772         pTxTd->status.val = status;
00773 
00774         /* Make newly initialized descriptor visible to hardware */
00775         GMAC_CACHE_COHERENCE
00776     }
00777 
00778     /* Update TX ring buffer pointers */
00779     pGmacd->queueList[queIdx].wTxHead = wTxHead;
00780     /* Now start to transmit if it is not already done */
00781     
00782     GMAC_TransmissionStart(pHw);
00783     return GMACD_OK;
00784 }
00785 
00786 /**
00787  * \brief Send a packet with GMAC. If the packet size is larger than transfer 
00788  * buffer size error returned. If packet transfer status is monitored, specify
00789  * callback for each packet.
00790  *  \param pGmacd Pointer to GMAC Driver instance. 
00791  *  \param pBuffer   The buffer to be send
00792  *  \param size     The size of buffer to be send
00793  *  \param fTxCb Threshold Wakeup callback
00794  *  \return         OK, Busy or invalid packet
00795  */
00796 uint8_t GMACD_Send(sGmacd *pGmacd,
00797                    void *pBuffer,
00798                    uint32_t size,
00799                    fGmacdTransferCallback fTxCb,
00800                    gmacQueList_t queIdx)
00801 {
00802     sGmacSGList sgl;
00803     sGmacSG sg;
00804     
00805     uint8_t *msgPtr;
00806     ptpMsgType ptpMsg;
00807     /* Init single entry scatter-gather list */
00808     sg.size = size;
00809     sg.pBuffer = pBuffer;
00810     sgl.len = 1;
00811     sgl.sg = &sg;
00812 
00813 
00814     
00815 #ifndef PTP_1588_TX_DISABLE
00816 
00817     msgPtr = (uint8_t *)pBuffer;
00818     if(0x88u == msgPtr[12] && 0xf7u == msgPtr[13]) {
00819         /* Extract Tx PTP message  type */
00820         ptpMsg = (ptpMsgType)(msgPtr[14] & 0x0F);
00821         if (ptpMsg == SYNC_MSG_TYPE || ptpMsg == PDELAY_REQ_TYPE 
00822             || ptpMsg == PDELAY_RESP_TYPE) {
00823             /* Only add message to Tx queue of msg types that have 
00824                 tx event ISRs enabled. */
00825             gPtpMsgTxQue[ptpTxQueWriteIdx] = ptpMsg;
00826             
00827             /* Copy the Sequence Id */
00828             gPtpMsgTxSeqId[ptpTxQueWriteIdx] = 
00829                 (uint16_t)(((uint16_t)msgPtr[44] << 8) | msgPtr[45]);
00830             ptpTxQueWriteIdx++;
00831             ptpTxQueWriteIdx &= (EFRS_BUFFER_LEN-1u);
00832         } else { 
00833                 /* if (ptpMsg == SYNC_MSG_TYPE || ptpMsg == PDELAY_REQ_TYPE\
00834                 || ptpMsg == PDELAY_RESP_TYPE) { */
00835         }
00836     } else { /* if(0x88 == msgPtr[12] && 0xf7 == msgPtr[13]) { */
00837     }  
00838 #endif /* #ifndef PTP_1588_TX_DISABLE */
00839     return GMACD_SendSG(pGmacd, &sgl, fTxCb, queIdx);
00840 }
00841 
00842 /**
00843  * Return current load of TX.
00844  * \param pGmacd   Pointer to GMAC Driver instance.
00845  */
00846 uint32_t GMACD_TxLoad(sGmacd *pGmacd, gmacQueList_t queIdx)
00847 {
00848     uint16_t head = pGmacd->queueList[queIdx].wTxHead;
00849     uint16_t tail = pGmacd->queueList[queIdx].wTxTail;
00850     return GCIRC_CNT(head, tail, pGmacd->queueList[queIdx].wTxListSize);
00851 }
00852 
00853 /**
00854  * \brief Receive a packet with GMAC.
00855  * If not enough buffer for the packet, the remaining data is lost but right
00856  * frame length is returned.
00857  *  \param pGmacd Pointer to GMAC Driver instance. 
00858  *  \param pFrame           Buffer to store the frame
00859  *  \param frameSize        Size of the frame
00860  *  \param pRcvSize         Received size
00861  *  \return                 OK, no data, or frame too small
00862  */
00863 uint8_t GMACD_Poll(sGmacd * pGmacd, 
00864                   uint8_t *pFrame, 
00865                   uint32_t frameSize, 
00866                   uint32_t *pRcvSize,
00867                   gmacQueList_t queIdx)
00868 {
00869 
00870     uint16_t bufferLength;
00871     uint32_t   tmpFrameSize = 0;
00872     uint8_t  *pTmpFrame = 0;
00873     uint32_t   tmpIdx = pGmacd->queueList[queIdx].wRxI;
00874     volatile sGmacRxDescriptor *pRxTd = 
00875         &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; 
00876 
00877     uint8_t isFrame = 0;
00878     
00879     if (pFrame == NULL) return GMACD_PARAM;
00880 
00881     /* Set the default return value */
00882     *pRcvSize = 0;
00883     
00884     /* Process received RxTd */
00885     while ((pRxTd->addr.val & GMAC_RX_OWNERSHIP_BIT) == GMAC_RX_OWNERSHIP_BIT) {
00886         /* A start of frame has been received, discard previous fragments */
00887         if ((pRxTd->status.val & GMAC_RX_SOF_BIT) == GMAC_RX_SOF_BIT) {
00888             /* Skip previous fragment */
00889             while (tmpIdx != pGmacd->queueList[queIdx].wRxI) {
00890                 pRxTd = 
00891                     &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; 
00892                 pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);
00893                 GCIRC_INC(pGmacd->queueList[queIdx].wRxI, 
00894                     pGmacd->queueList[queIdx].wRxListSize);
00895             }
00896             pTmpFrame = pFrame;
00897             tmpFrameSize = 0;
00898             /* Start to gather buffers in a frame */
00899             isFrame = 1;
00900         }
00901         /* Increment the pointer */
00902         GCIRC_INC(tmpIdx, pGmacd->queueList[queIdx].wRxListSize);
00903         
00904         /* Copy data in the frame buffer */
00905         if (isFrame) {
00906             if (tmpIdx == pGmacd->queueList[queIdx].wRxI) {
00907                 TRACE_INFO("no EOF (Invalid of buffers too small)\n\r");
00908                 do {
00909                     pRxTd = 
00910                         &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; 
00911                     pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);
00912                     GCIRC_INC(pGmacd->queueList[queIdx].wRxI, 
00913                         pGmacd->queueList[queIdx].wRxListSize);
00914                 } while(tmpIdx != pGmacd->queueList[queIdx].wRxI);
00915                 return GMACD_RX_NULL;
00916             }
00917 
00918             /* Copy the buffer into the application frame */
00919             bufferLength = pGmacd->queueList[queIdx].wRxBufferSize;
00920             if ((tmpFrameSize + bufferLength) > frameSize) {
00921                 bufferLength = frameSize - tmpFrameSize;
00922             }
00923             memcpy(pTmpFrame, (void*)(pRxTd->addr.val & GMAC_ADDRESS_MASK),
00924                 bufferLength);
00925             pTmpFrame += bufferLength;
00926             tmpFrameSize += bufferLength;
00927 
00928             /* An end of frame has been received, return the data */
00929             if ((pRxTd->status.val & GMAC_RX_EOF_BIT) == GMAC_RX_EOF_BIT)
00930             {
00931                 /* Frame size from the GMAC */
00932                 *pRcvSize = (pRxTd->status.val & GMAC_LENGTH_FRAME);
00933 
00934                 /* Application frame buffer is too small all data have not been
00935                     copied */
00936                 if (tmpFrameSize < *pRcvSize) {
00937                     return GMACD_SIZE_TOO_SMALL;
00938                 }
00939                 TRACE_DEBUG("packet %d-%d (%d)\n\r",
00940                     pGmacd->queueList[queIdx].wRxI, tmpIdx, *pRcvSize);
00941                 /* All data have been copied in the application frame buffer
00942                     => release TD */
00943                 while (pGmacd->queueList[queIdx].wRxI != tmpIdx) {
00944                     pRxTd = 
00945                         &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; 
00946                     pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);
00947                     GCIRC_INC(pGmacd->queueList[queIdx].wRxI, 
00948                         pGmacd->queueList[queIdx].wRxListSize);
00949                 }
00950                 
00951                 GMAC_CACHE_COHERENCE
00952                 return GMACD_OK;
00953             }
00954         } else {
00955             /* SOF has not been detected, skip the fragment */
00956             pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);
00957             pGmacd->queueList[queIdx].wRxI = tmpIdx;
00958             GMAC_CACHE_COHERENCE
00959         }
00960         /* Process the next buffer */
00961         pRxTd = &pGmacd->queueList[queIdx].pRxD[tmpIdx];
00962         GMAC_CACHE_COHERENCE
00963     }
00964     return GMACD_RX_NULL;
00965 }
00966 
00967 /**
00968  * \brief Registers pRxCb callback. Callback will be invoked after the next 
00969  * received frame. When GMAC_Poll() returns GMAC_RX_NO_DATA the application task 
00970  * call GMAC_Set_RxCb() to register pRxCb() callback and enters suspend state. 
00971  * The callback is in charge to resume the task once a new frame has been 
00972  * received. The next time GMAC_Poll() is called, it will be successful.
00973  *  \param pGmacd Pointer to GMAC Driver instance. 
00974  *  \param fRxCb   Pointer to callback function
00975  *  \return        OK, no data, or frame too small
00976  */
00977 
00978 void GMACD_SetRxCallback(sGmacd * pGmacd, fGmacdTransferCallback fRxCb,
00979                         gmacQueList_t queIdx)
00980 {
00981     Gmac *pHw = pGmacd->pHw;
00982     if (fRxCb == NULL) {
00983         GMAC_DisableIt(pHw, GMAC_IDR_RCOMP, queIdx);
00984         pGmacd->queueList[queIdx].fRxCb = NULL;
00985     } else {
00986         pGmacd->queueList[queIdx].fRxCb = fRxCb;
00987         GMAC_EnableIt(pHw, GMAC_IER_RCOMP, queIdx);
00988     }
00989 }
00990 
00991 /**
00992  * Register/Clear TX wakeup callback.
00993  *
00994  * When GMACD_Send() returns GMACD_TX_BUSY (all TD busy) the application 
00995  * task calls GMACD_SetTxWakeupCallback() to register fWakeup() callback and 
00996  * enters suspend state. The callback is in charge to resume the task once 
00997  * several TD have been released. The next time GMACD_Send() will be called,
00998  * it shall be successful.
00999  *
01000  * This function is usually invoked with NULL callback from the TX wakeup
01001  * callback itself, to unregister. Once the callback has resumed the
01002  * application task, there is no need to invoke the callback again.
01003  *
01004  * \param pGmacd   Pointer to GMAC Driver instance.
01005  * \param fWakeup     Wakeup callback.
01006  * \param bThreshold  Number of free TD before wakeup callback invoked.
01007  * \return GMACD_OK, GMACD_PARAM on parameter error.
01008  */
01009 uint8_t GMACD_SetTxWakeupCallback(sGmacd * pGmacd,
01010                                   fGmacdWakeupCallback fWakeup,
01011                                   uint8_t bThreshold,
01012                                   gmacQueList_t queIdx)
01013 {
01014     if (fWakeup == NULL) {
01015         pGmacd->queueList[queIdx].fWakupCb = NULL;
01016     } else {
01017         if (bThreshold <= pGmacd->queueList[queIdx].wTxListSize) {
01018             pGmacd->queueList[queIdx].fWakupCb = fWakeup;
01019             pGmacd->queueList[queIdx].bWakeupThreshold = bThreshold;
01020         } else {
01021             return GMACD_PARAM;
01022         }
01023     }
01024     return GMACD_OK;
01025 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines