SAMV71 Xplained Ultra Software Package 1.5

gmacd.c

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