xref: /FreeRTOS-Plus-TCP-v4.0.0/source/portable/NetworkInterface/DriverSAM/gmac_SAM.c (revision 245d5879903cfc6e52a466fc1067fe54f869740c)
1 /**
2  * \file
3  *
4  * \brief GMAC (Ethernet MAC) driver for SAM.
5  *
6  * Copyright (c) 2015-2016 Atmel Corporation. All rights reserved.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * 3. The name of Atmel may not be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * 4. This software may only be redistributed and used in connection with an
26  *    Atmel microcontroller product.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * \asf_license_stop
41  *
42  */
43 
44 /*
45  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
46  */
47 
48 
49 /* Standard includes. */
50 #include <stdint.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <stdlib.h>
54 
55 /* FreeRTOS includes. */
56 #include "FreeRTOS.h"
57 #include "task.h"
58 #include "semphr.h"
59 
60 #include "FreeRTOSIPConfig.h"
61 
62 /* FreeRTOS+TCP includes. */
63 #include "FreeRTOS_IP.h"
64 #include "FreeRTOS_Sockets.h"
65 #include "FreeRTOS_IP_Private.h"
66 #include "FreeRTOS_ARP.h"
67 #include "NetworkBufferManagement.h"
68 #include "NetworkInterface.h"
69 
70 #include "compiler.h"
71 #include "gmac_SAM.h"
72 
73 #if ( SAME70 != 0 )
74     /* This file is included to see if 'CONF_BOARD_ENABLE_CACHE' is defined. */
75     #include "conf_board.h"
76     #include "core_cm7.h"
77 #endif
78 
79 /*/ @cond 0 */
80 /**INDENT-OFF**/
81 #ifdef __cplusplus
82     extern "C" {
83 #endif
84 /**INDENT-ON**/
85 /*/ @endcond */
86 
87 #ifndef ARRAY_SIZE
88     #define ARRAY_SIZE( x )    ( int ) ( sizeof( x ) / sizeof( x )[ 0 ] )
89 #endif
90 
91 #if ( GMAC_RX_BUFFERS <= 1 )
92     #error Configuration error, GMAC_RX_BUFFERS must be at least 2
93 #endif
94 
95 #if ( GMAC_TX_BUFFERS <= 1 )
96     #error Configuration error, GMAC_TX_BUFFERS must be at least 2
97 #endif
98 
99 /* Interesting bits in the Transmission Status Register. */
100 #define TSR_TSR_BITS    ( GMAC_TSR_TXCOMP | GMAC_TSR_COL | GMAC_TSR_RLE | GMAC_TSR_UND )
101 
102 #if ( GMAC_STATS != 0 )
103     #if ( ipconfigPORT_SUPPRESS_WARNING == 0 )
104         #warning Statistics are enabled
105     #endif
106 
107     struct SGmacStats gmacStats;
108     TransmitStats_t xTransmitStats;
109 #endif
110 
111 /**
112  * \defgroup gmac_group Ethernet Media Access Controller
113  *
114  * See \ref gmac_quickstart.
115  *
116  * Driver for the GMAC (Ethernet Media Access Controller).
117  * This file contains basic functions for the GMAC, with support for all modes,
118  * settings and clock speeds.
119  *
120  * \section dependencies Dependencies
121  * This driver does not depend on other modules.
122  *
123  * @{
124  */
125 
126 /*
127  *     When BufferAllocation_1.c is used, the network buffer space
128  *     is declared statically as 'ucNetworkPackets[]'.
129  *     Like the DMA descriptors, this array is located in a non-cached area.
130  *     Here an example of the total size:
131  *
132  *         #define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS    24
133  *         #define GMAC_FRAME_LENTGH_MAX                     1536
134  *         Hidden space for back-pointer and IP-type         16
135  *
136  *     Total size: 24 * ( 1536 + 16 ) = 37248 bytes
137  */
138 __attribute__( ( aligned( 32 ) ) )
139 __attribute__( ( section( ".first_data" ) ) )
140 uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * NETWORK_BUFFER_SIZE ];
141 
142 /** TX descriptor lists */
143 __attribute__( ( section( ".first_data" ) ) )
144 COMPILER_ALIGNED( 8 )
145 static gmac_tx_descriptor_t gs_tx_desc[ GMAC_TX_BUFFERS ];
146 
147 #if ( SAME70 != 0 )
148     __attribute__( ( section( ".first_data" ) ) )
149     COMPILER_ALIGNED( 8 )
150     static gmac_tx_descriptor_t gs_tx_desc_null;
151 #endif
152 
153 /** RX descriptors lists */
154 __attribute__( ( section( ".first_data" ) ) )
155 COMPILER_ALIGNED( 8 )
156 static gmac_rx_descriptor_t gs_rx_desc[ GMAC_RX_BUFFERS ];
157 
158 #if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
159 
160 /** Send Buffer. Section 3.6 of AMBA 2.0 spec states that burst should not cross the
161  * 1K Boundaries. Receive buffer manager write operations are burst of 2 words => 3 lsb bits
162  * of the address shall be set to 0.
163  */
164     __attribute__( ( section( ".first_data" ) ) )
165     COMPILER_ALIGNED( 8 )
166     static uint8_t gs_uc_tx_buffer[ GMAC_TX_BUFFERS * GMAC_TX_UNITSIZE ];
167 #endif /* ipconfigZERO_COPY_TX_DRIVER */
168 
169 #if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
170     /** Receive Buffer */
171     __attribute__( ( section( ".first_data" ) ) )
172     COMPILER_ALIGNED( 8 )
173     static uint8_t gs_uc_rx_buffer[ GMAC_RX_BUFFERS * GMAC_RX_UNITSIZE ];
174 #endif /* ipconfigZERO_COPY_RX_DRIVER */
175 
176 /** Return count in buffer */
177 #define CIRC_CNT( head, tail, size )      ( ( ( head ) - ( tail ) ) % ( size ) )
178 
179 /*
180  * Return space available, from 0 to size-1.
181  * Always leave one free char as a completely full buffer that has (head == tail),
182  * which is the same as empty.
183  */
184 #define CIRC_SPACE( head, tail, size )    CIRC_CNT( ( tail ), ( ( head ) + 1 ), ( size ) )
185 
186 /** Circular buffer is empty ? */
187 #define CIRC_EMPTY( head, tail )          ( ( head ) == ( tail ) )
188 /** Clear circular buffer */
189 #define CIRC_CLEAR( head, tail )          do { ( head ) = 0; ( tail ) = 0; } while( 0 )
190 
191 /* Two call-back functions that should be defined in NetworkInterface.c */
192 extern void xRxCallback( uint32_t ulStatus );
193 extern void xTxCallback( uint32_t ulStatus,
194                          uint8_t * puc_buffer );
195 extern void returnTxBuffer( uint8_t * puc_buffer );
196 
197 
198 /** Increment head or tail */
circ_inc32(int32_t * lHeadOrTail,uint32_t ulSize)199 static __inline void circ_inc32( int32_t * lHeadOrTail,
200                                  uint32_t ulSize )
201 {
202     ( *lHeadOrTail )++;
203 
204     if( ( *lHeadOrTail ) >= ( int32_t ) ulSize )
205     {
206         ( *lHeadOrTail ) = 0;
207     }
208 }
209 
210 /**
211  * \brief Wait PHY operation to be completed.
212  *
213  * \param p_gmac HW controller address.
214  * \param ul_retry The retry times, 0 to wait forever until completeness.
215  *
216  * Return GMAC_OK if the operation is completed successfully.
217  */
gmac_wait_phy(Gmac * p_gmac,const uint32_t ul_retry)218 uint8_t gmac_wait_phy( Gmac * p_gmac,
219                        const uint32_t ul_retry )
220 {
221     volatile uint32_t ul_retry_count = 0;
222     const uint32_t xPHYPollDelay = pdMS_TO_TICKS( 1ul );
223 
224     while( !gmac_is_phy_idle( p_gmac ) )
225     {
226         if( ul_retry == 0 )
227         {
228             continue;
229         }
230 
231         ul_retry_count++;
232 
233         if( ul_retry_count >= ul_retry )
234         {
235             return GMAC_TIMEOUT;
236         }
237 
238         /* Block the task to allow other tasks to execute while the PHY
239          * is not connected. */
240         vTaskDelay( xPHYPollDelay );
241     }
242 
243     return GMAC_OK;
244 }
245 
246 /**
247  * \brief Disable transfer, reset registers and descriptor lists.
248  *
249  * \param p_dev Pointer to GMAC driver instance.
250  *
251  */
gmac_reset_tx_mem(gmac_device_t * p_dev)252 void gmac_reset_tx_mem( gmac_device_t * p_dev )
253 {
254     Gmac * p_hw = p_dev->p_hw;
255 
256     uint32_t ul_index;
257     uint32_t ul_address;
258 
259     /* Disable TX */
260     gmac_enable_transmit( p_hw, 0 );
261 
262     {
263         for( ul_index = 0; ul_index < ARRAY_SIZE( gs_tx_desc ); ul_index++ )
264         {
265             uint32_t ulAddr = gs_tx_desc[ ul_index ].addr;
266 
267             if( ulAddr )
268             {
269                 returnTxBuffer( ( uint8_t * ) ulAddr );
270             }
271         }
272     }
273     /* Set up the TX descriptors */
274     CIRC_CLEAR( p_dev->l_tx_head, p_dev->l_tx_tail );
275 
276     for( ul_index = 0; ul_index < GMAC_TX_BUFFERS; ul_index++ )
277     {
278         #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
279             {
280                 ul_address = ( uint32_t ) 0u;
281             }
282         #else
283             {
284                 ul_address = ( uint32_t ) ( &( gs_uc_tx_buffer[ ul_index * GMAC_TX_UNITSIZE ] ) );
285             }
286         #endif /* ipconfigZERO_COPY_TX_DRIVER */
287         gs_tx_desc[ ul_index ].addr = ul_address;
288         gs_tx_desc[ ul_index ].status.val = GMAC_TXD_USED;
289     }
290 
291     /* Set the WRAP bit in the last descriptor. */
292     gs_tx_desc[ GMAC_TX_BUFFERS - 1 ].status.val = GMAC_TXD_USED | GMAC_TXD_WRAP;
293 
294     /* Set transmit buffer queue */
295     gmac_set_tx_queue( p_hw, ( uint32_t ) gs_tx_desc );
296     #if ( SAME70 != 0 )
297         {
298             gmac_set_tx_priority_queue( p_hw, ( uint32_t ) &gs_tx_desc_null, GMAC_QUE_1 );
299             gmac_set_tx_priority_queue( p_hw, ( uint32_t ) &gs_tx_desc_null, GMAC_QUE_2 );
300             /* Note that SAME70 REV B had 6 priority queues. */
301             gmac_set_tx_priority_queue( p_hw, ( uint32_t ) &gs_tx_desc_null, GMAC_QUE_3 );
302             gmac_set_tx_priority_queue( p_hw, ( uint32_t ) &gs_tx_desc_null, GMAC_QUE_4 );
303             gmac_set_tx_priority_queue( p_hw, ( uint32_t ) &gs_tx_desc_null, GMAC_QUE_5 );
304         }
305     #endif
306 }
307 
308 /**
309  * \brief Disable receiver, reset registers and descriptor list.
310  *
311  * \param p_dev Pointer to GMAC Driver instance.
312  */
gmac_reset_rx_mem(gmac_device_t * p_dev)313 static void gmac_reset_rx_mem( gmac_device_t * p_dev )
314 {
315     Gmac * p_hw = p_dev->p_hw;
316 
317     uint32_t ul_index;
318     uint32_t ul_address;
319 
320     /* Disable RX */
321     gmac_enable_receive( p_hw, 0 );
322 
323     /* Set up the RX descriptors */
324     p_dev->ul_rx_idx = 0;
325 
326     for( ul_index = 0; ul_index < GMAC_RX_BUFFERS; ul_index++ )
327     {
328         #if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
329             {
330                 NetworkBufferDescriptor_t * pxNextNetworkBufferDescriptor;
331 
332                 pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( GMAC_RX_UNITSIZE, 0ul );
333                 configASSERT( pxNextNetworkBufferDescriptor != NULL );
334                 ul_address = ( uint32_t ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer );
335             }
336         #else
337             {
338                 ul_address = ( uint32_t ) ( &( gs_uc_rx_buffer[ ul_index * GMAC_RX_UNITSIZE ] ) );
339             }
340         #endif /* ipconfigZERO_COPY_RX_DRIVER */
341         gs_rx_desc[ ul_index ].addr.val = ul_address & GMAC_RXD_ADDR_MASK;
342         gs_rx_desc[ ul_index ].status.val = 0;
343     }
344 
345     /* Set the WRAP bit in the last descriptor. */
346     gs_rx_desc[ GMAC_RX_BUFFERS - 1 ].addr.bm.b_wrap = 1;
347 
348     /* Set receive buffer queue */
349     gmac_set_rx_queue( p_hw, ( uint32_t ) gs_rx_desc );
350 }
351 
352 
353 /**
354  * \brief Initialize the allocated buffer lists for GMAC driver to transfer data.
355  * Must be invoked after gmac_dev_init() but before RX/TX starts.
356  *
357  * \note If input address is not 8-byte aligned, the address is automatically
358  *       adjusted and the list size is reduced by one.
359  *
360  * \param p_gmac Pointer to GMAC instance.
361  * \param p_gmac_dev Pointer to GMAC device instance.
362  * \param p_dev_mm Pointer to the GMAC memory management control block.
363  *
364  * \return GMAC_OK or GMAC_PARAM.
365  */
gmac_init_mem(Gmac * p_gmac,gmac_device_t * p_gmac_dev)366 static uint8_t gmac_init_mem( Gmac * p_gmac,
367                               gmac_device_t * p_gmac_dev )
368 {
369     /* Assign TX buffers */
370     #if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
371         if( ( ( ( uint32_t ) gs_uc_tx_buffer ) & 0x7 ) ||
372             ( ( uint32_t ) p_dev_mm->p_tx_dscr & 0x7 ) )
373         {
374             p_dev_mm->ul_tx_size--;
375         }
376 
377         p_gmac_dev->p_tx_buffer =
378             ( uint8_t * ) ( ( ( uint32_t ) gs_uc_tx_buffer ) & 0xFFFFFFF8 );
379     #endif
380 
381     /* Reset TX & RX Memory */
382     gmac_reset_rx_mem( p_gmac_dev );
383     gmac_reset_tx_mem( p_gmac_dev );
384 
385     /* Enable Rx and Tx, plus the statistics register */
386     gmac_enable_transmit( p_gmac, true );
387     gmac_enable_receive( p_gmac, true );
388     gmac_enable_statistics_write( p_gmac, true );
389 
390     /* Set up the interrupts for transmission and errors */
391     gmac_enable_interrupt( p_gmac,
392                            GMAC_IER_RLEX |   /* Enable retry limit  exceeded interrupt. */
393                            GMAC_IER_RXUBR |  /* Enable receive used bit read interrupt. */
394                            GMAC_IER_ROVR |   /* Enable receive overrun interrupt. */
395                            GMAC_IER_TCOMP |  /* Enable transmit complete interrupt. */
396                            GMAC_IER_TUR |    /* Enable transmit underrun interrupt. */
397                            GMAC_IER_TFC |    /* Enable transmit buffers exhausted in mid-frame interrupt. */
398                            GMAC_IER_HRESP |  /* Enable Hresp not OK interrupt. */
399                            GMAC_IER_PFNZ |   /* Enable pause frame received interrupt. */
400                            GMAC_IER_PTZ |    /* Enable pause time zero interrupt. */
401                            GMAC_IER_RCOMP ); /* Enable receive complete interrupt. */
402 
403     return GMAC_OK;
404 }
405 
406 /**
407  * \brief Initialize the GMAC driver.
408  *
409  * \param p_gmac   Pointer to the GMAC instance.
410  * \param p_gmac_dev Pointer to the GMAC device instance.
411  * \param p_opt GMAC configure options.
412  */
gmac_dev_init(Gmac * p_gmac,gmac_device_t * p_gmac_dev,gmac_options_t * p_opt)413 void gmac_dev_init( Gmac * p_gmac,
414                     gmac_device_t * p_gmac_dev,
415                     gmac_options_t * p_opt )
416 {
417     /* Disable TX & RX and more */
418     gmac_network_control( p_gmac, 0 );
419     gmac_disable_interrupt( p_gmac, ~0u );
420 
421     gmac_clear_statistics( p_gmac );
422 
423     /* Clear all status bits in the receive status register. */
424     gmac_clear_rx_status( p_gmac, GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA
425                           | GMAC_RSR_HNO );
426 
427     #ifndef GMAC_TSR_UND
428         /* GMAC_TSR_UND is only defined by SAM4E. */
429     #define GMAC_TSR_UND    0ul
430     #endif
431     /* Clear all status bits in the transmit status register */
432     gmac_clear_tx_status( p_gmac, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE
433                           | GMAC_TSR_TFC | GMAC_TSR_TXCOMP | GMAC_TSR_UND );
434 
435     /* Clear interrupts */
436     gmac_get_interrupt_status( p_gmac );
437     #if !defined( ETHERNET_CONF_DATA_OFFSET )
438 
439         /*  Receive Buffer Offset
440          * Indicates the number of bytes by which the received data
441          * is offset from the start of the receive buffer
442          * which can be handy for alignment reasons */
443         /* Note: FreeRTOS+TCP wants to have this offset set to 2 bytes */
444     #error ETHERNET_CONF_DATA_OFFSET not defined, assuming 0
445     #endif
446 
447     /* Enable the copy of data into the buffers
448      * ignore broadcasts, and not copy FCS. */
449 
450     gmac_set_config( p_gmac,
451                      ( gmac_get_config( p_gmac ) & ~GMAC_NCFGR_RXBUFO_Msk ) |
452                      GMAC_NCFGR_RFCS |                                /*  Remove FCS, frame check sequence (last 4 bytes) */
453                      GMAC_NCFGR_PEN |                                 /* Pause Enable */
454                      GMAC_NCFGR_RXBUFO( ETHERNET_CONF_DATA_OFFSET ) | /* Set Ethernet Offset  */
455                      GMAC_RXD_RXCOEN );                               /* RXCOEN related function */
456 
457     /*
458      * GMAC_DCFGR_TXCOEN: (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable.
459      * Note: SAM4E/SAME70 do have RX checksum offloading
460      * but TX checksum offloading has NOT been implemented,
461      * at least on a SAM4E.
462      * http://community.atmel.com/forum/sam4e-gmac-transmit-checksum-offload-enablesolved
463      */
464 
465     {
466         uint32_t ulValue = gmac_get_dma( p_gmac );
467 
468         /* Let the GMAC set TX checksum's. */
469         ulValue |= GMAC_DCFGR_TXCOEN;
470         #if ( SAME70 != 0 )
471             {
472                 /* Transmitter Packet Buffer Memory Size Select:
473                  * Use full configured addressable space (4 Kbytes). */
474                 ulValue |= GMAC_DCFGR_TXPBMS;
475             }
476         #endif
477 
478         /* Clear the DMA Receive Buffer Size (DRBS) field: */
479         ulValue &= ~( GMAC_DCFGR_DRBS_Msk );
480         /* And set it: */
481         ulValue |= ( GMAC_RX_UNITSIZE / 64 ) << GMAC_DCFGR_DRBS_Pos;
482 
483         gmac_set_dma( p_gmac, ulValue );
484     }
485 
486     /* Enable/Disable Copy(Receive) All Valid Frames. */
487     gmac_enable_copy_all( p_gmac, p_opt->uc_copy_all_frame );
488 
489     /* Disable/Enable broadcast receiving */
490     gmac_disable_broadcast( p_gmac, p_opt->uc_no_boardcast );
491 
492 
493     /* Initialize memory */
494     gmac_init_mem( p_gmac, p_gmac_dev );
495 
496     /* Set Mac Address */
497     gmac_set_address( p_gmac, 0, p_opt->uc_mac_addr );
498 }
499 
500 /**
501  * \brief Frames can be read from the GMAC in multiple sections.
502  *
503  * Returns > 0 if a complete frame is available
504  * It also it cleans up incomplete older frames
505  */
506 
gmac_dev_poll(gmac_device_t * p_gmac_dev)507 static uint32_t gmac_dev_poll( gmac_device_t * p_gmac_dev )
508 {
509     uint32_t ulReturn = 0;
510     int32_t ulIndex = p_gmac_dev->ul_rx_idx;
511     gmac_rx_descriptor_t * pxHead = &gs_rx_desc[ ulIndex ];
512 
513     #if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
514         {
515             /* Discard any incomplete frames */
516             while( ( pxHead->addr.val & GMAC_RXD_OWNERSHIP ) &&
517                    ( pxHead->status.val & GMAC_RXD_SOF ) == 0 )
518             {
519                 pxHead->addr.val &= ~( GMAC_RXD_OWNERSHIP );
520                 circ_inc32( &ulIndex, GMAC_RX_BUFFERS );
521                 pxHead = &gs_rx_desc[ ulIndex ];
522                 p_gmac_dev->ul_rx_idx = ulIndex;
523                 #if ( GMAC_STATS != 0 )
524                     {
525                         gmacStats.incompCount++;
526                     }
527                 #endif
528             }
529         }
530     #endif /* ipconfigZERO_COPY_RX_DRIVER == 0 */
531 
532     while( ( pxHead->addr.val & GMAC_RXD_OWNERSHIP ) != 0 )
533     {
534         #if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
535             {
536                 if( ( pxHead->status.val & GMAC_RXD_EOF ) != 0 )
537                 {
538                     /* Here a complete frame has been seen with SOF and EOF */
539                     ulReturn = pxHead->status.bm.b_len;
540                     break;
541                 }
542 
543                 circ_inc32( &ulIndex, GMAC_RX_BUFFERS );
544                 pxHead = &gs_rx_desc[ ulIndex ];
545 
546                 if( ( pxHead->addr.val & GMAC_RXD_OWNERSHIP ) == 0 )
547                 {
548                     /* CPU is not the owner (yet) */
549                     break;
550                 }
551 
552                 if( ( pxHead->status.val & GMAC_RXD_SOF ) != 0 )
553                 {
554                     /* Strange, we found a new Start Of Frame
555                      * discard previous segments */
556                     int32_t ulPrev = p_gmac_dev->ul_rx_idx;
557                     pxHead = &gs_rx_desc[ ulPrev ];
558 
559                     do
560                     {
561                         pxHead->addr.val &= ~( GMAC_RXD_OWNERSHIP );
562                         circ_inc32( &ulPrev, GMAC_RX_BUFFERS );
563                         pxHead = &gs_rx_desc[ ulPrev ];
564                         #if ( GMAC_STATS != 0 )
565                             {
566                                 gmacStats.truncCount++;
567                             }
568                         #endif
569                     } while( ulPrev != ulIndex );
570 
571                     p_gmac_dev->ul_rx_idx = ulIndex;
572                 }
573             }
574         #else /* ipconfigZERO_COPY_RX_DRIVER */
575             {
576                 if( ( pxHead->status.val & ( GMAC_RXD_SOF | GMAC_RXD_EOF ) ) == ( GMAC_RXD_SOF | GMAC_RXD_EOF ) )
577                 {
578                     /* Here a complete frame in a single segment. */
579                     ulReturn = pxHead->status.bm.b_len;
580                     break;
581                 }
582 
583                 /* Return the buffer to DMA. */
584                 pxHead->addr.bm.b_ownership = 0;
585 
586                 /* Let ulIndex/pxHead point to the next buffer. */
587                 circ_inc32( &ulIndex, GMAC_RX_BUFFERS );
588                 pxHead = &gs_rx_desc[ ulIndex ];
589                 /* And remember this index. */
590                 p_gmac_dev->ul_rx_idx = ulIndex;
591             }
592         #endif /* ipconfigZERO_COPY_RX_DRIVER */
593     }
594 
595     return ulReturn;
596 }
597 
598 /**
599  * \brief Frames can be read from the GMAC in multiple sections.
600  * Read ul_frame_size bytes from the GMAC receive buffers to pcTo.
601  * p_rcv_size is the size of the entire frame.  Generally gmac_read
602  * will be repeatedly called until the sum of all the ul_frame_size equals
603  * the value of p_rcv_size.
604  *
605  * \param p_gmac_dev Pointer to the GMAC device instance.
606  * \param p_frame Address of the frame buffer.
607  * \param ul_frame_size  Length of the frame.
608  * \param p_rcv_size   Received frame size.
609  *
610  * \return GMAC_OK if receiving frame successfully, otherwise failed.
611  */
gmac_dev_read(gmac_device_t * p_gmac_dev,uint8_t * p_frame,uint32_t ul_frame_size,uint32_t * p_rcv_size,uint8_t ** pp_recv_frame)612 uint32_t gmac_dev_read( gmac_device_t * p_gmac_dev,
613                         uint8_t * p_frame,
614                         uint32_t ul_frame_size,
615                         uint32_t * p_rcv_size,
616                         uint8_t ** pp_recv_frame )
617 {
618     int32_t nextIdx; /* A copy of the Rx-index 'ul_rx_idx' */
619     int32_t bytesLeft = gmac_dev_poll( p_gmac_dev );
620     gmac_rx_descriptor_t * pxHead;
621 
622     if( bytesLeft == 0 )
623     {
624         return GMAC_RX_NO_DATA;
625     }
626 
627     /* gmac_dev_poll has confirmed that there is a complete frame at
628      * the current position 'ul_rx_idx'
629      */
630     nextIdx = p_gmac_dev->ul_rx_idx;
631 
632     /* Read +2 bytes because buffers are aligned at -2 bytes */
633     bytesLeft = min( bytesLeft + 2, ( int32_t ) ul_frame_size );
634 
635     #if ( NETWORK_BUFFERS_CACHED != 0 ) && ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE )
636         SCB_InvalidateDCache();
637     #endif
638 
639     #if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
640         {
641             /* The frame will be copied in 1 or 2 memcpy's */
642             if( ( p_frame != NULL ) && ( bytesLeft != 0 ) )
643             {
644                 const uint8_t * source;
645                 int32_t left;
646                 int32_t toCopy;
647 
648                 source = gs_uc_rx_buffer + nextIdx * GMAC_RX_UNITSIZE;
649                 left = bytesLeft;
650                 toCopy = ( GMAC_RX_BUFFERS - nextIdx ) * GMAC_RX_UNITSIZE;
651 
652                 if( toCopy > left )
653                 {
654                     toCopy = left;
655                 }
656 
657                 memcpy( p_frame, source, toCopy );
658                 left -= toCopy;
659 
660                 if( left != 0ul )
661                 {
662                     memcpy( p_frame + toCopy, ( void * ) gs_uc_rx_buffer, left );
663                 }
664             }
665         }
666     #else /* ipconfigZERO_COPY_RX_DRIVER */
667         {
668             if( p_frame != NULL )
669             {
670                 /* Return a pointer to the earlier DMA buffer. */
671                 *( pp_recv_frame ) = ( uint8_t * )
672                                      ( ( ( gs_rx_desc[ nextIdx ].addr.val ) & ~( 0x03ul ) ) + 2 );
673                 /* Set the new DMA-buffer. */
674                 gs_rx_desc[ nextIdx ].addr.bm.addr_dw = ( ( uint32_t ) p_frame ) / 4;
675             }
676             else
677             {
678                 /* The driver could not allocate a buffer to receive a packet.
679                  * Leave the current DMA buffer in place. */
680             }
681         }
682     #endif /* ipconfigZERO_COPY_RX_DRIVER */
683 
684     do
685     {
686         pxHead = &gs_rx_desc[ nextIdx ];
687         pxHead->addr.val &= ~( GMAC_RXD_OWNERSHIP );
688         circ_inc32( &nextIdx, GMAC_RX_BUFFERS );
689 
690         if( pxHead->addr.val )
691         {
692             /* Just read it back to make sure that
693              * it was written to SRAM. */
694         }
695     } while( ( pxHead->status.val & GMAC_RXD_EOF ) == 0 );
696 
697     p_gmac_dev->ul_rx_idx = nextIdx;
698 
699     *p_rcv_size = bytesLeft;
700 
701     return GMAC_OK;
702 }
703 
704 /**
705  * \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the
706  * GMAC Tx buffers, and then indicates to the GMAC that the buffer is ready.
707  * If lEndOfFrame is true then the data being copied is the end of the frame
708  * and the frame can be transmitted.
709  *
710  * \param p_gmac_dev Pointer to the GMAC device instance.
711  * \param p_buffer       Pointer to the data buffer.
712  * \param ul_size    Length of the frame.
713  *
714  * \return Length sent.
715  */
gmac_dev_write(gmac_device_t * p_gmac_dev,void * p_buffer,uint32_t ul_size)716 uint32_t gmac_dev_write( gmac_device_t * p_gmac_dev,
717                          void * p_buffer,
718                          uint32_t ul_size )
719 {
720     volatile gmac_tx_descriptor_t * p_tx_td;
721 
722     Gmac * p_hw = p_gmac_dev->p_hw;
723 
724     configASSERT( p_buffer != NULL );
725     configASSERT( ul_size >= ipconfigETHERNET_MINIMUM_PACKET_BYTES );
726 
727     /* Check parameter */
728     if( ul_size > GMAC_TX_UNITSIZE )
729     {
730         return GMAC_PARAM;
731     }
732 
733     /* Pointers to the current transmit descriptor */
734     p_tx_td = &gs_tx_desc[ p_gmac_dev->l_tx_head ];
735 
736     /* If no free TxTd, buffer can't be sent, schedule the wakeup callback */
737     if( ( p_tx_td->status.val & GMAC_TXD_USED ) == 0 )
738     {
739         return GMAC_TX_BUSY;
740     }
741 
742     /* Set up/copy data to transmission buffer */
743     if( p_buffer && ul_size )
744     {
745         /* Driver manages the ring buffer */
746 
747         /* Calculating the checksum here is faster than calculating it from the GMAC buffer
748          * because within p_buffer, it is well aligned */
749         #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
750             {
751                 /* Zero-copy... */
752                 p_tx_td->addr = ( uint32_t ) p_buffer;
753             }
754         #else
755             {
756                 /* Or memcopy... */
757                 memcpy( ( void * ) p_tx_td->addr, p_buffer, ul_size );
758             }
759         #endif /* ipconfigZERO_COPY_TX_DRIVER */
760         {
761             /* Needs to be called for SAM4E series only. */
762             vGMACGenerateChecksum( ( uint8_t * ) p_tx_td->addr, ( size_t ) ul_size );
763         }
764     }
765 
766     /* Update transmit descriptor status */
767 
768     /* The buffer size defined is the length of ethernet frame,
769      * so it's always the last buffer of the frame. */
770     if( p_gmac_dev->l_tx_head == ( int32_t ) ( GMAC_TX_BUFFERS - 1 ) )
771     {
772         /* No need to 'and' with GMAC_TXD_LEN_MASK because ul_size has been checked
773          * GMAC_TXD_USED will now be cleared. */
774         p_tx_td->status.val =
775             ul_size | GMAC_TXD_LAST | GMAC_TXD_WRAP;
776     }
777     else
778     {
779         /* GMAC_TXD_USED will now be cleared. */
780         p_tx_td->status.val =
781             ul_size | GMAC_TXD_LAST;
782     }
783 
784     if( p_tx_td->status.val )
785     {
786         /* Just read it back to make sure that
787          * it was written to SRAM. */
788     }
789 
790     circ_inc32( &p_gmac_dev->l_tx_head, GMAC_TX_BUFFERS );
791 
792     /* Now start to transmit if it is still not done */
793     gmac_start_transmission( p_hw );
794 
795     return GMAC_OK;
796 }
797 
798 /**
799  * \brief Get current load of transmit.
800  *
801  * \param p_gmac_dev Pointer to the GMAC device instance.
802  *
803  * \return Current load of transmit.
804  */
gmac_dev_get_tx_load(gmac_device_t * p_gmac_dev)805 uint32_t gmac_dev_get_tx_load( gmac_device_t * p_gmac_dev )
806 {
807     uint16_t us_head = p_gmac_dev->l_tx_head;
808     uint16_t us_tail = p_gmac_dev->l_tx_tail;
809 
810     return CIRC_CNT( us_head, us_tail, GMAC_TX_BUFFERS );
811 }
812 
813 /**
814  *  \brief Register/Clear TX wakeup callback.
815  *
816  * When gmac_dev_write() returns GMAC_TX_BUSY (all transmit descriptor busy), the application
817  * task calls gmac_dev_set_tx_wakeup_callback() to register func_wakeup() callback and
818  * enters suspend state. The callback is in charge to resume the task once
819  * several transmit descriptors have been released. The next time gmac_dev_write() will be called,
820  * it shall be successful.
821  *
822  * This function is usually invoked with NULL callback from the TX wakeup
823  * callback itself, to unregister. Once the callback has resumed the
824  * application task, there is no need to invoke the callback again.
825  *
826  * \param p_gmac_dev   Pointer to GMAC device instance.
827  * \param func_wakeup    Pointer to wakeup callback function.
828  * \param uc_threshold Number of free transmit descriptor before wakeup callback invoked.
829  *
830  * \return GMAC_OK, GMAC_PARAM on parameter error.
831  */
832 #if ( GMAC_USES_WAKEUP_CALLBACK )
gmac_dev_set_tx_wakeup_callback(gmac_device_t * p_gmac_dev,gmac_dev_wakeup_cb_t func_wakeup_cb,uint8_t uc_threshold)833     uint8_t gmac_dev_set_tx_wakeup_callback( gmac_device_t * p_gmac_dev,
834                                              gmac_dev_wakeup_cb_t func_wakeup_cb,
835                                              uint8_t uc_threshold )
836     {
837         if( func_wakeup_cb == NULL )
838         {
839             p_gmac_dev->func_wakeup_cb = NULL;
840         }
841         else
842         {
843             if( uc_threshold <= GMAC_TX_BUFFERS )
844             {
845                 p_gmac_dev->func_wakeup_cb = func_wakeup_cb;
846                 p_gmac_dev->ul_wakeup_threshold = ( uint32_t ) uc_threshold;
847             }
848             else
849             {
850                 return GMAC_PARAM;
851             }
852         }
853 
854         return GMAC_OK;
855     }
856 #endif /* GMAC_USES_WAKEUP_CALLBACK */
857 
858 /**
859  * \brief Reset TX & RX queue & statistics.
860  *
861  * \param p_gmac_dev   Pointer to GMAC device instance.
862  */
gmac_dev_reset(gmac_device_t * p_gmac_dev)863 void gmac_dev_reset( gmac_device_t * p_gmac_dev )
864 {
865     Gmac * p_hw = p_gmac_dev->p_hw;
866 
867     gmac_reset_rx_mem( p_gmac_dev );
868     gmac_reset_tx_mem( p_gmac_dev );
869     gmac_network_control( p_hw, GMAC_NCR_TXEN | GMAC_NCR_RXEN
870                           | GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT );
871 }
872 
873 void gmac_dev_halt( Gmac * p_gmac );
874 
gmac_dev_halt(Gmac * p_gmac)875 void gmac_dev_halt( Gmac * p_gmac )
876 {
877     gmac_network_control( p_gmac, GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT );
878     gmac_disable_interrupt( p_gmac, ~0u );
879 }
880 
881 
882 /**
883  * \brief GMAC Interrupt handler.
884  *
885  * \param p_gmac_dev   Pointer to GMAC device instance.
886  */
887 
888 #if ( GMAC_STATS != 0 )
gmac_show_irq_counts()889     void gmac_show_irq_counts()
890     {
891         int index;
892 
893         for( index = 0; index < ARRAY_SIZE( intPairs ); index++ )
894         {
895             if( gmacStats.intStatus[ intPairs[ index ].index ] )
896             {
897                 FreeRTOS_printf( ( "%s : %6u\n", intPairs[ index ].name, gmacStats.intStatus[ intPairs[ index ].index ] ) );
898             }
899         }
900     }
901 #endif /* if ( GMAC_STATS != 0 ) */
902 
gmac_handler(gmac_device_t * p_gmac_dev)903 void gmac_handler( gmac_device_t * p_gmac_dev )
904 {
905     Gmac * p_hw = p_gmac_dev->p_hw;
906 
907     gmac_tx_descriptor_t * p_tx_td;
908     uint32_t ul_tx_status_flag;
909 
910     #if ( GMAC_STATS != 0 )
911         int index;
912     #endif
913 
914     uint32_t ul_isr = gmac_get_interrupt_status( p_hw );
915     uint32_t ul_rsr = gmac_get_rx_status( p_hw );
916     uint32_t ul_tsr = gmac_get_tx_status( p_hw );
917 
918     #if ( GMAC_STATS != 0 )
919         {
920             for( index = 0; index < ARRAY_SIZE( intPairs ); index++ )
921             {
922                 if( ul_isr & intPairs[ index ].mask )
923                 {
924                     gmacStats.intStatus[ intPairs[ index ].index ]++;
925                 }
926             }
927         }
928     #endif /* GMAC_STATS != 0 */
929 
930     /* RX packet */
931     if( ( ul_isr & GMAC_ISR_RCOMP ) || ( ul_rsr & ( GMAC_RSR_REC | GMAC_RSR_RXOVR | GMAC_RSR_BNA ) ) )
932     {
933         /* Clear status */
934         gmac_clear_rx_status( p_hw, ul_rsr );
935 
936         if( ul_isr & GMAC_ISR_RCOMP )
937         {
938             ul_rsr |= GMAC_RSR_REC;
939         }
940 
941         /* Invoke callbacks which can be useful to wake up a task */
942         xRxCallback( ul_rsr );
943     }
944 
945     /* TX packet */
946     if( ( ul_isr & GMAC_ISR_TCOMP ) || ( ( ul_tsr & TSR_TSR_BITS ) != 0U ) )
947     {
948         ul_tx_status_flag = GMAC_TSR_TXCOMP;
949         /* A frame transmitted */
950 
951         /* Check RLE */
952         if( ul_tsr & GMAC_TSR_RLE )
953         {
954             /* Status RLE & Number of discarded buffers */
955             ul_tx_status_flag = GMAC_TSR_RLE | CIRC_CNT( p_gmac_dev->l_tx_head,
956                                                          p_gmac_dev->l_tx_tail, GMAC_TX_BUFFERS );
957             gmac_reset_tx_mem( p_gmac_dev );
958             gmac_enable_transmit( p_hw, 1 );
959         }
960 
961         /* Clear status */
962         gmac_clear_tx_status( p_hw, ul_tsr );
963 
964         if( !CIRC_EMPTY( p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail ) )
965         {
966             /* Check the buffers */
967             do
968             {
969                 p_tx_td = &gs_tx_desc[ p_gmac_dev->l_tx_tail ];
970 
971                 /* Any error? Exit if buffer has not been sent yet */
972                 if( ( p_tx_td->status.val & GMAC_TXD_USED ) == 0 )
973                 {
974                     break;
975                 }
976 
977                 /* Notify upper layer that a packet has been sent */
978                 xTxCallback( ul_tx_status_flag, ( void * ) p_tx_td->addr ); /* Function call prvTxCallback */
979                 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
980                     {
981                         p_tx_td->addr = 0ul;
982                     }
983                 #endif /* ipconfigZERO_COPY_TX_DRIVER */
984 
985                 circ_inc32( &p_gmac_dev->l_tx_tail, GMAC_TX_BUFFERS );
986             } while( CIRC_CNT( p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
987                                GMAC_TX_BUFFERS ) );
988         }
989 
990         if( ul_tsr & GMAC_TSR_RLE )
991         {
992             /* Notify upper layer RLE
993              * (GMAC_TSR) Retry Limit Exceeded */
994             xTxCallback( ul_tx_status_flag, NULL );
995         }
996 
997         #if ( GMAC_USES_WAKEUP_CALLBACK )
998 
999             /* If a wakeup has been scheduled, notify upper layer that it can
1000              * send other packets, and the sending will be successful. */
1001             if( ( CIRC_SPACE( p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
1002                               GMAC_TX_BUFFERS ) >= p_gmac_dev->ul_wakeup_threshold ) &&
1003                 p_gmac_dev->func_wakeup_cb )
1004             {
1005                 p_gmac_dev->func_wakeup_cb();
1006             }
1007         #endif
1008     }
1009 }
1010 
1011 /*@} */
1012 
1013 /*/ @cond 0 */
1014 /**INDENT-OFF**/
1015 #ifdef __cplusplus
1016 }
1017 #endif
1018 /**INDENT-ON**/
1019 /*/ @endcond */
1020