]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained_IAR_Keil/libchip_samv7/source/gmacd.c
Final V8.2.1 release ready for tagging:
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained_IAR_Keil / libchip_samv7 / 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 "chip.h"\r
36 #include <string.h>\r
37 \r
38 /** \addtogroup gmacd_defines\r
39     @{*/\r
40 \r
41 /*----------------------------------------------------------------------------\r
42  *        Macro\r
43  *----------------------------------------------------------------------------*/\r
44 \r
45 \r
46 /** ISO/IEC 14882:2003(E) - 5.6 Multiplicative operators:\r
47  * The binary / operator yields the quotient, and the binary % operator yields the remainder \r
48  * from the division of the first expression by the second. \r
49  * If the second operand of / or % is zero the behavior is undefined; otherwise (a/b)*b + a%b is equal to a.\r
50  * If both operands are nonnegative then the remainder is nonnegative;\r
51  * if not, the sign of the remainder is implementation-defined 74).\r
52  */\r
53 static inline int fixed_mod(int a, int b)\r
54 {\r
55     int rem = a % b;\r
56     while (rem < 0)\r
57         rem += b;\r
58 \r
59     return rem;\r
60 }\r
61 \r
62 /** Return count in buffer */\r
63 #define GCIRC_CNT(head,tail,size)  fixed_mod((head) - (tail), (size))\r
64 \r
65 /** Return space available, 0..size-1. always leave one free char as a completely full buffer \r
66     has head == tail, which is the same as empty */\r
67 #define GCIRC_SPACE(head,tail,size) GCIRC_CNT((tail),((head)+1),(size))\r
68 \r
69 /** Return count up to the end of the buffer. Carefully avoid accessing head and tail more than once,\r
70     so they can change underneath us without returning inconsistent results */\r
71 #define GCIRC_CNT_TO_END(head,tail,size) \\r
72      ({int end = (size) - (tail); \\r
73      int n = fixed_mod((head) + end, (size));   \\r
74      n < end ? n : end;})\r
75 \r
76 /** Return space available up to the end of the buffer */\r
77 #define GCIRC_SPACE_TO_END(head,tail,size) \\r
78    ({int end = (size) - 1 - (head); \\r
79      int n = fixed_mod(end + (tail), (size));   \\r
80      n <= end ? n : end+1;})\r
81 \r
82 /** Increment head or tail */\r
83 #define GCIRC_INC(headortail,size) \\r
84        headortail++;             \\r
85         if(headortail >= size) {  \\r
86             headortail = 0;       \\r
87         }\r
88 \r
89 /** Circular buffer is empty ? */\r
90 #define GCIRC_EMPTY(head, tail)     (head == tail)\r
91 \r
92 /** Clear circular buffer */\r
93 #define GCIRC_CLEAR(head, tail)  (head = tail = 0)\r
94 \r
95 \r
96 \r
97 /*---------------------------------------------------------------------------\r
98  *         Local functions\r
99  *---------------------------------------------------------------------------*/\r
100 \r
101 /**\r
102  *  \brief Disable TX & reset registers and descriptor list\r
103  *  \param pDrv Pointer to GMAC Driver instance.\r
104  */\r
105 static void GMACD_ResetTx(sGmacd *pDrv, gmacQueList_t queIdx)\r
106 {\r
107     Gmac *pHw = pDrv->pHw;\r
108     uint8_t *pTxBuffer = pDrv->queueList[queIdx].pTxBuffer;\r
109     sGmacTxDescriptor *pTd = pDrv->queueList[queIdx].pTxD;\r
110     uint32_t Index;\r
111     uint32_t Address;\r
112 \r
113     /* Disable TX */\r
114     GMAC_TransmitEnable(pHw, 0);\r
115     \r
116     /* Setup the TX descriptors. */\r
117     GCIRC_CLEAR(pDrv->queueList[queIdx].wTxHead, pDrv->queueList[queIdx].wTxTail);\r
118     for(Index = 0; Index < pDrv->queueList[queIdx].wTxListSize; Index++) {\r
119         Address = (uint32_t)(&(pTxBuffer[Index * GMAC_TX_UNITSIZE]));\r
120         pTd[Index].addr = Address;\r
121         pTd[Index].status.val = (uint32_t)GMAC_TX_USED_BIT;\r
122     }\r
123     \r
124     pTd[pDrv->queueList[queIdx].wTxListSize - 1].status.val = GMAC_TX_USED_BIT | GMAC_TX_WRAP_BIT;    \r
125     \r
126     /* Transmit Buffer Queue Pointer Register */\r
127       \r
128     GMAC_SetTxQueue(pHw, (uint32_t)pTd, queIdx);\r
129 }\r
130     \r
131 /**\r
132  *  \brief Disable RX & reset registers and descriptor list\r
133  *  \param pDrv Pointer to GMAC Driver instance. \r
134  */\r
135 static void GMACD_ResetRx(sGmacd *pDrv, gmacQueList_t queIdx )\r
136 {\r
137     Gmac    *pHw = pDrv->pHw;\r
138     uint8_t *pRxBuffer = pDrv->queueList[queIdx].pRxBuffer;\r
139     sGmacRxDescriptor *pRd = pDrv->queueList[queIdx].pRxD;\r
140 \r
141     uint32_t Index;\r
142     uint32_t Address;\r
143 \r
144     /* Disable RX */\r
145     GMAC_ReceiveEnable(pHw, 0);\r
146 \r
147     /* Setup the RX descriptors. */\r
148     pDrv->queueList[queIdx].wRxI = 0;\r
149     for(Index = 0; Index < pDrv->queueList[queIdx].wRxListSize; Index++)\r
150     {\r
151         Address = (uint32_t)(&(pRxBuffer[Index * GMAC_RX_UNITSIZE]));\r
152         /* Remove GMAC_RXD_bmOWNERSHIP and GMAC_RXD_bmWRAP */\r
153         pRd[Index].addr.val = Address & GMAC_ADDRESS_MASK;\r
154         pRd[Index].status.val = 0;\r
155     }\r
156     \r
157     pRd[pDrv->queueList[queIdx].wRxListSize - 1].addr.val |= GMAC_RX_WRAP_BIT;\r
158     \r
159     /* Receive Buffer Queue Pointer Register */ \r
160     GMAC_SetRxQueue(pHw, (uint32_t) pRd, queIdx);\r
161 }\r
162 \r
163 \r
164 /**\r
165  *  \brief Process successfully sent packets\r
166  *  \param pGmacd Pointer to GMAC Driver instance.\r
167  */\r
168 static void GMACD_TxCompleteHandler(sGmacd *pGmacd, gmacQueList_t qId)\r
169 {\r
170     Gmac                   *pHw = pGmacd->pHw;\r
171     sGmacTxDescriptor      *pTxTd;\r
172     fGmacdTransferCallback fTxCb;\r
173     uint32_t               tsr;\r
174 \r
175     /* Clear status */\r
176     tsr = GMAC_GetTxStatus(pHw);\r
177     GMAC_ClearTxStatus(pHw, tsr);\r
178 \r
179     while (!GCIRC_EMPTY(pGmacd->queueList[qId].wTxHead, pGmacd->queueList[qId].wTxTail)) {\r
180         pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];\r
181 \r
182         /* Make hw descriptor updates visible to CPU */\r
183         memory_barrier();\r
184 \r
185         /* Exit if frame has not been sent yet:\r
186          * On TX completion, the GMAC set the USED bit only into the\r
187          * very first buffer descriptor of the sent frame.\r
188          * Otherwise it updates this descriptor with status error bits.\r
189          * This is the descriptor writeback.\r
190          */\r
191         if ((pTxTd->status.val & GMAC_TX_USED_BIT) == 0)\r
192             break;\r
193 \r
194         /* Process all buffers of the current transmitted frame */\r
195         while ((pTxTd->status.val & GMAC_TX_LAST_BUFFER_BIT) == 0) {\r
196             GCIRC_INC(pGmacd->queueList[qId].wTxTail, pGmacd->queueList[qId].wTxListSize);\r
197             pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];\r
198         }\r
199 \r
200         /* Notify upper layer that a frame has been sent */\r
201         fTxCb = pGmacd->queueList[qId].fTxCbList[pGmacd->queueList[qId].wTxTail];\r
202         if (fTxCb)\r
203             fTxCb(tsr);\r
204 \r
205         /* Go to next frame */\r
206         GCIRC_INC(pGmacd->queueList[qId].wTxTail, pGmacd->queueList[qId].wTxListSize);\r
207     }\r
208 \r
209     /* If a wakeup has been scheduled, notify upper layer that it can\r
210        send other packets, send will be successfull. */\r
211     if (pGmacd->queueList[qId].fWakupCb &&\r
212         GCIRC_SPACE(pGmacd->queueList[qId].wTxHead,\r
213                     pGmacd->queueList[qId].wTxTail,\r
214                     pGmacd->queueList[qId].wTxListSize) >= pGmacd->queueList[qId].bWakeupThreshold)\r
215         pGmacd->queueList[qId].fWakupCb();\r
216 }\r
217 \r
218 \r
219 /**\r
220  *  \brief Reset TX queue when errors are detected\r
221  *  \param pGmacd Pointer to GMAC Driver instance.\r
222  */\r
223 static void GMACD_TxErrorHandler(sGmacd *pGmacd, gmacQueList_t qId)\r
224 {\r
225     Gmac                   *pHw = pGmacd->pHw;\r
226     sGmacTxDescriptor      *pTxTd;\r
227     fGmacdTransferCallback fTxCb;\r
228     uint32_t               tsr;\r
229 \r
230     /* Clear TXEN bit into the Network Configuration Register:\r
231      * this is a workaround to recover from TX lockups that \r
232      * occur on sama5d3 gmac (r1p24f2) when using  scatter-gather.\r
233      * This issue has never been seen on sama5d4 gmac (r1p31).\r
234      */\r
235     GMAC_TransmitEnable(pHw, 0);\r
236 \r
237     /* The following step should be optional since this function is called \r
238      * directly by the IRQ handler. Indeed, according to Cadence \r
239      * documentation, the transmission is halted on errors such as\r
240      * too many retries or transmit under run.\r
241      * However it would become mandatory if the call of this function\r
242      * were scheduled as a task by the IRQ handler (this is how Linux \r
243      * driver works). Then this function might compete with GMACD_Send().\r
244      *\r
245      * Setting bit 10, tx_halt, of the Network Control Register is not enough:\r
246      * We should wait for bit 3, tx_go, of the Transmit Status Register to \r
247      * be cleared at transmit completion if a frame is being transmitted.\r
248      */\r
249     GMAC_TransmissionHalt(pHw);\r
250     while (GMAC_GetTxStatus(pHw) & GMAC_TSR_TXGO);\r
251 \r
252     /* Treat frames in TX queue including the ones that caused the error. */\r
253     while (!GCIRC_EMPTY(pGmacd->queueList[qId].wTxHead, pGmacd->queueList[qId].wTxTail)) {\r
254         int tx_completed = 0;\r
255         pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];\r
256 \r
257         /* Make hw descriptor updates visible to CPU */\r
258         memory_barrier();\r
259 \r
260         /* Check USED bit on the very first buffer descriptor to validate\r
261          * TX completion.\r
262          */\r
263         if (pTxTd->status.val & GMAC_TX_USED_BIT)\r
264             tx_completed = 1;\r
265 \r
266         /* Go to the last buffer descriptor of the frame */\r
267         while ((pTxTd->status.val & GMAC_TX_LAST_BUFFER_BIT) == 0) {\r
268             GCIRC_INC(pGmacd->queueList[qId].wTxTail, pGmacd->queueList[qId].wTxListSize);\r
269             pTxTd = &pGmacd->queueList[qId].pTxD[pGmacd->queueList[qId].wTxTail];\r
270         }\r
271 \r
272         /* Notify upper layer that a frame status */\r
273         fTxCb = pGmacd->queueList[qId].fTxCbList[pGmacd->queueList[qId].wTxTail];\r
274         if (fTxCb)\r
275             fTxCb(tx_completed ? GMAC_TSR_TXCOMP : 0); // TODO: which error to notify?\r
276 \r
277         /* Go to next frame */\r
278         GCIRC_INC(pGmacd->queueList[qId].wTxTail, pGmacd->queueList[qId].wTxListSize);\r
279     }    \r
280 \r
281     /* Reset TX queue */\r
282     GMACD_ResetTx(pGmacd, qId);\r
283     \r
284     /* Clear status */\r
285     tsr = GMAC_GetTxStatus(pHw);\r
286     GMAC_ClearTxStatus(pHw, tsr);\r
287 \r
288     /* Now we are ready to start transmission again */\r
289     GMAC_TransmitEnable(pHw, 1);\r
290     if (pGmacd->queueList[qId].fWakupCb)\r
291         pGmacd->queueList[qId].fWakupCb();\r
292 }\r
293 \r
294  \r
295 /*---------------------------------------------------------------------------\r
296  *         Exported functions\r
297  *---------------------------------------------------------------------------*/\r
298  \r
299  \r
300 /**\r
301  *  \brief GMAC Interrupt handler\r
302  *  \param pGmacd Pointer to GMAC Driver instance.\r
303  */\r
304 void GMACD_Handler(sGmacd *pGmacd, gmacQueList_t queIdx)\r
305 {\r
306     Gmac *pHw = pGmacd->pHw;\r
307     uint32_t isr;\r
308     uint32_t rsr;\r
309     \r
310     \r
311     \r
312     /* Interrupt Status Register is cleared on read */\r
313     while ( (isr = GMAC_GetItStatus(pHw, queIdx)) !=0) {\r
314         /* RX packet */\r
315         if (isr & GMAC_INT_RX_BITS) {\r
316             /* Clear status */\r
317             rsr = GMAC_GetRxStatus(pHw);\r
318             GMAC_ClearRxStatus(pHw, rsr);\r
319 \r
320             /* Invoke callback */\r
321             if (pGmacd->queueList[queIdx].fRxCb)\r
322                 pGmacd->queueList[queIdx].fRxCb(rsr);\r
323         }\r
324 \r
325         /* TX error */\r
326         if (isr & GMAC_INT_TX_ERR_BITS) {\r
327             GMACD_TxErrorHandler(pGmacd, queIdx);\r
328             break;\r
329         }\r
330 \r
331         /* TX packet */\r
332         if (isr & GMAC_IER_TCOMP)\r
333             GMACD_TxCompleteHandler(pGmacd, queIdx);\r
334 \r
335         if (isr & GMAC_IER_HRESP) {\r
336             TRACE_ERROR("HRESP\n\r");\r
337         }\r
338                         \r
339     }\r
340 }\r
341 \r
342 \r
343 /**\r
344  * \brief Initialize the GMAC with the Gmac controller address\r
345  *  \param pGmacd Pointer to GMAC Driver instance. \r
346  *  \param pHw    Pointer to HW address for registers.\r
347  *  \param bID     HW ID for power management\r
348  *  \param enableCAF    Enable/Disable CopyAllFrame.\r
349  *  \param enableNBC    Enable/Disable NoBroadCast.\r
350  */\r
351  void GMACD_Init(sGmacd *pGmacd,\r
352                 Gmac *pHw,\r
353                 uint8_t bID, \r
354                 uint8_t enableCAF, \r
355                 uint8_t enableNBC )\r
356 {\r
357     uint32_t dwNcfgr, dwDcfgr;\r
358     \r
359     /* Check parameters */\r
360 //    assert(GRX_BUFFERS * GMAC_RX_UNITSIZE > GMAC_FRAME_LENTGH_MAX);\r
361 \r
362     TRACE_DEBUG("GMAC_Init\n\r");\r
363 \r
364     /* Initialize struct */\r
365     pGmacd->pHw = pHw;\r
366     pGmacd->bId = bID;\r
367 \r
368     /* Power ON */\r
369     PMC_EnablePeripheral(bID);\r
370 \r
371     /* Disable TX & RX and more */\r
372     GMAC_NetworkControl(pHw, 0);\r
373     GMAC_DisableAllQueueIt(pHw, ~0u);\r
374     \r
375     GMAC_ClearStatistics(pHw);\r
376     /* Clear all status bits in the receive status register. */\r
377     GMAC_ClearRxStatus(pHw, GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA |GMAC_RSR_HNO);\r
378 \r
379     /* Clear all status bits in the transmit status register */\r
380     GMAC_ClearTxStatus(pHw, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE\r
381                             | GMAC_TSR_TXGO | GMAC_TSR_TFC | GMAC_TSR_TXCOMP\r
382                             | GMAC_TSR_UND | GMAC_TSR_HRESP );\r
383 \r
384     /* Clear All interrupts */\r
385     GMAC_GetItStatus(pHw, GMAC_QUE_0);\r
386     GMAC_GetItStatus(pHw, GMAC_QUE_1);\r
387     GMAC_GetItStatus(pHw, GMAC_QUE_2);\r
388 \r
389     /* Enable the copy of data into the buffers\r
390        ignore broadcasts, and don't copy FCS. */\r
391     dwNcfgr = GMAC_NCFGR_FD | GMAC_NCFGR_DBW(0) | GMAC_NCFGR_CLK_MCK_64;\r
392     /* enable 1536 buffer */\r
393 //    dwNcfgr |= GMAC_NCFGR_MAXFS;\r
394     if( enableCAF ) {\r
395         dwNcfgr |= GMAC_NCFGR_CAF;\r
396     }\r
397     if( enableNBC ) {\r
398         dwNcfgr |= GMAC_NCFGR_NBC;\r
399     }\r
400     \r
401     dwDcfgr = (GMAC_DCFGR_DRBS(8) |  (0<<8) | (0<<10) );\r
402     GMAC_Configure(pHw, dwNcfgr);\r
403     GMAC_DmaConfigure(pHw, dwDcfgr);\r
404 }\r
405 \r
406 \r
407 /**\r
408  * Initialize necessary allocated buffer lists for GMAC Driver to transfer data.\r
409  * Must be invoked after GMACD_Init() but before RX/TX start.\r
410  * \param pGmacd Pointer to GMAC Driver instance.\r
411  * \param pRxBuffer Pointer to allocated buffer for RX. The address should\r
412  *                  be 8-byte aligned and the size should be\r
413  *                  GMAC_RX_UNITSIZE * wRxSize.\r
414  * \param pRxD      Pointer to allocated RX descriptor list.\r
415  * \param wRxSize   RX size, in number of registered units (RX descriptors).\r
416  * \param pTxBuffer Pointer to allocated buffer for TX. The address should\r
417  *                  be 8-byte aligned and the size should be\r
418  *                  GMAC_TX_UNITSIZE * wTxSize.\r
419  * \param pTxD      Pointer to allocated TX descriptor list.\r
420  * \param pTxCb     Pointer to allocated TX callback list.\r
421  * \param wTxSize   TX size, in number of registered units (TX descriptors).\r
422  * \return GMACD_OK or GMACD_PARAM.\r
423  * \note If input address is not 8-byte aligned the address is automatically\r
424  *       adjusted and the list size is reduced by one.\r
425  */\r
426 uint8_t GMACD_InitTransfer( sGmacd *pGmacd,\r
427     uint8_t *pRxBuffer, sGmacRxDescriptor *pRxD,\r
428     uint16_t wRxSize,\r
429     uint8_t *pTxBuffer, sGmacTxDescriptor *pTxD, fGmacdTransferCallback *pTxCb,\r
430     uint16_t wTxSize,\r
431     gmacQueList_t queIdx)\r
432 {\r
433     Gmac *pHw = pGmacd->pHw;\r
434 \r
435     if (wRxSize <= 1 || wTxSize <= 1 || pTxCb == NULL) return GMACD_PARAM;\r
436 \r
437     /* Assign RX buffers */\r
438     if (   ((uint32_t)pRxBuffer & 0x7)\r
439         || ((uint32_t)pRxD      & 0x7) )\r
440     {\r
441         wRxSize --;\r
442         TRACE_DEBUG("RX list address adjusted\n\r");\r
443     }\r
444     pGmacd->queueList[queIdx].pRxBuffer = (uint8_t*)((uint32_t)pRxBuffer & 0xFFFFFFF8);\r
445     pGmacd->queueList[queIdx].pRxD = (sGmacRxDescriptor*)((uint32_t)pRxD & 0xFFFFFFF8);\r
446     pGmacd->queueList[queIdx].wRxListSize = wRxSize;\r
447     /* Assign TX buffers */\r
448     if (   ((uint32_t)pTxBuffer & 0x7)\r
449         || ((uint32_t)pTxD      & 0x7) )\r
450     {\r
451         wTxSize --;\r
452         TRACE_DEBUG("TX list address adjusted\n\r");\r
453     }\r
454     pGmacd->queueList[queIdx].pTxBuffer = (uint8_t*)((uint32_t)pTxBuffer & 0xFFFFFFF8);\r
455     pGmacd->queueList[queIdx].pTxD = (sGmacTxDescriptor*)((uint32_t)pTxD & 0xFFFFFFF8);\r
456     pGmacd->queueList[queIdx].wTxListSize = wTxSize;\r
457     pGmacd->queueList[queIdx].fTxCbList = pTxCb;\r
458     \r
459     /* Reset TX & RX */\r
460     GMACD_ResetRx(pGmacd, queIdx);\r
461     GMACD_ResetTx(pGmacd, queIdx);\r
462     \r
463     \r
464     /* Setup the interrupts for RX/TX completion (and errors) */\r
465     switch(queIdx) \r
466     {\r
467     case GMAC_QUE_0:\r
468      /* YBP: Que 0 should be configured last so as to enable transmit and Receive in the NCR register */\r
469                 \r
470     /* Enable Rx and Tx, plus the stats register. */\r
471     GMAC_TransmitEnable(pHw, 1);\r
472     GMAC_ReceiveEnable(pHw, 1);\r
473     GMAC_StatisticsWriteEnable(pHw, 1);\r
474 \r
475         GMAC_EnableIt(pHw,\r
476                   GMAC_INT_RX_BITS |\r
477                   GMAC_INT_TX_BITS |\r
478                   GMAC_INT_TX_ERR_BITS, GMAC_QUE_0);\r
479     break;\r
480     \r
481     case GMAC_QUE_1:\r
482       \r
483       \r
484         GMAC_EnableIt(pHw,\r
485                   GMAC_INT_RX_BITS |\r
486                   GMAC_INT_TX_BITS |\r
487                   GMAC_INT_TX_ERR_BITS, GMAC_QUE_1);\r
488         break;\r
489     case GMAC_QUE_2:\r
490         \r
491       GMAC_EnableIt(pHw,\r
492                   GMAC_INT_RX_BITS |\r
493                   GMAC_INT_TX_BITS |\r
494                   GMAC_INT_TX_ERR_BITS, GMAC_QUE_2);\r
495     break;\r
496     };\r
497     \r
498     return GMACD_OK;\r
499 }\r
500 \r
501 \r
502 /**\r
503  * Reset TX & RX queue & statistics\r
504  * \param pGmacd Pointer to GMAC Driver instance.\r
505  */\r
506 void GMACD_Reset(sGmacd *pGmacd)\r
507 {\r
508     Gmac *pHw = pGmacd->pHw;\r
509 \r
510     GMACD_ResetRx(pGmacd, GMAC_QUE_0);\r
511     GMACD_ResetRx(pGmacd, GMAC_QUE_1);\r
512     GMACD_ResetRx(pGmacd, GMAC_QUE_2);\r
513         \r
514     GMACD_ResetTx(pGmacd, GMAC_QUE_0);\r
515     GMACD_ResetTx(pGmacd, GMAC_QUE_1);\r
516     GMACD_ResetTx(pGmacd, GMAC_QUE_2);\r
517     \r
518         //memset((void*)&GmacStatistics, 0x00, sizeof(GmacStats));\r
519     GMAC_NetworkControl(pHw, GMAC_NCR_TXEN | GMAC_NCR_RXEN\r
520                              | GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);\r
521 }\r
522 \r
523 /**\r
524  * \brief Send a frame splitted into buffers. If the frame size is larger than transfer buffer size\r
525  * error returned. If frame transfer status is monitored, specify callback for each frame.\r
526  *  \param pGmacd Pointer to GMAC Driver instance. \r
527  *  \param sgl Pointer to a scatter-gather list describing the buffers of the ethernet frame.\r
528  */\r
529 uint8_t GMACD_SendSG(sGmacd *pGmacd,\r
530                      const sGmacSGList *sgl,\r
531                      fGmacdTransferCallback fTxCb,\r
532                      gmacQueList_t queIdx)\r
533 {\r
534     Gmac *pHw = pGmacd->pHw;\r
535     sGmacTxDescriptor *pTd = pGmacd->queueList[queIdx].pTxD;\r
536     sGmacTxDescriptor *pTxTd;\r
537     uint16_t wTxPos, wTxHead;\r
538     int i;\r
539 \r
540     TRACE_DEBUG("%s\n\r", __FUNCTION__);\r
541 \r
542     /* Check parameter */\r
543     if (!sgl->len) {\r
544         TRACE_ERROR("%s:: ethernet frame is empty.\r\n", __FUNCTION__);\r
545         return GMACD_PARAM;\r
546     }\r
547     if (sgl->len >= pGmacd->queueList[queIdx].wTxListSize) {\r
548         TRACE_ERROR("%s: ethernet frame has too many buffers.\r\n", __FUNCTION__);\r
549         return GMACD_PARAM;\r
550     }\r
551 \r
552     /* Check available space */\r
553     if (GCIRC_SPACE(pGmacd->queueList[queIdx].wTxHead, pGmacd->queueList[queIdx].wTxTail, pGmacd->queueList[queIdx].wTxListSize) < (int)sgl->len)\r
554         return GMACD_TX_BUSY;\r
555 \r
556     /* Tag end of TX queue */\r
557     wTxHead = fixed_mod(pGmacd->queueList[queIdx].wTxHead + sgl->len, pGmacd->queueList[queIdx].wTxListSize);\r
558     wTxPos = wTxHead;\r
559     pGmacd->queueList[queIdx].fTxCbList[wTxPos] = NULL;\r
560     pTxTd = &pTd[wTxPos];\r
561     pTxTd->status.val = GMAC_TX_USED_BIT;    \r
562 \r
563     /* Update buffer descriptors in reverse order to avoid a race \r
564      * condition with hardware.\r
565      */\r
566     for (i = (int)(sgl->len-1); i >= 0; --i) {\r
567         const sGmacSG *sg = &sgl->sg[i];\r
568         uint32_t status;\r
569 \r
570         if (sg->size > GMAC_TX_UNITSIZE) {\r
571             TRACE_ERROR("%s: buffer size is too big.\r\n", __FUNCTION__);\r
572             return GMACD_PARAM;\r
573         }\r
574 \r
575         if (wTxPos == 0)\r
576             wTxPos = pGmacd->queueList[queIdx].wTxListSize-1;\r
577         else\r
578             wTxPos--;\r
579 \r
580         /* Reset TX callback */\r
581         pGmacd->queueList[queIdx].fTxCbList[wTxPos] = NULL;\r
582 \r
583         pTxTd = &pTd[wTxPos];\r
584 #ifdef GMAC_ZERO_COPY\r
585         /** Update buffer descriptor address word:\r
586          *  MUST be done before status word to avoid a race condition.\r
587          */\r
588         pTxTd->addr = (uint32_t)sg->pBuffer;        \r
589 #else\r
590         /* Copy data into transmittion buffer */\r
591         if (sg->pBuffer && sg->size)\r
592             memcpy((void *)pTxTd->addr, sg->pBuffer, sg->size);        \r
593 #endif\r
594 \r
595         /* Compute buffer descriptor status word */\r
596         status = sg->size & GMAC_LENGTH_FRAME;\r
597         if (i == (int)(sgl->len-1)) {\r
598             status |= GMAC_TX_LAST_BUFFER_BIT;\r
599             pGmacd->queueList[queIdx].fTxCbList[wTxPos] = fTxCb;\r
600         }\r
601         if (wTxPos == pGmacd->queueList[queIdx].wTxListSize-1)\r
602             status |= GMAC_TX_WRAP_BIT;\r
603 \r
604         /* Update buffer descriptor status word: clear USED bit */\r
605         pTxTd->status.val = status;\r
606 \r
607         /* Make newly initialized descriptor visible to hardware */\r
608         memory_barrier();\r
609     }\r
610 \r
611     /* Update TX ring buffer pointers */\r
612     pGmacd->queueList[queIdx].wTxHead = wTxHead;\r
613 \r
614     memory_barrier();\r
615     /* Now start to transmit if it is not already done */\r
616     GMAC_TransmissionStart(pHw);\r
617 \r
618     return GMACD_OK;\r
619 }\r
620 \r
621 /**\r
622  * \brief Send a packet with GMAC. If the packet size is larger than transfer buffer size \r
623  * error returned. If packet transfer status is monitored, specify callback for each packet.\r
624  *  \param pGmacd Pointer to GMAC Driver instance. \r
625  *  \param buffer   The buffer to be send\r
626  *  \param size     The size of buffer to be send\r
627  *  \param fGMAC_TxCallback Threshold Wakeup callback\r
628  *  \param fWakeUpCb   TX Wakeup\r
629  *  \return         OK, Busy or invalid packet\r
630  */\r
631 uint8_t GMACD_Send(sGmacd *pGmacd,\r
632                    void *pBuffer,\r
633                    uint32_t size,\r
634                    fGmacdTransferCallback fTxCb,\r
635                                    gmacQueList_t queIdx)\r
636 {\r
637     sGmacSGList sgl;\r
638     sGmacSG sg;\r
639 \r
640     /* Init single entry scatter-gather list */\r
641     sg.size = size;\r
642     sg.pBuffer = pBuffer;\r
643     sgl.len = 1;\r
644     sgl.sg = &sg;\r
645 \r
646     return GMACD_SendSG(pGmacd, &sgl, fTxCb, queIdx);\r
647 }\r
648 \r
649 \r
650 /**\r
651  * Return current load of TX.\r
652  * \param pGmacd   Pointer to GMAC Driver instance.\r
653  */\r
654 uint32_t GMACD_TxLoad(sGmacd *pGmacd, gmacQueList_t queIdx)\r
655 {\r
656     uint16_t head = pGmacd->queueList[queIdx].wTxHead;\r
657     uint16_t tail = pGmacd->queueList[queIdx].wTxTail;\r
658     return GCIRC_CNT(head, tail, pGmacd->queueList[queIdx].wTxListSize);\r
659 }\r
660 \r
661 /**\r
662  * \brief Receive a packet with GMAC.\r
663  * If not enough buffer for the packet, the remaining data is lost but right\r
664  * frame length is returned.\r
665  *  \param pGmacd Pointer to GMAC Driver instance. \r
666  *  \param pFrame           Buffer to store the frame\r
667  *  \param frameSize        Size of the frame\r
668  *  \param pRcvSize         Received size\r
669  *  \return                 OK, no data, or frame too small\r
670  */\r
671 uint8_t GMACD_Poll(sGmacd * pGmacd, \r
672                   uint8_t *pFrame, \r
673                   uint32_t frameSize, \r
674                   uint32_t *pRcvSize,\r
675                   gmacQueList_t queIdx)\r
676 {\r
677 \r
678     uint16_t bufferLength;\r
679     uint32_t   tmpFrameSize = 0;\r
680     uint8_t  *pTmpFrame = 0;\r
681     uint32_t   tmpIdx = pGmacd->queueList[queIdx].wRxI;\r
682     volatile sGmacRxDescriptor *pRxTd = &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; \r
683 \r
684     uint8_t isFrame = 0;\r
685     \r
686     if (pFrame == NULL) return GMACD_PARAM;\r
687 \r
688     /* Set the default return value */\r
689     *pRcvSize = 0;\r
690     \r
691     /* Process received RxTd */\r
692     while ((pRxTd->addr.val & GMAC_RX_OWNERSHIP_BIT) == GMAC_RX_OWNERSHIP_BIT)\r
693     {\r
694         /* A start of frame has been received, discard previous fragments */\r
695         if ((pRxTd->status.val & GMAC_RX_SOF_BIT) == GMAC_RX_SOF_BIT)\r
696         {\r
697             /* Skip previous fragment */\r
698             while (tmpIdx != pGmacd->queueList[queIdx].wRxI)\r
699             {\r
700                 pRxTd = &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; \r
701                 pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);\r
702                 GCIRC_INC(pGmacd->queueList[queIdx].wRxI, pGmacd->queueList[queIdx].wRxListSize);\r
703             }\r
704             pTmpFrame = pFrame;\r
705             tmpFrameSize = 0;\r
706             /* Start to gather buffers in a frame */\r
707             isFrame = 1;\r
708         }\r
709         /* Increment the pointer */\r
710         GCIRC_INC(tmpIdx, pGmacd->queueList[queIdx].wRxListSize);        \r
711         /* Copy data in the frame buffer */\r
712         if (isFrame) {\r
713             if (tmpIdx == pGmacd->queueList[queIdx].wRxI)\r
714             {\r
715                 TRACE_INFO("no EOF (Invalid of buffers too small)\n\r");\r
716 \r
717                 do {\r
718                     pRxTd = &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; \r
719                     pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);\r
720                     GCIRC_INC(pGmacd->queueList[queIdx].wRxI, pGmacd->queueList[queIdx].wRxListSize);\r
721                 } while(tmpIdx != pGmacd->queueList[queIdx].wRxI);\r
722                 return GMACD_RX_NULL;\r
723             }\r
724 \r
725             /* Copy the buffer into the application frame */\r
726             bufferLength = GMAC_RX_UNITSIZE;\r
727             if ((tmpFrameSize + bufferLength) > frameSize)\r
728             {\r
729                 bufferLength = frameSize - tmpFrameSize;\r
730             }\r
731          \r
732             memcpy(pTmpFrame, (void*)(pRxTd->addr.val & GMAC_ADDRESS_MASK), bufferLength);            \r
733             pTmpFrame += bufferLength;\r
734             tmpFrameSize += bufferLength;\r
735 \r
736             /* An end of frame has been received, return the data */\r
737             if ((pRxTd->status.val & GMAC_RX_EOF_BIT) == GMAC_RX_EOF_BIT)\r
738             {\r
739                 /* Frame size from the GMAC */\r
740                 *pRcvSize = (pRxTd->status.val & GMAC_LENGTH_FRAME);\r
741 \r
742                 /* Application frame buffer is too small all data have not been copied */\r
743                 if (tmpFrameSize < *pRcvSize) {\r
744                     return GMACD_SIZE_TOO_SMALL;\r
745                 }\r
746                 TRACE_DEBUG("packet %d-%d (%d)\n\r", pGmacd->queueList[queIdx].wRxI, tmpIdx, *pRcvSize);\r
747                 /* All data have been copied in the application frame buffer => release TD */\r
748                 while (pGmacd->queueList[queIdx].wRxI != tmpIdx)\r
749                 {\r
750                     pRxTd = &pGmacd->queueList[queIdx].pRxD[pGmacd->queueList[queIdx].wRxI]; \r
751                     pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);\r
752                     GCIRC_INC(pGmacd->queueList[queIdx].wRxI, pGmacd->queueList[queIdx].wRxListSize);\r
753                 }\r
754                 return GMACD_OK;\r
755             }\r
756         }\r
757         \r
758         /* SOF has not been detected, skip the fragment */\r
759         else {\r
760            pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);\r
761            pGmacd->queueList[queIdx].wRxI = tmpIdx;\r
762         }\r
763        \r
764         /* Process the next buffer */\r
765         pRxTd = &pGmacd->queueList[queIdx].pRxD[tmpIdx];\r
766         memory_barrier();\r
767     }\r
768     return GMACD_RX_NULL;\r
769 }\r
770 \r
771 /**\r
772  * \brief Registers pRxCb callback. Callback will be invoked after the next received\r
773  * frame. When GMAC_Poll() returns GMAC_RX_NO_DATA the application task call GMAC_Set_RxCb()\r
774  * to register pRxCb() callback and enters suspend state. The callback is in charge \r
775  * to resume the task once a new frame has been received. The next time GMAC_Poll()\r
776  * is called, it will be successfull.\r
777  *  \param pGmacd Pointer to GMAC Driver instance. \r
778  *  \param pRxCb   Pointer to callback function\r
779  *  \return        OK, no data, or frame too small\r
780  */\r
781 \r
782 void GMACD_SetRxCallback(sGmacd * pGmacd, fGmacdTransferCallback fRxCb, gmacQueList_t queIdx)\r
783 {\r
784     Gmac *pHw = pGmacd->pHw;\r
785 \r
786     if (fRxCb == NULL)\r
787     {\r
788         GMAC_DisableIt(pHw, GMAC_IDR_RCOMP, queIdx);\r
789         pGmacd->queueList[queIdx].fRxCb = NULL;\r
790     }\r
791     else\r
792     {\r
793         pGmacd->queueList[queIdx].fRxCb = fRxCb;\r
794         GMAC_EnableIt(pHw, GMAC_IER_RCOMP, queIdx);\r
795     }\r
796 }\r
797 \r
798 \r
799 /**\r
800  * Register/Clear TX wakeup callback.\r
801  *\r
802  * When GMACD_Send() returns GMACD_TX_BUSY (all TD busy) the application \r
803  * task calls GMACD_SetTxWakeupCallback() to register fWakeup() callback and \r
804  * enters suspend state. The callback is in charge to resume the task once \r
805  * several TD have been released. The next time GMACD_Send() will be called,\r
806  * it shall be successfull.\r
807  *\r
808  * This function is usually invoked with NULL callback from the TX wakeup\r
809  * callback itself, to unregister. Once the callback has resumed the\r
810  * application task, there is no need to invoke the callback again.\r
811  *\r
812  * \param pGmacd   Pointer to GMAC Driver instance.\r
813  * \param fWakeup     Wakeup callback.\r
814  * \param bThreshould Number of free TD before wakeup callback invoked.\r
815  * \return GMACD_OK, GMACD_PARAM on parameter error.\r
816  */\r
817 uint8_t GMACD_SetTxWakeupCallback(sGmacd * pGmacd,\r
818                                   fGmacdWakeupCallback fWakeup,\r
819                                   uint8_t bThreshold,\r
820                                   gmacQueList_t queIdx)\r
821 {\r
822     if (fWakeup == NULL)\r
823     {\r
824         pGmacd->queueList[queIdx].fWakupCb = NULL;\r
825     }\r
826     else\r
827     {\r
828         if (bThreshold <= pGmacd->queueList[queIdx].wTxListSize)\r
829         {\r
830             pGmacd->queueList[queIdx].fWakupCb = fWakeup;\r
831             pGmacd->queueList[queIdx].bWakeupThreshold = bThreshold;\r
832         }\r
833         else\r
834         {\r
835             return GMACD_PARAM;\r
836         }\r
837     }\r
838 \r
839     return GMACD_OK;\r
840 }\r
841 \r
842 //uint32_t GMACD_GetQ0BuffBaseAddr (uint8_t ** baseAddrPtr)\r
843 //{\r
844 //  *baseAddrPtr = &gs_uc_rx_buffer[0u];\r
845 //  return sizeof(gs_uc_rx_buffer);\r
846 //}\r
847 //\r
848 //uint32_t GMACD_GetQ1BuffBaseAddr (uint8_t ** baseAddrPtr)\r
849 //{\r
850 //  *baseAddrPtr = &gs_uc_q1_rx_buffer[0u];\r
851 //  return sizeof(gs_uc_q1_rx_buffer);\r
852 //}\r
853 //\r
854 //uint32_t GMACD_GetQ2BuffBaseAddr (uint8_t ** baseAddrPtr)\r
855 //{\r
856 //  *baseAddrPtr = &gs_uc_q2_rx_buffer[0u];\r
857 //  return sizeof(gs_uc_q2_rx_buffer);\r
858 //}\r