SAMV71 Xplained Ultra Software Package 1.4

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         /* Exit if frame has not been sent yet:
00207          * On TX completion, the GMAC set the USED bit only into the
00208          * very first buffer descriptor of the sent frame.
00209          * Otherwise it updates this descriptor with status error bits.
00210          * This is the descriptor write back.
00211          */
00212         if ((pTxTd->status.val & GMAC_TX_USED_BIT) == 0)
00213             break;
00214 
00215         /* Process all buffers of the current transmitted frame */
00216         while ((pTxTd->status.val & GMAC_TX_LAST_BUFFER_BIT) == 0) {
00217             GCIRC_INC(pGmacd->queueList[qId].wTxTail, 
00218                     pGmacd->queueList[qId].wTxListSize);
00219             pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];
00220             memory_sync();
00221         }
00222 
00223         /* Notify upper layer that a frame has been sent */
00224         fTxCb = pGmacd->queueList[qId].fTxCbList[pGmacd->queueList[qId].wTxTail];
00225         if (fTxCb)
00226             fTxCb(tsr);
00227 
00228         /* Go to next frame */
00229         GCIRC_INC(pGmacd->queueList[qId].wTxTail, pGmacd->queueList[qId].wTxListSize);
00230     }
00231 
00232     /* If a wakeup has been scheduled, notify upper layer that it can
00233        send other packets, send will be successful. */
00234     if (pGmacd->queueList[qId].fWakupCb &&
00235         GCIRC_SPACE(pGmacd->queueList[qId].wTxHead,
00236                     pGmacd->queueList[qId].wTxTail,
00237                     pGmacd->queueList[qId].wTxListSize) >= 
00238                         pGmacd->queueList[qId].bWakeupThreshold)
00239         pGmacd->queueList[qId].fWakupCb();
00240 }
00241 
00242 
00243 /**
00244  *  \brief Reset TX queue when errors are detected
00245  *  \param pGmacd Pointer to GMAC Driver instance.
00246  */
00247 static void GMACD_TxErrorHandler(sGmacd *pGmacd, gmacQueList_t qId)
00248 {
00249     Gmac                   *pHw = pGmacd->pHw;
00250     sGmacTxDescriptor      *pTxTd;
00251     fGmacdTransferCallback fTxCb;
00252     uint32_t               tsr;
00253 
00254     /* Clear TXEN bit into the Network Configuration Register:
00255      * this is a workaround to recover from TX lockups that 
00256      * occur on sama5d3 gmac (r1p24f2) when using  scatter-gather.
00257      * This issue has never been seen on sama5d4 gmac (r1p31).
00258      */
00259     GMAC_TransmitEnable(pHw, 0);
00260 
00261     /* The following step should be optional since this function is called 
00262      * directly by the IRQ handler. Indeed, according to Cadence 
00263      * documentation, the transmission is halted on errors such as
00264      * too many retries or transmit under run.
00265      * However it would become mandatory if the call of this function
00266      * were scheduled as a task by the IRQ handler (this is how Linux 
00267      * driver works). Then this function might compete with GMACD_Send().
00268      *
00269      * Setting bit 10, tx_halt, of the Network Control Register is not enough:
00270      * We should wait for bit 3, tx_go, of the Transmit Status Register to 
00271      * be cleared at transmit completion if a frame is being transmitted.
00272      */
00273     GMAC_TransmissionHalt(pHw);
00274     while (GMAC_GetTxStatus(pHw) & GMAC_TSR_TXGO);
00275 
00276     /* Treat frames in TX queue including the ones that caused the error. */
00277     while (!GCIRC_EMPTY(pGmacd->queueList[qId].wTxHead, 
00278             pGmacd->queueList[qId].wTxTail)) {
00279         int tx_completed = 0;
00280         pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];
00281 
00282         /* Check USED bit on the very first buffer descriptor to validate
00283          * TX completion.
00284          */
00285         if (pTxTd->status.val & GMAC_TX_USED_BIT)
00286             tx_completed = 1;
00287 
00288         /* Go to the last buffer descriptor of the frame */
00289         while ((pTxTd->status.val & GMAC_TX_LAST_BUFFER_BIT) == 0) {
00290             GCIRC_INC(pGmacd->queueList[qId].wTxTail, 
00291                     pGmacd->queueList[qId].wTxListSize);
00292             pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];
00293         }
00294 
00295         /* Notify upper layer that a frame status */
00296         fTxCb = pGmacd->queueList[qId].fTxCbList[pGmacd->queueList[qId].wTxTail];
00297         if (fTxCb)
00298             fTxCb(tx_completed ? GMAC_TSR_TXCOMP : 0); 
00299         // TODO: which error to notify?
00300 
00301         /* Go to next frame */
00302         GCIRC_INC(pGmacd->queueList[qId].wTxTail, pGmacd->queueList[qId].wTxListSize);
00303     }    
00304 
00305     /* Reset TX queue */
00306     GMACD_ResetTx(pGmacd, qId);
00307     
00308     /* Clear status */
00309     tsr = GMAC_GetTxStatus(pHw);
00310     GMAC_ClearTxStatus(pHw, tsr);
00311 
00312     /* Now we are ready to start transmission again */
00313     GMAC_TransmitEnable(pHw, 1);
00314     if (pGmacd->queueList[qId].fWakupCb)
00315         pGmacd->queueList[qId].fWakupCb();
00316 }
00317 
00318  
00319 /*---------------------------------------------------------------------------
00320  *         Exported functions
00321  *---------------------------------------------------------------------------*/
00322 
00323 
00324 #ifndef PTP_1588_TX_DISABLE  
00325 
00326 void GMACD_TxPtpEvtMsgCBRegister (sGmacd * pGmacd, 
00327         fGmacdTxPtpEvtCallBack pTxPtpEvtCb, gmacQueList_t queIdx)  
00328 {  
00329   pGmacd->queueList[queIdx].fTxPtpEvtCb = pTxPtpEvtCb;
00330 } 
00331 
00332 #endif   /* #ifdef PTP_1588_TX_DISABLE */  
00333  
00334 /**
00335  *  \brief GMAC Interrupt handler
00336  *  \param pGmacd Pointer to GMAC Driver instance.
00337  */
00338 void GMACD_Handler(sGmacd *pGmacd, gmacQueList_t queIdx)
00339 {
00340     Gmac *pHw = pGmacd->pHw;
00341     uint32_t isr;
00342     uint32_t rsr;
00343     
00344     /* Interrupt Status Register is cleared on read */
00345     while ( (isr = GMAC_GetItStatus(pHw, queIdx)) !=0) {
00346         /*  Sync Frame Received - PTP */
00347         if(0u != (isr & GMAC_ISR_SFR)) {
00348             rsr = GMAC_ISR_SFR;
00349             memory_barrier();
00350             /* Invoke callbacks */
00351             if (pGmacd->queueList[queIdx].fRxCb) {
00352                 pGmacd->queueList[queIdx].fRxCb(rsr);
00353             } else {
00354             }
00355         } else {
00356         }
00357         
00358         /* Peer Delay Request Frame Received - PTP */
00359         if (0u != (isr & GMAC_ISR_PDRQFR) ) {
00360             rsr = GMAC_ISR_PDRQFR;
00361             memory_barrier();
00362             
00363             /* Invoke callbacks */
00364             if (pGmacd->queueList[queIdx].fRxCb) {
00365                 pGmacd->queueList[queIdx].fRxCb(rsr);
00366             } else {
00367             }
00368         } else {
00369         }
00370 
00371         /* Peer Delay Response Frame Received - PTP */
00372         if (0u != (isr & GMAC_ISR_PDRSFR) ) {
00373             
00374             rsr = GMAC_ISR_PDRSFR;
00375             memory_barrier();
00376             
00377             /* Invoke callbacks */
00378             if (pGmacd->queueList[queIdx].fRxCb) {
00379                 pGmacd->queueList[queIdx].fRxCb(rsr);
00380             } else {
00381             }
00382         } else {
00383         }
00384     
00385         if( 0u != (isr & GMAC_ISR_TSU)) {
00386             /* Invoke call back with flag set to TSU comparison interrupt */
00387             rsr = GMAC_ISR_TSU;
00388             memory_barrier();
00389         
00390             /* Invoke callbacks */
00391             if (pGmacd->queueList[queIdx].fRxCb) { 
00392                 pGmacd->queueList[queIdx].fRxCb(rsr);
00393             } else {
00394             }
00395         } else {
00396         }
00397         
00398         /* RX packet */
00399         if (isr & GMAC_INT_RX_STATUS_BITS) {
00400             /* Clear status */
00401             rsr = GMAC_GetRxStatus(pHw);
00402             GMAC_ClearRxStatus(pHw, rsr);
00403 
00404             /* Invoke callback */
00405             if (pGmacd->queueList[queIdx].fRxCb)
00406                 pGmacd->queueList[queIdx].fRxCb(rsr);
00407         }
00408 
00409         /* TX error */
00410         if (isr & GMAC_INT_TX_STATUS_ERR_BITS) {
00411             GMACD_TxErrorHandler(pGmacd, queIdx);
00412             break;
00413         }
00414     
00415 #ifndef PTP_1588_TX_DISABLE
00416             /* Transmit of SYNC / PDELAY_REQ / PDELAY_RSP */    
00417             if(0u != (isr & isrMasks[gPtpMsgTxQue[ptpTxQueReadIdx]])) {
00418             /* Invoke callback */
00419             /*  Check if it is possible for multiple messages to be triggered 
00420             within a single isr. If so, a loop may be needed to validate the top
00421             of the queue with the actual interrupt that has been triggered */
00422 /* while(0u != (isr & (GMAC_IMR_SFT | GMAC_IMR_PDRQFT | GMAC_IMR_PDRSFT))) { */
00423             if (pGmacd->queueList[queIdx].fTxPtpEvtCb) {
00424                 switch (gPtpMsgTxQue[ptpTxQueReadIdx]) {
00425                 case SYNC_MSG_TYPE:
00426                     pGmacd->queueList[queIdx].fTxPtpEvtCb 
00427                                     (gPtpMsgTxQue[ptpTxQueReadIdx], 
00428                                     GMAC_GetTxEvtFrameSec(pHw), 
00429                                     GMAC_GetTxEvtFrameNsec(pHw), 
00430                                     gPtpMsgTxSeqId[ptpTxQueReadIdx]);
00431                     isr &= GMAC_IMR_SFT;
00432                     break;
00433                 case PDELAY_REQ_TYPE:
00434                     pGmacd->queueList[queIdx].fTxPtpEvtCb 
00435                                     (gPtpMsgTxQue[ptpTxQueReadIdx], 
00436                                     GMAC_GetTxPeerEvtFrameSec(pHw), 
00437                                     GMAC_GetTxPeerEvtFrameNsec(pHw), 
00438                                     gPtpMsgTxSeqId[ptpTxQueReadIdx]);
00439                     isr &= GMAC_IMR_PDRQFT;
00440                     break;
00441                 case PDELAY_RESP_TYPE:
00442                     pGmacd->queueList[queIdx].fTxPtpEvtCb 
00443                                     (gPtpMsgTxQue[ptpTxQueReadIdx], 
00444                                     GMAC_GetTxPeerEvtFrameSec(pHw), 
00445                                     GMAC_GetTxPeerEvtFrameNsec(pHw), 
00446                                     gPtpMsgTxSeqId[ptpTxQueReadIdx]);
00447                     isr &= GMAC_IMR_PDRSFT;
00448                     break;
00449                 default:
00450                     /* Only for Peer messages & sync messages */
00451                     break;
00452                 };
00453         } else {
00454         }
00455 
00456             ptpTxQueReadIdx++;
00457             ptpTxQueReadIdx &= (EFRS_BUFFER_LEN-1);
00458             
00459             } else { 
00460                 /* if(0u != (isr & isrMasks[gPtpMsgTxQue[ptpTxQueReadIdx]])) */
00461             }
00462 #endif /* #ifndef PTP_1588_TX_DISABLE */
00463         /* TX packet */
00464         if (isr & GMAC_IER_TCOMP)
00465             GMACD_TxCompleteHandler(pGmacd, queIdx);
00466         if (isr & GMAC_IER_HRESP) {
00467             TRACE_ERROR("HRESP\n\r");
00468         }
00469     }
00470 }
00471 
00472 
00473 /**
00474  * \brief Initialize the GMAC with the Gmac controller address
00475  *  \param pGmacd Pointer to GMAC Driver instance. 
00476  *  \param pHw    Pointer to HW address for registers.
00477  *  \param bID     HW ID for power management
00478  *  \param enableCAF    Enable/Disable CopyAllFrame.
00479  *  \param enableNBC    Enable/Disable NoBroadCast.
00480  */
00481  void GMACD_Init(sGmacd *pGmacd,
00482                 Gmac *pHw,
00483                 uint8_t bID, 
00484                 uint8_t enableCAF, 
00485                 uint8_t enableNBC )
00486 {
00487     uint32_t dwNcfgr;
00488     
00489     /* Check parameters */
00490 //    assert(GRX_BUFFERS * GMAC_RX_UNITSIZE > GMAC_FRAME_LENTGH_MAX);
00491 
00492     TRACE_DEBUG("GMAC_Init\n\r");
00493 
00494     /* Initialize struct */
00495     pGmacd->pHw = pHw;
00496     pGmacd->bId = bID;
00497 
00498     /* Power ON */
00499     PMC_EnablePeripheral(bID);
00500 
00501     /* Disable TX & RX and more */
00502     GMAC_NetworkControl(pHw, 0);
00503     GMAC_DisableAllQueueIt(pHw, ~0u);
00504     
00505     GMAC_ClearStatistics(pHw);
00506     /* Clear all status bits in the receive status register. */
00507     GMAC_ClearRxStatus(pHw, GMAC_RSR_RXOVR | GMAC_RSR_REC 
00508                     | GMAC_RSR_BNA |GMAC_RSR_HNO);
00509 
00510     /* Clear all status bits in the transmit status register */
00511     GMAC_ClearTxStatus(pHw, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE
00512                             | GMAC_TSR_TXGO | GMAC_TSR_TFC | GMAC_TSR_TXCOMP
00513                             | GMAC_TSR_HRESP );
00514 
00515     /* Clear All interrupts */
00516     GMAC_GetItStatus(pHw, GMAC_QUE_0);
00517     GMAC_GetItStatus(pHw, GMAC_QUE_1);
00518     GMAC_GetItStatus(pHw, GMAC_QUE_2);
00519 
00520     /* Enable the copy of data into the buffers
00521        ignore broadcasts, and don't copy FCS. */
00522     dwNcfgr = GMAC_NCFGR_FD | GMAC_NCFGR_DBW(0) | GMAC_NCFGR_CLK_MCK_64 |
00523               GMAC_NCFGR_MAXFS | GMAC_NCFGR_PEN | GMAC_NCFGR_RFCS;
00524     if( enableCAF ) {
00525         dwNcfgr |= GMAC_NCFGR_CAF;
00526     }
00527     if( enableNBC ) {
00528         dwNcfgr |= GMAC_NCFGR_NBC;
00529     }
00530     
00531     GMAC_Configure(pHw, dwNcfgr);
00532 }
00533 
00534 
00535 /**
00536  * Initialize necessary allocated buffer lists for GMAC Driver to transfer data.
00537  * Must be invoked after GMACD_Init() but before RX/TX start.
00538  * Replace the deprecated GMACD_InitTransfer().
00539  * \param pGmacd Pointer to GMAC Driver instance.
00540  * \param pInit  Pointer to sGmacInit.
00541  * \param pInit  Pointer to gmacQueList_t for different queue.
00542  * \return GMACD_OK or GMACD_PARAM.
00543  * \note If input address is not 8-byte aligned the address is automatically
00544  *       adjusted and the list size is reduced by one.
00545  */
00546 uint8_t GMACD_InitTransfer(sGmacd *pGmacd, const sGmacInit *pInit, 
00547                             gmacQueList_t queIdx)
00548 {
00549     Gmac *pHw = pGmacd->pHw;
00550     uint8_t *pRxBuffer = pInit->pRxBuffer;
00551     sGmacRxDescriptor *pRxD = pInit->pRxD;
00552     uint16_t wRxBufferSize = pInit->wRxBufferSize;
00553     uint16_t wRxSize = pInit->wRxSize;
00554     uint8_t *pTxBuffer = pInit->pTxBuffer;
00555     sGmacTxDescriptor *pTxD = pInit->pTxD;
00556     uint16_t wTxBufferSize = pInit->wTxBufferSize;
00557     uint16_t wTxSize = pInit->wTxSize;
00558     fGmacdTransferCallback *pTxCb = pInit->pTxCb;
00559     uint32_t dwDmaCfg;
00560     if (wRxSize <= 1 || wTxSize <= 1 || pTxCb == NULL) return GMACD_PARAM;
00561 
00562     if (!wRxBufferSize || wRxBufferSize > 16*1024 || wRxBufferSize & 0x3f)
00563         return GMACD_PARAM;
00564 
00565     if (!wTxBufferSize)
00566         return GMACD_PARAM;
00567 
00568     if (pInit->bIsGem) {
00569         if(!queIdx) {
00570             dwDmaCfg = (GMAC_DCFGR_DRBS(wRxBufferSize >> 6) ) 
00571                 | GMAC_DCFGR_RXBMS(3) | GMAC_DCFGR_TXPBMS;
00572             switch (pInit->bDmaBurstLength) {
00573             case 16:
00574                 dwDmaCfg |= GMAC_DCFGR_FBLDO_INCR16;
00575                 break;
00576             case 8:
00577                 dwDmaCfg |= GMAC_DCFGR_FBLDO_INCR8;
00578                 break;
00579             case 4:
00580                 dwDmaCfg |= GMAC_DCFGR_FBLDO_INCR4;
00581                 break;
00582             case 1:
00583                 dwDmaCfg |= GMAC_DCFGR_FBLDO_SINGLE;
00584                 break;
00585             default:
00586                 return GMACD_PARAM;
00587                 break;
00588             }
00589         } else {
00590             dwDmaCfg = (GMAC_RBSRPQ_RBS(wRxBufferSize >> 6) );
00591         }
00592         GMAC_SetDMAConfig(pHw, dwDmaCfg, queIdx);
00593     }
00594 
00595     pGmacd->queueList[queIdx].wRxBufferSize = wRxBufferSize;
00596     pGmacd->queueList[queIdx].wTxBufferSize = wTxBufferSize;
00597     /* Assign RX buffers */
00598     if (((uint32_t)pRxBuffer & 0x7)
00599         || ((uint32_t)pRxD & 0x7) ) {
00600         wRxSize --;
00601         TRACE_DEBUG("RX list address adjusted\n\r");
00602     }
00603     pGmacd->queueList[queIdx].pRxBuffer = (uint8_t*)((uint32_t)pRxBuffer & 0xFFFFFFF8);
00604     pGmacd->queueList[queIdx].pRxD = (sGmacRxDescriptor*)((uint32_t)pRxD & 0xFFFFFFF8);
00605     pGmacd->queueList[queIdx].wRxListSize = wRxSize;
00606 
00607     /* Assign TX buffers */
00608     if (   ((uint32_t)pTxBuffer & 0x7)
00609         || ((uint32_t)pTxD & 0x7) ) {
00610         wTxSize --;
00611         TRACE_DEBUG("TX list address adjusted\n\r");
00612     }
00613     pGmacd->queueList[queIdx].pTxBuffer = (uint8_t*)((uint32_t)pTxBuffer & 0xFFFFFFF8);
00614     pGmacd->queueList[queIdx].pTxD = (sGmacTxDescriptor*)((uint32_t)pTxD & 0xFFFFFFF8);
00615     pGmacd->queueList[queIdx].wTxListSize = wTxSize;
00616     pGmacd->queueList[queIdx].fTxCbList = pTxCb;
00617 
00618     /* Reset TX & RX */
00619     GMACD_ResetRx(pGmacd, queIdx);
00620     GMACD_ResetTx(pGmacd, queIdx);
00621 
00622    /* Setup the interrupts for RX/TX completion (and errors) */
00623     switch(queIdx) {
00624     case GMAC_QUE_0:
00625         /* YBP: Que 0 should be configured last so as to enable transmit and
00626         Receive in the NCR register */
00627         
00628         /* Enable Rx and Tx, plus the status register. */
00629         GMAC_TransmitEnable(pHw, 1);
00630         GMAC_ReceiveEnable(pHw, 1);
00631         GMAC_StatisticsWriteEnable(pHw, 1);
00632 
00633         GMAC_EnableIt(pHw,
00634                   GMAC_INT_RX_BITS |
00635                   GMAC_INT_TX_BITS |
00636                   GMAC_INT_TX_ERR_BITS, GMAC_QUE_0);
00637         break;
00638         
00639     case GMAC_QUE_1:
00640         GMAC_EnableIt(pHw,
00641                   GMAC_INT_RX_BITS |
00642                   GMAC_INT_TX_BITS |
00643                   GMAC_INT_TX_ERR_BITS, GMAC_QUE_1);
00644         break;
00645     case GMAC_QUE_2:
00646           GMAC_EnableIt(pHw,
00647                   GMAC_INT_RX_BITS |
00648                   GMAC_INT_TX_BITS |
00649                   GMAC_INT_TX_ERR_BITS, GMAC_QUE_2);
00650         break;
00651     };
00652     return GMACD_OK;
00653 }
00654 
00655 
00656 /**
00657  * Reset TX & RX queue & statistics
00658  * \param pGmacd Pointer to GMAC Driver instance.
00659  */
00660 void GMACD_Reset(sGmacd *pGmacd)
00661 {
00662     Gmac *pHw = pGmacd->pHw;
00663 
00664     GMACD_ResetRx(pGmacd, GMAC_QUE_0);
00665     GMACD_ResetRx(pGmacd, GMAC_QUE_1);
00666     GMACD_ResetRx(pGmacd, GMAC_QUE_2);
00667     
00668     GMACD_ResetTx(pGmacd, GMAC_QUE_0);
00669     GMACD_ResetTx(pGmacd, GMAC_QUE_1);
00670     GMACD_ResetTx(pGmacd, GMAC_QUE_2);
00671     
00672     //memset((void*)&GmacStatistics, 0x00, sizeof(GmacStats));
00673     GMAC_NetworkControl(pHw, GMAC_NCR_TXEN | GMAC_NCR_RXEN
00674                              | GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);
00675 }
00676 
00677 /**
00678  * \brief Send a frame split into buffers. If the frame size is larger than 
00679  * transfer buffer size error returned. If frame transfer status is monitored, 
00680  * specify callback for each frame.
00681  *  \param pGmacd Pointer to GMAC Driver instance. 
00682  *  \param sgl Pointer to a scatter-gather list describing the buffers of the 
00683  * ethernet frame.
00684  *  \param fTxCb Pointer to callback function.
00685  */
00686 uint8_t GMACD_SendSG(sGmacd *pGmacd,
00687                      const sGmacSGList *sgl,
00688                      fGmacdTransferCallback fTxCb,
00689                      gmacQueList_t queIdx)
00690 {
00691     Gmac *pHw = pGmacd->pHw;
00692     sGmacTxDescriptor *pTd = pGmacd->queueList[queIdx].pTxD;
00693     sGmacTxDescriptor *pTxTd;
00694     uint16_t wTxPos, wTxHead;
00695     int i;
00696 
00697     TRACE_DEBUG("%s\n\r", __FUNCTION__);
00698 
00699     /* Check parameter */
00700     if (!sgl->len) {
00701         TRACE_ERROR("%s:: ethernet frame is empty.\r\n", __FUNCTION__);
00702         return GMACD_PARAM;
00703     }
00704     if (sgl->len >= pGmacd->queueList[queIdx].wTxListSize) {
00705         TRACE_ERROR("%s: ethernet frame has too many buffers.\r\n", __FUNCTION__);
00706         return GMACD_PARAM;
00707     }
00708     /* Check available space */
00709     if (GCIRC_SPACE(pGmacd->queueList[queIdx].wTxHead, 
00710             pGmacd->queueList[queIdx].wTxTail,
00711             pGmacd->queueList[queIdx].wTxListSize) < (int)sgl->len)
00712         return GMACD_TX_BUSY;
00713 
00714     /* Tag end of TX queue */
00715     wTxHead = fixed_mod(pGmacd->queueList[queIdx].wTxHead + sgl->len, 
00716             pGmacd->queueList[queIdx].wTxListSize);
00717     wTxPos = wTxHead;
00718     pGmacd->queueList[queIdx].fTxCbList[wTxPos] = NULL;
00719     pTxTd = &pTd[wTxPos];
00720     pTxTd->status.val = GMAC_TX_USED_BIT;
00721     /* Update buffer descriptors in reverse order to avoid a race 
00722      * condition with hardware.
00723      */
00724     for (i = (int)(sgl->len-1); i >= 0; --i) {
00725         const sGmacSG *sg = &sgl->sg[i];
00726         uint32_t status;
00727 
00728         if (sg->size > pGmacd->queueList[queIdx].wTxBufferSize) {
00729             TRACE_ERROR("%s: buffer size is too big.\r\n", __FUNCTION__);
00730             return GMACD_PARAM;
00731         }
00732 
00733         if (wTxPos == 0)
00734             wTxPos = pGmacd->queueList[queIdx].wTxListSize-1;
00735         else
00736             wTxPos--;
00737 
00738         /* Reset TX callback */
00739         pGmacd->queueList[queIdx].fTxCbList[wTxPos] = NULL;
00740 
00741         pTxTd = &pTd[wTxPos];
00742 #ifdef GMAC_ZERO_COPY
00743         /** Update buffer descriptor address word:
00744          *  MUST be done before status word to avoid a race condition.
00745          */
00746         pTxTd->addr = (uint32_t)sg->pBuffer;
00747         
00748 #else
00749         /* Copy data into transmission buffer */
00750         if (sg->pBuffer && sg->size){
00751             memcpy((void *)pTxTd->addr, sg->pBuffer, sg->size); 
00752             SCB_CleanDCache_by_Addr((void *)pTxTd->addr,sg->size);
00753          }
00754 #endif
00755 
00756         /* Compute buffer descriptor status word */
00757         status = sg->size & GMAC_LENGTH_FRAME;
00758         if (i == (int)(sgl->len-1)) {
00759             status |= GMAC_TX_LAST_BUFFER_BIT;
00760             pGmacd->queueList[queIdx].fTxCbList[wTxPos] = fTxCb;
00761         }
00762         if (wTxPos == pGmacd->queueList[queIdx].wTxListSize-1)
00763             status |= GMAC_TX_WRAP_BIT;
00764 
00765         /* Update buffer descriptor status word: clear USED bit */
00766         pTxTd->status.val = status;
00767 
00768         memory_sync();
00769     }
00770 
00771     /* Update TX ring buffer pointers */
00772     pGmacd->queueList[queIdx].wTxHead = wTxHead;
00773     /* Now start to transmit if it is not already done */
00774     
00775     GMAC_TransmissionStart(pHw);
00776     return GMACD_OK;
00777 }
00778 
00779 /**
00780  * \brief Send a packet with GMAC. If the packet size is larger than transfer 
00781  * buffer size error returned. If packet transfer status is monitored, specify
00782  * callback for each packet.
00783  *  \param pGmacd Pointer to GMAC Driver instance. 
00784  *  \param pBuffer   The buffer to be send
00785  *  \param size     The size of buffer to be send
00786  *  \param fTxCb Threshold Wakeup callback
00787  *  \return         OK, Busy or invalid packet
00788  */
00789 uint8_t GMACD_Send(sGmacd *pGmacd,
00790                    void *pBuffer,
00791                    uint32_t size,
00792                    fGmacdTransferCallback fTxCb,
00793                    gmacQueList_t queIdx)
00794 {
00795     sGmacSGList sgl;
00796     sGmacSG sg;
00797     
00798     uint8_t *msgPtr;
00799     ptpMsgType ptpMsg;
00800     /* Init single entry scatter-gather list */
00801     sg.size = size;
00802     sg.pBuffer = pBuffer;
00803     sgl.len = 1;
00804     sgl.sg = &sg;
00805 
00806 
00807     
00808 #ifndef PTP_1588_TX_DISABLE
00809 
00810     msgPtr = (uint8_t *)pBuffer;
00811     if(0x88u == msgPtr[12] && 0xf7u == msgPtr[13]) {
00812         /* Extract Tx PTP message  type */
00813         ptpMsg = (ptpMsgType)(msgPtr[14] & 0x0F);
00814         if (ptpMsg == SYNC_MSG_TYPE || ptpMsg == PDELAY_REQ_TYPE 
00815             || ptpMsg == PDELAY_RESP_TYPE) {
00816             /* Only add message to Tx queue of msg types that have 
00817                 tx event ISRs enabled. */
00818             gPtpMsgTxQue[ptpTxQueWriteIdx] = ptpMsg;
00819             
00820             /* Copy the Sequence Id */
00821             gPtpMsgTxSeqId[ptpTxQueWriteIdx] = 
00822                 (uint16_t)(((uint16_t)msgPtr[44] << 8) | msgPtr[45]);
00823             ptpTxQueWriteIdx++;
00824             ptpTxQueWriteIdx &= (EFRS_BUFFER_LEN-1u);
00825         } else { 
00826                 /* if (ptpMsg == SYNC_MSG_TYPE || ptpMsg == PDELAY_REQ_TYPE\
00827                 || ptpMsg == PDELAY_RESP_TYPE) { */
00828         }
00829     } else { /* if(0x88 == msgPtr[12] && 0xf7 == msgPtr[13]) { */
00830     }  
00831 #endif /* #ifndef PTP_1588_TX_DISABLE */
00832     return GMACD_SendSG(pGmacd, &sgl, fTxCb, queIdx);
00833 }
00834 
00835 /**
00836  * Return current load of TX.
00837  * \param pGmacd   Pointer to GMAC Driver instance.
00838  */
00839 uint32_t GMACD_TxLoad(sGmacd *pGmacd, gmacQueList_t queIdx)
00840 {
00841     uint16_t head = pGmacd->queueList[queIdx].wTxHead;
00842     uint16_t tail = pGmacd->queueList[queIdx].wTxTail;
00843     return GCIRC_CNT(head, tail, pGmacd->queueList[queIdx].wTxListSize);
00844 }
00845 
00846 /**
00847  * \brief Receive a packet with GMAC.
00848  * If not enough buffer for the packet, the remaining data is lost but right
00849  * frame length is returned.
00850  *  \param pGmacd Pointer to GMAC Driver instance. 
00851  *  \param pFrame           Buffer to store the frame
00852  *  \param frameSize        Size of the frame
00853  *  \param pRcvSize         Received size
00854  *  \return                 OK, no data, or frame too small
00855  */
00856 uint8_t GMACD_Poll(sGmacd * pGmacd, 
00857                   uint8_t *pFrame, 
00858                   uint32_t frameSize, 
00859                   uint32_t *pRcvSize,
00860                   gmacQueList_t queIdx)
00861 {
00862 
00863     uint16_t bufferLength;
00864     uint32_t   tmpFrameSize = 0;
00865     uint8_t  *pTmpFrame = 0;
00866     uint32_t   tmpIdx = pGmacd->queueList[queIdx].wRxI;
00867     volatile sGmacRxDescriptor *pRxTd = 
00868         &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; 
00869 
00870     uint8_t isFrame = 0;
00871     
00872     if (pFrame == NULL) return GMACD_PARAM;
00873 
00874     /* Set the default return value */
00875     *pRcvSize = 0;
00876     
00877     /* Process received RxTd */
00878     while ((pRxTd->addr.val & GMAC_RX_OWNERSHIP_BIT) == GMAC_RX_OWNERSHIP_BIT) {
00879         /* A start of frame has been received, discard previous fragments */
00880         if ((pRxTd->status.val & GMAC_RX_SOF_BIT) == GMAC_RX_SOF_BIT) {
00881             /* Skip previous fragment */
00882             while (tmpIdx != pGmacd->queueList[queIdx].wRxI) {
00883                 pRxTd = 
00884                     &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; 
00885                 pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);
00886                 GCIRC_INC(pGmacd->queueList[queIdx].wRxI, 
00887                     pGmacd->queueList[queIdx].wRxListSize);
00888             }
00889             pTmpFrame = pFrame;
00890             tmpFrameSize = 0;
00891             /* Start to gather buffers in a frame */
00892             isFrame = 1;
00893         }
00894         /* Increment the pointer */
00895         GCIRC_INC(tmpIdx, pGmacd->queueList[queIdx].wRxListSize);
00896         
00897         /* Copy data in the frame buffer */
00898         if (isFrame) {
00899             if (tmpIdx == pGmacd->queueList[queIdx].wRxI) {
00900                 TRACE_INFO("no EOF (Invalid of buffers too small)\n\r");
00901                 do {
00902                     pRxTd = 
00903                         &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; 
00904                     pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);
00905                     GCIRC_INC(pGmacd->queueList[queIdx].wRxI, 
00906                         pGmacd->queueList[queIdx].wRxListSize);
00907                 } while(tmpIdx != pGmacd->queueList[queIdx].wRxI);
00908                 return GMACD_RX_NULL;
00909             }
00910 
00911             /* Copy the buffer into the application frame */
00912             bufferLength = pGmacd->queueList[queIdx].wRxBufferSize;
00913             if ((tmpFrameSize + bufferLength) > frameSize) {
00914                 bufferLength = frameSize - tmpFrameSize;
00915             }
00916             SCB_InvalidateDCache_by_Addr((void*)(pRxTd->addr.val & GMAC_ADDRESS_MASK) ,bufferLength );
00917             memcpy(pTmpFrame, (void*)(pRxTd->addr.val & GMAC_ADDRESS_MASK),
00918                 bufferLength);
00919             pTmpFrame += bufferLength;
00920             tmpFrameSize += bufferLength;
00921 
00922             /* An end of frame has been received, return the data */
00923             if ((pRxTd->status.val & GMAC_RX_EOF_BIT) == GMAC_RX_EOF_BIT)
00924             {
00925                 /* Frame size from the GMAC */
00926                 *pRcvSize = (pRxTd->status.val & GMAC_LENGTH_FRAME);
00927 
00928                 /* Application frame buffer is too small all data have not been
00929                     copied */
00930                 if (tmpFrameSize < *pRcvSize) {
00931                     return GMACD_SIZE_TOO_SMALL;
00932                 }
00933                 TRACE_DEBUG("packet %d-%d (%d)\n\r",
00934                     pGmacd->queueList[queIdx].wRxI, tmpIdx, *pRcvSize);
00935                 /* All data have been copied in the application frame buffer
00936                     => release TD */
00937                 while (pGmacd->queueList[queIdx].wRxI != tmpIdx) {
00938                     pRxTd = 
00939                         &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; 
00940                     pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);
00941                     GCIRC_INC(pGmacd->queueList[queIdx].wRxI, 
00942                         pGmacd->queueList[queIdx].wRxListSize);
00943                 }
00944                 
00945                 return GMACD_OK;
00946             }
00947         } else {
00948             /* SOF has not been detected, skip the fragment */
00949             pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);
00950             pGmacd->queueList[queIdx].wRxI = tmpIdx;
00951         }
00952         /* Process the next buffer */
00953         pRxTd = &pGmacd->queueList[queIdx].pRxD[tmpIdx];
00954     }
00955     return GMACD_RX_NULL;
00956 }
00957 
00958 /**
00959  * \brief Registers pRxCb callback. Callback will be invoked after the next 
00960  * received frame. When GMAC_Poll() returns GMAC_RX_NO_DATA the application task 
00961  * call GMAC_Set_RxCb() to register pRxCb() callback and enters suspend state. 
00962  * The callback is in charge to resume the task once a new frame has been 
00963  * received. The next time GMAC_Poll() is called, it will be successful.
00964  *  \param pGmacd Pointer to GMAC Driver instance. 
00965  *  \param fRxCb   Pointer to callback function
00966  *  \return        OK, no data, or frame too small
00967  */
00968 
00969 void GMACD_SetRxCallback(sGmacd * pGmacd, fGmacdTransferCallback fRxCb,
00970                         gmacQueList_t queIdx)
00971 {
00972     Gmac *pHw = pGmacd->pHw;
00973     if (fRxCb == NULL) {
00974         GMAC_DisableIt(pHw, GMAC_IDR_RCOMP, queIdx);
00975         pGmacd->queueList[queIdx].fRxCb = NULL;
00976     } else {
00977         pGmacd->queueList[queIdx].fRxCb = fRxCb;
00978         GMAC_EnableIt(pHw, GMAC_IER_RCOMP, queIdx);
00979     }
00980 }
00981 
00982 /**
00983  * Register/Clear TX wakeup callback.
00984  *
00985  * When GMACD_Send() returns GMACD_TX_BUSY (all TD busy) the application 
00986  * task calls GMACD_SetTxWakeupCallback() to register fWakeup() callback and 
00987  * enters suspend state. The callback is in charge to resume the task once 
00988  * several TD have been released. The next time GMACD_Send() will be called,
00989  * it shall be successful.
00990  *
00991  * This function is usually invoked with NULL callback from the TX wakeup
00992  * callback itself, to unregister. Once the callback has resumed the
00993  * application task, there is no need to invoke the callback again.
00994  *
00995  * \param pGmacd   Pointer to GMAC Driver instance.
00996  * \param fWakeup     Wakeup callback.
00997  * \param bThreshold  Number of free TD before wakeup callback invoked.
00998  * \return GMACD_OK, GMACD_PARAM on parameter error.
00999  */
01000 uint8_t GMACD_SetTxWakeupCallback(sGmacd * pGmacd,
01001                                   fGmacdWakeupCallback fWakeup,
01002                                   uint8_t bThreshold,
01003                                   gmacQueList_t queIdx)
01004 {
01005     if (fWakeup == NULL) {
01006         pGmacd->queueList[queIdx].fWakupCb = NULL;
01007     } else {
01008         if (bThreshold <= pGmacd->queueList[queIdx].wTxListSize) {
01009             pGmacd->queueList[queIdx].fWakupCb = fWakeup;
01010             pGmacd->queueList[queIdx].bWakeupThreshold = bThreshold;
01011         } else {
01012             return GMACD_PARAM;
01013         }
01014     }
01015     return GMACD_OK;
01016 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines