1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2012, Atmel Corporation
\r
6 * All rights reserved.
\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
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\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
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
31 /*---------------------------------------------------------------------------
\r
33 *---------------------------------------------------------------------------*/
\r
38 /** \addtogroup gmacd_defines
\r
42 /*----------------------------------------------------------------------------
\r
44 *----------------------------------------------------------------------------*/
\r
45 /** Return count in buffer */
\r
46 #define GCIRC_CNT(head,tail,size) (((head) - (tail)) % (size))
\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
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
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
65 /** Increment head or tail */
\r
66 #define GCIRC_INC(headortail,size) \
\r
68 if(headortail >= size) { \
\r
72 /** Circular buffer is empty ? */
\r
73 #define GCIRC_EMPTY(head, tail) (head == tail)
\r
75 /** Clear circular buffer */
\r
76 #define GCIRC_CLEAR(head, tail) (head = tail = 0)
\r
78 //------------------------------------------------------------------------------
\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
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
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
103 /*---------------------------------------------------------------------------
\r
105 *---------------------------------------------------------------------------*/
\r
108 * \brief Disable TX & reset registers and descriptor list
\r
109 * \param pDrv Pointer to GMAC Driver instance.
\r
111 static void GMACD_ResetTx(sGmacd *pDrv )
\r
113 Gmac *pHw = pDrv->pHw;
\r
114 uint8_t *pTxBuffer = pDrv->pTxBuffer;
\r
115 sGmacTxDescriptor *pTd = pDrv->pTxD;
\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
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
134 * \brief Disable RX & reset registers and descriptor list
\r
135 * \param pDrv Pointer to GMAC Driver instance.
\r
137 static void GMACD_ResetRx(sGmacd *pDrv )
\r
139 Gmac *pHw = pDrv->pHw;
\r
140 uint8_t *pRxBuffer = pDrv->pRxBuffer;
\r
141 sGmacRxDescriptor *pRd = pDrv->pRxD;
\r
147 GMAC_ReceiveEnable(pHw, 0);
\r
149 /* Setup the RX descriptors. */
\r
151 for(Index = 0; Index < pDrv->wRxListSize; Index++)
\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
158 pRd[pDrv->wRxListSize - 1].addr.val |= GMAC_RX_WRAP_BIT;
\r
160 /* Receive Buffer Queue Pointer Register */
\r
161 GMAC_SetRxQueue(pHw, (uint32_t) pRd);
\r
165 /*---------------------------------------------------------------------------
\r
166 * Exported functions
\r
167 *---------------------------------------------------------------------------*/
\r
171 * \brief GMAC Interrupt handler
\r
172 * \param pGmacd Pointer to GMAC Driver instance.
\r
174 void GMACD_Handler(sGmacd *pGmacd )
\r
176 Gmac *pHw = pGmacd->pHw;
\r
177 sGmacTxDescriptor *pTxTd;
\r
178 fGmacdTransferCallback *pTxCb = NULL;
\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
189 isr &= ~(GMAC_GetItMask(pHw)| 0xF8030300);
\r
192 if ((isr & GMAC_ISR_RCOMP) || (rsr & GMAC_RSR_REC)) {
\r
194 rxStatusFlag = GMAC_RSR_REC;
\r
195 /* Frame received */
\r
197 if (rsr & GMAC_RSR_RXOVR) {
\r
198 rxStatusFlag |= GMAC_RSR_RXOVR;
\r
201 if (rsr & GMAC_RSR_BNA) {
\r
202 rxStatusFlag |= GMAC_RSR_BNA;
\r
205 if (rsr & GMAC_RSR_HNO) {
\r
206 rxStatusFlag |= GMAC_RSR_HNO;
\r
209 GMAC_ClearRxStatus(pHw, rxStatusFlag);
\r
211 /* Invoke callbacks */
\r
214 pGmacd->fRxCb(rxStatusFlag);
\r
219 if ((isr & GMAC_ISR_TCOMP) || (tsr & GMAC_TSR_TXCOMP)) {
\r
221 txStatusFlag = GMAC_TSR_TXCOMP;
\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
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
236 if (tsr & GMAC_TSR_COL) {
\r
237 txStatusFlag |= GMAC_TSR_COL;
\r
240 if (tsr & GMAC_TSR_TFC) {
\r
241 txStatusFlag |= GMAC_TSR_TFC;
\r
244 if (tsr & GMAC_TSR_UND) {
\r
245 txStatusFlag |= GMAC_TSR_UND;
\r
248 if (tsr & GMAC_TSR_HRESP) {
\r
249 txStatusFlag |= GMAC_TSR_HRESP;
\r
252 GMAC_ClearTxStatus(pHw, txStatusFlag);
\r
254 if (!GCIRC_EMPTY(pGmacd->wTxHead, pGmacd->wTxTail))
\r
256 /* Check the buffers */
\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
262 if ((pTxTd->status.val & (uint32_t)GMAC_TX_USED_BIT) == 0) {
\r
265 /* Notify upper layer that a packet has been sent */
\r
267 (*pTxCb)(txStatusFlag);
\r
269 GCIRC_INC( pGmacd->wTxTail, pGmacd->wTxListSize );
\r
270 } while (GCIRC_CNT(pGmacd->wTxHead, pGmacd->wTxTail, pGmacd->wTxListSize));
\r
273 if (tsr & GMAC_TSR_RLE) {
\r
274 /* Notify upper layer RLE */
\r
276 (*pTxCb)(txStatusFlag);
\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
284 pGmacd->wTxListSize) >= pGmacd->bWakeupThreshold) && pGmacd->fWakupCb)
\r
286 pGmacd->fWakupCb();
\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
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
304 void GMACD_Init(sGmacd *pGmacd,
\r
307 uint8_t enableCAF,
\r
308 uint8_t enableNBC )
\r
312 /* Check parameters */
\r
313 assert(GRX_BUFFERS * GMAC_RX_UNITSIZE > GMAC_FRAME_LENTGH_MAX);
\r
315 TRACE_DEBUG("GMAC_Init\n\r");
\r
317 /* Initialize struct */
\r
322 PMC_EnablePeripheral(bID);
\r
324 /* Disable TX & RX and more */
\r
325 GMAC_NetworkControl(pHw, 0);
\r
326 GMAC_DisableIt(pHw, ~0u);
\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
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
337 /* Clear interrupts */
\r
338 GMAC_GetItStatus(pHw);
\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
344 dwNcfgr |= GMAC_NCFGR_CAF;
\r
347 dwNcfgr |= GMAC_NCFGR_NBC;
\r
350 GMAC_Configure(pHw, dwNcfgr);
\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
373 uint8_t GMACD_InitTransfer( sGmacd *pGmacd,
\r
374 uint8_t *pRxBuffer, sGmacRxDescriptor *pRxD,
\r
376 uint8_t *pTxBuffer, sGmacTxDescriptor *pTxD, fGmacdTransferCallback *pTxCb,
\r
379 Gmac *pHw = pGmacd->pHw;
\r
381 if (wRxSize <= 1 || wTxSize <= 1 || pTxCb == NULL) return GMACD_PARAM;
\r
383 /* Assign RX buffers */
\r
384 if ( ((uint32_t)pRxBuffer & 0x7)
\r
385 || ((uint32_t)pRxD & 0x7) )
\r
388 TRACE_DEBUG("RX list address adjusted\n\r");
\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
394 /* Assign TX buffers */
\r
395 if ( ((uint32_t)pTxBuffer & 0x7)
\r
396 || ((uint32_t)pTxD & 0x7) )
\r
399 TRACE_DEBUG("TX list address adjusted\n\r");
\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
406 /* Reset TX & RX */
\r
407 GMACD_ResetRx(pGmacd);
\r
408 GMACD_ResetTx(pGmacd);
\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
415 /* Setup the interrupts for TX (and errors) */
\r
416 GMAC_EnableIt(pHw, GMAC_IER_MFS
\r
444 * Reset TX & RX queue & statistics
\r
445 * \param pGmacd Pointer to GMAC Driver instance.
\r
447 void GMACD_Reset(sGmacd *pGmacd)
\r
449 Gmac *pHw = pGmacd->pHw;
\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
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
468 uint8_t GMACD_Send(sGmacd *pGmacd,
\r
471 fGmacdTransferCallback fTxCb )
\r
473 Gmac *pHw = pGmacd->pHw;
\r
474 sGmacTxDescriptor *pTxTd;
\r
475 volatile fGmacdTransferCallback *pfTxCb;
\r
477 TRACE_DEBUG("GMAC_Send\n\r");
\r
478 /* Check parameter */
\r
479 if (size > GMAC_TX_UNITSIZE) {
\r
481 TRACE_ERROR("GMAC driver does not split send packets.");
\r
482 return GMACD_PARAM;
\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
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
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
509 pTxTd->status.val = (size & GMAC_LENGTH_FRAME) | GMAC_TX_LAST_BUFFER_BIT;
\r
512 GCIRC_INC(pGmacd->wTxHead, pGmacd->wTxListSize);
\r
514 //CP15_flush_dcache_for_dma ((uint32_t)(pTxTd), ((uint32_t)(pTxTd) + sizeof(pTxTd)));
\r
515 /* Tx packets count */
\r
517 /* Now start to transmit if it is not already done */
\r
518 GMAC_TransmissionStart(pHw);
\r
525 * Return current load of TX.
\r
526 * \param pGmacd Pointer to GMAC Driver instance.
\r
528 uint32_t GMACD_TxLoad(sGmacd *pGmacd)
\r
530 uint16_t head = pGmacd->wTxHead;
\r
531 uint16_t tail = pGmacd->wTxTail;
\r
532 return GCIRC_CNT(head, tail, pGmacd->wTxListSize);
\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
545 uint8_t GMACD_Poll(sGmacd * pGmacd,
\r
547 uint32_t frameSize,
\r
548 uint32_t *pRcvSize)
\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
558 if (pFrame == NULL) return GMACD_PARAM;
\r
560 /* Set the default return value */
\r
563 /* Process received RxTd */
\r
564 while ((pRxTd->addr.val & GMAC_RX_OWNERSHIP_BIT) == GMAC_RX_OWNERSHIP_BIT)
\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
569 /* Skip previous fragment */
\r
570 while (tmpIdx != pGmacd->wRxI)
\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
576 pTmpFrame = pFrame;
\r
578 /* Start to gather buffers in a frame */
\r
581 /* Increment the pointer */
\r
582 GCIRC_INC(tmpIdx, pGmacd->wRxListSize);
\r
584 /* Copy data in the frame buffer */
\r
586 if (tmpIdx == pGmacd->wRxI)
\r
588 TRACE_INFO("no EOF (Invalid of buffers too small)\n\r");
\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
598 /* Copy the buffer into the application frame */
\r
599 bufferLength = GMAC_RX_UNITSIZE;
\r
600 if ((tmpFrameSize + bufferLength) > frameSize)
\r
602 bufferLength = frameSize - tmpFrameSize;
\r
605 memcpy(pTmpFrame, (void*)(pRxTd->addr.val & GMAC_ADDRESS_MASK), bufferLength);
\r
606 pTmpFrame += bufferLength;
\r
607 tmpFrameSize += bufferLength;
\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
612 /* Frame size from the GMAC */
\r
613 *pRcvSize = (pRxTd->status.val & GMAC_LENGTH_FRAME);
\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
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
623 pRxTd = &pGmacd->pRxD[pGmacd->wRxI];
\r
624 pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);
\r
625 GCIRC_INC(pGmacd->wRxI, pGmacd->wRxListSize);
\r
631 /* SOF has not been detected, skip the fragment */
\r
633 pRxTd->addr.val &= ~(GMAC_RX_OWNERSHIP_BIT);
\r
634 pGmacd->wRxI = tmpIdx;
\r
637 /* Process the next buffer */
\r
638 pRxTd = &pGmacd->pRxD[tmpIdx];
\r
640 return GMACD_RX_NULL;
\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
654 void GMACD_SetRxCallback(sGmacd * pGmacd, fGmacdTransferCallback fRxCb)
\r
656 Gmac *pHw = pGmacd->pHw;
\r
660 GMAC_DisableIt(pHw, GMAC_IDR_RCOMP);
\r
661 pGmacd->fRxCb = NULL;
\r
665 pGmacd->fRxCb = fRxCb;
\r
666 GMAC_EnableIt(pHw, GMAC_IER_RCOMP);
\r
672 * Register/Clear TX wakeup callback.
\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
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
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
689 uint8_t GMACD_SetTxWakeupCallback(sGmacd * pGmacd,
\r
690 fGmacdWakeupCallback fWakeup,
\r
691 uint8_t bThreshold)
\r
693 if (fWakeup == NULL)
\r
695 pGmacd->fWakupCb = NULL;
\r
699 if (bThreshold <= pGmacd->wTxListSize)
\r
701 pGmacd->fWakupCb = fWakeup;
\r
702 pGmacd->bWakeupThreshold = bThreshold;
\r
706 return GMACD_PARAM;
\r