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