]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A5_SAMA5D4x_EK_IAR/AtmelFiles/libboard_sama5d4x-ek/source/gmacd.c
Core kernel files:
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D4x_EK_IAR / AtmelFiles / libboard_sama5d4x-ek / source / gmacd.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License \r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2012, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29  /** \file */\r
30 \r
31 /*---------------------------------------------------------------------------\r
32  *         Headers\r
33  *---------------------------------------------------------------------------*/\r
34 \r
35 #include <board.h>\r
36 #include <string.h>\r
37 \r
38 /** \addtogroup gmacd_defines\r
39     @{*/\r
40 \r
41 \r
42 /*----------------------------------------------------------------------------\r
43  *        Macro\r
44  *----------------------------------------------------------------------------*/\r
45 /** Return count in buffer */\r
46 #define GCIRC_CNT(head,tail,size) (((head) - (tail)) % (size))\r
47 \r
48 /** Return space available, 0..size-1. always leave one free char as a completely full buffer \r
49     has head == tail, which is the same as empty */\r
50 #define GCIRC_SPACE(head,tail,size) GCIRC_CNT((tail),((head)+1),(size))\r
51 \r
52 /** Return count up to the end of the buffer. Carefully avoid accessing head and tail more than once,\r
53     so they can change underneath us without returning inconsistent results */\r
54 #define GCIRC_CNT_TO_END(head,tail,size) \\r
55      ({int end = (size) - (tail); \\r
56      int n = ((head) + end) % (size); \\r
57      n < end ? n : end;})\r
58 \r
59 /** Return space available up to the end of the buffer */\r
60 #define GCIRC_SPACE_TO_END(head,tail,size) \\r
61    ({int end = (size) - 1 - (head); \\r
62      int n = (end + (tail)) % (size); \\r
63      n <= end ? n : end+1;})\r
64 \r
65 /** Increment head or tail */\r
66 #define GCIRC_INC(headortail,size) \\r
67        headortail++;             \\r
68         if(headortail >= size) {  \\r
69             headortail = 0;       \\r
70         }\r
71 \r
72 /** Circular buffer is empty ? */\r
73 #define GCIRC_EMPTY(head, tail)     (head == tail)\r
74 \r
75 /** Clear circular buffer */\r
76 #define GCIRC_CLEAR(head, tail)  (head = tail = 0)\r
77 \r
78 //------------------------------------------------------------------------------\r
79 //         Definitions\r
80 //------------------------------------------------------------------------------\r
81 /// The buffer addresses written into the descriptors must be aligned so the\r
82 /// last few bits are zero.  These bits have special meaning for the GMAC\r
83 /// peripheral and cannot be used as part of the address.\r
84 #define GMAC_ADDRESS_MASK   ((unsigned int)0xFFFFFFFC)\r
85 #define GMAC_LENGTH_FRAME   ((unsigned int)0x3FFF)    /// Length of frame mask\r
86 \r
87 // receive buffer descriptor bits\r
88 #define GMAC_RX_OWNERSHIP_BIT   (1 <<  0)\r
89 #define GMAC_RX_WRAP_BIT        (1 <<  1)\r
90 #define GMAC_RX_SOF_BIT         (1 << 14)\r
91 #define GMAC_RX_EOF_BIT         (1 << 15)\r
92 \r
93 // Transmit buffer descriptor bits\r
94 #define GMAC_TX_LAST_BUFFER_BIT (1 << 15)\r
95 #define GMAC_TX_WRAP_BIT        (1 << 30)\r
96 #define GMAC_TX_USED_BIT        (1 << 31)\r
97 #define GMAC_TX_RLE_BIT         (1 << 29) /// Retry Limit Exceeded\r
98 #define GMAC_TX_UND_BIT         (1 << 28) /// Tx Buffer Underrun\r
99 #define GMAC_TX_ERR_BIT         (1 << 27) /// Exhausted in mid-frame\r
100 #define GMAC_TX_ERR_BITS  \\r
101     (GMAC_TX_RLE_BIT | GMAC_TX_UND_BIT | GMAC_TX_ERR_BIT)\r
102 \r
103 /*---------------------------------------------------------------------------\r
104  *         Local functions\r
105  *---------------------------------------------------------------------------*/\r
106 \r
107 /**\r
108  *  \brief Disable TX & reset registers and descriptor list\r
109  *  \param pDrv Pointer to GMAC Driver instance.\r
110  */\r
111 static void GMACD_ResetTx(sGmacd *pDrv )\r
112 {\r
113     Gmac *pHw = pDrv->pHw;\r
114     uint8_t *pTxBuffer = pDrv->pTxBuffer;\r
115     sGmacTxDescriptor *pTd = pDrv->pTxD;\r
116     uint32_t Index;\r
117     uint32_t Address;\r
118 \r
119     /* Disable TX */\r
120     GMAC_TransmitEnable(pHw, 0);\r
121     /* Setup the TX descriptors. */\r
122     GCIRC_CLEAR(pDrv->wTxHead, pDrv->wTxTail);\r
123     for(Index = 0; Index < pDrv->wTxListSize; Index++) {\r
124         Address = (uint32_t)(&(pTxBuffer[Index * GMAC_TX_UNITSIZE]));\r
125         pTd[Index].addr = Address;\r
126         pTd[Index].status.val = (uint32_t)GMAC_TX_USED_BIT;\r
127     }\r
128     pTd[pDrv->wTxListSize - 1].status.val = GMAC_TX_USED_BIT | GMAC_TX_WRAP_BIT;\r
129     /* Transmit Buffer Queue Pointer Register */\r
130     GMAC_SetTxQueue(pHw, (uint32_t)pTd);\r
131 }\r
132     \r
133 /**\r
134  *  \brief Disable RX & reset registers and descriptor list\r
135  *  \param pDrv Pointer to GMAC Driver instance. \r
136  */\r
137 static void GMACD_ResetRx(sGmacd *pDrv )\r
138 {\r
139     Gmac    *pHw = pDrv->pHw;\r
140     uint8_t *pRxBuffer = pDrv->pRxBuffer;\r
141     sGmacRxDescriptor *pRd = pDrv->pRxD;\r
142 \r
143     uint32_t Index;\r
144     uint32_t Address;\r
145 \r
146     /* Disable RX */\r
147     GMAC_ReceiveEnable(pHw, 0);\r
148 \r
149     /* Setup the RX descriptors. */\r
150     pDrv->wRxI = 0;\r
151     for(Index = 0; Index < pDrv->wRxListSize; Index++)\r
152     {\r
153         Address = (uint32_t)(&(pRxBuffer[Index * GMAC_RX_UNITSIZE]));\r
154         /* Remove GMAC_RXD_bmOWNERSHIP and GMAC_RXD_bmWRAP */\r
155         pRd[Index].addr.val = Address & GMAC_ADDRESS_MASK;\r
156         pRd[Index].status.val = 0;\r
157     }\r
158     pRd[pDrv->wRxListSize - 1].addr.val |= GMAC_RX_WRAP_BIT;\r
159 \r
160     /* Receive Buffer Queue Pointer Register */\r
161     GMAC_SetRxQueue(pHw, (uint32_t) pRd);\r
162 }\r
163 \r
164     \r
165 /*---------------------------------------------------------------------------\r
166  *         Exported functions\r
167  *---------------------------------------------------------------------------*/\r
168  \r
169  \r
170 /**\r
171  *  \brief GMAC Interrupt handler\r
172  *  \param pGmacd Pointer to GMAC Driver instance.\r
173  */\r
174 void GMACD_Handler(sGmacd *pGmacd )\r
175 {\r
176     Gmac *pHw = pGmacd->pHw;\r
177     sGmacTxDescriptor      *pTxTd;\r
178     fGmacdTransferCallback *pTxCb = NULL;\r
179     uint32_t isr;\r
180     uint32_t rsr;\r
181     uint32_t tsr;\r
182    \r
183     uint32_t rxStatusFlag;\r
184     uint32_t txStatusFlag;\r
185     isr = GMAC_GetItStatus(pHw);\r
186     rsr = GMAC_GetRxStatus(pHw);\r
187     tsr = GMAC_GetTxStatus(pHw);\r
188 \r
189     isr &= ~(GMAC_GetItMask(pHw)| 0xF8030300);\r
190 \r
191     /* RX packet */\r
192     if ((isr & GMAC_ISR_RCOMP) || (rsr & GMAC_RSR_REC)) {\r
193         asm("nop");\r
194         rxStatusFlag = GMAC_RSR_REC;\r
195         /* Frame received */\r
196         /* Check OVR */\r
197         if (rsr & GMAC_RSR_RXOVR) {\r
198             rxStatusFlag |= GMAC_RSR_RXOVR;\r
199         }\r
200         /* Check BNA */\r
201         if (rsr & GMAC_RSR_BNA) {\r
202             rxStatusFlag |= GMAC_RSR_BNA;\r
203         }\r
204         /* Check HNO */\r
205         if (rsr & GMAC_RSR_HNO) {\r
206             rxStatusFlag |= GMAC_RSR_HNO;\r
207         }        \r
208         /* Clear status */\r
209         GMAC_ClearRxStatus(pHw, rxStatusFlag);\r
210 \r
211         /* Invoke callbacks */\r
212         if (pGmacd->fRxCb)\r
213         {\r
214             pGmacd->fRxCb(rxStatusFlag);\r
215         }\r
216     }\r
217 \r
218     /* TX packet */\r
219     if ((isr & GMAC_ISR_TCOMP) || (tsr & GMAC_TSR_TXCOMP)) {\r
220         asm("nop");\r
221         txStatusFlag = GMAC_TSR_TXCOMP;\r
222 \r
223         /*  A frame transmitted Check RLE */\r
224         if (tsr & GMAC_TSR_RLE) {\r
225             /* Status RLE & Number of discarded buffers */\r
226             txStatusFlag = GMAC_TSR_RLE\r
227                          | GCIRC_CNT(pGmacd->wTxHead,\r
228                                      pGmacd->wTxTail,\r
229                                      pGmacd->wTxListSize);\r
230             pTxCb = &pGmacd->fTxCbList[pGmacd->wTxTail];\r
231             GMACD_ResetTx(pGmacd);\r
232             TRACE_INFO("Tx RLE!!\n\r");\r
233             GMAC_TransmitEnable(pHw, 1);\r
234         }\r
235         /* Check COL */\r
236         if (tsr & GMAC_TSR_COL) {\r
237             txStatusFlag |= GMAC_TSR_COL;\r
238         }\r
239         /* Check TFC */\r
240         if (tsr & GMAC_TSR_TFC) {\r
241             txStatusFlag |= GMAC_TSR_TFC;\r
242         }\r
243         /* Check UND */\r
244         if (tsr & GMAC_TSR_UND) {\r
245             txStatusFlag |= GMAC_TSR_UND;\r
246         }\r
247         /* Check HRESP */\r
248         if (tsr & GMAC_TSR_HRESP) {\r
249             txStatusFlag |= GMAC_TSR_HRESP;\r
250         }\r
251         /* Clear status */\r
252         GMAC_ClearTxStatus(pHw, txStatusFlag);\r
253 \r
254         if (!GCIRC_EMPTY(pGmacd->wTxHead, pGmacd->wTxTail))\r
255         {\r
256             /* Check the buffers */\r
257             do {\r
258                 pTxTd = &pGmacd->pTxD[pGmacd->wTxTail];\r
259                 pTxCb = &pGmacd->fTxCbList[pGmacd->wTxTail];\r
260                 /* Exit if buffer has not been sent yet */\r
261 \r
262                 if ((pTxTd->status.val & (uint32_t)GMAC_TX_USED_BIT) == 0) {\r
263                     break;\r
264                 }\r
265                 /* Notify upper layer that a packet has been sent */\r
266                 if (*pTxCb) {\r
267                     (*pTxCb)(txStatusFlag);\r
268                 }\r
269                 GCIRC_INC( pGmacd->wTxTail, pGmacd->wTxListSize );\r
270             } while (GCIRC_CNT(pGmacd->wTxHead, pGmacd->wTxTail, pGmacd->wTxListSize));\r
271         }\r
272         \r
273         if (tsr & GMAC_TSR_RLE) {\r
274             /* Notify upper layer RLE */\r
275             if (*pTxCb) {\r
276                 (*pTxCb)(txStatusFlag);\r
277             }\r
278         }\r
279         \r
280         /* If a wakeup has been scheduled, notify upper layer that it can\r
281            send other packets, send will be successfull. */\r
282         if((GCIRC_SPACE(pGmacd->wTxHead,\r
283                          pGmacd->wTxTail,\r
284                          pGmacd->wTxListSize) >= pGmacd->bWakeupThreshold) && pGmacd->fWakupCb)\r
285         {\r
286             pGmacd->fWakupCb();\r
287         }\r
288     }\r
289 \r
290     /* PAUSE Frame */\r
291     if (isr & GMAC_ISR_PFNZ) TRACE_INFO("Pause!\n\r");\r
292     if (isr & GMAC_ISR_PTZ)  TRACE_INFO("Pause TO!\n\r");\r
293 }\r
294 \r
295 \r
296 /**\r
297  * \brief Initialize the GMAC with the Gmac controller address\r
298  *  \param pGmacd Pointer to GMAC Driver instance. \r
299  *  \param pHw    Pointer to HW address for registers.\r
300  *  \param bID     HW ID for power management\r
301  *  \param enableCAF    Enable/Disable CopyAllFrame.\r
302  *  \param enableNBC    Enable/Disable NoBroadCast.\r
303  */\r
304  void GMACD_Init(sGmacd *pGmacd,\r
305                 Gmac *pHw,\r
306                 uint8_t bID, \r
307                 uint8_t enableCAF, \r
308                 uint8_t enableNBC )\r
309 {\r
310     uint32_t dwNcfgr;\r
311     \r
312     /* Check parameters */\r
313     assert(GRX_BUFFERS * GMAC_RX_UNITSIZE > GMAC_FRAME_LENTGH_MAX);\r
314 \r
315     TRACE_DEBUG("GMAC_Init\n\r");\r
316 \r
317     /* Initialize struct */\r
318     pGmacd->pHw = pHw;\r
319     pGmacd->bId = bID;\r
320 \r
321     /* Power ON */\r
322     PMC_EnablePeripheral(bID);\r
323 \r
324     /* Disable TX & RX and more */\r
325     GMAC_NetworkControl(pHw, 0);\r
326     GMAC_DisableIt(pHw, ~0u);\r
327     \r
328     GMAC_ClearStatistics(pHw);\r
329     /* Clear all status bits in the receive status register. */\r
330     GMAC_ClearRxStatus(pHw, GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA |GMAC_RSR_HNO);\r
331 \r
332     /* Clear all status bits in the transmit status register */\r
333     GMAC_ClearTxStatus(pHw, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE\r
334                             | GMAC_TSR_TXGO | GMAC_TSR_TFC | GMAC_TSR_TXCOMP\r
335                             | GMAC_TSR_UND | GMAC_TSR_HRESP );\r
336 \r
337     /* Clear interrupts */\r
338     GMAC_GetItStatus(pHw);\r
339 \r
340     /* Enable the copy of data into the buffers\r
341        ignore broadcasts, and don't copy FCS. */\r
342     dwNcfgr = GMAC_NCFGR_FD | GMAC_NCFGR_DBW_DBW32 | GMAC_NCFGR_CLK_MCK_64;\r
343     if( enableCAF ) {\r
344         dwNcfgr |= GMAC_NCFGR_CAF;\r
345     }\r
346     if( enableNBC ) {\r
347         dwNcfgr |= GMAC_NCFGR_NBC;\r
348     }\r
349     \r
350     GMAC_Configure(pHw, dwNcfgr);\r
351 }\r
352 \r
353 \r
354 /**\r
355  * Initialize necessary allocated buffer lists for GMAC Driver to transfer data.\r
356  * Must be invoked after GMACD_Init() but before RX/TX start.\r
357  * \param pGmacd Pointer to GMAC Driver instance.\r
358  * \param pRxBuffer Pointer to allocated buffer for RX. The address should\r
359  *                  be 8-byte aligned and the size should be\r
360  *                  GMAC_RX_UNITSIZE * wRxSize.\r
361  * \param pRxD      Pointer to allocated RX descriptor list.\r
362  * \param wRxSize   RX size, in number of registered units (RX descriptors).\r
363  * \param pTxBuffer Pointer to allocated buffer for TX. The address should\r
364  *                  be 8-byte aligned and the size should be\r
365  *                  GMAC_TX_UNITSIZE * wTxSize.\r
366  * \param pTxD      Pointer to allocated TX descriptor list.\r
367  * \param pTxCb     Pointer to allocated TX callback list.\r
368  * \param wTxSize   TX size, in number of registered units (TX descriptors).\r
369  * \return GMACD_OK or GMACD_PARAM.\r
370  * \note If input address is not 8-byte aligned the address is automatically\r
371  *       adjusted and the list size is reduced by one.\r
372  */\r
373 uint8_t GMACD_InitTransfer( sGmacd *pGmacd,\r
374     uint8_t *pRxBuffer, sGmacRxDescriptor *pRxD,\r
375     uint16_t wRxSize,\r
376     uint8_t *pTxBuffer, sGmacTxDescriptor *pTxD, fGmacdTransferCallback *pTxCb,\r
377     uint16_t wTxSize)\r
378 {\r
379     Gmac *pHw = pGmacd->pHw;\r
380 \r
381     if (wRxSize <= 1 || wTxSize <= 1 || pTxCb == NULL) return GMACD_PARAM;\r
382 \r
383     /* Assign RX buffers */\r
384     if (   ((uint32_t)pRxBuffer & 0x7)\r
385         || ((uint32_t)pRxD      & 0x7) )\r
386     {\r
387         wRxSize --;\r
388         TRACE_DEBUG("RX list address adjusted\n\r");\r
389     }\r
390     pGmacd->pRxBuffer = (uint8_t*)((uint32_t)pRxBuffer & 0xFFFFFFF8);\r
391     pGmacd->pRxD = (sGmacRxDescriptor*)((uint32_t)pRxD & 0xFFFFFFF8);\r
392     pGmacd->wRxListSize = wRxSize;\r
393 \r
394     /* Assign TX buffers */\r
395     if (   ((uint32_t)pTxBuffer & 0x7)\r
396         || ((uint32_t)pTxD      & 0x7) )\r
397     {\r
398         wTxSize --;\r
399         TRACE_DEBUG("TX list address adjusted\n\r");\r
400     }\r
401     pGmacd->pTxBuffer = (uint8_t*)((uint32_t)pTxBuffer & 0xFFFFFFF8);\r
402     pGmacd->pTxD = (sGmacTxDescriptor*)((uint32_t)pTxD & 0xFFFFFFF8);\r
403     pGmacd->wTxListSize = wTxSize;\r
404     pGmacd->fTxCbList = pTxCb;\r
405 \r
406     /* Reset TX & RX */\r
407     GMACD_ResetRx(pGmacd);\r
408     GMACD_ResetTx(pGmacd);\r
409 \r
410     /* Enable Rx and Tx, plus the stats register. */\r
411     GMAC_TransmitEnable(pHw, 1);\r
412     GMAC_ReceiveEnable(pHw, 1);\r
413     GMAC_StatisticsWriteEnable(pHw, 1);\r
414 \r
415     /* Setup the interrupts for TX (and errors) */\r
416     GMAC_EnableIt(pHw, GMAC_IER_MFS \r
417                       |GMAC_IER_RCOMP\r
418                       |GMAC_IER_RXUBR\r
419                       |GMAC_IER_TXUBR\r
420                       |GMAC_IER_TUR\r
421                       |GMAC_IER_RLEX\r
422                       |GMAC_IER_TFC \r
423                       |GMAC_IER_TCOMP\r
424                       |GMAC_IER_ROVR \r
425                       |GMAC_IER_HRESP\r
426                       |GMAC_IER_PFNZ \r
427                       |GMAC_IER_PTZ \r
428                       |GMAC_IER_PFTR\r
429                       |GMAC_IER_EXINT\r
430                       |GMAC_IER_DRQFR\r
431                       |GMAC_IER_SFR\r
432                       |GMAC_IER_DRQFT\r
433                       |GMAC_IER_SFT\r
434                       |GMAC_IER_PDRQFR\r
435                       |GMAC_IER_PDRSFR\r
436                       |GMAC_IER_PDRQFT\r
437                       |GMAC_IER_PDRSFT);\r
438     //0x03FCFCFF\r
439     return GMACD_OK;\r
440 }\r
441 \r
442 \r
443 /**\r
444  * Reset TX & RX queue & statistics\r
445  * \param pGmacd Pointer to GMAC Driver instance.\r
446  */\r
447 void GMACD_Reset(sGmacd *pGmacd)\r
448 {\r
449     Gmac *pHw = pGmacd->pHw;\r
450 \r
451     GMACD_ResetRx(pGmacd);\r
452     GMACD_ResetTx(pGmacd);\r
453     //memset((void*)&GmacStatistics, 0x00, sizeof(GmacStats));\r
454     GMAC_NetworkControl(pHw, GMAC_NCR_TXEN | GMAC_NCR_RXEN\r
455                              | GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);\r
456 }\r
457 \r
458 /**\r
459  * \brief Send a packet with GMAC. If the packet size is larger than transfer buffer size \r
460  * error returned. If packet transfer status is monitored, specify callback for each packet.\r
461  *  \param pGmacd Pointer to GMAC Driver instance. \r
462  *  \param buffer   The buffer to be send\r
463  *  \param size     The size of buffer to be send\r
464  *  \param fGMAC_TxCallback Threshold Wakeup callback\r
465  *  \param fWakeUpCb   TX Wakeup\r
466  *  \return         OK, Busy or invalid packet\r
467  */\r
468 uint8_t GMACD_Send(sGmacd *pGmacd,\r
469                   void *pBuffer,\r
470                   uint32_t size,\r
471                   fGmacdTransferCallback fTxCb )\r
472 {\r
473     Gmac *pHw = pGmacd->pHw;\r
474     sGmacTxDescriptor      *pTxTd;\r
475     volatile fGmacdTransferCallback *pfTxCb;\r
476     \r
477     TRACE_DEBUG("GMAC_Send\n\r");\r
478     /* Check parameter */\r
479     if (size > GMAC_TX_UNITSIZE) {\r
480 \r
481         TRACE_ERROR("GMAC driver does not split send packets.");\r
482         return GMACD_PARAM;\r
483     }\r
484 \r
485     /* Pointers to the current TxTd */\r
486     pTxTd = &pGmacd->pTxD[pGmacd->wTxHead];\r
487     /* If no free TxTd, buffer can't be sent */\r
488     if( GCIRC_SPACE(pGmacd->wTxHead, pGmacd->wTxTail, pGmacd->wTxListSize) == 0)\r
489         return GMACD_TX_BUSY;\r
490     /* Pointers to the current Tx Callback */\r
491     pfTxCb = &pGmacd->fTxCbList[pGmacd->wTxHead];\r
492     /* Sanity check */\r
493 \r
494     /* Setup/Copy data to transmition buffer */\r
495     if (pBuffer && size) {\r
496         // Driver manage the ring buffer\r
497         memcpy((void *)pTxTd->addr, pBuffer, size);\r
498     }\r
499     /* Tx Callback */\r
500     *pfTxCb = fTxCb;\r
501 \r
502     /* Update TD status. The buffer size defined is length of ethernet frame\r
503       so it's always the last buffer of the frame. */\r
504     if (pGmacd->wTxHead == pGmacd->wTxListSize-1) {\r
505         pTxTd->status.val = \r
506             (size & GMAC_LENGTH_FRAME) | GMAC_TX_LAST_BUFFER_BIT | GMAC_TX_WRAP_BIT;\r
507     }\r
508     else {\r
509         pTxTd->status.val = (size & GMAC_LENGTH_FRAME) | GMAC_TX_LAST_BUFFER_BIT;\r
510     }\r
511     \r
512     GCIRC_INC(pGmacd->wTxHead, pGmacd->wTxListSize);\r
513     \r
514     //CP15_flush_dcache_for_dma ((uint32_t)(pTxTd), ((uint32_t)(pTxTd) + sizeof(pTxTd)));\r
515     /* Tx packets count */\r
516 \r
517     /* Now start to transmit if it is not already done */\r
518     GMAC_TransmissionStart(pHw);\r
519 \r
520     return GMACD_OK;\r
521 }\r
522 \r
523 \r
524 /**\r
525  * Return current load of TX.\r
526  * \param pGmacd   Pointer to GMAC Driver instance.\r
527  */\r
528 uint32_t GMACD_TxLoad(sGmacd *pGmacd)\r
529 {\r
530     uint16_t head = pGmacd->wTxHead;\r
531     uint16_t tail = pGmacd->wTxTail;\r
532     return GCIRC_CNT(head, tail, pGmacd->wTxListSize);\r
533 }\r
534 \r
535 /**\r
536  * \brief Receive a packet with GMAC.\r
537  * If not enough buffer for the packet, the remaining data is lost but right\r
538  * frame length is returned.\r
539  *  \param pGmacd Pointer to GMAC Driver instance. \r
540  *  \param pFrame           Buffer to store the frame\r
541  *  \param frameSize        Size of the frame\r
542  *  \param pRcvSize         Received size\r
543  *  \return                 OK, no data, or frame too small\r
544  */\r
545 uint8_t GMACD_Poll(sGmacd * pGmacd, \r
546                   uint8_t *pFrame, \r
547                   uint32_t frameSize, \r
548                   uint32_t *pRcvSize)\r
549 {\r
550 \r
551     uint16_t bufferLength;\r
552     uint32_t   tmpFrameSize = 0;\r
553     uint8_t  *pTmpFrame = 0;\r
554     uint32_t   tmpIdx = pGmacd->wRxI;\r
555     volatile sGmacRxDescriptor *pRxTd = &pGmacd->pRxD[pGmacd->wRxI];\r
556     uint8_t isFrame = 0;\r
557     \r
558     if (pFrame == NULL) return GMACD_PARAM;\r
559 \r
560     /* Set the default return value */\r
561     *pRcvSize = 0;\r
562     \r
563     /* Process received RxTd */\r
564     while ((pRxTd->addr.val & GMAC_RX_OWNERSHIP_BIT) == GMAC_RX_OWNERSHIP_BIT)\r
565     {\r
566         /* A start of frame has been received, discard previous fragments */\r
567         if ((pRxTd->status.val & GMAC_RX_SOF_BIT) == GMAC_RX_SOF_BIT)\r
568         {\r
569             /* Skip previous fragment */\r
570             while (tmpIdx != pGmacd->wRxI)\r
571             {\r
572                 pRxTd = &pGmacd->pRxD[pGmacd->wRxI];\r
573                 pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);\r
574                 GCIRC_INC(pGmacd->wRxI, pGmacd->wRxListSize);\r
575             }\r
576             pTmpFrame = pFrame;\r
577             tmpFrameSize = 0;\r
578             /* Start to gather buffers in a frame */\r
579             isFrame = 1;\r
580         }\r
581         /* Increment the pointer */\r
582         GCIRC_INC(tmpIdx, pGmacd->wRxListSize);\r
583         asm("nop");\r
584         /* Copy data in the frame buffer */\r
585         if (isFrame) {\r
586             if (tmpIdx == pGmacd->wRxI)\r
587             {\r
588                 TRACE_INFO("no EOF (Invalid of buffers too small)\n\r");\r
589 \r
590                 do {\r
591                     pRxTd = &pGmacd->pRxD[pGmacd->wRxI];\r
592                     pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);\r
593                     GCIRC_INC(pGmacd->wRxI, pGmacd->wRxListSize);\r
594                 } while(tmpIdx != pGmacd->wRxI);\r
595                 return GMACD_RX_NULL;\r
596             }\r
597 \r
598             /* Copy the buffer into the application frame */\r
599             bufferLength = GMAC_RX_UNITSIZE;\r
600             if ((tmpFrameSize + bufferLength) > frameSize)\r
601             {\r
602                 bufferLength = frameSize - tmpFrameSize;\r
603             }\r
604          \r
605             memcpy(pTmpFrame, (void*)(pRxTd->addr.val & GMAC_ADDRESS_MASK), bufferLength);\r
606             pTmpFrame += bufferLength;\r
607             tmpFrameSize += bufferLength;\r
608 \r
609             /* An end of frame has been received, return the data */\r
610             if ((pRxTd->status.val & GMAC_RX_EOF_BIT) == GMAC_RX_EOF_BIT)\r
611             {\r
612                 /* Frame size from the GMAC */\r
613                 *pRcvSize = (pRxTd->status.val & GMAC_LENGTH_FRAME);\r
614 \r
615                 /* Application frame buffer is too small all data have not been copied */\r
616                 if (tmpFrameSize < *pRcvSize) {\r
617                     return GMACD_SIZE_TOO_SMALL;\r
618                 }\r
619                 TRACE_DEBUG("packet %d-%d (%d)\n\r", pGmacd->wRxI, tmpIdx, *pRcvSize);\r
620                 /* All data have been copied in the application frame buffer => release TD */\r
621                 while (pGmacd->wRxI != tmpIdx)\r
622                 {\r
623                     pRxTd = &pGmacd->pRxD[pGmacd->wRxI];\r
624                     pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);\r
625                     GCIRC_INC(pGmacd->wRxI, pGmacd->wRxListSize);\r
626                 }\r
627                 return GMACD_OK;\r
628             }\r
629         }\r
630         \r
631         /* SOF has not been detected, skip the fragment */\r
632         else {\r
633            pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);\r
634            pGmacd->wRxI = tmpIdx;\r
635         }\r
636        \r
637         /* Process the next buffer */\r
638         pRxTd = &pGmacd->pRxD[tmpIdx];\r
639     }\r
640     return GMACD_RX_NULL;\r
641 }\r
642 \r
643 /**\r
644  * \brief Registers pRxCb callback. Callback will be invoked after the next received\r
645  * frame. When GMAC_Poll() returns GMAC_RX_NO_DATA the application task call GMAC_Set_RxCb()\r
646  * to register pRxCb() callback and enters suspend state. The callback is in charge \r
647  * to resume the task once a new frame has been received. The next time GMAC_Poll()\r
648  * is called, it will be successfull.\r
649  *  \param pGmacd Pointer to GMAC Driver instance. \r
650  *  \param pRxCb   Pointer to callback function\r
651  *  \return        OK, no data, or frame too small\r
652  */\r
653 \r
654 void GMACD_SetRxCallback(sGmacd * pGmacd, fGmacdTransferCallback fRxCb)\r
655 {\r
656     Gmac *pHw = pGmacd->pHw;\r
657 \r
658     if (fRxCb == NULL)\r
659     {\r
660         GMAC_DisableIt(pHw, GMAC_IDR_RCOMP);\r
661         pGmacd->fRxCb = NULL;\r
662     }\r
663     else\r
664     {\r
665         pGmacd->fRxCb = fRxCb;\r
666         GMAC_EnableIt(pHw, GMAC_IER_RCOMP);\r
667     }\r
668 }\r
669 \r
670 \r
671 /**\r
672  * Register/Clear TX wakeup callback.\r
673  *\r
674  * When GMACD_Send() returns GMACD_TX_BUSY (all TD busy) the application \r
675  * task calls GMACD_SetTxWakeupCallback() to register fWakeup() callback and \r
676  * enters suspend state. The callback is in charge to resume the task once \r
677  * several TD have been released. The next time GMACD_Send() will be called,\r
678  * it shall be successfull.\r
679  *\r
680  * This function is usually invoked with NULL callback from the TX wakeup\r
681  * callback itself, to unregister. Once the callback has resumed the\r
682  * application task, there is no need to invoke the callback again.\r
683  *\r
684  * \param pGmacd   Pointer to GMAC Driver instance.\r
685  * \param fWakeup     Wakeup callback.\r
686  * \param bThreshould Number of free TD before wakeup callback invoked.\r
687  * \return GMACD_OK, GMACD_PARAM on parameter error.\r
688  */\r
689 uint8_t GMACD_SetTxWakeupCallback(sGmacd * pGmacd,\r
690                                   fGmacdWakeupCallback fWakeup,\r
691                                   uint8_t bThreshold)\r
692 {\r
693     if (fWakeup == NULL)\r
694     {\r
695         pGmacd->fWakupCb = NULL;\r
696     }\r
697     else\r
698     {\r
699         if (bThreshold <= pGmacd->wTxListSize)\r
700         {\r
701             pGmacd->fWakupCb = fWakeup;\r
702             pGmacd->bWakeupThreshold = bThreshold;\r
703         }\r
704         else\r
705         {\r
706             return GMACD_PARAM;\r
707         }\r
708     }\r
709 \r
710     return GMACD_OK;\r
711 }\r