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