]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2822 1d2547de-c912-0410...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / ATSAM4E / gmac.c
index e4a3ba988a3dc745b6eaf9a01ba7b2ca259f8dd5..948f9a661be10d631f958fb6fff813e81fb12ee4 100644 (file)
- /**
- * \file
- *
- * \brief GMAC (Ethernet MAC) driver for SAM.
- *
- * Copyright (c) 2013 Atmel Corporation. All rights reserved.
- *
- * \asf_license_start
- *
- * \page License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- *
- * 3. The name of Atmel may not be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * 4. This software may only be redistributed and used in connection with an
- *    Atmel microcontroller product.
- *
- * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
- * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * \asf_license_stop
- *
- */
-
-/* Standard includes. */
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-/* FreeRTOS includes. */
-#include "FreeRTOS.h"
-#include "task.h"
-
-#include "FreeRTOSIPConfig.h"
-
-#include "compiler.h"
-#include "instance/gmac.h"
-#include "ethernet_phy.h"
-
-/// @cond 0
-/**INDENT-OFF**/
-#ifdef __cplusplus
-extern "C" {
-#endif
-/**INDENT-ON**/
-/// @endcond
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x)  (int)( sizeof(x) / sizeof(x)[0] )
-#endif
-/**
- * \defgroup gmac_group Ethernet Media Access Controller
- *
- * See \ref gmac_quickstart.
- *
- * Driver for the GMAC (Ethernet Media Access Controller).
- * This file contains basic functions for the GMAC, with support for all modes, settings
- * and clock speeds.
- *
- * \section dependencies Dependencies
- * This driver does not depend on other modules.
- *
- * @{
- */
-
-/** TX descriptor lists */
-COMPILER_ALIGNED(8)
-static gmac_tx_descriptor_t gs_tx_desc[ GMAC_TX_BUFFERS ];
-#if( GMAC_USES_TX_CALLBACK != 0 )
-/** TX callback lists */
-static gmac_dev_tx_cb_t gs_tx_callback[ GMAC_TX_BUFFERS ];
-#endif
-/** RX descriptors lists */
-COMPILER_ALIGNED(8)
-static gmac_rx_descriptor_t gs_rx_desc[ GMAC_RX_BUFFERS ];
-
-#if( ipconfigZERO_COPY_TX_DRIVER == 0 )
-       /** Send Buffer. Section 3.6 of AMBA 2.0 spec states that burst should not cross the
-        * 1K Boundaries. Receive buffer manager write operations are burst of 2 words => 3 lsb bits
-        * of the address shall be set to 0.
-        */
-       COMPILER_ALIGNED(8)
-       static uint8_t gs_uc_tx_buffer[ GMAC_TX_BUFFERS * GMAC_TX_UNITSIZE ];
-#endif /* ipconfigZERO_COPY_TX_DRIVER */
-
-/** Receive Buffer */
-COMPILER_ALIGNED(8)
-static uint8_t gs_uc_rx_buffer[ GMAC_RX_BUFFERS * GMAC_RX_UNITSIZE ];
-
-/**
- * GMAC device memory management struct.
- */
-typedef struct gmac_dev_mem {
-       /* Pointer to allocated buffer for RX. The address should be 8-byte aligned
-       and the size should be GMAC_RX_UNITSIZE * wRxSize. */
-       uint8_t *p_rx_buffer;
-       /* Pointer to allocated RX descriptor list. */
-       gmac_rx_descriptor_t *p_rx_dscr;
-       /* RX size, in number of registered units (RX descriptors). */
-       /* Increased size from 16- to 32-bits, because it's more efficient */
-       uint32_t us_rx_size;
-       /* Pointer to allocated buffer for TX. The address should be 8-byte aligned
-       and the size should be GMAC_TX_UNITSIZE * wTxSize. */
-       uint8_t *p_tx_buffer;
-       /* Pointer to allocated TX descriptor list. */
-       gmac_tx_descriptor_t *p_tx_dscr;
-       /* TX size, in number of registered units (TX descriptors). */
-       uint32_t us_tx_size;
-} gmac_dev_mem_t;
-
-/** Return count in buffer */
-#define CIRC_CNT( head, tail, size )           ( ( ( head ) - ( tail ) ) % ( size ) )
-
-/*
- * Return space available, from 0 to size-1.
- * Always leave one free char as a completely full buffer that has (head == tail),
- * which is the same as empty.
- */
-#define CIRC_SPACE( head, tail, size )         CIRC_CNT( ( tail ), ( ( head ) + 1 ), ( size ) )
-
-/** Circular buffer is empty ? */
-#define CIRC_EMPTY( head, tail )                       ( head == tail )
-/** Clear circular buffer */
-#define CIRC_CLEAR( head, tail )                       do { ( head ) = 0; ( tail ) = 0; } while( 0 )
-
-/** Increment head or tail */
-static __inline void circ_inc32( int32_t *lHeadOrTail, uint32_t ulSize )
-{
-       ( *lHeadOrTail ) ++;
-    if( ( *lHeadOrTail ) >= ( int32_t )ulSize )
-       {
-               ( *lHeadOrTail ) = 0;
-       }
-}
-
-/**
- * \brief Wait PHY operation to be completed.
- *
- * \param p_gmac HW controller address.
- * \param ul_retry The retry times, 0 to wait forever until completeness.
- *
- * Return GMAC_OK if the operation is completed successfully.
- */
-static uint8_t gmac_wait_phy(Gmac* p_gmac, const uint32_t ul_retry)
-{
-       volatile uint32_t ul_retry_count = 0;
-       const uint32_t xPHYPollDelay = pdMS_TO_TICKS( 1ul );
-
-       while (!gmac_is_phy_idle(p_gmac)) {
-               if (ul_retry == 0) {
-                       continue;
-               }
-
-               ul_retry_count++;
-
-               if (ul_retry_count >= ul_retry) {
-                       return GMAC_TIMEOUT;
-               }
-
-               /* Block the task to allow other tasks to execute while the PHY
-               is not connected. */
-               vTaskDelay( xPHYPollDelay );
-       }
-       return GMAC_OK;
-}
-
-/**
- * \brief Disable transfer, reset registers and descriptor lists.
- *
- * \param p_dev Pointer to GMAC driver instance.
- *
- */
-static void gmac_reset_tx_mem(gmac_device_t* p_dev)
-{
-       Gmac *p_hw = p_dev->p_hw;
-       uint8_t *p_tx_buff = p_dev->p_tx_buffer;
-       gmac_tx_descriptor_t *p_td = p_dev->p_tx_dscr;
-
-       uint32_t ul_index;
-       uint32_t ul_address;
-
-       /* Disable TX */
-       gmac_enable_transmit(p_hw, 0);
-
-       /* Set up the TX descriptors */
-       CIRC_CLEAR(p_dev->l_tx_head, p_dev->l_tx_tail);
-       for( ul_index = 0; ul_index < p_dev->ul_tx_list_size; ul_index++ )
-       {
-               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
-               {
-                       ul_address = (uint32_t) 0u;
-               }
-               #else
-               {
-                       ul_address = (uint32_t) (&(p_tx_buff[ul_index * GMAC_TX_UNITSIZE]));
-               }
-               #endif /* ipconfigZERO_COPY_TX_DRIVER */
-               p_td[ul_index].addr = ul_address;
-               p_td[ul_index].status.val = GMAC_TXD_USED;
-       }
-       p_td[p_dev->ul_tx_list_size - 1].status.val =
-                       GMAC_TXD_USED | GMAC_TXD_WRAP;
-
-       /* Set transmit buffer queue */
-       gmac_set_tx_queue(p_hw, (uint32_t) p_td);
-}
-
-/**
- * \brief Disable receiver, reset registers and descriptor list.
- *
- * \param p_drv Pointer to GMAC Driver instance.
- */
-static void gmac_reset_rx_mem(gmac_device_t* p_dev)
-{
-       Gmac *p_hw = p_dev->p_hw;
-       uint8_t *p_rx_buff = p_dev->p_rx_buffer;
-       gmac_rx_descriptor_t *pRd = p_dev->p_rx_dscr;
-
-       uint32_t ul_index;
-       uint32_t ul_address;
-
-       /* Disable RX */
-       gmac_enable_receive(p_hw, 0);
-
-       /* Set up the RX descriptors */
-       p_dev->ul_rx_idx = 0;
-       for( ul_index = 0; ul_index < p_dev->ul_rx_list_size; ul_index++ )
-       {
-               ul_address = (uint32_t) (&(p_rx_buff[ul_index * GMAC_RX_UNITSIZE]));
-               pRd[ul_index].addr.val = ul_address & GMAC_RXD_ADDR_MASK;
-               pRd[ul_index].status.val = 0;
-       }
-       pRd[p_dev->ul_rx_list_size - 1].addr.val |= GMAC_RXD_WRAP;
-
-       /* Set receive buffer queue */
-       gmac_set_rx_queue(p_hw, (uint32_t) pRd);
-}
-
-
-/**
- * \brief Initialize the allocated buffer lists for GMAC driver to transfer data.
- * Must be invoked after gmac_dev_init() but before RX/TX starts.
- *
- * \note If input address is not 8-byte aligned, the address is automatically
- *       adjusted and the list size is reduced by one.
- *
- * \param p_gmac Pointer to GMAC instance.
- * \param p_gmac_dev Pointer to GMAC device instance.
- * \param p_dev_mm Pointer to the GMAC memory management control block.
- * \param p_tx_cb Pointer to allocated TX callback list.
- *
- * \return GMAC_OK or GMAC_PARAM.
- */
-static uint8_t gmac_init_mem(Gmac* p_gmac, gmac_device_t* p_gmac_dev,
-               gmac_dev_mem_t* p_dev_mm
-#if( GMAC_USES_TX_CALLBACK != 0 )
-               , gmac_dev_tx_cb_t* p_tx_cb
-#endif
-               )
-{
-       if (p_dev_mm->us_rx_size <= 1 || p_dev_mm->us_tx_size <= 1
-#if( GMAC_USES_TX_CALLBACK != 0 )
-               || p_tx_cb == NULL
-#endif
-               ) {
-               return GMAC_PARAM;
-       }
-
-       /* Assign RX buffers */
-       if (((uint32_t) p_dev_mm->p_rx_buffer & 0x7)
-                       || ((uint32_t) p_dev_mm->p_rx_dscr & 0x7)) {
-               p_dev_mm->us_rx_size--;
-       }
-       p_gmac_dev->p_rx_buffer =
-                       (uint8_t *) ((uint32_t) p_dev_mm->p_rx_buffer & 0xFFFFFFF8);
-       p_gmac_dev->p_rx_dscr =
-                       (gmac_rx_descriptor_t *) ((uint32_t) p_dev_mm->p_rx_dscr
-                       & 0xFFFFFFF8);
-       p_gmac_dev->ul_rx_list_size = p_dev_mm->us_rx_size;
-
-       /* Assign TX buffers */
-       if (((uint32_t) p_dev_mm->p_tx_buffer & 0x7)
-                       || ((uint32_t) p_dev_mm->p_tx_dscr & 0x7)) {
-               p_dev_mm->us_tx_size--;
-       }
-       p_gmac_dev->p_tx_buffer =
-                       (uint8_t *) ((uint32_t) p_dev_mm->p_tx_buffer & 0xFFFFFFF8);
-       p_gmac_dev->p_tx_dscr =
-                       (gmac_tx_descriptor_t *) ((uint32_t) p_dev_mm->p_tx_dscr
-                       & 0xFFFFFFF8);
-       p_gmac_dev->ul_tx_list_size = p_dev_mm->us_tx_size;
-#if( GMAC_USES_TX_CALLBACK != 0 )
-       p_gmac_dev->func_tx_cb_list = p_tx_cb;
-#endif
-       /* Reset TX & RX */
-       gmac_reset_rx_mem(p_gmac_dev);
-       gmac_reset_tx_mem(p_gmac_dev);
-
-       /* Enable Rx and Tx, plus the statistics register */
-       gmac_enable_transmit(p_gmac, true);
-       gmac_enable_receive(p_gmac, true);
-       gmac_enable_statistics_write(p_gmac, true);
-
-       /* Set up the interrupts for transmission and errors */
-       gmac_enable_interrupt(p_gmac,
-                       GMAC_IER_RXUBR | /* Enable receive used bit read interrupt. */
-                       GMAC_IER_TUR   | /* Enable transmit underrun interrupt. */
-                       GMAC_IER_RLEX  | /* Enable retry limit  exceeded interrupt. */
-                       GMAC_IER_TFC   | /* Enable transmit buffers exhausted in mid-frame interrupt. */
-                       GMAC_IER_TCOMP | /* Enable transmit complete interrupt. */
-                       GMAC_IER_ROVR  | /* Enable receive overrun interrupt. */
-                       GMAC_IER_HRESP | /* Enable Hresp not OK interrupt. */
-                       GMAC_IER_PFNZ  | /* Enable pause frame received interrupt. */
-                       GMAC_IER_PTZ);   /* Enable pause time zero interrupt. */
-
-       return GMAC_OK;
-}
-
-/**
- * \brief Read the PHY register.
- *
- * \param p_gmac   Pointer to the GMAC instance.
- * \param uc_phy_address PHY address.
- * \param uc_address Register address.
- * \param p_value Pointer to a 32-bit location to store read data.
- *
- * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
- */
-uint8_t gmac_phy_read(Gmac* p_gmac, uint8_t uc_phy_address, uint8_t uc_address,
-               uint32_t* p_value)
-{
-       gmac_maintain_phy(p_gmac, uc_phy_address, uc_address, 1, 0);
-
-       if (gmac_wait_phy(p_gmac, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) {
-               return GMAC_TIMEOUT;
-       }
-       *p_value = gmac_get_phy_data(p_gmac);
-       return GMAC_OK;
-}
-
-/**
- * \brief Write the PHY register.
- *
- * \param p_gmac   Pointer to the GMAC instance.
- * \param uc_phy_address PHY Address.
- * \param uc_address Register Address.
- * \param ul_value Data to write, actually 16-bit data.
- *
- * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
- */
-uint8_t gmac_phy_write(Gmac* p_gmac, uint8_t uc_phy_address,
-               uint8_t uc_address, uint32_t ul_value)
-{
-       gmac_maintain_phy(p_gmac, uc_phy_address, uc_address, 0, ul_value);
-
-       if (gmac_wait_phy(p_gmac, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) {
-               return GMAC_TIMEOUT;
-       }
-       return GMAC_OK;
-}
-
-/**
- * \brief Initialize the GMAC driver.
- *
- * \param p_gmac   Pointer to the GMAC instance.
- * \param p_gmac_dev Pointer to the GMAC device instance.
- * \param p_opt GMAC configure options.
- */
-void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev,
-               gmac_options_t* p_opt)
-{
-       gmac_dev_mem_t gmac_dev_mm;
-
-       /* Disable TX & RX and more */
-       gmac_network_control(p_gmac, 0);
-       gmac_disable_interrupt(p_gmac, ~0u);
-
-
-       gmac_clear_statistics(p_gmac);
-
-       /* Clear all status bits in the receive status register. */
-       gmac_clear_rx_status(p_gmac, GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA);
-
-       /* Clear all status bits in the transmit status register */
-       gmac_clear_tx_status(p_gmac, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE
-                       | GMAC_TSR_TFC | GMAC_TSR_TXCOMP | GMAC_TSR_UND);
-
-       /* Clear interrupts */
-       gmac_get_interrupt_status(p_gmac);
-#if !defined(ETHERNET_CONF_DATA_OFFSET)
-       /*  Receive Buffer Offset
-        * Indicates the number of bytes by which the received data
-        * is offset from the start of the receive buffer
-        * which can be handy for alignment reasons */
-       /* Note: FreeRTOS+TCP wants to have this offset set to 2 bytes */
-       #error ETHERNET_CONF_DATA_OFFSET not defined, assuming 0
-#endif
-       /* Enable the copy of data into the buffers
-          ignore broadcasts, and not copy FCS. */
-
-       gmac_set_configure(p_gmac,
-                       ( gmac_get_configure(p_gmac) & ~GMAC_NCFGR_RXBUFO_Msk ) |
-                       GMAC_NCFGR_RFCS |   /*  Remove FCS, frame check sequence (last 4 bytes) */
-                       GMAC_NCFGR_PEN |    /* Pause Enable */
-                       GMAC_NCFGR_RXBUFO( ETHERNET_CONF_DATA_OFFSET ) |
-                       GMAC_RXD_RXCOEN );
-
-       /*
-        * GMAC_DCFGR_TXCOEN: (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable.
-        * Note: tha SAM4E does have RX checksum offloading
-        * but TX checksum offloading has NOT been implemented.
-        */
-
-       gmac_set_dma(p_gmac,
-                       gmac_get_dma(p_gmac) | GMAC_DCFGR_TXCOEN );
-
-       gmac_enable_copy_all(p_gmac, p_opt->uc_copy_all_frame);
-       gmac_disable_broadcast(p_gmac, p_opt->uc_no_boardcast);
-
-       /* Fill in GMAC device memory management */
-       gmac_dev_mm.p_rx_buffer = gs_uc_rx_buffer;
-       gmac_dev_mm.p_rx_dscr = gs_rx_desc;
-       gmac_dev_mm.us_rx_size = GMAC_RX_BUFFERS;
-
-       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
-       {
-               gmac_dev_mm.p_tx_buffer = NULL;
-       }
-       #else
-       {
-               gmac_dev_mm.p_tx_buffer = gs_uc_tx_buffer;
-       }
-       #endif
-       gmac_dev_mm.p_tx_dscr = gs_tx_desc;
-       gmac_dev_mm.us_tx_size = GMAC_TX_BUFFERS;
-
-       gmac_init_mem(p_gmac, p_gmac_dev, &gmac_dev_mm
-#if( GMAC_USES_TX_CALLBACK != 0 )
-               , gs_tx_callback
-#endif
-               );
-
-       gmac_set_address(p_gmac, 0, p_opt->uc_mac_addr);
-}
-
-/**
- * \brief Frames can be read from the GMAC in multiple sections.
- *
- * Returns > 0 if a complete frame is available
- * It also it cleans up incomplete older frames
- */
-
-static uint32_t gmac_dev_poll(gmac_device_t* p_gmac_dev)
-{
-       uint32_t ulReturn = 0;
-       int32_t ulIndex = p_gmac_dev->ul_rx_idx;
-       gmac_rx_descriptor_t *pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];
-
-       /* Discard any incomplete frames */
-       while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) &&
-                       (pxHead->status.val & GMAC_RXD_SOF) == 0) {
-               pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);
-               circ_inc32 (&ulIndex, p_gmac_dev->ul_rx_list_size);
-               pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];
-               p_gmac_dev->ul_rx_idx = ulIndex;
-               #if( GMAC_STATS != 0 )
-               {
-                       gmacStats.incompCount++;
-               }
-               #endif
-       }
-
-       while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) != 0) {
-               if ((pxHead->status.val & GMAC_RXD_EOF) != 0) {
-                       /* Here a complete frame has been seen with SOF and EOF */
-                       ulReturn = pxHead->status.bm.len;
-                       break;
-               }
-               circ_inc32 (&ulIndex, p_gmac_dev->ul_rx_list_size);
-               pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];
-               if ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) == 0) {
-                       /* CPU is not the owner (yet) */
-                       break;
-               }
-               if ((pxHead->status.val & GMAC_RXD_SOF) != 0) {
-                       /* Strange, we found a new Start Of Frame
-                        * discard previous segments */
-                       int32_t ulPrev = p_gmac_dev->ul_rx_idx;
-                       pxHead = &p_gmac_dev->p_rx_dscr[ulPrev];
-                       do {
-                               pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);
-                               circ_inc32 (&ulPrev, p_gmac_dev->ul_rx_list_size);
-                               pxHead = &p_gmac_dev->p_rx_dscr[ulPrev];
-                               #if( GMAC_STATS != 0 )
-                               {
-                                       gmacStats.truncCount++;
-                               }
-                               #endif
-                       } while (ulPrev != ulIndex);
-                       p_gmac_dev->ul_rx_idx = ulIndex;
-               }
-       }
-       return ulReturn;
-}
-
-/**
- * \brief Frames can be read from the GMAC in multiple sections.
- * Read ul_frame_size bytes from the GMAC receive buffers to pcTo.
- * p_rcv_size is the size of the entire frame.  Generally gmac_read
- * will be repeatedly called until the sum of all the ul_frame_size equals
- * the value of p_rcv_size.
- *
- * \param p_gmac_dev Pointer to the GMAC device instance.
- * \param p_frame Address of the frame buffer.
- * \param ul_frame_size  Length of the frame.
- * \param p_rcv_size   Received frame size.
- *
- * \return GMAC_OK if receiving frame successfully, otherwise failed.
- */
-uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame,
-               uint32_t ul_frame_size, uint32_t* p_rcv_size)
-{
-       int32_t nextIdx;        /* A copy of the Rx-index 'ul_rx_idx' */
-       int32_t bytesLeft = gmac_dev_poll (p_gmac_dev);
-       gmac_rx_descriptor_t *pxHead;
-
-       if (bytesLeft == 0 )
-       {
-               return GMAC_RX_NULL;
-       }
-
-       /* gmac_dev_poll has confirmed that there is a complete frame at
-        * the current position 'ul_rx_idx'
-        */
-       nextIdx = p_gmac_dev->ul_rx_idx;
-
-       /* Read +2 bytes because buffers are aligned at -2 bytes */
-       bytesLeft = min( bytesLeft + 2, ( int32_t )ul_frame_size );
-
-       /* The frame will be copied in 1 or 2 memcpy's */
-       if( ( p_frame != NULL ) && ( bytesLeft != 0 ) )
-       {
-       const uint8_t *source;
-       int32_t left;
-       int32_t toCopy;
-
-               source = p_gmac_dev->p_rx_buffer + nextIdx * GMAC_RX_UNITSIZE;
-               left = bytesLeft;
-               toCopy = ( p_gmac_dev->ul_rx_list_size - nextIdx ) * GMAC_RX_UNITSIZE;
-               if(toCopy > left )
-               {
-                       toCopy = left;
-               }
-               memcpy (p_frame, source, toCopy);
-               left -= toCopy;
-
-               if( left != 0ul )
-               {
-                       memcpy (p_frame + toCopy, (void*)p_gmac_dev->p_rx_buffer, left);
-               }
-       }
-
-       do
-       {
-               pxHead = &p_gmac_dev->p_rx_dscr[nextIdx];
-               pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);
-               circ_inc32 (&nextIdx, p_gmac_dev->ul_rx_list_size);
-       } while ((pxHead->status.val & GMAC_RXD_EOF) == 0);
-
-       p_gmac_dev->ul_rx_idx = nextIdx;
-
-       *p_rcv_size = bytesLeft;
-
-       return GMAC_OK;
-}
-
-
-extern void vGMACGenerateChecksum( uint8_t *apBuffer );
-
-/**
- * \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the
- * GMAC Tx buffers, and then indicates to the GMAC that the buffer is ready.
- * If lEndOfFrame is true then the data being copied is the end of the frame
- * and the frame can be transmitted.
- *
- * \param p_gmac_dev Pointer to the GMAC device instance.
- * \param p_buffer       Pointer to the data buffer.
- * \param ul_size    Length of the frame.
- * \param func_tx_cb  Transmit callback function.
- *
- * \return Length sent.
- */
-uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer,
-               uint32_t ul_size, gmac_dev_tx_cb_t func_tx_cb)
-{
-
-       volatile gmac_tx_descriptor_t *p_tx_td;
-#if( GMAC_USES_TX_CALLBACK != 0 )
-       volatile gmac_dev_tx_cb_t *p_func_tx_cb;
-#endif
-
-       Gmac *p_hw = p_gmac_dev->p_hw;
-
-#if( GMAC_USES_TX_CALLBACK == 0 )
-       ( void )func_tx_cb;
-#endif
-
-       /* Check parameter */
-       if (ul_size > GMAC_TX_UNITSIZE) {
-               return GMAC_PARAM;
-       }
-
-       /* Pointers to the current transmit descriptor */
-       p_tx_td = &p_gmac_dev->p_tx_dscr[p_gmac_dev->l_tx_head];
-
-       /* If no free TxTd, buffer can't be sent, schedule the wakeup callback */
-//     if (CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
-//                                     p_gmac_dev->ul_tx_list_size) == 0)
-       {
-               if ((p_tx_td->status.val & GMAC_TXD_USED) == 0)
-                       return GMAC_TX_BUSY;
-       }
-#if( GMAC_USES_TX_CALLBACK != 0 )
-       /* Pointers to the current Tx callback */
-       p_func_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_head];
-#endif
-
-       /* Set up/copy data to transmission buffer */
-       if (p_buffer && ul_size) {
-               /* Driver manages the ring buffer */
-               /* Calculating the checksum here is faster than calculating it from the GMAC buffer
-                * because withing p_buffer, it is well aligned */
-               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
-               {
-                       /* Zero-copy... */
-                       p_tx_td->addr = ( uint32_t ) p_buffer;
-               }
-               #else
-               {
-                       /* Or Memcopy... */
-                       memcpy((void *)p_tx_td->addr, p_buffer, ul_size);
-               }
-               #endif /* ipconfigZERO_COPY_TX_DRIVER */
-               vGMACGenerateChecksum( ( uint8_t * ) p_tx_td->addr );
-       }
-
-#if( GMAC_USES_TX_CALLBACK != 0 )
-       /* Tx callback */
-       *p_func_tx_cb = func_tx_cb;
-#endif
-
-       /* Update transmit descriptor status */
-
-       /* The buffer size defined is the length of ethernet frame,
-          so it's always the last buffer of the frame. */
-       if( p_gmac_dev->l_tx_head == ( int32_t )( p_gmac_dev->ul_tx_list_size - 1 ) )
-       {
-               /* No need to 'and' with GMAC_TXD_LEN_MASK because ul_size has been checked */
-               p_tx_td->status.val =
-                       ul_size | GMAC_TXD_LAST | GMAC_TXD_WRAP;
-       } else {
-               p_tx_td->status.val =
-                       ul_size | GMAC_TXD_LAST;
-       }
-
-       circ_inc32( &p_gmac_dev->l_tx_head, p_gmac_dev->ul_tx_list_size );
-
-       /* Now start to transmit if it is still not done */
-       gmac_start_transmission(p_hw);
-
-       return GMAC_OK;
-}
-
-/**
- * \brief Get current load of transmit.
- *
- * \param p_gmac_dev Pointer to the GMAC device instance.
- *
- * \return Current load of transmit.
- */
-#if( GMAC_USES_TX_CALLBACK != 0 )
-/* Without defining GMAC_USES_TX_CALLBACK, l_tx_tail won't be updated */
-uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev)
-{
-       uint16_t us_head = p_gmac_dev->l_tx_head;
-       uint16_t us_tail = p_gmac_dev->l_tx_tail;
-       return CIRC_CNT(us_head, us_tail, p_gmac_dev->ul_tx_list_size);
-}
-#endif
-
-/**
- * \brief Register/Clear RX callback. Callback will be invoked after the next received
- * frame.
- *
- * When gmac_dev_read() returns GMAC_RX_NULL, the application task calls
- * gmac_dev_set_rx_callback() to register func_rx_cb() callback and enters suspend state.
- * The callback is in charge to resume the task once a new frame has been
- * received. The next time gmac_dev_read() is called, it will be successful.
- *
- * This function is usually invoked from the RX callback itself with NULL
- * callback, to unregister. Once the callback has resumed the application task,
- * there is no need to invoke the callback again.
- *
- * \param p_gmac_dev Pointer to the GMAC device instance.
- * \param func_tx_cb  Receive callback function.
- */
-void gmac_dev_set_rx_callback(gmac_device_t* p_gmac_dev,
-               gmac_dev_rx_cb_t func_rx_cb)
-{
-       Gmac *p_hw = p_gmac_dev->p_hw;
-
-       if (func_rx_cb == NULL) {
-               gmac_disable_interrupt(p_hw, GMAC_IDR_RCOMP);
-               p_gmac_dev->func_rx_cb = NULL;
-       } else {
-               p_gmac_dev->func_rx_cb = func_rx_cb;
-               gmac_enable_interrupt(p_hw, GMAC_IER_RCOMP);
-       }
-}
-
-/**
- *  \brief Register/Clear TX wakeup callback.
- *
- * When gmac_dev_write() returns GMAC_TX_BUSY (all transmit descriptor busy), the application
- * task calls gmac_dev_set_tx_wakeup_callback() to register func_wakeup() callback and
- * enters suspend state. The callback is in charge to resume the task once
- * several transmit descriptors have been released. The next time gmac_dev_write() will be called,
- * it shall be successful.
- *
- * This function is usually invoked with NULL callback from the TX wakeup
- * callback itself, to unregister. Once the callback has resumed the
- * application task, there is no need to invoke the callback again.
- *
- * \param p_gmac_dev   Pointer to GMAC device instance.
- * \param func_wakeup    Pointer to wakeup callback function.
- * \param uc_threshold Number of free transmit descriptor before wakeup callback invoked.
- *
- * \return GMAC_OK, GMAC_PARAM on parameter error.
- */
-#if( GMAC_USES_WAKEUP_CALLBACK )
-uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev,
-               gmac_dev_wakeup_cb_t func_wakeup_cb, uint8_t uc_threshold)
-{
-       if (func_wakeup_cb == NULL) {
-               p_gmac_dev->func_wakeup_cb = NULL;
-       } else {
-               if (uc_threshold <= p_gmac_dev->ul_tx_list_size) {
-                       p_gmac_dev->func_wakeup_cb = func_wakeup_cb;
-                       p_gmac_dev->uc_wakeup_threshold = uc_threshold;
-               } else {
-                       return GMAC_PARAM;
-               }
-       }
-
-       return GMAC_OK;
-}
-#endif /* GMAC_USES_WAKEUP_CALLBACK */
-
-/**
- * \brief Reset TX & RX queue & statistics.
- *
- * \param p_gmac_dev   Pointer to GMAC device instance.
- */
-void gmac_dev_reset(gmac_device_t* p_gmac_dev)
-{
-       Gmac *p_hw = p_gmac_dev->p_hw;
-
-       gmac_reset_rx_mem(p_gmac_dev);
-       gmac_reset_tx_mem(p_gmac_dev);
-       gmac_network_control(p_hw, GMAC_NCR_TXEN | GMAC_NCR_RXEN
-                       | GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);
-}
-
-void gmac_dev_halt(Gmac* p_gmac);
-
-void gmac_dev_halt(Gmac* p_gmac)
-{
-       gmac_network_control(p_gmac, GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);
-       gmac_disable_interrupt(p_gmac, ~0u);
-}
-
-
-/**
- * \brief GMAC Interrupt handler.
- *
- * \param p_gmac_dev   Pointer to GMAC device instance.
- */
-
-#if( GMAC_STATS != 0 )
-       extern int logPrintf( const char *pcFormat, ... );
-
-       void gmac_show_irq_counts ()
-       {
-               int index;
-               for (index = 0; index < ARRAY_SIZE(intPairs); index++) {
-                       if (gmacStats.intStatus[intPairs[index].index]) {
-                               logPrintf("%s : %6u\n", intPairs[index].name, gmacStats.intStatus[intPairs[index].index]);
-                       }
-               }
-       }
-#endif
-
-void gmac_handler(gmac_device_t* p_gmac_dev)
-{
-       Gmac *p_hw = p_gmac_dev->p_hw;
-
-#if( GMAC_USES_TX_CALLBACK != 0 )
-       gmac_tx_descriptor_t *p_tx_td;
-       gmac_dev_tx_cb_t *p_tx_cb = NULL;
-       uint32_t ul_tx_status_flag;
-#endif
-#if( GMAC_STATS != 0 )
-       int index;
-#endif
-
-       /* volatile */ uint32_t ul_isr;
-       /* volatile */ uint32_t ul_rsr;
-       /* volatile */ uint32_t ul_tsr;
-
-       ul_isr = gmac_get_interrupt_status(p_hw);
-       ul_rsr = gmac_get_rx_status(p_hw);
-       ul_tsr = gmac_get_tx_status(p_hw);
-
-/*     Why clear bits that are ignored anyway ? */
-/*     ul_isr &= ~(gmac_get_interrupt_mask(p_hw) | 0xF8030300); */
-       #if( GMAC_STATS != 0 )
-       {
-               for (index = 0; index < ARRAY_SIZE(intPairs); index++) {
-                       if (ul_isr & intPairs[index].mask)
-                               gmacStats.intStatus[intPairs[index].index]++;
-               }
-       }
-       #endif /* GMAC_STATS != 0 */
-
-       /* RX packet */
-       if ((ul_isr & GMAC_ISR_RCOMP) || (ul_rsr & (GMAC_RSR_REC|GMAC_RSR_RXOVR|GMAC_RSR_BNA))) {
-               /* Clear status */
-               gmac_clear_rx_status(p_hw, ul_rsr);
-
-               if (ul_isr & GMAC_ISR_RCOMP)
-                       ul_rsr |= GMAC_RSR_REC;
-               /* Invoke callbacks which can be useful to wake op a task */
-               if (p_gmac_dev->func_rx_cb) {
-                       p_gmac_dev->func_rx_cb(ul_rsr);
-               }
-       }
-
-       /* TX packet */
-       if ((ul_isr & GMAC_ISR_TCOMP) || (ul_tsr & (GMAC_TSR_TXCOMP|GMAC_TSR_COL|GMAC_TSR_RLE|GMAC_TSR_UND))) {
-
-#if( GMAC_USES_TX_CALLBACK != 0 )
-               ul_tx_status_flag = GMAC_TSR_TXCOMP;
-#endif
-               /* A frame transmitted */
-
-               /* Check RLE */
-               if (ul_tsr & GMAC_TSR_RLE) {
-                       /* Status RLE & Number of discarded buffers */
-#if( GMAC_USES_TX_CALLBACK != 0 )
-                       ul_tx_status_flag = GMAC_TSR_RLE | CIRC_CNT(p_gmac_dev->l_tx_head,
-                                       p_gmac_dev->l_tx_tail, p_gmac_dev->ul_tx_list_size);
-                       p_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_tail];
-#endif
-                       gmac_reset_tx_mem(p_gmac_dev);
-                       gmac_enable_transmit(p_hw, 1);
-               }
-               /* Clear status */
-               gmac_clear_tx_status(p_hw, ul_tsr);
-
-#if( GMAC_USES_TX_CALLBACK != 0 )
-               if (!CIRC_EMPTY(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail)) {
-                       /* Check the buffers */
-                       do {
-                               p_tx_td = &p_gmac_dev->p_tx_dscr[p_gmac_dev->l_tx_tail];
-                               p_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_tail];
-                               /* Any error? Exit if buffer has not been sent yet */
-                               if ((p_tx_td->status.val & GMAC_TXD_USED) == 0) {
-                                       break;
-                               }
-
-                               /* Notify upper layer that a packet has been sent */
-                               if (*p_tx_cb) {
-                                       (*p_tx_cb) (ul_tx_status_flag, (void*)p_tx_td->addr);
-                                       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
-                                       {
-                                               p_tx_td->addr = 0ul;
-                                       }
-                                       #endif /* ipconfigZERO_COPY_TX_DRIVER */
-                               }
-
-                               circ_inc32(&p_gmac_dev->l_tx_tail, p_gmac_dev->ul_tx_list_size);
-                       } while (CIRC_CNT(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
-                                                       p_gmac_dev->ul_tx_list_size));
-               }
-
-               if (ul_tsr & GMAC_TSR_RLE) {
-                       /* Notify upper layer RLE */
-                       if (*p_tx_cb) {
-                               (*p_tx_cb) (ul_tx_status_flag, NULL);
-                       }
-               }
-#endif /* GMAC_USES_TX_CALLBACK */
-
-#if( GMAC_USES_WAKEUP_CALLBACK )
-               /* If a wakeup has been scheduled, notify upper layer that it can
-                  send other packets, and the sending will be successful. */
-               if ((CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
-                               p_gmac_dev->ul_tx_list_size) >= p_gmac_dev->uc_wakeup_threshold)
-                               && p_gmac_dev->func_wakeup_cb) {
-                       p_gmac_dev->func_wakeup_cb();
-               }
-#endif
-       }
-}
-
-//@}
-
-/// @cond 0
-/**INDENT-OFF**/
-#ifdef __cplusplus
-}
-#endif
-/**INDENT-ON**/
-/// @endcond
+ /**\r
+ * \file\r
+ *\r
+ * \brief GMAC (Ethernet MAC) driver for SAM.\r
+ *\r
+ * Copyright (c) 2013 Atmel Corporation. All rights reserved.\r
+ *\r
+ * \asf_license_start\r
+ *\r
+ * \page License\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ *\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ *\r
+ * 3. The name of Atmel may not be used to endorse or promote products derived\r
+ *    from this software without specific prior written permission.\r
+ *\r
+ * 4. This software may only be redistributed and used in connection with an\r
+ *    Atmel microcontroller product.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR\r
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ * \asf_license_stop\r
+ *\r
+ */\r
+\r
+/* Standard includes. */\r
+#include <stdint.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+\r
+/* FreeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+\r
+#include "FreeRTOSIPConfig.h"\r
+\r
+#include "compiler.h"\r
+#include "instance/gmac.h"\r
+#include "ethernet_phy.h"\r
+\r
+/// @cond 0\r
+/**INDENT-OFF**/\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+/**INDENT-ON**/\r
+/// @endcond\r
+\r
+#ifndef ARRAY_SIZE\r
+#define ARRAY_SIZE(x)  (int)( sizeof(x) / sizeof(x)[0] )\r
+#endif\r
+/**\r
+ * \defgroup gmac_group Ethernet Media Access Controller\r
+ *\r
+ * See \ref gmac_quickstart.\r
+ *\r
+ * Driver for the GMAC (Ethernet Media Access Controller).\r
+ * This file contains basic functions for the GMAC, with support for all modes, settings\r
+ * and clock speeds.\r
+ *\r
+ * \section dependencies Dependencies\r
+ * This driver does not depend on other modules.\r
+ *\r
+ * @{\r
+ */\r
+\r
+/** TX descriptor lists */\r
+COMPILER_ALIGNED(8)\r
+static gmac_tx_descriptor_t gs_tx_desc[ GMAC_TX_BUFFERS ];\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+/** TX callback lists */\r
+static gmac_dev_tx_cb_t gs_tx_callback[ GMAC_TX_BUFFERS ];\r
+#endif\r
+/** RX descriptors lists */\r
+COMPILER_ALIGNED(8)\r
+static gmac_rx_descriptor_t gs_rx_desc[ GMAC_RX_BUFFERS ];\r
+\r
+#if( ipconfigZERO_COPY_TX_DRIVER == 0 )\r
+       /** Send Buffer. Section 3.6 of AMBA 2.0 spec states that burst should not cross the\r
+        * 1K Boundaries. Receive buffer manager write operations are burst of 2 words => 3 lsb bits\r
+        * of the address shall be set to 0.\r
+        */\r
+       COMPILER_ALIGNED(8)\r
+       static uint8_t gs_uc_tx_buffer[ GMAC_TX_BUFFERS * GMAC_TX_UNITSIZE ];\r
+#endif /* ipconfigZERO_COPY_TX_DRIVER */\r
+\r
+/** Receive Buffer */\r
+COMPILER_ALIGNED(8)\r
+static uint8_t gs_uc_rx_buffer[ GMAC_RX_BUFFERS * GMAC_RX_UNITSIZE ];\r
+\r
+/**\r
+ * GMAC device memory management struct.\r
+ */\r
+typedef struct gmac_dev_mem {\r
+       /* Pointer to allocated buffer for RX. The address should be 8-byte aligned\r
+       and the size should be GMAC_RX_UNITSIZE * wRxSize. */\r
+       uint8_t *p_rx_buffer;\r
+       /* Pointer to allocated RX descriptor list. */\r
+       gmac_rx_descriptor_t *p_rx_dscr;\r
+       /* RX size, in number of registered units (RX descriptors). */\r
+       /* Increased size from 16- to 32-bits, because it's more efficient */\r
+       uint32_t us_rx_size;\r
+       /* Pointer to allocated buffer for TX. The address should be 8-byte aligned\r
+       and the size should be GMAC_TX_UNITSIZE * wTxSize. */\r
+       uint8_t *p_tx_buffer;\r
+       /* Pointer to allocated TX descriptor list. */\r
+       gmac_tx_descriptor_t *p_tx_dscr;\r
+       /* TX size, in number of registered units (TX descriptors). */\r
+       uint32_t us_tx_size;\r
+} gmac_dev_mem_t;\r
+\r
+/** Return count in buffer */\r
+#define CIRC_CNT( head, tail, size )           ( ( ( head ) - ( tail ) ) % ( size ) )\r
+\r
+/*\r
+ * Return space available, from 0 to size-1.\r
+ * Always leave one free char as a completely full buffer that has (head == tail),\r
+ * which is the same as empty.\r
+ */\r
+#define CIRC_SPACE( head, tail, size )         CIRC_CNT( ( tail ), ( ( head ) + 1 ), ( size ) )\r
+\r
+/** Circular buffer is empty ? */\r
+#define CIRC_EMPTY( head, tail )                       ( head == tail )\r
+/** Clear circular buffer */\r
+#define CIRC_CLEAR( head, tail )                       do { ( head ) = 0; ( tail ) = 0; } while( 0 )\r
+\r
+/** Increment head or tail */\r
+static __inline void circ_inc32( int32_t *lHeadOrTail, uint32_t ulSize )\r
+{\r
+       ( *lHeadOrTail ) ++;\r
+    if( ( *lHeadOrTail ) >= ( int32_t )ulSize )\r
+       {\r
+               ( *lHeadOrTail ) = 0;\r
+       }\r
+}\r
+\r
+/**\r
+ * \brief Wait PHY operation to be completed.\r
+ *\r
+ * \param p_gmac HW controller address.\r
+ * \param ul_retry The retry times, 0 to wait forever until completeness.\r
+ *\r
+ * Return GMAC_OK if the operation is completed successfully.\r
+ */\r
+static uint8_t gmac_wait_phy(Gmac* p_gmac, const uint32_t ul_retry)\r
+{\r
+       volatile uint32_t ul_retry_count = 0;\r
+       const uint32_t xPHYPollDelay = pdMS_TO_TICKS( 1ul );\r
+\r
+       while (!gmac_is_phy_idle(p_gmac)) {\r
+               if (ul_retry == 0) {\r
+                       continue;\r
+               }\r
+\r
+               ul_retry_count++;\r
+\r
+               if (ul_retry_count >= ul_retry) {\r
+                       return GMAC_TIMEOUT;\r
+               }\r
+\r
+               /* Block the task to allow other tasks to execute while the PHY\r
+               is not connected. */\r
+               vTaskDelay( xPHYPollDelay );\r
+       }\r
+       return GMAC_OK;\r
+}\r
+\r
+/**\r
+ * \brief Disable transfer, reset registers and descriptor lists.\r
+ *\r
+ * \param p_dev Pointer to GMAC driver instance.\r
+ *\r
+ */\r
+static void gmac_reset_tx_mem(gmac_device_t* p_dev)\r
+{\r
+       Gmac *p_hw = p_dev->p_hw;\r
+       uint8_t *p_tx_buff = p_dev->p_tx_buffer;\r
+       gmac_tx_descriptor_t *p_td = p_dev->p_tx_dscr;\r
+\r
+       uint32_t ul_index;\r
+       uint32_t ul_address;\r
+\r
+       /* Disable TX */\r
+       gmac_enable_transmit(p_hw, 0);\r
+\r
+       /* Set up the TX descriptors */\r
+       CIRC_CLEAR(p_dev->l_tx_head, p_dev->l_tx_tail);\r
+       for( ul_index = 0; ul_index < p_dev->ul_tx_list_size; ul_index++ )\r
+       {\r
+               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
+               {\r
+                       ul_address = (uint32_t) 0u;\r
+               }\r
+               #else\r
+               {\r
+                       ul_address = (uint32_t) (&(p_tx_buff[ul_index * GMAC_TX_UNITSIZE]));\r
+               }\r
+               #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
+               p_td[ul_index].addr = ul_address;\r
+               p_td[ul_index].status.val = GMAC_TXD_USED;\r
+       }\r
+       p_td[p_dev->ul_tx_list_size - 1].status.val =\r
+                       GMAC_TXD_USED | GMAC_TXD_WRAP;\r
+\r
+       /* Set transmit buffer queue */\r
+       gmac_set_tx_queue(p_hw, (uint32_t) p_td);\r
+}\r
+\r
+/**\r
+ * \brief Disable receiver, reset registers and descriptor list.\r
+ *\r
+ * \param p_drv Pointer to GMAC Driver instance.\r
+ */\r
+static void gmac_reset_rx_mem(gmac_device_t* p_dev)\r
+{\r
+       Gmac *p_hw = p_dev->p_hw;\r
+       uint8_t *p_rx_buff = p_dev->p_rx_buffer;\r
+       gmac_rx_descriptor_t *pRd = p_dev->p_rx_dscr;\r
+\r
+       uint32_t ul_index;\r
+       uint32_t ul_address;\r
+\r
+       /* Disable RX */\r
+       gmac_enable_receive(p_hw, 0);\r
+\r
+       /* Set up the RX descriptors */\r
+       p_dev->ul_rx_idx = 0;\r
+       for( ul_index = 0; ul_index < p_dev->ul_rx_list_size; ul_index++ )\r
+       {\r
+               ul_address = (uint32_t) (&(p_rx_buff[ul_index * GMAC_RX_UNITSIZE]));\r
+               pRd[ul_index].addr.val = ul_address & GMAC_RXD_ADDR_MASK;\r
+               pRd[ul_index].status.val = 0;\r
+       }\r
+       pRd[p_dev->ul_rx_list_size - 1].addr.val |= GMAC_RXD_WRAP;\r
+\r
+       /* Set receive buffer queue */\r
+       gmac_set_rx_queue(p_hw, (uint32_t) pRd);\r
+}\r
+\r
+\r
+/**\r
+ * \brief Initialize the allocated buffer lists for GMAC driver to transfer data.\r
+ * Must be invoked after gmac_dev_init() but before RX/TX starts.\r
+ *\r
+ * \note If input address is not 8-byte aligned, the address is automatically\r
+ *       adjusted and the list size is reduced by one.\r
+ *\r
+ * \param p_gmac Pointer to GMAC instance.\r
+ * \param p_gmac_dev Pointer to GMAC device instance.\r
+ * \param p_dev_mm Pointer to the GMAC memory management control block.\r
+ * \param p_tx_cb Pointer to allocated TX callback list.\r
+ *\r
+ * \return GMAC_OK or GMAC_PARAM.\r
+ */\r
+static uint8_t gmac_init_mem(Gmac* p_gmac, gmac_device_t* p_gmac_dev,\r
+               gmac_dev_mem_t* p_dev_mm\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+               , gmac_dev_tx_cb_t* p_tx_cb\r
+#endif\r
+               )\r
+{\r
+       if (p_dev_mm->us_rx_size <= 1 || p_dev_mm->us_tx_size <= 1\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+               || p_tx_cb == NULL\r
+#endif\r
+               ) {\r
+               return GMAC_PARAM;\r
+       }\r
+\r
+       /* Assign RX buffers */\r
+       if (((uint32_t) p_dev_mm->p_rx_buffer & 0x7)\r
+                       || ((uint32_t) p_dev_mm->p_rx_dscr & 0x7)) {\r
+               p_dev_mm->us_rx_size--;\r
+       }\r
+       p_gmac_dev->p_rx_buffer =\r
+                       (uint8_t *) ((uint32_t) p_dev_mm->p_rx_buffer & 0xFFFFFFF8);\r
+       p_gmac_dev->p_rx_dscr =\r
+                       (gmac_rx_descriptor_t *) ((uint32_t) p_dev_mm->p_rx_dscr\r
+                       & 0xFFFFFFF8);\r
+       p_gmac_dev->ul_rx_list_size = p_dev_mm->us_rx_size;\r
+\r
+       /* Assign TX buffers */\r
+       if (((uint32_t) p_dev_mm->p_tx_buffer & 0x7)\r
+                       || ((uint32_t) p_dev_mm->p_tx_dscr & 0x7)) {\r
+               p_dev_mm->us_tx_size--;\r
+       }\r
+       p_gmac_dev->p_tx_buffer =\r
+                       (uint8_t *) ((uint32_t) p_dev_mm->p_tx_buffer & 0xFFFFFFF8);\r
+       p_gmac_dev->p_tx_dscr =\r
+                       (gmac_tx_descriptor_t *) ((uint32_t) p_dev_mm->p_tx_dscr\r
+                       & 0xFFFFFFF8);\r
+       p_gmac_dev->ul_tx_list_size = p_dev_mm->us_tx_size;\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+       p_gmac_dev->func_tx_cb_list = p_tx_cb;\r
+#endif\r
+       /* Reset TX & RX */\r
+       gmac_reset_rx_mem(p_gmac_dev);\r
+       gmac_reset_tx_mem(p_gmac_dev);\r
+\r
+       /* Enable Rx and Tx, plus the statistics register */\r
+       gmac_enable_transmit(p_gmac, true);\r
+       gmac_enable_receive(p_gmac, true);\r
+       gmac_enable_statistics_write(p_gmac, true);\r
+\r
+       /* Set up the interrupts for transmission and errors */\r
+       gmac_enable_interrupt(p_gmac,\r
+                       GMAC_IER_RXUBR | /* Enable receive used bit read interrupt. */\r
+                       GMAC_IER_TUR   | /* Enable transmit underrun interrupt. */\r
+                       GMAC_IER_RLEX  | /* Enable retry limit  exceeded interrupt. */\r
+                       GMAC_IER_TFC   | /* Enable transmit buffers exhausted in mid-frame interrupt. */\r
+                       GMAC_IER_TCOMP | /* Enable transmit complete interrupt. */\r
+                       GMAC_IER_ROVR  | /* Enable receive overrun interrupt. */\r
+                       GMAC_IER_HRESP | /* Enable Hresp not OK interrupt. */\r
+                       GMAC_IER_PFNZ  | /* Enable pause frame received interrupt. */\r
+                       GMAC_IER_PTZ);   /* Enable pause time zero interrupt. */\r
+\r
+       return GMAC_OK;\r
+}\r
+\r
+/**\r
+ * \brief Read the PHY register.\r
+ *\r
+ * \param p_gmac   Pointer to the GMAC instance.\r
+ * \param uc_phy_address PHY address.\r
+ * \param uc_address Register address.\r
+ * \param p_value Pointer to a 32-bit location to store read data.\r
+ *\r
+ * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.\r
+ */\r
+uint8_t gmac_phy_read(Gmac* p_gmac, uint8_t uc_phy_address, uint8_t uc_address,\r
+               uint32_t* p_value)\r
+{\r
+       gmac_maintain_phy(p_gmac, uc_phy_address, uc_address, 1, 0);\r
+\r
+       if (gmac_wait_phy(p_gmac, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) {\r
+               return GMAC_TIMEOUT;\r
+       }\r
+       *p_value = gmac_get_phy_data(p_gmac);\r
+       return GMAC_OK;\r
+}\r
+\r
+/**\r
+ * \brief Write the PHY register.\r
+ *\r
+ * \param p_gmac   Pointer to the GMAC instance.\r
+ * \param uc_phy_address PHY Address.\r
+ * \param uc_address Register Address.\r
+ * \param ul_value Data to write, actually 16-bit data.\r
+ *\r
+ * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.\r
+ */\r
+uint8_t gmac_phy_write(Gmac* p_gmac, uint8_t uc_phy_address,\r
+               uint8_t uc_address, uint32_t ul_value)\r
+{\r
+       gmac_maintain_phy(p_gmac, uc_phy_address, uc_address, 0, ul_value);\r
+\r
+       if (gmac_wait_phy(p_gmac, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) {\r
+               return GMAC_TIMEOUT;\r
+       }\r
+       return GMAC_OK;\r
+}\r
+\r
+/**\r
+ * \brief Initialize the GMAC driver.\r
+ *\r
+ * \param p_gmac   Pointer to the GMAC instance.\r
+ * \param p_gmac_dev Pointer to the GMAC device instance.\r
+ * \param p_opt GMAC configure options.\r
+ */\r
+void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev,\r
+               gmac_options_t* p_opt)\r
+{\r
+       gmac_dev_mem_t gmac_dev_mm;\r
+\r
+       /* Disable TX & RX and more */\r
+       gmac_network_control(p_gmac, 0);\r
+       gmac_disable_interrupt(p_gmac, ~0u);\r
+\r
+\r
+       gmac_clear_statistics(p_gmac);\r
+\r
+       /* Clear all status bits in the receive status register. */\r
+       gmac_clear_rx_status(p_gmac, GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA);\r
+\r
+       /* Clear all status bits in the transmit status register */\r
+       gmac_clear_tx_status(p_gmac, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE\r
+                       | GMAC_TSR_TFC | GMAC_TSR_TXCOMP | GMAC_TSR_UND);\r
+\r
+       /* Clear interrupts */\r
+       gmac_get_interrupt_status(p_gmac);\r
+#if !defined(ETHERNET_CONF_DATA_OFFSET)\r
+       /*  Receive Buffer Offset\r
+        * Indicates the number of bytes by which the received data\r
+        * is offset from the start of the receive buffer\r
+        * which can be handy for alignment reasons */\r
+       /* Note: FreeRTOS+TCP wants to have this offset set to 2 bytes */\r
+       #error ETHERNET_CONF_DATA_OFFSET not defined, assuming 0\r
+#endif\r
+       /* Enable the copy of data into the buffers\r
+          ignore broadcasts, and not copy FCS. */\r
+\r
+       gmac_set_configure(p_gmac,\r
+                       ( gmac_get_configure(p_gmac) & ~GMAC_NCFGR_RXBUFO_Msk ) |\r
+                       GMAC_NCFGR_RFCS |   /*  Remove FCS, frame check sequence (last 4 bytes) */\r
+                       GMAC_NCFGR_PEN |    /* Pause Enable */\r
+                       GMAC_NCFGR_RXBUFO( ETHERNET_CONF_DATA_OFFSET ) |\r
+                       GMAC_RXD_RXCOEN );\r
+\r
+       /*\r
+        * GMAC_DCFGR_TXCOEN: (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable.\r
+        * Note: tha SAM4E does have RX checksum offloading\r
+        * but TX checksum offloading has NOT been implemented.\r
+        */\r
+\r
+       gmac_set_dma(p_gmac,\r
+                       gmac_get_dma(p_gmac) | GMAC_DCFGR_TXCOEN );\r
+\r
+       gmac_enable_copy_all(p_gmac, p_opt->uc_copy_all_frame);\r
+       gmac_disable_broadcast(p_gmac, p_opt->uc_no_boardcast);\r
+\r
+       /* Fill in GMAC device memory management */\r
+       gmac_dev_mm.p_rx_buffer = gs_uc_rx_buffer;\r
+       gmac_dev_mm.p_rx_dscr = gs_rx_desc;\r
+       gmac_dev_mm.us_rx_size = GMAC_RX_BUFFERS;\r
+\r
+       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
+       {\r
+               gmac_dev_mm.p_tx_buffer = NULL;\r
+       }\r
+       #else\r
+       {\r
+               gmac_dev_mm.p_tx_buffer = gs_uc_tx_buffer;\r
+       }\r
+       #endif\r
+       gmac_dev_mm.p_tx_dscr = gs_tx_desc;\r
+       gmac_dev_mm.us_tx_size = GMAC_TX_BUFFERS;\r
+\r
+       gmac_init_mem(p_gmac, p_gmac_dev, &gmac_dev_mm\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+               , gs_tx_callback\r
+#endif\r
+               );\r
+\r
+       gmac_set_address(p_gmac, 0, p_opt->uc_mac_addr);\r
+}\r
+\r
+/**\r
+ * \brief Frames can be read from the GMAC in multiple sections.\r
+ *\r
+ * Returns > 0 if a complete frame is available\r
+ * It also it cleans up incomplete older frames\r
+ */\r
+\r
+static uint32_t gmac_dev_poll(gmac_device_t* p_gmac_dev)\r
+{\r
+       uint32_t ulReturn = 0;\r
+       int32_t ulIndex = p_gmac_dev->ul_rx_idx;\r
+       gmac_rx_descriptor_t *pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];\r
+\r
+       /* Discard any incomplete frames */\r
+       while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) &&\r
+                       (pxHead->status.val & GMAC_RXD_SOF) == 0) {\r
+               pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);\r
+               circ_inc32 (&ulIndex, p_gmac_dev->ul_rx_list_size);\r
+               pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];\r
+               p_gmac_dev->ul_rx_idx = ulIndex;\r
+               #if( GMAC_STATS != 0 )\r
+               {\r
+                       gmacStats.incompCount++;\r
+               }\r
+               #endif\r
+       }\r
+\r
+       while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) != 0) {\r
+               if ((pxHead->status.val & GMAC_RXD_EOF) != 0) {\r
+                       /* Here a complete frame has been seen with SOF and EOF */\r
+                       ulReturn = pxHead->status.bm.len;\r
+                       break;\r
+               }\r
+               circ_inc32 (&ulIndex, p_gmac_dev->ul_rx_list_size);\r
+               pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];\r
+               if ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) == 0) {\r
+                       /* CPU is not the owner (yet) */\r
+                       break;\r
+               }\r
+               if ((pxHead->status.val & GMAC_RXD_SOF) != 0) {\r
+                       /* Strange, we found a new Start Of Frame\r
+                        * discard previous segments */\r
+                       int32_t ulPrev = p_gmac_dev->ul_rx_idx;\r
+                       pxHead = &p_gmac_dev->p_rx_dscr[ulPrev];\r
+                       do {\r
+                               pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);\r
+                               circ_inc32 (&ulPrev, p_gmac_dev->ul_rx_list_size);\r
+                               pxHead = &p_gmac_dev->p_rx_dscr[ulPrev];\r
+                               #if( GMAC_STATS != 0 )\r
+                               {\r
+                                       gmacStats.truncCount++;\r
+                               }\r
+                               #endif\r
+                       } while (ulPrev != ulIndex);\r
+                       p_gmac_dev->ul_rx_idx = ulIndex;\r
+               }\r
+       }\r
+       return ulReturn;\r
+}\r
+\r
+/**\r
+ * \brief Frames can be read from the GMAC in multiple sections.\r
+ * Read ul_frame_size bytes from the GMAC receive buffers to pcTo.\r
+ * p_rcv_size is the size of the entire frame.  Generally gmac_read\r
+ * will be repeatedly called until the sum of all the ul_frame_size equals\r
+ * the value of p_rcv_size.\r
+ *\r
+ * \param p_gmac_dev Pointer to the GMAC device instance.\r
+ * \param p_frame Address of the frame buffer.\r
+ * \param ul_frame_size  Length of the frame.\r
+ * \param p_rcv_size   Received frame size.\r
+ *\r
+ * \return GMAC_OK if receiving frame successfully, otherwise failed.\r
+ */\r
+uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame,\r
+               uint32_t ul_frame_size, uint32_t* p_rcv_size)\r
+{\r
+       int32_t nextIdx;        /* A copy of the Rx-index 'ul_rx_idx' */\r
+       int32_t bytesLeft = gmac_dev_poll (p_gmac_dev);\r
+       gmac_rx_descriptor_t *pxHead;\r
+\r
+       if (bytesLeft == 0 )\r
+       {\r
+               return GMAC_RX_NULL;\r
+       }\r
+\r
+       /* gmac_dev_poll has confirmed that there is a complete frame at\r
+        * the current position 'ul_rx_idx'\r
+        */\r
+       nextIdx = p_gmac_dev->ul_rx_idx;\r
+\r
+       /* Read +2 bytes because buffers are aligned at -2 bytes */\r
+       bytesLeft = min( bytesLeft + 2, ( int32_t )ul_frame_size );\r
+\r
+       /* The frame will be copied in 1 or 2 memcpy's */\r
+       if( ( p_frame != NULL ) && ( bytesLeft != 0 ) )\r
+       {\r
+       const uint8_t *source;\r
+       int32_t left;\r
+       int32_t toCopy;\r
+\r
+               source = p_gmac_dev->p_rx_buffer + nextIdx * GMAC_RX_UNITSIZE;\r
+               left = bytesLeft;\r
+               toCopy = ( p_gmac_dev->ul_rx_list_size - nextIdx ) * GMAC_RX_UNITSIZE;\r
+               if(toCopy > left )\r
+               {\r
+                       toCopy = left;\r
+               }\r
+               memcpy (p_frame, source, toCopy);\r
+               left -= toCopy;\r
+\r
+               if( left != 0ul )\r
+               {\r
+                       memcpy (p_frame + toCopy, (void*)p_gmac_dev->p_rx_buffer, left);\r
+               }\r
+       }\r
+\r
+       do\r
+       {\r
+               pxHead = &p_gmac_dev->p_rx_dscr[nextIdx];\r
+               pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);\r
+               circ_inc32 (&nextIdx, p_gmac_dev->ul_rx_list_size);\r
+       } while ((pxHead->status.val & GMAC_RXD_EOF) == 0);\r
+\r
+       p_gmac_dev->ul_rx_idx = nextIdx;\r
+\r
+       *p_rcv_size = bytesLeft;\r
+\r
+       return GMAC_OK;\r
+}\r
+\r
+\r
+extern void vGMACGenerateChecksum( uint8_t *apBuffer );\r
+\r
+/**\r
+ * \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the\r
+ * GMAC Tx buffers, and then indicates to the GMAC that the buffer is ready.\r
+ * If lEndOfFrame is true then the data being copied is the end of the frame\r
+ * and the frame can be transmitted.\r
+ *\r
+ * \param p_gmac_dev Pointer to the GMAC device instance.\r
+ * \param p_buffer       Pointer to the data buffer.\r
+ * \param ul_size    Length of the frame.\r
+ * \param func_tx_cb  Transmit callback function.\r
+ *\r
+ * \return Length sent.\r
+ */\r
+uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer,\r
+               uint32_t ul_size, gmac_dev_tx_cb_t func_tx_cb)\r
+{\r
+\r
+       volatile gmac_tx_descriptor_t *p_tx_td;\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+       volatile gmac_dev_tx_cb_t *p_func_tx_cb;\r
+#endif\r
+\r
+       Gmac *p_hw = p_gmac_dev->p_hw;\r
+\r
+#if( GMAC_USES_TX_CALLBACK == 0 )\r
+       ( void )func_tx_cb;\r
+#endif\r
+\r
+       /* Check parameter */\r
+       if (ul_size > GMAC_TX_UNITSIZE) {\r
+               return GMAC_PARAM;\r
+       }\r
+\r
+       /* Pointers to the current transmit descriptor */\r
+       p_tx_td = &p_gmac_dev->p_tx_dscr[p_gmac_dev->l_tx_head];\r
+\r
+       /* If no free TxTd, buffer can't be sent, schedule the wakeup callback */\r
+//     if (CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,\r
+//                                     p_gmac_dev->ul_tx_list_size) == 0)\r
+       {\r
+               if ((p_tx_td->status.val & GMAC_TXD_USED) == 0)\r
+                       return GMAC_TX_BUSY;\r
+       }\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+       /* Pointers to the current Tx callback */\r
+       p_func_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_head];\r
+#endif\r
+\r
+       /* Set up/copy data to transmission buffer */\r
+       if (p_buffer && ul_size) {\r
+               /* Driver manages the ring buffer */\r
+               /* Calculating the checksum here is faster than calculating it from the GMAC buffer\r
+                * because withing p_buffer, it is well aligned */\r
+               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
+               {\r
+                       /* Zero-copy... */\r
+                       p_tx_td->addr = ( uint32_t ) p_buffer;\r
+               }\r
+               #else\r
+               {\r
+                       /* Or Memcopy... */\r
+                       memcpy((void *)p_tx_td->addr, p_buffer, ul_size);\r
+               }\r
+               #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
+               vGMACGenerateChecksum( ( uint8_t * ) p_tx_td->addr );\r
+       }\r
+\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+       /* Tx callback */\r
+       *p_func_tx_cb = func_tx_cb;\r
+#endif\r
+\r
+       /* Update transmit descriptor status */\r
+\r
+       /* The buffer size defined is the length of ethernet frame,\r
+          so it's always the last buffer of the frame. */\r
+       if( p_gmac_dev->l_tx_head == ( int32_t )( p_gmac_dev->ul_tx_list_size - 1 ) )\r
+       {\r
+               /* No need to 'and' with GMAC_TXD_LEN_MASK because ul_size has been checked */\r
+               p_tx_td->status.val =\r
+                       ul_size | GMAC_TXD_LAST | GMAC_TXD_WRAP;\r
+       } else {\r
+               p_tx_td->status.val =\r
+                       ul_size | GMAC_TXD_LAST;\r
+       }\r
+\r
+       circ_inc32( &p_gmac_dev->l_tx_head, p_gmac_dev->ul_tx_list_size );\r
+\r
+       /* Now start to transmit if it is still not done */\r
+       gmac_start_transmission(p_hw);\r
+\r
+       return GMAC_OK;\r
+}\r
+\r
+/**\r
+ * \brief Get current load of transmit.\r
+ *\r
+ * \param p_gmac_dev Pointer to the GMAC device instance.\r
+ *\r
+ * \return Current load of transmit.\r
+ */\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+/* Without defining GMAC_USES_TX_CALLBACK, l_tx_tail won't be updated */\r
+uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev)\r
+{\r
+       uint16_t us_head = p_gmac_dev->l_tx_head;\r
+       uint16_t us_tail = p_gmac_dev->l_tx_tail;\r
+       return CIRC_CNT(us_head, us_tail, p_gmac_dev->ul_tx_list_size);\r
+}\r
+#endif\r
+\r
+/**\r
+ * \brief Register/Clear RX callback. Callback will be invoked after the next received\r
+ * frame.\r
+ *\r
+ * When gmac_dev_read() returns GMAC_RX_NULL, the application task calls\r
+ * gmac_dev_set_rx_callback() to register func_rx_cb() callback and enters suspend state.\r
+ * The callback is in charge to resume the task once a new frame has been\r
+ * received. The next time gmac_dev_read() is called, it will be successful.\r
+ *\r
+ * This function is usually invoked from the RX callback itself with NULL\r
+ * callback, to unregister. Once the callback has resumed the application task,\r
+ * there is no need to invoke the callback again.\r
+ *\r
+ * \param p_gmac_dev Pointer to the GMAC device instance.\r
+ * \param func_tx_cb  Receive callback function.\r
+ */\r
+void gmac_dev_set_rx_callback(gmac_device_t* p_gmac_dev,\r
+               gmac_dev_rx_cb_t func_rx_cb)\r
+{\r
+       Gmac *p_hw = p_gmac_dev->p_hw;\r
+\r
+       if (func_rx_cb == NULL) {\r
+               gmac_disable_interrupt(p_hw, GMAC_IDR_RCOMP);\r
+               p_gmac_dev->func_rx_cb = NULL;\r
+       } else {\r
+               p_gmac_dev->func_rx_cb = func_rx_cb;\r
+               gmac_enable_interrupt(p_hw, GMAC_IER_RCOMP);\r
+       }\r
+}\r
+\r
+/**\r
+ *  \brief Register/Clear TX wakeup callback.\r
+ *\r
+ * When gmac_dev_write() returns GMAC_TX_BUSY (all transmit descriptor busy), the application\r
+ * task calls gmac_dev_set_tx_wakeup_callback() to register func_wakeup() callback and\r
+ * enters suspend state. The callback is in charge to resume the task once\r
+ * several transmit descriptors have been released. The next time gmac_dev_write() will be called,\r
+ * it shall be successful.\r
+ *\r
+ * This function is usually invoked with NULL callback from the TX wakeup\r
+ * callback itself, to unregister. Once the callback has resumed the\r
+ * application task, there is no need to invoke the callback again.\r
+ *\r
+ * \param p_gmac_dev   Pointer to GMAC device instance.\r
+ * \param func_wakeup    Pointer to wakeup callback function.\r
+ * \param uc_threshold Number of free transmit descriptor before wakeup callback invoked.\r
+ *\r
+ * \return GMAC_OK, GMAC_PARAM on parameter error.\r
+ */\r
+#if( GMAC_USES_WAKEUP_CALLBACK )\r
+uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev,\r
+               gmac_dev_wakeup_cb_t func_wakeup_cb, uint8_t uc_threshold)\r
+{\r
+       if (func_wakeup_cb == NULL) {\r
+               p_gmac_dev->func_wakeup_cb = NULL;\r
+       } else {\r
+               if (uc_threshold <= p_gmac_dev->ul_tx_list_size) {\r
+                       p_gmac_dev->func_wakeup_cb = func_wakeup_cb;\r
+                       p_gmac_dev->uc_wakeup_threshold = uc_threshold;\r
+               } else {\r
+                       return GMAC_PARAM;\r
+               }\r
+       }\r
+\r
+       return GMAC_OK;\r
+}\r
+#endif /* GMAC_USES_WAKEUP_CALLBACK */\r
+\r
+/**\r
+ * \brief Reset TX & RX queue & statistics.\r
+ *\r
+ * \param p_gmac_dev   Pointer to GMAC device instance.\r
+ */\r
+void gmac_dev_reset(gmac_device_t* p_gmac_dev)\r
+{\r
+       Gmac *p_hw = p_gmac_dev->p_hw;\r
+\r
+       gmac_reset_rx_mem(p_gmac_dev);\r
+       gmac_reset_tx_mem(p_gmac_dev);\r
+       gmac_network_control(p_hw, GMAC_NCR_TXEN | GMAC_NCR_RXEN\r
+                       | GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);\r
+}\r
+\r
+void gmac_dev_halt(Gmac* p_gmac);\r
+\r
+void gmac_dev_halt(Gmac* p_gmac)\r
+{\r
+       gmac_network_control(p_gmac, GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);\r
+       gmac_disable_interrupt(p_gmac, ~0u);\r
+}\r
+\r
+\r
+/**\r
+ * \brief GMAC Interrupt handler.\r
+ *\r
+ * \param p_gmac_dev   Pointer to GMAC device instance.\r
+ */\r
+\r
+#if( GMAC_STATS != 0 )\r
+       extern int logPrintf( const char *pcFormat, ... );\r
+\r
+       void gmac_show_irq_counts ()\r
+       {\r
+               int index;\r
+               for (index = 0; index < ARRAY_SIZE(intPairs); index++) {\r
+                       if (gmacStats.intStatus[intPairs[index].index]) {\r
+                               logPrintf("%s : %6u\n", intPairs[index].name, gmacStats.intStatus[intPairs[index].index]);\r
+                       }\r
+               }\r
+       }\r
+#endif\r
+\r
+void gmac_handler(gmac_device_t* p_gmac_dev)\r
+{\r
+       Gmac *p_hw = p_gmac_dev->p_hw;\r
+\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+       gmac_tx_descriptor_t *p_tx_td;\r
+       gmac_dev_tx_cb_t *p_tx_cb = NULL;\r
+       uint32_t ul_tx_status_flag;\r
+#endif\r
+#if( GMAC_STATS != 0 )\r
+       int index;\r
+#endif\r
+\r
+       /* volatile */ uint32_t ul_isr;\r
+       /* volatile */ uint32_t ul_rsr;\r
+       /* volatile */ uint32_t ul_tsr;\r
+\r
+       ul_isr = gmac_get_interrupt_status(p_hw);\r
+       ul_rsr = gmac_get_rx_status(p_hw);\r
+       ul_tsr = gmac_get_tx_status(p_hw);\r
+\r
+/*     Why clear bits that are ignored anyway ? */\r
+/*     ul_isr &= ~(gmac_get_interrupt_mask(p_hw) | 0xF8030300); */\r
+       #if( GMAC_STATS != 0 )\r
+       {\r
+               for (index = 0; index < ARRAY_SIZE(intPairs); index++) {\r
+                       if (ul_isr & intPairs[index].mask)\r
+                               gmacStats.intStatus[intPairs[index].index]++;\r
+               }\r
+       }\r
+       #endif /* GMAC_STATS != 0 */\r
+\r
+       /* RX packet */\r
+       if ((ul_isr & GMAC_ISR_RCOMP) || (ul_rsr & (GMAC_RSR_REC|GMAC_RSR_RXOVR|GMAC_RSR_BNA))) {\r
+               /* Clear status */\r
+               gmac_clear_rx_status(p_hw, ul_rsr);\r
+\r
+               if (ul_isr & GMAC_ISR_RCOMP)\r
+                       ul_rsr |= GMAC_RSR_REC;\r
+               /* Invoke callbacks which can be useful to wake op a task */\r
+               if (p_gmac_dev->func_rx_cb) {\r
+                       p_gmac_dev->func_rx_cb(ul_rsr);\r
+               }\r
+       }\r
+\r
+       /* TX packet */\r
+       if ((ul_isr & GMAC_ISR_TCOMP) || (ul_tsr & (GMAC_TSR_TXCOMP|GMAC_TSR_COL|GMAC_TSR_RLE|GMAC_TSR_UND))) {\r
+\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+               ul_tx_status_flag = GMAC_TSR_TXCOMP;\r
+#endif\r
+               /* A frame transmitted */\r
+\r
+               /* Check RLE */\r
+               if (ul_tsr & GMAC_TSR_RLE) {\r
+                       /* Status RLE & Number of discarded buffers */\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+                       ul_tx_status_flag = GMAC_TSR_RLE | CIRC_CNT(p_gmac_dev->l_tx_head,\r
+                                       p_gmac_dev->l_tx_tail, p_gmac_dev->ul_tx_list_size);\r
+                       p_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_tail];\r
+#endif\r
+                       gmac_reset_tx_mem(p_gmac_dev);\r
+                       gmac_enable_transmit(p_hw, 1);\r
+               }\r
+               /* Clear status */\r
+               gmac_clear_tx_status(p_hw, ul_tsr);\r
+\r
+#if( GMAC_USES_TX_CALLBACK != 0 )\r
+               if (!CIRC_EMPTY(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail)) {\r
+                       /* Check the buffers */\r
+                       do {\r
+                               p_tx_td = &p_gmac_dev->p_tx_dscr[p_gmac_dev->l_tx_tail];\r
+                               p_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_tail];\r
+                               /* Any error? Exit if buffer has not been sent yet */\r
+                               if ((p_tx_td->status.val & GMAC_TXD_USED) == 0) {\r
+                                       break;\r
+                               }\r
+\r
+                               /* Notify upper layer that a packet has been sent */\r
+                               if (*p_tx_cb) {\r
+                                       (*p_tx_cb) (ul_tx_status_flag, (void*)p_tx_td->addr);\r
+                                       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
+                                       {\r
+                                               p_tx_td->addr = 0ul;\r
+                                       }\r
+                                       #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
+                               }\r
+\r
+                               circ_inc32(&p_gmac_dev->l_tx_tail, p_gmac_dev->ul_tx_list_size);\r
+                       } while (CIRC_CNT(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,\r
+                                                       p_gmac_dev->ul_tx_list_size));\r
+               }\r
+\r
+               if (ul_tsr & GMAC_TSR_RLE) {\r
+                       /* Notify upper layer RLE */\r
+                       if (*p_tx_cb) {\r
+                               (*p_tx_cb) (ul_tx_status_flag, NULL);\r
+                       }\r
+               }\r
+#endif /* GMAC_USES_TX_CALLBACK */\r
+\r
+#if( GMAC_USES_WAKEUP_CALLBACK )\r
+               /* If a wakeup has been scheduled, notify upper layer that it can\r
+                  send other packets, and the sending will be successful. */\r
+               if ((CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,\r
+                               p_gmac_dev->ul_tx_list_size) >= p_gmac_dev->uc_wakeup_threshold)\r
+                               && p_gmac_dev->func_wakeup_cb) {\r
+                       p_gmac_dev->func_wakeup_cb();\r
+               }\r
+#endif\r
+       }\r
+}\r
+\r
+//@}\r
+\r
+/// @cond 0\r
+/**INDENT-OFF**/\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+/**INDENT-ON**/\r
+/// @endcond\r