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