]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
0cec48a90acba8e141feaa9d7e728e5b1736feab
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / Zynq / x_emacpsif_dma.c
1 /*\r
2  * FreeRTOS+TCP V2.0.1\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 #include "Zynq/x_emacpsif.h"\r
29 #include "Zynq/x_topology.h"\r
30 #include "xstatus.h"\r
31 \r
32 #include "xparameters.h"\r
33 #include "xparameters_ps.h"\r
34 #include "xil_exception.h"\r
35 #include "xil_mmu.h"\r
36 \r
37 #include "FreeRTOS.h"\r
38 #include "task.h"\r
39 #include "timers.h"\r
40 #include "semphr.h"\r
41 \r
42 /* FreeRTOS+TCP includes. */\r
43 #include "FreeRTOS_IP.h"\r
44 #include "FreeRTOS_Sockets.h"\r
45 #include "FreeRTOS_IP_Private.h"\r
46 #include "NetworkBufferManagement.h"\r
47 \r
48 #include "uncached_memory.h"\r
49 \r
50 /* Two defines used to set or clear the EMAC interrupt */\r
51 #define INTC_BASE_ADDR          XPAR_SCUGIC_CPU_BASEADDR\r
52 #define INTC_DIST_BASE_ADDR     XPAR_SCUGIC_DIST_BASEADDR\r
53 \r
54 \r
55 \r
56 #if( ipconfigPACKET_FILLER_SIZE != 2 )\r
57         #error Please define ipconfigPACKET_FILLER_SIZE as the value '2'\r
58 #endif\r
59 #define TX_OFFSET                               ipconfigPACKET_FILLER_SIZE\r
60 \r
61 /* Defined in NetworkInterface.c */\r
62 extern TaskHandle_t xEMACTaskHandle;\r
63 \r
64 /*\r
65         pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.\r
66         The actual TX buffers are located in uncached RAM.\r
67 */\r
68 static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };\r
69 \r
70 /*\r
71         pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.\r
72         Once a message has been received by the EMAC, the descriptor can be passed\r
73         immediately to the IP-task.\r
74 */\r
75 static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };\r
76 \r
77 /*\r
78         The FreeRTOS+TCP port is using a fixed 'topology', which is declared in\r
79         ./portable/NetworkInterface/Zynq/NetworkInterface.c\r
80 */\r
81 extern struct xtopology_t xXTopology;\r
82 \r
83 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;\r
84 \r
85 /*\r
86         The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".\r
87         In stead 'struct xemacpsif_s' has a "head" and a "tail" index.\r
88         "head" is the next index to be written, used.\r
89         "tail" is the next index to be read, freed.\r
90 */\r
91 \r
92 int is_tx_space_available( xemacpsif_s *xemacpsif )\r
93 {\r
94 size_t uxCount;\r
95 \r
96         if( xTXDescriptorSemaphore != NULL )\r
97         {\r
98                 uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
99         }\r
100         else\r
101         {\r
102                 uxCount = ( UBaseType_t ) 0u;\r
103         }\r
104 \r
105         return uxCount;\r
106 }\r
107 \r
108 void emacps_check_tx( xemacpsif_s *xemacpsif )\r
109 {\r
110 int tail = xemacpsif->txTail;\r
111 int head = xemacpsif->txHead;\r
112 size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
113 \r
114         /* uxCount is the number of TX descriptors that are in use by the DMA. */\r
115         /* When done, "TXBUF_USED" will be set. */\r
116 \r
117         while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )\r
118         {\r
119                 if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )\r
120                 {\r
121                         break;\r
122                 }\r
123 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
124 #warning ipconfigZERO_COPY_TX_DRIVER is defined\r
125                 {\r
126                 void *pvBuffer = pxDMA_tx_buffers[ tail ];\r
127                 NetworkBufferDescriptor_t *pxBuffer;\r
128 \r
129                         if( pvBuffer != NULL )\r
130                         {\r
131                                 pxDMA_tx_buffers[ tail ] = NULL;\r
132                                 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );\r
133                                 if( pxBuffer != NULL )\r
134                                 {\r
135                                         vReleaseNetworkBufferAndDescriptor( pxBuffer );\r
136                                 }\r
137                                 else\r
138                                 {\r
139                                         FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );\r
140                                 }\r
141                         }\r
142                 }\r
143 #endif\r
144                 /* Clear all but the "used" and "wrap" bits. */\r
145                 if( tail < ipconfigNIC_N_TX_DESC - 1 )\r
146                 {\r
147                         xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;\r
148                 }\r
149                 else\r
150                 {\r
151                         xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;\r
152                 }\r
153                 uxCount--;\r
154                 /* Tell the counting semaphore that one more TX descriptor is available. */\r
155                 xSemaphoreGive( xTXDescriptorSemaphore );\r
156                 if( ++tail == ipconfigNIC_N_TX_DESC )\r
157                 {\r
158                         tail = 0;\r
159                 }\r
160                 xemacpsif->txTail = tail;\r
161         }\r
162 \r
163         return;\r
164 }\r
165 \r
166 void emacps_send_handler(void *arg)\r
167 {\r
168 xemacpsif_s   *xemacpsif;\r
169 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
170 \r
171         xemacpsif = (xemacpsif_s *)(arg);\r
172 \r
173         /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in\r
174         "isr_events". The task in NetworkInterface will wake-up and do the necessary work.\r
175         */\r
176         xemacpsif->isr_events |= EMAC_IF_TX_EVENT;\r
177         xemacpsif->txBusy = pdFALSE;\r
178 \r
179         if( xEMACTaskHandle != NULL )\r
180         {\r
181                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
182         }\r
183 \r
184         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
185 }\r
186 \r
187 static BaseType_t xValidLength( BaseType_t xLength )\r
188 {\r
189 BaseType_t xReturn;\r
190 \r
191         if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )\r
192         {\r
193                 xReturn = pdTRUE;\r
194         }\r
195         else\r
196         {\r
197                 xReturn =  pdFALSE;\r
198         }\r
199 \r
200         return xReturn;\r
201 }\r
202 \r
203 XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )\r
204 {\r
205 int head = xemacpsif->txHead;\r
206 int tail = xemacpsif->txTail;\r
207 int iHasSent = 0;\r
208 uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;\r
209 TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );\r
210 \r
211         #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
212         {\r
213                 /* This driver wants to own all network buffers which are to be transmitted. */\r
214                 configASSERT( iReleaseAfterSend != pdFALSE );\r
215         }\r
216         #endif\r
217 \r
218         /* Open a do {} while ( 0 ) loop to be able to call break. */\r
219         do\r
220         {\r
221         uint32_t ulFlags = 0;\r
222 \r
223                 if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )\r
224                 {\r
225                         break;\r
226                 }\r
227 \r
228                 if( xTXDescriptorSemaphore == NULL )\r
229                 {\r
230                         break;\r
231                 }\r
232 \r
233                 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
234                 {\r
235                         FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );\r
236                         break;\r
237                 }\r
238 \r
239 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
240                 /* Pass the pointer (and its ownership) directly to DMA. */\r
241                 pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;\r
242                 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
243                 {\r
244                         Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );\r
245                 }\r
246                 /* Buffer has been transferred, do not release it. */\r
247                 iReleaseAfterSend = pdFALSE;\r
248 #else\r
249                 if( pxDMA_tx_buffers[ head ] == NULL )\r
250                 {\r
251                         FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );\r
252                         break;\r
253                 }\r
254                 /* Copy the message to unbuffered space in RAM. */\r
255                 memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );\r
256 #endif\r
257                 /* Packets will be sent one-by-one, so for each packet\r
258                 the TXBUF_LAST bit will be set. */\r
259                 ulFlags |= XEMACPS_TXBUF_LAST_MASK;\r
260                 ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );\r
261                 if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )\r
262                 {\r
263                         ulFlags |= XEMACPS_TXBUF_WRAP_MASK;\r
264                 }\r
265 \r
266                 /* Copy the address of the buffer and set the flags. */\r
267                 xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];\r
268                 xemacpsif->txSegments[ head ].flags = ulFlags;\r
269 \r
270                 iHasSent = pdTRUE;\r
271                 if( ++head == ipconfigNIC_N_TX_DESC )\r
272                 {\r
273                         head = 0;\r
274                 }\r
275                 /* Update the TX-head index. These variable are declared volatile so they will be\r
276                 accessed as little as possible. */\r
277                 xemacpsif->txHead = head;\r
278         } while( pdFALSE );\r
279 \r
280         if( iReleaseAfterSend != pdFALSE )\r
281         {\r
282                 vReleaseNetworkBufferAndDescriptor( pxBuffer );\r
283                 pxBuffer = NULL;\r
284         }\r
285 \r
286         /* Data Synchronization Barrier */\r
287         dsb();\r
288 \r
289         if( iHasSent != pdFALSE )\r
290         {\r
291                 /* Make STARTTX high */\r
292                 uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);\r
293                 /* Start transmit */\r
294                 xemacpsif->txBusy = pdTRUE;\r
295                 XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );\r
296         }\r
297         dsb();\r
298 \r
299         return 0;\r
300 }\r
301 \r
302 void emacps_recv_handler(void *arg)\r
303 {\r
304         xemacpsif_s *xemacpsif;\r
305         BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
306 \r
307         xemacpsif = (xemacpsif_s *)(arg);\r
308         xemacpsif->isr_events |= EMAC_IF_RX_EVENT;\r
309 \r
310         if( xEMACTaskHandle != NULL )\r
311         {\r
312                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
313         }\r
314 \r
315         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
316 }\r
317 \r
318 static NetworkBufferDescriptor_t *ethMsg = NULL;\r
319 static NetworkBufferDescriptor_t *ethLast = NULL;\r
320 \r
321 static void passEthMessages( void )\r
322 {\r
323 IPStackEvent_t xRxEvent;\r
324 \r
325         xRxEvent.eEventType = eNetworkRxEvent;\r
326         xRxEvent.pvData = ( void * ) ethMsg;\r
327 \r
328         if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )\r
329         {\r
330                 /* The buffer could not be sent to the stack so must be released again.\r
331                 This is a deferred handler taskr, not a real interrupt, so it is ok to\r
332                 use the task level function here. */\r
333                 do\r
334                 {\r
335                         NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;\r
336                         vReleaseNetworkBufferAndDescriptor( ethMsg );\r
337                         ethMsg = xNext;\r
338                 } while( ethMsg != NULL );\r
339 \r
340                 iptraceETHERNET_RX_EVENT_LOST();\r
341                 FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );\r
342         }\r
343 \r
344         ethMsg = ethLast = NULL;\r
345 }\r
346 \r
347 int emacps_check_rx( xemacpsif_s *xemacpsif )\r
348 {\r
349 NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;\r
350 int rx_bytes;\r
351 volatile int msgCount = 0;\r
352 int head = xemacpsif->rxHead;\r
353 \r
354         /* There seems to be an issue (SI# 692601), see comments below. */\r
355         resetrx_on_no_rxdata(xemacpsif);\r
356 \r
357         /* This FreeRTOS+TCP driver shall be compiled with the option\r
358         "ipconfigUSE_LINKED_RX_MESSAGES" enabled.  It allows the driver to send a\r
359         chain of RX messages within one message to the IP-task. */\r
360         for( ;; )\r
361         {\r
362                 if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||\r
363                         ( pxDMA_rx_buffers[ head ] == NULL ) )\r
364                 {\r
365                         break;\r
366                 }\r
367 \r
368                 pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );\r
369                 if( pxNewBuffer == NULL )\r
370                 {\r
371                         /* A packet has been received, but there is no replacement for this Network Buffer.\r
372                         The packet will be dropped, and it Network Buffer will stay in place. */\r
373                         FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );\r
374                         pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];\r
375                 }\r
376                 else\r
377                 {\r
378                         pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];\r
379 \r
380                         /* Just avoiding to use or refer to the same buffer again */\r
381                         pxDMA_rx_buffers[ head ] = pxNewBuffer;\r
382 \r
383                         /*\r
384                          * Adjust the buffer size to the actual number of bytes received.\r
385                          */\r
386                         rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;\r
387 \r
388                         pxBuffer->xDataLength = rx_bytes;\r
389 \r
390                         if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
391                         {\r
392                                 Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );\r
393                         }\r
394 \r
395                         /* store it in the receive queue, where it'll be processed by a\r
396                         different handler. */\r
397                         iptraceNETWORK_INTERFACE_RECEIVE();\r
398                         pxBuffer->pxNextBuffer = NULL;\r
399 \r
400                         if( ethMsg == NULL )\r
401                         {\r
402                                 // Becomes the first message\r
403                                 ethMsg = pxBuffer;\r
404                         }\r
405                         else if( ethLast != NULL )\r
406                         {\r
407                                 // Add to the tail\r
408                                 ethLast->pxNextBuffer = pxBuffer;\r
409                         }\r
410 \r
411                         ethLast = pxBuffer;\r
412                         msgCount++;\r
413                 }\r
414                 {\r
415                         if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )\r
416                         {\r
417                                 Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );\r
418                         }\r
419                         {\r
420                                 uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
421                                 if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )\r
422                                 {\r
423                                         addr |= XEMACPS_RXBUF_WRAP_MASK;\r
424                                 }\r
425                                 /* Clearing 'XEMACPS_RXBUF_NEW_MASK'       0x00000001 *< Used bit.. */\r
426                                 xemacpsif->rxSegments[ head ].address = addr;\r
427                                 xemacpsif->rxSegments[ head ].flags = 0;\r
428                         }\r
429                 }\r
430 \r
431                 if( ++head == ipconfigNIC_N_RX_DESC )\r
432                 {\r
433                         head = 0;\r
434                 }\r
435                 xemacpsif->rxHead = head;\r
436         }\r
437 \r
438         if( ethMsg != NULL )\r
439         {\r
440                 passEthMessages( );\r
441         }\r
442 \r
443         return msgCount;\r
444 }\r
445 \r
446 void clean_dma_txdescs(xemacpsif_s *xemacpsif)\r
447 {\r
448 int index;\r
449 unsigned char *ucTxBuffer;\r
450 \r
451         /* Clear all TX descriptors and assign uncached memory to each descriptor.\r
452         "tx_space" points to the first available TX buffer. */\r
453         ucTxBuffer = xemacpsif->tx_space;\r
454 \r
455         for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )\r
456         {\r
457                 xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;\r
458                 xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;\r
459 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
460                 pxDMA_tx_buffers[ index ] = ( void* )NULL;\r
461 #else\r
462                 pxDMA_tx_buffers[ index ] = ( void* )( ucTxBuffer + TX_OFFSET );\r
463 #endif\r
464                 ucTxBuffer += xemacpsif->uTxUnitSize;\r
465         }\r
466         xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =\r
467                 XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;\r
468 }\r
469 \r
470 XStatus init_dma(xemacpsif_s *xemacpsif)\r
471 {\r
472         NetworkBufferDescriptor_t *pxBuffer;\r
473 \r
474         int iIndex;\r
475         UBaseType_t xRxSize;\r
476         UBaseType_t xTxSize;\r
477         struct xtopology_t *xtopologyp = &xXTopology;\r
478 \r
479         xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );\r
480 \r
481         xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );\r
482 \r
483         /* Also round-up to 4KB */\r
484         xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;\r
485         /*\r
486          * We allocate 65536 bytes for RX BDs which can accommodate a\r
487          * maximum of 8192 BDs which is much more than any application\r
488          * will ever need.\r
489          */\r
490         xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize )  );\r
491         xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );\r
492         xemacpsif->tx_space   = ( unsigned char *   )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );\r
493 \r
494         /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */\r
495         xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;\r
496         xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;\r
497 \r
498         if( xTXDescriptorSemaphore == NULL )\r
499         {\r
500                 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );\r
501                 configASSERT( xTXDescriptorSemaphore );\r
502         }\r
503         /*\r
504          * Allocate RX descriptors, 1 RxBD at a time.\r
505          */\r
506         for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )\r
507         {\r
508                 pxBuffer = pxDMA_rx_buffers[ iIndex ];\r
509                 if( pxBuffer == NULL )\r
510                 {\r
511                         pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );\r
512                         if( pxBuffer == NULL )\r
513                         {\r
514                                 FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );\r
515                                 return -1;\r
516                         }\r
517                 }\r
518 \r
519                 xemacpsif->rxSegments[ iIndex ].flags = 0;\r
520                 xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
521 \r
522                 pxDMA_rx_buffers[ iIndex ] = pxBuffer;\r
523                 /* Make sure this memory is not in cache for now. */\r
524                 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
525                 {\r
526                         Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,\r
527                                 (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );\r
528                 }\r
529         }\r
530 \r
531         xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;\r
532 \r
533         memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );\r
534 \r
535         clean_dma_txdescs( xemacpsif );\r
536 \r
537         {\r
538                 uint32_t value;\r
539                 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );\r
540 \r
541                 // 1xxxx: Attempt to use INCR16 AHB bursts\r
542                 value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;\r
543 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )\r
544                 value |= XEMACPS_DMACR_TCPCKSUM_MASK;\r
545 #else\r
546 #warning Are you sure the EMAC should not calculate outgoing checksums?\r
547                 value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;\r
548 #endif\r
549                 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );\r
550         }\r
551         {\r
552                 uint32_t value;\r
553                 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );\r
554 \r
555                 /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).\r
556                 Now tell the EMAC that received messages should be stored at "address + 2". */\r
557                 value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;\r
558 \r
559 #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )\r
560                 value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;\r
561 #else\r
562 #warning Are you sure the EMAC should not calculate incoming checksums?\r
563                 value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;\r
564 #endif\r
565                 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );\r
566         }\r
567 \r
568         /*\r
569          * Connect the device driver handler that will be called when an\r
570          * interrupt for the device occurs, the handler defined above performs\r
571          * the specific interrupt processing for the device.\r
572          */\r
573         XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,\r
574                 (Xil_ExceptionHandler)XEmacPs_IntrHandler,\r
575                 (void *)&xemacpsif->emacps);\r
576         /*\r
577          * Enable the interrupt for emacps.\r
578          */\r
579         EmacEnableIntr( );\r
580 \r
581         return 0;\r
582 }\r
583 \r
584 /*\r
585  * resetrx_on_no_rxdata():\r
586  *\r
587  * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata\r
588  * called by the user.\r
589  * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.\r
590  * Under heavy Rx traffic because of the HW bug there are times when the Rx path\r
591  * becomes unresponsive. The workaround for it is to check for the Rx path for\r
592  * traffic (by reading the stats registers regularly). If the stats register\r
593  * does not increment for sometime (proving no Rx traffic), the function resets\r
594  * the Rx data path.\r
595  *\r
596  */\r
597 \r
598 void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)\r
599 {\r
600         unsigned long regctrl;\r
601         unsigned long tempcntr;\r
602 \r
603         tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );\r
604         if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )\r
605         {\r
606                 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,\r
607                                 XEMACPS_NWCTRL_OFFSET);\r
608                 regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);\r
609                 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,\r
610                                 XEMACPS_NWCTRL_OFFSET, regctrl);\r
611                 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);\r
612                 regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);\r
613                 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);\r
614         }\r
615         xemacpsif->last_rx_frms_cntr = tempcntr;\r
616 }\r
617 \r
618 void EmacDisableIntr(void)\r
619 {\r
620         XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);\r
621 }\r
622 \r
623 void EmacEnableIntr(void)\r
624 {\r
625         XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);\r
626 }\r
627 \r